diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 8ccf32252..1d29a0f4f 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -98,6 +98,7 @@ guestfsd_SOURCES = \ daemon.h \ dd.c \ debug.c \ + debug-bmap.c \ devsparts.c \ df.c \ dir.c \ diff --git a/daemon/daemon.h b/daemon/daemon.h index f442efdb7..c101c3b2a 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -257,6 +257,11 @@ extern int copy_xattrs (const char *src, const char *dest); /* Documented in xfs_admin(8). */ #define XFS_LABEL_MAX 12 +/*-- debug-bmap.c --*/ +extern char *debug_bmap (const char *subcmd, size_t argc, char *const *const argv); +extern char *debug_bmap_file (const char *subcmd, size_t argc, char *const *const argv); +extern char *debug_bmap_device (const char *subcmd, size_t argc, char *const *const argv); + /* ordinary daemon functions use these to indicate errors * NB: you don't need to prefix the string with the current command, * it is added automatically by the client-side RPC stubs. diff --git a/daemon/debug-bmap.c b/daemon/debug-bmap.c new file mode 100644 index 000000000..fcf3edee0 --- /dev/null +++ b/daemon/debug-bmap.c @@ -0,0 +1,216 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2014 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* This file provides some interim APIs for virt-bmap. They will + * eventually be replaced by real APIs, see: + * https://www.redhat.com/archives/libguestfs/2014-November/msg00197.html + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" + +static int fd = -1; +static DIR *dir = NULL; +static struct stat statbuf; + +static void bmap_finalize (void) __attribute__((destructor)); +static void +bmap_finalize (void) +{ + if (fd >= 0) { + close (fd); + fd = -1; + } + if (dir != NULL) { + closedir (dir); + dir = NULL; + } +} + +static char * +bmap_prepare (const char *path, const char *orig_path) +{ + char *ret; + + bmap_finalize (); + + if (stat (path, &statbuf) == -1) { + reply_with_perror ("%s", orig_path); + return NULL; + } + + if (S_ISDIR (statbuf.st_mode)) { + /* Open a directory. */ + dir = opendir (path); + if (dir == NULL) { + reply_with_perror ("opendir: %s", orig_path); + return NULL; + } + } + else { + /* Open a regular file. */ + fd = open (path, O_RDONLY | O_CLOEXEC); + if (fd == -1) { + reply_with_perror ("%s", orig_path); + return NULL; + } + + posix_fadvise (fd, 0, 0, + POSIX_FADV_SEQUENTIAL | + POSIX_FADV_NOREUSE | + POSIX_FADV_DONTNEED); + } + + ret = strdup ("ok"); + if (ret == NULL) { + reply_with_perror ("strdup"); + return NULL; + } + return ret; +} + +char * +debug_bmap_file (const char *subcmd, size_t argc, char *const *const argv) +{ + CLEANUP_FREE char *buf = NULL; + const char *path; + + if (argc != 1) { + reply_with_error ("bmap-file: missing path"); + return NULL; + } + path = argv[0]; + + buf = sysroot_path (path); + if (!buf) { + reply_with_perror ("malloc"); + return NULL; + } + + return bmap_prepare (buf, path); +} + +char * +debug_bmap_device (const char *subcmd, size_t argc, char *const *const argv) +{ + const char *device; + + if (argc != 1) { + reply_with_error ("bmap-device: missing device"); + return NULL; + } + device = argv[0]; + + return bmap_prepare (device, device); +} + +static char buffer[BUFSIZ]; + +char * +debug_bmap (const char *subcmd, size_t argc, char *const *const argv) +{ + uint64_t n; + ssize_t r; + struct dirent *d; + char *ret; + + if (argc != 0) { + reply_with_error ("bmap: extra parameters on command line"); + return NULL; + } + + /* Drop caches before starting the read. */ + if (do_drop_caches (3) == -1) + return NULL; + + if (fd >= 0) { + if (S_ISBLK (statbuf.st_mode)) { + /* Get size of block device. */ + if (ioctl (fd, BLKGETSIZE64, &n) == -1) { + reply_with_perror ("ioctl: BLKGETSIZE64"); + return NULL; + } + } + else + n = statbuf.st_size; + + while (n > 0) { + r = read (fd, buffer, n > BUFSIZ ? BUFSIZ : n); + if (r == -1) { + reply_with_perror ("read"); + close (fd); + fd = -1; + return NULL; + } + n -= r; + } + + if (close (fd) == -1) { + reply_with_perror ("close"); + fd = -1; + return NULL; + } + fd = -1; + } + + if (dir != NULL) { + for (;;) { + errno = 0; + d = readdir (dir); + if (!d) break; + } + + /* Check readdir didn't fail */ + if (errno != 0) { + reply_with_perror ("readdir"); + closedir (dir); + dir = NULL; + return NULL; + } + + /* Close the directory handle */ + if (closedir (dir) == -1) { + reply_with_perror ("closedir"); + dir = NULL; + return NULL; + } + dir = NULL; + } + + ret = strdup ("ok"); + if (ret == NULL) { + reply_with_perror ("strdup"); + return NULL; + } + return ret; +} diff --git a/daemon/debug.c b/daemon/debug.c index d29ca7860..6b7cfe5f1 100644 --- a/daemon/debug.c +++ b/daemon/debug.c @@ -83,6 +83,9 @@ static void deliberately_cause_a_segfault (void); static struct cmd cmds[] = { { "help", debug_help }, { "binaries", debug_binaries }, + { "bmap", debug_bmap }, + { "bmap_device", debug_bmap_device }, + { "bmap_file", debug_bmap_file }, { "core_pattern", debug_core_pattern }, { "device_speed", debug_device_speed }, { "env", debug_env }, diff --git a/po/POTFILES b/po/POTFILES index 9333ebeaa..2aed29737 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -32,6 +32,7 @@ daemon/copy.c daemon/cpio.c daemon/cpmv.c daemon/dd.c +daemon/debug-bmap.c daemon/debug.c daemon/devsparts.c daemon/df.c