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