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