Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/postconf/   (Postfix Mailserver Version 3.11©)  Datei vom 28.0.2026 mit Größe 37 kB image not shown  

Quelle  postconf_master.c

  Sprache: C
 

/*++
/* NAME
/* postconf_master 3
/* SUMMARY
/* support for master.cf
/* SYNOPSIS
/* #include <postconf.h>
/*
/* const char pcf_daemon_options_expecting_value[];
/*
/* void pcf_read_master(fail_on_open)
/* int fail_on_open;
/*
/* void pcf_show_master_entries(fp, mode, service_filters)
/* VSTREAM *fp;
/* int mode;
/* char **service_filters;
/*
/* void pcf_show_master_fields(fp, mode, n_filters, field_filters)
/* VSTREAM *fp;
/* int mode;
/* int n_filters;
/* char **field_filters;
/*
/* void pcf_edit_master_field(masterp, field, new_value)
/* PCF_MASTER_ENT *masterp;
/* int field;
/* const char *new_value;
/*
/* void pcf_show_master_params(fp, mode, param_class, argc, **param_filters)
/* VSTREAM *fp;
/* int mode;
/* int param_class;
/* int argc;
/* char **param_filters;
/*
/* void pcf_edit_master_param(masterp, mode, param_name, param_value)
/* PCF_MASTER_ENT *masterp;
/* int mode;
/* const char *param_name;
/* const char *param_value;
/* AUXILIARY FUNCTIONS
/* const char *pcf_parse_master_entry(masterp, buf)
/* PCF_MASTER_ENT *masterp;
/* const char *buf;
/*
/* void pcf_print_master_entry(fp, mode, masterp)
/* VSTREAM *fp;
/* int mode;
/* PCF_MASTER_ENT *masterp;
/*
/* void pcf_free_master_entry(masterp)
/* PCF_MASTER_ENT *masterp;
/* DESCRIPTION
/* pcf_read_master() reads entries from master.cf into memory.
/*
/* pcf_show_master_entries() writes the entries in the master.cf
/* file to the specified stream.
/*
/* pcf_show_master_fields() writes name/type/field=value records
/* to the specified stream.
/*
/* pcf_edit_master_field() updates the value of a single-column
/* or multi-column attribute.
/*
/* pcf_show_master_params() writes name/type/parameter=value
/* records to the specified stream. Like show_parameters(),
/* this may list either selected parameters, or all parameters that
/* match the param_class argument.
/*
/* pcf_edit_master_param() updates, removes or adds the named
/* parameter in a master.cf entry (the remove request ignores
/* the parameter value).
/*
/* pcf_daemon_options_expecting_value[] is an array of master.cf
/* daemon command-line options that expect an option value.
/*
/* pcf_parse_master_entry() parses a (perhaps multi-line)
/* string that contains a complete master.cf entry, and
/* normalizes daemon command-line options to simplify further
/* handling.
/*
/* pcf_print_master_entry() prints a parsed master.cf entry.
/*
/* pcf_free_master_entry() returns storage to the heap that
/* was allocated by pcf_parse_master_entry().
/*
/* Arguments
/* .IP fail_on_open
/* Specify FAIL_ON_OPEN if open failure is a fatal error,
/* WARN_ON_OPEN if a warning should be logged instead.
/* .IP fp
/* Output stream.
/* .IP mode
/* Bit-wise OR of flags. Flags other than the following are
/* ignored.
/* .RS
/* .IP PCF_FOLD_LINE
/* Wrap long output lines.
/* .IP PCF_SHOW_EVAL
/* Expand $name in parameter values.
/* .IP PCF_EDIT_EXCL
/* Request that pcf_edit_master_param() removes the parameter.
/* .RE
/* .IP n_filters
/* The number of command-line filters.
/* .IP field_filters
/* A list of zero or more service field patterns (name/type/field).
/* The output is formatted as "name/type/field = value".  If
/* no filters are specified, pcf_show_master_fields() outputs
/* the fields of all master.cf entries in the specified order.
/* .IP param_filters
/* A list of zero or more service parameter patterns
/* (name/type/parameter).  The output is formatted as
/* "name/type/parameter = value".  If no filters are specified,
/* pcf_show_master_params() outputs the parameters of all
/* master.cf entries in sorted order.
/* .IP service_filters
/* A list of zero or more service patterns (name or name/type).
/* If no filters are specified, pcf_show_master_entries()
/* outputs all master.cf entries in the specified order.
/* .IP field
/* Index into parsed master.cf entry.
/* .IP new_value
/* Replacement value for the specified field. It is split in
/* whitespace in case of a multi-field attribute.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <argv.h>
#include <vstream.h>
#include <readlline.h>
#include <stringops.h>
#include <split_at.h>
#include <dict_ht.h>

/* Global library. */

#include <mail_params.h>

/* Master library. */

#include <master_proto.h>

/* Application-specific. */

#include <postconf.h>

const char pcf_daemon_options_expecting_value[] = "o";

 /*
  * Data structure to capture a command-line service field filter.
  */

