/* List is built in reverse order, so mount them in reverse order. */ void mount_mps (struct mp *mp) { int r; if (mp) { mount_mps (mp->next); const char *options; if (mp->options) options = mp->options; else if (read_only) options = "ro"; else options = ""; if (mp->fstype) r = guestfs_mount_vfs (g, options, mp->fstype, mp->device, mp->mountpoint); else r = guestfs_mount_options (g, options, mp->device, mp->mountpoint); if (r == -1) { display_mountpoints_on_failure (mp->device, mp->options); exit (EXIT_FAILURE); } } }
/* List is built in reverse order, so mount them in reverse order. */ void mount_mps (struct mp *mp) { int r; if (mp) { mount_mps (mp->next); const char *options; if (mp->options) options = mp->options; else if (read_only) options = "ro"; else options = ""; /* Don't use guestfs_mount here because that will default to mount * options -o sync,noatime. For more information, see guestfs(3) * section "LIBGUESTFS GOTCHAS". */ r = guestfs_mount_options (g, options, mp->device, mp->mountpoint); if (r == -1) { display_mountpoints_on_failure (mp->device); exit (EXIT_FAILURE); } } }
int main (int argc, char *argv[]) { /* Current time for --time-days, --time-relative output. */ time (&now); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEBASEDIR); textdomain (PACKAGE); enum { HELP_OPTION = CHAR_MAX + 1 }; static const char options[] = "a:c:d:hlm:RvVx"; static const struct option long_options[] = { { "add", 1, 0, 'a' }, { "checksum", 2, 0, 0 }, { "checksums", 2, 0, 0 }, { "csv", 0, 0, 0 }, { "connect", 1, 0, 'c' }, { "domain", 1, 0, 'd' }, { "echo-keys", 0, 0, 0 }, { "extra-stat", 0, 0, 0 }, { "extra-stats", 0, 0, 0 }, { "format", 2, 0, 0 }, { "help", 0, 0, HELP_OPTION }, { "human-readable", 0, 0, 'h' }, { "key", 1, 0, 0 }, { "keys-from-stdin", 0, 0, 0 }, { "long", 0, 0, 'l' }, { "long-options", 0, 0, 0 }, { "mount", 1, 0, 'm' }, { "recursive", 0, 0, 'R' }, { "short-options", 0, 0, 0 }, { "time", 0, 0, 0 }, { "times", 0, 0, 0 }, { "time-days", 0, 0, 0 }, { "time-relative", 0, 0, 0 }, { "time-t", 0, 0, 0 }, { "uid", 0, 0, 0 }, { "uids", 0, 0, 0 }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; struct drv *drvs = NULL; struct drv *drv; struct mp *mps = NULL; struct mp *mp; char *p; const char *format = NULL; bool format_consumed = true; int c; int option_index; #define MODE_LS_L 1 #define MODE_LS_R 2 #define MODE_LS_LR (MODE_LS_L|MODE_LS_R) int mode = 0; struct key_store *ks = NULL; g = guestfs_create (); if (g == NULL) error (EXIT_FAILURE, errno, "guestfs_create"); for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* options which are long only */ if (STREQ (long_options[option_index].name, "long-options")) display_long_options (long_options); else if (STREQ (long_options[option_index].name, "short-options")) display_short_options (options); else if (STREQ (long_options[option_index].name, "keys-from-stdin")) { keys_from_stdin = 1; } else if (STREQ (long_options[option_index].name, "echo-keys")) { echo_keys = 1; } else if (STREQ (long_options[option_index].name, "format")) { OPTION_format; } else if (STREQ (long_options[option_index].name, "checksum") || STREQ (long_options[option_index].name, "checksums")) { if (!optarg || STREQ (optarg, "")) checksum = "md5"; else checksum = optarg; } else if (STREQ (long_options[option_index].name, "csv")) { csv = 1; } else if (STREQ (long_options[option_index].name, "extra-stat") || STREQ (long_options[option_index].name, "extra-stats")) { enable_extra_stats = 1; } else if (STREQ (long_options[option_index].name, "time") || STREQ (long_options[option_index].name, "times")) { enable_times = 1; } else if (STREQ (long_options[option_index].name, "time-t")) { enable_times = 1; time_t_output = 1; } else if (STREQ (long_options[option_index].name, "time-relative")) { enable_times = 1; time_t_output = 1; time_relative = 1; } else if (STREQ (long_options[option_index].name, "time-days")) { enable_times = 1; time_t_output = 1; time_relative = 2; } else if (STREQ (long_options[option_index].name, "uid") || STREQ (long_options[option_index].name, "uids")) { enable_uids = 1; } else if (STREQ (long_options[option_index].name, "key")) { OPTION_key; } else error (EXIT_FAILURE, 0, _("unknown long option: %s (%d)"), long_options[option_index].name, option_index); break; case 'a': OPTION_a; break; case 'c': OPTION_c; break; case 'd': OPTION_d; break; case 'h': human = 1; break; case 'l': mode |= MODE_LS_L; break; case 'm': OPTION_m; inspector = 0; break; case 'R': mode |= MODE_LS_R; break; case 'v': OPTION_v; break; case 'V': OPTION_V; break; case 'x': OPTION_x; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } /* Old-style syntax? There were no -a or -d options in the old * virt-ls which is how we detect this. */ if (drvs == NULL) { /* argc - 1 because last parameter is the single directory name. */ while (optind < argc - 1) { if (strchr (argv[optind], '/') || access (argv[optind], F_OK) == 0) { /* simulate -a option */ drv = calloc (1, sizeof (struct drv)); if (!drv) error (EXIT_FAILURE, errno, "calloc"); drv->type = drv_a; drv->a.filename = strdup (argv[optind]); if (!drv->a.filename) error (EXIT_FAILURE, errno, "strdup"); drv->next = drvs; drvs = drv; } else { /* simulate -d option */ drv = calloc (1, sizeof (struct drv)); if (!drv) error (EXIT_FAILURE, errno, "calloc"); drv->type = drv_d; drv->d.guest = argv[optind]; drv->next = drvs; drvs = drv; } optind++; } } /* These are really constants, but they have to be variables for the * options parsing code. Assert here that they have known-good * values. */ assert (read_only == 1); assert (inspector == 1 || mps != NULL); assert (live == 0); CHECK_OPTION_format_consumed; /* Many flags only apply to -lR mode. */ if (mode != MODE_LS_LR && (csv || human || enable_uids || enable_times || enable_extra_stats || checksum)) error (EXIT_FAILURE, 0, _("used a flag which can only be combined with -lR mode\nFor more information, read the virt-ls(1) man page.")); /* CSV && human is unsafe because spreadsheets fail to parse these * fields correctly. (RHBZ#600977). */ if (human && csv) error (EXIT_FAILURE, 0, _("you cannot use -h and --csv options together.")); /* User must specify at least one directory name on the command line. */ if (optind >= argc || argc - optind < 1) usage (EXIT_FAILURE); /* User must have specified some drives. */ if (drvs == NULL) { fprintf (stderr, _("%s: error: you must specify at least one -a or -d option.\n"), getprogname ()); usage (EXIT_FAILURE); } /* Add drives, inspect and mount. */ add_drives (drvs); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); if (mps != NULL) mount_mps (mps); else inspect_mount (); /* Free up data structures, no longer needed after this point. */ free_drives (drvs); free_mps (mps); free_key_store (ks); unsigned errors = 0; while (optind < argc) { const char *dir = argv[optind]; switch (mode) { case 0: /* no -l or -R option */ if (do_ls (dir) == -1) errors++; break; case MODE_LS_L: /* virt-ls -l */ if (do_ls_l (dir) == -1) errors++; break; case MODE_LS_R: /* virt-ls -R */ if (do_ls_R (dir) == -1) errors++; break; case MODE_LS_LR: /* virt-ls -lR */ if (do_ls_lR (dir) == -1) errors++; break; default: abort (); /* can't happen */ } optind++; } guestfs_close (g); exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
int main (int argc, char *argv[]) { setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEBASEDIR); textdomain (PACKAGE); parse_config (); enum { HELP_OPTION = CHAR_MAX + 1 }; /* The command line arguments are broadly compatible with (a subset * of) guestfish. Thus we have to deal mainly with -a, -m and --ro. */ static const char options[] = "a:c:d:im:no:rvVwx"; static const struct option long_options[] = { { "add", 1, 0, 'a' }, { "connect", 1, 0, 'c' }, { "dir-cache-timeout", 1, 0, 0 }, { "domain", 1, 0, 'd' }, { "echo-keys", 0, 0, 0 }, { "fd", 1, 0, 0 }, { "format", 2, 0, 0 }, { "fuse-help", 0, 0, 0 }, { "help", 0, 0, HELP_OPTION }, { "inspector", 0, 0, 'i' }, { "keys-from-stdin", 0, 0, 0 }, { "live", 0, 0, 0 }, { "long-options", 0, 0, 0 }, { "mount", 1, 0, 'm' }, { "no-fork", 0, 0, 0 }, { "no-sync", 0, 0, 'n' }, { "option", 1, 0, 'o' }, { "pid-file", 1, 0, 0 }, { "ro", 0, 0, 'r' }, { "rw", 0, 0, 'w' }, { "selinux", 0, 0, 0 }, { "short-options", 0, 0, 0 }, { "trace", 0, 0, 'x' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; struct drv *drvs = NULL; struct mp *mps = NULL; struct mp *mp; char *p; const char *format = NULL; bool format_consumed = true; int c, r; int option_index; struct sigaction sa; int debug_calls = 0; int dir_cache_timeout = -1; int do_fork = 1; char *fuse_options = NULL; char *pid_file = NULL; int pipe_fd = -1; struct guestfs_mount_local_argv optargs; /* LC_ALL=C is required so we can parse error messages. */ setenv ("LC_ALL", "C", 1); memset (&sa, 0, sizeof sa); sa.sa_handler = SIG_IGN; sa.sa_flags = SA_RESTART; sigaction (SIGPIPE, &sa, NULL); g = guestfs_create (); if (g == NULL) error (EXIT_FAILURE, errno, "guestfs_create"); for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* options which are long only */ if (STREQ (long_options[option_index].name, "long-options")) display_long_options (long_options); else if (STREQ (long_options[option_index].name, "short-options")) display_short_options (options); else if (STREQ (long_options[option_index].name, "dir-cache-timeout")) dir_cache_timeout = atoi (optarg); else if (STREQ (long_options[option_index].name, "fuse-help")) fuse_help (); else if (STREQ (long_options[option_index].name, "selinux")) { /* nothing */ } else if (STREQ (long_options[option_index].name, "format")) { OPTION_format; } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) { keys_from_stdin = 1; } else if (STREQ (long_options[option_index].name, "echo-keys")) { echo_keys = 1; } else if (STREQ (long_options[option_index].name, "live")) { live = 1; } else if (STREQ (long_options[option_index].name, "pid-file")) { pid_file = optarg; } else if (STREQ (long_options[option_index].name, "no-fork")) { do_fork = 0; } else if (STREQ (long_options[option_index].name, "fd")) { if (sscanf (optarg, "%d", &pipe_fd) != 1 || pipe_fd < 0) error (EXIT_FAILURE, 0, _("unable to parse --fd option value: %s"), optarg); } else error (EXIT_FAILURE, 0, _("unknown long option: %s (%d)"), long_options[option_index].name, option_index); break; case 'a': OPTION_a; break; case 'c': OPTION_c; break; case 'd': OPTION_d; break; case 'i': OPTION_i; break; case 'm': OPTION_m; break; case 'n': OPTION_n; break; case 'o': fuse_opt_add_opt_escaped (&fuse_options, optarg); break; case 'r': OPTION_r; break; case 'v': OPTION_v; break; case 'V': OPTION_V; break; case 'w': OPTION_w; break; case 'x': OPTION_x; debug_calls = 1; do_fork = 0; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } CHECK_OPTION_format_consumed; /* Check we have the right options. */ if (!live) { if (drvs == NULL) { fprintf (stderr, _("%s: error: you must specify at least one -a or -d option.\n"), getprogname ()); usage (EXIT_FAILURE); } if (!(mps || inspector)) { fprintf (stderr, _("%s: error: you must specify either -i at least one -m option.\n"), getprogname ()); usage (EXIT_FAILURE); } } else { size_t count_d = 0, count_other = 0; struct drv *drv; if (read_only) error (EXIT_FAILURE, 0, _("--live is not compatible with --ro option")); if (inspector) error (EXIT_FAILURE, 0, _("--live is not compatible with -i option")); /* --live: make sure there was one -d option and no -a options */ for (drv = drvs; drv; drv = drv->next) { if (drv->type == drv_d) count_d++; else count_other++; } if (count_d != 1) error (EXIT_FAILURE, 0, _("with --live, you must use exactly one -d option")); if (count_other != 0) error (EXIT_FAILURE, 0, _("--live is not compatible with -a option")); } /* We'd better have a mountpoint. */ if (optind+1 != argc) error (EXIT_FAILURE, 0, _("you must specify a mountpoint in the host filesystem")); /* If we're forking, we can't use the recovery process. */ if (guestfs_set_recovery_proc (g, !do_fork) == -1) exit (EXIT_FAILURE); /* Do the guest drives and mountpoints. */ add_drives (drvs, 'a'); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); if (inspector) inspect_mount (); mount_mps (mps); free_drives (drvs); free_mps (mps); /* FUSE example does this, not clear if it's necessary, but ... */ if (guestfs_umask (g, 0) == -1) exit (EXIT_FAILURE); optargs.bitmask = 0; if (read_only) { optargs.bitmask |= GUESTFS_MOUNT_LOCAL_READONLY_BITMASK; optargs.readonly = 1; } if (debug_calls) { optargs.bitmask |= GUESTFS_MOUNT_LOCAL_DEBUGCALLS_BITMASK; optargs.debugcalls = 1; } if (dir_cache_timeout > 0) { optargs.bitmask |= GUESTFS_MOUNT_LOCAL_CACHETIMEOUT_BITMASK; optargs.cachetimeout = dir_cache_timeout; } if (fuse_options != NULL) { optargs.bitmask |= GUESTFS_MOUNT_LOCAL_OPTIONS_BITMASK; optargs.options = fuse_options; } if (guestfs_mount_local_argv (g, argv[optind], &optargs) == -1) exit (EXIT_FAILURE); /* Daemonize. */ if (do_fork) { pid_t pid; int fd; pid = fork (); if (pid == -1) error (EXIT_FAILURE, errno, "fork"); if (pid != 0) { /* parent */ if (write_pid_file (pid_file, pid) == -1) _exit (EXIT_FAILURE); if (write_pipe_fd (pipe_fd) == -1) _exit (EXIT_FAILURE); _exit (EXIT_SUCCESS); } /* Emulate what old fuse_daemonize used to do. */ if (setsid () == -1) error (EXIT_FAILURE, errno, "setsid"); ignore_value (chdir ("/")); fd = open ("/dev/null", O_RDWR); if (fd >= 0) { dup2 (fd, 0); dup2 (fd, 1); dup2 (fd, 2); if (fd > 2) close (fd); } } else { /* not forking, write PID file and pipe FD anyway */ if (write_pid_file (pid_file, getpid ()) == -1) exit (EXIT_FAILURE); if (write_pipe_fd (pipe_fd) == -1) exit (EXIT_FAILURE); } /* At the last minute, remove the libguestfs error handler. In code * above this point, the default error handler has been used which * sends all errors to stderr. From now on, the FUSE code will * convert errors into error codes (errnos) when appropriate. */ guestfs_push_error_handler (g, NULL, NULL); /* Main loop. */ r = guestfs_mount_local_run (g); guestfs_pop_error_handler (g); /* Cleanup. */ if (guestfs_shutdown (g) == -1) r = -1; guestfs_close (g); /* Don't delete PID file until the cleanup has been completed. */ if (pid_file) unlink (pid_file); exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
int main (int argc, char *argv[]) { setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEBASEDIR); textdomain (PACKAGE); parse_config (); enum { HELP_OPTION = CHAR_MAX + 1 }; /* The command line arguments are broadly compatible with (a subset * of) guestfish. Thus we have to deal mainly with -a, -m and --ro. */ static const char *options = "a:c:d:im:no:rv?Vwx"; static const struct option long_options[] = { { "add", 1, 0, 'a' }, { "connect", 1, 0, 'c' }, { "dir-cache-timeout", 1, 0, 0 }, { "domain", 1, 0, 'd' }, { "echo-keys", 0, 0, 0 }, { "format", 2, 0, 0 }, { "fuse-help", 0, 0, 0 }, { "help", 0, 0, HELP_OPTION }, { "inspector", 0, 0, 'i' }, { "keys-from-stdin", 0, 0, 0 }, { "live", 0, 0, 0 }, { "mount", 1, 0, 'm' }, { "no-sync", 0, 0, 'n' }, { "option", 1, 0, 'o' }, { "ro", 0, 0, 'r' }, { "rw", 0, 0, 'w' }, { "selinux", 0, 0, 0 }, { "trace", 0, 0, 'x' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; struct drv *drvs = NULL; struct drv *drv; struct mp *mps = NULL; struct mp *mp; char *p; const char *format = NULL; int c, r; int option_index; struct sigaction sa; int fuse_argc = 0; const char **fuse_argv = NULL; #define ADD_FUSE_ARG(str) \ do { \ fuse_argc ++; \ fuse_argv = realloc (fuse_argv, (1+fuse_argc) * sizeof (char *)); \ if (!fuse_argv) { \ perror ("realloc"); \ exit (EXIT_FAILURE); \ } \ fuse_argv[fuse_argc-1] = (str); \ fuse_argv[fuse_argc] = NULL; \ } while (0) /* LC_ALL=C is required so we can parse error messages. */ setenv ("LC_ALL", "C", 1); /* Set global program name that is not polluted with libtool artifacts. */ set_program_name (argv[0]); memset (&sa, 0, sizeof sa); sa.sa_handler = SIG_IGN; sa.sa_flags = SA_RESTART; sigaction (SIGPIPE, &sa, NULL); /* Various initialization. */ init_dir_caches (); g = guestfs_create (); if (g == NULL) { fprintf (stderr, _("guestfs_create: failed to create handle\n")); exit (EXIT_FAILURE); } guestfs_set_recovery_proc (g, 0); ADD_FUSE_ARG (program_name); /* MUST be single-threaded. You cannot have two threads accessing the * same libguestfs handle, and opening more than one handle is likely * to be very expensive. */ ADD_FUSE_ARG ("-s"); for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* options which are long only */ if (STREQ (long_options[option_index].name, "dir-cache-timeout")) dir_cache_timeout = atoi (optarg); else if (STREQ (long_options[option_index].name, "fuse-help")) fuse_help (); else if (STREQ (long_options[option_index].name, "selinux")) guestfs_set_selinux (g, 1); else if (STREQ (long_options[option_index].name, "format")) { if (!optarg || STREQ (optarg, "")) format = NULL; else format = optarg; } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) { keys_from_stdin = 1; } else if (STREQ (long_options[option_index].name, "echo-keys")) { echo_keys = 1; } else if (STREQ (long_options[option_index].name, "live")) { live = 1; } else { fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), program_name, long_options[option_index].name, option_index); exit (EXIT_FAILURE); } break; case 'a': OPTION_a; break; case 'c': OPTION_c; break; case 'd': OPTION_d; break; case 'i': OPTION_i; break; case 'm': OPTION_m; break; case 'n': OPTION_n; break; case 'o': ADD_FUSE_ARG ("-o"); ADD_FUSE_ARG (optarg); break; case 'r': OPTION_r; break; case 'v': OPTION_v; break; case 'V': OPTION_V; break; case 'w': OPTION_w; break; case 'x': OPTION_x; ADD_FUSE_ARG ("-f"); guestfs_set_recovery_proc (g, 1); trace_calls = 1; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } /* Check we have the right options. */ if (!live) { if (!drvs || !(mps || inspector)) { fprintf (stderr, _("%s: must have at least one -a/-d and at least one -m/-i option\n"), program_name); exit (EXIT_FAILURE); } } else { size_t count_d = 0, count_other = 0; struct drv *drv; if (read_only) { fprintf (stderr, _("%s: --live is not compatible with --ro option\n"), program_name); exit (EXIT_FAILURE); } if (inspector) { fprintf (stderr, _("%s: --live is not compatible with -i option\n"), program_name); exit (EXIT_FAILURE); } /* --live: make sure there was one -d option and no -a options */ for (drv = drvs; drv; drv = drv->next) { if (drv->type == drv_d) count_d++; else count_other++; } if (count_d != 1) { fprintf (stderr, _("%s: with --live, you must use exactly one -d option\n"), program_name); exit (EXIT_FAILURE); } if (count_other != 0) { fprintf (stderr, _("%s: --live is not compatible with -a option\n"), program_name); exit (EXIT_FAILURE); } } /* We'd better have a mountpoint. */ if (optind+1 != argc) { fprintf (stderr, _("%s: you must specify a mountpoint in the host filesystem\n"), program_name); exit (EXIT_FAILURE); } /* Do the guest drives and mountpoints. */ add_drives (drvs, 'a'); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); if (inspector) inspect_mount (); mount_mps (mps); free_drives (drvs); free_mps (mps); /* FUSE example does this, not clear if it's necessary, but ... */ if (guestfs_umask (g, 0) == -1) exit (EXIT_FAILURE); /* At the last minute, remove the libguestfs error handler. In code * above this point, the default error handler has been used which * sends all errors to stderr. Now before entering FUSE itself we * want to silence errors so we can convert them (see error() * function above). */ guestfs_set_error_handler (g, NULL, NULL); /* Finish off FUSE args. */ ADD_FUSE_ARG (argv[optind]); /* It says about the line containing the for-statement: error: assuming signed overflow does not occur when simplifying conditional to constant [-Wstrict-overflow] if (verbose) { fprintf (stderr, "guestmount: invoking FUSE with args ["); for (i = 0; i < fuse_argc; ++i) { if (i > 0) fprintf (stderr, ", "); fprintf (stderr, "%s", fuse_argv[i]); } fprintf (stderr, "]\n"); } */ r = fuse_main (fuse_argc, (char **) fuse_argv, &fg_operations, NULL); /* Cleanup. */ guestfs_close (g); free_dir_caches (); exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
int main (int argc, char *argv[]) { setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEBASEDIR); textdomain (PACKAGE); /* We use random(3) below. */ srandom (time (NULL)); enum { HELP_OPTION = CHAR_MAX + 1 }; static const char *options = "a:b:c:d:e:m:vVx"; static const struct option long_options[] = { { "add", 1, 0, 'a' }, { "backup", 1, 0, 'b' }, { "connect", 1, 0, 'c' }, { "domain", 1, 0, 'd' }, { "echo-keys", 0, 0, 0 }, { "edit", 1, 0, 'e' }, { "expr", 1, 0, 'e' }, { "format", 2, 0, 0 }, { "help", 0, 0, HELP_OPTION }, { "keys-from-stdin", 0, 0, 0 }, { "long-options", 0, 0, 0 }, { "mount", 1, 0, 'm' }, { "short-options", 0, 0, 0 }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; struct drv *drvs = NULL; struct drv *drv; struct mp *mps = NULL; struct mp *mp; char *p; const char *format = NULL; bool format_consumed = true; int c; int option_index; g = guestfs_create (); if (g == NULL) { fprintf (stderr, _("guestfs_create: failed to create handle\n")); exit (EXIT_FAILURE); } for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* options which are long only */ if (STREQ (long_options[option_index].name, "long-options")) display_long_options (long_options); else if (STREQ (long_options[option_index].name, "short-options")) display_short_options (options); else if (STREQ (long_options[option_index].name, "keys-from-stdin")) { keys_from_stdin = 1; } else if (STREQ (long_options[option_index].name, "echo-keys")) { echo_keys = 1; } else if (STREQ (long_options[option_index].name, "format")) { OPTION_format; } else { fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), guestfs_int_program_name, long_options[option_index].name, option_index); exit (EXIT_FAILURE); } break; case 'a': OPTION_a; break; case 'b': if (backup_extension) { fprintf (stderr, _("%s: -b option given multiple times\n"), guestfs_int_program_name); exit (EXIT_FAILURE); } backup_extension = optarg; break; case 'c': OPTION_c; break; case 'd': OPTION_d; break; case 'e': if (perl_expr) { fprintf (stderr, _("%s: -e option given multiple times\n"), guestfs_int_program_name); exit (EXIT_FAILURE); } perl_expr = optarg; break; case 'm': OPTION_m; inspector = 0; break; case 'v': OPTION_v; break; case 'V': OPTION_V; break; case 'x': OPTION_x; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } /* Old-style syntax? There were no -a or -d options in the old * virt-edit which is how we detect this. */ if (drvs == NULL) { /* argc - 1 because last parameter is the single filename. */ while (optind < argc - 1) { if (strchr (argv[optind], '/') || access (argv[optind], F_OK) == 0) { /* simulate -a option */ drv = calloc (1, sizeof (struct drv)); if (!drv) { perror ("calloc"); exit (EXIT_FAILURE); } drv->type = drv_a; drv->a.filename = strdup (argv[optind]); if (!drv->a.filename) { perror ("strdup"); exit (EXIT_FAILURE); } drv->next = drvs; drvs = drv; } else { /* simulate -d option */ drv = calloc (1, sizeof (struct drv)); if (!drv) { perror ("calloc"); exit (EXIT_FAILURE); } drv->type = drv_d; drv->d.guest = argv[optind]; drv->next = drvs; drvs = drv; } optind++; } } /* These are really constants, but they have to be variables for the * options parsing code. Assert here that they have known-good * values. */ assert (read_only == 0); assert (inspector == 1 || mps != NULL); assert (live == 0); /* User must specify at least one filename on the command line. */ if (optind >= argc || argc - optind < 1) usage (EXIT_FAILURE); CHECK_OPTION_format_consumed; /* User must have specified some drives. */ if (drvs == NULL) usage (EXIT_FAILURE); /* Add drives. */ add_drives (drvs, 'a'); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); if (mps != NULL) mount_mps (mps); else inspect_mount (); /* Free up data structures, no longer needed after this point. */ free_drives (drvs); free_mps (mps); edit_files (argc - optind, &argv[optind]); /* Cleanly unmount the disks after editing. */ if (guestfs_shutdown (g) == -1) exit (EXIT_FAILURE); guestfs_close (g); exit (EXIT_SUCCESS); }