~ubuntu-branches/debian/sid/postfix/sid

« back to all changes in this revision

Viewing changes to src/postconf/postconf_edit.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones, LaMont Jones, localization folks
  • Date: 2014-02-11 07:44:30 UTC
  • mfrom: (1.1.41)
  • Revision ID: package-import@ubuntu.com-20140211074430-91tdwgjriazawdz4
Tags: 2.11.0-1
[LaMont Jones]

* New upstream release: 2.11.0

[localization folks]

* l10n: Updated German translations.  Closes: #734893 (Helge Kreutzmann)

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/* NAME
3
3
/*      postconf_edit 3
4
4
/* SUMMARY
5
 
/*      edit main.cf
 
5
/*      edit main.cf or master.cf
6
6
/* SYNOPSIS
7
7
/*      #include <postconf.h>
8
8
/*
9
 
/*      void    edit_parameters(mode, argc, argv)
 
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)
10
15
/*      int     mode;
11
16
/*      int     argc;
12
17
/*      char    **argv;
13
18
/* DESCRIPTION
14
 
/*      Edit the \fBmain.cf\fR configuration file, and update
15
 
/*      parameter settings with the "\fIname\fR=\fIvalue\fR" pairs
16
 
/*      given on the command line. The file is copied to a temporary
17
 
/*      file then renamed into place.
 
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".
18
48
/* DIAGNOSTICS
19
49
/*      Problems are reported to the standard error stream.
20
50
/* FILES
21
51
/*      /etc/postfix/main.cf, Postfix configuration parameters
22
52
/*      /etc/postfix/main.cf.tmp, temporary name
 
53
/*      /etc/postfix/master.cf, Postfix configuration parameters
 
54
/*      /etc/postfix/master.cf.tmp, temporary name
23
55
/* LICENSE
24
56
/* .ad
25
57
/* .fi
47
79
#include <edit_file.h>
48
80
#include <readlline.h>
49
81
#include <stringops.h>
 
82
#include <split_at.h>
50
83
 
51
84
/* Global library. */
52
85
 
58
91
 
59
92
#define STR(x) vstring_str(x)
60
93
 
61
 
/* edit_parameters - edit parameter file */
62
 
 
63
 
void    edit_parameters(int mode, int argc, char **argv)
 
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)
64
149
{
65
150
    char   *path;
66
151
    EDIT_FILE *ep;
69
154
    VSTRING *buf = vstring_alloc(100);
70
155
    VSTRING *key = vstring_alloc(10);
71
156
    char   *cp;
72
 
    char   *edit_key;
73
 
    char   *edit_val;
 
157
    char   *pattern;
 
158
    char   *edit_value;
74
159
    HTABLE *table;
75
160
    struct cvalue {
76
161
        char   *value;
93
178
            cp++;
94
179
        if (*cp == '#')
95
180
            msg_fatal("-e, -X, or -# accepts no comment input");
96
 
        if (mode & EDIT_MAIN) {
97
 
            if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0)
 
181
        if (mode & PCF_EDIT_CONF) {
 
182
            if ((err = split_nameval(cp, &pattern, &edit_value)) != 0)
98
183
                msg_fatal("%s: \"%s\"", err, cp);
99
 
        } else if (mode & (COMMENT_OUT | EDIT_EXCL)) {
 
184
        } else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
100
185
            if (*cp == 0)
101
186
                msg_fatal("-X or -# requires non-blank parameter names");
102
187
            if (strchr(cp, '=') != 0)
103
 
                msg_fatal("-X or -# requires parameter names only");
104
 
            edit_key = cp;
105
 
            trimblanks(edit_key, 0);
106
 
            edit_val = 0;
 
188
                msg_fatal("-X or -# requires parameter names without value");
 
189
            pattern = cp;
 
190
            trimblanks(pattern, 0);
 
191
            edit_value = 0;
107
192
        } else {
108
 
            msg_panic("edit_parameters: unknown mode %d", mode);
 
193
            msg_panic("pcf_edit_main: unknown mode %d", mode);
109
194
        }
110
195
        cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
111
 
        cvalue->value = edit_val;
 
196
        cvalue->value = edit_value;
112
197
        cvalue->found = 0;
113
 
        htable_enter(table, edit_key, (char *) cvalue);
 
198
        htable_enter(table, pattern, (char *) cvalue);
114
199
    }