typedef struct {
    int     match_count;  /* hit count */
    const char *raw_text;  /* full pattern text */
    ARGV   *service_pattern;  /* parsed service name, type, ... */
    int     field_pattern;  /* parsed field pattern */
    const char *param_pattern;  /* parameter pattern */
} PCF_MASTER_FLD_REQ;

 /*
  * Valid inputs.
  */

static const char *pcf_valid_master_types[] = {
    MASTER_XPORT_NAME_UNIX,
    MASTER_XPORT_NAME_FIFO,
    MASTER_XPORT_NAME_INET,
    MASTER_XPORT_NAME_PASS,
    MASTER_XPORT_NAME_UXDG,
    0,
};

static const char pcf_valid_bool_types[] = "yn-";

static VSTRING *pcf_exp_buf;
static VSTRING *pcf_json_buf;

#define STR(x) vstring_str(x)

/* pcf_extract_field - extract text from {}, trim leading/trailing blanks */

static void pcf_extract_field(ARGV *argv, int field, const char *parens)
{
    char   *arg = argv->argv[field];
    char   *err;

    if ((err = extpar(&arg, parens, EXTPAR_FLAG_STRIP)) != 0) {
 msg_warn("%s: %s", MASTER_CONF_FILE, err);
 myfree(err);
    }
    argv_replace_one(argv, field, arg);
}

/* pcf_normalize_nameval - normalize name = value from inside {} */

static void pcf_normalize_nameval(ARGV *argv, int field)
{
    char   *arg = argv->argv[field];
    char   *name;
    char   *value;
    const char *err;
    char   *normalized;

    if ((err = split_nameval(arg, &name, &value)) != 0) {
 msg_warn("%s: %s: \"%s\"", MASTER_CONF_FILE, err, arg);
    } else {
 normalized = concatenate(name, "=", value, (char *) 0);
 argv_replace_one(argv, field, normalized);
 myfree(normalized);
    }
}

/* pcf_normalize_daemon_args - bring daemon arguments into canonical form */

static void pcf_normalize_daemon_args(ARGV *argv)
{
    int     field;
    char   *arg;
    char   *cp;
    char   *junk;
    int     extract_field;

    /*
     * Normalize options to simplify later processing.
     */

    for (field = PCF_MASTER_MIN_FIELDS; argv->argv[field] != 0; field++) {
 arg = argv->argv[field];
 if (arg[0] != '-' || strcmp(arg, "--") == 0)
     break;
 for (cp = arg + 1; *cp; cp++) {
     if (strchr(pcf_daemon_options_expecting_value, *cp) != 0
  && cp > arg + 1) {
  /* Split "-stuffozz" into "-stuff" and "-ozz". */
  junk = concatenate("-", cp, (char *) 0);
  argv_insert_one(argv, field + 1, junk);
  myfree(junk);
  *cp = 0;   /* XXX argv_replace_one() */
  break;
     }
 }
 if (strchr(pcf_daemon_options_expecting_value, arg[1]) == 0)
     /* Option requires no value. */
     continue;
 if (arg[2] != 0) {
     /* Split "-oname=value" into "-o" "name=value". */
     argv_insert_one(argv, field + 1, arg + 2);
     arg[2] = 0;    /* XXX argv_replace_one() */
     field += 1;
     extract_field = (argv->argv[field][0] == CHARS_BRACE[0]);
 } else if (argv->argv[field + 1] != 0) {
     /* Already in "-o" "name=value" form. */
     field += 1;
     extract_field = (argv->argv[field][0] == CHARS_BRACE[0]);
 } else
     extract_field = 0;
 /* Extract text inside {}, optionally convert to name=value. */
 if (extract_field) {
     pcf_extract_field(argv, field, CHARS_BRACE);
     if (argv->argv[field - 1][1] == 'o')
  pcf_normalize_nameval(argv, field);
 }
    }
    /* Normalize non-option arguments. */
    for ( /* void */ ; argv->argv[field] != 0; field++)
 /* Extract text inside {}. */
 if (argv->argv[field][0] == CHARS_BRACE[0])
     pcf_extract_field(argv, field, CHARS_BRACE);
}

/* pcf_fix_fatal - fix multiline text before release */

static NORETURN PRINTFLIKE(12) pcf_fix_fatal(const char *fmt,...)
{
    VSTRING *buf = vstring_alloc(100);
    va_list ap;

    /*
     * Replace newline with whitespace.
     */

    va_start(ap, fmt);
    vstring_vsprintf(buf, fmt, ap);
    va_end(ap);
    translit(STR(buf), "\n"" ");
    msg_fatal("%s", STR(buf));
    /* NOTREACHED */
}

/* pcf_check_master_entry - sanity check master.cf entry */

