Cleanup: in the PostgreSQL client, cosmetic changes to make
the code easier to maintain (in preparation for adding new
functionality). File: global/dict_pgsql.c.
+
+20230428
+
+ Bugfix (defect introduced: Postfix 1.0): the command 'postconf
+ .. name=v1 .. name=v2 ..' (multiple instances of the same
+ parameter name) created multiple name=value entries with
+ the same parameter name. It now logs a warning and skips
+ the earlier update. Found during code maintenance. File:
+ postconf/postconf_edit.c
+
+ Bugfix (defect introduced: Postfix 3.3): the command 'postconf
+ -M name1/type1='name2 type2 ..." died with a segmentation
+ violation when the request matched multiple master.cf
+ entries. The master.cf file was not damaged. Problem reported
+ by SATOH Fumiyasu. File: postconf/postconf_master.c.
+
+20230502
+
+ Bugfix (defect introduced: Postfix 2.11): the command
+ 'postconf -M name1/type1="name2 type2 ...'" could add a
+ service definition to master.cf that conflicted with an
+ already existing service definition. It now replaces all
+ existing service definitions that match the service pattern
+ 'name1/type1' or the service name and type in 'name2 type2
+ ...' with a single service definition 'name2 type2 ...'.
+ Problem reported by SATOH Fumiyasu. File: postconf/postconf_edit.c.
Florian
Piekert
refactored
+Fumiyasu
+SATOH
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20230419"
+#define MAIL_RELEASE_DATE "20230502"
#define MAIL_VERSION_NUMBER "3.9"
#ifdef SNAPSHOT
test31 test32 test33 test34 test35 test36 test37 test39 test40 test41 \
test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \
test52 test53 test54 test55 test56 test57 test58 test59 test60 test61 \
- test62 test63 test64 test65 test66 test67 test68 test69 test70 test71
+ test62 test63 test64 test65 test66 test67 test68 test69 test70 test71 \
+ test72 test73 test74 test75
root_tests:
diff test71.ref test71.tmp
rm -f main.cf master.cf test71.tmp
+# Different requests to add lines to master.cf.
+test72: $(PROG) test72.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ ./postconf -Mc. smtp/unix='smtp unix - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp fifo - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp inet - n n - 0 other'
+ touch -t 197201010000 main.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -Mc. >test72.tmp 2>&1
+ diff test72.ref test72.tmp
+ rm -f main.cf master.cf test72.tmp
+
+# Replace one entry based on the name+type in the request's service entry.
+test73: $(PROG) test73.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ ./postconf -Mc. smtp/unix='smtp unix - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp fifo - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp inet - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp unix - n n - 0 otherx'
+ touch -t 197301010000 main.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -Mc. >test73.tmp 2>&1
+ diff test73.ref test73.tmp
+ rm -f main.cf master.cf test73.tmp
+
+# Replace one entry based on the name+type in the request's service pattern.
+test74: $(PROG) test74.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ ./postconf -Mc. smtp/unix='smtp unix - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp fifo - n n - 0 other'
+ ./postconf -Mc. smtp/abcd='smtp inet - n n - 0 other'
+ ./postconf -Mc. smtp/fifo='lmtp unix - n n - 0 otherx'
+ touch -t 197401010000 main.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -Mc. >test74.tmp 2>&1
+ diff test74.ref test74.tmp
+ rm -f main.cf master.cf test74.tmp
+
+# Warn about skipping redundant name=value update.
+test75: $(PROG) test75.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ ./postconf -c. mail_version=x mail_version=y >test75.tmp 2>&1
+ touch -t 197501010000 main.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -nc. >>test75.tmp 2>&1
+ diff test75.ref test75.tmp
+ rm -f main.cf master.cf test75.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
postconf_master.o: ../../include/argv.h
postconf_master.o: ../../include/check_arg.h
postconf_master.o: ../../include/dict.h
+postconf_master.o: ../../include/dict_ht.h
postconf_master.o: ../../include/htable.h
postconf_master.o: ../../include/mail_params.h
postconf_master.o: ../../include/master_proto.h
} else {
msg_panic("pcf_edit_main: unknown mode %d", mode);
}
+ if ((cvalue = htable_find(table, pattern)) != 0) {
+ msg_warn("ignoring earlier request: '%s = %s'",
+ pattern, cvalue->value);
+ htable_delete(table, pattern, myfree);
+ }
cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
cvalue->value = edit_value;
cvalue->found = 0;
/*
* Match each service pattern.
+ *
+ * Additional care is needed when a request adds or replaces an
+ * entire service definition, instead of a specific field or
+ * parameter. Given a command "postconf -M name1/type1='name2
+ * type2 ...'", where name1 and name2 may differ, and likewise
+ * for type1 and type2:
+ *
+ * - First, if an existing service definition a) matches the service
+ * pattern 'name1/type1', or b) matches the name and type in the
+ * new service definition 'name2 type2 ...', remove the service
+ * definition.
+ *
+ * - Then, after an a) or b) type match, add a new service
+ * definition for 'name2 type2 ...', but only after the first
+ * match.
+ *
+ * - Finally, if a request had no a) or b) type match for any
+ * master.cf service definition, add a new service definition for
+ * 'name2 type2 ...'.
*/
for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
+ PCF_MASTER_ENT *tentative_entry = 0;
+ int use_tentative_entry = 0;
+
+ /* Additional care for whole service definition requests. */
+ if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
+ tentative_entry = (PCF_MASTER_ENT *)
+ mymalloc(sizeof(*tentative_entry));
+ if ((err = pcf_parse_master_entry(tentative_entry,
+ req->edit_value)) != 0)
+ msg_fatal("%s: \"%s\"", err, req->raw_text);
+ }
if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
service_name,
service_type)) {
* 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);
+ if (req->match_count == 1)
+ use_tentative_entry = 1;
break;
default:
msg_panic("%s: unknown edit mode %d", myname, mode);
}
}
+ } else if (tentative_entry != 0
+ && PCF_MATCH_SERVICE_PATTERN(tentative_entry->argv,
+ service_name,
+ service_type)) {
+ service_name_type_matched = 1; /* Sticky flag */
+ req->match_count += 1;
+ if (req->match_count == 1)
+ use_tentative_entry = 1;
+ }
+ if (tentative_entry != 0) {
+ if (use_tentative_entry) {
+ if (new_entry != 0)
+ pcf_free_master_entry(new_entry);
+ new_entry = tentative_entry;
+ } else {
+ pcf_free_master_entry(tentative_entry);
+ }
}
}
#include <readlline.h>
#include <stringops.h>
#include <split_at.h>
+#include <dict_ht.h>
/* Global library. */
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_update(ro_name_space, VAR_PROCNAME, process_name);
- dict_update(ro_name_space, VAR_SERVNAME,
- strcmp(process_name, argv->argv[0]) != 0 ?
- argv->argv[0] : process_name);
- masterp->ro_params = dict_handle(ro_name_space);
+ 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);
--- /dev/null
+smtp unix - n n - 0 other
+smtp fifo - n n - 0 other
+smtp inet - n n - 0 other
--- /dev/null
+smtp unix - n n - 0 otherx
+smtp fifo - n n - 0 other
+smtp inet - n n - 0 other
--- /dev/null
+smtp unix - n n - 0 other
+lmtp unix - n n - 0 otherx
+smtp inet - n n - 0 other
--- /dev/null
+./postconf: warning: ignoring earlier request: 'mail_version = x'
+config_directory = .
+mail_version = y