xref: /illumos-gate/usr/src/cmd/fs.d/ff.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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