static void pcf_check_master_entry(ARGV *argv, const char *raw_text)
{
    const char **cpp;
    char   *cp;
    int     len;
    int     field;

    cp = argv->argv[PCF_MASTER_FLD_TYPE];
    for (cpp = pcf_valid_master_types; /* see below */ ; cpp++) {
 if (*cpp == 0)
     pcf_fix_fatal("invalid " PCF_MASTER_NAME_TYPE " field \"%s\" in \"%s\"",
     cp, raw_text);
 if (strcmp(*cpp, cp) == 0)
     break;
    }

    for (field = PCF_MASTER_FLD_PRIVATE; field <= PCF_MASTER_FLD_CHROOT; field++) {
 cp = argv->argv[field];
 if (cp[1] != 0 || strchr(pcf_valid_bool_types, *cp) == 0)
     pcf_fix_fatal("invalid %s field \"%s\" in \"%s\"",
     pcf_str_field_pattern(field), cp, raw_text);
    }

    cp = argv->argv[PCF_MASTER_FLD_WAKEUP];
    len = strlen(cp);
    if (len > 0 && cp[len - 1] == '?')
 len--;
    if (!(cp[0] == '-' && len == 1) && strspn(cp, "0123456789") != len)
 pcf_fix_fatal("invalid " PCF_MASTER_NAME_WAKEUP " field \"%s\" in \"%s\"",
        cp, raw_text);

    cp = argv->argv[PCF_MASTER_FLD_MAXPROC];
    if (strcmp("-", cp) != 0 && cp[strspn(cp, "0123456789")] != 0)
 pcf_fix_fatal("invalid " PCF_MASTER_NAME_MAXPROC " field \"%s\" in \"%s\"",
        cp, raw_text);
}

/* pcf_free_master_entry - destroy parsed entry */

void    pcf_free_master_entry(PCF_MASTER_ENT *masterp)
{
    /* XX Fixme: allocation/deallocation asymmetry. */
    myfree(masterp->name_space);
    argv_free(masterp->argv);
    if (masterp->valid_names)
 htable_free(masterp->valid_names, myfree);
    if (masterp->ro_params)
 dict_close(masterp->ro_params);
    if (masterp->all_params)
 dict_close(masterp->all_params);
    myfree((void *) masterp);
}

/* pcf_parse_master_entry - parse one master line */

const char *pcf_parse_master_entry(PCF_MASTER_ENT *masterp, const char *buf)
{
    ARGV   *argv;
    char   *ro_name_space;
    char   *process_name;

    /*
     * We can't use the master daemon's master_ent routines in their current
     * form. They convert everything to internal form, and they skip disabled
     * services.
     * 
     * The postconf command needs to show default fields as "-", and needs to
     * know about all service names so that it can generate service-dependent
     * parameter names (transport-dependent etc.).
     * 
     * XXX Do per-field sanity checks.
     */

    argv = argv_splitq(buf, PCF_MASTER_BLANKS, CHARS_BRACE);
    if (argv->argc < PCF_MASTER_MIN_FIELDS) {
 argv_free(argv);   /* Coverity 201311 */
 return ("bad field count");
    }
    pcf_check_master_entry(argv, buf);
    pcf_normalize_daemon_args(argv);
    masterp->name_space =
 concatenate(argv->argv[0], PCF_NAMESP_SEP_STR, argv->argv[1], (char *) 0);
    ro_name_space =
 concatenate("ro", PCF_NAMESP_SEP_STR, masterp->name_space, (char *) 0);
    masterp->argv = argv;
    masterp->valid_names = 0;
    masterp->ro_params = dict_ht_open(ro_name_space, O_CREAT | O_RDWR, 0);
    process_name = basename(argv->argv[PCF_MASTER_FLD_CMD]);
    dict_put(masterp->ro_params, VAR_PROCNAME, process_name);
    dict_put(masterp->ro_params, VAR_SERVNAME,
      strcmp(process_name, argv->argv[0]) != 0 ?
      argv->argv[0] : process_name);
    myfree(ro_name_space);
    masterp->all_params = 0;
    return (0);
}

/* pcf_read_master - read and digest the master.cf file */

void    pcf_read_master(int fail_on_open_error)
{
    const char *myname = "pcf_read_master";
    const char *path;
    VSTRING *buf;
    VSTREAM *fp;
    const char *err;
    int     entry_count = 0;
    int     line_count;
    int     last_line = 0;

    /*
     * Sanity check.
     */

    if (pcf_master_table != 0)
 msg_panic("%s: master table is already initialized", myname);

    /*
     * Get the location of master.cf.
     */

    path = pcf_get_master_path();

    /*
     * Initialize the in-memory master table.
     */

    pcf_master_table = (PCF_MASTER_ENT *) mymalloc(sizeof(*pcf_master_table));

    /*
     * Skip blank lines and comment lines. Degrade gracefully if master.cf is
     * not available, and master.cf is not the primary target.
     */

    if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) {
 if (fail_on_open_error)
     msg_fatal("open %s: %m", path);
 msg_warn("open %s: %m", path);
    } else {
 buf = vstring_alloc(100);
 while (readllines(buf, fp, &last_line, &line_count) != 0) {
     pcf_master_table = (PCF_MASTER_ENT *) myrealloc((void *) pcf_master_table,
        (entry_count + 2) * sizeof(*pcf_master_table));
     if ((err = pcf_parse_master_entry(pcf_master_table + entry_count,
           STR(buf))) != 0)
  msg_fatal("file %s: line %d: %s", path, line_count, err);
     entry_count += 1;
 }
 vstream_fclose(fp);
 vstring_free(buf);
    }

    /*
     * Null-terminate the master table and clean up.
     */

    pcf_master_table[entry_count].argv = 0;
}

