/* This function is called only if the above function was called, * and only after we've printed the prompt in interactive mode. */ void print_inspect_prompt (void) { size_t i; CLEANUP_FREE char *name = NULL; CLEANUP_FREE_STRING_LIST char **mountpoints; name = guestfs_inspect_get_product_name (g, root); if (name && STRNEQ (name, "unknown")) printf (_("Operating system: %s\n"), name); mountpoints = guestfs_inspect_get_mountpoints (g, root); if (mountpoints == NULL) return; /* Sort by key. */ qsort (mountpoints, guestfs___count_strings (mountpoints) / 2, 2 * sizeof (char *), compare_keys); for (i = 0; mountpoints[i] != NULL; i += 2) { /* Try to make the device name canonical for printing, but don't * worry if this fails. */ CLEANUP_FREE char *dev = guestfs_canonical_device_name (g, mountpoints[i+1]); printf (_("%s mounted on %s\n"), dev ? dev : mountpoints[i+1], mountpoints[i]); } }
/* Note: This is testing characters in the Latin2 set, but the * encoding is still UTF-8 as it must be for libguestfs. */ static void test_latin2 (guestfs_h *g, const struct filesystem *fs) { /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ const char O_dacute[] = { 0xc5, 0x90, 0 }; const char slash_O_dacute[] = { '/', 0xc5, 0x90, 0 }; /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ const char o_dacute[] = { 0xc5, 0x91, 0 }; const char slash_o_dacute[] = { '/', 0xc5, 0x91, 0 }; char **files; size_t count; if (guestfs_touch (g, slash_O_dacute) == -1) exit (EXIT_FAILURE); if (guestfs_touch (g, slash_o_dacute) == -1) exit (EXIT_FAILURE); /* Read list of files, check for case sensitivity. */ files = guestfs_ls (g, "/"); if (files == NULL) exit (EXIT_FAILURE); ignore_lost_and_found (files); count = guestfs___count_strings (files); if (fs->fs_case_insensitive) { /* case insensitive */ if (count != 1) error (EXIT_FAILURE, 0, "error: %s: %s is supposed to be case-insensitive, but %zu files " "(instead of 1) were returned", __func__, fs->fs_name, count); if (memcmp (files[0], o_dacute, 3) != 0 && memcmp (files[0], O_dacute, 3) != 0) error (EXIT_FAILURE, 0, "error: %s: %s returned unexpected filename '%s'", __func__, fs->fs_name, files[0]); } else { /* case sensitive */ if (count != 2) error (EXIT_FAILURE, 0, "error: %s: %s is supposed to be case-sensitive, but %zu files " "(instead of 2) were returned", __func__, fs->fs_name, count); if (memcmp (files[0], O_dacute, 3) != 0 || memcmp (files[1], o_dacute, 3) != 0) error (EXIT_FAILURE, 0, "error: %s: %s returned unexpected filenames '%s' and '%s'", __func__, fs->fs_name, files[0], files[1]); if (guestfs_rm (g, slash_O_dacute) == -1) exit (EXIT_FAILURE); } if (guestfs_rm (g, slash_o_dacute) == -1) exit (EXIT_FAILURE); }
static void test_ascii (guestfs_h *g, const struct filesystem *fs) { char **files; size_t count; /* Create various ASCII-named files. */ if (guestfs_touch (g, "/ABC") == -1) exit (EXIT_FAILURE); if (guestfs_touch (g, "/def") == -1) exit (EXIT_FAILURE); if (guestfs_touch (g, "/abc") == -1) exit (EXIT_FAILURE); /* Read list of files, check for case sensitivity. */ files = guestfs_ls (g, "/"); if (files == NULL) exit (EXIT_FAILURE); ignore_lost_and_found (files); count = guestfs___count_strings (files); if (fs->fs_case_insensitive) { /* case insensitive */ if (count != 2) error (EXIT_FAILURE, 0, "error: %s: %s is supposed to be case-insensitive, but %zu files " "(instead of 2) were returned", __func__, fs->fs_name, count); if (STRCASENEQ (files[0], "abc") || STRCASENEQ (files[1], "def")) error (EXIT_FAILURE, 0, "error: %s: %s returned unexpected filenames '%s' and '%s'", __func__, fs->fs_name, files[0], files[1]); } else { /* case sensitive */ if (count != 3) error (EXIT_FAILURE, 0, "error: %s: %s is supposed to be case-sensitive, but %zu files " "(instead of 3) were returned", __func__, fs->fs_name, count); if (STRNEQ (files[0], "ABC") == -1 || STRNEQ (files[1], "abc") == -1 || STRNEQ (files[2], "def") == -1) error (EXIT_FAILURE, 0, "error: %s: %s returned unexpected filenames '%s', '%s', '%s'", __func__, fs->fs_name, files[0], files[1], files[2]); if (guestfs_rm (g, "/abc") == -1) exit (EXIT_FAILURE); } if (guestfs_rm (g, "/ABC") == -1) exit (EXIT_FAILURE); if (guestfs_rm (g, "/def") == -1) exit (EXIT_FAILURE); }
static void test_chinese (guestfs_h *g, const struct filesystem *fs) { /* Various Simplified Chinese characters from: * https://secure.wikimedia.org/wikipedia/en/wiki/Chinese_characters#Comparisons_of_traditional_Chinese.2C_simplified_Chinese.2C_and_Japanese */ char filenames[][5] = { { '/', 0xe7, 0x94, 0xb5, 0 }, { '/', 0xe4, 0xb9, 0xb0, 0 }, { '/', 0xe5, 0xbc, 0x80, 0 }, { '/', 0xe4, 0xb8, 0x9c, 0 }, { '/', 0xe8, 0xbd, 0xa6, 0 }, { '/', 0xe7, 0xba, 0xa2, 0 }, }; const size_t nr_filenames = sizeof filenames / sizeof filenames[0]; size_t i, j; char **files; size_t count; for (i = 0; i < nr_filenames; ++i) { if (guestfs_touch (g, filenames[i]) == -1) exit (EXIT_FAILURE); } /* Check the filenames. */ files = guestfs_ls (g, "/"); if (files == NULL) exit (EXIT_FAILURE); ignore_lost_and_found (files); count = guestfs___count_strings (files); if (count != nr_filenames) error (EXIT_FAILURE, 0, "error: %s: %s returned unexpected number of files " "(%zu, expecting %zu)", __func__, fs->fs_name, count, nr_filenames); for (j = 0; j < count; ++j) { for (i = 0; i < nr_filenames; ++i) if (memcmp (files[j], &filenames[i][1], 4) == 0) goto next; error (EXIT_FAILURE, 0, "error: %s: %s returned unexpected filename '%s'", __func__, fs->fs_name, files[j]); next:; } for (i = 0; i < nr_filenames; ++i) if (guestfs_rm (g, filenames[i]) == -1) exit (EXIT_FAILURE); }
/* Start ssh subprocess with the standard arguments and possibly some * optional arguments. Also handles password authentication. */ static mexp_h * start_ssh (struct config *config, char **extra_args, int wait_prompt) { size_t i, j, nr_args, count; char port_str[64]; CLEANUP_FREE /* [sic] */ const char **args = NULL; mexp_h *h; const int ovecsize = 12; int ovector[ovecsize]; int saved_timeout; /* Create the ssh argument array. */ nr_args = 0; if (extra_args != NULL) nr_args = guestfs___count_strings (extra_args); nr_args += 11; args = malloc (sizeof (char *) * nr_args); if (args == NULL) { perror ("malloc"); exit (EXIT_FAILURE); } j = 0; args[j++] = "ssh"; args[j++] = "-p"; /* Port. */ snprintf (port_str, sizeof port_str, "%d", config->port); args[j++] = port_str; args[j++] = "-l"; /* Username. */ args[j++] = config->username ? config->username : "******"; args[j++] = "-o"; /* Host key will always be novel. */ args[j++] = "StrictHostKeyChecking=no"; args[j++] = "-o"; /* Only use password authentication. */ args[j++] = "PreferredAuthentications=keyboard-interactive,password"; if (extra_args != NULL) { for (i = 0; extra_args[i] != NULL; ++i) args[j++] = extra_args[i]; } args[j++] = config->server; /* Conversion server. */ args[j++] = NULL; assert (j == nr_args); h = mexp_spawnv ("ssh", (char **) args); if (h == NULL) return NULL; if (config->password && strlen (config->password) > 0) { /* Wait for the password prompt. */ switch (mexp_expect (h, (mexp_regexp[]) { { 100, .re = password_re }, { 0 } }, ovector, ovecsize)) {
/* Test guestfs___split_string. */ static void test_split (void) { char **ret; ret = guestfs___split_string (':', ""); assert (ret); assert (guestfs___count_strings (ret) == 0); guestfs___free_string_list (ret); ret = guestfs___split_string (':', "a"); assert (ret); assert (guestfs___count_strings (ret) == 1); assert (STREQ (ret[0], "a")); guestfs___free_string_list (ret); ret = guestfs___split_string (':', ":"); assert (ret); assert (guestfs___count_strings (ret) == 2); assert (STREQ (ret[0], "")); assert (STREQ (ret[1], "")); guestfs___free_string_list (ret); ret = guestfs___split_string (':', "::"); assert (ret); assert (guestfs___count_strings (ret) == 3); assert (STREQ (ret[0], "")); assert (STREQ (ret[1], "")); assert (STREQ (ret[2], "")); guestfs___free_string_list (ret); ret = guestfs___split_string (':', ":a"); assert (ret); assert (guestfs___count_strings (ret) == 2); assert (STREQ (ret[0], "")); assert (STREQ (ret[1], "a")); guestfs___free_string_list (ret); ret = guestfs___split_string (':', "a:"); assert (ret); assert (guestfs___count_strings (ret) == 2); assert (STREQ (ret[0], "a")); assert (STREQ (ret[1], "")); guestfs___free_string_list (ret); ret = guestfs___split_string (':', "a:b:c"); assert (ret); assert (guestfs___count_strings (ret) == 3); assert (STREQ (ret[0], "a")); assert (STREQ (ret[1], "b")); assert (STREQ (ret[2], "c")); guestfs___free_string_list (ret); }
struct guestfs_xattr_list * guestfs__lxattrlist (guestfs_h *g, const char *dir, char *const *names) { size_t len = guestfs___count_strings (names); size_t i, old_len; struct guestfs_xattr_list *ret; ret = safe_malloc (g, sizeof *ret); ret->len = 0; ret->val = NULL; while (len > 0) { CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; /* Note we don't need to free up the strings because take_strings * does not do a deep copy. */ CLEANUP_FREE char **first = take_strings (g, names, LXATTRLIST_MAX, &names); len = len <= LXATTRLIST_MAX ? 0 : len - LXATTRLIST_MAX; xattrs = guestfs_internal_lxattrlist (g, dir, first); if (xattrs == NULL) { guestfs_free_xattr_list (ret); return NULL; } /* Append xattrs to ret. */ old_len = ret->len; ret->len += xattrs->len; ret->val = safe_realloc (g, ret->val, ret->len * sizeof (struct guestfs_xattr)); for (i = 0; i < xattrs->len; ++i, ++old_len) { /* We have to make a deep copy of the attribute name and value. */ ret->val[old_len].attrname = safe_strdup (g, xattrs->val[i].attrname); ret->val[old_len].attrval = safe_malloc (g, xattrs->val[i].attrval_len); ret->val[old_len].attrval_len = xattrs->val[i].attrval_len; memcpy (ret->val[old_len].attrval, xattrs->val[i].attrval, xattrs->val[i].attrval_len); } } return ret; }
struct guestfs_stat_list * guestfs__lstatlist (guestfs_h *g, const char *dir, char * const*names) { size_t len = guestfs___count_strings (names); size_t old_len; struct guestfs_stat_list *ret; ret = safe_malloc (g, sizeof *ret); ret->len = 0; ret->val = NULL; while (len > 0) { CLEANUP_FREE_STAT_LIST struct guestfs_stat_list *stats = NULL; /* Note we don't need to free up the strings because take_strings * does not do a deep copy. */ CLEANUP_FREE char **first = take_strings (g, names, LSTATLIST_MAX, &names); len = len <= LSTATLIST_MAX ? 0 : len - LSTATLIST_MAX; stats = guestfs_internal_lstatlist (g, dir, first); if (stats == NULL) { guestfs_free_stat_list (ret); return NULL; } /* Append stats to ret. */ old_len = ret->len; ret->len += stats->len; ret->val = safe_realloc (g, ret->val, ret->len * sizeof (struct guestfs_stat)); memcpy (&ret->val[old_len], stats->val, stats->len * sizeof (struct guestfs_stat)); } return ret; }
void inspect_mount_root (const char *root) { CLEANUP_FREE_STRING_LIST char **mountpoints = guestfs_inspect_get_mountpoints (g, root); if (mountpoints == NULL) exit (EXIT_FAILURE); /* Sort by key length, shortest key first, so that we end up * mounting the filesystems in the correct order. */ qsort (mountpoints, guestfs___count_strings (mountpoints) / 2, 2 * sizeof (char *), compare_keys_len); size_t i; size_t mount_errors = 0; for (i = 0; mountpoints[i] != NULL; i += 2) { int r; if (!read_only) r = guestfs_mount (g, mountpoints[i+1], mountpoints[i]); else r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]); if (r == -1) { /* If the "/" filesystem could not be mounted, give up, else * just count the errors and print a warning. */ if (STREQ (mountpoints[i], "/")) exit (EXIT_FAILURE); mount_errors++; } } if (mount_errors) fprintf (stderr, _("%s: some filesystems could not be mounted (ignored)\n"), program_name); }