--- /dev/null
+LINUX SYSLOGD PERFORMANCE
+=========================
+
+LINUX syslogd uses synchronous writes by default, which is very
+expensive. For services such as mail it is recommended that you
+disable synchronous logfile writes by editing /etc/syslog.conf and
+by prepending a - to the logfile name:
+
+ mail.* -/var/log/mail.log
+
+Send a "kill -HUP" to the syslogd to make the change effective.
will give more insight into how Postfix uses its lookup
tables. User interface comes later. File: util/dict_debug.c.
-20010215
-
- The showq output format assumes queue IDs of up to 10
- characters. It can be more with large file systems.
- Workaround for 11 character queue IDs by Lamont Jones.
- File: showq/showq.c.
-
20010216
Bugfix: the pipe delivery agent expanded $size as if it
in $mydestination, because Postfix would send one recipient
at a time, with multiple deliveries of recipients of the
same message in parallel; a similar problem could exist
- with firewall relay hosts that forward mail for $mydestination
- to an inside machine. This behavior is now changed to depend
- on the transport-specific xxx_destination_recipient_limit
- parameter. This also means that you can now get qmail behavior
- for SMTP deliveries by setting smtp_destination_recipient_limit=1.
- File: {qmgr,nqmgr}/qmgr_message.c.
+ with virus scanning and with firewall relay hosts that
+ forward mail for $mydestination to an inside machine. This
+ behavior is now changed to depend on the transport-specific
+ xxx_destination_recipient_limit parameter. This also means
+ that you can now get qmail behavior for SMTP deliveries by
+ setting smtp_destination_recipient_limit=1. File:
+ {qmgr,nqmgr}/qmgr_message.c.
Workaround: Solaris socketpair() can fail with EINTR. Added
a sane_socketpair.c module that joins the ranks of the other
configuration file edits" has a section that explains that
mynetworks should be properly configured in order to reject
unauthorized mail relay requests from strangers.
+
+20010223
+
+ Documentation: the basic.html document has a section that
+ explains that mynetworks should be properly configured in
+ order to reject unauthorized mail relay requests from
+ strangers.
+
+ Feature: new "mynetworks_style" parameter that controls
+ how mynetworks (trusted networks) is derived from the
+ inet_interfaces (machine interfaces) setting. Specify
+ "class" for entire class A, B, C networks; "subnet" for
+ the local subnets only; or "host" for maximal privacy.
+ Files: util/inet_addr_local.[hc], global/own_inet_addr.[hc],
+ global/mynetworks.[hc], postconf/postconf.c.
+
+ Portability: MACOSX patches by Gerben Wierda.
+
+ Portability: Solaris /dev/null is a symlink, which tripped
+ up the code to safely open a file before delivery. We now
+ grudgingly allow symlinks owned by root. File: util/safe_open.c.
+
+20010224
+
+ Bugfix: "postconf mynetworks" ignored the inet_interfaces
+ setting. That was a very old one. File: postconf/postconf.c.
Linux SuSE 6.x
Linux SuSE 7.x
Mac OS X server
+ Mac OS X Public Beta
NEXTSTEP 3.x
NetBSD 1.x
OPENSTEP 4.x
will have to build the alias database (with: sendmail -bi, or:
newaliases). Be sure to set up aliases for root and postmaster that
forward mail to a real person. Postfix has a sample aliases file
-the conf/aliases.
+conf/aliases that you can adapt to local conditions.
11 - To chroot or not to chroot
-==============================
+===============================
Postfix can run most daemon processes in a chroot jail, that is,
the processes run at a fixed low privilege and with access only to
)
esac
-test "$need_config" = 1 && cat <<EOF 1>&2
+test "$need_config" = 1 || exit 0
+
+ALIASES=`bin/postconf -h alias_database | sed 's/^[^:]*://'`
+cat <<EOF 1>&2
- Warning: you still need to edit myorigin/mydestination in
- $CONFIG_DIRECTORY/main.cf. See also html/faq.html for dialup
+ Warning: you still need to edit myorigin/mydestination/mynetworks
+ in $CONFIG_DIRECTORY/main.cf. See also html/faq.html for dialup
sites or for sites inside a firewalled network.
- BTW: Edit your alias database and be sure to set up aliases
- for root and postmaster, then run $NEWALIASES_PATH.
+ BTW: Check your $ALIASES file and be sure to set up aliases
+ for root and postmaster that direct mail to a real person, then
+ run $NEWALIASES_PATH.
EOF
Postfix no longer automatically delivers recipients one at a time
when their domain is listed in $mydestination. This change solves
-delivery performance problems with delivery via LMTP, and with
-firewall relays that forward all mail for $mydestination to an
-inside host.
+delivery performance problems with delivery via LMTP, with virus
+scanning, and with firewall relays that forward all mail for
+$mydestination to an inside host.
The "one recipient at a time" delivery behavior is now controlled
by the per-transport recipient limit (xxx_destination_recipient_limit,
# RELAY CONTROL
# The mynetworks parameter specifies the list of networks that make
-# up the local neighborhood. The list is used by the anti-UCE software
-# to distinguish local clients from strangers. See permit_mynetworks
-# and smtpd_recipient_restrictions in the file sample-smtpd.cf file.
+# up the local neighborhood. The list is used by the anti-UCE
+# software to relay authorize clients. See the check_relay_domains
+# and and smtpd_recipient_restrictions in the sample-smtpd.cf file.
#
-# The default is a list of all networks attached to the machine: a
-# complete class A network (X.0.0.0/8), a complete class B network
-# (X.X.0.0/16), and so on.
+# By default, Postfix derives the mynetworks setting from the local
+# machine network addresses.
+
+# The mynetworks_style parameter specifies how Postfix computes the
+# mynetworks default value from the local machine network addresses.
+#
+# By default (mynetworks_style = subnet), Postfix relay authorizes
+# all clients in the subnets that are attached to this machine.
#
-# YOU MUST CHANGE THIS DEFAULT SETTING IF YOUR ADDRESS BLOCK IS PART
-# OF A LARGER ADDRESS RANGE THAT IS OWNED BY YOUR PROVIDER - IT WOULD
-# CAUSE POSTFIX TO RELAY MAIL FROM ALL THEIR CUSTOMERS.
+# Specify "mynetworks_style = class" when you want to relay authorize
+# all clients in the class A, B or C networks that are attached to
+# to this machine.
+#
+# Specify "mynetworks_style = host" if you do not want to relay
+# authorize clients other than the local machine.
#
-# If you need stricter control than the default, specify a list of
-# network/mask patterns, where the mask specifies the number of bits
-# in the network part of a host address.
+# mynetworks_style = class
+# mynetworks_style = subnet
+# mynetworks_style = host
+
+# Instead of implicitly deriving the mynetworks value from local
+# machine addresses, you can specify an explicit list of network/mask
+# patterns, where the mask specifies the number of bits in the network
+# part of a host address.
#
# You can also specify the absolute pathname of a pattern file instead
# of listing the patterns here.
<li> <a href="#mydestination"> What domains to receive mail for
</a>
+<p>
+
+<li> <a href="#relaying"> What clients to relay mail for </a>
</ul>
</dl>
+<a name="relaying"> <h2> What clients to relay mail for </h2> </a>
+
+By default, Postfix will relay mail for clients in relay authorized
+networks and in relay authorized domains.
+
+<p>
+
+Relay authorized client networks are defined by the <a
+href="#mynetworks">mynetworks</a> parameter. The default is to
+relay authorize all clients in all class A, B or C networks that
+are attached to the machine.
+
+<p>
+
+<b>YOU MUST <a href="#mynetworks">CHANGE</a> THIS DEFAULT SETTING
+IF YOUR ADDRESS BLOCK IS PART OF A LARGER ADDRESS RANGE THAT IS
+OWNED BY YOUR PROVIDER - IT WOULD CAUSE POSTFIX TO RELAY MAIL FROM
+ALL THEIR CUSTOMERS</b>.
+
+<p>
+
+Relay authorized client domains are by defined by the <a
+href="uce.html#relay_domains"> relay_domains</a> comfiguration
+parameter. The default setting trusts clients with hostnames below
+the domain(s) listed in <a href="#mydestination">mydestination</a>.
+
<a name="notify"> <h2> What trouble to report to the postmaster
</h2> </a>
The <b>mynetworks</b> parameter lists all networks that this machine
is attached to. This information can be used by the <a href="uce.html">
-anti-UCE</a> features to distinguish between local systems and
-strangers.
+anti-UCE</a> features to distinguish between relay authorized
+clients and relay unauthorized strangers.
<p>
that the machine is attached to. For example, for my machines at
home, the result is: <b>168.100.0.0/16 127.0.0.0/8. </b> However,
network <b>168.100</b> is owned by my ISP. Of course I do not want
-to consider all their customer systems as local, so I use instead:
+to consider all their customer systems as relay authorized clients,
+so I use instead:
<dl>
mynetworks.o: ../../include/vstring.h
mynetworks.o: ../../include/vbuf.h
mynetworks.o: ../../include/inet_addr_list.h
+mynetworks.o: ../../include/name_mask.h
mynetworks.o: own_inet_addr.h
+mynetworks.o: mail_params.h
mynetworks.o: mynetworks.h
mypwd.o: mypwd.c
mypwd.o: ../../include/sys_defs.h
/* char *var_relay_domains;
/* char *var_fflush_domains;
/* char *var_def_transport;
+/* char *var_mynetworks_style;
/*
/* char *var_import_environ;
/* char *var_export_environ;
char *var_relay_domains;
char *var_fflush_domains;
char *var_def_transport;
+char *var_mynetworks_style;
char *var_import_environ;
char *var_export_environ;
VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0,
VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0,
VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 0, 0,
+ VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0,
0,
};
static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
#define VAR_MYNETWORKS "mynetworks"
extern char *var_mynetworks;
+#define VAR_MYNETWORKS_STYLE "mynetworks_style"
+#define DEF_MYNETWORKS_STYLE MYNETWORKS_STYLE_SUBNET
+extern char *var_mynetworks_style;
+
+#define MYNETWORKS_STYLE_CLASS "class"
+#define MYNETWORKS_STYLE_SUBNET "subnet"
+#define MYNETWORKS_STYLE_HOST "host"
+
#define VAR_RELAY_DOMAINS "relay_domains"
#define DEF_RELAY_DOMAINS "$mydestination"
extern char *var_relay_domains;
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20010222"
+#define DEF_MAIL_VERSION "Snapshot-20010224"
extern char *var_mail_version;
/* LICENSE
/* DESCRIPTION
/* This routine uses the address list built by own_inet_addr()
/* to produce a list of patterns that match the corresponding
-/* networks. The patterns are conservative: they match whole
-/* class A, B, C or D networks. This is usually sufficient to
-/* distinguish between organizations.
+/* networks.
+/*
+/* The interface list is specified with the "inet_interfaces"
+/* configuration parameter.
+/*
+/* The address to netblock conversion style is specified with
+/* the "mynetworks_style" parameter: one of "class" (match
+/* whole class A, B, C or D networks), "subnet" (match local
+/* subnets), or "host" (match local interfaces only).
/* LICENSE
/* .ad
/* .fi
#include <msg.h>
#include <vstring.h>
#include <inet_addr_list.h>
+#include <name_mask.h>
/* Global library. */
#include <own_inet_addr.h>
+#include <mail_params.h>
#include <mynetworks.h>
+/* Application-specific. */
+
+#define MASK_STYLE_CLASS (1 << 0)
+#define MASK_STYLE_SUBNET (1 << 1)
+#define MASK_STYLE_HOST (1 << 2)
+
+static NAME_MASK mask_styles[] = {
+ MYNETWORKS_STYLE_CLASS, MASK_STYLE_CLASS,
+ MYNETWORKS_STYLE_SUBNET, MASK_STYLE_SUBNET,
+ MYNETWORKS_STYLE_HOST, MASK_STYLE_HOST,
+ 0,
+};
+
/* mynetworks - return patterns that match my own networks */
const char *mynetworks(void)
if (result == 0) {
char *myname = "mynetworks";
INET_ADDR_LIST *my_addr_list;
+ INET_ADDR_LIST *my_mask_list;
unsigned long addr;
unsigned long mask;
struct in_addr net;
int shift;
+ int junk;
int i;
+ int mask_style;
+
+ mask_style = name_mask("mynetworks mask style", mask_styles,
+ var_mynetworks_style);
result = vstring_alloc(20);
my_addr_list = own_inet_addr_list();
+ my_mask_list = own_inet_mask_list();
for (i = 0; i < my_addr_list->used; i++) {
addr = ntohl(my_addr_list->addrs[i].s_addr);
- if (IN_CLASSA(addr)) {
- mask = IN_CLASSA_NET;
- shift = IN_CLASSA_NSHIFT;
- } else if (IN_CLASSB(addr)) {
- mask = IN_CLASSB_NET;
- shift = IN_CLASSB_NSHIFT;
- } else if (IN_CLASSC(addr)) {
- mask = IN_CLASSC_NET;
- shift = IN_CLASSC_NSHIFT;
- } else if (IN_CLASSD(addr)) {
- mask = IN_CLASSD_NET;
- shift = IN_CLASSD_NSHIFT;
- } else {
- msg_fatal("%s: bad address class: %s",
- myname, inet_ntoa(my_addr_list->addrs[i]));
+ mask = ntohl(my_mask_list->addrs[i].s_addr);
+
+ switch (mask_style) {
+
+ /*
+ * Natural mask. This is dangerous if you're customer of an
+ * ISP who gave you a small portion of their network.
+ */
+ case MASK_STYLE_CLASS:
+ if (IN_CLASSA(addr)) {
+ mask = IN_CLASSA_NET;
+ shift = IN_CLASSA_NSHIFT;
+ } else if (IN_CLASSB(addr)) {
+ mask = IN_CLASSB_NET;
+ shift = IN_CLASSB_NSHIFT;
+ } else if (IN_CLASSC(addr)) {
+ mask = IN_CLASSC_NET;
+ shift = IN_CLASSC_NSHIFT;
+ } else if (IN_CLASSD(addr)) {
+ mask = IN_CLASSD_NET;
+ shift = IN_CLASSD_NSHIFT;
+ } else {
+ msg_fatal("%s: bad address class: %s",
+ myname, inet_ntoa(my_addr_list->addrs[i]));
+ }
+ break;
+
+ /*
+ * Subnet mask. This is safe, but breaks backwards
+ * compatibility when used as default setting.
+ */
+ case MASK_STYLE_SUBNET:
+ for (junk = mask, shift = BITS_PER_ADDR; junk != 0; shift--, (junk <<= 1))
+ /* void */ ;
+ break;
+
+ /*
+ * Host only. Do not relay authorize other hosts.
+ */
+ case MASK_STYLE_HOST:
+ mask = ~0;
+ shift = 0;
+ break;
+
+ default:
+ msg_panic("unknown mynetworks mask style: %s",
+ var_mynetworks_style);
}
net.s_addr = htonl(addr & mask);
vstring_sprintf_append(result, "%s/%d ",
#ifdef TEST
char *var_inet_interfaces;
+char *var_mynetworks_style;
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
- if (argc != 2)
- msg_fatal("usage: %s interface_list", argv[0]);
+ if (argc != 3)
+ msg_fatal("usage: %s mask_style interface_list", argv[0]);
msg_verbose = 10;
- var_inet_interfaces = argv[1];
+ var_inet_interfaces = argv[2];
+ var_mynetworks_style = argv[1];
mynetworks();
}
/* struct in_addr *addr;
/*
/* INET_ADDR_LIST *own_inet_addr_list()
+/*
+/* INET_ADDR_LIST *own_inet_mask_list()
/* DESCRIPTION
/* own_inet_addr() determines if the specified IP address belongs
/* to this mail system instance, i.e. if this mail system instance
/*
/* own_inet_addr_list() returns the list of all addresses that
/* belong to this mail system instance.
+/*
+/* own_inet_mask_list() returns the list of all corresponding
+/* netmasks.
/* LICENSE
/* .ad
/* .fi
/* Application-specific. */
static INET_ADDR_LIST addr_list;
+static INET_ADDR_LIST mask_list;
/* own_inet_addr_init - initialize my own address list */
-static void own_inet_addr_init(INET_ADDR_LIST *addr_list)
+static void own_inet_addr_init(INET_ADDR_LIST *addr_list,
+ INET_ADDR_LIST *mask_list)
{
+ INET_ADDR_LIST local_addrs;
+ INET_ADDR_LIST local_masks;
char *hosts;
char *host;
char *sep = " \t,";
char *bufp;
+ int nvirtual;
+ int nlocal;
inet_addr_list_init(addr_list);
+ inet_addr_list_init(mask_list);
/*
* If we are listening on all interfaces (default), ask the system what
* the interfaces are.
*/
if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) {
- if (inet_addr_local(addr_list) == 0)
+ if (inet_addr_local(addr_list, mask_list) == 0)
msg_fatal("could not find any active network interfaces");
#if 0
if (addr_list->used == 1)
msg_fatal("config variable %s: host not found: %s",
VAR_INET_INTERFACES, host);
myfree(hosts);
+
+ inet_addr_list_init(&local_addrs);
+ inet_addr_list_init(&local_masks);
+ if (inet_addr_local(&local_addrs, &local_masks) == 0)
+ msg_fatal("could not find any active network interfaces");
+ for (nvirtual = 0; nvirtual < addr_list->used; nvirtual++) {
+ for (nlocal = 0; /* see below */ ; nlocal++) {
+ if (nlocal >= local_addrs.used)
+ msg_fatal("parameter %s: no local interface found for %s",
+ VAR_INET_INTERFACES,
+ inet_ntoa(addr_list->addrs[nvirtual]));
+ if (addr_list->addrs[nvirtual].s_addr
+ == local_addrs.addrs[nlocal].s_addr) {
+ inet_addr_list_append(mask_list, &local_masks.addrs[nlocal]);
+ break;
+ }
+ }
+ }
+ inet_addr_list_free(&local_addrs);
+ inet_addr_list_free(&local_masks);
}
}
int i;
if (addr_list.used == 0)
- own_inet_addr_init(&addr_list);
+ own_inet_addr_init(&addr_list, &mask_list);
for (i = 0; i < addr_list.used; i++)
if (addr->s_addr == addr_list.addrs[i].s_addr)
INET_ADDR_LIST *own_inet_addr_list(void)
{
if (addr_list.used == 0)
- own_inet_addr_init(&addr_list);
+ own_inet_addr_init(&addr_list, &mask_list);
return (&addr_list);
}
+
+/* own_inet_mask_list - return list of addresses */
+
+INET_ADDR_LIST *own_inet_mask_list(void)
+{
+ if (addr_list.used == 0)
+ own_inet_addr_init(&addr_list, &mask_list);
+
+ return (&mask_list);
+}
*/
extern int own_inet_addr(struct in_addr *);
extern struct INET_ADDR_LIST *own_inet_addr_list(void);
+extern struct INET_ADDR_LIST *own_inet_mask_list(void);
/* LICENSE
/* .ad
static const char *check_mynetworks(void)
{
- if (var_inet_interfaces == 0)
- var_inet_interfaces = mystrdup(DEF_INET_INTERFACES);
+ const char *junk;
+
+ if (var_inet_interfaces == 0) {
+ if ((mode & SHOW_DEFS)
+ || !(junk = mail_conf_lookup(VAR_INET_INTERFACES)))
+ junk = DEF_INET_INTERFACES;
+ var_inet_interfaces = mystrdup(junk);
+ }
+ if (var_mynetworks_style == 0) {
+ if ((mode & SHOW_DEFS)
+ || !(junk = mail_conf_lookup(VAR_MYNETWORKS_STYLE)))
+ junk = DEF_MYNETWORKS_STYLE;
+ var_mynetworks_style = mystrdup(junk);
+ }
return (mynetworks());
}
/* SYNOPSIS
/* #include <inet_addr_local.h>
/*
-/* int inet_addr_local(list)
-/* INET_ADDR_LIST *list;
+/* int inet_addr_local(addr_list, mask_list)
+/* INET_ADDR_LIST *addr_list;
+/* INET_ADDR_LIST *mask_list;
/* DESCRIPTION
/* inet_addr_local() determines all active IP interface addresses
/* of the local system. Any address found is appended to the
/* specified address list. The result value is the number of
/* active interfaces found.
+/*
+/* The mask_list is either a null pointer, or it is an list
+/* that receives the netmasks corresponding to the address list.
/* DIAGNOSTICS
/* Fatal errors: out of memory.
/* SEE ALSO
/* inet_addr_local - find all IP addresses for this host */
-int inet_addr_local(INET_ADDR_LIST *addr_list)
+int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list)
{
char *myname = "inet_addr_local";
struct ifconf ifc;
for (ifr = ifc.ifc_req; ifr < the_end;) {
if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */
addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
- if (addr.s_addr != INADDR_ANY) /* has IP address */
+ if (addr.s_addr != INADDR_ANY) { /* has IP address */
inet_addr_list_append(addr_list, &addr);
+ if (mask_list) {
+ if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
+ msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);
+ addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
+ inet_addr_list_append(mask_list, &addr);
+ }
+ }
}
ifr = NEXT_INTERFACE(ifr);
}
int main(int unused_argc, char **argv)
{
INET_ADDR_LIST addr_list;
+ INET_ADDR_LIST mask_list;
int i;
msg_vstream_init(argv[0], VSTREAM_ERR);
inet_addr_list_init(&addr_list);
- inet_addr_local(&addr_list);
+ inet_addr_list_init(&mask_list);
+ inet_addr_local(&addr_list, &mask_list);
if (addr_list.used == 0)
msg_fatal("cannot find any active network interfaces");
if (addr_list.used == 1)
msg_warn("found only one active network interface");
- for (i = 0; i < addr_list.used; i++)
- vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i]));
+ for (i = 0; i < addr_list.used; i++) {
+ vstream_printf("%s/", inet_ntoa(addr_list.addrs[i]));
+ vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i]));
+ }
vstream_fflush(VSTREAM_OUT);
inet_addr_list_free(&addr_list);
+ inet_addr_list_free(&mask_list);
}
#endif
/*
* External interface.
*/
-extern int inet_addr_local(INET_ADDR_LIST *);
+extern int inet_addr_local(INET_ADDR_LIST *, INET_ADDR_LIST *);
/* LICENSE
/* .ad
/* safe_open_exist - open existing file */
static VSTREAM *safe_open_exist(const char *path, int flags,
- struct stat * fstat_st, VSTRING * why)
+ struct stat * fstat_st, VSTRING *why)
{
struct stat local_statbuf;
struct stat lstat_st;
* slowed down by arbitrary amounts, and there it would make sense to
* compare even more file attributes, such as the inode generation number
* on systems that have one.
+ *
+ * Grr. Solaris /dev/whatever is a symlink. We'll have to make an exception
+ * for symlinks owned by root. NEVER, NEVER, make exceptions for symlinks
+ * owned by a non-root user. This would open a security hole when
+ * delivering mail to a world-writable mailbox directory.
*/
- else if (lstat(path, &lstat_st) < 0
- || fstat_st->st_dev != lstat_st.st_dev
- || fstat_st->st_ino != lstat_st.st_ino
+ else if (lstat(path, &lstat_st) < 0) {
+ vstring_sprintf(why, "file status changed unexpectedly: %m");
+ } else if (S_ISLNK(lstat_st.st_mode)) {
+ if (lstat_st.st_uid == 0)
+ return (fp);
+ vstring_sprintf(why, "file is a symbolic link");
+ } else if (fstat_st->st_dev != lstat_st.st_dev
+ || fstat_st->st_ino != lstat_st.st_ino
#ifdef HAS_ST_GEN
- || fstat_st->st_gen != lstat_st.st_gen
+ || fstat_st->st_gen != lstat_st.st_gen
#endif
- || fstat_st->st_nlink != lstat_st.st_nlink
- || fstat_st->st_mode != lstat_st.st_mode) {
- vstring_sprintf(why, "%s", S_ISLNK(lstat_st.st_mode) ?
- "file is a symbolic link" : "file status changed unexpectedly");
+ || fstat_st->st_nlink != lstat_st.st_nlink
+ || fstat_st->st_mode != lstat_st.st_mode) {
+ vstring_sprintf(why, "file status changed unexpectedly");
}
/*
/* safe_open_create - create new file */
static VSTREAM *safe_open_create(const char *path, int flags, int mode,
- struct stat * st, uid_t user, uid_t group, VSTRING * why)
+ struct stat * st, uid_t user, uid_t group, VSTRING *why)
{
VSTREAM *fp;
/* safe_open - safely open or create file */
VSTREAM *safe_open(const char *path, int flags, int mode,
- struct stat * st, uid_t user, gid_t group, VSTRING * why)
+ struct stat * st, uid_t user, gid_t group, VSTRING *why)
{
VSTREAM *fp;
#define S_ISSOCK(mode) (((mode) & (_S_IFMT)) == (_S_IFSOCK))
#define S_ISFIFO(mode) (((mode) & (_S_IFMT)) == (_S_IFIFO))
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
+#define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK))
#endif
#ifdef MISSING_POSIX_S_MODES