2 * Copyright (C) 2010-2011 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
41 #include "ignore-value.h"
45 #include "guestfs-internal.h"
46 #include "guestfs-internal-actions.h"
47 #include "guestfs_protocol.h"
49 #if defined(HAVE_PCRE) && defined(HAVE_HIVEX)
51 /* The main inspection code. */
53 guestfs__inspect_os (guestfs_h *g)
55 /* Remove any information previously stored in the handle. */
56 guestfs___free_inspect_info (g);
58 if (guestfs_umount_all (g) == -1)
61 /* Iterate over all possible devices. Try to mount each
62 * (read-only). Examine ones which contain filesystems and add that
63 * information to the handle.
65 /* Look to see if any devices directly contain filesystems (RHBZ#590167). */
67 devices = guestfs_list_devices (g);
72 for (i = 0; devices[i] != NULL; ++i) {
73 if (guestfs___check_for_filesystem_on (g, devices[i], 1, 0) == -1) {
74 guestfs___free_string_list (devices);
75 guestfs___free_inspect_info (g);
79 guestfs___free_string_list (devices);
81 /* Look at all partitions. */
83 partitions = guestfs_list_partitions (g);
84 if (partitions == NULL) {
85 guestfs___free_inspect_info (g);
89 for (i = 0; partitions[i] != NULL; ++i) {
90 if (guestfs___check_for_filesystem_on (g, partitions[i], 0, i+1) == -1) {
91 guestfs___free_string_list (partitions);
92 guestfs___free_inspect_info (g);
96 guestfs___free_string_list (partitions);
98 /* Look at all LVs. */
99 if (guestfs___feature_available (g, "lvm2")) {
101 lvs = guestfs_lvs (g);
103 guestfs___free_inspect_info (g);
107 for (i = 0; lvs[i] != NULL; ++i) {
108 if (guestfs___check_for_filesystem_on (g, lvs[i], 0, 0) == -1) {
109 guestfs___free_string_list (lvs);
110 guestfs___free_inspect_info (g);
114 guestfs___free_string_list (lvs);
117 /* At this point we have, in the handle, a list of all filesystems
118 * found and data about each one. Now we assemble the list of
119 * filesystems which are root devices and return that to the user.
120 * Fall through to guestfs__inspect_get_roots to do that.
122 char **ret = guestfs__inspect_get_roots (g);
124 guestfs___free_inspect_info (g);
129 guestfs__inspect_get_roots (guestfs_h *g)
131 /* NB. Doesn't matter if g->nr_fses == 0. We just return an empty
137 for (i = 0; i < g->nr_fses; ++i)
138 if (g->fses[i].is_root)
141 char **ret = calloc (count+1, sizeof (char *));
143 perrorf (g, "calloc");
148 for (i = 0; i < g->nr_fses; ++i) {
149 if (g->fses[i].is_root) {
150 ret[count] = safe_strdup (g, g->fses[i].device);
160 guestfs__inspect_get_type (guestfs_h *g, const char *root)
162 struct inspect_fs *fs = guestfs___search_for_root (g, root);
168 case OS_TYPE_LINUX: ret = safe_strdup (g, "linux"); break;
169 case OS_TYPE_WINDOWS: ret = safe_strdup (g, "windows"); break;
170 case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
171 case OS_TYPE_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
178 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
180 struct inspect_fs *fs = guestfs___search_for_root (g, root);
184 return safe_strdup (g, fs->arch ? : "unknown");
188 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
190 struct inspect_fs *fs = guestfs___search_for_root (g, root);
195 switch (fs->distro) {
196 case OS_DISTRO_ARCHLINUX: ret = safe_strdup (g, "archlinux"); break;
197 case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break;
198 case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break;
199 case OS_DISTRO_GENTOO: ret = safe_strdup (g, "gentoo"); break;
200 case OS_DISTRO_LINUX_MINT: ret = safe_strdup (g, "linuxmint"); break;
201 case OS_DISTRO_MANDRIVA: ret = safe_strdup (g, "mandriva"); break;
202 case OS_DISTRO_MEEGO: ret = safe_strdup (g, "meego"); break;
203 case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break;
204 case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break;
205 case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break;
206 case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break;
207 case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break;
208 case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break;
209 case OS_DISTRO_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
216 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
218 struct inspect_fs *fs = guestfs___search_for_root (g, root);
222 return fs->major_version;
226 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
228 struct inspect_fs *fs = guestfs___search_for_root (g, root);
232 return fs->minor_version;
236 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
238 struct inspect_fs *fs = guestfs___search_for_root (g, root);
242 return safe_strdup (g, fs->product_name ? : "unknown");
246 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
248 struct inspect_fs *fs = guestfs___search_for_root (g, root);
252 return safe_strdup (g, fs->product_variant ? : "unknown");
256 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
258 struct inspect_fs *fs = guestfs___search_for_root (g, root);
262 if (!fs->windows_systemroot) {
263 error (g, _("not a Windows guest, or systemroot could not be determined"));
267 return safe_strdup (g, fs->windows_systemroot);
271 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
274 struct inspect_fs *fs = guestfs___search_for_root (g, root);
278 if (!fs->windows_current_control_set) {
279 error (g, _("not a Windows guest, or CurrentControlSet could not be determined"));
283 return safe_strdup (g, fs->windows_current_control_set);
287 guestfs__inspect_get_format (guestfs_h *g, const char *root)
289 struct inspect_fs *fs = guestfs___search_for_root (g, root);
294 switch (fs->format) {
295 case OS_FORMAT_INSTALLED: ret = safe_strdup (g, "installed"); break;
296 case OS_FORMAT_INSTALLER: ret = safe_strdup (g, "installer"); break;
297 case OS_FORMAT_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
304 guestfs__inspect_is_live (guestfs_h *g, const char *root)
306 struct inspect_fs *fs = guestfs___search_for_root (g, root);
310 return fs->is_live_disk;
314 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
316 struct inspect_fs *fs = guestfs___search_for_root (g, root);
320 return fs->is_netinst_disk;
324 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
326 struct inspect_fs *fs = guestfs___search_for_root (g, root);
330 return fs->is_multipart_disk;
334 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
336 struct inspect_fs *fs = guestfs___search_for_root (g, root);
342 /* If no fstab information (Windows) return just the root. */
343 if (fs->nr_fstab == 0) {
344 ret = calloc (3, sizeof (char *));
345 ret[0] = safe_strdup (g, "/");
346 ret[1] = safe_strdup (g, root);
351 #define CRITERION fs->fstab[i].mountpoint[0] == '/'
353 for (i = 0; i < fs->nr_fstab; ++i)
357 /* Hashtables have 2N+1 entries. */
358 ret = calloc (2*count+1, sizeof (char *));
360 perrorf (g, "calloc");
365 for (i = 0; i < fs->nr_fstab; ++i)
367 ret[2*count] = safe_strdup (g, fs->fstab[i].mountpoint);
368 ret[2*count+1] = safe_strdup (g, fs->fstab[i].device);
377 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
379 struct inspect_fs *fs = guestfs___search_for_root (g, root);
385 /* If no fstab information (Windows) return just the root. */
386 if (fs->nr_fstab == 0) {
387 ret = calloc (2, sizeof (char *));
388 ret[0] = safe_strdup (g, root);
393 ret = calloc (fs->nr_fstab + 1, sizeof (char *));
395 perrorf (g, "calloc");
400 for (i = 0; i < fs->nr_fstab; ++i)
401 ret[i] = safe_strdup (g, fs->fstab[i].device);
407 guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root)
411 struct inspect_fs *fs;
413 fs = guestfs___search_for_root (g, root);
417 /* If no drive mappings, return an empty hashtable. */
418 if (!fs->drive_mappings)
421 for (count = 0; fs->drive_mappings[count] != NULL; count++)
425 ret = calloc (count+1, sizeof (char *));
427 perrorf (g, "calloc");
431 /* We need to make a deep copy of the hashtable since the caller
434 for (i = 0; i < count; ++i)
435 ret[i] = safe_strdup (g, fs->drive_mappings[i]);
443 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
445 struct inspect_fs *fs = guestfs___search_for_root (g, root);
450 switch (fs->package_format) {
451 case OS_PACKAGE_FORMAT_RPM: ret = safe_strdup (g, "rpm"); break;
452 case OS_PACKAGE_FORMAT_DEB: ret = safe_strdup (g, "deb"); break;
453 case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break;
454 case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break;
455 case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break;
456 case OS_PACKAGE_FORMAT_UNKNOWN:
458 ret = safe_strdup (g, "unknown");
466 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
468 struct inspect_fs *fs = guestfs___search_for_root (g, root);
473 switch (fs->package_management) {
474 case OS_PACKAGE_MANAGEMENT_YUM: ret = safe_strdup (g, "yum"); break;
475 case OS_PACKAGE_MANAGEMENT_UP2DATE: ret = safe_strdup (g, "up2date"); break;
476 case OS_PACKAGE_MANAGEMENT_APT: ret = safe_strdup (g, "apt"); break;
477 case OS_PACKAGE_MANAGEMENT_PACMAN: ret = safe_strdup (g, "pacman"); break;
478 case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break;
479 case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break;
480 case OS_PACKAGE_MANAGEMENT_URPMI: ret = safe_strdup (g, "urpmi"); break;
481 case OS_PACKAGE_MANAGEMENT_UNKNOWN:
483 ret = safe_strdup (g, "unknown");
491 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
493 struct inspect_fs *fs = guestfs___search_for_root (g, root);
497 return safe_strdup (g, fs->hostname ? : "unknown");
500 /* Download a guest file to a local temporary file. The file is
501 * downloaded into g->tmpdir, unless it already exists in g->tmpdir.
502 * The final name will be g->tmpdir + "/" + basename. Refuse to
503 * download the guest file if it is larger than max_size. The caller
504 * does not need to delete the temporary file after use: it will be
505 * deleted when the handle is cleaned up.
508 guestfs___download_to_tmp (guestfs_h *g, const char *filename,
509 const char *basename, int64_t max_size)
511 int tmpdirfd, fd, r = -1;
515 tmpdirfd = open (g->tmpdir, O_RDONLY);
516 if (tmpdirfd == -1) {
517 perrorf (g, _("%s: temporary directory not found"), g->tmpdir);
521 /* If the file has already been downloaded, return. */
522 if (faccessat (tmpdirfd, basename, R_OK, 0) == 0) {
527 /* Check size of remote file. */
528 size = guestfs_filesize (g, filename);
530 /* guestfs_filesize failed and has already set error in handle */
532 if (size > max_size) {
533 error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
538 fd = openat (tmpdirfd, basename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600);
540 perrorf (g, "openat: %s/%s", g->tmpdir, basename);
544 snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
546 if (guestfs_download (g, filename, buf) == -1) {
547 unlinkat (tmpdirfd, basename, 0);
552 if (close (fd) == -1) {
553 perrorf (g, "close: %s/%s", g->tmpdir, basename);
554 unlinkat (tmpdirfd, basename, 0);
567 guestfs___search_for_root (guestfs_h *g, const char *root)
569 if (g->nr_fses == 0) {
570 error (g, _("no inspection data: call guestfs_inspect_os first"));
575 struct inspect_fs *fs;
576 for (i = 0; i < g->nr_fses; ++i) {
578 if (fs->is_root && STREQ (root, fs->device))
582 error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"),
587 #else /* no PCRE or hivex at compile time */
589 /* XXX These functions should be in an optgroup. */
591 #define NOT_IMPL(r) \
592 error (g, _("inspection API not available since this version of libguestfs was compiled without PCRE or hivex libraries")); \
596 guestfs__inspect_os (guestfs_h *g)
602 guestfs__inspect_get_roots (guestfs_h *g)
608 guestfs__inspect_get_type (guestfs_h *g, const char *root)
614 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
620 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
626 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
632 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
638 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
644 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
650 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
656 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
663 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
669 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
675 guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root)
681 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
687 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
693 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
699 guestfs__inspect_get_format (guestfs_h *g, const char *root)
705 guestfs__inspect_is_live (guestfs_h *g, const char *root)
711 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
717 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
722 #endif /* no PCRE or hivex at compile time */
725 guestfs___free_inspect_info (guestfs_h *g)
728 for (i = 0; i < g->nr_fses; ++i) {
729 free (g->fses[i].device);
730 free (g->fses[i].product_name);
731 free (g->fses[i].product_variant);
732 free (g->fses[i].arch);
733 free (g->fses[i].hostname);
734 free (g->fses[i].windows_systemroot);
735 free (g->fses[i].windows_current_control_set);
737 for (j = 0; j < g->fses[i].nr_fstab; ++j) {
738 free (g->fses[i].fstab[j].device);
739 free (g->fses[i].fstab[j].mountpoint);
741 free (g->fses[i].fstab);
742 if (g->fses[i].drive_mappings)
743 guestfs___free_string_list (g->fses[i].drive_mappings);
750 /* In the Perl code this is a public function. */
752 guestfs___feature_available (guestfs_h *g, const char *feature)
754 /* If there's an error we should ignore it, so to do that we have to
755 * temporarily replace the error handler with a null one.
757 guestfs_error_handler_cb old_error_cb = g->error_cb;
760 const char *groups[] = { feature, NULL };
761 int r = guestfs_available (g, (char * const *) groups);
763 g->error_cb = old_error_cb;
765 return r == 0 ? 1 : 0;