[Nut-upsuser] Problem after reboot

Peter Selinger selinger at mathstat.dal.ca
Thu Mar 2 16:44:54 UTC 2006

Arjen de Korte wrote:
> > I tried running the driver on its own:
> >
> > destiny:/usr/local/ups/bin# ./apcsmart /dev/ttyS0 -x cable=3D940-0024C
> > Network UPS Tools (version 2.0.2) - APC Smart protocol driver
> >          Driver version 1.99.7, command table version 2.0
> > getpwnam(nut): Success
> > destiny:/usr/local/ups/bin#
> >
> > which points to me there's a problem with upsdrvctl somehow.
> No. The 'getpwnam(nut): Success' should not be displayed by the driver as
> far as I can tell. Throughout the sources, the word 'getpwnam' is only
> used to display a fatal error when NUT isn't able to locate a userid, in
> this case for 'nut'. Where this 'Success' is coming from, is beyond me.

The reason for "Success" is that the code calls 

 fatal("getpwnam(%s)", user);

and not 

 fatalx("getpwnam(%s)", user);

While this fact is not widely documented, the only difference between
the (badly named) procedures fatal() and fatalx() is that fatal()
prints an error message based on errno, whereas fatalx() does not.  So
one should only call fatal() in the case of an error condition that
has actually set errno.

The problem with the getpwnam() function is that POSIX does not
consider "not found" an error condition, and therefore, many
implementations do not set errno to anything if a user was not found.
(It will however set errno on some other possible errors). So what one
should do is set errno=0 before calling getpwnam(), then check
afterwards if the return value is NULL, and if yes, whether errno!=0. 
If the return value is NULL, but errno==0, then the user was not found. 

The attached patch is a possible fix.  It would give the error message
"no such file or directory" in the above situation, which is not very
helpful, but better than "Success".

Index: common/common.c
--- common/common.c	(revision 361)
+++ common/common.c	(working copy)
@@ -99,7 +99,22 @@
 /* do this here to keep pwd/grp stuff out of the main files */
 struct passwd *get_user_pwent(const char *name)
-	return getpwnam(name);
+	struct passwd *r;
+	errno = 0;
+	r = getpwnam(name);
+	if (r) {
+		return r;
+	} else if (errno != 0) {
+		return NULL;
+	} else {
+		/* POSIX does not specify that "user not found" is an
+		   error, so some implementations of getpwnam() do not
+		   set errno when this happens. So we do it
+		   manually. There is no official error code for "user
+		   not found", so we use ENOENT ("no such file or
+		   directory"). */
+		errno = ENOENT;
+	}
 /* change to the user defined in the struct */

More information about the Nut-upsuser mailing list