10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 230Sstevel@tonic-gate /* All Rights Reserved */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 27*767Ssjelinek * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 280Sstevel@tonic-gate * Use is subject to license terms. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <limits.h> 350Sstevel@tonic-gate #include <locale.h> 360Sstevel@tonic-gate #include <libintl.h> 370Sstevel@tonic-gate #include <sys/fstyp.h> 380Sstevel@tonic-gate #include <errno.h> 390Sstevel@tonic-gate #include <sys/vfstab.h> 400Sstevel@tonic-gate #include <sys/types.h> 410Sstevel@tonic-gate #include <sys/stat.h> 420Sstevel@tonic-gate #include <fcntl.h> 430Sstevel@tonic-gate #include <string.h> 44*767Ssjelinek #include <libdiskmgt.h> 45*767Ssjelinek #include "fslib.h" 46*767Ssjelinek 47*767Ssjelinek 48*767Ssjelinek static int match(char **opts, char *s); 490Sstevel@tonic-gate 500Sstevel@tonic-gate #define FSTYPE_MAX 8 510Sstevel@tonic-gate #define ARGV_MAX 1024 520Sstevel@tonic-gate #define VFS_PATH "/usr/lib/fs" 530Sstevel@tonic-gate #define ALT_PATH "/etc/fs" 540Sstevel@tonic-gate 550Sstevel@tonic-gate extern char *default_fstype(); 560Sstevel@tonic-gate void stat_snap(char *, char *, char *); 570Sstevel@tonic-gate char *special = NULL; /* device special name */ 580Sstevel@tonic-gate char *fstype = NULL; /* fstype name is filled in here */ 590Sstevel@tonic-gate char *cbasename; /* name of command */ 600Sstevel@tonic-gate char *newargv[ARGV_MAX]; /* args for the fstype specific command */ 610Sstevel@tonic-gate char vfstab[] = VFSTAB; 620Sstevel@tonic-gate int newargc = 2; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* 650Sstevel@tonic-gate * TRANSLATION_NOTE - the usage strings in the c_usgstr[] of the 660Sstevel@tonic-gate * following structures should be given a translation; the call to gettext 670Sstevel@tonic-gate * is in the usage() function. The strings are the ones containing 680Sstevel@tonic-gate * "[-F FSType]". 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate 710Sstevel@tonic-gate struct commands { 720Sstevel@tonic-gate char *c_basename; 730Sstevel@tonic-gate char *c_optstr; 740Sstevel@tonic-gate char *c_usgstr[4]; /* make sure as large as largest array size */ 750Sstevel@tonic-gate } cmd_data[] = { 760Sstevel@tonic-gate "clri", "F:o:?V", 770Sstevel@tonic-gate { 780Sstevel@tonic-gate "[-F FSType] [-V] special inumber ...", 790Sstevel@tonic-gate NULL 800Sstevel@tonic-gate }, 810Sstevel@tonic-gate "mkfs", "F:o:mb:?V", 820Sstevel@tonic-gate { 830Sstevel@tonic-gate "[-F FSType] [-V] [-m] [-o specific_options] special ", 840Sstevel@tonic-gate "[operands]", NULL 850Sstevel@tonic-gate }, 860Sstevel@tonic-gate "dcopy", "F:o:?V", 870Sstevel@tonic-gate { 880Sstevel@tonic-gate "[-F FSType] [-V] special inumber ...", 890Sstevel@tonic-gate NULL 900Sstevel@tonic-gate }, 910Sstevel@tonic-gate "fsdb", "F:o:z:?V", 920Sstevel@tonic-gate { 930Sstevel@tonic-gate "[-F FSType] [-V] [-o specific_options] special", 940Sstevel@tonic-gate NULL 950Sstevel@tonic-gate }, 960Sstevel@tonic-gate "fssnap", "F:dio:?V", 970Sstevel@tonic-gate { 980Sstevel@tonic-gate "[-F FSType] [-V] -o special_options /mount/point", 990Sstevel@tonic-gate "-d [-F FSType] [-V] /mount/point | dev", 1000Sstevel@tonic-gate "-i [-F FSType] [-V] [-o special-options] [/mount/point | dev]", 1010Sstevel@tonic-gate NULL 1020Sstevel@tonic-gate }, 1030Sstevel@tonic-gate "labelit", "F:o:?nV", 1040Sstevel@tonic-gate { 1050Sstevel@tonic-gate "[-F FSType] [-V] [-o specific_options] special [operands]", 1060Sstevel@tonic-gate NULL 1070Sstevel@tonic-gate }, 1080Sstevel@tonic-gate NULL, "F:o:?V", 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate "[-F FSType] [-V] [-o specific_options] special [operands]", 1110Sstevel@tonic-gate NULL 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate }; 1140Sstevel@tonic-gate struct commands *c_ptr; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate main(argc, argv) 1170Sstevel@tonic-gate int argc; 1180Sstevel@tonic-gate char *argv[]; 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate register char *ptr; 1210Sstevel@tonic-gate char full_path[PATH_MAX]; 1220Sstevel@tonic-gate char *vfs_path = VFS_PATH; 1230Sstevel@tonic-gate char *alt_path = ALT_PATH; 1240Sstevel@tonic-gate int i; 125*767Ssjelinek int j; 1260Sstevel@tonic-gate int verbose = 0; /* set if -V is specified */ 1270Sstevel@tonic-gate int F_flg = 0; 1280Sstevel@tonic-gate int mflag = 0; 129*767Ssjelinek int Nflag = 0; 1300Sstevel@tonic-gate char *oopts = NULL; 131*767Ssjelinek char *tmpopts = NULL; /* used for in use checking */ 1320Sstevel@tonic-gate int iflag = 0; 1330Sstevel@tonic-gate int usgflag = 0; 1340Sstevel@tonic-gate int arg; /* argument from getopt() */ 135*767Ssjelinek char *msg; 136*767Ssjelinek int error; 1370Sstevel@tonic-gate extern char *optarg; /* getopt specific */ 1380Sstevel@tonic-gate extern int optind; 1390Sstevel@tonic-gate extern int opterr; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1440Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1450Sstevel@tonic-gate #endif 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate cbasename = ptr = argv[0]; 1500Sstevel@tonic-gate while (*ptr) { 1510Sstevel@tonic-gate if (*ptr++ == '/') 1520Sstevel@tonic-gate cbasename = ptr; 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate if (argc == 1) { 1570Sstevel@tonic-gate for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) && 1580Sstevel@tonic-gate (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++) 1590Sstevel@tonic-gate ; 1600Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 1610Sstevel@tonic-gate exit(2); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) && 1650Sstevel@tonic-gate (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++) 1660Sstevel@tonic-gate ; 1670Sstevel@tonic-gate while ((arg = getopt(argc, argv, c_ptr->c_optstr)) != -1) { 1680Sstevel@tonic-gate switch (arg) { 1690Sstevel@tonic-gate case 'V': /* echo complete command line */ 1700Sstevel@tonic-gate verbose = 1; 1710Sstevel@tonic-gate break; 1720Sstevel@tonic-gate case 'F': /* FSType specified */ 1730Sstevel@tonic-gate F_flg++; 1740Sstevel@tonic-gate fstype = optarg; 1750Sstevel@tonic-gate break; 1760Sstevel@tonic-gate case 'o': /* FSType specific arguments */ 1770Sstevel@tonic-gate newargv[newargc++] = "-o"; 1780Sstevel@tonic-gate newargv[newargc++] = optarg; 1790Sstevel@tonic-gate oopts = optarg; 180*767Ssjelinek if (!Nflag) { 181*767Ssjelinek tmpopts = optarg; 182*767Ssjelinek Nflag = has_Nflag(tmpopts); 183*767Ssjelinek } 1840Sstevel@tonic-gate break; 1850Sstevel@tonic-gate case '?': /* print usage message */ 1860Sstevel@tonic-gate newargv[newargc++] = "-?"; 1870Sstevel@tonic-gate usgflag = 1; 1880Sstevel@tonic-gate break; 1890Sstevel@tonic-gate case 'm': /* FSType specific arguments */ 1900Sstevel@tonic-gate mflag = 1; 1910Sstevel@tonic-gate newargv[newargc] = (char *)malloc(3); 1920Sstevel@tonic-gate sprintf(newargv[newargc++], "-%c", arg); 1930Sstevel@tonic-gate if (optarg) 1940Sstevel@tonic-gate newargv[newargc++] = optarg; 1950Sstevel@tonic-gate break; 1960Sstevel@tonic-gate case 'i': /* fssnap only */ 1970Sstevel@tonic-gate iflag = 1; 1980Sstevel@tonic-gate /*FALLTHROUGH*/ 1990Sstevel@tonic-gate default: 2000Sstevel@tonic-gate newargv[newargc] = (char *)malloc(3); 2010Sstevel@tonic-gate sprintf(newargv[newargc++], "-%c", arg); 2020Sstevel@tonic-gate if (optarg) 2030Sstevel@tonic-gate newargv[newargc++] = optarg; 2040Sstevel@tonic-gate break; 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate optarg = NULL; 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate if (F_flg > 1) { 209*767Ssjelinek (void) fprintf(stderr, 210*767Ssjelinek gettext("%s: more than one FSType specified\n"), 211*767Ssjelinek cbasename); 2120Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2130Sstevel@tonic-gate exit(2); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate if (fstype != NULL) { 2160Sstevel@tonic-gate if (strlen(fstype) > FSTYPE_MAX) { 217*767Ssjelinek (void) fprintf(stderr, 2180Sstevel@tonic-gate gettext("%s: FSType %s exceeds %d characters\n"), 2190Sstevel@tonic-gate cbasename, fstype, FSTYPE_MAX); 2200Sstevel@tonic-gate exit(2); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* perform a lookup if fstype is not specified */ 2250Sstevel@tonic-gate special = argv[optind]; 2260Sstevel@tonic-gate optind++; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* handle -i (fssnap command only) */ 2290Sstevel@tonic-gate if (iflag) { 2300Sstevel@tonic-gate int diff = argc - optind; 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * There is no reason to ever call a file system specific 2330Sstevel@tonic-gate * version since its all in kstats. 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate if (diff > 0) /* gave more than one mountpoint or device */ 2360Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2370Sstevel@tonic-gate stat_snap(cbasename, diff == 0 ? argv[argc-1] : NULL, oopts); 2380Sstevel@tonic-gate exit(0); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate if ((special == NULL) && (!usgflag)) { 242*767Ssjelinek (void) fprintf(stderr, gettext("%s: special not specified\n"), 2430Sstevel@tonic-gate cbasename); 2440Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2450Sstevel@tonic-gate exit(2); 2460Sstevel@tonic-gate } 247*767Ssjelinek 2480Sstevel@tonic-gate if ((fstype == NULL) && (usgflag)) 2490Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2500Sstevel@tonic-gate if (fstype == NULL) 2510Sstevel@tonic-gate lookup(); 2520Sstevel@tonic-gate if (fstype == NULL) { 253*767Ssjelinek (void) fprintf(stderr, 254*767Ssjelinek gettext("%s: FSType cannot be identified\n"), cbasename); 2550Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2560Sstevel@tonic-gate exit(2); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate newargv[newargc++] = special; 2590Sstevel@tonic-gate for (; optind < argc; optind++) 2600Sstevel@tonic-gate newargv[newargc++] = argv[optind]; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* build the full pathname of the fstype dependent command */ 2630Sstevel@tonic-gate sprintf(full_path, "%s/%s/%s", vfs_path, fstype, cbasename); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate newargv[1] = cbasename; 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if (verbose) { 2680Sstevel@tonic-gate printf("%s -F %s ", cbasename, fstype); 2690Sstevel@tonic-gate for (i = 2; newargv[i]; i++) 2700Sstevel@tonic-gate printf("%s ", newargv[i]); 2710Sstevel@tonic-gate printf("\n"); 2720Sstevel@tonic-gate exit(0); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* 276*767Ssjelinek * Prior to executing the command for mkfs check for device in use. 277*767Ssjelinek * If the mflag is set, user wants to see command that created 278*767Ssjelinek * an already existing filesystem. Do not check for in use in this 279*767Ssjelinek * case. If Nflag is set user wants to see what the parameters 280*767Ssjelinek * would be to create the filesystem. Do not check for in use in 281*767Ssjelinek * this case. 282*767Ssjelinek */ 283*767Ssjelinek if (strcmp(cbasename, "mkfs") == 0 && !mflag && !Nflag) { 284*767Ssjelinek if (dm_inuse(special, &msg, DM_WHO_MKFS, &error) || 285*767Ssjelinek error) { 286*767Ssjelinek if (error != 0) { 287*767Ssjelinek (void) fprintf(stderr, gettext("Error occurred" 288*767Ssjelinek " with device in use checking: %s\n"), 289*767Ssjelinek strerror(error)); 290*767Ssjelinek } else { 291*767Ssjelinek (void) fprintf(stderr, "%s", msg); 292*767Ssjelinek free(msg); 293*767Ssjelinek exit(2); 294*767Ssjelinek } 295*767Ssjelinek } 296*767Ssjelinek } 297*767Ssjelinek 298*767Ssjelinek /* 2990Sstevel@tonic-gate * Execute the FSType specific command. 3000Sstevel@tonic-gate */ 3010Sstevel@tonic-gate execv(full_path, &newargv[1]); 3020Sstevel@tonic-gate if ((errno == ENOENT) || (errno == EACCES)) { 3030Sstevel@tonic-gate /* build the alternate pathname */ 3040Sstevel@tonic-gate sprintf(full_path, "%s/%s/%s", alt_path, fstype, cbasename); 3050Sstevel@tonic-gate if (verbose) { 3060Sstevel@tonic-gate printf("%s -F %s ", cbasename, fstype); 3070Sstevel@tonic-gate for (i = 2; newargv[i]; i++) 3080Sstevel@tonic-gate printf("%s ", newargv[i]); 3090Sstevel@tonic-gate printf("\n"); 3100Sstevel@tonic-gate exit(0); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate execv(full_path, &newargv[1]); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate if (errno == ENOEXEC) { 3150Sstevel@tonic-gate newargv[0] = "sh"; 3160Sstevel@tonic-gate newargv[1] = full_path; 3170Sstevel@tonic-gate execv("/sbin/sh", &newargv[0]); 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate if (errno != ENOENT) { 3200Sstevel@tonic-gate perror(cbasename); 321*767Ssjelinek (void) fprintf(stderr, gettext("%s: cannot execute %s\n"), 322*767Ssjelinek cbasename, full_path); 3230Sstevel@tonic-gate exit(2); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate if (sysfs(GETFSIND, fstype) == (-1)) { 327*767Ssjelinek (void) fprintf(stderr, 3280Sstevel@tonic-gate gettext("%s: FSType %s not installed in the kernel\n"), 3290Sstevel@tonic-gate cbasename, fstype); 3300Sstevel@tonic-gate exit(2); 3310Sstevel@tonic-gate } 332*767Ssjelinek (void) fprintf(stderr, 3330Sstevel@tonic-gate gettext("%s: Operation not applicable for FSType %s \n"), 3340Sstevel@tonic-gate cbasename, fstype); 3350Sstevel@tonic-gate exit(2); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate usage(cmd, usg) 3390Sstevel@tonic-gate char *cmd; 3400Sstevel@tonic-gate char **usg; 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate int i; 343*767Ssjelinek (void) fprintf(stderr, gettext("Usage:\n")); 3440Sstevel@tonic-gate for (i = 0; usg[i] != NULL; i++) 345*767Ssjelinek (void) fprintf(stderr, "%s %s\n", gettext(cmd), 346*767Ssjelinek gettext(usg[i])); 3470Sstevel@tonic-gate exit(2); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate /* 3520Sstevel@tonic-gate * This looks up the /etc/vfstab entry given the device 'special'. 3530Sstevel@tonic-gate * It is called when the fstype is not specified on the command line. 3540Sstevel@tonic-gate * 3550Sstevel@tonic-gate * The following global variables are used: 3560Sstevel@tonic-gate * special, fstype 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate lookup() 3600Sstevel@tonic-gate { 3610Sstevel@tonic-gate FILE *fd; 3620Sstevel@tonic-gate int ret; 3630Sstevel@tonic-gate struct vfstab vget, vref; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate if ((fd = fopen(vfstab, "r")) == NULL) { 366*767Ssjelinek (void) fprintf(stderr, gettext("%s: cannot open vfstab\n"), 367*767Ssjelinek cbasename); 3680Sstevel@tonic-gate exit(1); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate vfsnull(&vref); 3710Sstevel@tonic-gate vref.vfs_special = special; 3720Sstevel@tonic-gate ret = getvfsany(fd, &vget, &vref); 3730Sstevel@tonic-gate if (ret == -1) { 3740Sstevel@tonic-gate rewind(fd); 3750Sstevel@tonic-gate vfsnull(&vref); 3760Sstevel@tonic-gate vref.vfs_fsckdev = special; 3770Sstevel@tonic-gate ret = getvfsany(fd, &vget, &vref); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate fclose(fd); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate switch (ret) { 3820Sstevel@tonic-gate case -1: 3830Sstevel@tonic-gate fstype = default_fstype(special); 3840Sstevel@tonic-gate break; 3850Sstevel@tonic-gate case 0: 3860Sstevel@tonic-gate fstype = vget.vfs_fstype; 3870Sstevel@tonic-gate break; 3880Sstevel@tonic-gate case VFS_TOOLONG: 389*767Ssjelinek (void) fprintf(stderr, 3900Sstevel@tonic-gate gettext("%s: line in vfstab exceeds %d characters\n"), 3910Sstevel@tonic-gate cbasename, VFS_LINE_MAX-2); 3920Sstevel@tonic-gate exit(1); 3930Sstevel@tonic-gate break; 3940Sstevel@tonic-gate case VFS_TOOFEW: 395*767Ssjelinek (void) fprintf(stderr, 3960Sstevel@tonic-gate gettext("%s: line in vfstab has too few entries\n"), 3970Sstevel@tonic-gate cbasename); 3980Sstevel@tonic-gate exit(1); 3990Sstevel@tonic-gate break; 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate void 4040Sstevel@tonic-gate stat_snap(cmd, mountpoint, opts) 4050Sstevel@tonic-gate char *cmd; 4060Sstevel@tonic-gate char *mountpoint; 4070Sstevel@tonic-gate char *opts; 4080Sstevel@tonic-gate { 4090Sstevel@tonic-gate int fd; /* check mount point if given */ 4100Sstevel@tonic-gate int en; 4110Sstevel@tonic-gate char *errstr; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate if (mountpoint) { 4140Sstevel@tonic-gate if ((fd = open(mountpoint, O_RDONLY)) < 0) { 4150Sstevel@tonic-gate en = errno; 4160Sstevel@tonic-gate errstr = strerror(errno); 4170Sstevel@tonic-gate if (errstr == NULL) 4180Sstevel@tonic-gate errstr = gettext("Unknown error"); 4190Sstevel@tonic-gate 420*767Ssjelinek (void) fprintf(stderr, 421*767Ssjelinek gettext("%s: %s: error %d: %s\n"), 422*767Ssjelinek cmd, mountpoint, en, errstr); 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate exit(2); 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate close(fd); 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate fssnap_show_status(mountpoint, opts, 1, (opts ? 0 : 1)); 4290Sstevel@tonic-gate } 430*767Ssjelinek static int 431*767Ssjelinek has_Nflag(char *opts) 432*767Ssjelinek { 433*767Ssjelinek while (opts != NULL && *opts != '\0') { 434*767Ssjelinek if (match(&opts, "N")) { 435*767Ssjelinek return (1); 436*767Ssjelinek } 437*767Ssjelinek if (!opts) 438*767Ssjelinek break; 439*767Ssjelinek if (*opts == ',') 440*767Ssjelinek opts ++; 441*767Ssjelinek if (*opts == ' ') 442*767Ssjelinek opts ++; 443*767Ssjelinek } 444*767Ssjelinek return (0); 445*767Ssjelinek } 446*767Ssjelinek /* 447*767Ssjelinek * Parses the -o [fs specific options string] to search for the UFS -N flag. 448*767Ssjelinek * Return the opts string pointing to the next position in the string if 449*767Ssjelinek * match is not found. A delimiter of , or ' ' can be used depending on the 450*767Ssjelinek * caller, newfs or mkfs. 451*767Ssjelinek */ 452*767Ssjelinek static int 453*767Ssjelinek match(char **opts, char *s) 454*767Ssjelinek { 455*767Ssjelinek char *cs; 456*767Ssjelinek char *tmp_str; 457*767Ssjelinek 458*767Ssjelinek cs = *opts; 459*767Ssjelinek 460*767Ssjelinek while (*cs++ == *s) { 461*767Ssjelinek if (*s++ == '\0') { 462*767Ssjelinek goto true; 463*767Ssjelinek } 464*767Ssjelinek } 465*767Ssjelinek if (*s != '\0') { 466*767Ssjelinek /* 467*767Ssjelinek * If we cannot find the delimiter it means we 468*767Ssjelinek * have hit the end of the string. 469*767Ssjelinek */ 470*767Ssjelinek tmp_str = strchr(*opts, ','); 471*767Ssjelinek if (!tmp_str) 472*767Ssjelinek tmp_str = strchr(*opts, ' '); 473*767Ssjelinek 474*767Ssjelinek *opts = tmp_str; 475*767Ssjelinek return (0); 476*767Ssjelinek } 477*767Ssjelinek true: 478*767Ssjelinek cs--; 479*767Ssjelinek *opts = cs; 480*767Ssjelinek return (1); 481*767Ssjelinek } 482