/* libguestfs - the guestfsd daemon
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 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
#include <config.h>
-#define _BSD_SOURCE /* for daemon(3) */
-
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <errno.h>
#ifdef HAVE_PRINTF_H
# include <printf.h>
static char *read_cmdline (void);
-/* This is the default address we connect to for very old libraries
- * which didn't specify the address and port number explicitly on the
- * kernel command line. It's now recommended to always specify the
- * address and port number on the command line, so this will not be
- * used any more.
- */
-#define OLD_GUESTFWD_ADDR "10.0.2.4"
-#define OLD_GUESTFWD_PORT "6666"
-
-/* This is only a hint. If not defined, ignore it. */
-#ifndef AI_ADDRCONFIG
-# define AI_ADDRCONFIG 0
-#endif
-
#ifndef MAX
# define MAX(a,b) ((a)>(b)?(a):(b))
#endif
+/* Not the end of the world if this open flag is not defined. */
+#ifndef O_CLOEXEC
+# define O_CLOEXEC 0
+#endif
+
+/* If root device is an ext2 filesystem, this is the major and minor.
+ * This is so we can ignore this device from the point of view of the
+ * user, eg. in guestfs_list_devices and many other places.
+ */
+static dev_t root_device = 0;
+
int verbose = 0;
static int print_shell_quote (FILE *stream, const struct printf_info *info, const void *const *args);
#ifdef WIN32
static int
-daemon (int nochdir, int noclose)
-{
- fprintf (stderr,
- "On Windows the daemon does not support forking into the "
- "background.\nYou *must* run the daemon with the -f option.\n");
- exit (EXIT_FAILURE);
-}
-#endif /* WIN32 */
-
-#ifdef WIN32
-static int
winsock_init (void)
{
int r;
/* Location to mount root device. */
const char *sysroot = "/sysroot"; /* No trailing slash. */
-int sysroot_len = 8;
+size_t sysroot_len = 8;
+
+/* If set (the default), do 'umount-all' when performing autosync. */
+int autosync_umount = 1;
/* Not used explicitly, but required by the gnulib 'error' module. */
const char *program_name = "guestfsd";
usage (void)
{
fprintf (stderr,
- "guestfsd [-f|--foreground] [-c|--channel vmchannel] [-v|--verbose]\n");
+ "guestfsd [-r] [-v|--verbose]\n");
}
int
main (int argc, char *argv[])
{
- static const char *options = "fc:v?";
+ static const char *options = "rv?";
static const struct option long_options[] = {
- { "channel", required_argument, 0, 'c' },
- { "foreground", 0, 0, 'f' },
{ "help", 0, 0, '?' },
{ "verbose", 0, 0, 'v' },
{ 0, 0, 0, 0 }
};
int c;
- int dont_fork = 0;
char *cmdline;
- char *vmchannel = NULL;
+
+ ignore_value (chdir ("/"));
if (winsock_init () == -1)
error (EXIT_FAILURE, 0, "winsock initialization failed");
#endif
#endif
+ struct stat statbuf;
+ if (stat ("/", &statbuf) == 0)
+ root_device = statbuf.st_dev;
+
for (;;) {
c = getopt_long (argc, argv, options, long_options, NULL);
if (c == -1) break;
switch (c) {
- case 'c':
- vmchannel = optarg;
- break;
-
- case 'f':
- dont_fork = 1;
+ /* The -r flag is used when running standalone. It changes
+ * several aspects of the daemon.
+ */
+ case 'r':
+ sysroot = "";
+ sysroot_len = 0;
+ autosync_umount = 0;
break;
case 'v':
_umask (0);
#endif
- /* Get the vmchannel string.
- *
- * Sources:
- * --channel/-c option on the command line
- * guestfs_vmchannel=... from the kernel command line
- * guestfs=... from the kernel command line
- * built-in default
- *
- * At the moment we expect this to contain "tcp:ip:port" but in
- * future it might contain a device name, eg. "/dev/vcon4" for
- * virtio-console vmchannel.
- */
- if (vmchannel == NULL && cmdline) {
- char *p;
- size_t len;
-
- p = strstr (cmdline, "guestfs_vmchannel=");
- if (p) {
- len = strcspn (p + 18, " \t\n");
- vmchannel = strndup (p + 18, len);
- if (!vmchannel) {
- perror ("strndup");
- exit (EXIT_FAILURE);
- }
- }
-
- /* Old libraries passed guestfs=host:port. Rewrite it as tcp:host:port. */
- if (vmchannel == NULL) {
- /* We will rewrite it part of the "guestfs=" string with
- * "tcp:" hence p + 4 below. */
- p = strstr (cmdline, "guestfs=");
- if (p) {
- len = strcspn (p + 4, " \t\n");
- vmchannel = strndup (p + 4, len);
- if (!vmchannel) {
- perror ("strndup");
- exit (EXIT_FAILURE);
- }
- memcpy (vmchannel, "tcp:", 4);
- }
- }
- }
-
- /* Default vmchannel. */
- if (vmchannel == NULL) {
- vmchannel = strdup ("tcp:" OLD_GUESTFWD_ADDR ":" OLD_GUESTFWD_PORT);
- if (!vmchannel) {
- perror ("strdup");
- exit (EXIT_FAILURE);
- }
- }
-
- if (verbose)
- printf ("vmchannel: %s\n", vmchannel);
-
- /* Connect to vmchannel. */
- int sock = -1;
-
- if (STREQLEN (vmchannel, "tcp:", 4)) {
- /* Resolve the hostname. */
- struct addrinfo *res, *rr;
- struct addrinfo hints;
- int r;
- char *host, *port;
-
- host = vmchannel+4;
- port = strchr (host, ':');
- if (port) {
- port[0] = '\0';
- port++;
- } else {
- fprintf (stderr, "vmchannel: expecting \"tcp:<ip>:<port>\": %s\n",
- vmchannel);
- exit (EXIT_FAILURE);
- }
-
- memset (&hints, 0, sizeof hints);
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_ADDRCONFIG;
- r = getaddrinfo (host, port, &hints, &res);
- if (r != 0) {
- fprintf (stderr, "%s:%s: %s\n",
- host, port, gai_strerror (r));
- exit (EXIT_FAILURE);
- }
-
- /* Connect to the given TCP socket. */
- for (rr = res; rr != NULL; rr = rr->ai_next) {
- sock = socket (rr->ai_family, rr->ai_socktype, rr->ai_protocol);
- if (sock != -1) {
- if (connect (sock, rr->ai_addr, rr->ai_addrlen) == 0)
- break;
- perror ("connect");
-
- close (sock);
- sock = -1;
- }
- }
- freeaddrinfo (res);
- } else {
- fprintf (stderr,
- "unknown vmchannel connection type: %s\n"
- "expecting \"tcp:<ip>:<port>\"\n",
- vmchannel);
- exit (EXIT_FAILURE);
- }
-
+ /* Connect to virtio-serial channel. */
+ int sock = open ("/dev/virtio-ports/org.libguestfs.channel.0",
+ O_RDWR | O_CLOEXEC);
if (sock == -1) {
fprintf (stderr,
"\n"
- "Failed to connect to any vmchannel implementation.\n"
- "vmchannel: %s\n"
+ "Failed to connect to virtio-serial channel.\n"
"\n"
"This is a fatal error and the appliance will now exit.\n"
"\n"
"'libguestfs-test-tool' and provide the complete, unedited\n"
"output to the libguestfs developers, either in a bug report\n"
"or on the libguestfs redhat com mailing list.\n"
- "\n",
- vmchannel);
+ "\n");
+ perror ("/dev/virtio-ports/org.libguestfs.channel.0");
exit (EXIT_FAILURE);
}
xdrmem_create (&xdr, lenbuf, sizeof lenbuf, XDR_ENCODE);
xdr_u_int (&xdr, &len);
- if (xwrite (sock, lenbuf, sizeof lenbuf) == -1)
+ if (xwrite (sock, lenbuf, sizeof lenbuf) == -1) {
+ perror ("xwrite");
exit (EXIT_FAILURE);
+ }
xdr_destroy (&xdr);
- /* Fork into the background. */
- if (!dont_fork) {
- if (daemon (0, 1) == -1) {
- perror ("daemon");
- exit (EXIT_FAILURE);
- }
- }
-
/* Enter the main loop, reading and performing actions. */
main_loop (sock);
return r;
}
+/* Return true iff device is the root device (and therefore should be
+ * ignored from the point of view of user calls).
+ */
+int
+is_root_device (const char *device)
+{
+ struct stat statbuf;
+ if (stat (device, &statbuf) == -1) {
+ perror (device);
+ return 0;
+ }
+ if (statbuf.st_rdev == root_device)
+ return 1;
+ return 0;
+}
+
/* Turn "/path" into "/sysroot/path".
*
* Caller must check for NULL and call reply_with_perror ("malloc")
return 0;
}
-int
+size_t
count_strings (char *const *argv)
{
- int argc;
+ size_t argc;
for (argc = 0; argv[argc] != NULL; ++argc)
;
return argc;
}
+/* http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 */
+int
+is_power_of_2 (unsigned long v)
+{
+ return v && ((v & (v - 1)) == 0);
+}
+
static int
compare (const void *vp1, const void *vp2)
{
*/
if (pipe (so_fd) == -1 || pipe (se_fd) == -1) {
- perror ("pipe");
+ error (0, errno, "pipe");
abort ();
}
if (flag_copy_stdin) {
if (pipe (stdin_fd) == -1) {
- perror ("pipe");
+ error (0, errno, "pipe");
abort ();
}
}
pid = fork ();
if (pid == -1) {
- perror ("fork");
+ error (0, errno, "fork");
abort ();
}
if (pid == 0) { /* Child process running the command. */
+ signal (SIGALRM, SIG_DFL);
+ signal (SIGPIPE, SIG_DFL);
close (0);
if (flag_copy_stdin) {
dup2 (stdin_fd[0], 0);
close (stdin_fd[0]);
close (stdin_fd[1]);
- } else
+ } else {
/* Set stdin to /dev/null (ignore failure) */
open ("/dev/null", O_RDONLY);
+ }
close (so_fd[0]);
close (se_fd[0]);
if (!(flags & COMMAND_FLAG_FOLD_STDOUT_ON_STDERR))
stdin_pid = fork ();
if (stdin_pid == -1) {
- perror ("fork");
+ error (0, errno, "fork");
abort ();
}
quit = 0;
while (quit < 2) {
+ again:
rset2 = rset;
r = select (MAX (so_fd[0], se_fd[0]) + 1, &rset2, NULL, NULL, NULL);
if (r == -1) {
+ if (errno == EINTR)
+ goto again;
+
perror ("select");
quit:
if (stdoutput) free (*stdoutput);
}
/* printf helper function so we can use %Q ("quoted") and %R to print
- * shell-quoted strings. See HACKING file for more details.
+ * shell-quoted strings. See guestfs(3)/EXTENDING LIBGUESTFS for more
+ * details.
*/
static int
print_shell_quote (FILE *stream,