Make sure the correct errno is reported by warn* or err* and not
authorguenther <guenther@openbsd.org>
Sun, 20 Jul 2014 01:38:40 +0000 (01:38 +0000)
committerguenther <guenther@openbsd.org>
Sun, 20 Jul 2014 01:38:40 +0000 (01:38 +0000)
the errno of an intervening cleanup operation like close/unlink/etc.

Diff from Doug Hogan (doug (at) acyclic.org)

21 files changed:
bin/systrace/intercept.c
regress/lib/libc/stdio_threading/fgetln/fgetln_test.c
regress/lib/libc/stdio_threading/fgets/fgets_test.c
regress/lib/libc/stdio_threading/fputs/fputs_test.c
regress/lib/libc/stdio_threading/fread/fread_test.c
regress/lib/libc/stdio_threading/fwrite/fwrite_test.c
regress/lib/libc/stdio_threading/include/local.h
regress/sys/kern/getpeereid/getpeereid_test.c
sbin/bioctl/bioctl.c
sbin/disklabel/disklabel.c
sbin/newfs/newfs.c
sbin/restore/dirs.c
usr.bin/indent/indent.c
usr.bin/nc/netcat.c
usr.sbin/edquota/edquota.c
usr.sbin/ikectl/ikeca.c
usr.sbin/kvm_mkdb/kvm_mkdb.c
usr.sbin/lpr/common_source/startdaemon.c
usr.sbin/smtpd/enqueue.c
usr.sbin/smtpd/smtpctl.c
usr.sbin/user/user.c

index c3eb23e..00618f7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: intercept.c,v 1.61 2014/04/24 01:57:06 tedu Exp $     */
+/*     $OpenBSD: intercept.c,v 1.62 2014/07/20 01:38:40 guenther Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * All rights reserved.
@@ -356,22 +356,26 @@ intercept_run(int bg, int *fdp, uid_t uid, gid_t gid,
        
        /* Setup done, restore signal handling state */
        if (signal(SIGUSR1, ohandler) == SIG_ERR) {
+               int saved_errno = errno;
                kill(pid, SIGKILL);
-               err(1, "signal");
+               errc(1, saved_errno, "signal");
        }
        if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
+               int saved_errno = errno;
                kill(pid, SIGKILL);
-               err(1, "sigprocmask");
+               errc(1, saved_errno, "sigprocmask");
        }
 
        if (bg) {
                if (daemon(1, 1) == -1) {
+                       int saved_errno = errno;
                        kill(pid, SIGKILL);
-                       err(1, "daemon");
+                       errc(1, saved_errno, "daemon");
                }
                if ((*fdp = intercept_open()) == -1) {
+                       int saved_errno = errno;
                        kill(pid, SIGKILL);
-                       err(1, "intercept_open");
+                       errc(1, saved_errno, "intercept_open");
                }
        }
 
index 0c81583..76d154b 100755 (executable)
@@ -49,11 +49,12 @@ main(void)
        strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
        if ((fd = mkstemp(sfn)) == -1 ||
            (sfp = fdopen(fd, "w+")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1) {
                        unlink(sfn);
                        close(fd);
                }
-               err(1, "could not open temporary file");
+               errc(1, saved_errno, "could not open temporary file");
        }
 
        for (i = 0; i < 4096 * THREAD_COUNT; i++)
index c53abbc..7c5008e 100755 (executable)
@@ -48,11 +48,12 @@ main(void)
        strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
        if ((fd = mkstemp(sfn)) == -1 ||
            (sfp = fdopen(fd, "w+")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1) {
                        unlink(sfn);
                        close(fd);
                }
-               err(1, "could not open temporary file");
+               errc(1, saved_errno, "could not open temporary file");
        }
 
        for (i = 0; i < 4096 * THREAD_COUNT; i++)
