/* Get the first line of a small file, without any trailing newline * character. * * NOTE: If the file is completely empty or begins with a '\n' * character, this returns an empty string (not NULL). The caller * will usually need to check for this case. */ char * guestfs_int_first_line_of_file (guestfs_h *g, const char *filename) { char **lines = NULL; /* sic: not CLEANUP_FREE_STRING_LIST */ int64_t size; char *ret; /* Don't trust guestfs_head_n not to break with very large files. * Check the file size is something reasonable first. */ size = guestfs_filesize (g, filename); if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return NULL; if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return NULL; } lines = guestfs_head_n (g, 1, filename); if (lines == NULL) return NULL; if (lines[0] == NULL) { guestfs_int_free_string_list (lines); /* Empty file: Return an empty string as explained above. */ return safe_strdup (g, ""); } /* lines[1] should be NULL because of '1' argument above ... */ ret = lines[0]; /* caller frees */ free (lines); return ret; }
static int parse_suse_release (guestfs_h *g, struct inspect_fs *fs, const char *filename) { int64_t size; char *major, *minor; CLEANUP_FREE_STRING_LIST char **lines = NULL; int r = -1; /* Don't trust guestfs_head_n not to break with very large files. * Check the file size is something reasonable first. */ size = guestfs_filesize (g, filename); if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; } lines = guestfs_head_n (g, 10, filename); if (lines == NULL) return -1; if (lines[0] == NULL) goto out; /* First line is dist release name */ fs->product_name = safe_strdup (g, lines[0]); /* Match SLES first because openSuSE regex overlaps some SLES release strings */ if (match (g, fs->product_name, re_sles) || match (g, fs->product_name, re_nld)) { fs->distro = OS_DISTRO_SLES; /* Second line contains version string */ if (lines[1] == NULL) goto out; major = match1 (g, lines[1], re_sles_version); if (major == NULL) goto out; fs->major_version = guestfs___parse_unsigned_int (g, major); free (major); if (fs->major_version == -1) goto out; /* Third line contains service pack string */ if (lines[2] == NULL) goto out; minor = match1 (g, lines[2], re_sles_patchlevel); if (minor == NULL) goto out; fs->minor_version = guestfs___parse_unsigned_int (g, minor); free (minor); if (fs->minor_version == -1) goto out; } else if (match (g, fs->product_name, re_opensuse)) { fs->distro = OS_DISTRO_OPENSUSE; /* Second line contains version string */ if (lines[1] == NULL) goto out; if (match2 (g, lines[1], re_opensuse_version, &major, &minor)) { fs->major_version = guestfs___parse_unsigned_int (g, major); fs->minor_version = guestfs___parse_unsigned_int (g, minor); free (major); free (minor); if (fs->major_version == -1 || fs->minor_version == -1) goto out; } } r = 0; out: return r; }
int main (int argc, char *argv[]) { guestfs_h *g; const char *disk; char **roots, *root, *str, **mountpoints, **lines; size_t i, j; if (argc != 2) { fprintf (stderr, "usage: inspect_vm disk.img\n"); exit (EXIT_FAILURE); } disk = argv[1]; g = guestfs_create (); if (g == NULL) { perror ("failed to create libguestfs handle"); exit (EXIT_FAILURE); } /* Attach the disk image read-only to libguestfs. */ if (guestfs_add_drive_opts (g, disk, /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */ GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, -1) /* this marks end of optional arguments */ == -1) exit (EXIT_FAILURE); /* Run the libguestfs back-end. */ if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); /* Ask libguestfs to inspect for operating systems. */ roots = guestfs_inspect_os (g); if (roots == NULL) exit (EXIT_FAILURE); if (roots[0] == NULL) { fprintf (stderr, "inspect_vm: no operating systems found\n"); exit (EXIT_FAILURE); } for (j = 0; roots[j] != NULL; ++j) { root = roots[j]; printf ("Root device: %s\n", root); /* Print basic information about the operating system. */ str = guestfs_inspect_get_product_name (g, root); if (str) printf (" Product name: %s\n", str); free (str); printf (" Version: %d.%d\n", guestfs_inspect_get_major_version (g, root), guestfs_inspect_get_minor_version (g, root)); str = guestfs_inspect_get_type (g, root); if (str) printf (" Type: %s\n", str); free (str); str = guestfs_inspect_get_distro (g, root); if (str) printf (" Distro: %s\n", str); free (str); /* Mount up the disks, like guestfish -i. * * Sort keys by length, shortest first, so that we end up * mounting the filesystems in the correct order. */ mountpoints = guestfs_inspect_get_mountpoints (g, root); if (mountpoints == NULL) exit (EXIT_FAILURE); qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *), compare_keys_len); for (i = 0; mountpoints[i] != NULL; i += 2) { /* Ignore failures from this call, since bogus entries can * appear in the guest's /etc/fstab. */ guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]); free (mountpoints[i]); free (mountpoints[i+1]); } free (mountpoints); /* If /etc/issue.net file exists, print up to 3 lines. */ if (guestfs_is_file (g, "/etc/issue.net") > 0) { printf ("--- /etc/issue.net ---\n"); lines = guestfs_head_n (g, 3, "/etc/issue.net"); if (lines == NULL) exit (EXIT_FAILURE); for (i = 0; lines[i] != NULL; ++i) { printf ("%s\n", lines[i]); free (lines[i]); } free (lines); } /* Unmount everything. */ if (guestfs_umount_all (g) == -1) exit (EXIT_FAILURE); free (root); } free (roots); guestfs_close (g); exit (EXIT_SUCCESS); }
/* Ubuntu has /etc/lsb-release containing: * DISTRIB_ID=Ubuntu # Distro * DISTRIB_RELEASE=10.04 # Version * DISTRIB_CODENAME=lucid * DISTRIB_DESCRIPTION="Ubuntu 10.04.1 LTS" # Product name * * [Ubuntu-derived ...] Linux Mint was found to have this: * DISTRIB_ID=LinuxMint * DISTRIB_RELEASE=10 * DISTRIB_CODENAME=julia * DISTRIB_DESCRIPTION="Linux Mint 10 Julia" * Linux Mint also has /etc/linuxmint/info with more information, * but we can use the LSB file. * * Mandriva has: * LSB_VERSION=lsb-4.0-amd64:lsb-4.0-noarch * DISTRIB_ID=MandrivaLinux * DISTRIB_RELEASE=2010.1 * DISTRIB_CODENAME=Henry_Farman * DISTRIB_DESCRIPTION="Mandriva Linux 2010.1" * Mandriva also has a normal release file called /etc/mandriva-release. */ static int parse_lsb_release (guestfs_h *g, struct inspect_fs *fs) { const char *filename = "/etc/lsb-release"; int64_t size; CLEANUP_FREE_STRING_LIST char **lines = NULL; size_t i; int r = 0; /* Don't trust guestfs_head_n not to break with very large files. * Check the file size is something reasonable first. */ size = guestfs_filesize (g, filename); if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; } lines = guestfs_head_n (g, 10, filename); if (lines == NULL) return -1; for (i = 0; lines[i] != NULL; ++i) { if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=Ubuntu")) { fs->distro = OS_DISTRO_UBUNTU; r = 1; } else if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=LinuxMint")) { fs->distro = OS_DISTRO_LINUX_MINT; r = 1; } else if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=MandrivaLinux")) { fs->distro = OS_DISTRO_MANDRIVA; r = 1; } else if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=\"Mageia\"")) { fs->distro = OS_DISTRO_MAGEIA; r = 1; } else if (STRPREFIX (lines[i], "DISTRIB_RELEASE=")) { char *major, *minor; if (match2 (g, &lines[i][16], re_major_minor, &major, &minor)) { fs->major_version = guestfs___parse_unsigned_int (g, major); free (major); if (fs->major_version == -1) { free (minor); return -1; } fs->minor_version = guestfs___parse_unsigned_int (g, minor); free (minor); if (fs->minor_version == -1) return -1; } } else if (fs->product_name == NULL && (STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=\"") || STRPREFIX (lines[i], "DISTRIB_DESCRIPTION='"))) { size_t len = strlen (lines[i]) - 21 - 1; fs->product_name = safe_strndup (g, &lines[i][21], len); r = 1; } else if (fs->product_name == NULL && STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=")) { size_t len = strlen (lines[i]) - 20; fs->product_name = safe_strndup (g, &lines[i][20], len); r = 1; } } /* The unnecessary construct in the next line is required to * workaround -Wstrict-overflow warning in gcc 4.5.1. */ return r ? 1 : 0; }