Home | History | Annotate | Download | only in fs.d
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     23 /*	  All Rights Reserved  	*/
     24 
     25 
     26 /*
     27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     28  * Use is subject to license terms.
     29  */
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include	<stdio.h>
     34 #include 	<limits.h>
     35 #include	<string.h>
     36 #include	<sys/fstyp.h>
     37 #include	<errno.h>
     38 #include	<sys/vfstab.h>
     39 #include	<sys/wait.h>
     40 #include	<sys/types.h>
     41 
     42 #define	FSTYPE_MAX	8
     43 #define	FULLPATH_MAX	64
     44 #define	ARGV_MAX	1024
     45 #define	VFS_PATH	"/usr/lib/fs"
     46 
     47 extern char	*default_fstype();
     48 
     49 char	*special = NULL;  /*  device special name  */
     50 char	*fstype = NULL;	  /*  fstype name is filled in here  */
     51 char	*cbasename;	  /* name of command */
     52 char	*newargv[ARGV_MAX]; 	/* args for the fstype specific command  */
     53 char	vfstab[] = VFSTAB;
     54 	char	full_path[FULLPATH_MAX];
     55 	char	*vfs_path = VFS_PATH;
     56 int	newargc = 2;
     57 
     58 struct commands {
     59 	char *c_basename;
     60 	char *c_optstr;
     61 	char *c_usgstr;
     62 } cmd_data[] = {
     63 	"ff", "F:o:p:a:m:c:n:i:?IlsuV",
     64 	"[-F FSType] [-V] [current_options] [-o specific_options] special ...",
     65 	"ncheck", "F:o:?i:asV",
     66 "[-F FSType] [-V] [current_options] [-o specific_options] [special ...]",
     67 	NULL, "F:o:?V",
     68 	"[-F FSType] [-V] [current_options] [-o specific_options] special ..."
     69 	};
     70 struct 	commands *c_ptr;
     71 
     72 static void usage(char *cmd, char *usg);
     73 static void exec_specific(void);
     74 static void lookup(void);
     75 
     76 int
     77 main(int argc, char *argv[])
     78 {
     79 	FILE *fp;
     80 	struct vfstab	vfsbuf;
     81 	char *ptr;
     82 	int	i;
     83 	int	verbose = 0;		/* set if -V is specified */
     84 	int	F_flg = 0;
     85 	int	usgflag = 0;
     86 	int	fs_flag = 0;
     87 	int	arg;			/* argument from getopt() */
     88 	extern	char *optarg;		/* getopt specific */
     89 	extern	int optind;
     90 	extern	int opterr;
     91 	size_t	strlen();
     92 
     93 	cbasename = ptr = argv[0];
     94 	while (*ptr) {
     95 		if (*ptr++ == '/')
     96 			cbasename = ptr;
     97 	}
     98 	/*
     99 	 * If there are no arguments and command is ncheck then the generic
    100 	 * reads the VFSTAB and executes the specific module of
    101 	 * each entry which has a numeric fsckpass field.
    102 	 */
    103 
    104 	if (argc == 1) {		/* no arguments or options */
    105 		if (strcmp(cbasename, "ncheck") == 0) {
    106 			/* open VFSTAB */
    107 			if ((fp = fopen(VFSTAB, "r")) == NULL) {
    108 				fprintf(stderr, "%s: cannot open vfstab\n",
    109 				    cbasename);
    110 				exit(2);
    111 			}
    112 			while ((i = getvfsent(fp, &vfsbuf)) == 0) {
    113 				if (numbers(vfsbuf.vfs_fsckpass)) {
    114 					fstype = vfsbuf.vfs_fstype;
    115 					newargv[newargc]  = vfsbuf.vfs_special;
    116 					exec_specific();
    117 				}
    118 			}
    119 			exit(0);
    120 		}
    121 		fprintf(stderr, "Usage:\n");
    122 		fprintf(stderr,
    123 "%s [-F FSType] [-V] [current_options] [-o specific_options] special ...\n",
    124 		    cbasename);
    125 		exit(2);
    126 	}
    127 
    128 	for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) &&
    129 	    (strcmp(c_ptr->c_basename, cbasename) != 0));  c_ptr++)
    130 		;
    131 	while ((arg = getopt(argc, argv, c_ptr->c_optstr)) != -1) {
    132 			switch (arg) {
    133 			case 'V':	/* echo complete command line */
    134 				verbose = 1;
    135 				break;
    136 			case 'F':	/* FSType specified */
    137 				F_flg++;
    138 				fstype = optarg;
    139 				break;
    140 			case 'o':	/* FSType specific arguments */
    141 				newargv[newargc++] = "-o";
    142 				newargv[newargc++] = optarg;
    143 				break;
    144 			case '?':	/* print usage message */
    145 				newargv[newargc++] = "-?";
    146 				usgflag = 1;
    147 				break;
    148 			default:
    149 				newargv[newargc] = (char *)malloc(3);
    150 				sprintf(newargv[newargc++], "-%c", arg);
    151 				if (optarg)
    152 					newargv[newargc++] = optarg;
    153 				break;
    154 			}
    155 			optarg = NULL;
    156 	}
    157 	if (F_flg > 1) {
    158 		fprintf(stderr, "%s: more than one FSType specified\n",
    159 			cbasename);
    160 		usage(cbasename, c_ptr->c_usgstr);
    161 	}
    162 	if (F_flg && (strlen(fstype) > (size_t)FSTYPE_MAX)) {
    163 		fprintf(stderr, "%s: FSType %s exceeds %d characters\n",
    164 			cbasename, fstype, FSTYPE_MAX);
    165 		exit(2);
    166 	}
    167 	if (optind == argc) {
    168 		/* all commands except ncheck must exit now */
    169 		if (strcmp(cbasename, "ncheck") != 0) {
    170 			if ((F_flg) && (usgflag)) {
    171 				exec_specific();
    172 				exit(0);
    173 			}
    174 			usage(cbasename, c_ptr->c_usgstr);
    175 		}
    176 		if ((F_flg) && (usgflag)) {
    177 			exec_specific();
    178 			exit(0);
    179 		}
    180 		if (usgflag)
    181 			usage(cbasename, c_ptr->c_usgstr);
    182 
    183 		/* open VFSTAB */
    184 		if ((fp = fopen(VFSTAB, "r")) == NULL) {
    185 			fprintf(stderr, "%s: cannot open vfstab\n", cbasename);
    186 			exit(2);
    187 		}
    188 		while ((i = getvfsent(fp, &vfsbuf)) == 0) {
    189 			if (!numbers(vfsbuf.vfs_fsckpass))
    190 				continue;
    191 			if ((F_flg) && (strcmp(fstype, vfsbuf.vfs_fstype) != 0))
    192 				continue;
    193 			fs_flag++;
    194 			fstype = vfsbuf.vfs_fstype;
    195 			newargv[newargc] = vfsbuf.vfs_special;
    196 			if (verbose) {
    197 				printf("%s -F %s ", cbasename,
    198 				    vfsbuf.vfs_fstype);
    199 				for (i = 2; newargv[i]; i++)
    200 					printf("%s\n", newargv[i]);
    201 				continue;
    202 			}
    203 			exec_specific();
    204 		}
    205 		/*
    206 		 * if (! fs_flag) {
    207 		 *	if (sysfs(GETFSIND, fstype) == (-1)) {
    208 		 *		fprintf(stderr,
    209 		 *		"%s: FSType %s not installed in the kernel\n",
    210 		 *			cbasename, fstype);
    211 		 *		exit(1);
    212 		 *	}
    213 		 * }
    214 		 */
    215 
    216 		exit(0);
    217 	}
    218 
    219 	/* All other arguments must be specials */
    220 	/*  perform a lookup if fstype is not specified  */
    221 
    222 	for (; optind < argc; optind++)  {
    223 		newargv[newargc] = argv[optind];
    224 		special = newargv[newargc];
    225 		if ((F_flg) && (usgflag)) {
    226 			exec_specific();
    227 			exit(0);
    228 		}
    229 		if (usgflag)
    230 			usage(cbasename, c_ptr->c_usgstr);
    231 		if (fstype == NULL)
    232 			lookup();
    233 		if (verbose) {
    234 			printf("%s -F %s ", cbasename, fstype);
    235 			for (i = 2; newargv[i]; i++)
    236 				printf("%s ", newargv[i]);
    237 			printf("\n");
    238 			continue;
    239 		}
    240 		exec_specific();
    241 		if (!F_flg)
    242 			fstype = NULL;
    243 	}
    244 	return (0);
    245 }
    246 
    247 /* see if all numbers */
    248 int
    249 numbers(char *yp)
    250 {
    251 	if (yp == NULL)
    252 		return (0);
    253 	while ('0' <= *yp && *yp <= '9')
    254 		yp++;
    255 	if (*yp)
    256 		return (0);
    257 	return (1);
    258 }
    259 
    260 static void
    261 usage(char *cmd, char *usg)
    262 {
    263 	fprintf(stderr, "Usage:\n");
    264 	fprintf(stderr, "%s %s\n", cmd, usg);
    265 	exit(2);
    266 }
    267 
    268 
    269 /*
    270  *  This looks up the /etc/vfstab entry given the device 'special'.
    271  *  It is called when the fstype is not specified on the command line.
    272  *
    273  *  The following global variables are used:
    274  *	special, fstype
    275  */
    276 
    277 static void
    278 lookup(void)
    279 {
    280 	FILE	*fd;
    281 	int	ret;
    282 	struct vfstab	vget, vref;
    283 
    284 	if ((fd = fopen(vfstab, "r")) == NULL) {
    285 		fprintf(stderr, "%s: cannot open vfstab\n", cbasename);
    286 		exit(1);
    287 	}
    288 	vfsnull(&vref);
    289 	vref.vfs_special = special;
    290 	ret = getvfsany(fd, &vget, &vref);
    291 	if (ret == -1) {
    292 		rewind(fd);
    293 		vfsnull(&vref);
    294 		vref.vfs_fsckdev = special;
    295 		ret = getvfsany(fd, &vget, &vref);
    296 	}
    297 	fclose(fd);
    298 
    299 	switch (ret) {
    300 	case -1:
    301 		fstype = default_fstype(special);
    302 		break;
    303 	case 0:
    304 		fstype = vget.vfs_fstype;
    305 		break;
    306 	case VFS_TOOLONG:
    307 		fprintf(stderr, "%s: line in vfstab exceeds %d characters\n",
    308 			cbasename, VFS_LINE_MAX-2);
    309 		exit(1);
    310 		break;
    311 	case VFS_TOOFEW:
    312 		fprintf(stderr, "%s: line in vfstab has too few entries\n",
    313 			cbasename);
    314 		exit(1);
    315 		break;
    316 	case VFS_TOOMANY:
    317 		fprintf(stderr, "%s: line in vfstab has too many entries\n",
    318 			cbasename);
    319 		exit(1);
    320 		break;
    321 	}
    322 }
    323 
    324 static void
    325 exec_specific(void)
    326 {
    327 int status, pid, ret;
    328 
    329 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, cbasename);
    330 	newargv[1] = &full_path[FULLPATH_MAX];
    331 	while (*newargv[1]-- != '/');
    332 	newargv[1] += 2;
    333 	switch (pid = fork()) {
    334 	case 0:
    335 		execv(full_path, &newargv[1]);
    336 		if (errno == ENOEXEC) {
    337 			newargv[0] = "sh";
    338 			newargv[1] = full_path;
    339 			execv("/sbin/sh", &newargv[0]);
    340 		}
    341 		if (errno != ENOENT) {
    342 			perror(cbasename);
    343 			fprintf(stderr, "%s: cannot execute %s\n", cbasename,
    344 			    full_path);
    345 			exit(1);
    346 		}
    347 		if (sysfs(GETFSIND, fstype) == (-1)) {
    348 			fprintf(stderr,
    349 				"%s: FSType %s not installed in the kernel\n",
    350 				cbasename, fstype);
    351 			exit(1);
    352 		}
    353 		fprintf(stderr, "%s: operation not applicable for FSType %s\n",
    354 		    cbasename, fstype);
    355 		exit(1);
    356 	case -1:
    357 		fprintf(stderr, "%s: cannot fork process\n", cbasename);
    358 		exit(2);
    359 	default:
    360 		/*
    361 		 * if cannot exec specific, or fstype is not installed, exit
    362 		 * after first 'exec_specific' to avoid printing duplicate
    363 		 * error messages
    364 		 */
    365 
    366 		if (wait(&status) == pid) {
    367 			ret = WHIBYTE(status);
    368 			if (ret > 0) {
    369 				exit(ret);
    370 			}
    371 		}
    372 	}
    373 }
    374