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