index 90b6179..93d0f0b 100755 (executable)
@@ -46,11 +46,12 @@ main(void)
        strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
        if ((fd = mkstemp(sfn)) == -1 ||
            (sfp = fdopen(fd, "w+")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1) {
                        unlink(sfn);
                        close(fd);
                }
-               err(1, "could not open temporary file");
+               errc(1, saved_errno, "could not open temporary file");
        }
 
        run_threads(fputs_thread, sfp);
index c45a64d..6bd734b 100755 (executable)
@@ -50,11 +50,12 @@ main(void)
        strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
        if ((fd = mkstemp(sfn)) == -1 ||
            (sfp = fdopen(fd, "w+")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1) {
                        unlink(sfn);
                        close(fd);
                }
-               err(1, "could not open temporary file");
+               errc(1, saved_errno, "could not open temporary file");
        }
 
        for (i = 0; i < 4096 * THREAD_COUNT; i++)
index 621c5cb..86c450c 100755 (executable)
@@ -46,11 +46,12 @@ main(void)
        strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
        if ((fd = mkstemp(sfn)) == -1 ||
            (sfp = fdopen(fd, "w+")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1) {
                        unlink(sfn);
                        close(fd);
                }
-               err(1, "could not open temporary file");
+               errc(1, saved_errno, "could not open temporary file");
        }
 
        run_threads(fwrite_thread, sfp);
index 8d0e628..7a7822a 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <err.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index fe4815b..70abbac 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: getpeereid_test.c,v 1.1 2006/10/23 15:18:47 espie Exp $ */
+/* $OpenBSD: getpeereid_test.c,v 1.2 2014/07/20 01:38:40 guenther Exp $ */
 /* Written by Marc Espie in 2006 */
 /* Public domain */
 #include <sys/types.h>