/* pcf_print_master_entry_as_json - JSON formatter */

static void pcf_print_master_entry_as_json(VSTREAM *fp, int mode,
                PCF_MASTER_ENT *masterp)
{
    char  **argv = masterp->argv->argv;
    const char *arg;
    const char *aval;
    int     field;
    int     in_daemon_options;
    int     need_parens;

    if (pcf_exp_buf == 0 && (mode & PCF_SHOW_EVAL))
 pcf_exp_buf = vstring_alloc(100);
    if (pcf_json_buf == 0 && (mode & PCF_SHOW_JSON))
 pcf_json_buf = vstring_alloc(100);

    /*
     * Output the namespace part first, so that we can reuse a buffer.
     */

    vstream_fprintf(fp, "{\"%s\": ",
      quote_for_json(pcf_json_buf, masterp->name_space, -1));

    /*
     * Show the standard fields with one-space column separation.
     */

#define APPEND_JSON_STR(s, l) quote_for_json_append(pcf_json_buf, (s), (l))
#define APPEND_JSON_STR0(s) APPEND_JSON_STR((s), -1)
#define APPEND_JSON_CHAR(s) APPEND_JSON_STR((s),  1)

    VSTRING_RESET(pcf_json_buf);
    for (field = 0; field < PCF_MASTER_MIN_FIELDS; field++) {
 arg = argv[field];
 if (field > 0)
     APPEND_JSON_CHAR(" ");
 APPEND_JSON_STR0(arg);
    }

    /*
     * Format the daemon command-line options and non-option arguments.
     */

    in_daemon_options = 1;
    for ( /* void */ ; (arg = argv[field]) != 0; field++) {
 aval = 0;
 need_parens = 0;
 if (in_daemon_options) {
     if (arg[0] != '-' || strcmp(arg, "--") == 0) {
  in_daemon_options = 0;
     }

     /*
      * Special processing for options that require a value.
     */

     else if (strchr(pcf_daemon_options_expecting_value, arg[1]) != 0
       && (aval = argv[field + 1]) != 0) {

  /*
   * Optionally, expand $name in parameter value.
 */

  if (strcmp(arg, "-o") == 0
      && (mode & PCF_SHOW_EVAL) != 0)
      aval = pcf_expand_parameter_value(pcf_exp_buf, mode,
            aval, masterp);
  need_parens = aval[strcspn(aval, PCF_MASTER_BLANKS)];
     }
 } else {
     need_parens = arg[strcspn(arg, PCF_MASTER_BLANKS)];
 }
 APPEND_JSON_CHAR(" ");
 if (in_daemon_options == 0 && need_parens)
     APPEND_JSON_CHAR("{");
 APPEND_JSON_STR0(arg);
 if (in_daemon_options == 0 && need_parens)
     APPEND_JSON_CHAR("}");
 if (aval) {
     APPEND_JSON_CHAR(" ");
     if (need_parens)
  APPEND_JSON_CHAR("{");
     APPEND_JSON_STR0(aval);
     if (need_parens)
  APPEND_JSON_CHAR("}");
     field += 1;
 }
    }
    VSTRING_TERMINATE(pcf_json_buf);
    vstream_fprintf(fp, "\"%s\"}\n", STR(pcf_json_buf));

    if (msg_verbose)
 vstream_fflush(fp);
}

/* pcf_print_master_entry - print one master line */

void    pcf_print_master_entry(VSTREAM *fp, int mode, PCF_MASTER_ENT *masterp)
{
    char  **argv = masterp->argv->argv;
    const char *arg;
    const char *aval;
    int     arg_len;
    int     line_len;
    int     field;
    int     in_daemon_options;
    int     need_parens;
    static int column_goal[] = {
 0,    /* service */
 11,    /* type */
 17,    /* private */
 25,    /* unpriv */
 33,    /* chroot */
 41,    /* wakeup */
 49,    /* maxproc */
 57,    /* command */
    };

    if (mode & PCF_SHOW_JSON) {
 pcf_print_master_entry_as_json(fp, mode, masterp);
 return;
    }
#define ADD_TEXT(text, len) do { \
        vstream_fputs(text, fp); line_len += len; } \
    while (0)
