/* Currently we use sfdisk for getting and setting the ID byte. In * future, extend parted to provide this functionality. As a result * of using sfdisk, this won't work for non-MBR-style partitions, but * that limitation is noted in the documentation and we can extend it * later without breaking the ABI. */ int do_part_get_mbr_id (const char *device, int partnum) { if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } char partnum_str[16]; snprintf (partnum_str, sizeof partnum_str, "%d", partnum); char *out, *err; int r; udev_settle (); r = command (&out, &err, "sfdisk", "--print-id", device, partnum_str, NULL); if (r == -1) { reply_with_error ("sfdisk --print-id: %s", err); free (out); free (err); return -1; } free (err); udev_settle (); /* It's printed in hex ... */ int id; if (sscanf (out, "%x", &id) != 1) { reply_with_error ("sfdisk --print-id: cannot parse output: %s", out); free (out); return -1; } free (out); return id; }
static int dosfslabel (const char *device, const char *label) { int r; CLEANUP_FREE char *err = NULL; r = command (NULL, &err, str_dosfslabel, device, label, NULL); if (r == -1) { reply_with_error ("%s", err); return -1; } return 0; }
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 swap_set_uuid (const char *device, const char *uuid) { int r; CLEANUP_FREE char *err = NULL; r = command (NULL, &err, "swaplabel", "-U", uuid, device, NULL); if (r == -1) { reply_with_error ("%s", err); return -1; } return 0; }
int do_md_stop (const char *md) { int r; CLEANUP_FREE char *err = NULL; const char *mdadm[] = { str_mdadm, "--stop", md, NULL}; r = commandv (NULL, &err, mdadm); if (r == -1) { reply_with_error ("%s", err); return -1; } return 0; }
int do_scrub_device (const char *device) { CLEANUP_FREE char *err = NULL; int r; r = command (NULL, &err, str_scrub, device, NULL); if (r == -1) { reply_with_error ("%s: %s", device, err); return -1; } return 0; }
static int e2uuid (const char *device, const char *uuid) { /* Don't allow the magic values here. If callers want to do this * we'll add alternate set_uuid_* calls. */ if (STREQ (uuid, "clear") || STREQ (uuid, "random") || STREQ (uuid, "time")) { reply_with_error ("e2: invalid new UUID"); return -1; } return do_set_e2uuid (device, uuid); }
/* Takes optional arguments, consult optargs_bitmask. */ int do_ntfsresize (const char *device, int64_t size, int force) { CLEANUP_FREE char *err = NULL; int r; const char *argv[MAX_ARGS]; size_t i = 0; char size_str[32]; ADD_ARG (argv, i, str_ntfsresize); ADD_ARG (argv, i, "-P"); if (optargs_bitmask & GUESTFS_NTFSRESIZE_SIZE_BITMASK) { if (size <= 0) { reply_with_error ("size is zero or negative"); return -1; } snprintf (size_str, sizeof size_str, "%" PRIi64, size); ADD_ARG (argv, i, "--size"); ADD_ARG (argv, i, size_str); } if (optargs_bitmask & GUESTFS_NTFSRESIZE_FORCE_BITMASK && force) ADD_ARG (argv, i, "--force"); ADD_ARG (argv, i, device); ADD_ARG (argv, i, NULL); r = commandvf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, argv); if (r == -1) { reply_with_error ("%s: %s", device, err); return -1; } return 0; }
/* Run 'ldd' on a file from the appliance. * See tests/regressions/rhbz727178.sh */ static char * debug_ldd (const char *subcmd, size_t argc, char *const *const argv) { int r; char *out, *ret; CLEANUP_FREE char *err = NULL; if (argc != 1) { reply_with_error ("ldd: no file argument"); return NULL; } /* Note that 'ldd' doesn't fail if it finds errors. We have to grep * for errors in the regression test instead. 'ldd' only fails here * if the binary is not a binary at all (eg. for shell scripts). * Also 'ldd' randomly sends messages to stderr and errors to stdout * depending on the phase of the moon. */ r = command (&out, &err, str_ldd, "-r", argv[0], NULL); if (r == -1) { reply_with_error ("ldd: %s: %s", argv[0], err); free (out); return NULL; } /* Concatenate stdout and stderr in the result. */ ret = realloc (out, strlen (out) + strlen (err) + 1); if (ret == NULL) { reply_with_perror ("realloc"); free (out); return NULL; } strcat (ret, err); return ret; }
char * get_blkid_tag (const char *device, const char *tag) { char *out; CLEANUP_FREE char *err = NULL; int r; size_t len; r = commandr (&out, &err, str_blkid, /* Adding -c option kills all caching, even on RHEL 5. */ "-c", "/dev/null", "-o", "value", "-s", tag, device, NULL); if (r != 0 && r != 2) { if (r >= 0) reply_with_error ("%s: %s (blkid returned %d)", device, err, r); else reply_with_error ("%s: %s", device, err); free (out); return NULL; } if (r == 2) { /* means UUID etc not found */ free (out); out = strdup (""); if (out == NULL) reply_with_perror ("strdup"); return out; } /* Trim trailing \n if present. */ len = strlen (out); if (len > 0 && out[len-1] == '\n') out[len-1] = '\0'; return out; /* caller frees */ }
int do_mke2fs_JL (const char *fstype, int blocksize, const char *device, const char *label) { CLEANUP_FREE char *err = NULL; int r; if (!fstype_is_extfs (fstype)) { reply_with_error ("%s: not a valid extended filesystem type", fstype); return -1; } if (strlen (label) > EXT2_LABEL_MAX) { reply_with_error ("%s: ext2/3/4 labels are limited to %d bytes", label, EXT2_LABEL_MAX); return -1; } char blocksize_s[32]; snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); size_t len = strlen (label); char jdev[len+32]; snprintf (jdev, len+32, "device=LABEL=%s", label); wipe_device_before_mkfs (device); r = command (NULL, &err, str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, device, NULL); if (r == -1) { reply_with_error ("%s", err); return -1; } return 0; }
/* zcat | file */ char * do_zfile (const char *method, const char *path) { size_t len; const char *zcat; CLEANUP_FREE char *cmd = NULL; FILE *fp; char line[256]; if (STREQ (method, "gzip") || STREQ (method, "compress")) zcat = str_zcat; else if (STREQ (method, "bzip2")) zcat = str_bzcat; else { reply_with_error ("unknown method"); return NULL; } if (asprintf_nowarn (&cmd, "%s %R | file -bsL -", zcat, path) == -1) { reply_with_perror ("asprintf"); return NULL; } if (verbose) fprintf (stderr, "%s\n", cmd); fp = popen (cmd, "r"); if (fp == NULL) { reply_with_perror ("%s", cmd); return NULL; } if (fgets (line, sizeof line, fp) == NULL) { reply_with_perror ("fgets"); pclose (fp); return NULL; } if (pclose (fp) == -1) { reply_with_perror ("pclose"); return NULL; } len = strlen (line); if (len > 0 && line[len-1] == '\n') line[len-1] = '\0'; return strdup (line); }
void reply (xdrproc_t xdrp, char *ret) { XDR xdr; CLEANUP_FREE char *buf = NULL; char lenbuf[4]; struct guestfs_message_header hdr; uint32_t len; buf = malloc (GUESTFS_MESSAGE_MAX); if (!buf) error (EXIT_FAILURE, errno, "malloc"); xdrmem_create (&xdr, buf, GUESTFS_MESSAGE_MAX, XDR_ENCODE); memset (&hdr, 0, sizeof hdr); hdr.prog = GUESTFS_PROGRAM; hdr.vers = GUESTFS_PROTOCOL_VERSION; hdr.direction = GUESTFS_DIRECTION_REPLY; hdr.status = GUESTFS_STATUS_OK; hdr.proc = proc_nr; hdr.serial = serial; if (!xdr_guestfs_message_header (&xdr, &hdr)) error (EXIT_FAILURE, 0, "failed to encode reply header"); if (xdrp) { /* This can fail if the reply body is too large, for example * if it exceeds the maximum message size. In that case * we want to return an error message instead. (RHBZ#509597). */ if (!(*xdrp) (&xdr, ret)) { reply_with_error ("guestfsd: failed to encode reply body\n(maybe the reply exceeds the maximum message size in the protocol?)"); xdr_destroy (&xdr); return; } } len = xdr_getpos (&xdr); xdr_destroy (&xdr); xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE); xdr_u_int (&xdr, &len); xdr_destroy (&xdr); if (xwrite (sock, lenbuf, 4) == -1) error (EXIT_FAILURE, 0, "xwrite failed"); if (xwrite (sock, buf, (size_t) len) == -1) error (EXIT_FAILURE, 0, "xwrite failed"); }
int do_touch (const char *path) { int fd; int r; struct stat buf; /* RHBZ#582484: Restrict touch to regular files. It's also OK * here if the file does not exist, since we will create it. */ CHROOT_IN; r = lstat (path, &buf); CHROOT_OUT; if (r == -1) { if (errno != ENOENT) { reply_with_perror ("lstat: %s", path); return -1; } } else { if (! S_ISREG (buf.st_mode)) { reply_with_error ("%s: touch can only be used on a regular files", path); return -1; } } CHROOT_IN; fd = open (path, O_WRONLY | O_CREAT | O_NOCTTY, 0666); CHROOT_OUT; if (fd == -1) { reply_with_perror ("open: %s", path); return -1; } r = futimens (fd, NULL); if (r == -1) { reply_with_perror ("futimens: %s", path); close (fd); return -1; } if (close (fd) == -1) { reply_with_perror ("close: %s", path); return -1; } return 0; }
int do_part_init (const char *device, const char *parttype) { parttype = check_parttype (parttype); if (!parttype) { reply_with_error ("unknown partition type: common choices are \"gpt\" and \"msdos\""); return -1; } RUN_PARTED (return -1, device, "mklabel", parttype, NULL); udev_settle (); return 0; }
char * do_ldmtool_diskgroup_name (const char *diskgroup) { int r; CLEANUP_FREE char *out = NULL, *err = NULL; r = command (&out, &err, "ldmtool", "show", "diskgroup", diskgroup, NULL); if (r == -1) { reply_with_error ("%s", err); return NULL; } return parse_json_get_object_string (out, "name", 0, __func__, "ldmtool show diskgroup"); }
/* Return canonical name of LV to caller (RHBZ#638899). */ char * do_lvm_canonical_lv_name (const char *device) { char *canonical; int r = lv_canonical (device, &canonical); if (r == -1) return NULL; if (r == 0) { reply_with_error ("%s: not a logical volume", device); return NULL; } return canonical; /* caller frees */ }
int do_part_to_partnum (const char *part) { int err = 1; size_t n = strlen (part); while (n >= 1 && c_isdigit (part[n-1])) { err = 0; n--; } if (err) { reply_with_error ("device name is not a partition"); return -1; } int r; if (sscanf (&part[n], "%d", &r) != 1) { reply_with_error ("could not parse number"); return -1; } return r; }
char * do_part_get_name (const char *device, int partnum) { CLEANUP_FREE char *parttype; parttype = do_part_get_parttype (device); if (parttype == NULL) return NULL; if (STREQ (parttype, "gpt")) { CLEANUP_FREE char *out = print_partition_table (device, true); if (!out) return NULL; CLEANUP_FREE_STRING_LIST char **lines = split_lines (out); if (!lines) return NULL; if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) { reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s", lines[0] ? lines[0] : "(signature was null)"); return NULL; } if (lines[1] == NULL) { reply_with_error ("parted didn't return a line describing the device"); return NULL; } size_t row; int pnum; for (row = 2; lines[row] != NULL; ++row) { if (sscanf (lines[row], "%d:", &pnum) != 1) { reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); return NULL; } if (pnum == partnum) break; } if (lines[row] == NULL) { reply_with_error ("partition number %d not found", partnum); return NULL; } char *name = get_table_field (lines[row], 5); if (name == NULL) reply_with_error ("cannot get the name field from '%s'", lines[row]); return name; } else { reply_with_error ("part-get-name can only be used on GUID Partition Tables"); return NULL; } }
int do_vgscan (void) { CLEANUP_FREE char *err = NULL; int r; r = command (NULL, &err, str_lvm, "vgscan", NULL); if (r == -1) { reply_with_error ("%s", err); return -1; } return 0; }
/* setcon is only valid under the following circumstances: * - single threaded * - enforcing=0 */ int do_setcon (const char *context) { #if defined(HAVE_SETCON) if (setcon ((char *) context) == -1) { reply_with_perror ("setcon"); return -1; } return 0; #else reply_with_error ("function not available"); return -1; #endif }
int64_t xfs_minimum_size (const char *path) { CLEANUP_FREE guestfs_int_xfsinfo *info = do_xfs_info (path); if (info == NULL) return -1; // XFS does not support shrinking. if (INT64_MAX / info->xfs_blocksize < info->xfs_datablocks) { reply_with_error ("filesystem size too big: overflow"); return -1; } return info->xfs_blocksize * info->xfs_datablocks; }
/* Send back an error of different lengths. */ static char * debug_error (const char *subcmd, size_t argc, char *const *const argv) { unsigned len; CLEANUP_FREE char *buf = NULL; if (argc != 1) { error: reply_with_error ("debug error: expecting one arg: length of error message"); return NULL; } if (sscanf (argv[0], "%u", &len) != 1) goto error; if (len > 1000000) { reply_with_error ("debug error: length argument too large"); return NULL; } buf = malloc (len + 1); if (buf == NULL) { reply_with_perror ("malloc"); return NULL; } memset (buf, 'a', len); buf[len] = '\0'; /* So that the regression test can tell this is the true return path * from the function and not an actual error, we set errno to some * value that cannot be returned by any other error path. */ reply_with_error_errno (EROFS, "%s", buf); return NULL; }
static int wc (const char *flag, const char *path) { CLEANUP_FREE char *out = NULL, *err = NULL; int fd, flags, r; CHROOT_IN; fd = open (path, O_RDONLY|O_CLOEXEC); 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); return -1; } #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); return -1; } return r; }
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; }
/* Print the environment that commands get (by running external printenv). */ static char * debug_env (const char *subcmd, size_t argc, char *const *const argv) { int r; char *out; CLEANUP_FREE char *err = NULL; r = command (&out, &err, str_printenv, NULL); if (r == -1) { reply_with_error ("printenv: %s", err); free (out); return NULL; } return out; }
int do_md_stop(const char *md) { int r; char *err = NULL; const char *mdadm[] = { "mdadm", "--stop", md, NULL}; r = commandv(NULL, &err, mdadm); if (r == -1) { reply_with_error("%s", err); free(err); return -1; } free (err); return 0; }
int do_fsck (const char *fstype, const char *device) { char *err; int r; r = commandr (NULL, &err, "fsck", "-a", "-t", fstype, device, NULL); if (r == -1) { reply_with_error ("%s: %s", device, err); free (err); return -1; } free (err); return r; }
char * do_debug (const char *subcmd, char *const *argv) { size_t argc, i; for (i = argc = 0; argv[i] != NULL; ++i) argc++; for (i = 0; cmds[i].cmd != NULL; ++i) { if (STRCASEEQ (subcmd, cmds[i].cmd)) return cmds[i].f (subcmd, argc, argv); } reply_with_error ("use 'debug help 0' to list the supported commands"); return NULL; }
int do_part_del (const char *device, int partnum) { if (partnum <= 0) { reply_with_error ("partition number must be >= 1"); return -1; } char partnum_str[16]; snprintf (partnum_str, sizeof partnum_str, "%d", partnum); RUN_PARTED (return -1, device, "rm", partnum_str, NULL); udev_settle (); return 0; }