Beispiel #1
0
void    pcf_show_master_entries(VSTREAM *fp, int mode, int argc, char **argv)
{
    PCF_MASTER_ENT *masterp;
    PCF_MASTER_FLD_REQ *field_reqs;
    PCF_MASTER_FLD_REQ *req;

    /*
     * Parse the filter expressions.
     */
    if (argc > 0) {
	field_reqs = (PCF_MASTER_FLD_REQ *)
	    mymalloc(sizeof(*field_reqs) * argc);
	for (req = field_reqs; req < field_reqs + argc; req++) {
	    req->match_count = 0;
	    req->raw_text = *argv++;
	    req->service_pattern =
		pcf_parse_service_pattern(req->raw_text, 1, 2);
	    if (req->service_pattern == 0)
		msg_fatal("-M option requires service_name[/type]");
	}
    }

    /*
     * Iterate over the master table.
     */
    for (masterp = pcf_master_table; masterp->argv != 0; masterp++) {
	if (argc > 0) {
	    for (req = field_reqs; req < field_reqs + argc; req++) {
		if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
					      masterp->argv->argv[0],
					      masterp->argv->argv[1])) {
		    req->match_count++;
		    pcf_print_master_entry(fp, mode, masterp);
		}
	    }
	} else {
	    pcf_print_master_entry(fp, mode, masterp);
	}
    }

    /*
     * Cleanup.
     */
    if (argc > 0) {
	for (req = field_reqs; req < field_reqs + argc; req++) {
	    if (req->match_count == 0)
		msg_warn("unmatched request: \"%s\"", req->raw_text);
	    argv_free(req->service_pattern);
	}
	myfree((void *) field_reqs);
    }
}
Beispiel #2
0
void    pcf_show_master_params(VSTREAM *fp, int mode, int argc, char **argv)
{
    PCF_MASTER_ENT *masterp;
    PCF_MASTER_FLD_REQ *field_reqs;
    PCF_MASTER_FLD_REQ *req;
    DICT   *dict;
    const char *param_value;

    /*
     * Parse the filter expressions.
     */
    if (argc > 0) {
	field_reqs = (PCF_MASTER_FLD_REQ *)
	    mymalloc(sizeof(*field_reqs) * argc);
	for (req = field_reqs; req < field_reqs + argc; req++) {
	    req->match_count = 0;
	    req->raw_text = *argv++;
	    req->service_pattern =
		pcf_parse_service_pattern(req->raw_text, 1, 3);
	    if (req->service_pattern == 0)
		msg_fatal("-P option requires service_name[/type[/parameter]]");
	    req->param_pattern = req->service_pattern->argv[2];
	}
    }

    /*
     * Iterate over the master table.
     */
    for (masterp = pcf_master_table; masterp->argv != 0; masterp++) {
	if ((dict = masterp->all_params) != 0) {
	    if (argc > 0) {
		for (req = field_reqs; req < field_reqs + argc; req++) {
		    if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
						  masterp->argv->argv[0],
						  masterp->argv->argv[1])) {
			if (PCF_IS_MAGIC_PARAM_PATTERN(req->param_pattern)) {
			    pcf_show_master_any_param(fp, mode, masterp);
			    req->match_count += 1;
			} else if ((param_value = dict_get(dict,
						req->param_pattern)) != 0) {
			    pcf_print_master_param(fp, mode, masterp,
						   req->param_pattern,
						   param_value);
			    req->match_count += 1;
			}
		    }
		}
	    } else {
		pcf_show_master_any_param(fp, mode, masterp);
	    }
	}
    }

    /*
     * Cleanup.
     */
    if (argc > 0) {
	for (req = field_reqs; req < field_reqs + argc; req++) {
	    if (req->match_count == 0)
		msg_warn("unmatched request: \"%s\"", req->raw_text);
	    argv_free(req->service_pattern);
	}
	myfree((void *) field_reqs);
    }
}
Beispiel #3
0
void    pcf_show_master_fields(VSTREAM *fp, int mode, int argc, char **argv)
{
    const char *myname = "pcf_show_master_fields";
    PCF_MASTER_ENT *masterp;
    PCF_MASTER_FLD_REQ *field_reqs;
    PCF_MASTER_FLD_REQ *req;
    int     field;

    /*
     * Parse the filter expressions.
     */
    if (argc > 0) {
	field_reqs = (PCF_MASTER_FLD_REQ *)
	    mymalloc(sizeof(*field_reqs) * argc);
	for (req = field_reqs; req < field_reqs + argc; req++) {
	    req->match_count = 0;
	    req->raw_text = *argv++;
	    req->service_pattern =
		pcf_parse_service_pattern(req->raw_text, 1, 3);
	    if (req->service_pattern == 0)
		msg_fatal("-F option requires service_name[/type[/field]]");
	    field = req->field_pattern =
		pcf_parse_field_pattern(req->service_pattern->argv[2]);
	    if (pcf_is_magic_field_pattern(field) == 0
		&& (field < 0 || field > PCF_MASTER_FLD_CMD))
		msg_panic("%s: bad attribute field index: %d",
			  myname, field);
	}
    }

    /*
     * Iterate over the master table.
     */
    for (masterp = pcf_master_table; masterp->argv != 0; masterp++) {
	if (argc > 0) {
	    for (req = field_reqs; req < field_reqs + argc; req++) {
		if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
					      masterp->argv->argv[0],
					      masterp->argv->argv[1])) {
		    req->match_count++;
		    field = req->field_pattern;
		    if (pcf_is_magic_field_pattern(field)) {
			for (field = 0; field <= PCF_MASTER_FLD_CMD; field++)
			    pcf_print_master_field(fp, mode, masterp, field);
		    } else {
			pcf_print_master_field(fp, mode, masterp, field);
		    }
		}
	    }
	} else {
	    for (field = 0; field <= PCF_MASTER_FLD_CMD; field++)
		pcf_print_master_field(fp, mode, masterp, field);
	}
    }

    /*
     * Cleanup.
     */
    if (argc > 0) {
	for (req = field_reqs; req < field_reqs + argc; req++) {
	    if (req->match_count == 0)
		msg_warn("unmatched request: \"%s\"", req->raw_text);
	    argv_free(req->service_pattern);
	}
	myfree((void *) field_reqs);
    }
}
Beispiel #4
0
void    pcf_edit_master(int mode, int argc, char **argv)
{
    const char *myname = "pcf_edit_master";
    char   *path;
    EDIT_FILE *ep;
    VSTREAM *src;
    VSTREAM *dst;
    VSTRING *line_buf = vstring_alloc(100);
    VSTRING *parse_buf = vstring_alloc(100);
    int     lineno;
    PCF_MASTER_ENT *new_entry;
    VSTRING *full_entry_buf = vstring_alloc(100);
    char   *cp;
    char   *pattern;
    int     service_name_type_matched;
    const char *err;
    PCF_MASTER_EDIT_REQ *edit_reqs;
    PCF_MASTER_EDIT_REQ *req;
    int     num_reqs = argc;
    const char *edit_opts = "-Me, -Fe, -Pe, -X, or -#";
    char   *service_name;
    char   *service_type;

    /*
     * Sanity check.
     */
    if (num_reqs <= 0)
	msg_panic("%s: empty argument list", myname);

    /*
     * Preprocessing: split pattern=value, then split the pattern components.
     */
    edit_reqs = (PCF_MASTER_EDIT_REQ *) mymalloc(sizeof(*edit_reqs) * num_reqs);
    for (req = edit_reqs; *argv != 0; req++, argv++) {
	req->match_count = 0;
	req->raw_text = *argv;
	cp = req->parsed_text = mystrdup(req->raw_text);
	if (strchr(cp, '\n') != 0)
	    msg_fatal("%s accept no multi-line input", edit_opts);
	while (ISSPACE(*cp))
	    cp++;
	if (*cp == '#')
	    msg_fatal("%s accept no comment input", edit_opts);
	/* Separate the pattern from the value. */
	if (mode & PCF_EDIT_CONF) {
	    if ((err = split_nameval(cp, &pattern, &req->edit_value)) != 0)
		msg_fatal("%s: \"%s\"", err, req->raw_text);
	    if ((mode & PCF_MASTER_PARAM)
	    && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
		msg_fatal("whitespace in parameter value: \"%s\"",
			  req->raw_text);
	} else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
	    if (strchr(cp, '=') != 0)
		msg_fatal("-X or -# requires names without value");
	    pattern = cp;
	    trimblanks(pattern, 0);
	    req->edit_value = 0;
	} else {
	    msg_panic("%s: unknown mode %d", myname, mode);
	}

#define PCF_MASTER_MASK (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)

	/*
	 * Split name/type or name/type/whatever pattern into components.
	 */
	switch (mode & PCF_MASTER_MASK) {
	case PCF_MASTER_ENTRY:
	    if ((req->service_pattern =
		 pcf_parse_service_pattern(pattern, 2, 2)) == 0)
		msg_fatal("-Me, -MX or -M# requires service_name/type");
	    break;
	case PCF_MASTER_FLD:
	    if ((req->service_pattern =
		 pcf_parse_service_pattern(pattern, 3, 3)) == 0)
		msg_fatal("-Fe or -FX requires service_name/type/field_name");
	    req->field_number =
		pcf_parse_field_pattern(req->service_pattern->argv[2]);
	    if (pcf_is_magic_field_pattern(req->field_number))
		msg_fatal("-Fe does not accept wild-card field name");
	    if ((mode & PCF_EDIT_CONF)
		&& req->field_number < PCF_MASTER_FLD_CMD
	    && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
		msg_fatal("-Fe does not accept whitespace in non-command field");
	    break;
	case PCF_MASTER_PARAM:
	    if ((req->service_pattern =
		 pcf_parse_service_pattern(pattern, 3, 3)) == 0)
		msg_fatal("-Pe or -PX requires service_name/type/parameter");
	    req->param_pattern = req->service_pattern->argv[2];
	    if (PCF_IS_MAGIC_PARAM_PATTERN(req->param_pattern))
		msg_fatal("-Pe does not accept wild-card parameter name");
	    if ((mode & PCF_EDIT_CONF)
	    && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
		msg_fatal("-Pe does not accept whitespace in parameter value");
	    break;
	default:
	    msg_panic("%s: unknown edit mode %d", myname, mode);
	}
    }

    /*
     * Open a temp file for the result. This uses a deterministic name so we
     * don't leave behind thrash with random names.
     */
    pcf_set_config_dir();
    path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
	msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
    dst = ep->tmp_fp;

    /*
     * Open the original file for input.
     */
    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
	/* OK to delete, since we control the temp file name exclusively. */
	(void) unlink(ep->tmp_path);
	msg_fatal("open %s for reading: %m", path);
    }

    /*
     * Copy original file to temp file, while replacing service entries on
     * the fly.
     */
    service_name_type_matched = 0;
    new_entry = 0;
    lineno = 0;
    while ((cp = pcf_next_cf_line(parse_buf, src, dst, &lineno)) != 0) {
	vstring_strcpy(line_buf, STR(parse_buf));

	/*
	 * Copy, skip or replace continued text.
	 */
	if (cp > STR(parse_buf)) {
	    if (service_name_type_matched == 0)
		vstream_fputs(STR(line_buf), dst);
	    else if (mode & PCF_COMMENT_OUT)
		vstream_fprintf(dst, "#%s", STR(line_buf));
	}

	/*
	 * Copy or replace (start of) logical line.
	 */
	else {
	    service_name_type_matched = 0;

	    /*
	     * Parse out the service name and type.
	     */
	    if ((service_name = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0
		|| (service_type = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0)
		msg_fatal("file %s: line %d: specify service name and type "
			  "on the same line", path, lineno);
	    if (strchr(service_name, '='))
		msg_fatal("file %s: line %d: service name syntax \"%s\" is "
			  "unsupported with %s", path, lineno, service_name,
			  edit_opts);
	    if (service_type[strcspn(service_type, "=/")] != 0)
		msg_fatal("file %s: line %d: "
			"service type syntax \"%s\" is unsupported with %s",
			  path, lineno, service_type, edit_opts);

	    /*
	     * Match each service pattern.
	     */
	    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
		if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
					      service_name,
					      service_type)) {
		    service_name_type_matched = 1;	/* Sticky flag */
		    req->match_count += 1;

		    /*
		     * Generate replacement master.cf entries.
		     */
		    if ((mode & PCF_EDIT_CONF)
			|| ((mode & PCF_MASTER_PARAM) && (mode & PCF_EDIT_EXCL))) {
			switch (mode & PCF_MASTER_MASK) {

			    /*
			     * Replace master.cf entry field or parameter
			     * value.
			     */
			case PCF_MASTER_FLD:
			case PCF_MASTER_PARAM:
			    if (new_entry == 0) {
				/* Gobble up any continuation lines. */
				pcf_gobble_cf_line(full_entry_buf, line_buf,
						   src, dst, &lineno);
				new_entry = (PCF_MASTER_ENT *)
				    mymalloc(sizeof(*new_entry));
				if ((err = pcf_parse_master_entry(new_entry,
						 STR(full_entry_buf))) != 0)
				    msg_fatal("file %s: line %d: %s",
					      path, lineno, err);
			    }
			    if (mode & PCF_MASTER_FLD) {
				pcf_edit_master_field(new_entry,
						      req->field_number,
						      req->edit_value);
			    } else {
				pcf_edit_master_param(new_entry, mode,
						      req->param_pattern,
						      req->edit_value);
			    }
			    break;

			    /*
			     * Replace entire master.cf entry.
			     */
			case PCF_MASTER_ENTRY:
			    if (new_entry != 0)
				pcf_free_master_entry(new_entry);
			    new_entry = (PCF_MASTER_ENT *)
				mymalloc(sizeof(*new_entry));
			    if ((err = pcf_parse_master_entry(new_entry,
						     req->edit_value)) != 0)
				msg_fatal("%s: \"%s\"", err, req->raw_text);
			    break;
			default:
			    msg_panic("%s: unknown edit mode %d", myname, mode);
			}
		    }
		}
	    }

	    /*
	     * Pass through or replace the current input line.
	     */
	    if (new_entry) {
		pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
		pcf_free_master_entry(new_entry);
		new_entry = 0;
	    } else if (service_name_type_matched == 0) {
		vstream_fputs(STR(line_buf), dst);
	    } else if (mode & PCF_COMMENT_OUT) {
		vstream_fprintf(dst, "#%s", STR(line_buf));
	    }
	}
    }

    /*
     * Postprocessing: when editing entire service entries, generate new
     * entries for services not found. Otherwise (editing fields or
     * parameters), "service not found" is a fatal error.
     */
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
	if (req->match_count == 0) {
	    if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
		new_entry = (PCF_MASTER_ENT *) mymalloc(sizeof(*new_entry));
		if ((err = pcf_parse_master_entry(new_entry, req->edit_value)) != 0)
		    msg_fatal("%s: \"%s\"", err, req->raw_text);
		pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
		pcf_free_master_entry(new_entry);
	    } else if ((mode & PCF_MASTER_ENTRY) == 0) {
		msg_warn("unmatched service_name/type: \"%s\"", req->raw_text);
	    }
	}
    }

    /*
     * When all is well, rename the temp file to the original one.
     */
    if (vstream_fclose(src))
	msg_fatal("read %s: %m", path);
    if (edit_file_close(ep) != 0)
	msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);

    /*
     * Cleanup.
     */
    myfree(path);
    vstring_free(line_buf);
    vstring_free(parse_buf);
    vstring_free(full_entry_buf);
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
	argv_free(req->service_pattern);
	myfree(req->parsed_text);
    }
    myfree((char *) edit_reqs);
}