#define ADD_SPACE ADD_TEXT(" "1)

    if (pcf_exp_buf == 0)
 pcf_exp_buf = vstring_alloc(100);

    /*
     * Show the standard fields at their preferred column position. Use at
     * least one-space column separation.
     */

    for (line_len = 0, field = 0; field < PCF_MASTER_MIN_FIELDS; field++) {
 arg = argv[field];
 if (line_len > 0) {
     do {
  ADD_SPACE;
     } while (line_len < column_goal[field]);
 }
 ADD_TEXT(arg, strlen(arg));
    }

    /*
     * Format the daemon command-line options and non-option arguments. Here,
     * we have no data-dependent preference for column positions, but we do
     * have argument grouping preferences.
     */

    in_daemon_options = 1;
    for ( /* void */ ; (arg = argv[field]) != 0; field++) {
 arg_len = strlen(arg);
 aval = 0;
 need_parens = 0;
 if (in_daemon_options) {

     /*
      * Try to show the generic options (-v -D) on the first line, and
      * non-options on a later line.
     */

     if (arg[0] != '-' || strcmp(arg, "--") == 0) {
  in_daemon_options = 0;
#if 0
  if (mode & PCF_FOLD_LINE)
      /* Force line wrap. */
      line_len = PCF_LINE_LIMIT;
#endif
     }

     /*
      * Special processing for options that require a value.
     */

     else if (strchr(pcf_daemon_options_expecting_value, arg[1]) != 0
       && (aval = argv[field + 1]) != 0) {

  /* Force line wrap before option with value. */
  line_len = PCF_LINE_LIMIT;

  /*
   * Optionally, expand $name in parameter value.
 */

  if (strcmp(arg, "-o") == 0
      && (mode & PCF_SHOW_EVAL) != 0)
      aval = pcf_expand_parameter_value(pcf_exp_buf, mode,
            aval, masterp);

  /*
   * Keep option and value on the same line.
 */

  arg_len += strlen(aval) + 3;
  if ((need_parens = aval[strcspn(aval, PCF_MASTER_BLANKS)]) != 0)
      arg_len += 2;
     }
 } else {
     need_parens = arg[strcspn(arg, PCF_MASTER_BLANKS)];
 }

 /*
  * Insert a line break when the next item won't fit.
 */

 if (line_len > PCF_INDENT_LEN) {
     if ((mode & PCF_FOLD_LINE) == 0
  || line_len + 1 + arg_len < PCF_LINE_LIMIT) {
  ADD_SPACE;
     } else {
  vstream_fputs("\n" PCF_INDENT_TEXT, fp);
  line_len = PCF_INDENT_LEN;
     }
 }
 if (in_daemon_options == 0 && need_parens)
     ADD_TEXT("{"1);
 ADD_TEXT(arg, strlen(arg));
 if (in_daemon_options == 0 && need_parens)
     ADD_TEXT("}"1);
 if (aval) {
     ADD_TEXT(" "1);
     if (need_parens)
  ADD_TEXT("{"1);
     ADD_TEXT(aval, strlen(aval));
     if (need_parens)
  ADD_TEXT("}"1);
     field += 1;

     /* Force line wrap after option with value. */
     line_len = PCF_LINE_LIMIT;

 }
    }
    vstream_fputs("\n", fp);

    if (msg_verbose)
 vstream_fflush(fp);
}

/* pcf_show_master_entries - show master.cf entries */

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, 12);
     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);
    }
}

/* pcf_print_master_field_as_json - scaffolding for JSON */

static void pcf_print_master_field_as_json(VSTREAM *fp, int mode,
                PCF_MASTER_ENT *masterp,
                int field)
{
    char  **argv = masterp->argv->argv;
    const char *arg;
    const char *aval;
    int     in_daemon_options;
    int     need_parens;

    if (pcf_exp_buf == 0 && (mode & PCF_SHOW_EVAL) != 0)
 pcf_exp_buf = vstring_alloc(100);
    if (pcf_json_buf == 0 && (mode & PCF_SHOW_JSON) != 0)
 pcf_json_buf = vstring_alloc(100);

    /*
     * Output the name part first, so that we can reuse a buffer.
     */

    vstream_fprintf(fp, "{\"%s\": ",
      quote_for_json_var(pcf_json_buf, masterp->name_space,
           PCF_NAMESP_SEP_STR,
           pcf_str_field_pattern(field),
           (const char *) 0));

    /*
     * Show the field value, or the first value in the case of a multi-column
     * field.
     */

    VSTRING_RESET(pcf_json_buf);
    APPEND_JSON_STR0(argv[field]);

    /*
     * Format the daemon command-line options and non-option arguments. Here,
     * we have no data-dependent preference for column positions, but we do
     * have argument grouping preferences.
     */

    if (field == PCF_MASTER_FLD_CMD) {
 in_daemon_options = 1;
 for (field += 1; (arg = argv[field]) != 0; field++) {
     aval = 0;
     need_parens = 0;
     if (in_daemon_options) {
  if (arg[0] != '-' || strcmp(arg, "--") == 0) {
      in_daemon_options = 0;
  } else if (strchr(pcf_daemon_options_expecting_value, arg[1]) != 0
      && (aval = argv[field + 1]) != 0) {

      /*
       * Optionally, expand $name in parameter value.
     */

      if (strcmp(arg, "-o") == 0
   && (mode & PCF_SHOW_EVAL) != 0)
   aval = pcf_expand_parameter_value(pcf_exp_buf, mode,
         aval, masterp);
      need_parens = aval[strcspn(aval, PCF_MASTER_BLANKS)];
  }
     } else {
  need_parens = arg[strcspn(arg, PCF_MASTER_BLANKS)];
     }
     APPEND_JSON_CHAR(" ");
     if (in_daemon_options == 0 && need_parens)
  APPEND_JSON_CHAR("{");
     APPEND_JSON_STR0(arg);
     if (in_daemon_options == 0 && need_parens)
  APPEND_JSON_CHAR("}");
     if (aval) {
  APPEND_JSON_CHAR(" ");
  if (need_parens)
      APPEND_JSON_CHAR("{");
  APPEND_JSON_STR0(aval);
  if (need_parens)
      APPEND_JSON_CHAR("}");
  field += 1;
     }
 }
    }
    VSTRING_TERMINATE(pcf_json_buf);
    vstream_fprintf(fp, "\"%s\"}\n", STR(pcf_json_buf));

    if (msg_verbose)
 vstream_fflush(fp);
}

