/* Run uml_mkcow to create a COW overlay. */ static char * make_cow_overlay (guestfs_h *g, const char *original) { CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); char *overlay; int r; if (guestfs___lazy_make_tmpdir (g) == -1) return NULL; overlay = safe_asprintf (g, "%s/overlay%d", g->tmpdir, g->unique++); guestfs___cmd_add_arg (cmd, "uml_mkcow"); guestfs___cmd_add_arg (cmd, overlay); guestfs___cmd_add_arg (cmd, original); r = guestfs___cmd_run (cmd); if (r == -1) { free (overlay); return NULL; } if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { guestfs___external_command_failed (g, r, "uml_mkcow", original); free (overlay); return NULL; } return overlay; }
static int write_or_append (guestfs_h *g, const char *path, const char *content, size_t size, int append) { CLEANUP_UNLINK_FREE char *tmpfile = NULL; int fd = -1; int64_t filesize; /* If the content is small enough, use guestfs_internal_write{,_append} * since that call is more efficient. */ if (size <= 2*1024*1024) return (!append ? guestfs_internal_write : guestfs_internal_write_append) (g, path, content, size); if (guestfs___lazy_make_tmpdir (g) == -1) goto err; /* Write the content out to a temporary file. */ tmpfile = safe_asprintf (g, "%s/write%d", g->tmpdir, ++g->unique); fd = open (tmpfile, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0600); if (fd == -1) { perrorf (g, "open: %s", tmpfile); goto err; } if (full_write (fd, content, size) != size) { perrorf (g, "write: %s", tmpfile); goto err; } if (close (fd) == -1) { perrorf (g, "close: %s", tmpfile); goto err; } fd = -1; if (!append) { if (guestfs_upload (g, tmpfile, path) == -1) goto err; } else { /* XXX Should have an 'upload-append' call to make this atomic. */ filesize = guestfs_filesize (g, path); if (filesize == -1) goto err; if (guestfs_upload_offset (g, tmpfile, path, filesize) == -1) goto err; } return 0; err: if (fd >= 0) close (fd); return -1; }
int guestfs__launch (guestfs_h *g) { /* Configured? */ if (g->state != CONFIG) { error (g, _("the libguestfs handle has already been launched")); return -1; } /* Start the clock ... */ gettimeofday (&g->launch_t, NULL); TRACE0 (launch_start); /* Make the temporary directory. */ if (guestfs___lazy_make_tmpdir (g) == -1) return -1; /* Allow anyone to read the temporary directory. The socket in this * directory won't be readable but anyone can see it exists if they * want. (RHBZ#610880). */ if (chmod (g->tmpdir, 0755) == -1) warning (g, "chmod: %s: %m (ignored)", g->tmpdir); /* Some common debugging information. */ if (g->verbose) { CLEANUP_FREE_VERSION struct guestfs_version *v = guestfs_version (g); struct backend *b; CLEANUP_FREE char *backend = guestfs_get_backend (g); debug (g, "launch: program=%s", g->program); debug (g, "launch: version=%"PRIi64".%"PRIi64".%"PRIi64"%s", v->major, v->minor, v->release, v->extra); for (b = backends; b != NULL; b = b->next) debug (g, "launch: backend registered: %s", b->name); debug (g, "launch: backend=%s", backend); debug (g, "launch: tmpdir=%s", g->tmpdir); debug (g, "launch: umask=0%03o", get_umask (g)); debug (g, "launch: euid=%d", geteuid ()); } /* Launch the appliance. */ if (g->backend_ops->launch (g, g->backend_data, g->backend_arg) == -1) return -1; /* If network is enabled, upload /etc/resolv.conf from the host so * the guest will know how to reach the nameservers. */ if (g->enable_network && access ("/etc/resolv.conf", F_OK) == 0) { guestfs_internal_upload (g, "/etc/resolv.conf", "/etc/resolv.conf", 0644); } return 0; }
static int run_qemu_img_info (guestfs_h *g, const char *filename, cmd_stdout_callback fn, void *data) { char *abs_filename = NULL; char *safe_filename = NULL; struct command *cmd; int r; if (guestfs___lazy_make_tmpdir (g) == -1) return -1; safe_filename = safe_asprintf (g, "%s/format.%d", g->tmpdir, ++g->unique); /* 'filename' must be an absolute path so we can link to it. */ abs_filename = realpath (filename, NULL); if (abs_filename == NULL) { perrorf (g, "realpath"); goto error; } if (symlink (abs_filename, safe_filename) == -1) { perrorf (g, "symlink"); goto error; } cmd = guestfs___new_command (g); guestfs___cmd_add_arg (cmd, "qemu-img"); guestfs___cmd_add_arg (cmd, "info"); guestfs___cmd_add_arg (cmd, safe_filename); guestfs___cmd_set_stdout_callback (cmd, fn, data, 0); r = guestfs___cmd_run (cmd); guestfs___cmd_close (cmd); if (r == -1) goto error; if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { error (g, _("qemu-img: %s: child process failed"), filename); goto error; } free (safe_filename); free (abs_filename); return 0; error: free (safe_filename); free (abs_filename); return -1; }
static char * create_cow_overlay_direct (guestfs_h *g, void *datav, struct drive *drv) { char *overlay = NULL; CLEANUP_FREE char *backing_drive = NULL; CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); int r; backing_drive = guestfs___drive_source_qemu_param (g, &drv->src); if (!backing_drive) goto error; if (guestfs___lazy_make_tmpdir (g) == -1) goto error; overlay = safe_asprintf (g, "%s/overlay%d", g->tmpdir, ++g->unique); guestfs___cmd_add_arg (cmd, "qemu-img"); guestfs___cmd_add_arg (cmd, "create"); guestfs___cmd_add_arg (cmd, "-f"); guestfs___cmd_add_arg (cmd, "qcow2"); guestfs___cmd_add_arg (cmd, "-b"); guestfs___cmd_add_arg (cmd, backing_drive); if (drv->src.format) { guestfs___cmd_add_arg (cmd, "-o"); guestfs___cmd_add_arg_format (cmd, "backing_fmt=%s", drv->src.format); } guestfs___cmd_add_arg (cmd, overlay); r = guestfs___cmd_run (cmd); if (r == -1) goto error; if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { guestfs___external_command_failed (g, r, "qemu-img create", backing_drive); goto error; } /* Caller sets g->overlay in the handle to this, and then manages * the memory. */ return overlay; error: free (overlay); return NULL; }
/* This is implemented library-side in order to get around potential * protocol limits. * * A journal record can contain an arbitrarily large amount of data * (stuff like core dumps in particular). To save the user from * having to deal with it, the implementation uses an internal * function that downloads to a FileOut, and we reconstruct the * hashtable entries from that. */ struct guestfs_xattr_list * guestfs__journal_get (guestfs_h *g) { CLEANUP_UNLINK_FREE char *tmpfile = NULL; CLEANUP_FREE char *buf = NULL; struct stat statbuf; struct guestfs_xattr_list *ret = NULL; char *p, *eofield, *eobuf; int fd = -1; size_t i, j, size; uint64_t len; if (guestfs___lazy_make_tmpdir (g) == -1) goto err; tmpfile = safe_asprintf (g, "%s/journal%d", g->tmpdir, ++g->unique); if (guestfs_internal_journal_get (g, tmpfile) == -1) goto err; fd = open (tmpfile, O_RDONLY|O_CLOEXEC); if (fd == -1) { perrorf (g, "open: %s", tmpfile); goto err; } /* Read the whole file into memory. */ if (fstat (fd, &statbuf) == -1) { perrorf (g, "stat: %s", tmpfile); goto err; } /* Don't use safe_malloc. Want to return an errno to the caller. */ size = statbuf.st_size; buf = malloc (size+1); if (!buf) { perrorf (g, "malloc: %zu bytes", size); goto err; } eobuf = &buf[size]; *eobuf = '\0'; /* Makes strchr etc safe. */ if (full_read (fd, buf, size) != size) { perrorf (g, "full-read: %s: %zu bytes", tmpfile, size); goto err; } if (close (fd) == -1) { perrorf (g, "close: %s", tmpfile); goto err; } fd = -1; j = 0; ret = safe_malloc (g, sizeof *ret); ret->len = 0; ret->val = NULL; /* There is a simple, private protocol employed here (note: it may * be changed at any time), where fields are sent using a big-endian * 64 bit length field followed by N bytes of 'field=data' binary * data. */ for (i = 0; i < size; ) { if (i+8 > size) { error (g, "invalid data from guestfs_internal_journal_get: " "truncated: " "size=%zu, i=%zu", size, i); goto err; } memcpy(&len, &buf[i], sizeof(len)); len = be64toh (len); i += 8; eofield = &buf[i+len]; if (eofield > eobuf) { error (g, "invalid data from guestfs_internal_journal_get: " "length field is too large: " "size=%zu, i=%zu, len=%" PRIu64, size, i, len); goto err; } p = strchr (&buf[i], '='); if (!p || p >= eofield) { error (g, "invalid data from guestfs_internal_journal_get: " "no '=' found separating field name and data: " "size=%zu, i=%zu, p=%p", size, i, p); goto err; } *p = '\0'; j++; ret->val = safe_realloc (g, ret->val, j * sizeof (struct guestfs_xattr)); ret->val[j-1].attrname = safe_strdup (g, &buf[i]); ret->val[j-1].attrval_len = eofield - (p+1); ret->val[j-1].attrval = safe_memdup (g, p+1, eofield - (p+1)); ret->len = j; i += len; } return ret; /* caller frees */ err: guestfs_free_xattr_list (ret); if (fd >= 0) close (fd); return NULL; }
char * guestfs__read_file (guestfs_h *g, const char *path, size_t *size_r) { int fd = -1; size_t size; CLEANUP_UNLINK_FREE char *tmpfile = NULL; char *ret = NULL; struct stat statbuf; if (guestfs___lazy_make_tmpdir (g) == -1) goto err; tmpfile = safe_asprintf (g, "%s/cat%d", g->tmpdir, ++g->unique); if (guestfs_download (g, path, tmpfile) == -1) goto err; fd = open (tmpfile, O_RDONLY|O_CLOEXEC); if (fd == -1) { perrorf (g, "open: %s", tmpfile); goto err; } /* Read the whole file into memory. */ if (fstat (fd, &statbuf) == -1) { perrorf (g, "stat: %s", tmpfile); goto err; } /* Don't use safe_malloc, because we want to return an errno to the caller. */ size = statbuf.st_size; ret = malloc (size + 1); if (!ret) { perrorf (g, "malloc: %zu bytes", size + 1); goto err; } if (full_read (fd, ret, size) != size) { perrorf (g, "full-read: %s: %zu bytes", tmpfile, size + 1); goto err; } ret[size] = '\0'; if (close (fd) == -1) { perrorf (g, "close: %s", tmpfile); goto err; } /* Mustn't touch *size_r until we are sure that we won't return any * error (RHBZ#589039). */ *size_r = size; return ret; err: free (ret); if (fd >= 0) close (fd); return NULL; }