115
200
 
116
201
    /*
117
202
     * Open a temp file for the result. This uses a deterministic name so we
118
203
     * don't leave behind thrash with random names.
119
204
     */
120
 
    set_config_dir();
 
205
    pcf_set_config_dir();
121
206
    path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
122
207
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
123
208
        msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
139
224
#define STR(x) vstring_str(x)
140
225
 
141
226
    interesting = 0;
142
 
    while (vstring_get(buf, src) != VSTREAM_EOF) {
143
 
        for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
144
 
             /* void */ ;
145
 
        /* Copy comment, all-whitespace, or empty line. */
146
 
        if (*cp == '#' || *cp == 0) {
147
 
            vstream_fputs(STR(buf), dst);
148
 
        }
 
227
    while ((cp = pcf_next_cf_line(buf, src, dst, (int *) 0)) != 0) {
149
228
        /* Copy, skip or replace continued text. */
150
 
        else if (cp > STR(buf)) {
 
229
        if (cp > STR(buf)) {
151
230
            if (interesting == 0)
152
231
                vstream_fputs(STR(buf), dst);
153
 
            else if (mode & COMMENT_OUT)
 
232
            else if (mode & PCF_COMMENT_OUT)
154
233
                vstream_fprintf(dst, "#%s", STR(buf));
155
234
        }
156
235
        /* Copy or replace start of logical line. */
160
239
            if ((interesting = !!cvalue) != 0) {
161
240
                if (cvalue->found++ == 1)
162
241
                    msg_warn("%s: multiple entries for \"%s\"", path, STR(key));
163
 
                if (mode & EDIT_MAIN)
 
242
                if (mode & PCF_EDIT_CONF)
164
243
                    vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
165
 
                else if (mode & COMMENT_OUT)
 
244
                else if (mode & PCF_COMMENT_OUT)
166
245
                    vstream_fprintf(dst, "#%s", cp);
167
246
            } else {
168
247
                vstream_fputs(STR(buf), dst);
173
252
    /*
174
253
     * Generate new entries for parameters that were not found.
175
254
     */
176
 
    if (mode & EDIT_MAIN) {
 
255
    if (mode & PCF_EDIT_CONF) {
177
256
        for (ht_info = ht = htable_list(table); *ht; ht++) {
178
257
            cvalue = (struct cvalue *) ht[0]->value;
179
258
            if (cvalue->found == 0)
198
277
    vstring_free(key);
199
278
    htable_free(table, myfree);
200
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 */
 
292
} PCF_MASTER_EDIT_REQ;
 
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 ((mode & PCF_MASTER_PARAM)
 
344
            && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
 
345
                msg_fatal("whitespace in parameter value: \"%s\"",
 
346
                          req->raw_text);
 
347
        } else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
 
348
            if (strchr(cp, '=') != 0)
 
349
                msg_fatal("-X or -# requires names without value");
 
350
            pattern = cp;
 
351
            trimblanks(pattern, 0);
 
352
            req->edit_value = 0;
 
353
        } else {
 
354
            msg_panic("%s: unknown mode %d", myname, mode);
 
355
        }
 
356
 
 
357
#define PCF_MASTER_MASK (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)
 
358
 
 
359
        /*
 
360
         * Split name/type or name/type/whatever pattern into components.
 
361
         */
 
362
        switch (mode & PCF_MASTER_MASK) {
 
363
        case PCF_MASTER_ENTRY:
 
364
            if ((req->service_pattern =
 
365
                 pcf_parse_service_pattern(pattern, 2, 2)) == 0)
 
366
                msg_fatal("-Me, -MX or -M# requires service_name/type");
 
367
            break;
 
368
        case PCF_MASTER_FLD:
 
369
            if ((req->service_pattern =
 
370
                 pcf_parse_service_pattern(pattern, 3, 3)) == 0)
 
371
                msg_fatal("-Fe or -FX requires service_name/type/field_name");
 
372
            req->field_number =
 
373
                pcf_parse_field_pattern(req->service_pattern->argv[2]);
 
374
            if (pcf_is_magic_field_pattern(req->field_number))
 
375
                msg_fatal("-Fe does not accept wild-card field name");
 
376
            if ((mode & PCF_EDIT_CONF)
 
377
                && req->field_number < PCF_MASTER_FLD_CMD
 
378
            && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
 
379
                msg_fatal("-Fe does not accept whitespace in non-command field");
 
380
            break;
 
381
        case PCF_MASTER_PARAM:
 
382
            if ((req->service_pattern =
 
383
                 pcf_parse_service_pattern(pattern, 3, 3)) == 0)
 
384
                msg_fatal("-Pe or -PX requires service_name/type/parameter");
 
385
            req->param_pattern = req->service_pattern->argv[2];
 
386
            if (PCF_IS_MAGIC_PARAM_PATTERN(req->param_pattern))
 
387
                msg_fatal("-Pe does not accept wild-card parameter name");
 
388
            if ((mode & PCF_EDIT_CONF)
 
389
            && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
 
390
                msg_fatal("-Pe does not accept whitespace in parameter value");
 
391
            break;
 
392
        default:
 
393
            msg_panic("%s: unknown edit mode %d", myname, mode);
 
394
        }
 
395
    }
 
396
 
 
397
    /*
 
398
     * Open a temp file for the result. This uses a deterministic name so we
 
399
     * don't leave behind thrash with random names.
 
400
     */
 
401
    pcf_set_config_dir();
 
402
    path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
 
403
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
 
404
        msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
 
405
    dst = ep->tmp_fp;
 
406
 
 
407
    /*
 
408
     * Open the original file for input.
 
409
     */
 
410
    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
 
411
        /* OK to delete, since we control the temp file name exclusively. */
 
412
        (void) unlink(ep->tmp_path);
 
413
        msg_fatal("open %s for reading: %m", path);
 
414
    }
 
415
 
 
416
    /*
 
417
     * Copy original file to temp file, while replacing service entries on
 
418
     * the fly.
 
419
     */
 
420
    service_name_type_matched = 0;
 
421
    new_entry = 0;
 
422
    lineno = 0;
 
423
    while ((cp = pcf_next_cf_line(parse_buf, src, dst, &lineno)) != 0) {
 
424
        vstring_strcpy(line_buf, STR(parse_buf));
 
425
 
 
426
        /*
 
427
         * Copy, skip or replace continued text.
 
428
         */
 
429
        if (cp > STR(parse_buf)) {
 
430
            if (service_name_type_matched == 0)
 
431
                vstream_fputs(STR(line_buf), dst);
 
432
            else if (mode & PCF_COMMENT_OUT)
 
433
                vstream_fprintf(dst, "#%s", STR(line_buf));
 
434
        }
 
435
 
 
436
        /*
 
437
         * Copy or replace (start of) logical line.
 
438
         */
 
439
        else {
 
440
            service_name_type_matched = 0;
 
441
 
 
442
            /*
 
443
             * Parse out the service name and type.
 
444
             */
 
445
            if ((service_name = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0
 
446
                || (service_type = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0)
 
447
                msg_fatal("file %s: line %d: specify service name and type "
 
448
                          "on the same line", path, lineno);
 
449
            if (strchr(service_name, '='))
 
450
                msg_fatal("file %s: line %d: service name syntax \"%s\" is "
 
451
                          "unsupported with %s", path, lineno, service_name,
 
452
                          edit_opts);
 
453
            if (service_type[strcspn(service_type, "=/")] != 0)
 
454
                msg_fatal("file %s: line %d: "
 
455
                        "service type syntax \"%s\" is unsupported with %s",
 
456
                          path, lineno, service_type, edit_opts);
 
457
 
 
458
            /*
 
459
             * Match each service pattern.
 
460
             */
 
461
            for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
 
462
                if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
 
463
                                              service_name,
 
464
                                              service_type)) {
 
465
                    service_name_type_matched = 1;      /* Sticky flag */
 
466
                    req->match_count += 1;
 
467
 
 
468
                    /*
 
469
                     * Generate replacement master.cf entries.
 
470
                     */
 
471
                    if ((mode & PCF_EDIT_CONF)
 
472
                        || ((mode & PCF_MASTER_PARAM) && (mode & PCF_EDIT_EXCL))) {
 
473
                        switch (mode & PCF_MASTER_MASK) {
 
474
 
 
475
                            /*
 
476
                             * Replace master.cf entry field or parameter
 
477
                             * value.
 
478
                             */
 
479
                        case PCF_MASTER_FLD:
 
480
                        case PCF_MASTER_PARAM:
 
481
                            if (new_entry == 0) {
 
482
                                /* Gobble up any continuation lines. */
 
483
                                pcf_gobble_cf_line(full_entry_buf, line_buf,
 
484
                                                   src, dst, &lineno);
 
485
                                new_entry = (PCF_MASTER_ENT *)
 
486
                                    mymalloc(sizeof(*new_entry));
 
487
                                if ((err = pcf_parse_master_entry(new_entry,
 
488
                                                 STR(full_entry_buf))) != 0)
 
489
                                    msg_fatal("file %s: line %d: %s",
 
490
                                              path, lineno, err);
 
491
                            }
 
492
                            if (mode & PCF_MASTER_FLD) {
 
493
                                pcf_edit_master_field(new_entry,
 
494
                                                      req->field_number,
 
495
                                                      req->edit_value);
 
496
                            } else {
 
497
                                pcf_edit_master_param(new_entry, mode,
 
498
                                                      req->param_pattern,
 
499
                                                      req->edit_value);
 
500
                            }
 
501
                            break;
 
502
 
 
503
                            /*
 
504
                             * Replace entire master.cf entry.
 
505
                             */
 
506
                        case PCF_MASTER_ENTRY:
 
507
                            if (new_entry != 0)
 
508
                                pcf_free_master_entry(new_entry);
 
509
                            new_entry = (PCF_MASTER_ENT *)
 
510
                                mymalloc(sizeof(*new_entry));
 
511
                            if ((err = pcf_parse_master_entry(new_entry,
 
512
                                                     req->edit_value)) != 0)
 
513
                                msg_fatal("%s: \"%s\"", err, req->raw_text);
 
514
                            break;
 
515
                        default:
 
516
                            msg_panic("%s: unknown edit mode %d", myname, mode);
 
517
                        }
 
518
                    }
 
519
                }
 
520
            }
 
521
 
 
522
            /*
 
523
             * Pass through or replace the current input line.
 
524
             */
 
525
            if (new_entry) {
 
526
                pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
 
527
                pcf_free_master_entry(new_entry);
 
528
                new_entry = 0;
 
529
            } else if (service_name_type_matched == 0) {
 
530
                vstream_fputs(STR(line_buf), dst);
 
531
            } else if (mode & PCF_COMMENT_OUT) {
 
532
                vstream_fprintf(dst, "#%s", STR(line_buf));
 
533
            }
 
534
        }
 
535
    }
 
536
 
 
537
    /*
 
538
     * Postprocessing: when editing entire service entries, generate new
 
539
     * entries for services not found. Otherwise (editing fields or
 
540
     * parameters), "service not found" is a fatal error.
 
541
     */
 
542
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
 
543
        if (req->match_count == 0) {
 
544
            if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
 
545
                new_entry = (PCF_MASTER_ENT *) mymalloc(sizeof(*new_entry));
 
546
                if ((err = pcf_parse_master_entry(new_entry, req->edit_value)) != 0)
 
547
                    msg_fatal("%s: \"%s\"", err, req->raw_text);
 
548
                pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
 
549
                pcf_free_master_entry(new_entry);
 
550
            } else if ((mode & PCF_MASTER_ENTRY) == 0) {
 
551
                msg_warn("unmatched service_name/type: \"%s\"", req->raw_text);
 
552
            }
 
553
        }
 
554
    }
 
555
 
 
556
    /*
 
557
     * When all is well, rename the temp file to the original one.
 
558
     */
 
559
    if (vstream_fclose(src))
 
560
        msg_fatal("read %s: %m", path);
 
561
    if (edit_file_close(ep) != 0)
 
562
        msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);
 
563
 
 
564
    /*
 
565
     * Cleanup.
 
566
     */
 
567
    myfree(path);
 
568
    vstring_free(line_buf);
 
569
    vstring_free(parse_buf);
 
570
    vstring_free(full_entry_buf);
 
571
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
 
572
        argv_free(req->service_pattern);
 
573
        myfree(req->parsed_text);
 
574
    }
 
575
    myfree((char *) edit_reqs);
 
576
}