void parse_osinfo(const char *osinfo_bytes, map_string_t *osinfo) { const char *cursor = osinfo_bytes; unsigned line = 0; while (cursor[0] != '\0') { ++line; if (cursor[0] == '#') goto skip_line; const char *key_end = strchrnul(cursor, '='); if (key_end[0] == '\0') { log_notice("os-release:%u: non empty last line", line); break; } if (key_end - cursor == 0) { log_notice("os-release:%u: 0 length key", line); goto skip_line; } const char *value_end = strchrnul(cursor, '\n'); if (key_end > value_end) { log_notice("os-release:%u: missing '='", line); goto skip_line; } char *key = xstrndup(cursor, key_end - cursor); if (get_map_string_item_or_NULL(osinfo, key) != NULL) { log_notice("os-release:%u: redefines key '%s'", line, key); } char *value = xstrndup(key_end + 1, value_end - key_end - 1); unescape_osnifo_value(value, value); log_debug("os-release:%u: parsed line: '%s'='%s'", line, key, value); /* The difference between replace and insert is that if the key already * exists in the GHashTable, it gets replaced by the new key. The old * key and the old value are freed. */ replace_map_string_item(osinfo, key, value); cursor = value_end; if (value_end[0] == '\0') { log_notice("os-release:%u: the last value is not terminated by newline", line); } else ++cursor; continue; skip_line: cursor = strchrnul(cursor, '\n'); cursor += (cursor[0] != '\0'); } }
void set_app_user_setting(map_string_t *settings, const char *name, const char *value) { if (value) replace_map_string_item(settings, xstrdup(name), xstrdup(value)); else remove_map_string_item(settings, name); }
/* Returns false if open failed, else returns true. * TODO: better error detection? */ bool load_conf_file(const char *path, map_string_t *settings, bool skipKeysWithoutValue) { FILE *fp = stdin; if (strcmp(path, "-") != 0) { fp = fopen(path, "r"); if (!fp) return false; } char *line; while ((line = xmalloc_fgetline(fp)) != NULL) { bool in_quote = false; /* We are reusing line buffer to form temporary * "key\0value\0..." in its beginning */ char *value = NULL; char *src; char *dst; for (src = dst = line; *src; src++) { char c = *src; if (c == '"') { in_quote = !in_quote; /* skip the opening quote */ if (in_quote) continue; } if (!in_quote) { /* skip white-space unless it's inside value */ if (isspace(c) && !(value && dst != value)) { continue; } if (c == '#' && dst == line) { break; } if (c == '=') { *dst++ = '\0'; /* terminate key */ value = dst; /* remember where value starts */ continue; } } *dst++ = c; /* store next key or value char */ } /* Skip broken or empty lines. */ if (!value) goto free_line; /* Strip trailing spaces and closing quote from value */ while (dst > value && (isspace(dst[-1]) || dst[-1] == '"')) { dst--; if (*dst == '"') break; } *dst = '\0'; /* terminate value */ if (skipKeysWithoutValue && value[0] == '\0') goto free_line; /* Skip lines with unclosed quotes. */ if (in_quote) goto free_line; replace_map_string_item(settings, xstrdup(line), xstrdup(value)); free_line: free(line); } if (fp != stdin) fclose(fp); return true; }
void set_map_string_item_from_string(map_string_t *ms, const char *key, const char *value) { replace_map_string_item(ms, xstrdup(key), xstrdup(value)); }
int main(int argc, char **argv) { abrt_init(argv); /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif const char *dump_dir_name = "."; const char *conf_file = CONF_DIR"/plugins/upload.conf"; const char *url = NULL; /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "& [-v] -d DIR [-c CONFFILE] [-u URL]\n" "\n" "Uploads compressed tarball of problem directory DIR to URL.\n" "If URL is not specified, creates tarball in "LARGE_DATA_TMP_DIR" and exits.\n" "\n" "URL should have form 'protocol://[user[:pass]@]host/dir/[file.tar.gz]'\n" "where protocol can be http(s), ftp, scp, or file.\n" "File protocol can't have user and host parts: 'file:///dir/[file.tar.gz].'\n" "If URL ends with a slash, the archive name will be generated and appended\n" "to URL; otherwise, URL will be used as full file name.\n" "\n" "Files with names listed in $EXCLUDE_FROM_REPORT are not included\n" "into the tarball.\n" "\n" "\n""If not specified, CONFFILE defaults to "CONF_DIR"/plugins/upload.conf" "\n""Its lines should have 'PARAM = VALUE' format." "Recognized string parameter: URL.\n" "Parameter can be overridden via $Upload_URL." ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, OPT_c = 1 << 2, OPT_u = 1 << 3, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Problem directory")), OPT_STRING('c', NULL, &conf_file , "CONFFILE", _("Config file")), OPT_STRING('u', NULL, &url , "URL" , _("Base URL to upload to")), OPT_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); map_string_t *settings = new_map_string(); if (url) replace_map_string_item(settings, xstrdup("URL"), xstrdup(url)); if (conf_file) load_conf_file(conf_file, settings, /*skip key w/o values:*/ false); int result = create_and_upload_archive(dump_dir_name, settings); free_map_string(settings); return result; }