* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)conf.c 8.37 (Berkeley) %G%";
** CONF.C -- Sendmail Configuration Tables.
** Defines the configuration of this installation.
** Configuration Variables:
** HdrInfo -- a table describing well-known header fields.
** Each entry has the field name and some flags,
** which are described in sendmail.h.
** I have tried to put almost all the reasonable
** configuration information into the configuration
** file read at runtime. My intent is that anything
** here is a function of the version of UNIX you
** are running, or is really static -- for example
** the headers are a superset of widely used
** protocols. If you find yourself playing with
** this file too much, you may be making a mistake!
** Final (null) entry contains the flags used for any other field.
** Not all of these are actually handled specially by sendmail
** at this time. They are included as placeholders, to let
** you know that "someday" I intend to have sendmail do
struct hdrinfo HdrInfo
[] =
/* originator fields, most to least significant */
"resent-sender", H_FROM
|H_RESENT
,
"resent-from", H_FROM
|H_RESENT
,
"resent-reply-to", H_FROM
|H_RESENT
,
"return-receipt-to", H_FROM
/* |H_RECEIPTTO */,
"errors-to", H_FROM
|H_ERRORSTO
,
"resent-to", H_RCPT
|H_RESENT
,
"resent-cc", H_RCPT
|H_RESENT
,
"resent-bcc", H_RCPT
|H_ACHECK
|H_RESENT
,
/* message identification and control */
"resent-message-id", H_RESENT
,
"received", H_TRACE
|H_FORCE
,
"x400-received", H_TRACE
|H_FORCE
,
"mail-from", H_TRACE
|H_FORCE
,
/* miscellaneous fields */
"return-path", H_FORCE
|H_ACHECK
,
** Location of system files/databases/etc.
char *PidFile
= _PATH_SENDMAILPID
; /* stores daemon proc id */
struct prival PrivacyValues
[] =
"needmailhelo", PRIV_NEEDMAILHELO
,
"needexpnhelo", PRIV_NEEDEXPNHELO
,
"needvrfyhelo", PRIV_NEEDVRFYHELO
,
"restrictmailq", PRIV_RESTRICTMAILQ
,
"restrictqrun", PRIV_RESTRICTQRUN
,
"authwarnings", PRIV_AUTHWARNINGS
,
int DtableSize
= 50; /* max open files; reset in 4.2bsd */
** SETDEFAULTS -- set default values
** Because of the way freezing is done, these must be initialized
** e -- the default envelope.
** Initializes a bunch of global variables to their
#define DAYS * 24 * 60 * 60
SpaceSub
= ' '; /* option B */
QueueLA
= 8; /* option x */
RefuseLA
= 12; /* option X */
WkRecipFact
= 30000L; /* option y */
WkClassFact
= 1800L; /* option z */
WkTimeFact
= 90000L; /* option Z */
QueueFactor
= WkRecipFact
* 20; /* option q */
FileMode
= (RealUid
!= geteuid()) ? 0644 : 0600;
DefUid
= 1; /* option u */
DefGid
= 1; /* option g */
CheckpointInterval
= 10; /* option C */
MaxHopCount
= 25; /* option h */
e
->e_sendmode
= SM_FORK
; /* option d */
e
->e_errormode
= EM_PRINT
; /* option e */
SevenBit
= FALSE
; /* option 7 */
MaxMciCache
= 1; /* option k */
MciCacheTimeout
= 300; /* option K */
LogLevel
= 9; /* option L */
settimeouts(NULL
); /* option r */
TimeOuts
.to_q_return
= 5 DAYS
; /* option T */
TimeOuts
.to_q_warning
= 0; /* option T */
PrivacyFlags
= 0; /* option p */
** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups())
static char defuserbuf
[40];
if ((defpwent
= getpwuid(DefUid
)) != NULL
)
strcpy(defuserbuf
, defpwent
->pw_name
);
strcpy(defuserbuf
, "nobody");
** HOST_MAP_INIT -- initialize host class structures
while (isascii(*p
) && isspace(*p
))
while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
if (map
->map_app
!= NULL
)
map
->map_app
= newstr(map
->map_app
);
** SETUPMAILERS -- initialize default mailers
strcpy(buf
, "prog, P=/bin/sh, F=lsD, A=sh -c $u");
strcpy(buf
, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE");
strcpy(buf
, "*include*, P=/dev/null, F=su, A=INCLUDE");
** SETUPMAPS -- set up map classes
#define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \
extern bool parse __P((MAP *, char *)); \
extern bool open __P((MAP *, int)); \
extern void close __P((MAP *)); \
extern char *lookup __P((MAP *, char *, char **, int *)); \
extern void store __P((MAP *, char *, char *)); \
s = stab(name, ST_MAPCLASS, ST_ENTER); \
s->s_mapclass.map_cname = name; \
s->s_mapclass.map_ext = ext; \
s->s_mapclass.map_cflags = flags; \
s->s_mapclass.map_parse = parse; \
s->s_mapclass.map_open = open; \
s->s_mapclass.map_close = close; \
s->s_mapclass.map_lookup = lookup; \
s->s_mapclass.map_store = store; \
MAPDEF("hash", ".db", MCF_ALIASOK
|MCF_REBUILDABLE
,
map_parseargs
, hash_map_open
, db_map_close
,
db_map_lookup
, db_map_store
);
MAPDEF("btree", ".db", MCF_ALIASOK
|MCF_REBUILDABLE
,
map_parseargs
, bt_map_open
, db_map_close
,
db_map_lookup
, db_map_store
);
MAPDEF("dbm", ".dir", MCF_ALIASOK
|MCF_REBUILDABLE
,
map_parseargs
, ndbm_map_open
, ndbm_map_close
,
ndbm_map_lookup
, ndbm_map_store
);
MAPDEF("nis", NULL
, MCF_ALIASOK
,
map_parseargs
, nis_map_open
, nis_map_close
,
nis_map_lookup
, nis_map_store
);
MAPDEF("stab", NULL
, MCF_ALIASOK
|MCF_ALIASONLY
,
map_parseargs
, stab_map_open
, stab_map_close
,
stab_map_lookup
, stab_map_store
);
MAPDEF("implicit", NULL
, MCF_ALIASOK
|MCF_ALIASONLY
|MCF_REBUILDABLE
,
map_parseargs
, impl_map_open
, impl_map_close
,
impl_map_lookup
, impl_map_store
);
host_map_init
, null_map_open
, null_map_close
,
host_map_lookup
, null_map_store
);
MAPDEF("dequote", NULL
, 0,
dequote_init
, null_map_open
, null_map_close
,
dequote_map
, null_map_store
);
udb_map_parse
, null_map_open
, null_map_close
,
udb_map_lookup
, null_map_store
);
** USERNAME -- return the user id of the logged in user.
** The login name of the logged in user.
** The return value is statically allocated.
static char *myname
= NULL
;
register struct passwd
*pw
;
if (myname
== NULL
|| myname
[0] == '\0')
myname
= newstr(pw
->pw_name
);
if ((pw
= getpwnam(myname
)) == NULL
||
(uid
!= 0 && uid
!= pw
->pw_uid
))
myname
= newstr(pw
->pw_name
);
if (myname
== NULL
|| myname
[0] == '\0')
syserr("554 Who are you?");
** TTYPATH -- Get the path of the user's tty
** Returns the pathname of the user's tty. Returns NULL if
** the user is not logged in or if s/he has write permission
** pathname of the user's tty.
** NULL if not logged in or write permission denied.
** Return value is in a local buffer.
/* compute the pathname of the controlling tty */
if ((pathn
= ttyname(2)) == NULL
&& (pathn
= ttyname(1)) == NULL
&&
(pathn
= ttyname(0)) == NULL
)
/* see if we have write permission */
if (stat(pathn
, &stbuf
) < 0 || !bitset(02, stbuf
.st_mode
))
/* see if the user is logged in */
** CHECKCOMPAT -- check for From and To person compatible.
** This routine can be supplied on a per-installation basis
** to determine whether a person is allowed to send a message.
** This allows restriction of certain types of internet
** forwarding or registration of users.
** If the hosts are found to be incompatible, an error
** message should be given using "usrerr" and 0 should
** 'NoReturn' can be set to suppress the return-to-sender
** function; this should be done on huge messages.
** to -- the person being sent to.
** none (unless you include the usrerr stuff)
printf("checkcompat(to=%s, from=%s)\n",
to
->q_paddr
, e
->e_from
.q_paddr
);
/* this code is intended as an example only */
s
= stab("arpa", ST_MAILER
, ST_FIND
);
if (s
!= NULL
&& e
->e_from
.q_mailer
!= LocalMailer
&&
to
->q_mailer
== s
->s_mailer
)
usrerr("553 No ARPA mail through this machine: see your system administration");
/* NoReturn = TRUE; to supress return copy */
# endif /* EXAMPLE_CODE */
** SETSIGNAL -- set a signal handler
** This is essentially old BSD "signal(3)".
#if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE)
return signal(sig
, handler
);
if (sigaction(sig
, &n
, &o
) < 0)
** HOLDSIGS -- arrange to hold all signals
** Arranges that signals are held.
** RLSESIGS -- arrange to release all signals
** This undoes the effect of holdsigs.
** Arranges that signals are released.
** GETLA -- get the current load average
** This code stolen from la.c.
** The current load average as an integer.
/* try to guess what style of load average we have */
#define LA_ZERO 1 /* always return load average as zero */
#define LA_INT 2 /* read kmem for avenrun; interpret as long */
#define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */
#define LA_SUBR 4 /* call getloadavg */
#define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */
#define LA_SHORT 6 /* read kmem for avenrun; interpret as short */
/* do guesses based on general OS type */
#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT)
# define LA_AVENRUN "avenrun"
# define LA_AVENRUN "_avenrun"
/* _PATH_UNIX should be defined in <paths.h> */
# define _PATH_UNIX "/unix"
# define _PATH_UNIX "/vmunix"
# if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
#if ((LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)) && !defined(FSCALE)
# define FSCALE (1 << FSHIFT)
kmem
= open("/dev/kmem", 0, 0);
printf("getla: open(/dev/kmem): %s\n",
(void) fcntl(kmem
, F_SETFD
, 1);
if (nlist(_PATH_UNIX
, Nl
) < 0)
printf("getla: nlist(%s): %s\n", _PATH_UNIX
,
if (Nl
[X_AVENRUN
].n_value
== 0)
printf("getla: nlist(%s, %s) ==> 0\n",
printf("getla: symbol address = %#x\n", Nl
[X_AVENRUN
].n_value
);
if (lseek(kmem
, (off_t
) Nl
[X_AVENRUN
].n_value
, 0) == -1 ||
read(kmem
, (char *) avenrun
, sizeof(avenrun
)) < sizeof(avenrun
))
printf("getla: lseek or read: %s\n", errstring(errno
));
#if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT)
printf("getla: avenrun = %d", avenrun
[0]);
printf(", %d, %d", avenrun
[1], avenrun
[2]);
printf("getla: %d\n", (int) (avenrun
[0] + FSCALE
/2) >> FSHIFT
);
return ((int) (avenrun
[0] + FSCALE
/2) >> FSHIFT
);
printf("getla: avenrun = %g", avenrun
[0]);
printf(", %g, %g", avenrun
[1], avenrun
[2]);
printf("getla: %d\n", (int) (avenrun
[0] +0.5));
return ((int) (avenrun
[0] + 0.5));
if (getloadavg(avenrun
, sizeof(avenrun
) / sizeof(avenrun
[0])) < 0)
perror("getla: getloadavg failed:");
printf("getla: %d\n", (int) (avenrun
[0] +0.5));
return ((int) (avenrun
[0] + 0.5));
** This has been tested on NeXT release 2.1.
processor_set_t default_set
;
struct processor_set_basic_info info
;
error
= processor_set_default(host_self(), &default_set
);
if (error
!= KERN_SUCCESS
)
info_count
= PROCESSOR_SET_BASIC_INFO_COUNT
;
if (processor_set_info(default_set
, PROCESSOR_SET_BASIC_INFO
,
&host
, (processor_set_info_t
)&info
,
&info_count
) != KERN_SUCCESS
)
return (int) (info
.load_average
+ (LOAD_SCALE
/ 2)) / LOAD_SCALE
;
** SHOULDQUEUE -- should this message be queued or sent?
** Compares the message cost to the load average to decide.
** pri -- the priority of the message in question.
** ctime -- the message creation time.
** TRUE -- if this message should be queued up for the
** FALSE -- if the load is low enough to send this message.
if (CurrentLA
>= RefuseLA
)
return (pri
> (QueueFactor
/ (CurrentLA
- QueueLA
+ 1)));
** REFUSECONNECTIONS -- decide if connections should be refused
** TRUE if incoming SMTP connections should be refused
** FALSE if we should accept new work.
/* this is probably too simplistic */
return (CurrentLA
>= RefuseLA
);
** SETPROCTITLE -- set process title for ps
** fmt -- a printf style format string. If NULL, the first
** parameter is a literal proctitle previously
** returned by getproctitle.
** va_alist -- possible parameters to fmt.
** Clobbers argv of our main procedure so ps(1) will
# include <machine/vmparam.h>
# undef PS_STRINGS /* BSDI 1.0 doesn't do PS_STRINGS as we expect */
# define SETPROC_STATIC static
char ProcTitleBuf
[MAXLINE
];
setproctitle(char *fmt
, ...)
setproctitle(fmt
, va_alist
)
/* restore old proctitle */
(void) strcpy(ProcTitleBuf
, va_arg(ap
, char *));
/* print sendmail: heading for grep */
(void) strcpy(p
, "sendmail: ");
/* print the argument string */
(void) vsprintf(p
, fmt
, ap
);
i
= strlen(ProcTitleBuf
);
if (i
> LastArgv
- Argv
[0] - 2)
i
= LastArgv
- Argv
[0] - 2;
(void) strcpy(Argv
[0], ProcTitleBuf
);
# endif /* SETPROCTITLE */
** REAPCHILD -- pick up the body of my child, lest it become a zombie
** Picks up extant zombies.
while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0)
syslog(LOG_ALERT
, "reapchild: waitpid loop: pid=%d, status=%x",
while (wait3(&status
, WNOHANG
, (struct rusage
*) NULL
) > 0)
while (wait(&status
) > 0)
(void) setsignal(SIGCHLD
, reapchild
);
** UNSETENV -- remove a variable from the environment
** Not needed on newer systems.
** name -- the string name of the environment variable to be
** deleted from the current environment.
** environ -- a pointer to the current environment.
for (pp
= environ
; *pp
!= NULL
; pp
++)
if (strncmp(name
, *pp
, len
) == 0 &&
((*pp
)[len
] == '=' || (*pp
)[len
] == '\0'))
for (; *pp
!= NULL
; pp
++)
** GETDTABLESIZE -- return number of file descriptors
** Only on non-BSD systems
** size of file descriptor table
# include <sys/resource.h>
if (getrlimit(RLIMIT_NOFILE
, &rl
) >= 0)
return sysconf(_SC_OPEN_MAX
);
** UNAME -- get the UUCP name of this system.
name
->nodename
[0] = '\0';
/* try /etc/whoami -- one line with the node name */
if ((file
= fopen("/etc/whoami", "r")) != NULL
)
(void) fgets(name
->nodename
, NODE_LENGTH
+ 1, file
);
n
= strchr(name
->nodename
, '\n');
if (name
->nodename
[0] != '\0')
/* try /usr/include/whoami.h -- has a #define somewhere */
if ((file
= fopen("/usr/include/whoami.h", "r")) != NULL
)
while (fgets(buf
, MAXLINE
, file
) != NULL
)
if (sscanf(buf
, "#define sysname \"%*[^\"]\"",
NODE_LENGTH
, name
->nodename
) > 0)
if (name
->nodename
[0] != '\0')
** Popen is known to have security holes.
/* try uuname -l to return local name */
if ((file
= popen("uuname -l", "r")) != NULL
)
(void) fgets(name
, NODE_LENGTH
+ 1, file
);
if (name
->nodename
[0] != '\0')
** INITGROUPS -- initialize groups
** Stub implementation for System V style systems
initgroups(name
, basegid
)
** SETSID -- set session id (for non-POSIX systems)
fd
= open("/dev/tty", 2);
(void) ioctl(fd
, (int) TIOCNOTTY
, (char *) 0);
return setpgid(0, getpid());
** GETOPT -- for old systems or systems with bogus implementations
* Copyright (c) 1985 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
** this version hacked to add `atend' flag to allow state machine
** to reset if invoked by the program to scan args for a 2nd time
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86";
#endif /* LIBC_SCCS and not lint */
* get option letter from argument vector
int opterr
= 1, /* if error message should be printed */
optind
= 1, /* index into parent argv vector */
optopt
; /* character checked for validity */
char *optarg
; /* argument associated with option */
#define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \
fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
static char *place
= EMSG
; /* option letter processing */
register char *oli
; /* option letter list index */
if(!*place
) { /* update scanning pointer */
if (optind
>= nargc
|| *(place
= nargv
[optind
]) != '-' || !*++place
) {
if (*place
== '-') { /* found "--" */
} /* option letter okay? */
if ((optopt
= (int)*place
++) == (int)':' || !(oli
= strchr(ostr
,optopt
))) {
tell(": illegal option -- ");
if (*++oli
!= ':') { /* don't need argument */
else { /* need an argument */
if (*place
) optarg
= place
; /* no white space */
else if (nargc
<= ++optind
) { /* no arg */
tell(": option requires an argument -- ");
else optarg
= nargv
[optind
]; /* white space */
return(optopt
); /* dump back option letter */
** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version
while (*ap
&& i
< MAXARG
)
fprintf(fp
, fmt
, bp
[0], bp
[1], bp
[2], bp
[3],
bp
[4], bp
[5], bp
[6], bp
[7],
bp
[8], bp
[9], bp
[10], bp
[11],
bp
[12], bp
[13], bp
[14], bp
[15]);
while (*ap
&& i
< MAXARG
)
sprintf(s
, fmt
, bp
[0], bp
[1], bp
[2], bp
[3],
bp
[4], bp
[5], bp
[6], bp
[7],
bp
[8], bp
[9], bp
[10], bp
[11],
bp
[12], bp
[13], bp
[14], bp
[15]);
** FREESPACE -- see how much free space is on the queue filesystem
** Only implemented if you have statfs.
** dir -- the directory in question.
** bsize -- a variable into which the filesystem
** The number of bytes free on the queue filesystem.
** -1 if the statfs call fails.
** Puts the filesystem block size into bsize.
# if defined(IRIX) || defined(apollo) || defined(_SCO_unix_)
# if (defined(sun) && !defined(BSD)) || defined(__hpux) || defined(_CONVEX_SOURCE) || defined(NeXT) || defined(_AUX_SOURCE)
#if defined(HASSTATFS) || defined(HASUSTAT)
# define FSBLOCKSIZE DEV_BSIZE
# define f_bavail f_tfree
# define f_bavail fd_bfreen
# define FSBLOCKSIZE fs.fd_bsize
# define FSBLOCKSIZE fs.f_bsize
# if defined(_SCO_unix_) || defined(IRIX)
# define f_bavail f_bfree
if (stat(dir
, &statbuf
) == 0 && ustat(statbuf
.st_dev
, &fs
) == 0)
# if defined(IRIX) || defined(apollo)
if (statfs(dir
, &fs
, sizeof fs
, 0) == 0)
if (statfs(dir
, &fs
) > 0)
if (statfs(dir
, &fs
) == 0)
** ENOUGHSPACE -- check to see if there is enough free space on the queue fs
** Only implemented if you have statfs.
** msize -- the size to check against. If zero, we don't yet
** know how big the message will be, so just check for
** a "reasonable" amount.
** TRUE if there is enough space.
if (MinBlocksFree
<= 0 && msize
<= 0)
printf("enoughspace: no threshold\n");
if ((bfree
= freespace(QueueDir
, &bsize
)) >= 0)
printf("enoughspace: bavail=%ld, need=%ld\n",
/* convert msize to block count */
msize
= msize
/ bsize
+ 1;
"%s: low on space (have %ld, %s needs %ld in %s)",
CurHostName
, msize
, QueueDir
);
printf("enoughspace failure: min=%ld, need=%ld: %s\n",
MinBlocksFree
, msize
, errstring(errno
));
** TRANSIENTERROR -- tell if an error code indicates a transient failure
** This looks at an errno value and tells if this is likely to
** go away if retried later.
** err -- the errno code to classify.
** TRUE if this is probably transient.
case EIO
: /* I/O error */
case ENXIO
: /* Device not configured */
case EAGAIN
: /* Resource temporarily unavailable */
case ENOMEM
: /* Cannot allocate memory */
case ENODEV
: /* Operation not supported by device */
case ENFILE
: /* Too many open files in system */
case EMFILE
: /* Too many open files */
case ENOSPC
: /* No space left on device */
case ETIMEDOUT
: /* Connection timed out */
case ESTALE
: /* Stale NFS file handle */
case ENETDOWN
: /* Network is down */
case ENETUNREACH
: /* Network is unreachable */
case ENETRESET
: /* Network dropped connection on reset */
case ECONNABORTED
: /* Software caused connection abort */
case ECONNRESET
: /* Connection reset by peer */
case ENOBUFS
: /* No buffer space available */
case ESHUTDOWN
: /* Can't send after socket shutdown */
case ECONNREFUSED
: /* Connection refused */
case EHOSTDOWN
: /* Host is down */
case EHOSTUNREACH
: /* No route to host */
case EDQUOT
: /* Disc quota exceeded */
case EPROCLIM
: /* Too many processes */
case EUSERS
: /* Too many users */
case EDEADLK
: /* Resource deadlock avoided */
case EISCONN
: /* Socket already connected */
case EINPROGRESS
: /* Operation now in progress */
case EALREADY
: /* Operation already in progress */
case EADDRINUSE
: /* Address already in use */
case EADDRNOTAVAIL
: /* Can't assign requested address */
#if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR))
case ENOSR
: /* Out of streams resources */
/* nope, must be permanent */
** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
** fd -- the file descriptor of the file.
** filename -- the file name (for error messages).
** ext -- the filename extension.
** type -- type of the lock. Bits can be:
** LOCK_EX -- exclusive lock.
** LOCK_NB -- non-blocking.
** TRUE if the lock was acquired.
lockfile(fd
, filename
, ext
, type
)
if (bitset(LOCK_UN
, type
))
else if (bitset(LOCK_EX
, type
))
if (bitset(LOCK_NB
, type
))
printf("lockfile(%s%s, action=%d, type=%d): ",
filename
, ext
, action
, lfd
.l_type
);
if (fcntl(fd
, action
, &lfd
) >= 0)
printf("(%s) ", errstring(errno
));
** On SunOS, if you are testing using -oQ/tmp/mqueue or
** -oA/tmp/aliases or anything like that, and /tmp is mounted
** as type "tmp" (that is, served from swap space), the
** previous fcntl will fail with "Invalid argument" errors.
** Since this is fairly common during testing, we will assume
** that this indicates that the lock is successfully grabbed.
if (!bitset(LOCK_NB
, type
) || (errno
!= EACCES
&& errno
!= EAGAIN
))
(void) fcntl(fd
, F_GETFL
, &omode
);
syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
filename
, ext
, fd
, type
, omode
, geteuid());
printf("lockfile(%s%s, type=%o): ", filename
, ext
, type
);
if (flock(fd
, type
) >= 0)
printf("(%s) ", errstring(errno
));
if (!bitset(LOCK_NB
, type
) || errno
!= EWOULDBLOCK
)
(void) fcntl(fd
, F_GETFL
, &omode
);
syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
filename
, ext
, fd
, type
, omode
, geteuid());
** GETCFNAME -- return the name of the .cf file.
** Some systems (e.g., NeXT) determine this dynamically.