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
39 #include "ignore-value.h"
43 #include "guestfs-internal.h"
44 #include "guestfs-internal-actions.h"
45 #include "guestfs_protocol.h"
47 #if defined(HAVE_HIVEX)
49 /* The main inspection code. */
51 guestfs__inspect_os (guestfs_h *g)
53 /* Remove any information previously stored in the handle. */
54 guestfs___free_inspect_info (g);
56 if (guestfs_umount_all (g) == -1)
59 /* Iterate over all possible devices. Try to mount each
60 * (read-only). Examine ones which contain filesystems and add that
61 * information to the handle.
63 /* Look to see if any devices directly contain filesystems (RHBZ#590167). */
64 char **devices = guestfs_list_devices (g);
69 for (i = 0; devices[i] != NULL; ++i) {
70 if (guestfs___check_for_filesystem_on (g, devices[i], 1, 0) == -1) {
71 guestfs___free_string_list (devices);
72 guestfs___free_inspect_info (g);
76 guestfs___free_string_list (devices);
78 /* Look at all partitions. */
79 char **partitions = guestfs_list_partitions (g);
80 if (partitions == NULL) {
81 guestfs___free_inspect_info (g);
85 for (i = 0; partitions[i] != NULL; ++i) {
86 if (guestfs___check_for_filesystem_on (g, partitions[i], 0, i+1) == -1) {
87 guestfs___free_string_list (partitions);
88 guestfs___free_inspect_info (g);
92 guestfs___free_string_list (partitions);
94 /* Look at MD devices. */
95 char **mds = guestfs_list_md_devices (g);
97 guestfs___free_inspect_info (g);
101 for (i = 0; mds[i] != NULL; ++i) {
102 if (guestfs___check_for_filesystem_on (g, mds[i], 0, i+1) == -1) {
103 guestfs___free_string_list (mds);
104 guestfs___free_inspect_info (g);
108 guestfs___free_string_list (mds);
110 /* Look at all LVs. */
111 if (guestfs___feature_available (g, "lvm2")) {
113 lvs = guestfs_lvs (g);
115 guestfs___free_inspect_info (g);
119 for (i = 0; lvs[i] != NULL; ++i) {
120 if (guestfs___check_for_filesystem_on (g, lvs[i], 0, 0) == -1) {
121 guestfs___free_string_list (lvs);
122 guestfs___free_inspect_info (g);
126 guestfs___free_string_list (lvs);
129 /* At this point we have, in the handle, a list of all filesystems
130 * found and data about each one. Now we assemble the list of
131 * filesystems which are root devices and return that to the user.
132 * Fall through to guestfs__inspect_get_roots to do that.
134 char **ret = guestfs__inspect_get_roots (g);
136 guestfs___free_inspect_info (g);
141 compare_strings (const void *vp1, const void *vp2)
143 const char *s1 = * (char * const *) vp1;
144 const char *s2 = * (char * const *) vp2;
146 return strcmp (s1, s2);
150 guestfs__inspect_get_roots (guestfs_h *g)
152 /* NB. Doesn't matter if g->nr_fses == 0. We just return an empty
158 for (i = 0; i < g->nr_fses; ++i)
159 if (g->fses[i].is_root)
162 char **ret = calloc (count+1, sizeof (char *));
164 perrorf (g, "calloc");
169 for (i = 0; i < g->nr_fses; ++i) {
170 if (g->fses[i].is_root) {
171 ret[count] = safe_strdup (g, g->fses[i].device);
177 qsort (ret, count, sizeof (char *), compare_strings);
183 guestfs__inspect_get_type (guestfs_h *g, const char *root)
185 struct inspect_fs *fs = guestfs___search_for_root (g, root);
191 case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
192 case OS_TYPE_HURD: ret = safe_strdup (g, "hurd"); break;
193 case OS_TYPE_LINUX: ret = safe_strdup (g, "linux"); break;
194 case OS_TYPE_NETBSD: ret = safe_strdup (g, "netbsd"); break;
195 case OS_TYPE_WINDOWS: ret = safe_strdup (g, "windows"); break;
196 case OS_TYPE_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
203 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
205 struct inspect_fs *fs = guestfs___search_for_root (g, root);
209 return safe_strdup (g, fs->arch ? : "unknown");
213 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
215 struct inspect_fs *fs = guestfs___search_for_root (g, root);
220 switch (fs->distro) {
221 case OS_DISTRO_ARCHLINUX: ret = safe_strdup (g, "archlinux"); break;
222 case OS_DISTRO_CENTOS: ret = safe_strdup (g, "centos"); break;
223 case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break;
224 case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break;
225 case OS_DISTRO_GENTOO: ret = safe_strdup (g, "gentoo"); break;
226 case OS_DISTRO_LINUX_MINT: ret = safe_strdup (g, "linuxmint"); break;
227 case OS_DISTRO_MAGEIA: ret = safe_strdup (g, "mageia"); break;
228 case OS_DISTRO_MANDRIVA: ret = safe_strdup (g, "mandriva"); break;
229 case OS_DISTRO_MEEGO: ret = safe_strdup (g, "meego"); break;
230 case OS_DISTRO_OPENSUSE: ret = safe_strdup (g, "opensuse"); break;
231 case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break;
232 case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break;
233 case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break;
234 case OS_DISTRO_SCIENTIFIC_LINUX: ret = safe_strdup (g, "scientificlinux"); break;
235 case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break;
236 case OS_DISTRO_TTYLINUX: ret = safe_strdup (g, "ttylinux"); break;
237 case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break;
238 case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break;
239 case OS_DISTRO_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
246 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
248 struct inspect_fs *fs = guestfs___search_for_root (g, root);
252 return fs->major_version;
256 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
258 struct inspect_fs *fs = guestfs___search_for_root (g, root);
262 return fs->minor_version;
266 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
268 struct inspect_fs *fs = guestfs___search_for_root (g, root);
272 return safe_strdup (g, fs->product_name ? : "unknown");
276 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
278 struct inspect_fs *fs = guestfs___search_for_root (g, root);
282 return safe_strdup (g, fs->product_variant ? : "unknown");
286 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
288 struct inspect_fs *fs = guestfs___search_for_root (g, root);
292 if (!fs->windows_systemroot) {
293 error (g, _("not a Windows guest, or systemroot could not be determined"));
297 return safe_strdup (g, fs->windows_systemroot);
301 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
304 struct inspect_fs *fs = guestfs___search_for_root (g, root);
308 if (!fs->windows_current_control_set) {
309 error (g, _("not a Windows guest, or CurrentControlSet could not be determined"));
313 return safe_strdup (g, fs->windows_current_control_set);
317 guestfs__inspect_get_format (guestfs_h *g, const char *root)
319 struct inspect_fs *fs = guestfs___search_for_root (g, root);
324 switch (fs->format) {
325 case OS_FORMAT_INSTALLED: ret = safe_strdup (g, "installed"); break;
326 case OS_FORMAT_INSTALLER: ret = safe_strdup (g, "installer"); break;
327 case OS_FORMAT_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
334 guestfs__inspect_is_live (guestfs_h *g, const char *root)
336 struct inspect_fs *fs = guestfs___search_for_root (g, root);
340 return fs->is_live_disk;
344 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
346 struct inspect_fs *fs = guestfs___search_for_root (g, root);
350 return fs->is_netinst_disk;
354 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
356 struct inspect_fs *fs = guestfs___search_for_root (g, root);
360 return fs->is_multipart_disk;
364 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
366 struct inspect_fs *fs = guestfs___search_for_root (g, root);
372 /* If no fstab information (Windows) return just the root. */
373 if (fs->nr_fstab == 0) {
374 ret = calloc (3, sizeof (char *));
375 ret[0] = safe_strdup (g, "/");
376 ret[1] = safe_strdup (g, root);
381 #define CRITERION fs->fstab[i].mountpoint[0] == '/'
383 for (i = 0; i < fs->nr_fstab; ++i)
387 /* Hashtables have 2N+1 entries. */
388 ret = calloc (2*count+1, sizeof (char *));
390 perrorf (g, "calloc");
395 for (i = 0; i < fs->nr_fstab; ++i)
397 ret[2*count] = safe_strdup (g, fs->fstab[i].mountpoint);
398 ret[2*count+1] = safe_strdup (g, fs->fstab[i].device);
407 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
409 struct inspect_fs *fs = guestfs___search_for_root (g, root);
415 /* If no fstab information (Windows) return just the root. */
416 if (fs->nr_fstab == 0) {
417 ret = calloc (2, sizeof (char *));
418 ret[0] = safe_strdup (g, root);
423 ret = calloc (fs->nr_fstab + 1, sizeof (char *));
425 perrorf (g, "calloc");
430 for (i = 0; i < fs->nr_fstab; ++i)
431 ret[i] = safe_strdup (g, fs->fstab[i].device);
437 guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root)
441 struct inspect_fs *fs;
443 fs = guestfs___search_for_root (g, root);
447 /* If no drive mappings, return an empty hashtable. */
448 if (!fs->drive_mappings)
451 for (count = 0; fs->drive_mappings[count] != NULL; count++)
455 ret = calloc (count+1, sizeof (char *));
457 perrorf (g, "calloc");
461 /* We need to make a deep copy of the hashtable since the caller
464 for (i = 0; i < count; ++i)
465 ret[i] = safe_strdup (g, fs->drive_mappings[i]);
473 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
475 struct inspect_fs *fs = guestfs___search_for_root (g, root);
480 switch (fs->package_format) {
481 case OS_PACKAGE_FORMAT_RPM: ret = safe_strdup (g, "rpm"); break;
482 case OS_PACKAGE_FORMAT_DEB: ret = safe_strdup (g, "deb"); break;
483 case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break;
484 case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break;
485 case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break;
486 case OS_PACKAGE_FORMAT_PKGSRC: ret = safe_strdup (g, "pkgsrc"); break;
487 case OS_PACKAGE_FORMAT_UNKNOWN:
489 ret = safe_strdup (g, "unknown");
497 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
499 struct inspect_fs *fs = guestfs___search_for_root (g, root);
504 switch (fs->package_management) {
505 case OS_PACKAGE_MANAGEMENT_YUM: ret = safe_strdup (g, "yum"); break;
506 case OS_PACKAGE_MANAGEMENT_UP2DATE: ret = safe_strdup (g, "up2date"); break;
507 case OS_PACKAGE_MANAGEMENT_APT: ret = safe_strdup (g, "apt"); break;
508 case OS_PACKAGE_MANAGEMENT_PACMAN: ret = safe_strdup (g, "pacman"); break;
509 case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break;
510 case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break;
511 case OS_PACKAGE_MANAGEMENT_URPMI: ret = safe_strdup (g, "urpmi"); break;
512 case OS_PACKAGE_MANAGEMENT_ZYPPER: ret = safe_strdup (g, "zypper"); break;
513 case OS_PACKAGE_MANAGEMENT_UNKNOWN:
515 ret = safe_strdup (g, "unknown");
523 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
525 struct inspect_fs *fs = guestfs___search_for_root (g, root);
529 return safe_strdup (g, fs->hostname ? : "unknown");
532 #else /* no hivex at compile time */
534 /* XXX These functions should be in an optgroup. */
536 #define NOT_IMPL(r) \
537 error (g, _("inspection API not available since this version of libguestfs was compiled without the hivex library")); \
541 guestfs__inspect_os (guestfs_h *g)
547 guestfs__inspect_get_roots (guestfs_h *g)
553 guestfs__inspect_get_type (guestfs_h *g, const char *root)
559 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
565 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
571 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
577 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
583 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
589 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
595 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
601 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
608 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
614 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
620 guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root)
626 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
632 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
638 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
644 guestfs__inspect_get_format (guestfs_h *g, const char *root)
650 guestfs__inspect_is_live (guestfs_h *g, const char *root)
656 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
662 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
667 #endif /* no hivex at compile time */
670 guestfs___free_inspect_info (guestfs_h *g)
673 for (i = 0; i < g->nr_fses; ++i) {
674 free (g->fses[i].device);
675 free (g->fses[i].product_name);
676 free (g->fses[i].product_variant);
677 free (g->fses[i].arch);
678 free (g->fses[i].hostname);
679 free (g->fses[i].windows_systemroot);
680 free (g->fses[i].windows_current_control_set);
682 for (j = 0; j < g->fses[i].nr_fstab; ++j) {
683 free (g->fses[i].fstab[j].device);
684 free (g->fses[i].fstab[j].mountpoint);
686 free (g->fses[i].fstab);
687 if (g->fses[i].drive_mappings)
688 guestfs___free_string_list (g->fses[i].drive_mappings);
695 /* In the Perl code this is a public function. */
697 guestfs___feature_available (guestfs_h *g, const char *feature)
699 /* If there's an error we should ignore it, so to do that we have to
700 * temporarily replace the error handler with a null one.
702 guestfs_error_handler_cb old_error_cb = g->error_cb;
705 const char *groups[] = { feature, NULL };
706 int r = guestfs_available (g, (char * const *) groups);
708 g->error_cb = old_error_cb;
710 return r == 0 ? 1 : 0;
713 /* Download a guest file to a local temporary file. The file is
714 * cached in the temporary directory, and is not downloaded again.
716 * The name of the temporary (downloaded) file is returned. The
717 * caller must free the pointer, but does *not* need to delete the
718 * temporary file. It will be deleted when the handle is closed.
720 * Refuse to download the guest file if it is larger than max_size.
721 * On this and other errors, NULL is returned.
723 * There is actually one cache per 'struct inspect_fs *' in order
724 * to handle the case of multiple roots.
727 guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs,
728 const char *filename,
729 const char *basename, int64_t max_size)
736 /* Make the basename unique by prefixing it with the fs number. */
737 if (asprintf (&r, "%s/%td-%s", g->tmpdir, fs - g->fses, basename) == -1) {
738 perrorf (g, "asprintf");
742 /* If the file has already been downloaded, return. */
743 if (access (r, R_OK) == 0)
746 /* Check size of remote file. */
747 size = guestfs_filesize (g, filename);
749 /* guestfs_filesize failed and has already set error in handle */
751 if (size > max_size) {
752 error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
757 fd = open (r, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600);
759 perrorf (g, "open: %s", r);
763 snprintf (devfd, sizeof devfd, "/dev/fd/%d", fd);
765 if (guestfs_download (g, filename, devfd) == -1) {
771 if (close (fd) == -1) {
772 perrorf (g, "close: %s", r);
785 guestfs___search_for_root (guestfs_h *g, const char *root)
787 if (g->nr_fses == 0) {
788 error (g, _("no inspection data: call guestfs_inspect_os first"));
793 struct inspect_fs *fs;
794 for (i = 0; i < g->nr_fses; ++i) {
796 if (fs->is_root && STREQ (root, fs->device))
800 error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"),