X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Finspect.c;h=e83e8241cf6a7a64f692a43a1074af3fcf54550d;hb=edd502543adbdc2fa5dda0c015ea7c390bb39f64;hp=fc8d8df9a0faac4fc370d38578edce20e9daafa4;hpb=3336b5448f12c9eb25bf7a0cecda1315c4cf07ea;p=libguestfs.git diff --git a/src/inspect.c b/src/inspect.c index fc8d8df..e83e824 100644 --- a/src/inspect.c +++ b/src/inspect.c @@ -29,9 +29,7 @@ #include #include -#ifdef HAVE_PCRE #include -#endif #ifdef HAVE_HIVEX #include @@ -46,7 +44,7 @@ #include "guestfs-internal-actions.h" #include "guestfs_protocol.h" -#if defined(HAVE_PCRE) && defined(HAVE_HIVEX) +#if defined(HAVE_HIVEX) /* The main inspection code. */ char ** @@ -125,6 +123,15 @@ guestfs__inspect_os (guestfs_h *g) return ret; } +static int +compare_strings (const void *vp1, const void *vp2) +{ + const char *s1 = * (char * const *) vp1; + const char *s2 = * (char * const *) vp2; + + return strcmp (s1, s2); +} + char ** guestfs__inspect_get_roots (guestfs_h *g) { @@ -153,6 +160,8 @@ guestfs__inspect_get_roots (guestfs_h *g) } ret[count] = NULL; + qsort (ret, count, sizeof (char *), compare_strings); + return ret; } @@ -165,9 +174,10 @@ guestfs__inspect_get_type (guestfs_h *g, const char *root) char *ret; switch (fs->type) { + case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break; case OS_TYPE_LINUX: ret = safe_strdup (g, "linux"); break; + case OS_TYPE_NETBSD: ret = safe_strdup (g, "netbsd"); break; case OS_TYPE_WINDOWS: ret = safe_strdup (g, "windows"); break; - case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break; case OS_TYPE_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break; } @@ -194,16 +204,21 @@ guestfs__inspect_get_distro (guestfs_h *g, const char *root) char *ret; switch (fs->distro) { case OS_DISTRO_ARCHLINUX: ret = safe_strdup (g, "archlinux"); break; + case OS_DISTRO_CENTOS: ret = safe_strdup (g, "centos"); break; case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break; case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break; case OS_DISTRO_GENTOO: ret = safe_strdup (g, "gentoo"); break; case OS_DISTRO_LINUX_MINT: ret = safe_strdup (g, "linuxmint"); break; + case OS_DISTRO_MAGEIA: ret = safe_strdup (g, "mageia"); break; case OS_DISTRO_MANDRIVA: ret = safe_strdup (g, "mandriva"); break; case OS_DISTRO_MEEGO: ret = safe_strdup (g, "meego"); break; + case OS_DISTRO_OPENSUSE: ret = safe_strdup (g, "opensuse"); break; case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break; case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break; case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break; + case OS_DISTRO_SCIENTIFIC_LINUX: ret = safe_strdup (g, "scientificlinux"); break; case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break; + case OS_DISTRO_TTYLINUX: ret = safe_strdup (g, "ttylinux"); break; case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break; case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break; case OS_DISTRO_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break; @@ -453,6 +468,7 @@ guestfs__inspect_get_package_format (guestfs_h *g, const char *root) case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break; case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break; case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break; + case OS_PACKAGE_FORMAT_PKGSRC: ret = safe_strdup (g, "pkgsrc"); break; case OS_PACKAGE_FORMAT_UNKNOWN: default: ret = safe_strdup (g, "unknown"); @@ -478,6 +494,7 @@ guestfs__inspect_get_package_management (guestfs_h *g, const char *root) case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break; case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break; case OS_PACKAGE_MANAGEMENT_URPMI: ret = safe_strdup (g, "urpmi"); break; + case OS_PACKAGE_MANAGEMENT_ZYPPER: ret = safe_strdup (g, "zypper"); break; case OS_PACKAGE_MANAGEMENT_UNKNOWN: default: ret = safe_strdup (g, "unknown"); @@ -497,99 +514,12 @@ guestfs__inspect_get_hostname (guestfs_h *g, const char *root) return safe_strdup (g, fs->hostname ? : "unknown"); } -/* Download a guest file to a local temporary file. The file is - * downloaded into g->tmpdir, unless it already exists in g->tmpdir. - * The final name will be g->tmpdir + "/" + basename. Refuse to - * download the guest file if it is larger than max_size. The caller - * does not need to delete the temporary file after use: it will be - * deleted when the handle is cleaned up. - */ -int -guestfs___download_to_tmp (guestfs_h *g, const char *filename, - const char *basename, int64_t max_size) -{ - int tmpdirfd, fd, r = -1; - char buf[32]; - int64_t size; - - tmpdirfd = open (g->tmpdir, O_RDONLY); - if (tmpdirfd == -1) { - perrorf (g, _("%s: temporary directory not found"), g->tmpdir); - return -1; - } - - /* If the file has already been downloaded, return. */ - if (faccessat (tmpdirfd, basename, R_OK, 0) == 0) { - r = 0; - goto out; - } - - /* Check size of remote file. */ - size = guestfs_filesize (g, filename); - if (size == -1) - /* guestfs_filesize failed and has already set error in handle */ - goto out; - if (size > max_size) { - error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), - filename, size); - goto out; - } - - fd = openat (tmpdirfd, basename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600); - if (fd == -1) { - perrorf (g, "openat: %s/%s", g->tmpdir, basename); - goto out; - } - - snprintf (buf, sizeof buf, "/dev/fd/%d", fd); - - if (guestfs_download (g, filename, buf) == -1) { - unlinkat (tmpdirfd, basename, 0); - close (fd); - goto out; - } - - if (close (fd) == -1) { - perrorf (g, "close: %s/%s", g->tmpdir, basename); - unlinkat (tmpdirfd, basename, 0); - goto out; - } - - r = 0; - out: - if (tmpdirfd >= 0) - close (tmpdirfd); - - return r; -} - -struct inspect_fs * -guestfs___search_for_root (guestfs_h *g, const char *root) -{ - if (g->nr_fses == 0) { - error (g, _("no inspection data: call guestfs_inspect_os first")); - return NULL; - } - - size_t i; - struct inspect_fs *fs; - for (i = 0; i < g->nr_fses; ++i) { - fs = &g->fses[i]; - if (fs->is_root && STREQ (root, fs->device)) - return fs; - } - - error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"), - root); - return NULL; -} - -#else /* no PCRE or hivex at compile time */ +#else /* no hivex at compile time */ /* XXX These functions should be in an optgroup. */ #define NOT_IMPL(r) \ - error (g, _("inspection API not available since this version of libguestfs was compiled without PCRE or hivex libraries")); \ + error (g, _("inspection API not available since this version of libguestfs was compiled without the hivex library")); \ return r char ** @@ -719,7 +649,7 @@ guestfs__inspect_is_multipart (guestfs_h *g, const char *root) NOT_IMPL(-1); } -#endif /* no PCRE or hivex at compile time */ +#endif /* no hivex at compile time */ void guestfs___free_inspect_info (guestfs_h *g) @@ -764,3 +694,95 @@ guestfs___feature_available (guestfs_h *g, const char *feature) return r == 0 ? 1 : 0; } + +/* Download a guest file to a local temporary file. The file is + * cached in the temporary directory, and is not downloaded again. + * + * The name of the temporary (downloaded) file is returned. The + * caller must free the pointer, but does *not* need to delete the + * temporary file. It will be deleted when the handle is closed. + * + * Refuse to download the guest file if it is larger than max_size. + * On this and other errors, NULL is returned. + * + * There is actually one cache per 'struct inspect_fs *' in order + * to handle the case of multiple roots. + */ +char * +guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs, + const char *filename, + const char *basename, int64_t max_size) +{ + char *r; + int fd; + char devfd[32]; + int64_t size; + + /* Make the basename unique by prefixing it with the fs number. */ + if (asprintf (&r, "%s/%ld-%s", g->tmpdir, fs - g->fses, basename) == -1) { + perrorf (g, "asprintf"); + return NULL; + } + + /* If the file has already been downloaded, return. */ + if (access (r, R_OK) == 0) + return r; + + /* Check size of remote file. */ + size = guestfs_filesize (g, filename); + if (size == -1) + /* guestfs_filesize failed and has already set error in handle */ + goto error; + if (size > max_size) { + error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), + filename, size); + goto error; + } + + fd = open (r, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600); + if (fd == -1) { + perrorf (g, "open: %s", r); + goto error; + } + + snprintf (devfd, sizeof devfd, "/dev/fd/%d", fd); + + if (guestfs_download (g, filename, devfd) == -1) { + unlink (r); + close (fd); + goto error; + } + + if (close (fd) == -1) { + perrorf (g, "close: %s", r); + unlink (r); + goto error; + } + + return r; + + error: + free (r); + return NULL; +} + +struct inspect_fs * +guestfs___search_for_root (guestfs_h *g, const char *root) +{ + if (g->nr_fses == 0) { + error (g, _("no inspection data: call guestfs_inspect_os first")); + return NULL; + } + + size_t i; + struct inspect_fs *fs; + for (i = 0; i < g->nr_fses; ++i) { + fs = &g->fses[i]; + if (fs->is_root && STREQ (root, fs->device)) + return fs; + } + + error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"), + root); + return NULL; +}