Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Jan 2003 16:14:11 -0800
From:      Terry Lambert <tlambert2@mindspring.com>
To:        Craig Rodrigues <rodrigc@attbi.com>
Cc:        Garrett Wollman <wollman@lcs.mit.edu>, current@FreeBSD.ORG
Subject:   Re: getpwnam_r missing
Message-ID:  <3E1F61D3.E776697F@mindspring.com>
References:  <200301061722.58880.andy@athame.co.uk> <200301061855.h06ItO6N088838@khavrinen.lcs.mit.edu> <20030110214530.GA23411@attbi.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Craig Rodrigues wrote:
> On Mon, Jan 06, 2003 at 01:55:24PM -0500, Garrett Wollman wrote:
> > (We really should figure out how to implement the _r functions,
> > because a POSIX.1-2001 system with threads is supposed to have them.)
> 
> How do these functions need to be implemented?  Is it sufficient
> to re-implement the non-reentrant versions of these functions,
> but avoid using static data variables?  Or does there need
> to be some use of thread mutexes within the function itself?

The pointers in the returned struct passwd already point to read-only
data areas, so it's not really an issue (they are strings in the areas
mmap'ed out of the password file itself).  You would need to pass a
struct down, and fill it in, instead of returning a static struct
with the pointer.

Applications can occasionally change the contents of these areas (e.g.
"cron"), assuming that they are application private.  If a threaded
application were to do the same thing, and assume the data areas were
thread-private, then it would need to copy the data pointed to by the
pointers.  Technically, this isn't a legal thing for the application
to do; a modification should be made to ensure the mmap() is actually
done read-only, so that a fault will occur if such access is attempted
(and then someone will need to fix cron).

The negative part of this is that you can not destruct the returned
struct passwd, and automatically destruct the strings, too: because
the areas are pointers to strings, rather than character arrays (as
they were in older implementations), unless these areas are treated
as "shared, read-only" (per the previous paragraph), you will need an
explicit destructor function, which will free the allocated regions
pointed to by the pointer memberts of the structure.

This is actually not as big a deal as it seems; you can, instead,
overallocate the returned structure by the amount necessary to
contain the strings and their NUL termination, too, instead.  Then
the structure may be freed, which will free the additional memory,
as a desirable side effect (no destructor function needed), e.g.:

	struct passwd *rvp;
	char *p;

	lname = strlen(op->pw_name) + 1;
	lpasswd = strlen(op->pw_passwd) + 1;
	lclass = strlen(op->pw_class) + 1;
	lgecos = strlen(op->pw_gecos) + 1;
	ldir = strlen(op->pw_dir) + 1;
	lshell = strlen(op->pw_shell) + 1;

	rvp = (struct passwd *)malloc(sizeof(struct passwd) +
			lname + lpasswd + lclass +
			lgecos + ldir + lshell);

	if ( rvp != NULL) {
		memcpy(rvp, op, sizeof(struct passwd)); 
		p = (char *)(rvp + 1);
		memcpy( p, op->pw_name, lname);
		rvp->pw_name = p;
		p += lname;
		...
	}
	...


The other big issue is mostly for the iterator functions; the current
offset used by getpwent/setpwent/setpassent/endpwent must also be
passed to those functions; I don't believe setpassent is completely
commonplace (it's a 4.3-RENO-ism), so there are no manual pages you
can look up for it (you'll have to make something up).

In that case, you will need to re-seek on each iteration before the
read, and have to hold the lock over the seek/read pair.  Probably
you will have to eat the open/close overhead, too, unless you lock
and maintain an open instance count, and only close on the 1->0
reference transition.

-- Terry

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3E1F61D3.E776697F>