mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 06:05:37 +00:00
snapshot-19991116
This commit is contained in:
@@ -43,6 +43,9 @@ a process is attempting to do. This is as much information as you
|
||||
can get without running an interactive debugger program, as described
|
||||
in the next section.
|
||||
|
||||
See the next section on how to automatically attach a program to
|
||||
a Postfix daemon.
|
||||
|
||||
5 - Running daemon programs under an interactive debugger
|
||||
=========================================================
|
||||
|
||||
@@ -68,3 +71,48 @@ Stop and start the Postfix system.
|
||||
|
||||
Whenever the suspect daemon process is started, a debugger window
|
||||
pops up and you can watch in detail what happens.
|
||||
|
||||
6 - Unreasonable behavior
|
||||
=========================
|
||||
|
||||
Sometimes the behavior exhibit by Postfix just does not match the
|
||||
source code. Why can a program deviate from the instructions given
|
||||
by its author? There are two possibilities.
|
||||
|
||||
1 - The compiler has messed up.
|
||||
|
||||
2 - The hardware has messed up.
|
||||
|
||||
In both cases, the program being executed is not the program that
|
||||
was supposed to be executed, so anything can happen.
|
||||
|
||||
Hardware-related failures happen erratically, and they usually do
|
||||
not reproduce after power cycling and rebooting the system. There's
|
||||
little I can do about bad hardware. Be sure to use hardware that
|
||||
at the very least can detect memory errors. Otherwise, Postfix will
|
||||
just be a sitting duck waiting to be hit by a bit error. Critical
|
||||
systems deserve real hardware.
|
||||
|
||||
When a compiler messes up, the problem can be reproduced whenever
|
||||
the resulting program is run. Compiler errors are most likely to
|
||||
happen in the code optimizer. If a problem is reproducible across
|
||||
power cycles and system reboots, it can be worthwhile to rebuild
|
||||
Postfix with optimization disabled, and to see if optimization
|
||||
makes a difference.
|
||||
|
||||
In order to compile Postfix with optimizations turned off:
|
||||
|
||||
% make tidy
|
||||
% make makefiles OPT=
|
||||
|
||||
This produces a set of Makefiles that do not request compiler
|
||||
optomization.
|
||||
|
||||
Once the makefiles are set up, build the software:
|
||||
|
||||
% make
|
||||
% su
|
||||
# make install
|
||||
|
||||
And see if the problem reproduces. If the problem goes away, talk
|
||||
to your vendor.
|
||||
|
@@ -3220,6 +3220,23 @@ Apologies for any names omitted.
|
||||
Feature: permit_auth_destination restriction based on code
|
||||
by Jesper Skriver @ skriver.dk.
|
||||
|
||||
Code cleanup: the transport table now can override local
|
||||
deliveries. Postfix no longer uses the "empty next-hop
|
||||
hostname hack" to remember that a destination is local.
|
||||
Code cleanup: the transport table now can override all
|
||||
deliveries, including local ones.
|
||||
|
||||
19991116
|
||||
|
||||
Code cleanup: a new "local_transports" configuration
|
||||
parameter explicitly lists all transports that deliver
|
||||
mail locally. The first name listed there is the default
|
||||
local transport. This is the end of the "empty next-hop
|
||||
hostname" hack to indicate that a destination is local.
|
||||
Files: trivial-rewrite/resolve.c, global/local_transport.[hc]
|
||||
|
||||
Feature: "postconf -m" shows what lookup table types are
|
||||
available. Code by Scott Cotton, Internet Consultants
|
||||
Group, Inc.
|
||||
|
||||
Feature: "postconf -e" edits any number of main.cf parameters.
|
||||
The edit is done on a copy, and the copy is renamed into
|
||||
the place of the original. File: postconf/postconf.c,
|
||||
util/readlline.[hc].
|
||||
|
@@ -75,6 +75,7 @@ dns_lookup.o: ../include/vstring.h
|
||||
dns_lookup.o: ../include/vbuf.h
|
||||
dns_lookup.o: ../include/msg.h
|
||||
dns_lookup.o: ../include/valid_hostname.h
|
||||
dns_lookup.o: ../include/stringops.h
|
||||
dns_lookup.o: dns.h
|
||||
dns_rr.o: dns_rr.c
|
||||
dns_rr.o: ../include/sys_defs.h
|
||||
|
@@ -247,7 +247,7 @@ static int dns_get_fixed(unsigned char *pos, DNS_FIXED *fixed)
|
||||
static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
|
||||
char *rr_name, DNS_FIXED *fixed)
|
||||
{
|
||||
char temp[DNS_NAME_LEN];
|
||||
unsigned char temp[DNS_NAME_LEN];
|
||||
int data_len;
|
||||
unsigned pref = 0;
|
||||
unsigned char *src;
|
||||
|
@@ -2,7 +2,8 @@ SHELL = /bin/sh
|
||||
SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
|
||||
debug_peer.c debug_process.c defer.c deliver_completed.c \
|
||||
deliver_flock.c deliver_pass.c deliver_request.c domain_list.c \
|
||||
dot_lockfile.c file_id.c header_opts.c is_header.c mail_addr.c \
|
||||
dot_lockfile.c dot_lockfile_as.c ext_prop.c file_id.c \
|
||||
header_opts.c is_header.c local_transport.c mail_addr.c \
|
||||
mail_addr_crunch.c mail_addr_find.c mail_addr_map.c \
|
||||
mail_command_read.c mail_command_write.c mail_conf.c \
|
||||
mail_conf_bool.c mail_conf_int.c mail_conf_raw.c mail_conf_str.c \
|
||||
@@ -16,12 +17,12 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
|
||||
recipient_list.c record.c remove.c resolve_clnt.c resolve_local.c \
|
||||
rewrite_clnt.c sent.c smtp_stream.c split_addr.c string_list.c \
|
||||
sys_exits.c timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
|
||||
tok822_resolve.c tok822_rewrite.c tok822_tree.c ext_prop.c \
|
||||
dot_lockfile_as.c
|
||||
tok822_resolve.c tok822_rewrite.c tok822_tree.c
|
||||
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
|
||||
debug_peer.o debug_process.o defer.o deliver_completed.o \
|
||||
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
|
||||
dot_lockfile.o file_id.o header_opts.o is_header.o mail_addr.o \
|
||||
dot_lockfile.o dot_lockfile_as.o ext_prop.o file_id.o \
|
||||
header_opts.o is_header.o local_transport.o mail_addr.o \
|
||||
mail_addr_crunch.o mail_addr_find.o mail_addr_map.o \
|
||||
mail_command_read.o mail_command_write.o mail_conf.o \
|
||||
mail_conf_bool.o mail_conf_int.o mail_conf_raw.o mail_conf_str.o \
|
||||
@@ -35,12 +36,12 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
|
||||
recipient_list.o record.o remove.o resolve_clnt.o resolve_local.o \
|
||||
rewrite_clnt.o sent.o smtp_stream.o split_addr.o string_list.o \
|
||||
sys_exits.o timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
|
||||
tok822_resolve.o tok822_rewrite.o tok822_tree.o ext_prop.o \
|
||||
dot_lockfile_as.o
|
||||
tok822_resolve.o tok822_rewrite.o tok822_tree.o
|
||||
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
|
||||
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
|
||||
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
|
||||
dot_lockfile.h file_id.h header_opts.h is_header.h mail_addr.h \
|
||||
dot_lockfile.h dot_lockfile_as.h ext_prop.h file_id.h \
|
||||
header_opts.h is_header.h local_transport.h mail_addr.h \
|
||||
mail_addr_crunch.h mail_addr_find.h mail_addr_map.h mail_conf.h \
|
||||
mail_copy.h mail_date.h mail_error.h mail_flush.h mail_open_ok.h \
|
||||
mail_params.h mail_proto.h mail_queue.h mail_run.h mail_scan_dir.h \
|
||||
@@ -50,7 +51,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
|
||||
quote_822_local.h rec_streamlf.h rec_type.h recipient_list.h \
|
||||
record.h resolve_clnt.h resolve_local.h rewrite_clnt.h sent.h \
|
||||
smtp_stream.h split_addr.h string_list.h sys_exits.h timed_ipc.h \
|
||||
tok822.h ext_prop.h dot_lockfile_as.h
|
||||
tok822.h
|
||||
TESTSRC = rec2stream.c stream2rec.c recdump.c
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||
@@ -62,7 +63,8 @@ LIB = libglobal.a
|
||||
TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
|
||||
mail_addr_map mail_date maps mynetworks mypwd namadr_list \
|
||||
off_cvt quote_822_local rec2stream recdump resolve_clnt \
|
||||
resolve_local rewrite_clnt stream2rec string_list tok822_parse
|
||||
resolve_local rewrite_clnt stream2rec string_list tok822_parse \
|
||||
local_transport
|
||||
|
||||
LIBS = ../lib/libutil.a
|
||||
LIB_DIR = ../lib
|
||||
@@ -187,6 +189,11 @@ string_list: $(LIB) $(LIBS)
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
|
||||
mv junk $@.o
|
||||
|
||||
local_transport: $(LIB) $(LIBS)
|
||||
mv $@.o junk
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
|
||||
mv junk $@.o
|
||||
|
||||
printfck: $(OBJS) $(PROG)
|
||||
rm -rf printfck
|
||||
mkdir printfck
|
||||
@@ -361,6 +368,13 @@ header_opts.o: header_opts.h
|
||||
is_header.o: is_header.c
|
||||
is_header.o: ../include/sys_defs.h
|
||||
is_header.o: is_header.h
|
||||
local_transport.o: local_transport.c
|
||||
local_transport.o: ../include/sys_defs.h
|
||||
local_transport.o: ../include/msg.h
|
||||
local_transport.o: ../include/mymalloc.h
|
||||
local_transport.o: string_list.h
|
||||
local_transport.o: mail_params.h
|
||||
local_transport.o: local_transport.h
|
||||
mail_addr.o: mail_addr.c
|
||||
mail_addr.o: ../include/sys_defs.h
|
||||
mail_addr.o: ../include/stringops.h
|
||||
|
134
postfix/global/local_transport.c
Normal file
134
postfix/global/local_transport.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* local_transport 3
|
||||
/* SUMMARY
|
||||
/* determine if transport delivers locally
|
||||
/* SYNOPSIS
|
||||
/* #include <local_transport.h>
|
||||
/*
|
||||
/* const char *def_local_transport()
|
||||
/*
|
||||
/* int local_transport(transport)
|
||||
/* const char *transport;
|
||||
/* DESCRIPTION
|
||||
/* This module uses the information kept in the "local_transports"
|
||||
/* configuration parameter, which lists the names of the default
|
||||
/* local transport followed by zero or more other transports that
|
||||
/* deliver locally.
|
||||
/*
|
||||
/* def_local_transport() returns the name of the default local
|
||||
/* transport, that is, the first transport name specified with
|
||||
/* the "local_transports" configuration parameter.
|
||||
/*
|
||||
/* local_transport() determines if the named transport is listed
|
||||
/* in the "local_transports" configuration parameter.
|
||||
/* SEE ALSO
|
||||
/* resolve_local(3), see if address resolves locally.
|
||||
/* 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
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <mymalloc.h>
|
||||
#include <string_list.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
#include <local_transport.h>
|
||||
|
||||
/* Application-specific */
|
||||
|
||||
static STRING_LIST *local_transport_list;
|
||||
static char *local_transport_name;
|
||||
|
||||
/* local_transport_init - initialize lookup table */
|
||||
|
||||
static void local_transport_init(void)
|
||||
{
|
||||
char *myname = "local_transport_init";
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (local_transport_list || local_transport_name)
|
||||
msg_panic("local_transport_init: duplicate initialization");
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
local_transport_list = string_list_init(var_local_transports);
|
||||
local_transport_name = mystrndup(var_local_transports,
|
||||
strcspn(var_local_transports, ", \t\r\n"));
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (!local_transport(local_transport_name))
|
||||
msg_panic("%s: unable to intialize", myname);
|
||||
}
|
||||
|
||||
/* def_local_transport - determine default local transport */
|
||||
|
||||
const char *def_local_transport(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Initialize on the fly.
|
||||
*/
|
||||
if (local_transport_list == 0)
|
||||
local_transport_init();
|
||||
|
||||
/*
|
||||
* Return the first transport listed.
|
||||
*/
|
||||
return (local_transport_name);
|
||||
}
|
||||
|
||||
/* local_transport - match address against list of local destinations */
|
||||
|
||||
int local_transport(const char *transport)
|
||||
{
|
||||
|
||||
/*
|
||||
* Initialize on the fly.
|
||||
*/
|
||||
if (local_transport_list == 0)
|
||||
local_transport_init();
|
||||
|
||||
/*
|
||||
* Compare the transport against the list of transports that are listed
|
||||
* as delivering locally.
|
||||
*/
|
||||
return (string_list_match(local_transport_list, transport));
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <vstream.h>
|
||||
#include <mail_conf.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
msg_fatal("usage: %s transport", argv[0]);
|
||||
mail_conf_read();
|
||||
vstream_printf("%s\n", local_transport(argv[1]) ? "yes" : "no");
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
||||
|
||||
#endif
|
31
postfix/global/local_transport.h
Normal file
31
postfix/global/local_transport.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef _LOCAL_TRANSPORT_H_INCLUDED_
|
||||
#define _LOCAL_TRANSPORT_H_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* local_transport 3h
|
||||
/* SUMMARY
|
||||
/* determine if transport delivers locally
|
||||
/* SYNOPSIS
|
||||
/* #include <local_transport.h>
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern const char *def_local_transport(void);
|
||||
extern int local_transport(const char *);
|
||||
|
||||
/* 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
|
||||
/*--*/
|
||||
|
||||
#endif
|
@@ -57,6 +57,7 @@
|
||||
/* time_t var_starttime;
|
||||
/* int var_ownreq_special;
|
||||
/* int var_daemon_timeout;
|
||||
/* char *var_local_transports;
|
||||
/*
|
||||
/* void mail_params_init()
|
||||
/* DESCRIPTION
|
||||
@@ -161,6 +162,7 @@ int var_soft_bounce;
|
||||
time_t var_starttime;
|
||||
int var_ownreq_special;
|
||||
int var_daemon_timeout;
|
||||
char *var_local_transports;
|
||||
|
||||
/* check_myhostname - lookup hostname and validate */
|
||||
|
||||
@@ -261,6 +263,7 @@ void mail_params_init()
|
||||
VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
|
||||
VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
|
||||
VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1,
|
||||
VAR_LOCAL_TRANSP, DEF_LOCAL_TRANSP, &var_local_transports, 1, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
|
||||
|
@@ -80,6 +80,13 @@ extern char *var_myhostname;
|
||||
#define VAR_MYDOMAIN "mydomain" /* my domain name */
|
||||
extern char *var_mydomain;
|
||||
|
||||
/*
|
||||
* Transports that deliver locally. Order matters.
|
||||
*/
|
||||
#define VAR_LOCAL_TRANSP "local_transports"
|
||||
#define DEF_LOCAL_TRANSP "local"
|
||||
extern char *var_local_transports;
|
||||
|
||||
/*
|
||||
* Where to send postmaster copies of bounced mail, and other notices.
|
||||
*/
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-19991115"
|
||||
#define DEF_MAIL_VERSION "Snapshot-19991116"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@@ -375,6 +375,7 @@ resolve.o: ../include/resolve_clnt.h
|
||||
resolve.o: ../include/rewrite_clnt.h
|
||||
resolve.o: ../include/tok822.h
|
||||
resolve.o: ../include/mail_params.h
|
||||
resolve.o: ../include/local_transport.h
|
||||
resolve.o: local.h
|
||||
resolve.o: ../include/been_here.h
|
||||
resolve.o: ../include/deliver_request.h
|
||||
|
@@ -62,7 +62,7 @@
|
||||
#include <rewrite_clnt.h>
|
||||
#include <tok822.h>
|
||||
#include <mail_params.h>
|
||||
#include <resolve_local.h>
|
||||
#include <local_transport.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -139,7 +139,7 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
|
||||
* ugly code to force local recursive alias expansions on a host with no
|
||||
* authority over the local domain, but that code was just too unclean.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))) {
|
||||
if (local_transport(STR(reply.transport))) {
|
||||
status = deliver_recipient(state, usr_attr);
|
||||
} else {
|
||||
status = deliver_indirect(state);
|
||||
|
@@ -237,7 +237,7 @@ MASTER_SERV *get_master_ent()
|
||||
* Skip blank lines and comment lines.
|
||||
*/
|
||||
do {
|
||||
if (readlline(buf, master_fp, &master_line) == 0) {
|
||||
if (readlline(buf, master_fp, &master_line, READLL_STRIPNL) == 0) {
|
||||
vstring_free(buf);
|
||||
vstring_free(junk);
|
||||
return (0);
|
||||
|
@@ -164,7 +164,7 @@ static void postalias(char *map_type, char *path_name,
|
||||
* Add records to the database.
|
||||
*/
|
||||
lineno = 0;
|
||||
while (readlline(line_buffer, source_fp, &lineno)) {
|
||||
while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) {
|
||||
|
||||
/*
|
||||
* Skip comments.
|
||||
|
@@ -5,21 +5,32 @@
|
||||
/* Postfix configuration utility
|
||||
/* SYNOPSIS
|
||||
/* .fi
|
||||
/* \fBpostconf\fR [\fB-c \fIconfig_dir\fR] [\fB-d\fR] [\fB-h\fR]
|
||||
/* [\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR]
|
||||
/* \fBpostconf\fR [\fB-dhnv\fR] [\fB-c \fIconfig_dir\fR]
|
||||
/* [\fIparameter ...\fR]
|
||||
/*
|
||||
/* \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
|
||||
/* [\fIparameter=value ...\fR]
|
||||
/* DESCRIPTION
|
||||
/* The \fBpostconf\fR command prints the actual value of
|
||||
/* \fIparameter\fR (all known parameters by default), one
|
||||
/* parameter per line.
|
||||
/* parameter per line, changes its value, or prints other
|
||||
/* information about the Postfix mail system.
|
||||
/*
|
||||
/* Options:
|
||||
/* .IP "\fB-c \fIconfig_dir\fR"
|
||||
/* The \fBmain.cf\fR configuration file is in the named directory.
|
||||
/* .IP \fB-d\fR
|
||||
/* Print default parameter settings instead of actual settings.
|
||||
/* .IP \fB-e\fR
|
||||
/* Edit the \fBmain.cf\fR configuration file. The file is copied
|
||||
/* to a temporary file then renamed into place. Parameters and
|
||||
/* values are specified on the command line. Use quotes in order
|
||||
/* to protect shell metacharacters and whitespace.
|
||||
/* .IP \fB-h\fR
|
||||
/* Show parameter values only, not the ``name = '' label
|
||||
/* that normally precedes the value.
|
||||
/* .IP \fB-m\fR
|
||||
/* List the names of all supported lookup table types.
|
||||
/* .IP \fB-n\fR
|
||||
/* Print non-default parameter settings only.
|
||||
/* .IP \fB-v\fR
|
||||
@@ -42,10 +53,12 @@
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h> /* rename() */
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
@@ -66,7 +79,10 @@
|
||||
#include <dict.h>
|
||||
#include <safe.h>
|
||||
#include <mymalloc.h>
|
||||
#include <line_wrap.h>
|
||||
#include <argv.h>
|
||||
#include <split_at.h>
|
||||
#include <readlline.h>
|
||||
#include <myflock.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
@@ -78,11 +94,13 @@
|
||||
#include <mail_addr.h>
|
||||
|
||||
/*
|
||||
* What output we should generate.
|
||||
* What we're supposed to be doing.
|
||||
*/
|
||||
#define SHOW_NONDEF (1<<0) /* show non-default settings */
|
||||
#define SHOW_DEFS (1<<1) /* show default setting */
|
||||
#define SHOW_NAME (1<<2) /* show parameter name */
|
||||
#define SHOW_MAPS (1<<3) /* show map types */
|
||||
#define EDIT_MAIN (1<<4) /* edit main.cf */
|
||||
|
||||
/*
|
||||
* Lookup table for in-core parameter info.
|
||||
@@ -214,6 +232,131 @@ static const char *check_mynetworks(void)
|
||||
return (mynetworks());
|
||||
}
|
||||
|
||||
/* edit_parameters - edit parameter file */
|
||||
|
||||
static void edit_parameters(int argc, char **argv)
|
||||
{
|
||||
char *config_dir;
|
||||
char *path;
|
||||
char *temp;
|
||||
VSTREAM *src;
|
||||
VSTREAM *dst;
|
||||
VSTRING *buf = vstring_alloc(100);
|
||||
VSTRING *key = vstring_alloc(10);
|
||||
char *cp;
|
||||
char *value;
|
||||
HTABLE *table;
|
||||
int first = 1;
|
||||
struct cvalue {
|
||||
char *value;
|
||||
int found;
|
||||
};
|
||||
struct cvalue *cvalue;
|
||||
HTABLE_INFO **ht_info;
|
||||
HTABLE_INFO **ht;
|
||||
|
||||
/*
|
||||
* Store command-line parameters for quick lookup.
|
||||
*/
|
||||
table = htable_create(argc);
|
||||
while ((cp = *argv++) != 0) {
|
||||
if ((value = split_at(cp, '=')) == 0
|
||||
|| *(cp += strspn(cp, " \t\r\n")) == 0)
|
||||
msg_fatal("edit requires \"key = value\" arguments");
|
||||
cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
|
||||
cvalue->value = value;
|
||||
cvalue->found = 0;
|
||||
htable_enter(table, mystrtok(&cp, " \t\r\n"), (char *) cvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Avoid code duplication by better code decomposition.
|
||||
*/
|
||||
if (var_config_dir)
|
||||
myfree(var_config_dir);
|
||||
var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
|
||||
config_dir : DEF_CONFIG_DIR); /* XXX */
|
||||
set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
|
||||
|
||||
/*
|
||||
* Open the original file for input.
|
||||
*/
|
||||
path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
|
||||
if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0)
|
||||
msg_fatal("open %s for reading: %m", path);
|
||||
|
||||
/*
|
||||
* Open a temp file for the result. We use a fixed name so we don't leave
|
||||
* behind thrash with random names. Lock the temp file to avoid
|
||||
* accidents. Truncate the file only after we have an exclusive lock.
|
||||
*/
|
||||
temp = concatenate(path, ".tmp", (char *) 0);
|
||||
if ((dst = vstream_fopen(temp, O_CREAT | O_WRONLY, 0644)) == 0)
|
||||
msg_fatal("open %s: %m", temp);
|
||||
if (myflock(vstream_fileno(dst), MYFLOCK_EXCLUSIVE) < 0)
|
||||
msg_fatal("lock %s: %m", temp);
|
||||
if (ftruncate(vstream_fileno(dst), 0) < 0)
|
||||
msg_fatal("truncate %s: %m", temp);
|
||||
|
||||
/*
|
||||
* Copy original file to temp file, while replacing parameters on the
|
||||
* fly. Issue warnings for names found multiple times.
|
||||
*/
|
||||
#define STR(x) vstring_str(x)
|
||||
|
||||
while (readlline(buf, src, (int *) 0, READLL_KEEPNL)) {
|
||||
cp = STR(buf);
|
||||
if (first) {
|
||||
first = 0;
|
||||
if (ISSPACE(*cp))
|
||||
msg_fatal("%s: file starts with whitespace", path);
|
||||
}
|
||||
if (*cp == '#') {
|
||||
vstream_fputs(STR(buf), dst);
|
||||
continue;
|
||||
}
|
||||
cp += strspn(cp, " \t\r\n");
|
||||
vstring_strncpy(key, cp, strcspn(cp, " \t\r\n="));
|
||||
cvalue = (struct cvalue *) htable_find(table, STR(key));
|
||||
if (cvalue == 0) {
|
||||
vstream_fputs(STR(buf), dst);
|
||||
} else {
|
||||
if (cvalue->found++ == 1)
|
||||
msg_warn("%s: multiple entries for key %s", path, STR(key));
|
||||
vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate new entries for parameters that were not found.
|
||||
*/
|
||||
for (ht_info = ht = htable_list(table); *ht; ht++) {
|
||||
cvalue = (struct cvalue *) ht[0]->value;
|
||||
if (cvalue->found == 0)
|
||||
vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
|
||||
}
|
||||
myfree((char *) ht_info);
|
||||
|
||||
/*
|
||||
* When all is well, rename the temp file to the original one.
|
||||
*/
|
||||
if (vstream_fclose(src))
|
||||
msg_fatal("read %s: %m", path);
|
||||
if (vstream_fclose(dst))
|
||||
msg_fatal("write %s: %m", temp);
|
||||
if (rename(temp, path) < 0)
|
||||
msg_fatal("rename %s to %s: %m", temp, path);
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
myfree(path);
|
||||
myfree(temp);
|
||||
vstring_free(buf);
|
||||
vstring_free(key);
|
||||
htable_free(table, myfree);
|
||||
}
|
||||
|
||||
/* read_parameters - read parameter info from file */
|
||||
|
||||
static void read_parameters(void)
|
||||
@@ -430,6 +573,19 @@ static int comp_names(const void *a, const void *b)
|
||||
return (strcmp(ap[0]->key, bp[0]->key));
|
||||
}
|
||||
|
||||
/* show_maps - show available maps */
|
||||
|
||||
static void show_maps(void)
|
||||
{
|
||||
ARGV *maps_argv;
|
||||
int i;
|
||||
|
||||
maps_argv = dict_mapnames();
|
||||
for (i = 0; i < maps_argv->argc; i++)
|
||||
vstream_printf("%s\n", maps_argv->argv[i]);
|
||||
argv_free(maps_argv);
|
||||
}
|
||||
|
||||
/* show_parameters - show parameter info */
|
||||
|
||||
static void show_parameters(int mode, char **names)
|
||||
@@ -470,6 +626,7 @@ int main(int argc, char **argv)
|
||||
int ch;
|
||||
int fd;
|
||||
struct stat st;
|
||||
int junk;
|
||||
|
||||
/*
|
||||
* To minimize confusion, make sure that the standard file descriptors
|
||||
@@ -489,44 +646,70 @@ int main(int argc, char **argv)
|
||||
/*
|
||||
* Parse JCL.
|
||||
*/
|
||||
while ((ch = GETOPT(argc, argv, "c:dhnv")) > 0) {
|
||||
while ((ch = GETOPT(argc, argv, "c:dehnmv")) > 0) {
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||
msg_fatal("out of memory");
|
||||
break;
|
||||
case 'd':
|
||||
if (mode & SHOW_NONDEF)
|
||||
msg_fatal("specify one of -d and -n");
|
||||
mode |= SHOW_DEFS;
|
||||
break;
|
||||
case 'e':
|
||||
mode |= EDIT_MAIN;
|
||||
break;
|
||||
case 'h':
|
||||
mode &= ~SHOW_NAME;
|
||||
break;
|
||||
case 'm':
|
||||
mode |= SHOW_MAPS;
|
||||
break;
|
||||
case 'n':
|
||||
if (mode & SHOW_DEFS)
|
||||
msg_fatal("specify one of -d and -n");
|
||||
mode |= SHOW_NONDEF;
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-h (no names)] [-n (non-defaults)] [-v] name...", argv[0]);
|
||||
msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-e (edit)] [-h (no names)] [-m (map types) [-n (non-defaults)] [-v] [name...]", argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
junk = (mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | EDIT_MAIN));
|
||||
if (junk != 0 && junk != SHOW_DEFS && junk != SHOW_NONDEF
|
||||
&& junk != SHOW_MAPS && junk != EDIT_MAIN)
|
||||
msg_fatal("specify one of -d, -e, -n and -m");
|
||||
|
||||
/*
|
||||
* If showing map types, show them and exit
|
||||
*/
|
||||
if (mode & SHOW_MAPS) {
|
||||
show_maps();
|
||||
}
|
||||
|
||||
/*
|
||||
* Edit main.cf.
|
||||
*/
|
||||
if (mode & EDIT_MAIN) {
|
||||
edit_parameters(argc - optind, argv + optind);
|
||||
}
|
||||
|
||||
/*
|
||||
* If showing non-default values, read main.cf.
|
||||
*/
|
||||
if ((mode & SHOW_DEFS) == 0)
|
||||
read_parameters();
|
||||
else {
|
||||
if ((mode & SHOW_DEFS) == 0)
|
||||
read_parameters();
|
||||
|
||||
/*
|
||||
* Throw together all parameters and show the asked values.
|
||||
*/
|
||||
hash_parameters();
|
||||
show_parameters(mode, argv + optind);
|
||||
/*
|
||||
* Throw together all parameters and show the asked values.
|
||||
*/
|
||||
hash_parameters();
|
||||
show_parameters(mode, argv + optind);
|
||||
}
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
exit(0);
|
||||
}
|
||||
|
@@ -168,7 +168,7 @@ static void postmap(char *map_type, char *path_name,
|
||||
* Add records to the database.
|
||||
*/
|
||||
lineno = 0;
|
||||
while (readlline(line_buffer, source_fp, &lineno)) {
|
||||
while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) {
|
||||
|
||||
/*
|
||||
* Skip comments.
|
||||
|
@@ -110,7 +110,7 @@
|
||||
#include <deliver_completed.h>
|
||||
#include <mail_addr_find.h>
|
||||
#include <opened.h>
|
||||
#include <resolve_local.h>
|
||||
#include <local_transport.h>
|
||||
|
||||
/* Client stubs. */
|
||||
|
||||
@@ -477,7 +477,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
/*
|
||||
* Bounce mail to non-existent users in virtual domains.
|
||||
*/
|
||||
if (!resolve_local(STR(reply.nexthop))
|
||||
if (!local_transport(STR(reply.transport))
|
||||
&& qmgr_virtual != 0
|
||||
&& (at = strrchr(recipient->address, '@')) != 0) {
|
||||
domain = lowercase(mystrdup(at + 1));
|
||||
@@ -516,7 +516,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
||||
* job requires knowledge of local aliases. Yuck! I don't want to
|
||||
* duplicate delivery-agent specific knowledge in the queue manager.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))) {
|
||||
if (local_transport(STR(reply.transport))) {
|
||||
vstring_strcpy(reply.nexthop, STR(reply.recipient));
|
||||
(void) split_at_right(STR(reply.nexthop), '@');
|
||||
#if 0
|
||||
|
@@ -172,6 +172,7 @@ smtpd_check.o: ../include/own_inet_addr.h
|
||||
smtpd_check.o: ../include/mail_conf.h
|
||||
smtpd_check.o: ../include/maps.h
|
||||
smtpd_check.o: ../include/mail_addr_find.h
|
||||
smtpd_check.o: ../include/local_transport.h
|
||||
smtpd_check.o: smtpd.h
|
||||
smtpd_check.o: ../include/mail_stream.h
|
||||
smtpd_check.o: smtpd_check.h
|
||||
|
@@ -275,6 +275,7 @@
|
||||
#include <mail_conf.h>
|
||||
#include <maps.h>
|
||||
#include <mail_addr_find.h>
|
||||
#include <local_transport.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -712,7 +713,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
|
||||
* Permit if destination is local. XXX This must be generalized for
|
||||
* per-domain user tables and for non-UNIX local delivery agents.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))
|
||||
if (local_transport(STR(reply.transport))
|
||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||
return (SMTPD_CHECK_OK);
|
||||
domain += 1;
|
||||
@@ -751,7 +752,7 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
||||
* Permit if destination is local. XXX This must be generalized for
|
||||
* per-domain user tables and for non-UNIX local delivery agents.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))
|
||||
if (local_transport(STR(reply.transport))
|
||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||
return (SMTPD_CHECK_OK);
|
||||
domain += 1;
|
||||
@@ -788,7 +789,7 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
|
||||
* Pass if destination is local. XXX This must be generalized for
|
||||
* per-domain user tables and for non-UNIX local delivery agents.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))
|
||||
if (local_transport(STR(reply.transport))
|
||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
domain += 1;
|
||||
@@ -890,7 +891,7 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient)
|
||||
* If the destination is local, it is acceptable, because we are
|
||||
* supposedly MX for our own address.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))
|
||||
if (local_transport(STR(reply.transport))
|
||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||
return (SMTPD_CHECK_OK);
|
||||
domain += 1;
|
||||
@@ -1024,7 +1025,7 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
||||
/*
|
||||
* Skip local destinations and non-DNS forms.
|
||||
*/
|
||||
if (resolve_local(STR(reply.nexthop))
|
||||
if (local_transport(STR(reply.transport))
|
||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
domain += 1;
|
||||
@@ -1064,7 +1065,7 @@ static int permit_rcpt_map(char *table, char *reply_name)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
domain += 1;
|
||||
if (domain[0] == '#' || domain[0] == '[')
|
||||
if (!resolve_local(STR(reply.nexthop)))
|
||||
if (!local_transport(STR(reply.transport)))
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
|
||||
/*
|
||||
|
@@ -72,6 +72,7 @@
|
||||
#include <mail_conf.h>
|
||||
#include <quote_822_local.h>
|
||||
#include <tok822.h>
|
||||
#include <local_transport.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -151,44 +152,55 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
|
||||
}
|
||||
|
||||
/*
|
||||
* The transport map, if specified, overrides default routing.
|
||||
* Make sure the resolved envelope recipient has the user@domain form. If
|
||||
* no domain was specified in the address, assume the local machine. See
|
||||
* above for what happens with an empty localpart.
|
||||
*/
|
||||
if (*var_transport_maps == 0
|
||||
|| (tok822_internalize(addr_buf, domain->next, TOK822_STR_DEFL),
|
||||
transport_lookup(STR(addr_buf), channel, nexthop)) == 0) {
|
||||
|
||||
/*
|
||||
* Non-local delivery. Use the default transport specified in
|
||||
* var_def_transport. If no default mail relay is specified in
|
||||
* var_relayhost, forward to the domain's mail exchanger.
|
||||
*/
|
||||
if (domain != 0) {
|
||||
vstring_strcpy(channel, var_def_transport);
|
||||
if (*var_relayhost)
|
||||
vstring_strcpy(nexthop, var_relayhost);
|
||||
else
|
||||
tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local delivery. Use the default transport and next-hop hostname.
|
||||
* If no domain was specified, assume the local machine. See above
|
||||
* for what happens with an empty localpart.
|
||||
*/
|
||||
else {
|
||||
vstring_strcpy(channel, MAIL_SERVICE_LOCAL);
|
||||
vstring_strcpy(nexthop, var_myhostname);
|
||||
if (saved_domain) {
|
||||
tok822_sub_append(tree, saved_domain);
|
||||
saved_domain = 0;
|
||||
} else {
|
||||
tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
|
||||
tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
|
||||
}
|
||||
if (domain == 0) {
|
||||
if (saved_domain) {
|
||||
tok822_sub_append(tree, saved_domain);
|
||||
saved_domain = 0;
|
||||
} else {
|
||||
tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
|
||||
tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
|
||||
}
|
||||
}
|
||||
tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
|
||||
|
||||
/*
|
||||
* The transport map overrides the default transport and next-hop host
|
||||
* info that was set up just moments ago. For a long time, it was not
|
||||
* possible to override routing of mail that resolves locally, because
|
||||
* Postfix used a zero-length next-hop hostname result to indicate local
|
||||
* delivery, and transport maps cannot return zero-length hostnames.
|
||||
*/
|
||||
if (*var_transport_maps
|
||||
&& transport_lookup(strrchr(STR(nextrcpt), '@') + 1, channel, nexthop)) {
|
||||
/* void */ ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-local delivery, presumably. Set up the default remote transport
|
||||
* specified with var_local_transports. Use the destination's mail
|
||||
* exchanger unless a default mail relay is specified with var_relayhost.
|
||||
*/
|
||||
else if (domain != 0) {
|
||||
vstring_strcpy(channel, var_def_transport);
|
||||
if (*var_relayhost)
|
||||
vstring_strcpy(nexthop, var_relayhost);
|
||||
else
|
||||
tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local delivery. Set up the default local transport and the default
|
||||
* next-hop hostname.
|
||||
*/
|
||||
else {
|
||||
vstring_strcpy(channel, def_local_transport());
|
||||
vstring_strcpy(nexthop, var_myhostname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up.
|
||||
*/
|
||||
|
@@ -394,7 +394,7 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
|
||||
buf = vstring_alloc(100);
|
||||
lineno = 0;
|
||||
|
||||
while (readlline(buf, fp, &lineno)) {
|
||||
while (readlline(buf, fp, &lineno, READLL_STRIPNL)) {
|
||||
start = STR(buf);
|
||||
SKIP(start, member, ISSPACE(*member)); /* find member begin */
|
||||
if (*member == 0 || *member == '#')
|
||||
|
@@ -20,6 +20,7 @@
|
||||
* Utility library.
|
||||
*/
|
||||
#include <vstream.h>
|
||||
#include <argv.h>
|
||||
|
||||
/*
|
||||
* Generic dictionary interface - in reality, a dictionary extends this
|
||||
@@ -56,6 +57,11 @@ extern int dict_errno;
|
||||
#define DICT_SEQ_FUN_FIRST 0 /* set cursor to first record */
|
||||
#define DICT_SEQ_FUN_NEXT 1 /* set cursor to next record */
|
||||
|
||||
/*
|
||||
* Interface for dictionary types.
|
||||
*/
|
||||
extern ARGV *dict_mapnames(void);
|
||||
|
||||
/*
|
||||
* High-level interface, with logical dictionary names.
|
||||
*/
|
||||
@@ -96,5 +102,6 @@ extern int dict_changed(void);
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
/**INDENT** Error@47: Unmatched #endif */
|
||||
|
||||
#endif
|
||||
|
@@ -280,6 +280,27 @@ void dict_open_register(const char *type,
|
||||
htable_enter(dict_open_hash, dp->type, (char *) dp);
|
||||
}
|
||||
|
||||
/* dict_mapnames - return an ARGV of available map_names */
|
||||
|
||||
ARGV *dict_mapnames()
|
||||
{
|
||||
HTABLE_INFO **ht_info;
|
||||
HTABLE_INFO **ht;
|
||||
DICT_OPEN_INFO *dp;
|
||||
ARGV *mapnames;
|
||||
|
||||
if (dict_open_hash == 0)
|
||||
dict_open_init();
|
||||
mapnames = argv_alloc(dict_open_hash->used + 1);
|
||||
for (ht_info = ht = htable_list(dict_open_hash); *ht; ht++) {
|
||||
dp = (DICT_OPEN_INFO *) ht[0]->value;
|
||||
argv_add(mapnames, dp->type, ARGV_END);
|
||||
}
|
||||
myfree((char *) ht_info);
|
||||
argv_terminate(mapnames);
|
||||
return mapnames;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
|
@@ -273,7 +273,7 @@ DICT *dict_pcre_open(const char *map, int unused_flags, int dict_flags)
|
||||
if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
|
||||
msg_fatal("open %s: %m", map);
|
||||
}
|
||||
while (readlline(line_buffer, map_fp, &lineno)) {
|
||||
while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) {
|
||||
|
||||
if (*vstring_str(line_buffer) == '#') /* Skip comments */
|
||||
continue;
|
||||
|
@@ -373,7 +373,7 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
|
||||
if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
|
||||
msg_fatal("open %s: %m", map);
|
||||
}
|
||||
while (readlline(line_buffer, map_fp, &lineno)) {
|
||||
while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) {
|
||||
p = vstring_str(line_buffer);
|
||||
|
||||
if (*p == '#') /* Skip comments */
|
||||
|
@@ -6,14 +6,16 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <readlline.h>
|
||||
/*
|
||||
/* VSTRING *readlline(buf, fp, lineno)
|
||||
/* VSTRING *readlline(buf, fp, lineno, stripnl)
|
||||
/* VSTRING *buf;
|
||||
/* VSTREAM *fp;
|
||||
/* int *lineno;
|
||||
/* int stripnl;
|
||||
/* DESCRIPTION
|
||||
/* readlline() reads one logical line from the named stream.
|
||||
/* A line that starts with whitespace is a continuation of
|
||||
/* the previous line. The newline between continued lines
|
||||
/* the previous line. When the stripnl argument is non-zero,
|
||||
/* the newline between continued lines
|
||||
/* is deleted from the input. The result value is the input
|
||||
/* buffer argument or a null pointer when no input is found.
|
||||
/*
|
||||
@@ -25,6 +27,9 @@
|
||||
/* .IP lineno
|
||||
/* A null pointer, or a pointer to an integer that is incremented
|
||||
/* after reading a newline.
|
||||
/* .IP stripnl
|
||||
/* Non-zero to strip newlines. readlline.h provides the symbolic
|
||||
/* constants READLL_STRIPNL and READLL_KEEPNL for convenience.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@@ -48,7 +53,7 @@
|
||||
|
||||
/* readlline - read one logical line */
|
||||
|
||||
VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
|
||||
VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno, int stripnl)
|
||||
{
|
||||
int ch;
|
||||
int next;
|
||||
@@ -59,6 +64,8 @@ VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
|
||||
VSTRING_RESET(buf);
|
||||
while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
|
||||
if (ch == '\n') {
|
||||
if (stripnl == 0)
|
||||
VSTRING_ADDCH(buf, ch);
|
||||
if (lineno)
|
||||
*lineno += 1;
|
||||
if ((next = VSTREAM_GETC(fp)) == ' ' || next == '\t') {
|
||||
|
@@ -20,7 +20,10 @@
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern VSTRING *readlline(VSTRING *, VSTREAM *, int *);
|
||||
extern VSTRING *readlline(VSTRING *, VSTREAM *, int *, int);
|
||||
|
||||
#define READLL_STRIPNL 1
|
||||
#define READLL_KEEPNL 0
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
Reference in New Issue
Block a user