/* pcf_print_master_field - scaffolding */

static void pcf_print_master_field(VSTREAM *fp, int mode,
               PCF_MASTER_ENT *masterp,
               int field)
{
    char  **argv = masterp->argv->argv;
    const char *arg;
    const char *aval;
    int     arg_len;
    int     line_len;
    int     in_daemon_options;
    int     need_parens;

    if (mode & PCF_SHOW_JSON) {
 pcf_print_master_field_as_json(fp, mode, masterp, field);
 return;
    }
    if (pcf_exp_buf == 0)
 pcf_exp_buf = vstring_alloc(100);

    /*
     * Show the field value, or the first value in the case of a multi-column
     * field.
     */

#define ADD_CHAR(ch) ADD_TEXT((ch), 1)

    line_len = 0;
    if ((mode & PCF_HIDE_NAME) == 0) {
 ADD_TEXT(argv[0], strlen(argv[0]));
 ADD_CHAR(PCF_NAMESP_SEP_STR);
 ADD_TEXT(argv[1], strlen(argv[1]));
 ADD_CHAR(PCF_NAMESP_SEP_STR);
 ADD_TEXT(pcf_str_field_pattern(field), strlen(pcf_str_field_pattern(field)));
    }
    if ((mode & (PCF_HIDE_NAME | PCF_HIDE_VALUE)) == 0) {
 ADD_TEXT(" = "3);
    }
    if ((mode & PCF_HIDE_VALUE) == 0) {
 if (line_len > 0 && line_len + strlen(argv[field]) > PCF_LINE_LIMIT) {
     vstream_fputs("\n" PCF_INDENT_TEXT, fp);
     line_len = PCF_INDENT_LEN;
 }
 ADD_TEXT(argv[field], strlen(argv[field]));
    }

    /*
     * Format the daemon command-line options and non-option arguments. Here,
     * we have no data-dependent preference for column positions, but we do
     * have argument grouping preferences.
     */

    if (field == PCF_MASTER_FLD_CMD && (mode & PCF_HIDE_VALUE) == 0) {
 in_daemon_options = 1;
 for (field += 1; (arg = argv[field]) != 0; field++) {
     arg_len = strlen(arg);
     aval = 0;
     need_parens = 0;
     if (in_daemon_options) {

  /*
   * We make no special case for generic options (-v -D)
   * options.
 */

  if (arg[0] != '-' || strcmp(arg, "--") == 0) {
      in_daemon_options = 0;
  } else if (strchr(pcf_daemon_options_expecting_value, arg[1]) != 0
      && (aval = argv[field + 1]) != 0) {

      /* Force line break before option with value. */
      line_len = PCF_LINE_LIMIT;

      /*
       * Optionally, expand $name in parameter value.
     */

      if (strcmp(arg, "-o") == 0
   && (mode & PCF_SHOW_EVAL) != 0)
   aval = pcf_expand_parameter_value(pcf_exp_buf, mode,
         aval, masterp);

      /*
       * Keep option and value on the same line.
     */

      arg_len += strlen(aval) + 1;
      if ((need_parens = aval[strcspn(aval, PCF_MASTER_BLANKS)]) != 0)
   arg_len += 2;
  }
     } else {
  need_parens = arg[strcspn(arg, PCF_MASTER_BLANKS)];
     }

     /*
      * Insert a line break when the next item won't fit.
     */

     if (line_len > PCF_INDENT_LEN) {
  if ((mode & PCF_FOLD_LINE) == 0
      || line_len + 1 + arg_len < PCF_LINE_LIMIT) {
      ADD_SPACE;
  } else {
      vstream_fputs("\n" PCF_INDENT_TEXT, fp);
      line_len = PCF_INDENT_LEN;
  }
     }
     if (in_daemon_options == 0 && need_parens)
  ADD_TEXT("{"1);
     ADD_TEXT(arg, strlen(arg));
     if (in_daemon_options == 0 && need_parens)
  ADD_TEXT("}"1);
     if (aval) {
  ADD_SPACE;
  if (need_parens)
      ADD_TEXT("{"1);
  ADD_TEXT(aval, strlen(aval));
  if (need_parens)
      ADD_TEXT("}"1);
  field += 1;

  /* Force line break after option with value. */
  line_len = PCF_LINE_LIMIT;
     }
 }
    }
    vstream_fputs("\n", fp);

    if (msg_verbose)
 vstream_fflush(fp);
}

