Subject: nsswitch / nsdispatch(3) cleanup ...
To: None <tech-userlevel@NetBSD.org>
From: Luke Mewburn <lukem@NetBSD.org>
List: tech-userlevel
Date: 09/27/2004 19:31:58
--sHrvAb52M6C8blB9
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi all.

We now have generic support for dynamic nsswitch back-ends,
based on work in FreeBSD by Jacques A. Vidrine, and
integrated by Jason Thorpe.

I've been working on a winbind nsswitch backend (for Samba 3),
and realised that the use of nsdispatch(3) in libc/gen/getpwent.c
and libc/gen/getgrent.c is ... suboptimal.  We currently
nsdispatch to internal methods with an internal API that is not
suited to make publically available for use in dynamic modules.=20
(E.g, look at nsdispatch(3)'s use within getgrent.c)

To recap, an nsswitch method has the API:
	typedef int (*nss_method)(void *retval, void *cb_data, va_list ap);
(See nsdispatch(3) for more details).

We need to standardize the API used between the "standard"
functions and the nsswitch methods invoked via nsdispatch(3).
I intend to use the following convention within each method:
    1.	void *retval is a pointer to the actual return
	value for the external function.
	The method should set this as necessary.
    2.	`va_list ap' has the same layout as the external
	function's calling convention.

E.g., for getgrgid_r(3);

	static int
	dns_getgrgid_r(void *retval, void *cb_data, va_list ap)
	{
		/* int *retval */
		gid_t            gid    =3D va_arg(ap, gid_t);
		struct group    *grp    =3D va_arg(ap, struct group *);
		char            *buffer =3D va_arg(ap, char *);
		size_t           buflen =3D va_arg(ap, size_t);
		struct group   **result =3D va_arg(ap, struct group **);

		*(int *)retval =3D 0;
			/* do the work */
		return NS_SUCCESS;
	}

	int
	getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t
	    buflen, struct group **result)
	{
		int r, retval;
		static const ns_dtab dtab[] =3D {
			NS_DNS_CB(dns_getgrgid_r, NULL)
			{ 0 }
		};

		*result =3D NULL;
		r =3D nsdispatch(&retval, dtab, NSDB_GROUP,
		    "getgrgid_r", __nsdefaultsrc,=20
		    gid, grp, buffer, buflen, result);
		return (r =3D=3D NS_SUCCESS) ? 0 : retval;
	}

This simplifies the work of an implementer of a third party
libnss_foo.so module because the API of the method's va_list
is directly derived from the API of standard function that
invokes it.

I'm in the process of cleaning up getgrent(3) (et al); it's almost
ready to commit, and I have implemented getgrgid_r() and getgrnam_r()
as well.  I'll be working on getpwent(3) et all) next.


This should not have any adverse affect on backward compatibility,
because I don't envisage that anyway has yet implemented backend
methods for these functions (e.g, "grscan", "getpwcompat", ...).


As a future project I'll be provide a build framework for building
libnss_{files,dns,nis,compat}.so from the libc sources, allowing us
to not have to compile in the "static" methods by default.


Cheers,
Luke.

--sHrvAb52M6C8blB9
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (NetBSD)

iD8DBQFBV94OpBhtmn8zJHIRAl9MAKDUHIfvYaTGyMMh1dn0mEBg0WqXOgCgsWf5
7SCDe6GP5eZISDod1Jwzm0I=
=d0YY
-----END PGP SIGNATURE-----

--sHrvAb52M6C8blB9--