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
main(int argc,char * argv[])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
numbers(char * yp)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
usage(char * cmd,char * usg)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
lookup(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
exec_specific(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