@@ -85,15 +85,17 @@ server(struct sockaddr_un *sun)
        if (bind(s, (struct sockaddr *)sun, sizeof(*sun)) != 0)
                err(1, "bind");
        if (listen(s, 5) != 0) {
+               int saved_errno = errno;
                unlink(path);
                rmdir(dir);
-               err(1, "listen");
+               errc(1, saved_errno, "listen");
        }
        fd = accept(s, (struct sockaddr *)&client_addr, &client_len);
        if (fd == -1) {
+               int saved_errno = errno;
                unlink(path);
                rmdir(dir);
-               err(1, "accept");
+               errc(1, saved_errno, "accept");
        }
        problem = check_id(fd);
        if (problem)  {
index cfd5b24..97de831 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: bioctl.c,v 1.120 2014/04/22 20:42:01 tedu Exp $       */
+/* $OpenBSD: bioctl.c,v 1.121 2014/07/20 01:38:40 guenther Exp $       */
 
 /*
  * Copyright (c) 2004, 2005 Marco Peereboom
@@ -926,8 +926,9 @@ bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
                if (fd == -1)
                        err(1, "could not open %s", key_disk);
                if (fstat(fd, &sb) == -1) {
+                       int saved_errno = errno;
                        close(fd);
-                       err(1, "could not stat %s", key_disk);
+                       errc(1, saved_errno, "could not stat %s", key_disk);
                }
                close(fd);
                create.bc_key_disk = sb.st_rdev;
@@ -1026,8 +1027,9 @@ bio_parse_devlist(char *lst, dev_t *dt)
                        if (fd == -1)
                                err(1, "could not open %s", dev);
                        if (fstat(fd, &sb) == -1) {
+                               int saved_errno = errno;
                                close(fd);
-                               err(1, "could not stat %s", dev);
+                               errc(1, saved_errno, "could not stat %s", dev);
                        }
                        close(fd);
                        dt[no_dev] = sb.st_rdev;
index e3daa53..6955b45 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: disklabel.c,v 1.195 2014/05/05 16:33:34 krw Exp $     */
+/*     $OpenBSD: disklabel.c,v 1.196 2014/07/20 01:38:40 guenther Exp $        */
 
 /*
  * Copyright (c) 1987, 1993
@@ -816,9 +816,9 @@ edit(struct disklabel *lp, int f)
        u_int64_t total_sectors, starting_sector, ending_sector;
 
        if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) {
+               warn("%s", tmpfil);
                if (fd != -1)
                        close(fd);
-               warn("%s", tmpfil);
                return (1);
        }
        display(fp, lp, 0, 1);
index 27e37a0..c5dd125 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: newfs.c,v 1.96 2014/07/20 00:46:26 guenther Exp $     */
+/*     $OpenBSD: newfs.c,v 1.97 2014/07/20 01:38:40 guenther Exp $     */
 /*     $NetBSD: newfs.c,v 1.20 1996/05/16 07:13:03 thorpej Exp $       */
 
 /*
@@ -756,11 +756,12 @@ copy(char *src, char *dst, struct mfs_args *args)
                mount_args.fspec = src;
                ret = mount(MOUNT_FFS, mountpoint, MNT_RDONLY, &mount_args);
                if (ret != 0) {
+                       int saved_errno = errno;
                        if (created && rmdir(mountpoint) != 0)
                                warn("rmdir %s", mountpoint);
                        if (unmount(dst, 0) != 0)
                                warn("unmount %s", dst);
-                       err(1, "mount %s %s", src, mountpoint);
+                       errc(1, saved_errno, "mount %s %s", src, mountpoint);
                }
        }
        ret = do_exec(mountpoint, "/bin/pax", argv);
index 1ac0d93..4696627 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: dirs.c,v 1.35 2013/04/25 06:43:20 otto Exp $  */
+/*     $OpenBSD: dirs.c,v 1.36 2014/07/20 01:38:40 guenther Exp $      */
 /*     $NetBSD: dirs.c,v 1.26 1997/07/01 05:37:49 lukem Exp $  */
 
 /*
@@ -45,6 +45,7 @@
 #include <protocols/dumprestore.h>
 
 #include <err.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <paths.h>
 #include <stdio.h>
@@ -148,9 +149,11 @@ extractdirs(int genmode)
        } else
                fd = open(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666);
        if (fd == -1 || (df = fdopen(fd, "w")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1)
                        close(fd);
-               err(1, "cannot create directory temporary %s", dirfile);
+               errc(1, saved_errno,
+                   "cannot create directory temporary %s", dirfile);
        }
        if (genmode != 0) {
                (void)snprintf(modefile, sizeof(modefile), "%s/rstmode%lld",
@@ -161,9 +164,11 @@ extractdirs(int genmode)
                } else
                        fd = open(modefile, O_RDWR|O_CREAT|O_EXCL, 0666);
                if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) {
+                       int saved_errno = errno;
                        if (fd != -1)
                                close(fd);
-                       err(1, "cannot create modefile %s", modefile);
+                       errc(1, saved_errno,
+                           "cannot create modefile %s", modefile);
                }
        }
        nulldir.d_ino = 0;
index a70943b..1bff676 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: indent.c,v 1.24 2014/05/20 01:25:23 guenther Exp $    */
+/*     $OpenBSD: indent.c,v 1.25 2014/07/20 01:38:40 guenther Exp $    */
 
 /*
  * Copyright (c) 1980, 1993
@@ -1200,7 +1200,8 @@ bakcopy(void)
     /* now the original input file will be the output */
     output = fopen(in_name, "w");
     if (output == NULL) {
+       int saved_errno = errno;
        unlink(bakfile);
-       err(1, "%s", in_name);
+       errc(1, saved_errno, "%s", in_name);
     }
 }
