17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*d1a180b0Smaheshvs * Common Development and Distribution License (the "License"). 6*d1a180b0Smaheshvs * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*d1a180b0Smaheshvs * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <unistd.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <strings.h> 337c478bd9Sstevel@tonic-gate #include <fcntl.h> 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/stat.h> 377c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 387c478bd9Sstevel@tonic-gate #include <sys/fssnap_if.h> 397c478bd9Sstevel@tonic-gate #include <sys/filio.h> 407c478bd9Sstevel@tonic-gate #include <setjmp.h> 417c478bd9Sstevel@tonic-gate #include <stdarg.h> 427c478bd9Sstevel@tonic-gate #include <kstat.h> 437c478bd9Sstevel@tonic-gate #include <libintl.h> 447c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 457c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 467c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 477c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_snap.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define SNAP_CTL_PATH "/dev/" SNAP_CTL_NAME 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate #define MAX_SUFFIX 6 /* '.' + 4 chars of number + trailing '\0' */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate static int max_uniq = 9999; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate void create_snap(int, char *, u_offset_t, uint_t, int, int); 587c478bd9Sstevel@tonic-gate void delete_snap(int); 597c478bd9Sstevel@tonic-gate void stats_snap(char *, char *); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate int open_backpath(int, u_offset_t, char **, char **, int **); 627c478bd9Sstevel@tonic-gate u_offset_t spec_to_bytes(char *); 637c478bd9Sstevel@tonic-gate void gen_backing_store_path(char *basepath, int num, char **outpath); 647c478bd9Sstevel@tonic-gate void unlink_all(char *, int); 657c478bd9Sstevel@tonic-gate void close_all(char *, int, int *); 667c478bd9Sstevel@tonic-gate int open_multi_backfile(char *, int, int **, int); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate void die_perror(char *); 697c478bd9Sstevel@tonic-gate void die_errno(int, char *, ...); 707c478bd9Sstevel@tonic-gate void die_create_error(int error); 717c478bd9Sstevel@tonic-gate void die_usage(void); 727c478bd9Sstevel@tonic-gate void die(char *, ...); 737c478bd9Sstevel@tonic-gate void warn_errno(int, char *, ...); 747c478bd9Sstevel@tonic-gate void usage(void); 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static char *subopts[] = { 777c478bd9Sstevel@tonic-gate #define BACKPATH (0) 787c478bd9Sstevel@tonic-gate "backing-store", 797c478bd9Sstevel@tonic-gate #define BACKPATH2 (1) 807c478bd9Sstevel@tonic-gate "bs", 817c478bd9Sstevel@tonic-gate #define BACKPATH3 (2) 827c478bd9Sstevel@tonic-gate "bf", 837c478bd9Sstevel@tonic-gate #define MAXSIZE (3) 847c478bd9Sstevel@tonic-gate "maxsize", 857c478bd9Sstevel@tonic-gate #define CHUNKSIZE (4) 867c478bd9Sstevel@tonic-gate "chunksize", 877c478bd9Sstevel@tonic-gate #define RAWFILE (5) 887c478bd9Sstevel@tonic-gate "raw", 897c478bd9Sstevel@tonic-gate #define UNLINK (6) 907c478bd9Sstevel@tonic-gate "unlink", 917c478bd9Sstevel@tonic-gate NULL 927c478bd9Sstevel@tonic-gate }; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static jmp_buf err_main; 957c478bd9Sstevel@tonic-gate static char *progname = NULL; 96*d1a180b0Smaheshvs static int backout_snap_fd = -1; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate extern void fssnap_show_status(char *mountpoint, char *opts, int labels, 997c478bd9Sstevel@tonic-gate int brief); /* in ../../fssnapsup.c */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate int 1027c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate int c; 1057c478bd9Sstevel@tonic-gate char *suboptions = NULL; 1067c478bd9Sstevel@tonic-gate char *value; 1077c478bd9Sstevel@tonic-gate int longjmp_return; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate char *mountpoint = NULL; 1107c478bd9Sstevel@tonic-gate int mountfd = -1; 1117c478bd9Sstevel@tonic-gate char *backpath = NULL; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate int delete = 0; 1147c478bd9Sstevel@tonic-gate int stats = 0; 1157c478bd9Sstevel@tonic-gate u_offset_t maxsize = 0; 1167c478bd9Sstevel@tonic-gate uint_t chunksize = 0; 1177c478bd9Sstevel@tonic-gate int rawfile = 0; 1187c478bd9Sstevel@tonic-gate int dounlink = 0; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) != NULL) 1217c478bd9Sstevel@tonic-gate ++progname; 1227c478bd9Sstevel@tonic-gate else 1237c478bd9Sstevel@tonic-gate progname = argv[0]; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if ((longjmp_return = setjmp(err_main)) != 0) { 1267c478bd9Sstevel@tonic-gate if (backout_snap_fd >= 0) { 1277c478bd9Sstevel@tonic-gate mountfd = backout_snap_fd; 1287c478bd9Sstevel@tonic-gate backout_snap_fd = -1; /* prevent infinite loop */ 1297c478bd9Sstevel@tonic-gate delete_snap(mountfd); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate return (longjmp_return); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "dio:")) != EOF) { 1367c478bd9Sstevel@tonic-gate switch (c) { 1377c478bd9Sstevel@tonic-gate case 'd': 1387c478bd9Sstevel@tonic-gate ++delete; 1397c478bd9Sstevel@tonic-gate break; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate case 'i': 1427c478bd9Sstevel@tonic-gate ++stats; 1437c478bd9Sstevel@tonic-gate break; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate case 'o': 1467c478bd9Sstevel@tonic-gate suboptions = optarg; 1477c478bd9Sstevel@tonic-gate break; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate default: 1507c478bd9Sstevel@tonic-gate die_usage(); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* if -i or -d are not specified then interpret the create options */ 1557c478bd9Sstevel@tonic-gate if ((stats == 0) && (delete == 0) && (suboptions != NULL)) { 1567c478bd9Sstevel@tonic-gate while (*suboptions != '\0') { 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate switch ((getsubopt(&suboptions, subopts, &value))) { 1597c478bd9Sstevel@tonic-gate case BACKPATH: 1607c478bd9Sstevel@tonic-gate case BACKPATH2: 1617c478bd9Sstevel@tonic-gate case BACKPATH3: 1627c478bd9Sstevel@tonic-gate if (value == NULL) 1637c478bd9Sstevel@tonic-gate die_usage(); 1647c478bd9Sstevel@tonic-gate backpath = strdup(value); 1657c478bd9Sstevel@tonic-gate if (backpath == NULL) { 1667c478bd9Sstevel@tonic-gate die_perror("strdup"); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate break; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate case MAXSIZE: 1717c478bd9Sstevel@tonic-gate maxsize = spec_to_bytes(value); 1727c478bd9Sstevel@tonic-gate break; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate case CHUNKSIZE: 1757c478bd9Sstevel@tonic-gate chunksize = spec_to_bytes(value); 1767c478bd9Sstevel@tonic-gate break; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate case RAWFILE: 1797c478bd9Sstevel@tonic-gate ++rawfile; 1807c478bd9Sstevel@tonic-gate break; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate case UNLINK: 1837c478bd9Sstevel@tonic-gate ++dounlink; 1847c478bd9Sstevel@tonic-gate break; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate default: 1877c478bd9Sstevel@tonic-gate die_usage(); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* -d and -i can not be specified together or more than once each */ 1937c478bd9Sstevel@tonic-gate if ((delete + stats) > 1) 1947c478bd9Sstevel@tonic-gate die_usage(); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* If no mount point is specified then -i is the only valid option. */ 1977c478bd9Sstevel@tonic-gate if ((optind >= argc) && (stats == 0)) 1987c478bd9Sstevel@tonic-gate die_usage(); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * If anything but the mount point or device is specified at the end 2027c478bd9Sstevel@tonic-gate * it's an error. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate if (optind != (argc - 1)) { 2057c478bd9Sstevel@tonic-gate if (!stats) 2067c478bd9Sstevel@tonic-gate die_usage(); 2077c478bd9Sstevel@tonic-gate } else { 2087c478bd9Sstevel@tonic-gate /* Otherwise, the last option is the mountpoint. */ 2097c478bd9Sstevel@tonic-gate mountpoint = argv[optind]; 2107c478bd9Sstevel@tonic-gate if ((mountfd = open(mountpoint, O_RDONLY)) < 0) 2117c478bd9Sstevel@tonic-gate die_perror(mountpoint); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate if (stats != 0) { 2157c478bd9Sstevel@tonic-gate stats_snap(mountpoint, suboptions); 2167c478bd9Sstevel@tonic-gate } else if (delete != 0) { 2177c478bd9Sstevel@tonic-gate delete_snap(mountfd); 2187c478bd9Sstevel@tonic-gate } else { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * backpath may be invalid upon return of create_snap call. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate create_snap(mountfd, backpath, maxsize, chunksize, 2237c478bd9Sstevel@tonic-gate rawfile, dounlink); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate return (0); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate void 2307c478bd9Sstevel@tonic-gate create_snap(int mountfd, char *backpath, u_offset_t maxsize, uint_t chunksize, 2317c478bd9Sstevel@tonic-gate int rawfile, int dounlink) 2327c478bd9Sstevel@tonic-gate { 2337c478bd9Sstevel@tonic-gate struct fiosnapcreate_multi *enable; 2347c478bd9Sstevel@tonic-gate int backcount; 2357c478bd9Sstevel@tonic-gate int ctlfd; 2367c478bd9Sstevel@tonic-gate char *unlinkpath = NULL; 2377c478bd9Sstevel@tonic-gate di_devlink_handle_t hdl; 2387c478bd9Sstevel@tonic-gate int *fd_array; 2397c478bd9Sstevel@tonic-gate u_offset_t max_bf_size; 2407c478bd9Sstevel@tonic-gate int save_errno; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * If chunksize is not a power of 2, the maximum size of a 2447c478bd9Sstevel@tonic-gate * backing store file might not be UFS_MAX_SNAPBACKFILESIZE, 2457c478bd9Sstevel@tonic-gate * since the size of the backing store files must be an 2467c478bd9Sstevel@tonic-gate * integral number of chunks (except for the last one). So 2477c478bd9Sstevel@tonic-gate * calculate the actual maximum backing store file size. 2487c478bd9Sstevel@tonic-gate * (It would be nice if we could assume that the chunksize 2497c478bd9Sstevel@tonic-gate * was a power of 2, but we can't.) 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if (chunksize != 0 && !POWEROF2(chunksize)) 2537c478bd9Sstevel@tonic-gate max_bf_size = (UFS_MAX_SNAPBACKFILESIZE/chunksize) * chunksize; 2547c478bd9Sstevel@tonic-gate else 2557c478bd9Sstevel@tonic-gate max_bf_size = UFS_MAX_SNAPBACKFILESIZE; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * open_backpath() only returns on success, and 2597c478bd9Sstevel@tonic-gate * can change the value of backpath when backpath 2607c478bd9Sstevel@tonic-gate * references a directory. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate if (backpath == NULL) 2637c478bd9Sstevel@tonic-gate die(gettext("No backing store path specified.\n")); 2647c478bd9Sstevel@tonic-gate backcount = open_backpath(mountfd, max_bf_size, &backpath, 2657c478bd9Sstevel@tonic-gate &unlinkpath, &fd_array); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * Only need backcount - 1 spaces for fd's since 2697c478bd9Sstevel@tonic-gate * fiosnapcreate_multi struct contains space for the 2707c478bd9Sstevel@tonic-gate * first one. 2717c478bd9Sstevel@tonic-gate */ 2727c478bd9Sstevel@tonic-gate if ((enable = calloc(1, sizeof (struct fiosnapcreate_multi) + 2737c478bd9Sstevel@tonic-gate (backcount - 1) * sizeof (int))) == NULL) 2747c478bd9Sstevel@tonic-gate die(gettext("Insufficient memory.\n")); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate enable->backfilecount = backcount; 2777c478bd9Sstevel@tonic-gate bcopy(fd_array, &(enable->backfiledesc), backcount * sizeof (int)); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate enable->rootfiledesc = mountfd; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate enable->maxsize = maxsize; 2827c478bd9Sstevel@tonic-gate enable->chunksize = chunksize; 2837c478bd9Sstevel@tonic-gate enable->backfilesize = max_bf_size; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate /* 2867c478bd9Sstevel@tonic-gate * enable.backfilename is advisory only. So, we don't overflow 2877c478bd9Sstevel@tonic-gate * the buffer, but we don't give an error if the backpath does not 2887c478bd9Sstevel@tonic-gate * fit. Instead, it is truncated, and the kstat shows all it can. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate if (backpath != NULL) { 2917c478bd9Sstevel@tonic-gate if (dounlink) 2927c478bd9Sstevel@tonic-gate (void) snprintf(enable->backfilename, 2937c478bd9Sstevel@tonic-gate sizeof (enable->backfilename) - 1, "%s <UNLINKED>", 2947c478bd9Sstevel@tonic-gate backpath); 2957c478bd9Sstevel@tonic-gate else 2967c478bd9Sstevel@tonic-gate (void) strncpy(enable->backfilename, backpath, 2977c478bd9Sstevel@tonic-gate sizeof (enable->backfilename) - 1); 2987c478bd9Sstevel@tonic-gate enable->backfilename[sizeof (enable->backfilename)-1] = '\0'; 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1) { 3027c478bd9Sstevel@tonic-gate unlink_all(unlinkpath, backcount); 3037c478bd9Sstevel@tonic-gate die_perror(SNAP_CTL_PATH); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate if (ioctl(ctlfd, _FIOSNAPSHOTCREATE_MULTI, enable) == -1) { 3077c478bd9Sstevel@tonic-gate unlink_all(unlinkpath, backcount); 3087c478bd9Sstevel@tonic-gate if (enable->error != 0) { 3097c478bd9Sstevel@tonic-gate die_create_error(enable->error); 3107c478bd9Sstevel@tonic-gate } else { 3117c478bd9Sstevel@tonic-gate die_perror("ioctl"); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate backout_snap_fd = mountfd; 3167c478bd9Sstevel@tonic-gate if (dounlink != 0) 3177c478bd9Sstevel@tonic-gate unlink_all(unlinkpath, backcount); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (close(ctlfd) != 0) { 3207c478bd9Sstevel@tonic-gate save_errno = errno; 3217c478bd9Sstevel@tonic-gate die_errno(save_errno, gettext("close of control file (%s)"), 3227c478bd9Sstevel@tonic-gate SNAP_CTL_PATH); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate close_all(unlinkpath, backcount, fd_array); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if ((hdl = di_devlink_init("fssnap", DI_MAKE_LINK)) == NULL) { 3287c478bd9Sstevel@tonic-gate save_errno = errno; 3297c478bd9Sstevel@tonic-gate warn_errno(save_errno, 3307c478bd9Sstevel@tonic-gate gettext("/dev/%s/%d may not be immediately available\n"), 3317c478bd9Sstevel@tonic-gate (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME, 3327c478bd9Sstevel@tonic-gate enable->snapshotnumber); 3337c478bd9Sstevel@tonic-gate } else { 3347c478bd9Sstevel@tonic-gate (void) di_devlink_fini(&hdl); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* intentionally not internationalized */ 3387c478bd9Sstevel@tonic-gate printf("/dev/%s/%d\n", (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME, 3397c478bd9Sstevel@tonic-gate enable->snapshotnumber); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate free(enable); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate void 3457c478bd9Sstevel@tonic-gate delete_snap(int mountfd) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate struct fiosnapdelete disable; 3487c478bd9Sstevel@tonic-gate int ctlfd; 3497c478bd9Sstevel@tonic-gate int save_errno; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate bzero(&disable, sizeof (disable)); 3527c478bd9Sstevel@tonic-gate if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1) 3537c478bd9Sstevel@tonic-gate die_perror(SNAP_CTL_PATH); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate disable.rootfiledesc = mountfd; 3567c478bd9Sstevel@tonic-gate if (ioctl(ctlfd, _FIOSNAPSHOTDELETE, &disable) == -1) { 3577c478bd9Sstevel@tonic-gate if (disable.error) { 3587c478bd9Sstevel@tonic-gate die(gettext("error %d"), disable.error); 3597c478bd9Sstevel@tonic-gate } else { 3607c478bd9Sstevel@tonic-gate die_perror("ioctl"); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate if (close(ctlfd) != 0) { 3657c478bd9Sstevel@tonic-gate save_errno = errno; 3667c478bd9Sstevel@tonic-gate die_errno(save_errno, gettext("close of control file (%s)"), 3677c478bd9Sstevel@tonic-gate SNAP_CTL_PATH); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate printf(gettext("Deleted snapshot %d.\n"), disable.snapshotnumber); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate void 3747c478bd9Sstevel@tonic-gate stats_snap(char *mountpath, char *opts) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate fssnap_show_status(mountpath, opts, ((opts != NULL) ? 0 : 1), 0); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * Open as many backing files as necessary for this snapshot. 3817c478bd9Sstevel@tonic-gate * There will be one backing file for each max_bf_size 3827c478bd9Sstevel@tonic-gate * number of bytes in the file system being snapped. 3837c478bd9Sstevel@tonic-gate * The array of file descriptors for the backing files is returned in 3847c478bd9Sstevel@tonic-gate * fd_array. The number of backing files is the return value of the 3857c478bd9Sstevel@tonic-gate * function. The name of the first backing file is returned in 3867c478bd9Sstevel@tonic-gate * unlinkpath. The subsequent backing files are assumed to have the 3877c478bd9Sstevel@tonic-gate * same name as the first, but with suffixes, .2, .3, etc. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate int 3907c478bd9Sstevel@tonic-gate open_backpath(int mountfd, u_offset_t max_bf_size, char **path, 3917c478bd9Sstevel@tonic-gate char **unlinkpath, int **fd_array) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate struct stat st; 3947c478bd9Sstevel@tonic-gate struct statvfs vfs; 3957c478bd9Sstevel@tonic-gate int fd, uniq, len; 3967c478bd9Sstevel@tonic-gate int ret_errno, i, num_back_files; 3977c478bd9Sstevel@tonic-gate offset_t fssize, backfilesize; 3987c478bd9Sstevel@tonic-gate char *locpath = NULL; 3997c478bd9Sstevel@tonic-gate int save_errno; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate *unlinkpath = NULL; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* determine size of the file system to be snapped */ 4047c478bd9Sstevel@tonic-gate if (fstatvfs(mountfd, &vfs) == -1) 4057c478bd9Sstevel@tonic-gate die_perror("statvfs"); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate fssize = vfs.f_blocks * vfs.f_frsize; 4087c478bd9Sstevel@tonic-gate num_back_files = howmany(fssize, max_bf_size); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (stat(*path, &st) < 0) { 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * Since we set the file_exists_is_fatal argument to 1, 4137c478bd9Sstevel@tonic-gate * if we return at all, it will be with all the backing 4147c478bd9Sstevel@tonic-gate * files successfully created and opened. 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate (void) open_multi_backfile(*path, num_back_files, fd_array, 1); 4177c478bd9Sstevel@tonic-gate *unlinkpath = strdup(*path); 4187c478bd9Sstevel@tonic-gate if (unlinkpath == NULL) 4197c478bd9Sstevel@tonic-gate die_perror("strdup"); 4207c478bd9Sstevel@tonic-gate } else if (S_ISDIR(st.st_mode)) { 4217c478bd9Sstevel@tonic-gate char temppath[MAXPATHLEN]; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* remove a trailing slash from the name */ 4247c478bd9Sstevel@tonic-gate len = strlen(*path) - 1; 4257c478bd9Sstevel@tonic-gate if ((*path)[len] == '/') 4267c478bd9Sstevel@tonic-gate (*path)[len] = '\0'; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* find a unique name */ 4297c478bd9Sstevel@tonic-gate for (uniq = 0; uniq <= max_uniq; uniq++) { 4307c478bd9Sstevel@tonic-gate /* cannot use tempnam, since TMPDIR overrides path */ 4317c478bd9Sstevel@tonic-gate (void) snprintf(temppath, MAXPATHLEN, "%s/snapshot%d", 4327c478bd9Sstevel@tonic-gate *path, uniq); 4337c478bd9Sstevel@tonic-gate ret_errno = open_multi_backfile(temppath, 4347c478bd9Sstevel@tonic-gate num_back_files, fd_array, 0); 4357c478bd9Sstevel@tonic-gate if (ret_errno == 0) 4367c478bd9Sstevel@tonic-gate break; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate if (uniq > max_uniq) { 4397c478bd9Sstevel@tonic-gate die(gettext("Could not find unique name in %s"), *path); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate *unlinkpath = strdup(temppath); 4427c478bd9Sstevel@tonic-gate free(*path); 4437c478bd9Sstevel@tonic-gate *path = *unlinkpath; 4447c478bd9Sstevel@tonic-gate } else if (S_ISREG(st.st_mode)) { 4457c478bd9Sstevel@tonic-gate die(gettext("%s already exists."), *path); 4467c478bd9Sstevel@tonic-gate } else { 4477c478bd9Sstevel@tonic-gate die(gettext("%s: must be either the name of a file to create " 4487c478bd9Sstevel@tonic-gate "or a directory."), *path); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * write a block to the end to bump up the file size and ensure the 4537c478bd9Sstevel@tonic-gate * entire range needed can be written to. 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate for (i = 0; i < num_back_files; i++) { 4567c478bd9Sstevel@tonic-gate fd = (*fd_array)[i]; 4577c478bd9Sstevel@tonic-gate if (i == num_back_files - 1 && fssize % max_bf_size != 0) 4587c478bd9Sstevel@tonic-gate backfilesize = fssize % max_bf_size; 4597c478bd9Sstevel@tonic-gate else 4607c478bd9Sstevel@tonic-gate backfilesize = max_bf_size; 4617c478bd9Sstevel@tonic-gate if (llseek(fd, backfilesize - 1, SEEK_SET) == -1) { 4627c478bd9Sstevel@tonic-gate unlink_all(*unlinkpath, num_back_files); 4637c478bd9Sstevel@tonic-gate die_perror("llseek"); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (write(fd, "0", 1) == -1) { 4677c478bd9Sstevel@tonic-gate save_errno = errno; 4687c478bd9Sstevel@tonic-gate unlink_all(*unlinkpath, num_back_files); 4697c478bd9Sstevel@tonic-gate if (save_errno == EFBIG) 4707c478bd9Sstevel@tonic-gate die(gettext("File system %s " 4717c478bd9Sstevel@tonic-gate "does not support large files.\n"), *path); 4727c478bd9Sstevel@tonic-gate else 4737c478bd9Sstevel@tonic-gate die_perror("write"); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate return (num_back_files); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate u_offset_t 4807c478bd9Sstevel@tonic-gate spec_to_bytes(char *spec) 4817c478bd9Sstevel@tonic-gate { 4827c478bd9Sstevel@tonic-gate u_offset_t base; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate base = strtoull(spec, NULL, 10); 4857c478bd9Sstevel@tonic-gate if ((base == 0LL) && (spec[0] != '0')) 4867c478bd9Sstevel@tonic-gate die(gettext("Numeric option value expected")); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate spec += strspn(spec, "0123456789"); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate if ((spec == NULL) || strlen(spec) != 1) 4917c478bd9Sstevel@tonic-gate die(gettext("Only one of b, k, m, or g may be used")); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate switch (spec[0]) { 4947c478bd9Sstevel@tonic-gate case 'B': 4957c478bd9Sstevel@tonic-gate case 'b': 4967c478bd9Sstevel@tonic-gate base *= 512; 4977c478bd9Sstevel@tonic-gate break; 4987c478bd9Sstevel@tonic-gate case 'K': 4997c478bd9Sstevel@tonic-gate case 'k': 5007c478bd9Sstevel@tonic-gate base *= 1024; 5017c478bd9Sstevel@tonic-gate break; 5027c478bd9Sstevel@tonic-gate case 'M': 5037c478bd9Sstevel@tonic-gate case 'm': 5047c478bd9Sstevel@tonic-gate base *= 1024 * 1024; 5057c478bd9Sstevel@tonic-gate break; 5067c478bd9Sstevel@tonic-gate case 'G': 5077c478bd9Sstevel@tonic-gate case 'g': 5087c478bd9Sstevel@tonic-gate base *= 1024 * 1024 * 1024; 5097c478bd9Sstevel@tonic-gate break; 5107c478bd9Sstevel@tonic-gate default: 5117c478bd9Sstevel@tonic-gate die(gettext("Must specify one of b, k, m, or g on size")); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate return (base); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate /* 5187c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store() in a loop 5197c478bd9Sstevel@tonic-gate * starts with a null pointer in the outpath argument 5207c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until 5217c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string 5227c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed by the caller. 5237c478bd9Sstevel@tonic-gate */ 5247c478bd9Sstevel@tonic-gate void 5257c478bd9Sstevel@tonic-gate gen_backing_store_path(char *basepath, int num, char **outpath) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate if (*outpath == NULL) { 5287c478bd9Sstevel@tonic-gate *outpath = malloc(strlen(basepath) + MAX_SUFFIX); 5297c478bd9Sstevel@tonic-gate if (*outpath == NULL) 5307c478bd9Sstevel@tonic-gate die_perror("malloc"); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * Security note: We use strcpy here, instead of the safer 5357c478bd9Sstevel@tonic-gate * strncpy, because the string pointed to by outpath has 5367c478bd9Sstevel@tonic-gate * been generated by THIS code, above. Hence it is impossible 5377c478bd9Sstevel@tonic-gate * for the strcpy to overrun the buffer. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate if (num == 1) 5407c478bd9Sstevel@tonic-gate (void) strcpy(*outpath, basepath); 5417c478bd9Sstevel@tonic-gate else 5427c478bd9Sstevel@tonic-gate (void) sprintf(*outpath, "%s.%d", basepath, num); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate void 5467c478bd9Sstevel@tonic-gate unlink_all(char *unlinkpath, int count) 5477c478bd9Sstevel@tonic-gate { 5487c478bd9Sstevel@tonic-gate char *bspath = NULL; 5497c478bd9Sstevel@tonic-gate int i; 5507c478bd9Sstevel@tonic-gate int save_errno; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate for (i = 1; i <= count; i++) { 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store() 5557c478bd9Sstevel@tonic-gate * starts with a null pointer in the third argument 5567c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until 5577c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string 5587c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate gen_backing_store_path(unlinkpath, i, &bspath); 5617c478bd9Sstevel@tonic-gate if (unlink(bspath) < 0) { 5627c478bd9Sstevel@tonic-gate save_errno = errno; 5637c478bd9Sstevel@tonic-gate warn_errno(save_errno, 5647c478bd9Sstevel@tonic-gate gettext("could not unlink %s"), bspath); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate free(bspath); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate void 5717c478bd9Sstevel@tonic-gate close_all(char *closepath, int count, int *fd_array) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate char *bspath = NULL; 5747c478bd9Sstevel@tonic-gate int i; 5757c478bd9Sstevel@tonic-gate int save_errno; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate for (i = 1; i <= count; i++) { 5787c478bd9Sstevel@tonic-gate if (close(fd_array[i - 1]) != 0) { 5797c478bd9Sstevel@tonic-gate save_errno = errno; 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store() 5827c478bd9Sstevel@tonic-gate * starts with a null pointer in the third argument 5837c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until 5847c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string 5857c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed. 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate gen_backing_store_path(closepath, i, &bspath); 5887c478bd9Sstevel@tonic-gate die_errno(save_errno, gettext( 5897c478bd9Sstevel@tonic-gate "close of backing-store (%s)"), bspath); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate if (bspath != NULL) 5937c478bd9Sstevel@tonic-gate free(bspath); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * Create "count" files starting with name backpath ("backpath", 5987c478bd9Sstevel@tonic-gate * "backpath".2, "backpath".3, etc. When this function returns, 5997c478bd9Sstevel@tonic-gate * either all of the files will exist and be opened (and their 6007c478bd9Sstevel@tonic-gate * file descriptors will be in fd_array), or NONE of will exist 6017c478bd9Sstevel@tonic-gate * (if they had to be created) and opened (that is, if we created a file, 6027c478bd9Sstevel@tonic-gate * and then failed to create a later file, the earlier files will 6037c478bd9Sstevel@tonic-gate * be closed and unlinked.) 6047c478bd9Sstevel@tonic-gate * 6057c478bd9Sstevel@tonic-gate * If file_exists_is_fatal is set, it is a fatal error (resulting in 6067c478bd9Sstevel@tonic-gate * an error message and termination) if any of the backing files to 6077c478bd9Sstevel@tonic-gate * be created already exists. Otherwise, if one of the backing 6087c478bd9Sstevel@tonic-gate * files already exists, we close and unlink all the files we already 6097c478bd9Sstevel@tonic-gate * created, and return an error to the caller, but we don't print 6107c478bd9Sstevel@tonic-gate * an error or terminate. 6117c478bd9Sstevel@tonic-gate * 6127c478bd9Sstevel@tonic-gate * If there is any failure other than EEXIST when attempting to 6137c478bd9Sstevel@tonic-gate * create the file, the routine prints an error and terminates the 6147c478bd9Sstevel@tonic-gate * program, regardless of the setting of file_exists_is_fatal. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate int 6177c478bd9Sstevel@tonic-gate open_multi_backfile(char *backpath, int count, int **fd_array, 6187c478bd9Sstevel@tonic-gate int file_exists_is_fatal) 6197c478bd9Sstevel@tonic-gate { 6207c478bd9Sstevel@tonic-gate char *wpath = NULL; /* working path */ 6217c478bd9Sstevel@tonic-gate int i, j, fd; 6227c478bd9Sstevel@tonic-gate struct stat st; 6237c478bd9Sstevel@tonic-gate int stat_succeeded = 0; 6247c478bd9Sstevel@tonic-gate int save_errno; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate *fd_array = (int *)malloc(count * sizeof (int)); 6277c478bd9Sstevel@tonic-gate if (*fd_array == NULL) 6287c478bd9Sstevel@tonic-gate die_perror("malloc"); 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store() 6337c478bd9Sstevel@tonic-gate * starts with a null pointer in the third argument 6347c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until 6357c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string 6367c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed. 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate gen_backing_store_path(backpath, i + 1, &wpath); 6397c478bd9Sstevel@tonic-gate if (stat(wpath, &st) == 0) 6407c478bd9Sstevel@tonic-gate stat_succeeded = 1; 6417c478bd9Sstevel@tonic-gate else 6427c478bd9Sstevel@tonic-gate fd = open(wpath, O_RDWR | O_CREAT | O_EXCL, 0600); 6437c478bd9Sstevel@tonic-gate if (stat_succeeded || fd < 0) { 6447c478bd9Sstevel@tonic-gate if (i > 0) { 6457c478bd9Sstevel@tonic-gate for (j = 0; j < i - 1; j++) 6467c478bd9Sstevel@tonic-gate (void) close((*fd_array)[j]); 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * unlink_all's second argument is the number 6497c478bd9Sstevel@tonic-gate * of files to be removed, NOT the offset 6507c478bd9Sstevel@tonic-gate * into the array of fd's of the last 6517c478bd9Sstevel@tonic-gate * successfully created file. 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate unlink_all(backpath, i); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate if (stat_succeeded || errno == EEXIST) { 6567c478bd9Sstevel@tonic-gate if (file_exists_is_fatal) 6577c478bd9Sstevel@tonic-gate die(gettext("%s exists, please specify" 6587c478bd9Sstevel@tonic-gate " a nonexistent backing store."), 6597c478bd9Sstevel@tonic-gate wpath); 6607c478bd9Sstevel@tonic-gate else 6617c478bd9Sstevel@tonic-gate return (1); 6627c478bd9Sstevel@tonic-gate } else { 6637c478bd9Sstevel@tonic-gate save_errno = errno; 6647c478bd9Sstevel@tonic-gate die_errno(save_errno, 6657c478bd9Sstevel@tonic-gate gettext("Could not create" 6667c478bd9Sstevel@tonic-gate " backing file %s"), wpath); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate (*fd_array)[i] = fd; 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate if (wpath != NULL) 6727c478bd9Sstevel@tonic-gate free(wpath); 6737c478bd9Sstevel@tonic-gate return (0); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate void 6777c478bd9Sstevel@tonic-gate die_perror(char *string) 6787c478bd9Sstevel@tonic-gate { 6797c478bd9Sstevel@tonic-gate int en = errno; 6807c478bd9Sstevel@tonic-gate char *errstr; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate if (string == NULL) { 6837c478bd9Sstevel@tonic-gate string = gettext("Fatal"); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate errstr = strerror(en); 6867c478bd9Sstevel@tonic-gate if (errstr == NULL) { 6877c478bd9Sstevel@tonic-gate errstr = gettext("Unknown error"); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: %s: error %d: %s\n"), 6917c478bd9Sstevel@tonic-gate progname, string, en, errstr); 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate longjmp(err_main, 2); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate void 6977c478bd9Sstevel@tonic-gate die_usage(void) 6987c478bd9Sstevel@tonic-gate { 6997c478bd9Sstevel@tonic-gate usage(); 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate longjmp(err_main, 1); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate void 7057c478bd9Sstevel@tonic-gate warn_errno(int en, char *fmt, ...) 7067c478bd9Sstevel@tonic-gate { 7077c478bd9Sstevel@tonic-gate va_list ap; 7087c478bd9Sstevel@tonic-gate char *errstr; 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate errstr = strerror(en); 7117c478bd9Sstevel@tonic-gate if (errstr == NULL) { 7127c478bd9Sstevel@tonic-gate errstr = gettext("Unknown error"); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate va_start(ap, fmt); 7167c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: Warning: "), progname); 7177c478bd9Sstevel@tonic-gate vfprintf(stderr, fmt, ap); 7187c478bd9Sstevel@tonic-gate fprintf(stderr, ": %s\n", errstr); 7197c478bd9Sstevel@tonic-gate va_end(ap); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate void 7237c478bd9Sstevel@tonic-gate die_errno(int en, char *fmt, ...) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate va_list ap; 7267c478bd9Sstevel@tonic-gate char *errstr; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate errstr = strerror(en); 7297c478bd9Sstevel@tonic-gate if (errstr == NULL) { 7307c478bd9Sstevel@tonic-gate errstr = gettext("Unknown error"); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate va_start(ap, fmt); 7347c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: Fatal: "), progname); 7357c478bd9Sstevel@tonic-gate vfprintf(stderr, fmt, ap); 7367c478bd9Sstevel@tonic-gate fprintf(stderr, ": %s\n", errstr); 7377c478bd9Sstevel@tonic-gate va_end(ap); 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate longjmp(err_main, 2); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate void 7437c478bd9Sstevel@tonic-gate die_create_error(int error) 7447c478bd9Sstevel@tonic-gate { 7457c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("snapshot error: ")); 7467c478bd9Sstevel@tonic-gate switch (error) { 7477c478bd9Sstevel@tonic-gate case FIOCOW_EREADONLY: 7487c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Read only file system\n")); 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate case FIOCOW_EBUSY: 7517c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Snapshot already enabled\n")); 7527c478bd9Sstevel@tonic-gate break; 7537c478bd9Sstevel@tonic-gate case FIOCOW_EULOCK: 7547c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system is locked\n")); 7557c478bd9Sstevel@tonic-gate break; 7567c478bd9Sstevel@tonic-gate case FIOCOW_EWLOCK: 7577c478bd9Sstevel@tonic-gate fprintf(stderr, 7587c478bd9Sstevel@tonic-gate gettext("File system could not be write locked\n")); 7597c478bd9Sstevel@tonic-gate break; 7607c478bd9Sstevel@tonic-gate case FIOCOW_EFLUSH: 7617c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system could not be flushed\n")); 7627c478bd9Sstevel@tonic-gate break; 7637c478bd9Sstevel@tonic-gate case FIOCOW_ECLEAN: 7647c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system may not be stable\n")); 7657c478bd9Sstevel@tonic-gate break; 7667c478bd9Sstevel@tonic-gate case FIOCOW_ENOULOCK: 7677c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system could not be unlocked\n")); 7687c478bd9Sstevel@tonic-gate break; 7697c478bd9Sstevel@tonic-gate case FIOCOW_ECHUNKSZ: 7707c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Chunk size must be a multiple of the " 7717c478bd9Sstevel@tonic-gate "fragment size\n")); 7727c478bd9Sstevel@tonic-gate break; 7737c478bd9Sstevel@tonic-gate case FIOCOW_ECREATE: 7747c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Could not allocate or create " 7757c478bd9Sstevel@tonic-gate "a new snapshot\n")); 7767c478bd9Sstevel@tonic-gate break; 7777c478bd9Sstevel@tonic-gate case FIOCOW_EBITMAP: 7787c478bd9Sstevel@tonic-gate fprintf(stderr, 7797c478bd9Sstevel@tonic-gate gettext("Error scanning file system bitmaps\n")); 7807c478bd9Sstevel@tonic-gate break; 7817c478bd9Sstevel@tonic-gate case FIOCOW_EBACKFILE: 7827c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Invalid backing file path\n")); 7837c478bd9Sstevel@tonic-gate break; 7847c478bd9Sstevel@tonic-gate default: 7857c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Unknown create error\n")); 7867c478bd9Sstevel@tonic-gate break; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate longjmp(err_main, 2); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate void 7937c478bd9Sstevel@tonic-gate die(char *fmt, ...) 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate va_list ap; 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate va_start(ap, fmt); 7987c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: Fatal: "), progname); 7997c478bd9Sstevel@tonic-gate vfprintf(stderr, fmt, ap); 8007c478bd9Sstevel@tonic-gate fprintf(stderr, "\n"); 8017c478bd9Sstevel@tonic-gate va_end(ap); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate longjmp(err_main, 2); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate void 8077c478bd9Sstevel@tonic-gate usage(void) 8087c478bd9Sstevel@tonic-gate { 8097c478bd9Sstevel@tonic-gate int i; 8107c478bd9Sstevel@tonic-gate char *use_str[] = { 8117c478bd9Sstevel@tonic-gate " %s [-F ufs] [-V] -o backing-store=path,[special_options] " 8127c478bd9Sstevel@tonic-gate "/mount/point\n", 8137c478bd9Sstevel@tonic-gate " %s -d [-F ufs] [-V] /mount/point | dev\n", 8147c478bd9Sstevel@tonic-gate " %s -i [-F ufS] [-V] [-o special-options] /mount/point " 8157c478bd9Sstevel@tonic-gate "| dev\n", 8167c478bd9Sstevel@tonic-gate NULL 8177c478bd9Sstevel@tonic-gate }; 8187c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Usage:\n")); 8197c478bd9Sstevel@tonic-gate for (i = 0; use_str[i] != NULL; i++) 8207c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(use_str[i]), progname); 8217c478bd9Sstevel@tonic-gate } 822