int guestfs_int_is_dir_nocase (guestfs_h *g, const char *path) { CLEANUP_FREE char *p = NULL; int r; p = guestfs_int_case_sensitive_path_silently (g, path); if (!p) return 0; r = guestfs_is_dir (g, p); return r > 0; }
int guestfs_impl_copy_in (guestfs_h *g, const char *localpath, const char *remotedir) { CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); int fd; int r; char fdbuf[64]; size_t buf_len = strlen (localpath) + 1; char buf[buf_len]; const char *dirname, *basename; int remote_is_dir = guestfs_is_dir (g, remotedir); if (remote_is_dir == -1) return -1; if (!remote_is_dir) { error (g, _("target '%s' is not a directory"), remotedir); return -1; } if (split_path (g, buf, buf_len, localpath, &dirname, &basename) == -1) return -1; guestfs_int_cmd_add_arg (cmd, "tar"); if (dirname) { guestfs_int_cmd_add_arg (cmd, "-C"); guestfs_int_cmd_add_arg (cmd, dirname); } guestfs_int_cmd_add_arg (cmd, "-cf"); guestfs_int_cmd_add_arg (cmd, "-"); guestfs_int_cmd_add_arg (cmd, basename); r = guestfs_int_cmd_run_async (cmd, NULL, NULL, &fd, NULL); if (r == -1) return -1; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd); r = guestfs_tar_in (g, fdbuf, remotedir); if (close (fd) == -1) { perrorf (g, "close (tar subprocess)"); return -1; } r = guestfs_int_cmd_wait (cmd); if (r == -1) return -1; if (!(WIFEXITED (r) && WEXITSTATUS (r) == 0)) return -1; return 0; }
static int check_filesystem (guestfs_h *g, const char *mountable, const struct guestfs_internal_mountable *m, int whole_device) { int partnum = -1, nr_partitions = -1; /* Not CLEANUP_FREE, as it will be cleaned up with inspection info */ char *windows_systemroot = NULL; extend_fses (g); if (!whole_device && m->im_type == MOUNTABLE_DEVICE && guestfs_int_is_partition (g, m->im_device)) { if (get_partition_context (g, m->im_device, &partnum, &nr_partitions) == -1) return -1; } struct inspect_fs *fs = &g->fses[g->nr_fses-1]; fs->mountable = safe_strdup (g, mountable); /* Optimize some of the tests by avoiding multiple tests of the same thing. */ const int is_dir_etc = guestfs_is_dir (g, "/etc") > 0; const int is_dir_bin = guestfs_is_dir (g, "/bin") > 0; const int is_dir_share = guestfs_is_dir (g, "/share") > 0; /* Grub /boot? */ if (guestfs_is_file (g, "/grub/menu.lst") > 0 || guestfs_is_file (g, "/grub/grub.conf") > 0 || guestfs_is_file (g, "/grub2/grub.cfg") > 0) ; /* FreeBSD root? */ else if (is_dir_etc && is_dir_bin && guestfs_is_file (g, "/etc/freebsd-update.conf") > 0 && guestfs_is_file (g, "/etc/fstab") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_freebsd_root (g, fs) == -1) return -1; } /* NetBSD root? */ else if (is_dir_etc && is_dir_bin && guestfs_is_file (g, "/netbsd") > 0 && guestfs_is_file (g, "/etc/fstab") > 0 && guestfs_is_file (g, "/etc/release") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_netbsd_root (g, fs) == -1) return -1; } /* OpenBSD root? */ else if (is_dir_etc && is_dir_bin && guestfs_is_file (g, "/bsd") > 0 && guestfs_is_file (g, "/etc/fstab") > 0 && guestfs_is_file (g, "/etc/motd") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_openbsd_root (g, fs) == -1) return -1; } /* Hurd root? */ else if (guestfs_is_file (g, "/hurd/console") > 0 && guestfs_is_file (g, "/hurd/hello") > 0 && guestfs_is_file (g, "/hurd/null") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; /* XXX could be more specific */ if (guestfs_int_check_hurd_root (g, fs) == -1) return -1; } /* Minix root? */ else if (is_dir_etc && is_dir_bin && guestfs_is_file (g, "/service/vm") > 0 && guestfs_is_file (g, "/etc/fstab") > 0 && guestfs_is_file (g, "/etc/version") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_minix_root (g, fs) == -1) return -1; } /* Linux root? */ else if (is_dir_etc && (is_dir_bin || is_symlink_to (g, "/bin", "usr/bin") > 0) && (guestfs_is_file (g, "/etc/fstab") > 0 || guestfs_is_file (g, "/etc/hosts") > 0)) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_linux_root (g, fs) == -1) return -1; } /* CoreOS root? */ else if (is_dir_etc && guestfs_is_dir (g, "/root") > 0 && guestfs_is_dir (g, "/home") > 0 && guestfs_is_dir (g, "/usr") > 0 && guestfs_is_file (g, "/etc/coreos/update.conf") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_coreos_root (g, fs) == -1) return -1; } /* Linux /usr/local? */ else if (is_dir_etc && is_dir_bin && is_dir_share && guestfs_is_dir (g, "/local") == 0 && guestfs_is_file (g, "/etc/fstab") == 0) ; /* Linux /usr? */ else if (is_dir_etc && is_dir_bin && is_dir_share && guestfs_is_dir (g, "/local") > 0 && guestfs_is_file (g, "/etc/fstab") == 0) { if (guestfs_int_check_linux_usr (g, fs) == -1) return -1; } /* CoreOS /usr? */ else if (is_dir_bin && is_dir_share && guestfs_is_dir (g, "/local") > 0 && guestfs_is_dir (g, "/share/coreos") > 0) { if (guestfs_int_check_coreos_usr (g, fs) == -1) return -1; } /* Linux /var? */ else if (guestfs_is_dir (g, "/log") > 0 && guestfs_is_dir (g, "/run") > 0 && guestfs_is_dir (g, "/spool") > 0) ; /* Windows root? */ else if ((windows_systemroot = guestfs_int_get_windows_systemroot (g)) != NULL) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; if (guestfs_int_check_windows_root (g, fs, windows_systemroot) == -1) return -1; } /* Windows volume with installed applications (but not root)? */ else if (guestfs_int_is_dir_nocase (g, "/System Volume Information") > 0 && guestfs_int_is_dir_nocase (g, "/Program Files") > 0) ; /* Windows volume (but not root)? */ else if (guestfs_int_is_dir_nocase (g, "/System Volume Information") > 0) ; /* FreeDOS? */ else if (guestfs_int_is_dir_nocase (g, "/FDOS") > 0 && guestfs_int_is_file_nocase (g, "/FDOS/FREEDOS.BSS") > 0) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLED; fs->type = OS_TYPE_DOS; fs->distro = OS_DISTRO_FREEDOS; /* FreeDOS is a mix of 16 and 32 bit, but assume it requires a * 32 bit i386 processor. */ fs->arch = safe_strdup (g, "i386"); } /* Install CD/disk? * * Note that we checked (above) for an install ISO, but there are * other types of install image (eg. USB keys) which that check * wouldn't have picked up. * * Skip these checks if it's not a whole device (eg. CD) or the * first partition (eg. bootable USB key). */ else if ((whole_device || (partnum == 1 && nr_partitions == 1)) && (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 || guestfs_is_dir (g, "/EFI/BOOT") > 0 || guestfs_is_file (g, "/images/install.img") > 0 || guestfs_is_dir (g, "/.disk") > 0 || guestfs_is_file (g, "/.discinfo") > 0 || guestfs_is_file (g, "/i386/txtsetup.sif") > 0 || guestfs_is_file (g, "/amd64/txtsetup.sif") > 0 || guestfs_is_file (g, "/freedos/freedos.ico") > 0 || guestfs_is_file (g, "/boot/loader.rc") > 0)) { fs->role = OS_ROLE_ROOT; fs->format = OS_FORMAT_INSTALLER; if (guestfs_int_check_installer_root (g, fs) == -1) return -1; } /* The above code should have set fs->type and fs->distro fields, so * we can now guess the package management system. */ guestfs_int_check_package_format (g, fs); guestfs_int_check_package_management (g, fs); return 0; }
int run_copy_in (const char *cmd, size_t argc, char *argv[]) { if (argc < 2) { fprintf (stderr, _("use 'copy-in <local> [<local>...] <remotedir>' to copy files into the image\n")); return -1; } /* Remote directory is always the last arg. */ char *remote = argv[argc-1]; /* Allow win: prefix on remote. */ remote = win_prefix (remote); if (remote == NULL) return -1; int nr_locals = argc-1; int remote_is_dir = guestfs_is_dir (g, remote); if (remote_is_dir == -1) { free (remote); return -1; } if (!remote_is_dir) { fprintf (stderr, _("copy-in: target '%s' is not a directory\n"), remote); free (remote); return -1; } /* Upload each local one at a time using tar-in. */ int i; for (i = 0; i < nr_locals; ++i) { struct fd_pid fdpid = make_tar_from_local (argv[i]); if (fdpid.fd == -1) { free (remote); return -1; } char fdbuf[64]; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fdpid.fd); int r = guestfs_tar_in (g, fdbuf, remote); if (close (fdpid.fd) == -1) { perror ("close (tar-from-local subprocess)"); r = -1; } int status; if (waitpid (fdpid.pid, &status, 0) == -1) { perror ("wait (tar-from-local subprocess)"); free (remote); return -1; } if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0)) { free (remote); return -1; } if (r == -1) { free (remote); return -1; } } free (remote); return 0; }
int run_copy_out (const char *cmd, size_t argc, char *argv[]) { if (argc < 2) { fprintf (stderr, _("use 'copy-out <remote> [<remote>...] <localdir>' to copy files out of the image\n")); return -1; } /* Local directory is always the last arg. */ const char *local = argv[argc-1]; int nr_remotes = argc-1; struct stat statbuf; if (stat (local, &statbuf) == -1 || ! (S_ISDIR (statbuf.st_mode))) { fprintf (stderr, _("copy-out: target '%s' is not a directory\n"), local); return -1; } /* Download each remote one at a time using tar-out. */ int i, r; for (i = 0; i < nr_remotes; ++i) { char *remote = argv[i]; /* Allow win:... prefix on remotes. */ remote = win_prefix (remote); if (remote == NULL) return -1; /* If the remote is a file, download it. If it's a directory, * create the directory in local first before using tar-out. */ r = guestfs_is_file (g, remote); if (r == -1) { free (remote); return -1; } if (r == 1) { /* is file */ char buf[PATH_MAX]; const char *basename; if (split_path (buf, sizeof buf, remote, NULL, &basename) == -1) { free (remote); return -1; } char filename[PATH_MAX]; snprintf (filename, sizeof filename, "%s/%s", local, basename); if (guestfs_download (g, remote, filename) == -1) { free (remote); return -1; } } else { /* not a regular file */ r = guestfs_is_dir (g, remote); if (r == -1) { free (remote); return -1; } if (r == 0) { fprintf (stderr, _("copy-out: '%s' is not a file or directory\n"), remote); free (remote); return -1; } char buf[PATH_MAX]; const char *basename; if (split_path (buf, sizeof buf, remote, NULL, &basename) == -1) { free (remote); return -1; } struct fd_pid fdpid = make_tar_output (local, basename); if (fdpid.fd == -1) { free (remote); return -1; } char fdbuf[64]; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fdpid.fd); int r = guestfs_tar_out (g, remote, fdbuf); if (close (fdpid.fd) == -1) { perror ("close (tar-output subprocess)"); free (remote); r = -1; } int status; if (waitpid (fdpid.pid, &status, 0) == -1) { perror ("wait (tar-output subprocess)"); free (remote); return -1; } if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0)) { free (remote); return -1; } if (r == -1) { free (remote); return -1; } } free (remote); } return 0; }
int guestfs_impl_copy_in (guestfs_h *g, const char *localpath, const char *remotedir) { CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); int fd; int r; char fdbuf[64]; size_t buf_len = strlen (localpath) + 1; CLEANUP_FREE char *buf = safe_malloc (g, buf_len); const char *dirname, *basename; struct stat statbuf; if (stat (localpath, &statbuf) == -1) { error (g, _("source '%s' does not exist (or cannot be read)"), localpath); return -1; } int remote_is_dir = guestfs_is_dir (g, remotedir); if (remote_is_dir == -1) return -1; if (!remote_is_dir) { error (g, _("target '%s' is not a directory"), remotedir); return -1; } if (split_path (g, buf, buf_len, localpath, &dirname, &basename) == -1) return -1; guestfs_int_cmd_add_arg (cmd, "tar"); if (dirname) { guestfs_int_cmd_add_arg (cmd, "-C"); guestfs_int_cmd_add_arg (cmd, dirname); } guestfs_int_cmd_add_arg (cmd, "-cf"); guestfs_int_cmd_add_arg (cmd, "-"); guestfs_int_cmd_add_arg (cmd, basename); guestfs_int_cmd_clear_capture_errors (cmd); fd = guestfs_int_cmd_pipe_run (cmd, "r"); if (fd == -1) return -1; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd); r = guestfs_tar_in (g, fdbuf, remotedir); if (close (fd) == -1) { perrorf (g, "close (tar subprocess)"); return -1; } r = guestfs_int_cmd_pipe_wait (cmd); if (r == -1) return -1; if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { CLEANUP_FREE char *errors = guestfs_int_cmd_get_pipe_errors (cmd); if (errors == NULL) return -1; error (g, "tar subprocess failed: %s", errors); return -1; } return 0; }
int guestfs_impl_copy_out (guestfs_h *g, const char *remotepath, const char *localdir) { struct stat statbuf; int r; if (stat (localdir, &statbuf) == -1 || ! (S_ISDIR (statbuf.st_mode))) { error (g, _("target '%s' is not a directory"), localdir); return -1; } /* If the remote is a file, download it. If it's a directory, * create the directory in localdir first before using tar-out. */ r = guestfs_is_file (g, remotepath); if (r == -1) return -1; if (r == 1) { /* is file */ CLEANUP_FREE char *filename = NULL; size_t buf_len = strlen (remotepath) + 1; CLEANUP_FREE char *buf = safe_malloc (g, buf_len); const char *basename; if (split_path (g, buf, buf_len, remotepath, NULL, &basename) == -1) return -1; if (asprintf (&filename, "%s/%s", localdir, basename) == -1) { perrorf (g, "asprintf"); return -1; } if (guestfs_download (g, remotepath, filename) == -1) return -1; } else { /* not a regular file */ CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); struct copy_out_child_data data; char fdbuf[64]; int fd; r = guestfs_is_dir (g, remotepath); if (r == -1) return -1; if (r == 0) { error (g, _("'%s' is not a file or directory"), remotepath); return -1; } size_t buf_len = strlen (remotepath) + 1; CLEANUP_FREE char *buf = safe_malloc (g, buf_len); const char *basename; if (split_path (g, buf, buf_len, remotepath, NULL, &basename) == -1) return -1; /* RHBZ#845522: If remotepath == "/" then basename would be an empty * string. Replace it with "." so that make_tar_output writes * to "localdir/." */ if (STREQ (basename, "")) basename = "."; data.localdir = localdir; data.basename = basename; guestfs_int_cmd_set_child_callback (cmd, &child_setup, &data); guestfs_int_cmd_add_arg (cmd, "tar"); guestfs_int_cmd_add_arg (cmd, "-xf"); guestfs_int_cmd_add_arg (cmd, "-"); guestfs_int_cmd_clear_capture_errors (cmd); fd = guestfs_int_cmd_pipe_run (cmd, "w"); if (fd == -1) return -1; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd); r = guestfs_tar_out (g, remotepath, fdbuf); if (close (fd) == -1) { perrorf (g, "close (tar-output subprocess)"); return -1; } r = guestfs_int_cmd_pipe_wait (cmd); if (r == -1) return -1; if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { CLEANUP_FREE char *errors = guestfs_int_cmd_get_pipe_errors (cmd); if (errors == NULL) return -1; error (g, "tar subprocess failed: %s", errors); return -1; } } return 0; }
static int check_filesystem (guestfs_h *g, const char *mountable, const struct guestfs_internal_mountable *m, int whole_device) { /* Not CLEANUP_FREE, as it will be cleaned up with inspection info */ char *windows_systemroot = NULL; if (extend_fses (g) == -1) return -1; int partnum = -1; if (!whole_device && m->im_type == MOUNTABLE_DEVICE) { guestfs_push_error_handler (g, NULL, NULL); partnum = guestfs_part_to_partnum (g, m->im_device); guestfs_pop_error_handler (g); } struct inspect_fs *fs = &g->fses[g->nr_fses-1]; fs->mountable = safe_strdup (g, mountable); /* Optimize some of the tests by avoiding multiple tests of the same thing. */ int is_dir_etc = guestfs_is_dir (g, "/etc") > 0; int is_dir_bin = guestfs_is_dir (g, "/bin") > 0; int is_dir_share = guestfs_is_dir (g, "/share") > 0; /* Grub /boot? */ if (guestfs_is_file (g, "/grub/menu.lst") > 0 || guestfs_is_file (g, "/grub/grub.conf") > 0 || guestfs_is_file (g, "/grub2/grub.cfg") > 0) ; /* FreeBSD root? */ else if (is_dir_etc && is_dir_bin && guestfs_is_file (g, "/etc/freebsd-update.conf") > 0 && guestfs_is_file (g, "/etc/fstab") > 0) { /* Ignore /dev/sda1 which is a shadow of the real root filesystem * that is probably /dev/sda5 (see: * http://www.freebsd.org/doc/handbook/disk-organization.html) */ if (m->im_type == MOUNTABLE_DEVICE && match (g, m->im_device, re_first_partition)) return 0; fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; if (guestfs___check_freebsd_root (g, fs) == -1) return -1; } else if (is_dir_etc && is_dir_bin && guestfs_is_file (g, "/etc/fstab") > 0 && guestfs_is_file (g, "/etc/release") > 0) { /* Ignore /dev/sda1 which is a shadow of the real root filesystem * that is probably /dev/sda5 (see: * http://www.freebsd.org/doc/handbook/disk-organization.html) */ if (m->im_type == MOUNTABLE_DEVICE && match (g, m->im_device, re_first_partition)) return 0; fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; if (guestfs___check_netbsd_root (g, fs) == -1) return -1; } /* Hurd root? */ else if (guestfs_is_file (g, "/hurd/console") > 0 && guestfs_is_file (g, "/hurd/hello") > 0 && guestfs_is_file (g, "/hurd/null") > 0) { fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; /* XXX could be more specific */ if (guestfs___check_hurd_root (g, fs) == -1) return -1; } /* Linux root? */ else if (is_dir_etc && (is_dir_bin || (guestfs_is_symlink (g, "/bin") > 0 && guestfs_is_dir (g, "/usr/bin") > 0)) && guestfs_is_file (g, "/etc/fstab") > 0) { fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; if (guestfs___check_linux_root (g, fs) == -1) return -1; } /* Linux /usr/local? */ else if (is_dir_etc && is_dir_bin && is_dir_share && guestfs_is_dir (g, "/local") == 0 && guestfs_is_file (g, "/etc/fstab") == 0) ; /* Linux /usr? */ else if (is_dir_etc && is_dir_bin && is_dir_share && guestfs_is_dir (g, "/local") > 0 && guestfs_is_file (g, "/etc/fstab") == 0) ; /* Linux /var? */ else if (guestfs_is_dir (g, "/log") > 0 && guestfs_is_dir (g, "/run") > 0 && guestfs_is_dir (g, "/spool") > 0) ; /* Windows root? */ else if ((windows_systemroot = guestfs___get_windows_systemroot (g)) != NULL) { fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; if (guestfs___check_windows_root (g, fs, windows_systemroot) == -1) return -1; } /* Windows volume with installed applications (but not root)? */ else if (guestfs___is_dir_nocase (g, "/System Volume Information") > 0 && guestfs___is_dir_nocase (g, "/Program Files") > 0) ; /* Windows volume (but not root)? */ else if (guestfs___is_dir_nocase (g, "/System Volume Information") > 0) ; /* FreeDOS? */ else if (guestfs___is_dir_nocase (g, "/FDOS") > 0 && guestfs___is_file_nocase (g, "/FDOS/FREEDOS.BSS") > 0) { fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; fs->type = OS_TYPE_DOS; fs->distro = OS_DISTRO_FREEDOS; /* FreeDOS is a mix of 16 and 32 bit, but assume it requires a * 32 bit i386 processor. */ fs->arch = safe_strdup (g, "i386"); } /* Install CD/disk? * * Note that we checked (above) for an install ISO, but there are * other types of install image (eg. USB keys) which that check * wouldn't have picked up. * * Skip these checks if it's not a whole device (eg. CD) or the * first partition (eg. bootable USB key). */ else if ((whole_device || partnum == 1) && (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 || guestfs_is_dir (g, "/EFI/BOOT") > 0 || guestfs_is_file (g, "/images/install.img") > 0 || guestfs_is_dir (g, "/.disk") > 0 || guestfs_is_file (g, "/.discinfo") > 0 || guestfs_is_file (g, "/i386/txtsetup.sif") > 0 || guestfs_is_file (g, "/amd64/txtsetup.sif") > 0 || guestfs_is_file (g, "/freedos/freedos.ico") > 0 || guestfs_is_file (g, "/boot/loader.rc") > 0)) { fs->is_root = 1; fs->format = OS_FORMAT_INSTALLER; if (guestfs___check_installer_root (g, fs) == -1) return -1; } /* The above code should have set fs->type and fs->distro fields, so * we can now guess the package management system. */ guestfs___check_package_format (g, fs); guestfs___check_package_management (g, fs); return 0; }