Postfix3.3.1
postconf_edit.c
[詳解]
1 /*++
2 /* NAME
3 /* postconf_edit 3
4 /* SUMMARY
5 /* edit main.cf or master.cf
6 /* SYNOPSIS
7 /* #include <postconf.h>
8 /*
9 /* void pcf_edit_main(mode, argc, argv)
10 /* int mode;
11 /* int argc;
12 /* char **argv;
13 /*
14 /* void pcf_edit_master(mode, argc, argv)
15 /* int mode;
16 /* int argc;
17 /* char **argv;
18 /* DESCRIPTION
19 /* pcf_edit_main() edits the \fBmain.cf\fR configuration file.
20 /* It replaces or adds parameter settings given as "\fIname=value\fR"
21 /* pairs given on the command line, or removes parameter
22 /* settings given as "\fIname\fR" on the command line. The
23 /* file is copied to a temporary file then renamed into place.
24 /*
25 /* pcf_edit_master() edits the \fBmaster.cf\fR configuration
26 /* file. The file is copied to a temporary file then renamed
27 /* into place. Depending on the flags in \fBmode\fR:
28 /* .IP PCF_MASTER_ENTRY
29 /* With PCF_EDIT_CONF, pcf_edit_master() replaces or adds
30 /* entire master.cf entries, specified on the command line as
31 /* "\fIname/type = name type private unprivileged chroot wakeup
32 /* process_limit command...\fR".
33 /*
34 /* With PCF_EDIT_EXCL or PCF_COMMENT_OUT, pcf_edit_master()
35 /* removes or comments out entries specified on the command
36 /* line as "\fIname/type\fR.
37 /* .IP PCF_MASTER_FLD
38 /* With PCF_EDIT_CONF, pcf_edit_master() replaces the value
39 /* of specific service attributes, specified on the command
40 /* line as "\fIname/type/attribute = value\fR".
41 /* .IP PCF_MASTER_PARAM
42 /* With PCF_EDIT_CONF, pcf_edit_master() replaces or adds the
43 /* value of service parameters, specified on the command line
44 /* as "\fIname/type/parameter = value\fR".
45 /*
46 /* With PCF_EDIT_EXCL, pcf_edit_master() removes service
47 /* parameters specified on the command line as "\fIparametername\fR".
48 /* DIAGNOSTICS
49 /* Problems are reported to the standard error stream.
50 /* FILES
51 /* /etc/postfix/main.cf, Postfix configuration parameters
52 /* /etc/postfix/main.cf.tmp, temporary name
53 /* /etc/postfix/master.cf, Postfix configuration parameters
54 /* /etc/postfix/master.cf.tmp, temporary name
55 /* LICENSE
56 /* .ad
57 /* .fi
58 /* The Secure Mailer license must be distributed with this software.
59 /* AUTHOR(S)
60 /* Wietse Venema
61 /* IBM T.J. Watson Research
62 /* P.O. Box 704
63 /* Yorktown Heights, NY 10598, USA
64 /*--*/
65 
66 /* System library. */
67 
68 #include <sys_defs.h>
69 #include <string.h>
70 #include <ctype.h>
71 
72 /* Utility library. */
73 
74 #include <msg.h>
75 #include <mymalloc.h>
76 #include <htable.h>
77 #include <vstring.h>
78 #include <vstring_vstream.h>
79 #include <edit_file.h>
80 #include <readlline.h>
81 #include <stringops.h>
82 #include <split_at.h>
83 
84 /* Global library. */
85 
86 #include <mail_params.h>
87 
88 /* Application-specific. */
89 
90 #include <postconf.h>
91 
92 #define STR(x) vstring_str(x)
93 
94 /* pcf_find_cf_info - pass-through non-content line, return content or null */
95 
96 static char *pcf_find_cf_info(VSTRING *buf, VSTREAM *dst)
97 {
98  char *cp;
99 
100  for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
101  /* void */ ;
102  /* Pass-through comment, all-whitespace, or empty line. */
103  if (*cp == '#' || *cp == 0) {
104  vstream_fputs(STR(buf), dst);
105  return (0);
106  } else {
107  return (cp);
108  }
109 }
110 
111 /* pcf_next_cf_line - return next content line, pass non-content */
112 
113 static char *pcf_next_cf_line(VSTRING *buf, VSTREAM *src, VSTREAM *dst, int *lineno)
114 {
115  char *cp;
116 
117  while (vstring_get(buf, src) != VSTREAM_EOF) {
118  if (lineno)
119  *lineno += 1;
120  if ((cp = pcf_find_cf_info(buf, dst)) != 0)
121  return (cp);
122  }
123  return (0);
124 }
125 
126 /* pcf_gobble_cf_line - accumulate multi-line content, pass non-content */
127 
128 static void pcf_gobble_cf_line(VSTRING *full_entry_buf, VSTRING *line_buf,
129  VSTREAM *src, VSTREAM *dst, int *lineno)
130 {
131  int ch;
132 
133  vstring_strcpy(full_entry_buf, STR(line_buf));
134  for (;;) {
135  if ((ch = VSTREAM_GETC(src)) != VSTREAM_EOF)
136  vstream_ungetc(src, ch);
137  if ((ch != '#' && !ISSPACE(ch))
138  || vstring_get(line_buf, src) == VSTREAM_EOF)
139  break;
140  lineno += 1;
141  if (pcf_find_cf_info(line_buf, dst))
142  vstring_strcat(full_entry_buf, STR(line_buf));
143  }
144 }
145 
146 /* pcf_edit_main - edit main.cf file */
147 
148 void pcf_edit_main(int mode, int argc, char **argv)
149 {
150  char *path;
151  EDIT_FILE *ep;
152  VSTREAM *src;
153  VSTREAM *dst;
154  VSTRING *buf = vstring_alloc(100);
155  VSTRING *key = vstring_alloc(10);
156  char *cp;
157  char *pattern;
158  char *edit_value;
159  HTABLE *table;
160  struct cvalue {
161  char *value;
162  int found;
163  };
164  struct cvalue *cvalue;
165  HTABLE_INFO **ht_info;
166  HTABLE_INFO **ht;
167  int interesting;
168  const char *err;
169 
170  /*
171  * Store command-line parameters for quick lookup.
172  */
173  table = htable_create(argc);
174  while ((cp = *argv++) != 0) {
175  if (strchr(cp, '\n') != 0)
176  msg_fatal("-e, -X, or -# accepts no multi-line input");
177  while (ISSPACE(*cp))
178  cp++;
179  if (*cp == '#')
180  msg_fatal("-e, -X, or -# accepts no comment input");
181  if (mode & PCF_EDIT_CONF) {
182  if ((err = split_nameval(cp, &pattern, &edit_value)) != 0)
183  msg_fatal("%s: \"%s\"", err, cp);
184  } else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
185  if (*cp == 0)
186  msg_fatal("-X or -# requires non-blank parameter names");
187  if (strchr(cp, '=') != 0)
188  msg_fatal("-X or -# requires parameter names without value");
189  pattern = cp;
190  trimblanks(pattern, 0);
191  edit_value = 0;
192  } else {
193  msg_panic("pcf_edit_main: unknown mode %d", mode);
194  }
195  cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
196  cvalue->value = edit_value;
197  cvalue->found = 0;
198  htable_enter(table, pattern, (void *) cvalue);
199  }
200 
201  /*
202  * Open a temp file for the result. This uses a deterministic name so we
203  * don't leave behind thrash with random names.
204  */
206  path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
207  if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
208  msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
209  dst = ep->tmp_fp;
210 
211  /*
212  * Open the original file for input.
213  */
214  if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
215  /* OK to delete, since we control the temp file name exclusively. */
216  (void) unlink(ep->tmp_path);
217  msg_fatal("open %s for reading: %m", path);
218  }
219 
220  /*
221  * Copy original file to temp file, while replacing parameters on the
222  * fly. Issue warnings for names found multiple times.
223  */
224 #define STR(x) vstring_str(x)
225 
226  interesting = 0;
227  while ((cp = pcf_next_cf_line(buf, src, dst, (int *) 0)) != 0) {
228  /* Copy, skip or replace continued text. */
229  if (cp > STR(buf)) {
230  if (interesting == 0)
231  vstream_fputs(STR(buf), dst);
232  else if (mode & PCF_COMMENT_OUT)
233  vstream_fprintf(dst, "#%s", STR(buf));
234  }
235  /* Copy or replace start of logical line. */
236  else {
237  vstring_strncpy(key, cp, strcspn(cp, CHARS_SPACE "="));
238  cvalue = (struct cvalue *) htable_find(table, STR(key));
239  if ((interesting = !!cvalue) != 0) {
240  if (cvalue->found++ == 1)
241  msg_warn("%s: multiple entries for \"%s\"", path, STR(key));
242  if (mode & PCF_EDIT_CONF)
243  vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
244  else if (mode & PCF_COMMENT_OUT)
245  vstream_fprintf(dst, "#%s", cp);
246  } else {
247  vstream_fputs(STR(buf), dst);
248  }
249  }
250  }
251 
252  /*
253  * Generate new entries for parameters that were not found.
254  */
255  if (mode & PCF_EDIT_CONF) {
256  for (ht_info = ht = htable_list(table); *ht; ht++) {
257  cvalue = (struct cvalue *) ht[0]->value;
258  if (cvalue->found == 0)
259  vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
260  }
261  myfree((void *) ht_info);
262  }
263 
264  /*
265  * When all is well, rename the temp file to the original one.
266  */
267  if (vstream_fclose(src))
268  msg_fatal("read %s: %m", path);
269  if (edit_file_close(ep) != 0)
270  msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);
271 
272  /*
273  * Cleanup.
274  */
275  myfree(path);
276  vstring_free(buf);
277  vstring_free(key);
278  htable_free(table, myfree);
279 }
280 
281  /*
282  * Data structure to hold a master.cf edit request.
283  */
284 typedef struct {
285  int match_count; /* hit count */
286  const char *raw_text; /* unparsed command-line argument */
287  char *parsed_text; /* destructive parse */
288  ARGV *service_pattern; /* service name, type, ... */
289  int field_number; /* attribute field number */
290  const char *param_pattern; /* parameter name */
291  char *edit_value; /* value substring */
293 
294 /* pcf_edit_master - edit master.cf file */
295 
296 void pcf_edit_master(int mode, int argc, char **argv)
297 {
298  const char *myname = "pcf_edit_master";
299  char *path;
300  EDIT_FILE *ep;
301  VSTREAM *src;
302  VSTREAM *dst;
303  VSTRING *line_buf = vstring_alloc(100);
304  VSTRING *parse_buf = vstring_alloc(100);
305  int lineno;
306  PCF_MASTER_ENT *new_entry;
307  VSTRING *full_entry_buf = vstring_alloc(100);
308  char *cp;
309  char *pattern;
310  int service_name_type_matched;
311  const char *err;
312  PCF_MASTER_EDIT_REQ *edit_reqs;
313  PCF_MASTER_EDIT_REQ *req;
314  int num_reqs = argc;
315  const char *edit_opts = "-Me, -Fe, -Pe, -X, or -#";
316  char *service_name;
317  char *service_type;
318 
319  /*
320  * Sanity check.
321  */
322  if (num_reqs <= 0)
323  msg_panic("%s: empty argument list", myname);
324 
325  /*
326  * Preprocessing: split pattern=value, then split the pattern components.
327  */
328  edit_reqs = (PCF_MASTER_EDIT_REQ *) mymalloc(sizeof(*edit_reqs) * num_reqs);
329  for (req = edit_reqs; *argv != 0; req++, argv++) {
330  req->match_count = 0;
331  req->raw_text = *argv;
332  cp = req->parsed_text = mystrdup(req->raw_text);
333  if (strchr(cp, '\n') != 0)
334  msg_fatal("%s accept no multi-line input", edit_opts);
335  while (ISSPACE(*cp))
336  cp++;
337  if (*cp == '#')
338  msg_fatal("%s accept no comment input", edit_opts);
339  /* Separate the pattern from the value. */
340  if (mode & PCF_EDIT_CONF) {
341  if ((err = split_nameval(cp, &pattern, &req->edit_value)) != 0)
342  msg_fatal("%s: \"%s\"", err, req->raw_text);
343 #if 0
344  if ((mode & PCF_MASTER_PARAM)
345  && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
346  msg_fatal("whitespace in parameter value: \"%s\"",
347  req->raw_text);
348 #endif
349  } else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
350  if (strchr(cp, '=') != 0)
351  msg_fatal("-X or -# requires names without value");
352  pattern = cp;
353  trimblanks(pattern, 0);
354  req->edit_value = 0;
355  } else {
356  msg_panic("%s: unknown mode %d", myname, mode);
357  }
358 
359 #define PCF_MASTER_MASK (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)
360 
361  /*
362  * Split name/type or name/type/whatever pattern into components.
363  */
364  switch (mode & PCF_MASTER_MASK) {
365  case PCF_MASTER_ENTRY:
366  if ((req->service_pattern =
367  pcf_parse_service_pattern(pattern, 2, 2)) == 0)
368  msg_fatal("-Me, -MX or -M# requires service_name/type");
369  break;
370  case PCF_MASTER_FLD:
371  if ((req->service_pattern =
372  pcf_parse_service_pattern(pattern, 3, 3)) == 0)
373  msg_fatal("-Fe or -FX requires service_name/type/field_name");
374  req->field_number =
377  msg_fatal("-Fe does not accept wild-card field name");
378  if ((mode & PCF_EDIT_CONF)
380  && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
381  msg_fatal("-Fe does not accept whitespace in non-command field");
382  break;
383  case PCF_MASTER_PARAM:
384  if ((req->service_pattern =
385  pcf_parse_service_pattern(pattern, 3, 3)) == 0)
386  msg_fatal("-Pe or -PX requires service_name/type/parameter");
387  req->param_pattern = req->service_pattern->argv[2];
389  msg_fatal("-Pe does not accept wild-card parameter name");
390  if ((mode & PCF_EDIT_CONF)
391  && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
392  msg_fatal("-Pe does not accept whitespace in parameter value");
393  break;
394  default:
395  msg_panic("%s: unknown edit mode %d", myname, mode);
396  }
397  }
398 
399  /*
400  * Open a temp file for the result. This uses a deterministic name so we
401  * don't leave behind thrash with random names.
402  */
404  path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
405  if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
406  msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
407  dst = ep->tmp_fp;
408 
409  /*
410  * Open the original file for input.
411  */
412  if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
413  /* OK to delete, since we control the temp file name exclusively. */
414  (void) unlink(ep->tmp_path);
415  msg_fatal("open %s for reading: %m", path);
416  }
417 
418  /*
419  * Copy original file to temp file, while replacing service entries on
420  * the fly.
421  */
422  service_name_type_matched = 0;
423  new_entry = 0;
424  lineno = 0;
425  while ((cp = pcf_next_cf_line(parse_buf, src, dst, &lineno)) != 0) {
426  vstring_strcpy(line_buf, STR(parse_buf));
427 
428  /*
429  * Copy, skip or replace continued text.
430  */
431  if (cp > STR(parse_buf)) {
432  if (service_name_type_matched == 0)
433  vstream_fputs(STR(line_buf), dst);
434  else if (mode & PCF_COMMENT_OUT)
435  vstream_fprintf(dst, "#%s", STR(line_buf));
436  }
437 
438  /*
439  * Copy or replace (start of) logical line.
440  */
441  else {
442  service_name_type_matched = 0;
443 
444  /*
445  * Parse out the service name and type.
446  */
447  if ((service_name = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0
448  || (service_type = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0)
449  msg_fatal("file %s: line %d: specify service name and type "
450  "on the same line", path, lineno);
451  if (strchr(service_name, '='))
452  msg_fatal("file %s: line %d: service name syntax \"%s\" is "
453  "unsupported with %s", path, lineno, service_name,
454  edit_opts);
455  if (service_type[strcspn(service_type, "=/")] != 0)
456  msg_fatal("file %s: line %d: "
457  "service type syntax \"%s\" is unsupported with %s",
458  path, lineno, service_type, edit_opts);
459 
460  /*
461  * Match each service pattern.
462  */
463  for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
465  service_name,
466  service_type)) {
467  service_name_type_matched = 1; /* Sticky flag */
468  req->match_count += 1;
469 
470  /*
471  * Generate replacement master.cf entries.
472  */
473  if ((mode & PCF_EDIT_CONF)
474  || ((mode & PCF_MASTER_PARAM) && (mode & PCF_EDIT_EXCL))) {
475  switch (mode & PCF_MASTER_MASK) {
476 
477  /*
478  * Replace master.cf entry field or parameter
479  * value.
480  */
481  case PCF_MASTER_FLD:
482  case PCF_MASTER_PARAM:
483  if (new_entry == 0) {
484  /* Gobble up any continuation lines. */
485  pcf_gobble_cf_line(full_entry_buf, line_buf,
486  src, dst, &lineno);
487  new_entry = (PCF_MASTER_ENT *)
488  mymalloc(sizeof(*new_entry));
489  if ((err = pcf_parse_master_entry(new_entry,
490  STR(full_entry_buf))) != 0)
491  msg_fatal("file %s: line %d: %s",
492  path, lineno, err);
493  }
494  if (mode & PCF_MASTER_FLD) {
495  pcf_edit_master_field(new_entry,
496  req->field_number,
497  req->edit_value);
498  } else {
499  pcf_edit_master_param(new_entry, mode,
500  req->param_pattern,
501  req->edit_value);
502  }
503  break;
504 
505  /*
506  * Replace entire master.cf entry.
507  */
508  case PCF_MASTER_ENTRY:
509  if (new_entry != 0)
510  pcf_free_master_entry(new_entry);
511  new_entry = (PCF_MASTER_ENT *)
512  mymalloc(sizeof(*new_entry));
513  if ((err = pcf_parse_master_entry(new_entry,
514  req->edit_value)) != 0)
515  msg_fatal("%s: \"%s\"", err, req->raw_text);
516  break;
517  default:
518  msg_panic("%s: unknown edit mode %d", myname, mode);
519  }
520  }
521  }
522  }
523 
524  /*
525  * Pass through or replace the current input line.
526  */
527  if (new_entry) {
528  pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
529  pcf_free_master_entry(new_entry);
530  new_entry = 0;
531  } else if (service_name_type_matched == 0) {
532  vstream_fputs(STR(line_buf), dst);
533  } else if (mode & PCF_COMMENT_OUT) {
534  vstream_fprintf(dst, "#%s", STR(line_buf));
535  }
536  }
537  }
538 
539  /*
540  * Postprocessing: when editing entire service entries, generate new
541  * entries for services not found. Otherwise (editing fields or
542  * parameters), "service not found" is a fatal error.
543  */
544  for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
545  if (req->match_count == 0) {
546  if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
547  new_entry = (PCF_MASTER_ENT *) mymalloc(sizeof(*new_entry));
548  if ((err = pcf_parse_master_entry(new_entry, req->edit_value)) != 0)
549  msg_fatal("%s: \"%s\"", err, req->raw_text);
550  pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
551  pcf_free_master_entry(new_entry);
552  } else if ((mode & PCF_MASTER_ENTRY) == 0) {
553  msg_warn("unmatched service_name/type: \"%s\"", req->raw_text);
554  }
555  }
556  }
557 
558  /*
559  * When all is well, rename the temp file to the original one.
560  */
561  if (vstream_fclose(src))
562  msg_fatal("read %s: %m", path);
563  if (edit_file_close(ep) != 0)
564  msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);
565 
566  /*
567  * Cleanup.
568  */
569  myfree(path);
570  vstring_free(line_buf);
571  vstring_free(parse_buf);
572  vstring_free(full_entry_buf);
573  for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
575  myfree(req->parsed_text);
576  }
577  myfree((void *) edit_reqs);
578 }
void htable_free(HTABLE *table, void(*free_fn)(void *))
Definition: htable.c:287
#define VSTREAM_EOF
Definition: vstream.h:110
void myfree(void *ptr)
Definition: mymalloc.c:207
char * mystrdup(const char *str)
Definition: mymalloc.c:225
void pcf_edit_master_field(PCF_MASTER_ENT *, int, const char *)
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
ARGV * pcf_parse_service_pattern(const char *, int, int)
void pcf_edit_master(int mode, int argc, char **argv)
#define VSTREAM_GETC(vp)
Definition: vstream.h:108
#define PCF_MASTER_FLD
Definition: postconf.h:40
int vstring_get(VSTRING *vp, VSTREAM *fp)
char ** argv
Definition: argv.h:20
char * var_config_dir
Definition: mail_params.c:241
#define PCF_FOLD_LINE
Definition: postconf.h:38
const char * param_pattern
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
Definition: htable.h:25
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define MAIN_CONF_FILE
Definition: mail_params.h:334
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
void pcf_print_master_entry(VSTREAM *, int, PCF_MASTER_ENT *)
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
Definition: vstream.c:1241
void pcf_free_master_entry(PCF_MASTER_ENT *)
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
#define PCF_COMMENT_OUT
Definition: postconf.h:36
HTABLE_INFO ** htable_list(HTABLE *table)
Definition: htable.c:330
#define PCF_MATCH_SERVICE_PATTERN(pat, name, type)
Definition: postconf.h:241
#define PCF_IS_MAGIC_PARAM_PATTERN(pat)
Definition: postconf.h:248
#define PCF_MASTER_MASK
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
Definition: vstream.c:1348
#define PCF_MASTER_FLD_CMD
Definition: postconf.h:146
#define vstream_ungetc(vp, ch)
Definition: vstream.h:109
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define MASTER_CONF_FILE
Definition: mail_params.h:335
void msg_warn(const char *fmt,...)
Definition: msg.c:215
const char * raw_text
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define CHARS_SPACE
Definition: sys_defs.h:1762
#define STR(x)
Definition: postconf_edit.c:92
void * htable_find(HTABLE *table, const char *key)
Definition: htable.c:227
void pcf_edit_main(int mode, int argc, char **argv)
int pcf_parse_field_pattern(const char *)
int edit_file_close(EDIT_FILE *ep)
Definition: edit_file.c:320
char * trimblanks(char *, ssize_t)
Definition: trimblanks.c:37
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
#define pcf_is_magic_field_pattern(pat)
Definition: postconf.h:245
#define PCF_MASTER_PARAM
Definition: postconf.h:46
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
void pcf_set_config_dir(void)
Definition: postconf_misc.c:48
void pcf_edit_master_param(PCF_MASTER_ENT *, int, const char *, const char *)
#define ISSPACE(c)
Definition: sys_defs.h:1753
char * tmp_path
Definition: edit_file.h:27
const char * pcf_parse_master_entry(PCF_MASTER_ENT *, const char *)
#define PCF_MASTER_ENTRY
Definition: postconf.h:37
#define PCF_EDIT_EXCL
Definition: postconf.h:39
VSTRING * vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:445
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
EDIT_FILE * edit_file_open(const char *path, int flags, mode_t mode)
Definition: edit_file.c:190
VSTREAM * tmp_fp
Definition: edit_file.h:28
#define PCF_MASTER_BLANKS
Definition: postconf.h:205
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
int vstream_fputs(const char *str, VSTREAM *stream)
Definition: vstream.c:1360
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
#define PCF_EDIT_CONF
Definition: postconf.h:31
#define EDIT_FILE_SUFFIX
Definition: edit_file.h:31