/* pcf_show_master_fields - show master.cf fields */

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, 13);
     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);
    }
}

/* pcf_edit_master_field - replace master.cf field value. */

void    pcf_edit_master_field(PCF_MASTER_ENT *masterp, int field,
                 const char *new_value)
{

    /*
     * Replace multi-column attribute.
     */

    if (field == PCF_MASTER_FLD_CMD) {
 argv_truncate(masterp->argv, PCF_MASTER_FLD_CMD);
 argv_splitq_append(masterp->argv, new_value, PCF_MASTER_BLANKS, CHARS_BRACE);
 pcf_normalize_daemon_args(masterp->argv);
    }

    /*
     * Replace single-column attribute.
     */

    else {
 argv_replace_one(masterp->argv, field, new_value);
    }

    /*
     * Do per-field sanity checks.
     */

    pcf_check_master_entry(masterp->argv, new_value);
}

/* pcf_print_master_param - scaffolding */

static void pcf_print_master_param(VSTREAM *fp, int mode,
               PCF_MASTER_ENT *masterp,
               const char *param_name,
               const char *param_value)
{
    if (pcf_exp_buf == 0 && (mode & PCF_SHOW_EVAL))
 pcf_exp_buf = vstring_alloc(100);
    if (pcf_json_buf == 0 && (mode & PCF_SHOW_JSON))
 pcf_json_buf = vstring_alloc(100);

    if (mode & PCF_HIDE_VALUE) {
 pcf_print_line(fp, mode, "%s%c%s\n",
         masterp->name_space, PCF_NAMESP_SEP_CH,
         param_name);
    } else {
 if ((mode & PCF_SHOW_EVAL) != 0)
     param_value = pcf_expand_parameter_value(pcf_exp_buf, mode,
           param_value, masterp);
 if (mode & PCF_SHOW_JSON) {
     vstream_fprintf(fp, "{\"%s\": ",
         quote_for_json_var(pcf_json_buf, masterp->name_space,
       PCF_NAMESP_SEP_STR, param_name,
       (const char *) 0));
     vstream_fprintf(fp, "\"%s\"}\n",
       quote_for_json(pcf_json_buf, param_value, -1));
 } else if ((mode & PCF_HIDE_NAME) == 0) {
     pcf_print_line(fp, mode, "%s%c%s = %s\n",
      masterp->name_space, PCF_NAMESP_SEP_CH,
      param_name, param_value);
 } else {
     pcf_print_line(fp, mode, "%s\n", param_value);
 }
    }
    if (msg_verbose)
 vstream_fflush(fp);
}

/* pcf_sort_argv_cb - sort argv call-back */

static int pcf_sort_argv_cb(const void *a, const void *b)
{
    return (strcmp(*(char **) a, *(char **) b));
}

/* merge_main_master_parameters - all parameters as sen by this service */

static DICT *merge_main_master_parameters(int mode, PCF_MASTER_ENT *masterp,
               int param_class)
{
    DICT   *dict;
    PCF_PARAM_INFO **main_list;
    PCF_PARAM_INFO **main_ht;
    const char *dict_spec = "merged_dict";
    const char *param_name;
    const char *param_value;
    int     how;

    /*
     * With -PP, use the merged main/master.cf settings instead of
     * masterp->allparams (the master.cf settings for this service).
     */

    dict = dict_ht_open(dict_spec, O_CREAT | O_RDWR, 0);
    dict_register(dict_spec, dict);

    /*
     * For each parameter in the main.cf namespace, look up its effective
     * value (from master.cf or main.cf, or use the default).
     */

    main_list = PCF_PARAM_TABLE_LIST(pcf_param_table);
    for (main_ht = main_list; *main_ht; main_ht++) {
 param_name = PCF_PARAM_INFO_NAME(*main_ht);
 if (param_class && !(PCF_PARAM_INFO_NODE(*main_ht)->flags & param_class))
     continue;
 if ((param_value =
      pcf_lookup_parameter_value(mode, param_name, masterp,
     PCF_PARAM_INFO_NODE(*main_ht))) == 0)
     msg_panic("%s: parameter name not found: %s", __func__, param_name);
 dict->update(dict, param_name, param_value);
    }
    myfree((void *) main_list);

    /*
     * Add master.cf settings with service-specific custom names. Skip
     * settings that were already copied in the above loop.
     */

    if (masterp->all_params) {
 DICT   *all_params = masterp->all_params;

 for (how = DICT_SEQ_FUN_FIRST;
      all_params->sequence(all_params, how, ¶m_name,
      ¶m_value) == 0;
      how = DICT_SEQ_FUN_NEXT) {
     if (dict->lookup(dict, param_name) == 0)
  dict->update(dict, param_name, param_value);
 }
    }
    return (dict);
}

