Ejemplo n.º 1
0
/*
 * 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;
}
Ejemplo n.º 2
0
/*
 * 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;
}