/* * get_file_options: * * If vendor == NULL, find a line in the config file with only "OPTIONS="; * if vendor and model are set find the first OPTIONS line in the config * file that matches. Set argc and argv to match the OPTIONS string. * * vendor and model can end in '\n'. */ static int get_file_options(const char *vendor, const char *model, int *argc, char ***newargv) { _cleanup_free_ char *buffer = NULL; _cleanup_fclose_ FILE *f; char *buf; char *str1; char *vendor_in, *model_in, *options_in; /* read in from file */ int lineno; int c; int retval = 0; f = fopen(config_file, "re"); if (!f) { if (errno == ENOENT) return 1; else { log_error_errno(errno, "can't open %s: %m", config_file); return -1; } } /* * Allocate a buffer rather than put it on the stack so we can * keep it around to parse any options (any allocated newargv * points into this buffer for its strings). */ buffer = malloc(MAX_BUFFER_LEN); if (!buffer) return log_oom(); *newargv = NULL; lineno = 0; for (;;) { vendor_in = model_in = options_in = NULL; buf = fgets(buffer, MAX_BUFFER_LEN, f); if (!buf) break; lineno++; if (buf[strlen(buffer) - 1] != '\n') { log_error("Config file line %d too long", lineno); break; } while (isspace(*buf)) buf++; /* blank or all whitespace line */ if (*buf == '\0') continue; /* comment line */ if (*buf == '#') continue; str1 = strsep(&buf, "="); if (str1 && strcaseeq(str1, "VENDOR")) { str1 = get_value(&buf); if (!str1) { retval = log_oom(); break; } vendor_in = str1; str1 = strsep(&buf, "="); if (str1 && strcaseeq(str1, "MODEL")) { str1 = get_value(&buf); if (!str1) { retval = log_oom(); break; } model_in = str1; str1 = strsep(&buf, "="); } } if (str1 && strcaseeq(str1, "OPTIONS")) { str1 = get_value(&buf); if (!str1) { retval = log_oom(); break; } options_in = str1; } /* * Only allow: [vendor=foo[,model=bar]]options=stuff */ if (!options_in || (!vendor_in && model_in)) { log_error("Error parsing config file line %d '%s'", lineno, buffer); retval = -1; break; } if (vendor == NULL) { if (!vendor_in) break; } else if (vendor_in && startswith(vendor, vendor_in) && (!model_in || startswith(model, model_in))) { /* * Matched vendor and optionally model. * * Note: a short vendor_in or model_in can * give a partial match (that is FOO * matches FOOBAR). */ break; } } if (retval == 0) { if (vendor_in != NULL || model_in != NULL || options_in != NULL) { /* * Something matched. Allocate newargv, and store * values found in options_in. */ strcpy(buffer, options_in); c = argc_count(buffer) + 2; *newargv = calloc(c, sizeof(**newargv)); if (!*newargv) retval = log_oom(); else { *argc = c; c = 0; /* * argv[0] at 0 is skipped by getopt, but * store the buffer address there for * later freeing */ (*newargv)[c] = buffer; for (c = 1; c < *argc; c++) (*newargv)[c] = strsep(&buffer, " \t"); buffer = NULL; } } else { /* No matches */ retval = 1; } } return retval; }
/* * get_file_options: * * If vendor == NULL, find a line in the config file with only "OPTIONS="; * if vendor and model are set find the first OPTIONS line in the config * file that matches. Set argc and argv to match the OPTIONS string. * * vendor and model can end in '\n'. */ static int get_file_options(const char *vendor, const char *model, int *argc, char ***newargv) { char *buffer; FILE *fd; char *buf; char *str1; char *vendor_in, *model_in, *options_in; /* read in from file */ int lineno; int c; int retval = 0; dbg("vendor='%s'; model='%s'\n", vendor, model); fd = fopen(config_file, "r"); if (fd == NULL) { dbg("can't open %s\n", config_file); if (errno == ENOENT) { return 1; } else { err("can't open %s: %s", config_file, strerror(errno)); return -1; } } /* * Allocate a buffer rather than put it on the stack so we can * keep it around to parse any options (any allocated newargv * points into this buffer for its strings). */ buffer = malloc(MAX_BUFFER_LEN); if (!buffer) { err("Can't allocate memory."); return -1; } *newargv = NULL; lineno = 0; while (1) { vendor_in = model_in = options_in = NULL; buf = fgets(buffer, MAX_BUFFER_LEN, fd); if (buf == NULL) break; lineno++; if (buf[strlen(buffer) - 1] != '\n') { info("Config file line %d too long.\n", lineno); break; } while (isspace(*buf)) buf++; /* blank or all whitespace line */ if (*buf == '\0') continue; /* comment line */ if (*buf == '#') continue; dbg("lineno %d: '%s'\n", lineno, buf); str1 = strsep(&buf, "="); if (str1 && strcasecmp(str1, "VENDOR") == 0) { str1 = get_value(&buf); if (!str1) { retval = -1; break; } vendor_in = str1; str1 = strsep(&buf, "="); if (str1 && strcasecmp(str1, "MODEL") == 0) { str1 = get_value(&buf); if (!str1) { retval = -1; break; } model_in = str1; str1 = strsep(&buf, "="); } } if (str1 && strcasecmp(str1, "OPTIONS") == 0) { str1 = get_value(&buf); if (!str1) { retval = -1; break; } options_in = str1; } dbg("config file line %d:" " vendor '%s'; model '%s'; options '%s'\n", lineno, vendor_in, model_in, options_in); /* * Only allow: [vendor=foo[,model=bar]]options=stuff */ if (!options_in || (!vendor_in && model_in)) { info("Error parsing config file line %d '%s'", lineno, buffer); retval = -1; break; } if (vendor == NULL) { if (vendor_in == NULL) { dbg("matched global option\n"); break; } } else if ((vendor_in && strncmp(vendor, vendor_in, strlen(vendor_in)) == 0) && (!model_in || (strncmp(model, model_in, strlen(model_in)) == 0))) { /* * Matched vendor and optionally model. * * Note: a short vendor_in or model_in can * give a partial match (that is FOO * matches FOOBAR). */ dbg("matched vendor/model\n"); break; } else { dbg("no match\n"); } } if (retval == 0) { if (vendor_in != NULL || model_in != NULL || options_in != NULL) { /* * Something matched. Allocate newargv, and store * values found in options_in. */ strcpy(buffer, options_in); c = argc_count(buffer) + 2; *newargv = calloc(c, sizeof(**newargv)); if (!*newargv) { err("Can't allocate memory."); retval = -1; } else { *argc = c; c = 0; /* * argv[0] at 0 is skipped by getopt, but * store the buffer address there for * alter freeing. */ (*newargv)[c] = buffer; for (c = 1; c < *argc; c++) (*newargv)[c] = strsep(&buffer, " "); } } else { /* No matches */ retval = 1; } } if (retval != 0) free(buffer); fclose(fd); return retval; }