/* pcf_show_master_any_param - show any parameter in master.cf service entry */

static void pcf_show_master_any_param(VSTREAM *fp, int mode,
                  PCF_MASTER_ENT *masterp,
                  DICT *dict)
{
    const char *myname = "pcf_show_master_any_param";
    ARGV   *argv = argv_alloc(10);
    const char *param_name;
    const char *param_value;
    int     param_count = 0;
    int     how;
    char  **cpp;

    /*
     * Print parameters in sorted order. The number of parameters per
     * master.cf entry is small, so we optimize for code simplicity and don't
     * worry about the cost of double lookup.
     */


    /* Look up the parameter names and ignore the values. */

    for (how = DICT_SEQ_FUN_FIRST;
  dict->sequence(dict, how, ¶m_name, ¶m_value) == 0;
  how = DICT_SEQ_FUN_NEXT) {
 argv_add(argv, param_name, ARGV_END);
 param_count++;
    }

    /* Print the parameters in sorted order. */

    qsort(argv->argv, param_count, sizeof(argv->argv[0]), pcf_sort_argv_cb);
    for (cpp = argv->argv; (param_name = *cpp) != 0; cpp++) {
 if ((param_value = dict_get(dict, param_name)) == 0)
     msg_panic("%s: parameter name not found: %s", myname, param_name);
 pcf_print_master_param(fp, mode, masterp, param_name, param_value);
    }

    /*
     * Clean up.
     */

    argv_free(argv);
}

/* pcf_show_master_params - show master.cf params */

void    pcf_show_master_params(VSTREAM *fp, int mode, int param_class,
                  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, 13);
     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 (mode & PCF_MASTER_PP) {
     dict = merge_main_master_parameters(mode, masterp,
      argc > 0 ? 0 : param_class);
 } else {
     dict = masterp->all_params;
 }
 if (dict != 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, dict);
       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, dict);
     }
 }
 if (mode & PCF_MASTER_PP)
     dict_close(dict);
    }

    /*
     * 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);
    }
}

/* pcf_edit_master_param - update, add or remove -o parameter=value */

void    pcf_edit_master_param(PCF_MASTER_ENT *masterp, int mode,
                 const char *param_name,
                 const char *param_value)
{
    const char *myname = "pcf_edit_master_param";
    ARGV   *argv = masterp->argv;
    const char *arg;
    const char *aval;
    int     param_match = 0;
    int     name_len = strlen(param_name);
    int     field;

    for (field = PCF_MASTER_MIN_FIELDS; argv->argv[field] != 0; field++) {
 arg = argv->argv[field];

 /*
  * Stop at the first non-option argument or end-of-list.
 */

 if (arg[0] != '-' || strcmp(arg, "--") == 0) {
     break;
 }

 /*
  * Zoom in on command-line options with a value.
 */

 else if (strchr(pcf_daemon_options_expecting_value, arg[1]) != 0
   && (aval = argv->argv[field + 1]) != 0) {

     /*
      * Zoom in on "-o parameter=value".
     */

     if (strcmp(arg, "-o") == 0) {
  if (strncmp(aval, param_name, name_len) == 0
      && aval[name_len] == '=') {
      param_match = 1;
      switch (mode & (PCF_EDIT_CONF | PCF_EDIT_EXCL)) {

   /*
    * Update parameter=value.
 */

      case PCF_EDIT_CONF:
   aval = concatenate(param_name, "=",
        param_value, (char *) 0);
   argv_replace_one(argv, field + 1, aval);
   myfree((void *) aval);
   if (masterp->all_params)
       dict_put(masterp->all_params, param_name, param_value);
   /* XXX Update parameter "used/defined" status. */
   break;

   /*
    * Delete parameter=value.
 */

      case PCF_EDIT_EXCL:
   argv_delete(argv, field, 2);
   if (masterp->all_params)
       dict_del(masterp->all_params, param_name);
   /* XXX Update parameter "used/defined" status. */
   field -= 2;
   break;
      default:
   msg_panic("%s: unexpected mode: %d", myname, mode);
      }
  }
     }

     /*
      * Skip over the command-line option value.
     */

     field += 1;
 }
    }

    /*
     * Add unmatched parameter.
     */

    if ((mode & PCF_EDIT_CONF) && param_match == 0) {
 /* XXX Generalize: argv_insert(argv, where, list...) */
 argv_insert_one(argv, field, "-o");
 aval = concatenate(param_name, "=",
      param_value, (char *) 0);
 argv_insert_one(argv, field + 1, aval);
 if (masterp->all_params)
     dict_put(masterp->all_params, param_name, param_value);
 /* XXX May affect parameter "used/defined" status. */
 myfree((void *) aval);
 param_match = 1;
    }
}

Messung V0.5 in Prozent
C=82 H=84 G=82

¤ Dauer der Verarbeitung: 0.52 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.