index 76794df..5845459 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: netcat.c,v 1.121 2014/06/10 16:35:42 tedu Exp $ */
+/* $OpenBSD: netcat.c,v 1.122 2014/07/20 01:38:40 guenther Exp $ */
 /*
  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
  *
@@ -753,8 +753,9 @@ readwrite(int nfd)
                        sleep(iflag);
 
                if ((n = poll(pfd, 2 - dflag, timeout)) < 0) {
+                       int saved_errno = errno;
                        close(nfd);
-                       err(1, "Polling Error");
+                       errc(1, saved_errno, "Polling Error");
                }
 
                if (n == 0)
index e5ff38c..5e92e16 100644 (file)
@@ -153,8 +153,9 @@ main(int argc, char *argv[])
                        exit(1);
                }
                if (editit(tmpfil) == -1) {
+                       int saved_errno = errno;
                        unlink(tmpfil);
-                       err(1, "error starting editor");
+                       errc(1, saved_errno, "error starting editor");
                }
                if (readtimes(protoprivs, tmpfd))
                        putprivs(0, quotatype, protoprivs);
index de4a903..c66fbb6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ikeca.c,v 1.26 2014/04/18 21:29:20 tedu Exp $ */
+/*     $OpenBSD: ikeca.c,v 1.27 2014/07/20 01:38:40 guenther Exp $     */
 
 /*
  * Copyright (c) 2010 Jonathan Gray <jsg@openbsd.org>
@@ -473,8 +473,9 @@ fcopy(char *src, char *dst, mode_t mode)
                err(1, "open %s", src);
 
        if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
+               int saved_errno = errno;
                close(ifd);
-               err(1, "open %s", dst);
+               errc(1, saved_errno, "open %s", dst);
        }
 
        while ((r = read(ifd, buf, sizeof(buf))) > 0) {
index e33d110..cfd043a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kvm_mkdb.c,v 1.17 2009/10/27 23:59:51 deraadt Exp $   */
+/*     $OpenBSD: kvm_mkdb.c,v 1.18 2014/07/20 01:38:40 guenther Exp $  */
 
 /*-
  * Copyright (c) 1990, 1993
@@ -161,8 +161,8 @@ kvm_mkdb(int fd, const char *dbdir, char *nlistpath, char *nlistname,
                return(1);
        }
        if (create_knlist(nlistpath, fd, db) != 0) {
-               (void)unlink(dbtemp);
                warn("cannot determine executable type of %s", nlistpath);
+               (void)unlink(dbtemp);
                return(1);
        }
        if (db->close(db)) {
index ca64669..6274215 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: startdaemon.c,v 1.13 2009/10/27 23:59:51 deraadt Exp $        */
+/*     $OpenBSD: startdaemon.c,v 1.14 2014/07/20 01:38:40 guenther Exp $       */
 /*     $NetBSD: startdaemon.c,v 1.10 1998/07/18 05:04:39 lukem Exp $   */
 
 /*
@@ -67,6 +67,7 @@ startdaemon(char *printer)
        siginterrupt(SIGINT, 1);
        PRIV_START;
        if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+               int saved_errno = errno;
                if (errno == EINTR && gotintr) {
                        PRIV_END;
                        siginterrupt(SIGINT, 0);
@@ -75,7 +76,7 @@ startdaemon(char *printer)
                }
                PRIV_END;
                siginterrupt(SIGINT, 0);
-               warn("connect");
+               warnc(saved_errno, "connect");
                (void)close(s);
                return(0);
        }
index 79abcc9..5f04d90 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: enqueue.c,v 1.81 2014/06/06 15:02:08 gilles Exp $     */
+/*     $OpenBSD: enqueue.c,v 1.82 2014/07/20 01:38:40 guenther Exp $   */
 
 /*
  * Copyright (c) 2005 Henning Brauer <henning@bulabula.org>
@@ -288,11 +288,12 @@ enqueue(int argc, char *argv[])
 
        if ((fd = mkstemp(sfn)) == -1 ||
            (fp = fdopen(fd, "w+")) == NULL) {
+               int saved_errno = errno;
                if (fd != -1) {
                        unlink(sfn);
                        close(fd);
                }
-               err(EX_UNAVAILABLE, "mkstemp");
+               errc(EX_UNAVAILABLE, saved_errno, "mkstemp");
        }
        unlink(sfn);
        noheader = parse_message(stdin, fake_from == NULL, tflag, fp);
index 3a591d6..74a81b8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: smtpctl.c,v 1.123 2014/07/08 20:14:46 eric Exp $      */
+/*     $OpenBSD: smtpctl.c,v 1.124 2014/07/20 01:38:40 guenther Exp $  */
 
 /*
  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -1089,11 +1089,12 @@ display(const char *s)
 
                if ((fd = mkstemp(sfn)) == -1 ||
                    (ofp = fdopen(fd, "w+")) == NULL) {
+                       int saved_errno = errno;
                        if (fd != -1) {
                                unlink(sfn);
                                close(fd);
                        }
-                       err(1, "mkstemp");
+                       errc(1, saved_errno, "mkstemp");
                }
                unlink(sfn);
 
index 087cbfa..df04e81 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: user.c,v 1.98 2013/11/23 17:14:05 deraadt Exp $ */
+/* $OpenBSD: user.c,v 1.99 2014/07/20 01:38:40 guenther Exp $ */
 /* $NetBSD: user.c,v 1.69 2003/04/14 17:40:07 agc Exp $ */
 
 /*
@@ -38,6 +38,7 @@
 #include <ctype.h>
 #include <dirent.h>
 #include <err.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <grp.h>
 #include <login_cap.h>
@@ -341,15 +342,15 @@ creategid(char *group, gid_t gid, const char *name)
        (void) fstat(fileno(from), &st);
        (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
        if ((fd = mkstemp(f)) < 0) {
-               (void) fclose(from);
                warn("can't create gid: mkstemp failed");
+               (void) fclose(from);
                return 0;
        }
        if ((to = fdopen(fd, "w")) == NULL) {
+               warn("can't create gid: fdopen `%s' failed", f);
                (void) fclose(from);
                (void) close(fd);
                (void) unlink(f);
-               warn("can't create gid: fdopen `%s' failed", f);
                return 0;
        }
        while ((buf = fgetln(from, &len)) != NULL && len > 0) {
@@ -360,10 +361,10 @@ creategid(char *group, gid_t gid, const char *name)
                }
                if (ret == -1 ||
                    fprintf(to, "%*.*s", (int)len, (int)len, buf) != len) {
+                       warn("can't create gid: short write to `%s'", f);
                        (void) fclose(from);
                        (void) fclose(to);
                        (void) unlink(f);
-                       warn("can't create gid: short write to `%s'", f);
                        return 0;
                }
        }
@@ -372,14 +373,14 @@ creategid(char *group, gid_t gid, const char *name)
                ret = fprintf(to, "%s:*:%u:%s\n", group, gid, name);
        (void) fclose(from);
        if (fclose(to) == EOF || ret == -1) {
-               (void) unlink(f);
                warn("can't create gid: short write to `%s'", f);
+               (void) unlink(f);
                return 0;
        }
        if (rename(f, _PATH_GROUP) < 0) {
-               (void) unlink(f);
                warn("can't create gid: can't rename `%s' to `%s'", f,
                    _PATH_GROUP);
+               (void) unlink(f);
                return 0;
        }
        (void) chmod(_PATH_GROUP, st.st_mode & 07777);
@@ -413,15 +414,15 @@ modify_gid(char *group, char *newent)
        (void) fstat(fileno(from), &st);
        (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
        if ((fd = mkstemp(f)) < 0) {
-               (void) fclose(from);
                warn("can't modify gid: mkstemp failed");
+               (void) fclose(from);
                return 0;
        }
        if ((to = fdopen(fd, "w")) == NULL) {
+               warn("can't modify gid: fdopen `%s' failed", f);
                (void) fclose(from);
                (void) close(fd);
                (void) unlink(f);
-               warn("can't modify gid: fdopen `%s' failed", f);
                return 0;
        }
        groupc = strlen(group);
@@ -459,22 +460,22 @@ modify_gid(char *group, char *newent)
                        }
                }
                if (fwrite(buf, cc, 1, to) != 1) {
+                       warn("can't modify gid: short write to `%s'", f);
                        (void) fclose(from);
                        (void) fclose(to);
                        (void) unlink(f);
-                       warn("can't modify gid: short write to `%s'", f);
                        return 0;
                }
        }
        (void) fclose(from);
        if (fclose(to) == EOF) {
-               (void) unlink(f);
                warn("can't modify gid: short write to `%s'", f);
+               (void) unlink(f);
                return 0;
        }
        if (rename(f, _PATH_GROUP) < 0) {
-               (void) unlink(f);
                warn("can't modify gid: can't rename `%s' to `%s'", f, _PATH_GROUP);
+               (void) unlink(f);
                return 0;
        }
        (void) chmod(_PATH_GROUP, st.st_mode & 07777);
@@ -535,15 +536,15 @@ append_group(char *user, int ngroups, const char **groups)
        (void) fstat(fileno(from), &st);
        (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
        if ((fd = mkstemp(f)) < 0) {
-               (void) fclose(from);
                warn("can't append group: mkstemp failed");
+               (void) fclose(from);
                return 0;
        }
        if ((to = fdopen(fd, "w")) == NULL) {
+               warn("can't append group: fdopen `%s' failed", f);
                (void) fclose(from);
                (void) close(fd);
                (void) unlink(f);
-               warn("can't append group: fdopen `%s' failed", f);
                return 0;
        }
        while (fgets(buf, sizeof(buf), from) != NULL) {
@@ -586,22 +587,22 @@ append_group(char *user, int ngroups, const char **groups)
                        }
                }
                if (fwrite(buf, cc, 1, to) != 1) {
+                       warn("can't append group: short write to `%s'", f);
                        (void) fclose(from);
                        (void) fclose(to);
                        (void) unlink(f);
-                       warn("can't append group: short write to `%s'", f);
                        return 0;
                }
        }
        (void) fclose(from);
        if (fclose(to) == EOF) {
-               (void) unlink(f);
                warn("can't append group: short write to `%s'", f);
+               (void) unlink(f);
                return 0;
        }
        if (rename(f, _PATH_GROUP) < 0) {
-               (void) unlink(f);
                warn("can't append group: can't rename `%s' to `%s'", f, _PATH_GROUP);
+               (void) unlink(f);
                return 0;
        }
        (void) chmod(_PATH_GROUP, st.st_mode & 07777);
@@ -980,15 +981,17 @@ adduser(char *login_name, user_t *up)
        }
        pw_init();
        if ((ptmpfd = pw_lock(WAITSECS)) < 0) {
+               int saved_errno = errno;
                (void) close(masterfd);
-               err(EXIT_FAILURE, "can't obtain pw_lock");
+               errc(EXIT_FAILURE, saved_errno, "can't obtain pw_lock");
        }
        if ((fp = fdopen(masterfd, "r")) == NULL) {
+               int saved_errno = errno;
                (void) close(masterfd);
                (void) close(ptmpfd);
                pw_abort();
-               err(EXIT_FAILURE, "can't fdopen `%s' for reading",
-                   _PATH_MASTERPASSWD);
+               errc(EXIT_FAILURE, saved_errno,
+                   "can't fdopen `%s' for reading", _PATH_MASTERPASSWD);
        }
        while (fgets(buf, sizeof(buf), fp) != NULL) {
                cc = strlen(buf);
@@ -1002,17 +1005,21 @@ adduser(char *login_name, user_t *up)
                        break;
                }
                if (write(ptmpfd, buf, (size_t)(cc)) != cc) {
+                       int saved_errno = errno;
                        (void) fclose(fp);
                        (void) close(ptmpfd);
                        pw_abort();
-                       err(EXIT_FAILURE, "short write to /etc/ptmp (not %d chars)", cc);
+                       errc(EXIT_FAILURE, saved_errno,
+                           "short write to /etc/ptmp (not %d chars)", cc);
                }
        }
        if (ferror(fp)) {
+               int saved_errno = errno;
                (void) fclose(fp);
                (void) close(ptmpfd);
                pw_abort();
-               err(EXIT_FAILURE, "read error on %s", _PATH_MASTERPASSWD);
+               errc(EXIT_FAILURE, saved_errno, "read error on %s",
+                   _PATH_MASTERPASSWD);
        }
        /* if no uid was specified, get next one in [low_uid..high_uid] range */
        sync_uid_gid = (strcmp(up->u_primgrp, "=uid") == 0);
