static void test_ctype(void) { int c; for (c = -1; c < 256; c++) { /* Test blank. */ if (c == '\t' || c == ' ') test_pass(c_isblank(c)); else test_fail(c_isblank(c)); /* Test white. */ if (c == '\t' || c == ' ' || c == '\n') test_pass(c_iswhite(c)); else test_fail(c_iswhite(c)); /* Test space. */ if (c == '\t' || c == '\v' || c == '\f' || c == '\r' || c == '\n' || c == ' ') test_pass(c_isspace(c)); else test_fail(c_isspace(c)); /* Test digit. */ if (c >= '0' && c <= '9') test_pass(c_isdigit(c)); else test_fail(c_isdigit(c)); /* Test lower case. */ if (c >= 'a' && c <= 'z') test_pass(c_islower(c)); else test_fail(c_islower(c)); /* Test upper case. */ if (c >= 'A' && c <= 'Z') test_pass(c_isupper(c)); else test_fail(c_isupper(c)); /* Test alpha. */ if (c_islower(c) || c_isupper(c)) test_pass(c_isalpha(c)); else test_fail(c_isalpha(c)); /* Test alphanumeric. */ if (c_isdigit(c) || c_isalpha(c)) test_pass(c_isalnum(c)); else test_fail(c_isalnum(c)); } }
/* Match a file suffix defined by this regular expression: /(\.[A-Za-z~][A-Za-z0-9~]*)*$/ Scan the string *STR and return a pointer to the matching suffix, or NULL if not found. Upon return, *STR points to terminating NUL. */ static const char * match_suffix (const char **str) { const char *match = NULL; bool read_alpha = false; while (**str) { if (read_alpha) { read_alpha = false; if (!c_isalpha (**str) && '~' != **str) match = NULL; } else if ('.' == **str) { read_alpha = true; if (!match) match = *str; } else if (!c_isalnum (**str) && '~' != **str) match = NULL; (*str)++; } return match; }
/** * virConfParseName: * @ctxt: the parsing context * * Parse one name * * Returns a copy of the new string, NULL in case of error */ static char * virConfParseName(virConfParserCtxtPtr ctxt) { const char *base; char *ret; SKIP_BLANKS; base = ctxt->cur; /* TODO: probably need encoding support and UTF-8 parsing ! */ if (!c_isalpha(CUR) && !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name")); return NULL; } while ((ctxt->cur < ctxt->end) && (c_isalnum(CUR) || (CUR == '_') || ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && ((CUR == ':') || (CUR == '.') || (CUR == '-'))) || ((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) && (CUR == '.')))) NEXT; if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; return ret; }
static int uncomment_all_params(char *data, size_t **ret) { size_t count = 0; char *tmp; size_t *params = 0; tmp = data; while (tmp && *tmp) { tmp = strchr(tmp, '\n'); if (!tmp) break; tmp++; /* Uncomment any lines starting #some_var */ if (*tmp == '#' && c_isalpha(*(tmp + 1))) { if (VIR_EXPAND_N(params, count, 1) < 0) { VIR_FREE(params); return -1; } *tmp = ' '; params[count-1] = (tmp + 1) - data; } } if (VIR_EXPAND_N(params, count, 1) < 0) { VIR_FREE(params); return -1; } params[count-1] = 0; *ret = params; return count; }
static void canonical_device_name (char *dev) { if (STRPREFIX (dev, "/dev/") && (dev[5] == 'h' || dev[5] == 'v') && dev[6] == 'd' && c_isalpha (dev[7]) && (c_isdigit (dev[8]) || dev[8] == '\0')) dev[5] = 's'; }
/* verrevcmp helper function */ static inline int order (unsigned char c) { if (c_isdigit (c)) return 0; else if (c_isalpha (c)) return c; else if (c == '~') return -1; else return (int) c + UCHAR_MAX + 1; }
static char * windows_path (guestfs_h *g, const char *root, const char *path) { char *ret; size_t i; /* If there is a drive letter, rewrite the path. */ if (c_isalpha (path[0]) && path[1] == ':') { char drive_letter = c_tolower (path[0]); /* This returns the newly allocated string. */ mount_drive_letter (drive_letter, root); ret = strdup (path + 2); if (ret == NULL) { perror ("strdup"); exit (EXIT_FAILURE); } } else if (!*path) { ret = strdup ("/"); if (ret == NULL) { perror ("strdup"); exit (EXIT_FAILURE); } } else { ret = strdup (path); if (ret == NULL) { perror ("strdup"); exit (EXIT_FAILURE); } } /* Blindly convert any backslashes into forward slashes. Is this good? */ for (i = 0; i < strlen (ret); ++i) if (ret[i] == '\\') ret[i] = '/'; char *t = guestfs_case_sensitive_path (g, ret); free (ret); ret = t; if (ret == NULL) exit (EXIT_FAILURE); return ret; }
static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) { int r; size_t len = strlen (fs->windows_systemroot) + 64; char system[len]; snprintf (system, len, "%s/system32/config/system", fs->windows_systemroot); CLEANUP_FREE char *system_path = guestfs_case_sensitive_path (g, system); if (!system_path) return -1; r = guestfs_is_file (g, system_path); if (r == -1) return -1; /* If the system hive doesn't exist, just accept that we cannot * find hostname etc. */ if (r == 0) return 0; int ret = -1; int64_t root, node, value; CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL; CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values2 = NULL; int32_t dword; size_t i, count; CLEANUP_FREE void *buf = NULL; size_t buflen; const char *hivepath[] = { NULL /* current control set */, "Services", "Tcpip", "Parameters" }; if (guestfs_hivex_open (g, system_path, GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1) goto out; root = guestfs_hivex_root (g); if (root == 0) goto out; /* Get the CurrentControlSet. */ node = guestfs_hivex_node_get_child (g, root, "Select"); if (node == -1) goto out; if (node == 0) { error (g, "hivex: could not locate HKLM\\SYSTEM\\Select"); goto out; } value = guestfs_hivex_node_get_value (g, node, "Current"); if (value == -1) goto out; if (value == 0) { error (g, "hivex: HKLM\\System\\Select Default entry not found"); goto out; } /* XXX Should check the type. */ buf = guestfs_hivex_value_value (g, value, &buflen); if (buflen != 4) { error (g, "hivex: HKLM\\System\\Select\\Current expected to be DWORD"); goto out; } dword = le32toh (*(int32_t *)buf); fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword); /* Get the drive mappings. * This page explains the contents of HKLM\System\MountedDevices: * http://www.goodells.net/multiboot/partsigs.shtml */ node = guestfs_hivex_node_get_child (g, root, "MountedDevices"); if (node == -1) goto out; if (node == 0) /* Not found: skip getting drive letter mappings (RHBZ#803664). */ goto skip_drive_letter_mappings; values = guestfs_hivex_node_values (g, node); /* Count how many DOS drive letter mappings there are. This doesn't * ignore removable devices, so it overestimates, but that doesn't * matter because it just means we'll allocate a few bytes extra. */ for (i = count = 0; i < values->len; ++i) { CLEANUP_FREE char *key = guestfs_hivex_value_key (g, values->val[i].hivex_value_h); if (key == NULL) goto out; if (STRCASEEQLEN (key, "\\DosDevices\\", 12) && c_isalpha (key[12]) && key[13] == ':') count++; } fs->drive_mappings = safe_calloc (g, 2*count + 1, sizeof (char *)); for (i = count = 0; i < values->len; ++i) { int64_t v = values->val[i].hivex_value_h; CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v); if (key == NULL) goto out; if (STRCASEEQLEN (key, "\\DosDevices\\", 12) && c_isalpha (key[12]) && key[13] == ':') { /* Get the binary value. Is it a fixed disk? */ CLEANUP_FREE char *blob = NULL; char *device; size_t len; int64_t type; type = guestfs_hivex_value_type (g, v); blob = guestfs_hivex_value_value (g, v, &len); if (blob != NULL && type == 3 && len == 12) { /* Try to map the blob to a known disk and partition. */ device = map_registry_disk_blob (g, blob); if (device != NULL) { fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1); fs->drive_mappings[count++] = device; } } } } skip_drive_letter_mappings:; /* Get the hostname. */ hivepath[0] = fs->windows_current_control_set; for (node = root, i = 0; node > 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i) { node = guestfs_hivex_node_get_child (g, node, hivepath[i]); } if (node == -1) goto out; if (node == 0) { perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters", fs->windows_current_control_set); goto out; } values2 = guestfs_hivex_node_values (g, node); if (values2 == NULL) goto out; for (i = 0; i < values2->len; ++i) { int64_t v = values2->val[i].hivex_value_h; CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v); if (key == NULL) goto out; if (STRCASEEQ (key, "Hostname")) { fs->hostname = guestfs_hivex_value_utf8 (g, v); if (!fs->hostname) goto out; } /* many other interesting fields here ... */ } ret = 0; out: guestfs_hivex_close (g); return ret; }
/* Parse a line like: "active raid1 sdb1[0] sdc1[1](F)" */ static guestfs_int_mdstat_list * parse_md_stat_line (char *line) { guestfs_int_mdstat_list *ret; guestfs_int_mdstat *t; size_t spaces, n, i, len; char *next; char *p, *q; ret = malloc (sizeof *ret); if (!ret) { reply_with_perror ("malloc"); return NULL; } /* We don't know exactly how many entries we will need yet, but we * can estimate it, and this will always be an over-estimate. */ spaces = count_spaces (line); ret->guestfs_int_mdstat_list_val = calloc (spaces+1, sizeof (struct guestfs_int_mdstat)); if (ret->guestfs_int_mdstat_list_val == NULL) { reply_with_perror ("calloc"); free (ret); return NULL; } for (n = 0; *line; line = next) { len = strcspn (line, " "); if (line[len] == '\0') next = &line[len]; else { line[len] = '\0'; next = &line[len+1]; } if (verbose) printf ("mdstat: %s\n", line); /* Looking for entries that contain "[..]", skip ones which don't. */ p = strchr (line, '['); if (p == NULL) continue; q = strchr (line, ']'); if (q == NULL) continue; if (p > q) continue; ret->guestfs_int_mdstat_list_len = n+1; t = &ret->guestfs_int_mdstat_list_val[n]; /* Device name is everything before the '[' character, but we * need to prefix with /dev/. */ if (p == line) { reply_with_error ("device entry is too short: %s", line); goto error; } *p = '\0'; if (asprintf (&t->mdstat_device, "/dev/%s", line) == -1) { reply_with_perror ("asprintf"); goto error; } /* Device index is the number after '['. */ line = p+1; *q = '\0'; if (sscanf (line, "%" SCNi32, &t->mdstat_index) != 1) { reply_with_error ("not a device number: %s", line); goto error; } /* Looking for flags "(F)(S)...". */ line = q+1; len = strlen (line); t->mdstat_flags = malloc (len+1); if (!t->mdstat_flags) { reply_with_error ("malloc"); goto error; } for (i = 0; *line; line++) { if (c_isalpha (*line)) t->mdstat_flags[i++] = *line; } t->mdstat_flags[i] = '\0'; n++; } return ret; error: for (i = 0; i < spaces+1; ++i) { free (ret->guestfs_int_mdstat_list_val[i].mdstat_device); free (ret->guestfs_int_mdstat_list_val[i].mdstat_flags); } free (ret->guestfs_int_mdstat_list_val); free (ret); return NULL; }
/** * Parse a version string and check for invalid syntax. * * Distinguish between lax (warnings) and strict (error) parsing. * * @param rversion The parsed version. * @param string The version string to parse. * @param err The warning or error message if any. * * @retval 0 On success. * @retval -1 On failure, and err is set accordingly. */ int parseversion(struct dpkg_version *rversion, const char *string, struct dpkg_error *err) { char *hyphen, *colon, *eepochcolon; const char *end, *ptr; /* Trim leading and trailing space. */ while (*string && c_isblank(*string)) string++; if (!*string) return dpkg_put_error(err, _("version string is empty")); /* String now points to the first non-whitespace char. */ end = string; /* Find either the end of the string, or a whitespace char. */ while (*end && !c_isblank(*end)) end++; /* Check for extra chars after trailing space. */ ptr = end; while (*ptr && c_isblank(*ptr)) ptr++; if (*ptr) return dpkg_put_error(err, _("version string has embedded spaces")); colon= strchr(string,':'); if (colon) { long epoch; errno = 0; epoch = strtol(string, &eepochcolon, 10); if (string == eepochcolon) return dpkg_put_error(err, _("epoch in version is empty")); if (colon != eepochcolon) return dpkg_put_error(err, _("epoch in version is not number")); if (epoch < 0) return dpkg_put_error(err, _("epoch in version is negative")); if (epoch > INT_MAX || errno == ERANGE) return dpkg_put_error(err, _("epoch in version is too big")); if (!*++colon) return dpkg_put_error(err, _("nothing after colon in version number")); string= colon; rversion->epoch= epoch; } else { rversion->epoch= 0; } rversion->version= nfstrnsave(string,end-string); hyphen= strrchr(rversion->version,'-'); if (hyphen) { *hyphen++ = '\0'; if (*hyphen == '\0') return dpkg_put_error(err, _("revision number is empty")); } rversion->revision= hyphen ? hyphen : ""; /* XXX: Would be faster to use something like cisversion and cisrevision. */ ptr = rversion->version; if (!*ptr) return dpkg_put_error(err, _("version number is empty")); if (*ptr && !c_isdigit(*ptr++)) return dpkg_put_warn(err, _("version number does not start with digit")); for (; *ptr; ptr++) { if (!c_isdigit(*ptr) && !c_isalpha(*ptr) && strchr(".-+~:", *ptr) == NULL) return dpkg_put_warn(err, _("invalid character in version number")); } for (ptr = rversion->revision; *ptr; ptr++) { if (!c_isdigit(*ptr) && !c_isalpha(*ptr) && strchr(".+~", *ptr) == NULL) return dpkg_put_warn(err, _("invalid character in revision number")); } return 0; }
static void test_all (void) { int c; for (c = -0x80; c < 0x100; c++) { ASSERT (c_isascii (c) == (c >= 0 && c < 0x80)); switch (c) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ASSERT (c_isalnum (c) == 1); break; default: ASSERT (c_isalnum (c) == 0); break; } switch (c) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': ASSERT (c_isalpha (c) == 1); break; default: ASSERT (c_isalpha (c) == 0); break; } switch (c) { case '\t': case ' ': ASSERT (c_isblank (c) == 1); break; default: ASSERT (c_isblank (c) == 0); break; } ASSERT (c_iscntrl (c) == ((c >= 0 && c < 0x20) || c == 0x7f)); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ASSERT (c_isdigit (c) == 1); break; default: ASSERT (c_isdigit (c) == 0); break; } switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': ASSERT (c_islower (c) == 1); break; default: ASSERT (c_islower (c) == 0); break; } ASSERT (c_isgraph (c) == ((c >= 0x20 && c < 0x7f) && c != ' ')); ASSERT (c_isprint (c) == (c >= 0x20 && c < 0x7f)); ASSERT (c_ispunct (c) == (c_isgraph (c) && !c_isalnum (c))); switch (c) { case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': ASSERT (c_isspace (c) == 1); break; default: ASSERT (c_isspace (c) == 0); break; } switch (c) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': ASSERT (c_isupper (c) == 1); break; default: ASSERT (c_isupper (c) == 0); break; } switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': ASSERT (c_isxdigit (c) == 1); break; default: ASSERT (c_isxdigit (c) == 0); break; } switch (c) { case 'A': ASSERT (c_tolower (c) == 'a'); ASSERT (c_toupper (c) == c); break; case 'B': ASSERT (c_tolower (c) == 'b'); ASSERT (c_toupper (c) == c); break; case 'C': ASSERT (c_tolower (c) == 'c'); ASSERT (c_toupper (c) == c); break; case 'D': ASSERT (c_tolower (c) == 'd'); ASSERT (c_toupper (c) == c); break; case 'E': ASSERT (c_tolower (c) == 'e'); ASSERT (c_toupper (c) == c); break; case 'F': ASSERT (c_tolower (c) == 'f'); ASSERT (c_toupper (c) == c); break; case 'G': ASSERT (c_tolower (c) == 'g'); ASSERT (c_toupper (c) == c); break; case 'H': ASSERT (c_tolower (c) == 'h'); ASSERT (c_toupper (c) == c); break; case 'I': ASSERT (c_tolower (c) == 'i'); ASSERT (c_toupper (c) == c); break; case 'J': ASSERT (c_tolower (c) == 'j'); ASSERT (c_toupper (c) == c); break; case 'K': ASSERT (c_tolower (c) == 'k'); ASSERT (c_toupper (c) == c); break; case 'L': ASSERT (c_tolower (c) == 'l'); ASSERT (c_toupper (c) == c); break; case 'M': ASSERT (c_tolower (c) == 'm'); ASSERT (c_toupper (c) == c); break; case 'N': ASSERT (c_tolower (c) == 'n'); ASSERT (c_toupper (c) == c); break; case 'O': ASSERT (c_tolower (c) == 'o'); ASSERT (c_toupper (c) == c); break; case 'P': ASSERT (c_tolower (c) == 'p'); ASSERT (c_toupper (c) == c); break; case 'Q': ASSERT (c_tolower (c) == 'q'); ASSERT (c_toupper (c) == c); break; case 'R': ASSERT (c_tolower (c) == 'r'); ASSERT (c_toupper (c) == c); break; case 'S': ASSERT (c_tolower (c) == 's'); ASSERT (c_toupper (c) == c); break; case 'T': ASSERT (c_tolower (c) == 't'); ASSERT (c_toupper (c) == c); break; case 'U': ASSERT (c_tolower (c) == 'u'); ASSERT (c_toupper (c) == c); break; case 'V': ASSERT (c_tolower (c) == 'v'); ASSERT (c_toupper (c) == c); break; case 'W': ASSERT (c_tolower (c) == 'w'); ASSERT (c_toupper (c) == c); break; case 'X': ASSERT (c_tolower (c) == 'x'); ASSERT (c_toupper (c) == c); break; case 'Y': ASSERT (c_tolower (c) == 'y'); ASSERT (c_toupper (c) == c); break; case 'Z': ASSERT (c_tolower (c) == 'z'); ASSERT (c_toupper (c) == c); break; case 'a': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'A'); break; case 'b': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'B'); break; case 'c': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'C'); break; case 'd': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'D'); break; case 'e': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'E'); break; case 'f': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'F'); break; case 'g': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'G'); break; case 'h': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'H'); break; case 'i': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'I'); break; case 'j': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'J'); break; case 'k': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'K'); break; case 'l': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'L'); break; case 'm': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'M'); break; case 'n': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'N'); break; case 'o': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'O'); break; case 'p': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'P'); break; case 'q': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'Q'); break; case 'r': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'R'); break; case 's': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'S'); break; case 't': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'T'); break; case 'u': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'U'); break; case 'v': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'V'); break; case 'w': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'W'); break; case 'x': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'X'); break; case 'y': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'Y'); break; case 'z': ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == 'Z'); break; default: ASSERT (c_tolower (c) == c); ASSERT (c_toupper (c) == c); break; } } }
enum TOKEN scanner_get_token () { char *pend; if (have_peek) { have_peek = false; return scan_peek; } assert (scan_pos != NULL); /* LCOV_EXCL_LINE */ if (*scan_pos == '\0') return TOK_END; /* White space */ if (c_isspace (*scan_pos)) { while ( c_isspace (*scan_pos) ) ++scan_pos; if (scanner_keep_whitespace) { if (*scan_pos == '\0') return TOK_END; return TOK_WHITESPACE; } } /* special characters */ if (*scan_pos == ',') { ++scan_pos; set_identifier (",", 1); return TOK_COMMA; } if (*scan_pos == '-') { ++scan_pos; set_identifier ("-", 1); return TOK_DASH; } if (*scan_pos == ':') { ++scan_pos; set_identifier (":", 1); return TOK_COLONS; } /* Integer or floating-point value */ if (c_isdigit (*scan_pos)) { enum TOKEN rc = TOK_INTEGER; errno = 0; scan_val_int = strtol (scan_pos, &pend, 10); if (*pend == '.') { /* a floating-point value */ scan_val_float = strtold (scan_pos, &pend); rc = TOK_FLOAT; } if ((c_isalpha (*pend) || *pend=='_') || (errno == ERANGE)) die (EXIT_FAILURE, 0, _("invalid numeric value '%s'"), scan_pos); set_identifier (scan_pos, pend-scan_pos); scan_pos = pend; return rc; } /* a valid identifier ( [a-z_][a-z0-9_]+ ) */ if (c_isalpha (*scan_pos) || *scan_pos == '_') { size_t l=1; char *v=scan_pos+1; while ( c_isalpha (*v) || c_isdigit (*v) || *v=='_' ) ++l, ++v; set_identifier (scan_pos, l); scan_pos += l; return TOK_IDENTIFIER; } die (EXIT_FAILURE, 0, _("invalid operand %s"), quote (scan_pos)); return TOK_END; }
static void * format_parse (const char *format, bool translated, char **invalid_reason) { struct spec spec; struct spec *result; spec.directives = 0; spec.named_arg_count = 0; spec.allocated = 0; spec.named = NULL; for (; *format != '\0';) if (*format++ == '$') { /* A variable substitution. */ char *name; spec.directives++; if (*format == '{') { const char *name_start; const char *name_end; size_t n; name_start = ++format; for (; *format != '\0'; format++) { if (*format == '}') break; if (!c_isascii (*format)) { *invalid_reason = INVALID_NON_ASCII_VARIABLE (); goto bad_format; } if (format > name_start && (*format == '-' || *format == '=' || *format == '+' || *format == '?' || *format == ':')) { *invalid_reason = INVALID_SHELL_SYNTAX (); goto bad_format; } if (!(c_isalnum (*format) || *format == '_') || (format == name_start && c_isdigit (*format))) { *invalid_reason = INVALID_CONTEXT_DEPENDENT_VARIABLE (); goto bad_format; } } if (*format == '\0') { *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE (); goto bad_format; } name_end = format++; n = name_end - name_start; if (n == 0) { *invalid_reason = INVALID_EMPTY_VARIABLE (); goto bad_format; } name = (char *) xmalloc (n + 1); memcpy (name, name_start, n); name[n] = '\0'; } else if (c_isalpha (*format) || *format == '_') { const char *name_start; const char *name_end; size_t n; name_start = format; do format++; while (*format != '\0' && (c_isalnum (*format) || *format == '_')); name_end = format; n = name_end - name_start; name = (char *) xmalloc (n + 1); memcpy (name, name_start, n); name[n] = '\0'; } else if (*format != '\0') { if (!c_isascii (*format)) { *invalid_reason = INVALID_NON_ASCII_VARIABLE (); goto bad_format; } else { *invalid_reason = INVALID_CONTEXT_DEPENDENT_VARIABLE (); goto bad_format; } } else { *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE (); goto bad_format; } /* Named argument. */ if (spec.allocated == spec.named_arg_count) { spec.allocated = 2 * spec.allocated + 1; spec.named = (struct named_arg *) xrealloc (spec.named, spec.allocated * sizeof (struct named_arg)); } spec.named[spec.named_arg_count].name = name; spec.named_arg_count++; } /* Sort the named argument array, and eliminate duplicates. */ if (spec.named_arg_count > 1) { unsigned int i, j; qsort (spec.named, spec.named_arg_count, sizeof (struct named_arg), named_arg_compare); /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i. */ for (i = j = 0; i < spec.named_arg_count; i++) if (j > 0 && strcmp (spec.named[i].name, spec.named[j-1].name) == 0) free (spec.named[i].name); else { if (j < i) spec.named[j].name = spec.named[i].name; j++; } spec.named_arg_count = j; } result = (struct spec *) xmalloc (sizeof (struct spec)); *result = spec; return result; bad_format: if (spec.named != NULL) { unsigned int i; for (i = 0; i < spec.named_arg_count; i++) free (spec.named[i].name); free (spec.named); } return NULL; }
/* Typical crazy output from the xfs_info command: * * meta-data=/dev/sda1 isize=256 agcount=4, agsize=6392 blks * = sectsz=512 attr=2 *[ = crc=0 ] * data = bsize=4096 blocks=25568, imaxpct=25 * = sunit=0 swidth=0 blks * naming =version 2 bsize=4096 ascii-ci=0 * log =internal bsize=4096 blocks=1200, version=2 * = sectsz=512 sunit=0 blks, lazy-count=1 * realtime =none extsz=4096 blocks=0, rtextents=0 * * [...] line only appears in Fedora >= 21 * * We may need to revisit this parsing code if the output changes * in future. */ static guestfs_int_xfsinfo * parse_xfs_info (char **lines) { guestfs_int_xfsinfo *ret; CLEANUP_FREE char *section = NULL; /* first column, eg "meta-data", "data" */ char *p; size_t i; ret = malloc (sizeof *ret); if (ret == NULL) { reply_with_error ("malloc"); return NULL; } /* Initialize fields to NULL or -1 so the caller can tell which fields * were updated in the code below. */ ret->xfs_mntpoint = NULL; ret->xfs_inodesize = -1; ret->xfs_agcount = -1; ret->xfs_agsize = -1; ret->xfs_sectsize = -1; ret->xfs_attr = -1; ret->xfs_blocksize = -1; ret->xfs_datablocks = -1; ret->xfs_imaxpct = -1; ret->xfs_sunit = -1; ret->xfs_swidth = -1; ret->xfs_dirversion = -1; ret->xfs_dirblocksize = -1; ret->xfs_cimode = -1; ret->xfs_logname = NULL; ret->xfs_logblocksize = -1; ret->xfs_logblocks = -1; ret->xfs_logversion = -1; ret->xfs_logsectsize = -1; ret->xfs_logsunit = -1; ret->xfs_lazycount = -1; ret->xfs_rtname = NULL; ret->xfs_rtextsize = -1; ret->xfs_rtblocks = -1; ret->xfs_rtextents = -1; for (i = 0; lines[i] != NULL; ++i) { if (verbose) fprintf (stderr, "xfs_info: lines[%zu] = \'%s\'\n", i, lines[i]); if (c_isalpha (lines[i][0])) { free (section); section = split_strdup (lines[i]); if (!section) goto error; if (verbose) fprintf (stderr, "xfs_info: new section %s\n", section); } if ((p = strstr (lines[i], "meta-data="))) { ret->xfs_mntpoint = split_strdup (p + 10); if (ret->xfs_mntpoint == NULL) goto error; } if ((p = strstr (lines[i], "isize="))) { CLEANUP_FREE char *buf = split_strdup (p + 6); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_inodesize, buf) == -1) goto error; } if ((p = strstr (lines[i], "agcount="))) { CLEANUP_FREE char *buf = split_strdup (p + 8); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_agcount, buf) == -1) goto error; } if ((p = strstr (lines[i], "agsize="))) { CLEANUP_FREE char *buf = split_strdup (p + 7); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_agsize, buf) == -1) goto error; } if ((p = strstr (lines[i], "sectsz="))) { if (section) { CLEANUP_FREE char *buf = split_strdup (p + 7); if (buf == NULL) goto error; if (STREQ (section, "meta-data")) { if (parse_uint32 (&ret->xfs_sectsize, buf) == -1) goto error; } else if (STREQ (section, "log")) { if (parse_uint32 (&ret->xfs_logsectsize, buf) == -1) goto error; } } } if ((p = strstr (lines[i], "attr="))) { CLEANUP_FREE char *buf = split_strdup (p + 5); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_attr, buf) == -1) goto error; } if ((p = strstr (lines[i], "bsize="))) { if (section) { CLEANUP_FREE char *buf = split_strdup (p + 6); if (buf == NULL) goto error; if (STREQ (section, "data")) { if (parse_uint32 (&ret->xfs_blocksize, buf) == -1) goto error; } else if (STREQ (section, "naming")) { if (parse_uint32 (&ret->xfs_dirblocksize, buf) == -1) goto error; } else if (STREQ (section, "log")) { if (parse_uint32 (&ret->xfs_logblocksize, buf) == -1) goto error; } } } if ((p = strstr (lines[i], "blocks="))) { if (section) { CLEANUP_FREE char *buf = split_strdup (p + 7); if (buf == NULL) goto error; if (STREQ (section, "data")) { if (parse_uint64 (&ret->xfs_datablocks, buf) == -1) goto error; } else if (STREQ (section, "log")) { if (parse_uint32 (&ret->xfs_logblocks, buf) == -1) goto error; } else if (STREQ (section, "realtime")) { if (parse_uint64 (&ret->xfs_rtblocks, buf) == -1) goto error; } } } if ((p = strstr (lines[i], "imaxpct="))) { CLEANUP_FREE char *buf = split_strdup (p + 8); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_imaxpct, buf) == -1) goto error; } if ((p = strstr (lines[i], "sunit="))) { if (section) { CLEANUP_FREE char *buf = split_strdup (p + 6); if (buf == NULL) goto error; if (STREQ (section, "data")) { if (parse_uint32 (&ret->xfs_sunit, buf) == -1) goto error; } else if (STREQ (section, "log")) { if (parse_uint32 (&ret->xfs_logsunit, buf) == -1) goto error; } } } if ((p = strstr (lines[i], "swidth="))) { CLEANUP_FREE char *buf = split_strdup (p + 7); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_swidth, buf) == -1) goto error; } if ((p = strstr (lines[i], "naming =version "))) { CLEANUP_FREE char *buf = split_strdup (p + 18); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_dirversion, buf) == -1) goto error; } if ((p = strstr (lines[i], "ascii-ci="))) { CLEANUP_FREE char *buf = split_strdup (p + 9); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_cimode, buf) == -1) goto error; } if ((p = strstr (lines[i], "log ="))) { ret->xfs_logname = split_strdup (p + 10); if (ret->xfs_logname == NULL) goto error; } if ((p = strstr (lines[i], "version="))) { CLEANUP_FREE char *buf = split_strdup (p + 8); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_logversion, buf) == -1) goto error; } if ((p = strstr (lines[i], "lazy-count="))) { CLEANUP_FREE char *buf = split_strdup (p + 11); if (buf == NULL) goto error; if (parse_uint32 (&ret->xfs_lazycount, buf) == -1) goto error; } if ((p = strstr (lines[i], "realtime ="))) { ret->xfs_rtname = split_strdup (p + 10); if (ret->xfs_rtname == NULL) goto error; } if ((p = strstr (lines[i], "rtextents="))) { CLEANUP_FREE char *buf = split_strdup (p + 10); if (buf == NULL) goto error; if (parse_uint64 (&ret->xfs_rtextents, buf) == -1) goto error; } } if (ret->xfs_mntpoint == NULL) { ret->xfs_mntpoint = strdup (""); if (ret->xfs_mntpoint == NULL) goto error; } if (ret->xfs_logname == NULL) { ret->xfs_logname = strdup (""); if (ret->xfs_logname == NULL) goto error; } if (ret->xfs_rtname == NULL) { ret->xfs_rtname = strdup (""); if (ret->xfs_rtname == NULL) goto error; } return ret; error: free (ret->xfs_mntpoint); free (ret->xfs_logname); free (ret->xfs_rtname); free (ret); return NULL; }