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 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <fcntl.h> 35 #include <errno.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/ioctl.h> 39 #include <sys/fssnap_if.h> 40 #include <sys/filio.h> 41 #include <setjmp.h> 42 #include <stdarg.h> 43 #include <kstat.h> 44 #include <libintl.h> 45 #include <libdevinfo.h> 46 #include <sys/sysmacros.h> 47 #include <sys/fs/ufs_fs.h> 48 #include <sys/fs/ufs_snap.h> 49 50 #define SNAP_CTL_PATH "/dev/" SNAP_CTL_NAME 51 52 #define MAX_SUFFIX 6 /* '.' + 4 chars of number + trailing '\0' */ 53 54 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 55 56 static int max_uniq = 9999; 57 58 void create_snap(int, char *, u_offset_t, uint_t, int, int); 59 void delete_snap(int); 60 void stats_snap(char *, char *); 61 62 int open_backpath(int, u_offset_t, char **, char **, int **); 63 u_offset_t spec_to_bytes(char *); 64 void gen_backing_store_path(char *basepath, int num, char **outpath); 65 void unlink_all(char *, int); 66 void close_all(char *, int, int *); 67 int open_multi_backfile(char *, int, int **, int); 68 69 void die_perror(char *); 70 void die_errno(int, char *, ...); 71 void die_create_error(int error); 72 void die_usage(void); 73 void die(char *, ...); 74 void warn_errno(int, char *, ...); 75 void usage(void); 76 77 static char *subopts[] = { 78 #define BACKPATH (0) 79 "backing-store", 80 #define BACKPATH2 (1) 81 "bs", 82 #define BACKPATH3 (2) 83 "bf", 84 #define MAXSIZE (3) 85 "maxsize", 86 #define CHUNKSIZE (4) 87 "chunksize", 88 #define RAWFILE (5) 89 "raw", 90 #define UNLINK (6) 91 "unlink", 92 NULL 93 }; 94 95 static jmp_buf err_main; 96 static char *progname = NULL; 97 static backout_snap_fd = -1; 98 99 extern void fssnap_show_status(char *mountpoint, char *opts, int labels, 100 int brief); /* in ../../fssnapsup.c */ 101 102 int 103 main(int argc, char *argv[]) 104 { 105 int c; 106 char *suboptions = NULL; 107 char *value; 108 int longjmp_return; 109 110 char *mountpoint = NULL; 111 int mountfd = -1; 112 char *backpath = NULL; 113 114 int delete = 0; 115 int stats = 0; 116 u_offset_t maxsize = 0; 117 uint_t chunksize = 0; 118 int rawfile = 0; 119 int dounlink = 0; 120 121 if ((progname = strrchr(argv[0], '/')) != NULL) 122 ++progname; 123 else 124 progname = argv[0]; 125 126 if ((longjmp_return = setjmp(err_main)) != 0) { 127 if (backout_snap_fd >= 0) { 128 mountfd = backout_snap_fd; 129 backout_snap_fd = -1; /* prevent infinite loop */ 130 delete_snap(mountfd); 131 } 132 133 return (longjmp_return); 134 } 135 136 while ((c = getopt(argc, argv, "dio:")) != EOF) { 137 switch (c) { 138 case 'd': 139 ++delete; 140 break; 141 142 case 'i': 143 ++stats; 144 break; 145 146 case 'o': 147 suboptions = optarg; 148 break; 149 150 default: 151 die_usage(); 152 } 153 } 154 155 /* if -i or -d are not specified then interpret the create options */ 156 if ((stats == 0) && (delete == 0) && (suboptions != NULL)) { 157 while (*suboptions != '\0') { 158 159 switch ((getsubopt(&suboptions, subopts, &value))) { 160 case BACKPATH: 161 case BACKPATH2: 162 case BACKPATH3: 163 if (value == NULL) 164 die_usage(); 165 backpath = strdup(value); 166 if (backpath == NULL) { 167 die_perror("strdup"); 168 } 169 break; 170 171 case MAXSIZE: 172 maxsize = spec_to_bytes(value); 173 break; 174 175 case CHUNKSIZE: 176 chunksize = spec_to_bytes(value); 177 break; 178 179 case RAWFILE: 180 ++rawfile; 181 break; 182 183 case UNLINK: 184 ++dounlink; 185 break; 186 187 default: 188 die_usage(); 189 } 190 } 191 } 192 193 /* -d and -i can not be specified together or more than once each */ 194 if ((delete + stats) > 1) 195 die_usage(); 196 197 /* If no mount point is specified then -i is the only valid option. */ 198 if ((optind >= argc) && (stats == 0)) 199 die_usage(); 200 201 /* 202 * If anything but the mount point or device is specified at the end 203 * it's an error. 204 */ 205 if (optind != (argc - 1)) { 206 if (!stats) 207 die_usage(); 208 } else { 209 /* Otherwise, the last option is the mountpoint. */ 210 mountpoint = argv[optind]; 211 if ((mountfd = open(mountpoint, O_RDONLY)) < 0) 212 die_perror(mountpoint); 213 } 214 215 if (stats != 0) { 216 stats_snap(mountpoint, suboptions); 217 } else if (delete != 0) { 218 delete_snap(mountfd); 219 } else { 220 /* 221 * backpath may be invalid upon return of create_snap call. 222 */ 223 create_snap(mountfd, backpath, maxsize, chunksize, 224 rawfile, dounlink); 225 } 226 227 return (0); 228 } 229 230 void 231 create_snap(int mountfd, char *backpath, u_offset_t maxsize, uint_t chunksize, 232 int rawfile, int dounlink) 233 { 234 struct fiosnapcreate_multi *enable; 235 int backcount; 236 int ctlfd; 237 char *unlinkpath = NULL; 238 di_devlink_handle_t hdl; 239 int *fd_array; 240 u_offset_t max_bf_size; 241 int save_errno; 242 243 /* 244 * If chunksize is not a power of 2, the maximum size of a 245 * backing store file might not be UFS_MAX_SNAPBACKFILESIZE, 246 * since the size of the backing store files must be an 247 * integral number of chunks (except for the last one). So 248 * calculate the actual maximum backing store file size. 249 * (It would be nice if we could assume that the chunksize 250 * was a power of 2, but we can't.) 251 */ 252 253 if (chunksize != 0 && !POWEROF2(chunksize)) 254 max_bf_size = (UFS_MAX_SNAPBACKFILESIZE/chunksize) * chunksize; 255 else 256 max_bf_size = UFS_MAX_SNAPBACKFILESIZE; 257 258 /* 259 * open_backpath() only returns on success, and 260 * can change the value of backpath when backpath 261 * references a directory. 262 */ 263 if (backpath == NULL) 264 die(gettext("No backing store path specified.\n")); 265 backcount = open_backpath(mountfd, max_bf_size, &backpath, 266 &unlinkpath, &fd_array); 267 268 /* 269 * Only need backcount - 1 spaces for fd's since 270 * fiosnapcreate_multi struct contains space for the 271 * first one. 272 */ 273 if ((enable = calloc(1, sizeof (struct fiosnapcreate_multi) + 274 (backcount - 1) * sizeof (int))) == NULL) 275 die(gettext("Insufficient memory.\n")); 276 277 enable->backfilecount = backcount; 278 bcopy(fd_array, &(enable->backfiledesc), backcount * sizeof (int)); 279 280 enable->rootfiledesc = mountfd; 281 282 enable->maxsize = maxsize; 283 enable->chunksize = chunksize; 284 enable->backfilesize = max_bf_size; 285 286 /* 287 * enable.backfilename is advisory only. So, we don't overflow 288 * the buffer, but we don't give an error if the backpath does not 289 * fit. Instead, it is truncated, and the kstat shows all it can. 290 */ 291 if (backpath != NULL) { 292 if (dounlink) 293 (void) snprintf(enable->backfilename, 294 sizeof (enable->backfilename) - 1, "%s <UNLINKED>", 295 backpath); 296 else 297 (void) strncpy(enable->backfilename, backpath, 298 sizeof (enable->backfilename) - 1); 299 enable->backfilename[sizeof (enable->backfilename)-1] = '\0'; 300 } 301 302 if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1) { 303 unlink_all(unlinkpath, backcount); 304 die_perror(SNAP_CTL_PATH); 305 } 306 307 if (ioctl(ctlfd, _FIOSNAPSHOTCREATE_MULTI, enable) == -1) { 308 unlink_all(unlinkpath, backcount); 309 if (enable->error != 0) { 310 die_create_error(enable->error); 311 } else { 312 die_perror("ioctl"); 313 } 314 } 315 316 backout_snap_fd = mountfd; 317 if (dounlink != 0) 318 unlink_all(unlinkpath, backcount); 319 320 if (close(ctlfd) != 0) { 321 save_errno = errno; 322 die_errno(save_errno, gettext("close of control file (%s)"), 323 SNAP_CTL_PATH); 324 } 325 326 close_all(unlinkpath, backcount, fd_array); 327 328 if ((hdl = di_devlink_init("fssnap", DI_MAKE_LINK)) == NULL) { 329 save_errno = errno; 330 warn_errno(save_errno, 331 gettext("/dev/%s/%d may not be immediately available\n"), 332 (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME, 333 enable->snapshotnumber); 334 } else { 335 (void) di_devlink_fini(&hdl); 336 } 337 338 /* intentionally not internationalized */ 339 printf("/dev/%s/%d\n", (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME, 340 enable->snapshotnumber); 341 342 free(enable); 343 } 344 345 void 346 delete_snap(int mountfd) 347 { 348 struct fiosnapdelete disable; 349 int ctlfd; 350 int save_errno; 351 352 bzero(&disable, sizeof (disable)); 353 if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1) 354 die_perror(SNAP_CTL_PATH); 355 356 disable.rootfiledesc = mountfd; 357 if (ioctl(ctlfd, _FIOSNAPSHOTDELETE, &disable) == -1) { 358 if (disable.error) { 359 die(gettext("error %d"), disable.error); 360 } else { 361 die_perror("ioctl"); 362 } 363 } 364 365 if (close(ctlfd) != 0) { 366 save_errno = errno; 367 die_errno(save_errno, gettext("close of control file (%s)"), 368 SNAP_CTL_PATH); 369 } 370 371 printf(gettext("Deleted snapshot %d.\n"), disable.snapshotnumber); 372 } 373 374 void 375 stats_snap(char *mountpath, char *opts) 376 { 377 fssnap_show_status(mountpath, opts, ((opts != NULL) ? 0 : 1), 0); 378 } 379 380 /* 381 * Open as many backing files as necessary for this snapshot. 382 * There will be one backing file for each max_bf_size 383 * number of bytes in the file system being snapped. 384 * The array of file descriptors for the backing files is returned in 385 * fd_array. The number of backing files is the return value of the 386 * function. The name of the first backing file is returned in 387 * unlinkpath. The subsequent backing files are assumed to have the 388 * same name as the first, but with suffixes, .2, .3, etc. 389 */ 390 int 391 open_backpath(int mountfd, u_offset_t max_bf_size, char **path, 392 char **unlinkpath, int **fd_array) 393 { 394 struct stat st; 395 struct statvfs vfs; 396 int fd, uniq, len; 397 int ret_errno, i, num_back_files; 398 offset_t fssize, backfilesize; 399 char *locpath = NULL; 400 int save_errno; 401 402 *unlinkpath = NULL; 403 404 /* determine size of the file system to be snapped */ 405 if (fstatvfs(mountfd, &vfs) == -1) 406 die_perror("statvfs"); 407 408 fssize = vfs.f_blocks * vfs.f_frsize; 409 num_back_files = howmany(fssize, max_bf_size); 410 411 if (stat(*path, &st) < 0) { 412 /* 413 * Since we set the file_exists_is_fatal argument to 1, 414 * if we return at all, it will be with all the backing 415 * files successfully created and opened. 416 */ 417 (void) open_multi_backfile(*path, num_back_files, fd_array, 1); 418 *unlinkpath = strdup(*path); 419 if (unlinkpath == NULL) 420 die_perror("strdup"); 421 } else if (S_ISDIR(st.st_mode)) { 422 char temppath[MAXPATHLEN]; 423 424 /* remove a trailing slash from the name */ 425 len = strlen(*path) - 1; 426 if ((*path)[len] == '/') 427 (*path)[len] = '\0'; 428 429 /* find a unique name */ 430 for (uniq = 0; uniq <= max_uniq; uniq++) { 431 /* cannot use tempnam, since TMPDIR overrides path */ 432 (void) snprintf(temppath, MAXPATHLEN, "%s/snapshot%d", 433 *path, uniq); 434 ret_errno = open_multi_backfile(temppath, 435 num_back_files, fd_array, 0); 436 if (ret_errno == 0) 437 break; 438 } 439 if (uniq > max_uniq) { 440 die(gettext("Could not find unique name in %s"), *path); 441 } 442 *unlinkpath = strdup(temppath); 443 free(*path); 444 *path = *unlinkpath; 445 } else if (S_ISREG(st.st_mode)) { 446 die(gettext("%s already exists."), *path); 447 } else { 448 die(gettext("%s: must be either the name of a file to create " 449 "or a directory."), *path); 450 } 451 452 /* 453 * write a block to the end to bump up the file size and ensure the 454 * entire range needed can be written to. 455 */ 456 for (i = 0; i < num_back_files; i++) { 457 fd = (*fd_array)[i]; 458 if (i == num_back_files - 1 && fssize % max_bf_size != 0) 459 backfilesize = fssize % max_bf_size; 460 else 461 backfilesize = max_bf_size; 462 if (llseek(fd, backfilesize - 1, SEEK_SET) == -1) { 463 unlink_all(*unlinkpath, num_back_files); 464 die_perror("llseek"); 465 } 466 467 if (write(fd, "0", 1) == -1) { 468 save_errno = errno; 469 unlink_all(*unlinkpath, num_back_files); 470 if (save_errno == EFBIG) 471 die(gettext("File system %s " 472 "does not support large files.\n"), *path); 473 else 474 die_perror("write"); 475 } 476 } 477 return (num_back_files); 478 } 479 480 u_offset_t 481 spec_to_bytes(char *spec) 482 { 483 u_offset_t base; 484 485 base = strtoull(spec, NULL, 10); 486 if ((base == 0LL) && (spec[0] != '0')) 487 die(gettext("Numeric option value expected")); 488 489 spec += strspn(spec, "0123456789"); 490 491 if ((spec == NULL) || strlen(spec) != 1) 492 die(gettext("Only one of b, k, m, or g may be used")); 493 494 switch (spec[0]) { 495 case 'B': 496 case 'b': 497 base *= 512; 498 break; 499 case 'K': 500 case 'k': 501 base *= 1024; 502 break; 503 case 'M': 504 case 'm': 505 base *= 1024 * 1024; 506 break; 507 case 'G': 508 case 'g': 509 base *= 1024 * 1024 * 1024; 510 break; 511 default: 512 die(gettext("Must specify one of b, k, m, or g on size")); 513 } 514 515 return (base); 516 } 517 518 /* 519 * Make sure that the first call to gen_backing_store() in a loop 520 * starts with a null pointer in the outpath argument 521 * and continues to pass in that same argument until 522 * the loop is complete, at which point the string 523 * pointed to by that argument must be freed by the caller. 524 */ 525 void 526 gen_backing_store_path(char *basepath, int num, char **outpath) 527 { 528 if (*outpath == NULL) { 529 *outpath = malloc(strlen(basepath) + MAX_SUFFIX); 530 if (*outpath == NULL) 531 die_perror("malloc"); 532 } 533 534 /* 535 * Security note: We use strcpy here, instead of the safer 536 * strncpy, because the string pointed to by outpath has 537 * been generated by THIS code, above. Hence it is impossible 538 * for the strcpy to overrun the buffer. 539 */ 540 if (num == 1) 541 (void) strcpy(*outpath, basepath); 542 else 543 (void) sprintf(*outpath, "%s.%d", basepath, num); 544 } 545 546 void 547 unlink_all(char *unlinkpath, int count) 548 { 549 char *bspath = NULL; 550 int i; 551 int save_errno; 552 553 for (i = 1; i <= count; i++) { 554 /* 555 * Make sure that the first call to gen_backing_store() 556 * starts with a null pointer in the third argument 557 * and continues to pass in that same argument until 558 * the loop is complete, at which point the string 559 * pointed to by that argument must be freed. 560 */ 561 gen_backing_store_path(unlinkpath, i, &bspath); 562 if (unlink(bspath) < 0) { 563 save_errno = errno; 564 warn_errno(save_errno, 565 gettext("could not unlink %s"), bspath); 566 } 567 } 568 free(bspath); 569 } 570 571 void 572 close_all(char *closepath, int count, int *fd_array) 573 { 574 char *bspath = NULL; 575 int i; 576 int save_errno; 577 578 for (i = 1; i <= count; i++) { 579 if (close(fd_array[i - 1]) != 0) { 580 save_errno = errno; 581 /* 582 * Make sure that the first call to gen_backing_store() 583 * starts with a null pointer in the third argument 584 * and continues to pass in that same argument until 585 * the loop is complete, at which point the string 586 * pointed to by that argument must be freed. 587 */ 588 gen_backing_store_path(closepath, i, &bspath); 589 die_errno(save_errno, gettext( 590 "close of backing-store (%s)"), bspath); 591 } 592 } 593 if (bspath != NULL) 594 free(bspath); 595 } 596 597 /* 598 * Create "count" files starting with name backpath ("backpath", 599 * "backpath".2, "backpath".3, etc. When this function returns, 600 * either all of the files will exist and be opened (and their 601 * file descriptors will be in fd_array), or NONE of will exist 602 * (if they had to be created) and opened (that is, if we created a file, 603 * and then failed to create a later file, the earlier files will 604 * be closed and unlinked.) 605 * 606 * If file_exists_is_fatal is set, it is a fatal error (resulting in 607 * an error message and termination) if any of the backing files to 608 * be created already exists. Otherwise, if one of the backing 609 * files already exists, we close and unlink all the files we already 610 * created, and return an error to the caller, but we don't print 611 * an error or terminate. 612 * 613 * If there is any failure other than EEXIST when attempting to 614 * create the file, the routine prints an error and terminates the 615 * program, regardless of the setting of file_exists_is_fatal. 616 */ 617 int 618 open_multi_backfile(char *backpath, int count, int **fd_array, 619 int file_exists_is_fatal) 620 { 621 char *wpath = NULL; /* working path */ 622 int i, j, fd; 623 struct stat st; 624 int stat_succeeded = 0; 625 int save_errno; 626 627 *fd_array = (int *)malloc(count * sizeof (int)); 628 if (*fd_array == NULL) 629 die_perror("malloc"); 630 631 for (i = 0; i < count; i++) { 632 /* 633 * Make sure that the first call to gen_backing_store() 634 * starts with a null pointer in the third argument 635 * and continues to pass in that same argument until 636 * the loop is complete, at which point the string 637 * pointed to by that argument must be freed. 638 */ 639 gen_backing_store_path(backpath, i + 1, &wpath); 640 if (stat(wpath, &st) == 0) 641 stat_succeeded = 1; 642 else 643 fd = open(wpath, O_RDWR | O_CREAT | O_EXCL, 0600); 644 if (stat_succeeded || fd < 0) { 645 if (i > 0) { 646 for (j = 0; j < i - 1; j++) 647 (void) close((*fd_array)[j]); 648 /* 649 * unlink_all's second argument is the number 650 * of files to be removed, NOT the offset 651 * into the array of fd's of the last 652 * successfully created file. 653 */ 654 unlink_all(backpath, i); 655 } 656 if (stat_succeeded || errno == EEXIST) { 657 if (file_exists_is_fatal) 658 die(gettext("%s exists, please specify" 659 " a nonexistent backing store."), 660 wpath); 661 else 662 return (1); 663 } else { 664 save_errno = errno; 665 die_errno(save_errno, 666 gettext("Could not create" 667 " backing file %s"), wpath); 668 } 669 } 670 (*fd_array)[i] = fd; 671 } 672 if (wpath != NULL) 673 free(wpath); 674 return (0); 675 } 676 677 void 678 die_perror(char *string) 679 { 680 int en = errno; 681 char *errstr; 682 683 if (string == NULL) { 684 string = gettext("Fatal"); 685 } 686 errstr = strerror(en); 687 if (errstr == NULL) { 688 errstr = gettext("Unknown error"); 689 } 690 691 fprintf(stderr, gettext("%s: %s: error %d: %s\n"), 692 progname, string, en, errstr); 693 694 longjmp(err_main, 2); 695 } 696 697 void 698 die_usage(void) 699 { 700 usage(); 701 702 longjmp(err_main, 1); 703 } 704 705 void 706 warn_errno(int en, char *fmt, ...) 707 { 708 va_list ap; 709 char *errstr; 710 711 errstr = strerror(en); 712 if (errstr == NULL) { 713 errstr = gettext("Unknown error"); 714 } 715 716 va_start(ap, fmt); 717 fprintf(stderr, gettext("%s: Warning: "), progname); 718 vfprintf(stderr, fmt, ap); 719 fprintf(stderr, ": %s\n", errstr); 720 va_end(ap); 721 } 722 723 void 724 die_errno(int en, char *fmt, ...) 725 { 726 va_list ap; 727 char *errstr; 728 729 errstr = strerror(en); 730 if (errstr == NULL) { 731 errstr = gettext("Unknown error"); 732 } 733 734 va_start(ap, fmt); 735 fprintf(stderr, gettext("%s: Fatal: "), progname); 736 vfprintf(stderr, fmt, ap); 737 fprintf(stderr, ": %s\n", errstr); 738 va_end(ap); 739 740 longjmp(err_main, 2); 741 } 742 743 void 744 die_create_error(int error) 745 { 746 fprintf(stderr, gettext("snapshot error: ")); 747 switch (error) { 748 case FIOCOW_EREADONLY: 749 fprintf(stderr, gettext("Read only file system\n")); 750 break; 751 case FIOCOW_EBUSY: 752 fprintf(stderr, gettext("Snapshot already enabled\n")); 753 break; 754 case FIOCOW_EULOCK: 755 fprintf(stderr, gettext("File system is locked\n")); 756 break; 757 case FIOCOW_EWLOCK: 758 fprintf(stderr, 759 gettext("File system could not be write locked\n")); 760 break; 761 case FIOCOW_EFLUSH: 762 fprintf(stderr, gettext("File system could not be flushed\n")); 763 break; 764 case FIOCOW_ECLEAN: 765 fprintf(stderr, gettext("File system may not be stable\n")); 766 break; 767 case FIOCOW_ENOULOCK: 768 fprintf(stderr, gettext("File system could not be unlocked\n")); 769 break; 770 case FIOCOW_ECHUNKSZ: 771 fprintf(stderr, gettext("Chunk size must be a multiple of the " 772 "fragment size\n")); 773 break; 774 case FIOCOW_ECREATE: 775 fprintf(stderr, gettext("Could not allocate or create " 776 "a new snapshot\n")); 777 break; 778 case FIOCOW_EBITMAP: 779 fprintf(stderr, 780 gettext("Error scanning file system bitmaps\n")); 781 break; 782 case FIOCOW_EBACKFILE: 783 fprintf(stderr, gettext("Invalid backing file path\n")); 784 break; 785 default: 786 fprintf(stderr, gettext("Unknown create error\n")); 787 break; 788 } 789 790 longjmp(err_main, 2); 791 } 792 793 void 794 die(char *fmt, ...) 795 { 796 va_list ap; 797 798 va_start(ap, fmt); 799 fprintf(stderr, gettext("%s: Fatal: "), progname); 800 vfprintf(stderr, fmt, ap); 801 fprintf(stderr, "\n"); 802 va_end(ap); 803 804 longjmp(err_main, 2); 805 } 806 807 void 808 usage(void) 809 { 810 int i; 811 char *use_str[] = { 812 " %s [-F ufs] [-V] -o backing-store=path,[special_options] " 813 "/mount/point\n", 814 " %s -d [-F ufs] [-V] /mount/point | dev\n", 815 " %s -i [-F ufS] [-V] [-o special-options] /mount/point " 816 "| dev\n", 817 NULL 818 }; 819 fprintf(stderr, gettext("Usage:\n")); 820 for (i = 0; use_str[i] != NULL; i++) 821 fprintf(stderr, gettext(use_str[i]), progname); 822 } 823