/* Detect if chown(2) is supported on the target directory. */ static int is_chown_supported (const char *dir) { CLEANUP_FREE char *buf = NULL; int fd, r, err, saved_errno; /* Create a randomly named file. */ if (asprintf (&buf, "%s%s/XXXXXXXX.XXX", sysroot, dir) == -1) { err = errno; r = cancel_receive (); errno = err; reply_with_perror ("asprintf"); return -1; } if (random_name (buf) == -1) { err = errno; r = cancel_receive (); errno = err; reply_with_perror ("random_name"); return -1; } /* Maybe 'dir' is not a directory or filesystem not writable? */ fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0666); if (fd == -1) { err = errno; r = cancel_receive (); errno = err; reply_with_perror ("%s", dir); return -1; } /* This is the test. */ r = fchown (fd, 1000, 1000); saved_errno = errno; /* Make sure the test file is removed. */ close (fd); unlink (buf); if (r == -1 && saved_errno == EPERM) { /* This means chown is not supported by the filesystem. */ return 0; } if (r == -1) { /* Some other error? */ err = errno; r = cancel_receive (); errno = err; reply_with_perror_errno (saved_errno, "unexpected error in fchown"); return -1; } /* Else chown is supported. */ return 1; }
static char * pread_fd (int fd, int count, int64_t offset, size_t *size_r, const char *display_path) { ssize_t r; char *buf; if (count < 0) { reply_with_error ("count is negative"); close (fd); return NULL; } if (offset < 0) { reply_with_error ("offset is negative"); close (fd); return NULL; } /* The actual limit on messages is smaller than this. This check * just limits the amount of memory we'll try and allocate in the * function. If the message is larger than the real limit, that * will be caught later when we try to serialize the message. */ if (count >= GUESTFS_MESSAGE_MAX) { reply_with_error ("%s: count is too large for the protocol, use smaller reads", display_path); close (fd); return NULL; } buf = malloc (count); if (buf == NULL) { reply_with_perror ("malloc"); close (fd); return NULL; } r = pread (fd, buf, count, offset); if (r == -1) { reply_with_perror ("pread: %s", display_path); close (fd); free (buf); return NULL; } if (close (fd) == -1) { reply_with_perror ("close: %s", display_path); free (buf); return NULL; } /* Mustn't touch *size_r until we are sure that we won't return any * error (RHBZ#589039). */ *size_r = r; return buf; }
/* Has one FileIn parameter. */ int do_base64_in (const char *file) { int err, r; FILE *fp; CLEANUP_FREE char *cmd = NULL; int fd; if (asprintf_nowarn (&cmd, "%s -d -i > %R", str_base64, file) == -1) { err = errno; cancel_receive (); errno = err; reply_with_perror ("asprintf"); return -1; } if (verbose) fprintf (stderr, "%s\n", cmd); fp = popen (cmd, "w"); if (fp == NULL) { err = errno; cancel_receive (); errno = err; reply_with_perror ("%s", cmd); return -1; } /* The semantics of fwrite are too undefined, so write to the * file descriptor directly instead. */ fd = fileno (fp); r = receive_file (write_cb, &fd); if (r == -1) { /* write error */ cancel_receive (); reply_with_error ("write error on file: %s", file); pclose (fp); return -1; } if (r == -2) { /* cancellation from library */ /* This error is ignored by the library since it initiated the * cancel. Nevertheless we must send an error reply here. */ reply_with_error ("file upload cancelled"); pclose (fp); return -1; } if (pclose (fp) != 0) { reply_with_error ("base64 subcommand failed on file: %s", file); return -1; } return 0; }
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. * * XXX Coverity flags this as a time-of-check to time-of-use race * condition, particularly in the libguestfs live case. Not clear * how to fix this yet, since unconditionally opening the file can * cause a hang, so you have to somehow check it first before you * open 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|O_CLOEXEC, 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_inotify_init (int max_events) { FILE *fp; NEED_ROOT (, return -1); if (max_events < 0) { reply_with_error ("max_events < 0"); return -1; } if (max_events > 0) { fp = fopen (MQE_PATH, "w"); if (fp == NULL) { reply_with_perror (MQE_PATH); return -1; } fprintf (fp, "%d\n", max_events); fclose (fp); } if (inotify_fd >= 0) if (do_inotify_close () == -1) return -1; #ifdef HAVE_INOTIFY_INIT1 inotify_fd = inotify_init1 (IN_NONBLOCK | IN_CLOEXEC); if (inotify_fd == -1) { reply_with_perror ("inotify_init1"); return -1; } #else inotify_fd = inotify_init (); if (inotify_fd == -1) { reply_with_perror ("inotify_init"); return -1; } if (fcntl (inotify_fd, F_SETFL, O_NONBLOCK) == -1) { reply_with_perror ("fcntl: O_NONBLOCK"); close (inotify_fd); inotify_fd = -1; return -1; } if (fcntl (inotify_fd, F_SETFD, FD_CLOEXEC) == -1) { reply_with_perror ("fcntl: FD_CLOEXEC"); close (inotify_fd); inotify_fd = -1; return -1; } #endif return 0; }
guestfs_int_statns_list * do_internal_lstatnslist (const char *path, char *const *names) { int path_fd; guestfs_int_statns_list *ret; size_t i, nr_names; nr_names = count_strings (names); ret = malloc (sizeof *ret); if (!ret) { reply_with_perror ("malloc"); return NULL; } ret->guestfs_int_statns_list_len = nr_names; ret->guestfs_int_statns_list_val = calloc (nr_names, sizeof (guestfs_int_statns)); if (ret->guestfs_int_statns_list_val == NULL) { reply_with_perror ("calloc"); free (ret); return NULL; } CHROOT_IN; path_fd = open (path, O_RDONLY|O_DIRECTORY|O_CLOEXEC); CHROOT_OUT; if (path_fd == -1) { reply_with_perror ("%s", path); free (ret->guestfs_int_statns_list_val); free (ret); return NULL; } for (i = 0; names[i] != NULL; ++i) { int r; struct stat statbuf; r = fstatat (path_fd, names[i], &statbuf, AT_SYMLINK_NOFOLLOW); if (r == -1) ret->guestfs_int_statns_list_val[i].st_ino = -1; else stat_to_statns (&ret->guestfs_int_statns_list_val[i], &statbuf); } if (close (path_fd) == -1) { reply_with_perror ("close: %s", path); free (ret->guestfs_int_statns_list_val); free (ret); return NULL; } return ret; }
/* zcat | file */ char * do_zfile (const char *method, const char *path) { int len; const char *zcat; char *cmd; FILE *fp; char line[256]; if (STREQ (method, "gzip") || STREQ (method, "compress")) zcat = "zcat"; else if (STREQ (method, "bzip2")) zcat = "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); free (cmd); return NULL; } free (cmd); if (fgets (line, sizeof line, fp) == NULL) { reply_with_perror ("fgets"); fclose (fp); return NULL; } if (fclose (fp) == -1) { reply_with_perror ("fclose"); return NULL; } len = strlen (line); if (len > 0 && line[len-1] == '\n') line[len-1] = '\0'; return strdup (line); }
extern guestfs_int_mdstat_list * do_md_stat (const char *md) { size_t mdlen; FILE *fp; CLEANUP_FREE char *line = NULL; size_t allocsize = 0; ssize_t n; guestfs_int_mdstat_list *ret = NULL; if (STRPREFIX (md, "/dev/")) md += 5; mdlen = strlen (md); fp = fopen ("/proc/mdstat", "r"); if (fp == NULL) { reply_with_perror ("fopen: %s", "/proc/mdstat"); return NULL; } /* Search for a line which begins with "<md> : ". */ while ((n = getline (&line, &allocsize, fp)) != -1) { if (STRPREFIX (line, md) && line[mdlen] == ' ' && line[mdlen+1] == ':' && line[mdlen+2] == ' ') { /* Found it. */ ret = parse_md_stat_line (&line[mdlen+3]); if (!ret) { fclose (fp); return NULL; } /* Stop parsing the mdstat file after we've found the line * we are interested in. */ break; } } if (fclose (fp) == EOF) { reply_with_perror ("fclose: %s", "/proc/mdstat"); xdr_free ((xdrproc_t) xdr_guestfs_int_mdstat_list, (char *) ret); return NULL; } /* Did we find the line? */ if (!ret) { reply_with_error ("%s: MD device not found", md); return NULL; } return ret; }
int do_write_file (const char *path, const char *content, int size) { int fd; /* This call is deprecated, and it has a broken interface. New code * should use the 'guestfs_write' call instead. Because we used an * XDR string type, 'content' cannot contain ASCII NUL and 'size' * must never be longer than the string. We must check this to * ensure random stuff from XDR or daemon memory isn't written to * the file (RHBZ#597135). */ if (size < 0) { reply_with_error ("size cannot be negative"); return -1; } /* Note content_len must be small because of the limits on protocol * message size. */ int content_len = (int) strlen (content); if (size == 0) size = content_len; else if (size > content_len) { reply_with_error ("size parameter is larger than string content"); return -1; } CHROOT_IN; fd = open (path, O_WRONLY | O_TRUNC | O_CREAT | O_NOCTTY, 0666); CHROOT_OUT; if (fd == -1) { reply_with_perror ("open: %s", path); return -1; } if (xwrite (fd, content, size) == -1) { reply_with_perror ("write"); close (fd); return -1; } if (close (fd) == -1) { reply_with_perror ("close: %s", path); return -1; } return 0; }
static int add_partitions(const char *device, char ***const r, int *const size, int *const alloc) { char devdir[256]; /* Open the device's directory under /sys/block */ snprintf (devdir, sizeof devdir, "/sys/block/%s", device); DIR *dir = opendir (devdir); if (!dir) { reply_with_perror ("opendir: %s", devdir); free_stringslen (*r, *size); return -1; } /* Look in /sys/block/<device>/ for entries starting with <device> * e.g. /sys/block/sda/sda1 */ errno = 0; struct dirent *d; while ((d = readdir (dir)) != NULL) { if (STREQLEN (d->d_name, device, strlen (device))) { char part[256]; snprintf (part, sizeof part, "/dev/%s", d->d_name); if (add_string (r, size, alloc, part) == -1) { closedir (dir); return -1; } } } /* Check if readdir failed */ if(0 != errno) { reply_with_perror ("readdir: %s", devdir); free_stringslen(*r, *size); closedir (dir); return -1; } /* Close the directory handle */ if (closedir (dir) == -1) { reply_with_perror ("closedir: /sys/block/%s", device); free_stringslen (*r, *size); return -1; } return 0; }
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_fill (int c, int len, const char *path) { int fd; ssize_t r; size_t len_sz; size_t n; char buf[BUFSIZ]; if (c < 0 || c > 255) { reply_with_error ("%d: byte number must be in range 0..255", c); return -1; } memset (buf, c, BUFSIZ); if (len < 0) { reply_with_error ("%d: length is < 0", len); return -1; } len_sz = (size_t) len; 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; } n = 0; while (n < len_sz) { r = write (fd, buf, len_sz - n < BUFSIZ ? len_sz - n : BUFSIZ); if (r == -1) { reply_with_perror ("write: %s", path); close (fd); return -1; } n += r; notify_progress ((uint64_t) n, (uint64_t) len_sz); } if (close (fd) == -1) { reply_with_perror ("close: %s", path); return -1; } return 0; }
/* List files in the appliance. */ static char * debug_ll (const char *subcmd, size_t argc, char *const *const argv) { const size_t len = guestfs_int_count_strings (argv); CLEANUP_FREE const char **cargv = NULL; size_t i; int r; char *out; CLEANUP_FREE char *err = NULL; cargv = malloc (sizeof (char *) * (len+3)); if (cargv == NULL) { reply_with_perror ("malloc"); return NULL; } cargv[0] = "ls"; cargv[1] = "-la"; for (i = 0; i < len; ++i) cargv[2+i] = argv[i]; cargv[2+len] = NULL; r = commandv (&out, &err, (void *) cargv); if (r == -1) { reply_with_error ("ll: %s", err); free (out); return NULL; } return out; }
/* We need to rewrite the root path so it is based at /sysroot. */ int do_aug_init (const char *root, int flags) { #ifdef HAVE_AUGEAS char *buf; if (aug) { aug_close (aug); aug = NULL; } buf = sysroot_path (root); if (!buf) { reply_with_perror ("malloc"); return -1; } aug = aug_init (buf, NULL, flags); free (buf); if (!aug) { reply_with_error ("Augeas initialization failed"); return -1; } return 0; #else NOT_AVAILABLE (-1); #endif }
/* Generate lots of debug messages. Each line of output is 72 * characters long (plus '\n'), so the total size of the output in * bytes is n*73. */ static char * debug_spew (const char *subcmd, size_t argc, char *const *const argv) { size_t i, n; char *ret; if (argc != 1) { reply_with_error ("spew: expecting number of lines <n>"); return NULL; } if (sscanf (argv[0], "%zu", &n) != 1) { reply_with_error ("spew: could not parse number of lines '%s'", argv[0]); return NULL; } for (i = 0; i < n; ++i) fprintf (stderr, "abcdefghijklmnopqrstuvwxyz" /* 26 */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 52 */ "01234567890123456789" /* 72 */ "\n"); ret = strdup ("ok"); if (!ret) { reply_with_perror ("strdup"); return NULL; } return ret; }
/* This implementation is quick and dirty, and allows people to try * to remove parts of the initramfs (eg. "rm -r /..") but if people * do stupid stuff, who are we to try to stop them? */ int do_rm_rf (const char *path) { int r; char *buf, *err; if (STREQ (path, "/")) { reply_with_error ("cannot remove root directory"); return -1; } buf = sysroot_path (path); if (buf == NULL) { reply_with_perror ("malloc"); return -1; } r = command (NULL, &err, str_rm, "-rf", buf, NULL); free (buf); /* rm -rf is never supposed to fail. I/O errors perhaps? */ if (r == -1) { reply_with_error ("%s: %s", path, err); free (err); return -1; } free (err); return 0; }
int do_vgcreate (const char *volgroup, char *const *physvols) { char *err; int r, argc, i; const char **argv; argc = count_strings (physvols) + 3; argv = malloc (sizeof (char *) * (argc + 1)); if (argv == NULL) { reply_with_perror ("malloc"); return -1; } argv[0] = "lvm"; argv[1] = "vgcreate"; argv[2] = volgroup; for (i = 3; i <= argc; ++i) argv[i] = physvols[i-3]; r = commandv (NULL, &err, (const char * const*) argv); if (r == -1) { reply_with_error ("%s", err); free (err); free (argv); return -1; } free (err); free (argv); 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; }
guestfs_int_xfsinfo * do_xfs_info (const char *pathordevice) { int r; CLEANUP_FREE char *buf = NULL; CLEANUP_FREE char *out = NULL, *err = NULL; CLEANUP_FREE_STRING_LIST char **lines = NULL; int is_dev; is_dev = STREQLEN (pathordevice, "/dev/", 5); buf = is_dev ? strdup (pathordevice) : sysroot_path (pathordevice); if (buf == NULL) { reply_with_perror ("malloc"); return NULL; } r = command (&out, &err, str_xfs_info, buf, NULL); if (r == -1) { reply_with_error ("%s", err); return NULL; } lines = split_lines (out); if (lines == NULL) return NULL; return parse_xfs_info (lines); }
/* Return the nth field from a string of ':'/';'-delimited strings. * Useful for parsing the return value from 'parted -m'. */ static char * get_table_field (const char *line, int n) { const char *p = line; while (*p && n > 0) { p += strcspn (p, ":;") + 1; n--; } if (n > 0) { reply_with_error ("not enough fields in output of parted print command: %s", line); return NULL; } size_t len = strcspn (p, ":;"); char *q = strndup (p, len); if (q == NULL) { reply_with_perror ("strndup"); return NULL; } return q; }
int64_t do_du (const char *path) { int r; int64_t rv; CLEANUP_FREE char *out = NULL, *err = NULL, *buf = NULL; /* Make the path relative to /sysroot. */ buf = sysroot_path (path); if (!buf) { reply_with_perror ("malloc"); return -1; } pulse_mode_start (); r = command (&out, &err, str_du, "-s", buf, NULL); if (r == -1) { pulse_mode_cancel (); reply_with_error ("%s: %s", path, err); return -1; } if (sscanf (out, "%"SCNi64, &rv) != 1) { pulse_mode_cancel (); reply_with_error ("%s: could not read output: %s", path, out); return -1; } pulse_mode_end (); return rv; }
/* Generate progress notification messages in order to test progress bars. */ static char * debug_progress (const char *subcmd, size_t argc, char *const *const argv) { if (argc < 1) { error: reply_with_error ("progress: expecting arg (time in seconds as string)"); return NULL; } char *secs_str = argv[0]; unsigned secs; if (sscanf (secs_str, "%u", &secs) != 1) goto error; if (secs == 0 || secs > 1000000) { /* RHBZ#816839 */ reply_with_error ("progress: argument is 0, less than 0, or too large"); return NULL; } unsigned i; unsigned tsecs = secs * 10; /* 1/10ths of seconds */ for (i = 1; i <= tsecs; ++i) { usleep (100000); notify_progress ((uint64_t) i, (uint64_t) tsecs); } char *ret = strdup ("ok"); if (ret == NULL) { reply_with_perror ("strdup"); return NULL; } return ret; }
/* Generate progress notification messages in order to test progress bars. */ static char * debug_progress (const char *subcmd, size_t argc, char *const *const argv) { uint64_t secs, rate = 0; char *ret; if (argc < 1) { error: reply_with_error ("progress: expecting one or more args: time in seconds [, rate in microseconds]"); return NULL; } if (sscanf (argv[0], "%" SCNu64, &secs) != 1) goto error; if (secs == 0 || secs > 1000000) { /* RHBZ#816839 */ reply_with_error ("progress: argument is 0, less than 0, or too large"); return NULL; } if (argc >= 2) { if (sscanf (argv[1], "%" SCNu64, &rate) != 1) goto error; if (rate == 0 || rate > 1000000) { reply_with_error ("progress: rate is 0 or too large"); return NULL; } } /* Note the inner loops go to '<= limit' because we want to ensure * that the final 100% completed message is set. */ if (rate == 0) { /* Ordinary rate-limited progress messages. */ uint64_t tsecs = secs * 10; /* 1/10ths of seconds */ uint64_t i; for (i = 1; i <= tsecs; ++i) { usleep (100000); notify_progress (i, tsecs); } } else { /* Send messages at a given rate. */ uint64_t usecs = secs * 1000000; /* microseconds */ uint64_t i; struct timeval now; for (i = rate; i <= usecs; i += rate) { usleep (rate); gettimeofday (&now, NULL); notify_progress_no_ratelimit (i, usecs, &now); } } ret = strdup ("ok"); if (ret == NULL) { reply_with_perror ("strdup"); return NULL; } return ret; }
int64_t do_get_e2generation (const char *filename) { int r; CLEANUP_FREE char *buf = NULL, *out = NULL, *err = NULL; int64_t ret; buf = sysroot_path (filename); if (!buf) { reply_with_perror ("malloc"); return -1; } r = command (&out, &err, str_lsattr, "-dv", "--", buf, NULL); if (r == -1) { reply_with_error ("%s: %s: %s", "lsattr", filename, err); return -1; } if (sscanf (out, "%" SCNi64, &ret) != 1) { reply_with_error ("cannot parse output from '%s' command: %s", "lsattr", out); return -1; } if (ret < 0) { reply_with_error ("unexpected negative number from '%s' command: %s", "lsattr", out); return -1; } return ret; }
int do_vg_activate (int activate, char *const *volgroups) { int r, i, argc; CLEANUP_FREE char *err = NULL; CLEANUP_FREE const char **argv = NULL; argc = count_strings (volgroups) + 4; argv = malloc (sizeof (char *) * (argc+1)); if (argv == NULL) { reply_with_perror ("malloc"); return -1; } argv[0] = str_lvm; argv[1] = "vgchange"; argv[2] = "-a"; argv[3] = activate ? "y" : "n"; for (i = 4; i < argc+1; ++i) argv[i] = volgroups[i-4]; r = commandv (NULL, &err, (const char * const*) argv); if (r == -1) { reply_with_error ("vgchange: %s", err); return -1; } udev_settle (); return 0; }
int do_scrub_file (const char *file) { CLEANUP_FREE char *buf = NULL; CLEANUP_FREE char *err = NULL; int r; /* Resolve the path to the file, and make the result relative to /sysroot. * If it fails, then the file most probably does not exist or "file" is * a symlink pointing outside the chroot. */ buf = sysroot_realpath (file); if (!buf) { reply_with_perror ("malloc"); return -1; } r = command (NULL, &err, str_scrub, "-r", buf, NULL); if (r == -1) { reply_with_error ("%s: %s", file, err); return -1; } return 0; }
int do_vgcreate (const char *volgroup, char *const *physvols) { int r, argc, i; CLEANUP_FREE char *err = NULL; CLEANUP_FREE const char **argv = NULL; argc = count_strings (physvols) + 3; argv = malloc (sizeof (char *) * (argc + 1)); if (argv == NULL) { reply_with_perror ("malloc"); return -1; } argv[0] = str_lvm; argv[1] = "vgcreate"; argv[2] = volgroup; for (i = 3; i < argc+1; ++i) argv[i] = physvols[i-3]; r = commandv (NULL, &err, (const char * const*) argv); if (r == -1) { reply_with_error ("%s", err); return -1; } udev_settle (); return 0; }
char * do_lgetxattr (const char *path, const char *name, size_t *size_r) { ssize_t r; char *buf; size_t len; CHROOT_IN; r = lgetxattr (path, name, NULL, 0); CHROOT_OUT; if (r == -1) { reply_with_perror ("lgetxattr"); return NULL; } len = r; if (len > XATTR_SIZE_MAX) { reply_with_error ("extended attribute is too large"); return NULL; } buf = malloc (len); if (buf == NULL) { reply_with_perror ("malloc"); return NULL; } CHROOT_IN; r = lgetxattr (path, name, buf, len); CHROOT_OUT; if (r == -1) { reply_with_perror ("lgetxattr"); free (buf); return NULL; } if (len != (size_t) r) { reply_with_error ("lgetxattr: unexpected size (%zu/%zd)", len, r); free (buf); return NULL; } /* Must set size_r last thing before returning. */ *size_r = len; return buf; /* caller frees */ }
int do_fill_pattern (const char *pattern, int len, const char *path) { size_t patlen = strlen (pattern); if (patlen < 1) { reply_with_error ("pattern string must be non-empty"); return -1; } if (len < 0) { reply_with_error ("%d: length is < 0", len); return -1; } size_t len_sz = (size_t) len; int fd; 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; } /* XXX This implementation won't be very efficient for large files. */ size_t n = 0; while (n < len_sz) { size_t wrlen = len_sz - n < patlen ? len_sz - n : patlen; if (xwrite (fd, pattern, wrlen) == -1) { reply_with_perror ("write: %s", path); close (fd); return -1; } n += wrlen; notify_progress ((uint64_t) n, (uint64_t) len_sz); } if (close (fd) == -1) { reply_with_perror ("close: %s", path); return -1; } return 0; }
guestfs_int_stat * do_lstat (const char *path) { int r; guestfs_int_stat *ret; struct stat statbuf; CHROOT_IN; r = lstat (path, &statbuf); CHROOT_OUT; if (r == -1) { reply_with_perror ("%s", path); return NULL; } ret = malloc (sizeof *ret); if (ret == NULL) { reply_with_perror ("malloc"); return NULL; } ret->dev = statbuf.st_dev; ret->ino = statbuf.st_ino; ret->mode = statbuf.st_mode; ret->nlink = statbuf.st_nlink; ret->uid = statbuf.st_uid; ret->gid = statbuf.st_gid; ret->rdev = statbuf.st_rdev; ret->size = statbuf.st_size; #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE ret->blksize = statbuf.st_blksize; #else ret->blksize = -1; #endif #ifdef HAVE_STRUCT_STAT_ST_BLOCKS ret->blocks = statbuf.st_blocks; #else ret->blocks = -1; #endif ret->atime = statbuf.st_atime; ret->mtime = statbuf.st_mtime; ret->ctime = statbuf.st_ctime; return ret; }