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