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 <locale.h> 36 #include <libintl.h> 37 #include <sys/fstyp.h> 38 #include <errno.h> 39 #include <sys/vfstab.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 #include <string.h> 44 45 #define FSTYPE_MAX 8 46 #define ARGV_MAX 1024 47 #define VFS_PATH "/usr/lib/fs" 48 #define ALT_PATH "/etc/fs" 49 50 extern char *default_fstype(); 51 void stat_snap(char *, char *, char *); 52 char *special = NULL; /* device special name */ 53 char *fstype = NULL; /* fstype name is filled in here */ 54 char *cbasename; /* name of command */ 55 char *newargv[ARGV_MAX]; /* args for the fstype specific command */ 56 char vfstab[] = VFSTAB; 57 int newargc = 2; 58 59 /* 60 * TRANSLATION_NOTE - the usage strings in the c_usgstr[] of the 61 * following structures should be given a translation; the call to gettext 62 * is in the usage() function. The strings are the ones containing 63 * "[-F FSType]". 64 */ 65 66 struct commands { 67 char *c_basename; 68 char *c_optstr; 69 char *c_usgstr[4]; /* make sure as large as largest array size */ 70 } cmd_data[] = { 71 "clri", "F:o:?V", 72 { 73 "[-F FSType] [-V] special inumber ...", 74 NULL 75 }, 76 "mkfs", "F:o:mb:?V", 77 { 78 "[-F FSType] [-V] [-m] [-o specific_options] special ", 79 "[operands]", NULL 80 }, 81 "dcopy", "F:o:?V", 82 { 83 "[-F FSType] [-V] special inumber ...", 84 NULL 85 }, 86 "fsdb", "F:o:z:?V", 87 { 88 "[-F FSType] [-V] [-o specific_options] special", 89 NULL 90 }, 91 "fssnap", "F:dio:?V", 92 { 93 "[-F FSType] [-V] -o special_options /mount/point", 94 "-d [-F FSType] [-V] /mount/point | dev", 95 "-i [-F FSType] [-V] [-o special-options] [/mount/point | dev]", 96 NULL 97 }, 98 "labelit", "F:o:?nV", 99 { 100 "[-F FSType] [-V] [-o specific_options] special [operands]", 101 NULL 102 }, 103 NULL, "F:o:?V", 104 { 105 "[-F FSType] [-V] [-o specific_options] special [operands]", 106 NULL 107 } 108 }; 109 struct commands *c_ptr; 110 111 main(argc, argv) 112 int argc; 113 char *argv[]; 114 { 115 register char *ptr; 116 char full_path[PATH_MAX]; 117 char *vfs_path = VFS_PATH; 118 char *alt_path = ALT_PATH; 119 int i; 120 int verbose = 0; /* set if -V is specified */ 121 int F_flg = 0; 122 int mflag = 0; 123 char *oopts = NULL; 124 int iflag = 0; 125 int usgflag = 0; 126 int arg; /* argument from getopt() */ 127 extern char *optarg; /* getopt specific */ 128 extern int optind; 129 extern int opterr; 130 131 (void) setlocale(LC_ALL, ""); 132 133 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 134 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 135 #endif 136 137 (void) textdomain(TEXT_DOMAIN); 138 139 cbasename = ptr = argv[0]; 140 while (*ptr) { 141 if (*ptr++ == '/') 142 cbasename = ptr; 143 } 144 145 146 if (argc == 1) { 147 for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) && 148 (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++) 149 ; 150 usage(cbasename, c_ptr->c_usgstr); 151 exit(2); 152 } 153 154 for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) && 155 (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++) 156 ; 157 while ((arg = getopt(argc, argv, c_ptr->c_optstr)) != -1) { 158 switch (arg) { 159 case 'V': /* echo complete command line */ 160 verbose = 1; 161 break; 162 case 'F': /* FSType specified */ 163 F_flg++; 164 fstype = optarg; 165 break; 166 case 'o': /* FSType specific arguments */ 167 newargv[newargc++] = "-o"; 168 newargv[newargc++] = optarg; 169 oopts = optarg; 170 break; 171 case '?': /* print usage message */ 172 newargv[newargc++] = "-?"; 173 usgflag = 1; 174 break; 175 case 'm': /* FSType specific arguments */ 176 mflag = 1; 177 newargv[newargc] = (char *)malloc(3); 178 sprintf(newargv[newargc++], "-%c", arg); 179 if (optarg) 180 newargv[newargc++] = optarg; 181 break; 182 case 'i': /* fssnap only */ 183 iflag = 1; 184 /*FALLTHROUGH*/ 185 default: 186 newargv[newargc] = (char *)malloc(3); 187 sprintf(newargv[newargc++], "-%c", arg); 188 if (optarg) 189 newargv[newargc++] = optarg; 190 break; 191 } 192 optarg = NULL; 193 } 194 if (F_flg > 1) { 195 fprintf(stderr, gettext("%s: more than one FSType specified\n"), 196 cbasename); 197 usage(cbasename, c_ptr->c_usgstr); 198 exit(2); 199 } 200 if (fstype != NULL) { 201 if (strlen(fstype) > FSTYPE_MAX) { 202 fprintf(stderr, 203 gettext("%s: FSType %s exceeds %d characters\n"), 204 cbasename, fstype, FSTYPE_MAX); 205 exit(2); 206 } 207 } 208 209 /* perform a lookup if fstype is not specified */ 210 special = argv[optind]; 211 optind++; 212 213 /* handle -i (fssnap command only) */ 214 if (iflag) { 215 int diff = argc - optind; 216 /* 217 * There is no reason to ever call a file system specific 218 * version since its all in kstats. 219 */ 220 if (diff > 0) /* gave more than one mountpoint or device */ 221 usage(cbasename, c_ptr->c_usgstr); 222 stat_snap(cbasename, diff == 0 ? argv[argc-1] : NULL, oopts); 223 exit(0); 224 } 225 226 if ((special == NULL) && (!usgflag)) { 227 fprintf(stderr, gettext("%s: special not specified\n"), 228 cbasename); 229 usage(cbasename, c_ptr->c_usgstr); 230 exit(2); 231 } 232 if ((fstype == NULL) && (usgflag)) 233 usage(cbasename, c_ptr->c_usgstr); 234 if (fstype == NULL) 235 lookup(); 236 if (fstype == NULL) { 237 fprintf(stderr, gettext("%s: FSType cannot be identified\n"), 238 cbasename); 239 usage(cbasename, c_ptr->c_usgstr); 240 exit(2); 241 } 242 newargv[newargc++] = special; 243 for (; optind < argc; optind++) 244 newargv[newargc++] = argv[optind]; 245 246 /* build the full pathname of the fstype dependent command */ 247 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, cbasename); 248 249 newargv[1] = cbasename; 250 251 if (verbose) { 252 printf("%s -F %s ", cbasename, fstype); 253 for (i = 2; newargv[i]; i++) 254 printf("%s ", newargv[i]); 255 printf("\n"); 256 exit(0); 257 } 258 259 /* 260 * Execute the FSType specific command. 261 */ 262 execv(full_path, &newargv[1]); 263 if ((errno == ENOENT) || (errno == EACCES)) { 264 /* build the alternate pathname */ 265 sprintf(full_path, "%s/%s/%s", alt_path, fstype, cbasename); 266 if (verbose) { 267 printf("%s -F %s ", cbasename, fstype); 268 for (i = 2; newargv[i]; i++) 269 printf("%s ", newargv[i]); 270 printf("\n"); 271 exit(0); 272 } 273 execv(full_path, &newargv[1]); 274 } 275 if (errno == ENOEXEC) { 276 newargv[0] = "sh"; 277 newargv[1] = full_path; 278 execv("/sbin/sh", &newargv[0]); 279 } 280 if (errno != ENOENT) { 281 perror(cbasename); 282 fprintf(stderr, gettext("%s: cannot execute %s\n"), cbasename, 283 full_path); 284 exit(2); 285 } 286 287 if (sysfs(GETFSIND, fstype) == (-1)) { 288 fprintf(stderr, 289 gettext("%s: FSType %s not installed in the kernel\n"), 290 cbasename, fstype); 291 exit(2); 292 } 293 fprintf(stderr, 294 gettext("%s: Operation not applicable for FSType %s \n"), 295 cbasename, fstype); 296 exit(2); 297 } 298 299 usage(cmd, usg) 300 char *cmd; 301 char **usg; 302 { 303 int i; 304 fprintf(stderr, gettext("Usage:\n")); 305 for (i = 0; usg[i] != NULL; i++) 306 fprintf(stderr, "%s %s\n", gettext(cmd), gettext(usg[i])); 307 exit(2); 308 } 309 310 311 /* 312 * This looks up the /etc/vfstab entry given the device 'special'. 313 * It is called when the fstype is not specified on the command line. 314 * 315 * The following global variables are used: 316 * special, fstype 317 */ 318 319 lookup() 320 { 321 FILE *fd; 322 int ret; 323 struct vfstab vget, vref; 324 325 if ((fd = fopen(vfstab, "r")) == NULL) { 326 fprintf(stderr, gettext("%s: cannot open vfstab\n"), cbasename); 327 exit(1); 328 } 329 vfsnull(&vref); 330 vref.vfs_special = special; 331 ret = getvfsany(fd, &vget, &vref); 332 if (ret == -1) { 333 rewind(fd); 334 vfsnull(&vref); 335 vref.vfs_fsckdev = special; 336 ret = getvfsany(fd, &vget, &vref); 337 } 338 fclose(fd); 339 340 switch (ret) { 341 case -1: 342 fstype = default_fstype(special); 343 break; 344 case 0: 345 fstype = vget.vfs_fstype; 346 break; 347 case VFS_TOOLONG: 348 fprintf(stderr, 349 gettext("%s: line in vfstab exceeds %d characters\n"), 350 cbasename, VFS_LINE_MAX-2); 351 exit(1); 352 break; 353 case VFS_TOOFEW: 354 fprintf(stderr, 355 gettext("%s: line in vfstab has too few entries\n"), 356 cbasename); 357 exit(1); 358 break; 359 } 360 } 361 362 void 363 stat_snap(cmd, mountpoint, opts) 364 char *cmd; 365 char *mountpoint; 366 char *opts; 367 { 368 int fd; /* check mount point if given */ 369 int en; 370 char *errstr; 371 372 if (mountpoint) { 373 if ((fd = open(mountpoint, O_RDONLY)) < 0) { 374 en = errno; 375 errstr = strerror(errno); 376 if (errstr == NULL) 377 errstr = gettext("Unknown error"); 378 379 fprintf(stderr, gettext("%s: %s: error %d: %s\n"), 380 cmd, mountpoint, en, errstr); 381 382 exit(2); 383 } 384 close(fd); 385 } 386 fssnap_show_status(mountpoint, opts, 1, (opts ? 0 : 1)); 387 } 388