@@ -1132,9 +1139,10 @@ adduser(char *login_name, user_t *up)
                errx(EXIT_FAILURE, "can't add `%s', line too long", buf);
        }
        if (write(ptmpfd, buf, (size_t) cc) != cc) {
+               int saved_errno = errno;
                (void) close(ptmpfd);
                pw_abort();
-               err(EXIT_FAILURE, "can't add `%s'", buf);
+               errc(EXIT_FAILURE, saved_errno, "can't add `%s'", buf);
        }
        if (yp) {
                /* put back the + line */
@@ -1145,25 +1153,31 @@ adduser(char *login_name, user_t *up)
                        errx(EXIT_FAILURE, "can't add `%s', line too long", buf);
                }
                if (write(ptmpfd, buf, (size_t) cc) != cc) {
+                       int saved_errno = errno;
                        (void) close(ptmpfd);
                        pw_abort();
-                       err(EXIT_FAILURE, "can't add `%s'", buf);
+                       errc(EXIT_FAILURE, saved_errno, "can't add `%s'", buf);
                }
                /* copy the entries following it, if any */
                while (fgets(buf, sizeof(buf), fp) != NULL) {
                        cc = strlen(buf);
                        if (write(ptmpfd, buf, (size_t)(cc)) != cc) {
+                               int saved_errno = errno;
                                (void) fclose(fp);
                                (void) close(ptmpfd);
                                pw_abort();
-                               err(EXIT_FAILURE, "short write to /etc/ptmp (not %d chars)", cc);
+                               errc(EXIT_FAILURE, saved_errno,
+                                   "short write to /etc/ptmp (not %d chars)",
+                                   cc);
                        }
                }
                if (ferror(fp)) {
+                       int saved_errno = errno;
                        (void) fclose(fp);
                        (void) close(ptmpfd);
                        pw_abort();
-                       err(EXIT_FAILURE, "read error on %s", _PATH_MASTERPASSWD);
+                       errc(EXIT_FAILURE, saved_errno, "read error on %s",
+                           _PATH_MASTERPASSWD);
                }
        }
        if (up->u_flags & F_MKDIR) {
@@ -1174,9 +1188,11 @@ adduser(char *login_name, user_t *up)
                            home);
                } else {
                        if (asystem("%s -p %s", MKDIR, home) != 0) {
+                               int saved_errno = errno;
                                (void) close(ptmpfd);
                                pw_abort();
-                               err(EXIT_FAILURE, "can't mkdir `%s'", home);
+                               errc(EXIT_FAILURE, saved_errno,
+                                   "can't mkdir `%s'", home);
                        }
                        (void) copydotfiles(up->u_skeldir, up->u_uid, gid, home);
                        (void) asystem("%s -R -P %u:%u %s", CHOWN, up->u_uid,
@@ -1233,16 +1249,16 @@ rm_user_from_groups(char *login_name)
        (void) fstat(fileno(from), &st);
        (void) snprintf(f, sizeof(f), "%s.XXXXXXXX", _PATH_GROUP);
        if ((fd = mkstemp(f)) < 0) {
-               (void) fclose(from);
                warn("can't remove gid for `%s': mkstemp failed", login_name);
+               (void) fclose(from);
                return 0;
        }
        if ((to = fdopen(fd, "w")) == NULL) {
+               warn("can't remove gid for `%s': fdopen `%s' failed",
+                   login_name, f);
                (void) fclose(from);
                (void) close(fd);
                (void) unlink(f);
-               warn("can't remove gid for `%s': fdopen `%s' failed",
-                   login_name, f);
                return 0;
        }
        while (fgets(buf, sizeof(buf), from) != NULL) {
@@ -1281,26 +1297,26 @@ rm_user_from_groups(char *login_name)
                        }
                }
                if (fwrite(buf, strlen(buf), 1, to) != 1) {
+                       warn("can't remove gid for `%s': short write to `%s'",
+                           login_name, f);
                        (void) fclose(from);
                        (void) fclose(to);
                        (void) unlink(f);
-                       warn("can't remove gid for `%s': short write to `%s'",
-                           login_name, f);
                        return 0;
                }
        }
        (void) fchmod(fileno(to), st.st_mode & 07777);
        (void) fclose(from);
        if (fclose(to) == EOF) {
-               (void) unlink(f);
                warn("can't remove gid for `%s': short write to `%s'",
                    login_name, f);
+               (void) unlink(f);
                return 0;
        }
        if (rename(f, _PATH_GROUP) < 0) {
-               (void) unlink(f);
                warn("can't remove gid for `%s': can't rename `%s' to `%s'",
                    login_name, f, _PATH_GROUP);
+               (void) unlink(f);
                return 0;
        }
        return 1;
