static char * checksum (const char *csumtype, int fd) { const char *program; char *out; CLEANUP_FREE char *err = NULL; int flags, r; size_t len; program = program_of_csum (csumtype); if (program == NULL) return NULL; pulse_mode_start (); flags = COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN | fd; r = commandf (&out, &err, flags, program, NULL); if (r == -1) { pulse_mode_cancel (); reply_with_error ("%s: %s", program, err); free (out); return NULL; } /* Split it at the first whitespace. */ len = strcspn (out, " \t\n"); out[len] = '\0'; pulse_mode_end (); return out; /* Caller frees. */ }
char * do_get_e2uuid (const char *device) { const mountable_t mountable = { .type = MOUNTABLE_DEVICE, .device = /* not really ... */ (char *) device, .volume = NULL, }; return do_vfs_uuid (&mountable); } /* If the filesystem is not mounted, run e2fsck -f on it unconditionally. */ static int if_not_mounted_run_e2fsck (const char *device) { CLEANUP_FREE char *err = NULL; int r, mounted; mounted = is_device_mounted (device); if (mounted == -1) return -1; if (!mounted) { r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, str_e2fsck, "-fy", device, NULL); if (r == -1) { reply_with_error ("%s", err); return -1; } } return 0; }
int do_part_init (const char *device, const char *parttype) { int r; CLEANUP_FREE char *err = NULL; parttype = check_parttype (parttype); if (!parttype) { reply_with_error ("unknown partition type: common choices are \"gpt\" and \"msdos\""); return -1; } udev_settle (); r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "parted", "-s", "--", device, "mklabel", parttype, NULL); if (r == -1) { reply_with_error ("parted: %s: %s", device, err); return -1; } udev_settle (); return 0; }
int do_part_set_gpt_guid (const char *device, int partnum, const char *guid) { if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } CLEANUP_FREE char *typecode = NULL; if (asprintf (&typecode, "%i:%s", partnum, guid) == -1) { reply_with_perror ("asprintf"); return -1; } CLEANUP_FREE char *err = NULL; int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "sgdisk", device, "-u", typecode, NULL); if (r == -1) { reply_with_error ("%s %s -u %s: %s", "sgdisk", device, typecode, err); return -1; } return 0; }
int do_part_resize (const char *device, int partnum, int64_t endsect) { int r; CLEANUP_FREE char *err = NULL; char endstr[32]; char partnum_str[16]; if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } snprintf (partnum_str, sizeof partnum_str, "%d", partnum); snprintf (endstr, sizeof endstr, "%" PRIi64 "s", endsect); udev_settle (); r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "parted", "-s", "--", device, "resizepart", partnum_str, endstr, NULL); if (r == -1) { reply_with_error ("parted: %s: %s:", device, err); return -1; } udev_settle(); return 0; }
int do_part_set_name (const char *device, int partnum, const char *name) { int r; CLEANUP_FREE char *err = NULL; if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } char partstr[16]; snprintf (partstr, sizeof partstr, "%d", partnum); udev_settle (); r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "parted", "-s", "--", device, "name", partstr, name, NULL); if (r == -1) { reply_with_error ("parted: %s: %s", device, err); return -1; } udev_settle (); return 0; }
int do_part_set_bootable (const char *device, int partnum, int bootable) { int r; char *err; if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } char partstr[16]; snprintf (partstr, sizeof partstr, "%d", partnum); udev_settle (); r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "parted", "-s", "--", device, "set", partstr, "boot", bootable ? "on" : "off", NULL); if (r == -1) { reply_with_error ("parted: %s: %s", device, err); free (err); return -1; } free (err); udev_settle (); return 0; }
int do_part_add (const char *device, const char *prlogex, int64_t startsect, int64_t endsect) { int r; char *err; char startstr[32]; char endstr[32]; /* Check and translate prlogex. */ if (STREQ (prlogex, "primary") || STREQ (prlogex, "logical") || STREQ (prlogex, "extended")) ; else if (STREQ (prlogex, "p")) prlogex = "primary"; else if (STREQ (prlogex, "l")) prlogex = "logical"; else if (STREQ (prlogex, "e")) prlogex = "extended"; else { reply_with_error ("unknown partition type: %s: this should be \"primary\", \"logical\" or \"extended\"", prlogex); return -1; } if (startsect < 0) { reply_with_error ("startsect cannot be negative"); return -1; } /* but endsect can be negative */ snprintf (startstr, sizeof startstr, "%" PRIi64 "s", startsect); snprintf (endstr, sizeof endstr, "%" PRIi64 "s", endsect); udev_settle (); /* XXX Bug: If the partition table type (which we don't know in this * function) is GPT, then this parted command sets the _partition * name_ to prlogex, eg. "primary". I would essentially describe * this as a bug in the parted mkpart command. */ r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "parted", "-s", "--", device, "mkpart", prlogex, startstr, endstr, NULL); if (r == -1) { reply_with_error ("parted: %s: %s", device, err); free (err); return -1; } free (err); udev_settle (); return 0; }
/* Run an arbitrary shell command using /bin/sh from the appliance. * * Note this is somewhat different from the ordinary guestfs_sh command * because it's not using the guest shell, and is not chrooted. */ static char * debug_sh (const char *subcmd, size_t argc, char *const *const argv) { CLEANUP_FREE char *cmd = NULL; size_t len, i, j; if (argc < 1) { reply_with_error ("sh: expecting a command to run"); return NULL; } /* guestfish splits the parameter(s) into a list of strings, * and we have to reassemble them here. Not ideal. XXX */ for (i = len = 0; i < argc; ++i) len += strlen (argv[i]) + 1; cmd = malloc (len); if (!cmd) { reply_with_perror ("malloc"); return NULL; } for (i = j = 0; i < argc; ++i) { len = strlen (argv[i]); memcpy (&cmd[j], argv[i], len); j += len; cmd[j] = ' '; j++; } cmd[j-1] = '\0'; /* Set up some environment variables. */ setenv ("root", sysroot, 1); if (access ("/sys/block/sda", F_OK) == 0) setenv ("sd", "sd", 1); else if (access ("/sys/block/hda", F_OK) == 0) setenv ("sd", "hd", 1); else if (access ("/sys/block/ubda", F_OK) == 0) setenv ("sd", "ubd", 1); else if (access ("/sys/block/vda", F_OK) == 0) setenv ("sd", "vd", 1); char *err; int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "/bin/sh", "-c", cmd, NULL); if (r == -1) { reply_with_error ("%s", err); free (err); return NULL; } return err; }
int do_part_set_disk_guid_random (const char *device) { CLEANUP_FREE char *err = NULL; int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "sgdisk", device, "-U", "R", NULL); if (r == -1) { reply_with_error ("%s %s -U R: %s", "sgdisk", device, err); return -1; } return 0; }
int do_part_expand_gpt(const char *device) { CLEANUP_FREE char *err = NULL; int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "sgdisk", "-e", device, NULL); if (r == -1) { reply_with_error ("%s -e %s: %s", "sgdisk", device, err); return -1; } return 0; }
/* Convenient place to test for the later version of e2fsprogs * and util-linux which supports -U parameters to specify UUIDs. * (Not supported in RHEL 5). */ int optgroup_linuxfsuuid_available (void) { CLEANUP_FREE char *err = NULL; int av; /* Upstream util-linux have been gradually changing '--help' to go * from stderr to stdout, and changing the return code from 1 to 0. * Thus we need to fold stdout and stderr together, and ignore the * return code. */ ignore_value (commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, str_mkswap, "--help", NULL)); av = strstr (err, "-U") != NULL; return av; }
int do_part_disk (const char *device, const char *parttype) { int r; char *err; parttype = check_parttype (parttype); if (!parttype) { reply_with_error ("unknown partition type: common choices are \"gpt\" and \"msdos\""); return -1; } /* Align all partitions created this way to 128 sectors, and leave * the last 128 sectors at the end of the disk free. This wastes * 64K+64K = 128K on 512-byte sector disks. The rationale is: * * - aligned operations are faster * - absolute minimum recommended alignment is 64K (1M would be better) * - GPT requires at least 34 sectors* at the end of the disk. * * *=except for 4k sector disks, where only 6 sectors are required */ const char *startstr = "128s"; const char *endstr = "-128s"; udev_settle (); r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "parted", "-s", "--", device, "mklabel", parttype, /* See comment about about the parted mkpart command. */ "mkpart", STREQ (parttype, "gpt") ? "p1" : "primary", startstr, endstr, NULL); if (r == -1) { reply_with_error ("parted: %s: %s", device, err); free (err); return -1; } free (err); udev_settle (); return 0; }
char * do_part_get_disk_guid (const char *device) { const char *pattern = "Disk identifier (GUID):"; size_t i; CLEANUP_FREE char *err = NULL; int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, "sgdisk", device, "-p", NULL); if (r == -1) { reply_with_error ("%s %s -p: %s", "sgdisk", device, err); return NULL; } CLEANUP_FREE_STRING_LIST char **lines = split_lines (err); if (lines == NULL) { reply_with_error ("'%s %s -p' returned no output", "sgdisk", device); return NULL; } for (i = 0; lines[i] != NULL; ++i) { if (STRPREFIX (lines[i], pattern)) { char *value = lines[i] + strlen (pattern); /* Skip any leading whitespace */ value += strspn (value, " \t"); /* Extract the actual information from the field. */ char *ret = extract_uuid (value); if (ret == NULL) { /* The extraction function already sends the error. */ return NULL; } return ret; } } /* If we got here it means we didn't find the field */ reply_with_error ("sgdisk output did not contain disk GUID. " "See LIBGUESTFS_DEBUG output for more details"); return NULL; }
static int wc (const char *flag, const char *path) { char *out, *err; int fd, flags, r; CHROOT_IN; fd = open (path, O_RDONLY); CHROOT_OUT; if (fd == -1) { reply_with_perror ("wc %s: %s", flag, path); return -1; } flags = COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN | fd; r = commandf (&out, &err, flags, "wc", flag, NULL); if (r == -1) { reply_with_error ("wc %s: %s", flag, err); free (out); free (err); return -1; } free (err); #if 0 /* Split it at the first whitespace. */ len = strcspn (out, " \t\n"); out[len] = '\0'; #endif /* Parse the number. */ if (sscanf (out, "%d", &r) != 1) { reply_with_error ("cannot parse number: %s", out); free (out); return -1; } free (out); return r; }
char * do_part_get_gpt_type(const char *device, int partnum) { if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return NULL; } CLEANUP_FREE char *partnum_str = NULL; if (asprintf (&partnum_str, "%i", partnum) == -1) { reply_with_perror ("asprintf"); return NULL; } CLEANUP_FREE char *err = NULL; int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, str_sgdisk, device, "-i", partnum_str, NULL); if (r == -1) { reply_with_error ("%s %s -i %s: %s", str_sgdisk, device, partnum_str, err); return NULL; } char **lines = split_lines (err); if (lines == NULL) { reply_with_error ("'%s %s -i %i' returned no output", str_sgdisk, device, partnum); return NULL; } /* Parse the output of sgdisk -i: * Partition GUID code: 21686148-6449-6E6F-744E-656564454649 (BIOS boot partition) * Partition unique GUID: 19AEC5FE-D63A-4A15-9D37-6FCBFB873DC0 * First sector: 2048 (at 1024.0 KiB) * Last sector: 411647 (at 201.0 MiB) * Partition size: 409600 sectors (200.0 MiB) * Attribute flags: 0000000000000000 * Partition name: 'EFI System Partition' */ for (char **i = lines; *i != NULL; i++) { char *line = *i; /* Skip blank lines */ if (line[0] == '\0') continue; /* Split the line in 2 at the colon */ char *colon = strchr (line, ':'); if (colon) { #define SEARCH "Partition GUID code" if (colon - line == strlen(SEARCH) && memcmp (line, SEARCH, strlen(SEARCH)) == 0) { #undef SEARCH /* The value starts after the colon */ char *value = colon + 1; /* Skip any leading whitespace */ value += strspn (value, " \t"); /* The value contains only valid GUID characters */ size_t value_len = strspn (value, "-0123456789ABCDEF"); char *ret = malloc (value_len + 1); if (ret == NULL) { reply_with_perror ("malloc"); return NULL; } memcpy (ret, value, value_len); ret[value_len] = '\0'; return ret; } } else { /* Ignore lines with no colon. Log to stderr so it will show up in * LIBGUESTFS_DEBUG. */ if (verbose) { fprintf (stderr, "get-gpt-type: unexpected sgdisk output ignored: %s\n", line); } } } /* If we got here it means we didn't find the Partition GUID code */ reply_with_error ("sgdisk output did not contain Partition GUID code. " "See LIBGUESTFS_DEBUG output for more details"); return NULL; }