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 /* 27767Ssjelinek * 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> 44767Ssjelinek #include <libdiskmgt.h> 45767Ssjelinek #include "fslib.h" 46767Ssjelinek 47767Ssjelinek 48767Ssjelinek 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 116*821Sdh145677 static void usage(char *cmd, char **usg); 117*821Sdh145677 static void lookup(void); 118*821Sdh145677 119*821Sdh145677 int 120*821Sdh145677 main(int argc, char *argv[]) 1210Sstevel@tonic-gate { 122*821Sdh145677 char *ptr; 1230Sstevel@tonic-gate char full_path[PATH_MAX]; 1240Sstevel@tonic-gate char *vfs_path = VFS_PATH; 1250Sstevel@tonic-gate char *alt_path = ALT_PATH; 1260Sstevel@tonic-gate int i; 127767Ssjelinek int j; 1280Sstevel@tonic-gate int verbose = 0; /* set if -V is specified */ 1290Sstevel@tonic-gate int F_flg = 0; 1300Sstevel@tonic-gate int mflag = 0; 131767Ssjelinek int Nflag = 0; 1320Sstevel@tonic-gate char *oopts = NULL; 133767Ssjelinek char *tmpopts = NULL; /* used for in use checking */ 1340Sstevel@tonic-gate int iflag = 0; 1350Sstevel@tonic-gate int usgflag = 0; 1360Sstevel@tonic-gate int arg; /* argument from getopt() */ 137767Ssjelinek char *msg; 138767Ssjelinek int error; 1390Sstevel@tonic-gate extern char *optarg; /* getopt specific */ 1400Sstevel@tonic-gate extern int optind; 1410Sstevel@tonic-gate extern int opterr; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1460Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1470Sstevel@tonic-gate #endif 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate cbasename = ptr = argv[0]; 1520Sstevel@tonic-gate while (*ptr) { 1530Sstevel@tonic-gate if (*ptr++ == '/') 1540Sstevel@tonic-gate cbasename = ptr; 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate if (argc == 1) { 1590Sstevel@tonic-gate for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) && 1600Sstevel@tonic-gate (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++) 1610Sstevel@tonic-gate ; 1620Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 1630Sstevel@tonic-gate exit(2); 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate for (c_ptr = cmd_data; ((c_ptr->c_basename != NULL) && 1670Sstevel@tonic-gate (strcmp(c_ptr->c_basename, cbasename) != 0)); c_ptr++) 1680Sstevel@tonic-gate ; 1690Sstevel@tonic-gate while ((arg = getopt(argc, argv, c_ptr->c_optstr)) != -1) { 1700Sstevel@tonic-gate switch (arg) { 1710Sstevel@tonic-gate case 'V': /* echo complete command line */ 1720Sstevel@tonic-gate verbose = 1; 1730Sstevel@tonic-gate break; 1740Sstevel@tonic-gate case 'F': /* FSType specified */ 1750Sstevel@tonic-gate F_flg++; 1760Sstevel@tonic-gate fstype = optarg; 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate case 'o': /* FSType specific arguments */ 1790Sstevel@tonic-gate newargv[newargc++] = "-o"; 1800Sstevel@tonic-gate newargv[newargc++] = optarg; 1810Sstevel@tonic-gate oopts = optarg; 182767Ssjelinek if (!Nflag) { 183767Ssjelinek tmpopts = optarg; 184767Ssjelinek Nflag = has_Nflag(tmpopts); 185767Ssjelinek } 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate case '?': /* print usage message */ 1880Sstevel@tonic-gate newargv[newargc++] = "-?"; 1890Sstevel@tonic-gate usgflag = 1; 1900Sstevel@tonic-gate break; 1910Sstevel@tonic-gate case 'm': /* FSType specific arguments */ 1920Sstevel@tonic-gate mflag = 1; 1930Sstevel@tonic-gate newargv[newargc] = (char *)malloc(3); 1940Sstevel@tonic-gate sprintf(newargv[newargc++], "-%c", arg); 1950Sstevel@tonic-gate if (optarg) 1960Sstevel@tonic-gate newargv[newargc++] = optarg; 1970Sstevel@tonic-gate break; 1980Sstevel@tonic-gate case 'i': /* fssnap only */ 1990Sstevel@tonic-gate iflag = 1; 2000Sstevel@tonic-gate /*FALLTHROUGH*/ 2010Sstevel@tonic-gate default: 2020Sstevel@tonic-gate newargv[newargc] = (char *)malloc(3); 2030Sstevel@tonic-gate sprintf(newargv[newargc++], "-%c", arg); 2040Sstevel@tonic-gate if (optarg) 2050Sstevel@tonic-gate newargv[newargc++] = optarg; 2060Sstevel@tonic-gate break; 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate optarg = NULL; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate if (F_flg > 1) { 211767Ssjelinek (void) fprintf(stderr, 212767Ssjelinek gettext("%s: more than one FSType specified\n"), 213767Ssjelinek cbasename); 2140Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2150Sstevel@tonic-gate exit(2); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate if (fstype != NULL) { 2180Sstevel@tonic-gate if (strlen(fstype) > FSTYPE_MAX) { 219767Ssjelinek (void) fprintf(stderr, 2200Sstevel@tonic-gate gettext("%s: FSType %s exceeds %d characters\n"), 2210Sstevel@tonic-gate cbasename, fstype, FSTYPE_MAX); 2220Sstevel@tonic-gate exit(2); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* perform a lookup if fstype is not specified */ 2270Sstevel@tonic-gate special = argv[optind]; 2280Sstevel@tonic-gate optind++; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* handle -i (fssnap command only) */ 2310Sstevel@tonic-gate if (iflag) { 2320Sstevel@tonic-gate int diff = argc - optind; 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * There is no reason to ever call a file system specific 2350Sstevel@tonic-gate * version since its all in kstats. 2360Sstevel@tonic-gate */ 2370Sstevel@tonic-gate if (diff > 0) /* gave more than one mountpoint or device */ 2380Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2390Sstevel@tonic-gate stat_snap(cbasename, diff == 0 ? argv[argc-1] : NULL, oopts); 2400Sstevel@tonic-gate exit(0); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate if ((special == NULL) && (!usgflag)) { 244767Ssjelinek (void) fprintf(stderr, gettext("%s: special not specified\n"), 2450Sstevel@tonic-gate cbasename); 2460Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2470Sstevel@tonic-gate exit(2); 2480Sstevel@tonic-gate } 249767Ssjelinek 2500Sstevel@tonic-gate if ((fstype == NULL) && (usgflag)) 2510Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2520Sstevel@tonic-gate if (fstype == NULL) 2530Sstevel@tonic-gate lookup(); 2540Sstevel@tonic-gate if (fstype == NULL) { 255767Ssjelinek (void) fprintf(stderr, 256767Ssjelinek gettext("%s: FSType cannot be identified\n"), cbasename); 2570Sstevel@tonic-gate usage(cbasename, c_ptr->c_usgstr); 2580Sstevel@tonic-gate exit(2); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate newargv[newargc++] = special; 2610Sstevel@tonic-gate for (; optind < argc; optind++) 2620Sstevel@tonic-gate newargv[newargc++] = argv[optind]; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate /* build the full pathname of the fstype dependent command */ 2650Sstevel@tonic-gate sprintf(full_path, "%s/%s/%s", vfs_path, fstype, cbasename); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate newargv[1] = cbasename; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if (verbose) { 2700Sstevel@tonic-gate printf("%s -F %s ", cbasename, fstype); 2710Sstevel@tonic-gate for (i = 2; newargv[i]; i++) 2720Sstevel@tonic-gate printf("%s ", newargv[i]); 2730Sstevel@tonic-gate printf("\n"); 2740Sstevel@tonic-gate exit(0); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 278767Ssjelinek * Prior to executing the command for mkfs check for device in use. 279767Ssjelinek * If the mflag is set, user wants to see command that created 280767Ssjelinek * an already existing filesystem. Do not check for in use in this 281767Ssjelinek * case. If Nflag is set user wants to see what the parameters 282767Ssjelinek * would be to create the filesystem. Do not check for in use in 283767Ssjelinek * this case. 284767Ssjelinek */ 285767Ssjelinek if (strcmp(cbasename, "mkfs") == 0 && !mflag && !Nflag) { 286767Ssjelinek if (dm_inuse(special, &msg, DM_WHO_MKFS, &error) || 287767Ssjelinek error) { 288767Ssjelinek if (error != 0) { 289767Ssjelinek (void) fprintf(stderr, gettext("Error occurred" 290767Ssjelinek " with device in use checking: %s\n"), 291767Ssjelinek strerror(error)); 292767Ssjelinek } else { 293767Ssjelinek (void) fprintf(stderr, "%s", msg); 294767Ssjelinek free(msg); 295767Ssjelinek exit(2); 296767Ssjelinek } 297767Ssjelinek } 298767Ssjelinek } 299767Ssjelinek 300767Ssjelinek /* 3010Sstevel@tonic-gate * Execute the FSType specific command. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate execv(full_path, &newargv[1]); 3040Sstevel@tonic-gate if ((errno == ENOENT) || (errno == EACCES)) { 3050Sstevel@tonic-gate /* build the alternate pathname */ 3060Sstevel@tonic-gate sprintf(full_path, "%s/%s/%s", alt_path, fstype, cbasename); 3070Sstevel@tonic-gate if (verbose) { 3080Sstevel@tonic-gate printf("%s -F %s ", cbasename, fstype); 3090Sstevel@tonic-gate for (i = 2; newargv[i]; i++) 3100Sstevel@tonic-gate printf("%s ", newargv[i]); 3110Sstevel@tonic-gate printf("\n"); 3120Sstevel@tonic-gate exit(0); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate execv(full_path, &newargv[1]); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate if (errno == ENOEXEC) { 3170Sstevel@tonic-gate newargv[0] = "sh"; 3180Sstevel@tonic-gate newargv[1] = full_path; 3190Sstevel@tonic-gate execv("/sbin/sh", &newargv[0]); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate if (errno != ENOENT) { 3220Sstevel@tonic-gate perror(cbasename); 323767Ssjelinek (void) fprintf(stderr, gettext("%s: cannot execute %s\n"), 324767Ssjelinek cbasename, full_path); 3250Sstevel@tonic-gate exit(2); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate if (sysfs(GETFSIND, fstype) == (-1)) { 329767Ssjelinek (void) fprintf(stderr, 3300Sstevel@tonic-gate gettext("%s: FSType %s not installed in the kernel\n"), 3310Sstevel@tonic-gate cbasename, fstype); 3320Sstevel@tonic-gate exit(2); 3330Sstevel@tonic-gate } 334767Ssjelinek (void) fprintf(stderr, 3350Sstevel@tonic-gate gettext("%s: Operation not applicable for FSType %s \n"), 3360Sstevel@tonic-gate cbasename, fstype); 337*821Sdh145677 return (2); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 340*821Sdh145677 static void 341*821Sdh145677 usage(char *cmd, char **usg) 3420Sstevel@tonic-gate { 3430Sstevel@tonic-gate int i; 344767Ssjelinek (void) fprintf(stderr, gettext("Usage:\n")); 3450Sstevel@tonic-gate for (i = 0; usg[i] != NULL; i++) 346767Ssjelinek (void) fprintf(stderr, "%s %s\n", gettext(cmd), 347767Ssjelinek gettext(usg[i])); 3480Sstevel@tonic-gate exit(2); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * This looks up the /etc/vfstab entry given the device 'special'. 3540Sstevel@tonic-gate * It is called when the fstype is not specified on the command line. 3550Sstevel@tonic-gate * 3560Sstevel@tonic-gate * The following global variables are used: 3570Sstevel@tonic-gate * special, fstype 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate 360*821Sdh145677 static void 361*821Sdh145677 lookup(void) 3620Sstevel@tonic-gate { 3630Sstevel@tonic-gate FILE *fd; 3640Sstevel@tonic-gate int ret; 3650Sstevel@tonic-gate struct vfstab vget, vref; 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate if ((fd = fopen(vfstab, "r")) == NULL) { 368767Ssjelinek (void) fprintf(stderr, gettext("%s: cannot open vfstab\n"), 369767Ssjelinek cbasename); 3700Sstevel@tonic-gate exit(1); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate vfsnull(&vref); 3730Sstevel@tonic-gate vref.vfs_special = special; 3740Sstevel@tonic-gate ret = getvfsany(fd, &vget, &vref); 3750Sstevel@tonic-gate if (ret == -1) { 3760Sstevel@tonic-gate rewind(fd); 3770Sstevel@tonic-gate vfsnull(&vref); 3780Sstevel@tonic-gate vref.vfs_fsckdev = special; 3790Sstevel@tonic-gate ret = getvfsany(fd, &vget, &vref); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate fclose(fd); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate switch (ret) { 3840Sstevel@tonic-gate case -1: 3850Sstevel@tonic-gate fstype = default_fstype(special); 3860Sstevel@tonic-gate break; 3870Sstevel@tonic-gate case 0: 3880Sstevel@tonic-gate fstype = vget.vfs_fstype; 3890Sstevel@tonic-gate break; 3900Sstevel@tonic-gate case VFS_TOOLONG: 391767Ssjelinek (void) fprintf(stderr, 3920Sstevel@tonic-gate gettext("%s: line in vfstab exceeds %d characters\n"), 3930Sstevel@tonic-gate cbasename, VFS_LINE_MAX-2); 3940Sstevel@tonic-gate exit(1); 3950Sstevel@tonic-gate break; 3960Sstevel@tonic-gate case VFS_TOOFEW: 397767Ssjelinek (void) fprintf(stderr, 3980Sstevel@tonic-gate gettext("%s: line in vfstab has too few entries\n"), 3990Sstevel@tonic-gate cbasename); 4000Sstevel@tonic-gate exit(1); 4010Sstevel@tonic-gate break; 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate void 406*821Sdh145677 stat_snap(char *cmd, char *mountpoint, char *opts) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate int fd; /* check mount point if given */ 4090Sstevel@tonic-gate int en; 4100Sstevel@tonic-gate char *errstr; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if (mountpoint) { 4130Sstevel@tonic-gate if ((fd = open(mountpoint, O_RDONLY)) < 0) { 4140Sstevel@tonic-gate en = errno; 4150Sstevel@tonic-gate errstr = strerror(errno); 4160Sstevel@tonic-gate if (errstr == NULL) 4170Sstevel@tonic-gate errstr = gettext("Unknown error"); 4180Sstevel@tonic-gate 419767Ssjelinek (void) fprintf(stderr, 420767Ssjelinek gettext("%s: %s: error %d: %s\n"), 421767Ssjelinek cmd, mountpoint, en, errstr); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate exit(2); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate close(fd); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate fssnap_show_status(mountpoint, opts, 1, (opts ? 0 : 1)); 4280Sstevel@tonic-gate } 429767Ssjelinek static int 430767Ssjelinek has_Nflag(char *opts) 431767Ssjelinek { 432767Ssjelinek while (opts != NULL && *opts != '\0') { 433767Ssjelinek if (match(&opts, "N")) { 434767Ssjelinek return (1); 435767Ssjelinek } 436767Ssjelinek if (!opts) 437767Ssjelinek break; 438767Ssjelinek if (*opts == ',') 439767Ssjelinek opts ++; 440767Ssjelinek if (*opts == ' ') 441767Ssjelinek opts ++; 442767Ssjelinek } 443767Ssjelinek return (0); 444767Ssjelinek } 445767Ssjelinek /* 446767Ssjelinek * Parses the -o [fs specific options string] to search for the UFS -N flag. 447767Ssjelinek * Return the opts string pointing to the next position in the string if 448767Ssjelinek * match is not found. A delimiter of , or ' ' can be used depending on the 449767Ssjelinek * caller, newfs or mkfs. 450767Ssjelinek */ 451767Ssjelinek static int 452767Ssjelinek match(char **opts, char *s) 453767Ssjelinek { 454767Ssjelinek char *cs; 455767Ssjelinek char *tmp_str; 456767Ssjelinek 457767Ssjelinek cs = *opts; 458767Ssjelinek 459767Ssjelinek while (*cs++ == *s) { 460767Ssjelinek if (*s++ == '\0') { 461767Ssjelinek goto true; 462767Ssjelinek } 463767Ssjelinek } 464767Ssjelinek if (*s != '\0') { 465767Ssjelinek /* 466767Ssjelinek * If we cannot find the delimiter it means we 467767Ssjelinek * have hit the end of the string. 468767Ssjelinek */ 469767Ssjelinek tmp_str = strchr(*opts, ','); 470767Ssjelinek if (!tmp_str) 471767Ssjelinek tmp_str = strchr(*opts, ' '); 472767Ssjelinek 473767Ssjelinek *opts = tmp_str; 474767Ssjelinek return (0); 475767Ssjelinek } 476767Ssjelinek true: 477767Ssjelinek cs--; 478767Ssjelinek *opts = cs; 479767Ssjelinek return (1); 480767Ssjelinek } 481