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