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