@@ -1394,14 +1410,17 @@ moduser(char *login_name, char *newlogin, user_t *up)
        }
        pw_init();
        if ((ptmpfd = pw_lock(WAITSECS)) < 0) {
+               int saved_errno = errno;
                (void) close(masterfd);
-               err(EXIT_FAILURE, "can't obtain pw_lock");
+               errc(EXIT_FAILURE, saved_errno, "can't obtain pw_lock");
        }
        if ((master = fdopen(masterfd, "r")) == NULL) {
+               int saved_errno = errno;
                (void) close(masterfd);
                (void) close(ptmpfd);
                pw_abort();
-               err(EXIT_FAILURE, "can't fdopen fd for %s", _PATH_MASTERPASSWD);
+               errc(EXIT_FAILURE, saved_errno, "can't fdopen fd for %s",
+                   _PATH_MASTERPASSWD);
        }
        if (up != NULL) {
                if (up->u_flags & F_USERNAME) {
@@ -1585,18 +1604,22 @@ moduser(char *login_name, char *newlogin, user_t *up)
                                            newlogin));
                                }
                                if (write(ptmpfd, buf, len) != len) {
+                                       int saved_errno = errno;
                                        (void) close(ptmpfd);
                                        pw_abort();
-                                       err(EXIT_FAILURE, "can't add `%s'", buf);
+                                       errc(EXIT_FAILURE, saved_errno,
+                                           "can't add `%s'", buf);
                                }
                        }
                } else {
                        len = strlen(buf);
                        if ((cc = write(ptmpfd, buf, len)) != len) {
+                               int saved_errno = errno;
                                (void) close(masterfd);
                                (void) close(ptmpfd);
                                pw_abort();
-                               err(EXIT_FAILURE, "short write to /etc/ptmp (%lld not %lld chars)",
+                               errc(EXIT_FAILURE, saved_errno,
+                                   "short write to /etc/ptmp (%lld not %lld chars)",
                                    (long long)cc, (long long)len);
                        }
                }
@@ -1604,10 +1627,11 @@ moduser(char *login_name, char *newlogin, user_t *up)
        if (up != NULL) {
                if ((up->u_flags & F_MKDIR) &&
                    asystem("%s %s %s", MV, homedir, pwp->pw_dir) != 0) {
+                       int saved_errno = errno;
                        (void) close(ptmpfd);
                        pw_abort();
-                       err(EXIT_FAILURE, "can't move `%s' to `%s'",
-                           homedir, pwp->pw_dir);
+                       errc(EXIT_FAILURE, saved_errno,
+                           "can't move `%s' to `%s'", homedir, pwp->pw_dir);
                }
                if (up->u_flags & F_SETSECGROUP) {
                    for (i = 0 ; i < up->u_groupc ; i++) {