X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Finspect_fs_unix.c;h=b68dde1ef6a6d80f57ce8a2fd2a23d7faf074ef5;hb=27d00960c93b26c68fa1f4068502c32a6e3b5e94;hp=04430e403f15fe6210c58d98070604b533beebf8;hpb=472f02d08b077a5c1ee233d9dcef92ac9b09d4ae;p=libguestfs.git diff --git a/src/inspect_fs_unix.c b/src/inspect_fs_unix.c index 04430e4..b68dde1 100644 --- a/src/inspect_fs_unix.c +++ b/src/inspect_fs_unix.c @@ -64,6 +64,7 @@ static pcre *re_scientific_linux_no_minor; static pcre *re_major_minor; static pcre *re_aug_seq; static pcre *re_xdev; +static pcre *re_cciss; static pcre *re_first_partition; static pcre *re_freebsd; static pcre *re_netbsd; @@ -106,8 +107,8 @@ compile_regexps (void) COMPILE (re_scientific_linux_no_minor, "Scientific Linux.*release (\\d+)", 0); COMPILE (re_major_minor, "(\\d+)\\.(\\d+)", 0); - COMPILE (re_aug_seq, "/\\d+$", 0); - COMPILE (re_xdev, "^/dev/(?:h|s|v|xv)d([a-z]+)(\\d*)$", 0); + COMPILE (re_xdev, "^/dev/(h|s|v|xv)d([a-z]+)(\\d*)$", 0); + COMPILE (re_cciss, "^/dev/(cciss/c\\d+d\\d+)(?:p(\\d+))?$", 0); COMPILE (re_freebsd, "^/dev/ad(\\d+)s(\\d+)([a-z])$", 0); COMPILE (re_netbsd, "^NetBSD (\\d+)\\.(\\d+)", 0); } @@ -126,8 +127,8 @@ free_regexps (void) pcre_free (re_scientific_linux); pcre_free (re_scientific_linux_no_minor); pcre_free (re_major_minor); - pcre_free (re_aug_seq); pcre_free (re_xdev); + pcre_free (re_cciss); pcre_free (re_freebsd); pcre_free (re_netbsd); } @@ -140,7 +141,7 @@ static int check_fstab (guestfs_h *g, struct inspect_fs *fs); static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs, const char *spec, const char *mp); static char *resolve_fstab_device (guestfs_h *g, const char *spec); -static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, int (*f) (guestfs_h *, struct inspect_fs *)); +static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char **configfiles, int (*f) (guestfs_h *, struct inspect_fs *)); /* Set fs->product_name to the first line of the release file. */ static int @@ -443,7 +444,8 @@ guestfs___check_linux_root (guestfs_h *g, struct inspect_fs *fs) * which filesystems are used by the operating system and how they * are mounted. */ - if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1) + const char *configfiles[] = { "/etc/fstab", NULL }; + if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1) return -1; /* Determine hostname. */ @@ -476,7 +478,8 @@ guestfs___check_freebsd_root (guestfs_h *g, struct inspect_fs *fs) check_architecture (g, fs); /* We already know /etc/fstab exists because it's part of the test above. */ - if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1) + const char *configfiles[] = { "/etc/fstab", NULL }; + if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1) return -1; /* Determine hostname. */ @@ -517,7 +520,8 @@ guestfs___check_netbsd_root (guestfs_h *g, struct inspect_fs *fs) check_architecture (g, fs); /* We already know /etc/fstab exists because it's part of the test above. */ - if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1) + const char *configfiles[] = { "/etc/fstab", NULL }; + if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1) return -1; /* Determine hostname. */ @@ -527,6 +531,41 @@ guestfs___check_netbsd_root (guestfs_h *g, struct inspect_fs *fs) return 0; } +/* The currently mounted device may be a Hurd root. Hurd has distros + * just like Linux. + */ +int +guestfs___check_hurd_root (guestfs_h *g, struct inspect_fs *fs) +{ + int r; + + fs->type = OS_TYPE_HURD; + + if (guestfs_exists (g, "/etc/debian_version") > 0) { + fs->distro = OS_DISTRO_DEBIAN; + + if (parse_release_file (g, fs, "/etc/debian_version") == -1) + return -1; + + if (guestfs___parse_major_minor (g, fs) == -1) + return -1; + } + + /* Arch Hurd also exists, but inconveniently it doesn't have + * the normal /etc/arch-release file. XXX + */ + + /* Determine the architecture. */ + check_architecture (g, fs); + + /* XXX Check for /etc/fstab. */ + + /* Determine hostname. */ + if (check_hostname_unix (g, fs) == -1) + return -1; + + return 0; +} static void check_architecture (guestfs_h *g, struct inspect_fs *fs) @@ -563,6 +602,7 @@ check_hostname_unix (guestfs_h *g, struct inspect_fs *fs) { switch (fs->type) { case OS_TYPE_LINUX: + case OS_TYPE_HURD: /* Red Hat-derived would be in /etc/sysconfig/network, and * Debian-derived in the file /etc/hostname. Very old Debian and * SUSE use /etc/HOSTNAME. It's best to just look for each of @@ -580,7 +620,8 @@ check_hostname_unix (guestfs_h *g, struct inspect_fs *fs) return -1; } else if (guestfs_is_file (g, "/etc/sysconfig/network")) { - if (inspect_with_augeas (g, fs, "/etc/sysconfig/network", + const char *configfiles[] = { "/etc/sysconfig/network", NULL }; + if (inspect_with_augeas (g, fs, configfiles, check_hostname_redhat) == -1) return -1; } @@ -681,51 +722,44 @@ check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs) static int check_fstab (guestfs_h *g, struct inspect_fs *fs) { - char **lines = guestfs_aug_ls (g, "/files/etc/fstab"); - if (lines == NULL) - return -1; + char **entries, **entry; + char augpath[256]; + char *spec, *mp; + int r; - if (lines[0] == NULL) { + entries = guestfs_aug_match (g, "/files/etc/fstab/*[label() != '#comment']"); + if (entries == NULL) goto error; + + if (entries[0] == NULL) { error (g, _("could not parse /etc/fstab or empty file")); - guestfs___free_string_list (lines); - return -1; + goto error; } - size_t i; - char augpath[256]; - for (i = 0; lines[i] != NULL; ++i) { - /* Ignore comments. Only care about sequence lines which - * match m{/\d+$}. - */ - if (match (g, lines[i], re_aug_seq)) { - snprintf (augpath, sizeof augpath, "%s/spec", lines[i]); - char *spec = guestfs_aug_get (g, augpath); - if (spec == NULL) { - guestfs___free_string_list (lines); - return -1; - } + for (entry = entries; *entry != NULL; entry++) { + snprintf (augpath, sizeof augpath, "%s/spec", *entry); + spec = guestfs_aug_get (g, augpath); + if (spec == NULL) goto error; - snprintf (augpath, sizeof augpath, "%s/file", lines[i]); - char *mp = guestfs_aug_get (g, augpath); - if (mp == NULL) { - guestfs___free_string_list (lines); - free (spec); - return -1; - } - - int r = add_fstab_entry (g, fs, spec, mp); + snprintf (augpath, sizeof augpath, "%s/file", *entry); + mp = guestfs_aug_get (g, augpath); + if (mp == NULL) { free (spec); - free (mp); - - if (r == -1) { - guestfs___free_string_list (lines); - return -1; - } + goto error; } + + r = add_fstab_entry (g, fs, spec, mp); + free (spec); + free (mp); + + if (r == -1) goto error; } - guestfs___free_string_list (lines); + guestfs___free_string_list (entries); return 0; + +error: + if (entries) guestfs___free_string_list (entries); + return -1; } /* Add a filesystem and possibly a mountpoint entry for @@ -817,7 +851,7 @@ static char * resolve_fstab_device (guestfs_h *g, const char *spec) { char *device = NULL; - char *slice, *disk, *part; + char *type, *slice, *disk, *part; if (STRPREFIX (spec, "/dev/mapper/")) { /* LVM2 does some strange munging on /dev/mapper paths for VGs and @@ -832,33 +866,79 @@ resolve_fstab_device (guestfs_h *g, const char *spec) */ device = guestfs_lvm_canonical_lv_name (g, spec); } - else if (match2 (g, spec, re_xdev, &disk, &part)) { - /* disk: ([a-z]+) + else if (match3 (g, spec, re_xdev, &type, &disk, &part)) { + /* type: (h|s|v|xv) + * disk: ([a-z]+) * part: (\d*) */ char **devices = guestfs_list_devices (g); if (devices == NULL) return NULL; - /* Count how many disks the libguestfs appliance has */ - size_t count; - for (count = 0; devices[count] != NULL; count++) - ; + /* Check any hints we were passed for a non-heuristic mapping */ + char *name = safe_asprintf (g, "%sd%s", type, disk); + size_t i = 0; + struct drive *drive = g->drives; + while (drive) { + if (drive->name && STREQ(drive->name, name)) { + device = safe_asprintf (g, "%s%s", devices[i], part); + break; + } - /* Calculate the numerical index of the disk */ - size_t i = disk[0] - 'a'; - for (char *p = disk + 1; *p != '\0'; p++) { - i += 1; i *= 26; - i += *p - 'a'; + i++; drive = drive->next; } + free (name); + + /* Guess the appliance device name if we didn't find a matching hint */ + if (!device) { + /* Count how many disks the libguestfs appliance has */ + size_t count; + for (count = 0; devices[count] != NULL; count++) + ; + + /* Calculate the numerical index of the disk */ + i = disk[0] - 'a'; + for (char *p = disk + 1; *p != '\0'; p++) { + i += 1; i *= 26; + i += *p - 'a'; + } + + /* Check the index makes sense wrt the number of disks the appliance has. + * If it does, map it to an appliance disk. */ + if (i < count) { + device = safe_asprintf (g, "%s%s", devices[i], part); + } + } + + free (type); + free (disk); + free (part); + guestfs___free_string_list (devices); + } + else if (match2 (g, spec, re_cciss, &disk, &part)) { + /* disk: (cciss/c\d+d\d+) + * part: (\d+)? */ + char **devices = guestfs_list_devices (g); + if (devices == NULL) + return NULL; + + /* Check any hints we were passed for a non-heuristic mapping */ + size_t i = 0; + struct drive *drive = g->drives; + while (drive) { + if (drive->name && STREQ(drive->name, disk)) { + if (part) { + device = safe_asprintf (g, "%s%s", devices[i], part); + } else { + device = safe_strdup (g, devices[i]); + } + break; + } - /* Check the index makes sense wrt the number of disks the appliance has. - * If it does, map it to an appliance disk. */ - if (i < count) { - size_t len = strlen (devices[i]) + strlen (part) + 1; - device = safe_malloc (g, len); - snprintf (device, len, "%s%s", devices[i], part); + i++; drive = drive->next; } + /* We don't try to guess mappings for cciss devices */ + free (disk); free (part); guestfs___free_string_list (devices); @@ -877,15 +957,13 @@ resolve_fstab_device (guestfs_h *g, const char *spec) free (slice); free (part); - if (disk_i == -1 || disk_i > 26 || - slice_i <= 0 || slice_i > 1 /* > 4 .. see comment above */ || - part_i < 0 || part_i >= 26) - goto out; - - device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i + 5); + if (disk_i != -1 && disk_i <= 26 && + slice_i > 0 && slice_i <= 1 /* > 4 .. see comment above */ && + part_i >= 0 && part_i < 26) { + device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i + 5); + } } - out: /* Didn't match device pattern, return original spec unchanged. */ if (device == NULL) device = safe_strdup (g, spec); @@ -899,18 +977,23 @@ resolve_fstab_device (guestfs_h *g, const char *spec) * Augeas is closed. */ static int -inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, +inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, + const char **configfiles, int (*f) (guestfs_h *, struct inspect_fs *)) { - /* Security: Refuse to do this if filename is too large. */ - int64_t size = guestfs_filesize (g, filename); - if (size == -1) - /* guestfs_filesize failed and has already set error in handle */ - return -1; - if (size > MAX_AUGEAS_FILE_SIZE) { - error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), - filename, size); - return -1; + /* Security: Refuse to do this if a config file is too large. */ + for (const char **i = configfiles; *i != NULL; i++) { + if (guestfs_exists(g, *i) == 0) continue; + + int64_t size = guestfs_filesize (g, *i); + if (size == -1) + /* guestfs_filesize failed and has already set error in handle */ + return -1; + if (size > MAX_AUGEAS_FILE_SIZE) { + error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), + *i, size); + return -1; + } } /* If !feature_available (g, "augeas") then the next call will fail. @@ -923,11 +1006,42 @@ inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, int r = -1; /* Tell Augeas to only load one file (thanks Raphaël Pinson). */ - char buf[strlen (filename) + 64]; - snprintf (buf, strlen (filename) + 64, "/augeas/load//incl[. != \"%s\"]", - filename); - if (guestfs_aug_rm (g, buf) == -1) +#define AUGEAS_LOAD "/augeas/load//incl[. != \"" +#define AUGEAS_LOAD_LEN (strlen(AUGEAS_LOAD)) + size_t conflen = strlen(configfiles[0]); + size_t buflen = AUGEAS_LOAD_LEN + conflen + 1 /* Closing " */; + char *buf = safe_malloc(g, buflen + 2 /* Closing ] + null terminator */); + + memcpy(buf, AUGEAS_LOAD, AUGEAS_LOAD_LEN); + memcpy(buf + AUGEAS_LOAD_LEN, configfiles[0], conflen); + buf[buflen - 1] = '"'; +#undef AUGEAS_LOAD_LEN +#undef AUGEAS_LOAD + +#define EXCL " and . != \"" +#define EXCL_LEN (strlen(EXCL)) + for (const char **i = &configfiles[1]; *i != NULL; i++) { + size_t orig_buflen = buflen; + conflen = strlen(*i); + buflen += EXCL_LEN + conflen + 1 /* Closing " */; + buf = safe_realloc(g, buf, buflen + 2 /* Closing ] + null terminator */); + char *s = buf + orig_buflen; + + memcpy(s, EXCL, EXCL_LEN); + memcpy(s + EXCL_LEN, *i, conflen); + buf[buflen - 1] = '"'; + } +#undef EXCL_LEN +#undef EXCL + + buf[buflen] = ']'; + buf[buflen + 1] = '\0'; + + if (guestfs_aug_rm (g, buf) == -1) { + free(buf); goto out; + } + free(buf); if (guestfs_aug_load (g) == -1) goto out;