PERFORCE change 100398 for review

Michael Bushkov bushman at FreeBSD.org
Sat Jul 1 16:03:48 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=100398

Change 100398 by bushman at bushman_nss_ldap_cached on 2006/07/01 15:29:47

	Regression tests for "passwd" and "group" databases added. Small bug fixes in test-getserv.c

Affected files ...

.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/Makefile#3 edit
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getgr.c#3 edit
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getgr.t#1 add
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getpw.c#3 edit
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getpw.t#1 add
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getserv.c#5 edit
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getserv.t#4 edit
.. //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/testutil.h#5 edit

Differences ...

==== //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/Makefile#3 (text+ko) ====

@@ -1,6 +1,6 @@
-# $FreeBSD: src/tools/regression/lib/libc/net/Makefile,v 1.2 2005/02/12 18:09:20 ru Exp $
+# $FreeBSD$
 
-TESTS=	test-getserv
+TESTS=	test-getpw test-getgr test-getserv
 CFLAGS+= -g -Wall
 
 .PHONY: tests

==== //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getgr.c#3 (text+ko) ====

@@ -1,0 +1,534 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman at freebsd.org>
+ * All rights regrped.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+#include "testutil.h"
+
+enum test_methods {
+	TEST_GETGRENT,
+	TEST_GETGRNAM,
+	TEST_GETGRGID,
+	TEST_GETGRENT_2PASS,
+	TEST_BUILD_SNAPSHOT
+};
+
+static int debug = 0;
+static enum test_methods method = TEST_BUILD_SNAPSHOT;
+
+DECLARE_TEST_DATA(group)
+DECLARE_TEST_FILE_SNAPSHOT(group)
+DECLARE_1PASS_TEST(group)
+DECLARE_2PASS_TEST(group)
+
+static void clone_group(struct group *, struct group const *);
+static int compare_group(struct group *, struct group *, void *);
+static void dump_group(struct group *);
+static void free_group(struct group *);
+
+static void sdump_group(struct group *, char *, size_t);
+static int group_read_snapshot_func(struct group *, char *);
+
+static int group_check_ambiguity(struct group_test_data *, 
+	struct group *);
+static int group_fill_test_data(struct group_test_data *);
+static int group_test_correctness(struct group *, void *);
+static int group_test_getgrnam(struct group *, void *);
+static int group_test_getgrgid(struct group *, void *);
+static int group_test_getgrent(struct group *, void *);
+	
+static void usage(void)  __attribute__((__noreturn__));
+
+IMPLEMENT_TEST_DATA(group)
+IMPLEMENT_TEST_FILE_SNAPSHOT(group)
+IMPLEMENT_1PASS_TEST(group)
+IMPLEMENT_2PASS_TEST(group)
+
+static void
+clone_group(struct group *dest, struct group const *src)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+	
+	char **cp;
+	int members_num;
+		
+	memset(dest, 0, sizeof(struct group));
+	
+	if (src->gr_name != NULL) {
+		dest->gr_name = strdup(src->gr_name);
+		assert(dest->gr_name != NULL);
+	}
+	
+	if (src->gr_passwd != NULL) {
+		dest->gr_passwd = strdup(src->gr_passwd);
+		assert(dest->gr_passwd != NULL);
+	}
+	dest->gr_gid = src->gr_gid;
+	
+	if (src->gr_mem != NULL) {
+		members_num = 0;
+		for (cp = src->gr_mem; *cp; ++cp)
+			++members_num;
+	
+		dest->gr_mem = (char **)malloc(
+			(members_num + 1) * (sizeof(char *)));
+		assert(dest->gr_mem != NULL);
+		memset(dest->gr_mem, 0, (members_num+1) * (sizeof(char *)));
+	
+		for (cp = src->gr_mem; *cp; ++cp) {
+			dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
+			assert(dest->gr_mem[cp - src->gr_mem] != NULL);
+		}
+	}
+}
+
+static void 
+free_group(struct group *grp)
+{
+	char **cp;
+	
+	assert(grp != NULL);
+	
+	free(grp->gr_name);
+	free(grp->gr_passwd);
+	
+	for (cp = grp->gr_mem; *cp; ++cp)
+		free(*cp);
+	free(grp->gr_mem);
+}
+
+static  int 
+compare_group(struct group *grp1, struct group *grp2, void *mdata)
+{
+	char **c1, **c2;
+        
+	if (grp1 == grp2)
+		return (0);
+        
+	if ((grp1 == NULL) || (grp2 == NULL))
+		goto errfin;
+        
+	if ((strcmp(grp1->gr_name, grp2->gr_name) != 0) ||
+		(strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0) ||
+		(grp1->gr_gid != grp2->gr_gid))
+			goto errfin;
+        
+	c1 = grp1->gr_mem;
+	c2 = grp2->gr_mem;
+	
+	if ((grp1->gr_mem == NULL) || (grp2->gr_mem == NULL))
+		goto errfin;
+	
+	for (;*c1 && *c2; ++c1, ++c2)
+		if (strcmp(*c1, *c2) != 0)
+			goto errfin;
+                
+	if ((*c1 != '\0') || (*c2 != '\0'))
+		goto errfin;
+        
+	return 0;
+	
+errfin:
+	if ((debug) && (mdata == NULL)) {
+		printf("following structures are not equal:\n");
+		dump_group(grp1);
+		dump_group(grp2);
+	}
+
+	return (-1);
+}
+
+static void
+sdump_group(struct group *grp, char *buffer, size_t buflen)
+{
+	char **cp;
+	int written;
+	
+	written = snprintf(buffer, buflen, "%s %s %d",
+		grp->gr_name, grp->gr_passwd, grp->gr_gid);	
+	buffer += written;
+	if (written > buflen)
+		return;
+	buflen -= written;
+			
+	if (grp->gr_mem != NULL) {
+		if (*(grp->gr_mem) != '\0') {
+			for (cp = grp->gr_mem; *cp; ++cp) {
+				written = snprintf(buffer, buflen, " %s",*cp);
+				buffer += written;
+				if (written > buflen)
+					return;
+				buflen -= written;
+				
+				if (buflen == 0)
+					return;				
+			}
+		} else
+			snprintf(buffer, buflen, " nomem");
+	} else
+		snprintf(buffer, buflen, " (null)");
+}
+
+static int
+group_read_snapshot_func(struct group *grp, char *line)
+{
+	StringList *sl;
+	char *s, *ps, *ts;
+	int i;
+
+	if (debug)
+		printf("1 line read from snapshot:\n%s\n", line);
+	
+	i = 0;
+	sl = NULL;
+	ps = line;
+	memset(grp, 0, sizeof(struct group));
+	while ( (s = strsep(&ps, " ")) != NULL) {
+		switch (i) {
+			case 0:
+				grp->gr_name = strdup(s);
+				assert(grp->gr_name != NULL);
+			break;
+
+			case 1:
+				grp->gr_passwd = strdup(s);
+				assert(grp->gr_passwd != NULL);
+			break;
+
+			case 2:
+				grp->gr_gid = (gid_t)strtol(s, &ts, 10);
+				if (*ts != '\0') {
+					free(grp->gr_name);
+					free(grp->gr_passwd);
+					return (-1);
+				}
+			break;
+
+			default:
+				if (sl == NULL) {
+					if (strcmp(s, "(null)") == 0)
+						return (0);
+										
+					sl = sl_init();
+					assert(sl != NULL);
+					
+					if (strcmp(s, "nomem") != 0) {
+						ts = strdup(s);
+						assert(ts != NULL);
+						sl_add(sl, ts);
+					}
+				} else {
+					ts = strdup(s);
+					assert(ts != NULL);
+					sl_add(sl, ts);
+				}
+			break;			
+		};
+		++i;
+	}
+
+	if (i < 3) {
+		free(grp->gr_name);
+		free(grp->gr_passwd);
+		memset(grp, 0, sizeof(struct group));
+		return (-1);
+	}
+	
+	sl_add(sl, NULL);
+	grp->gr_mem = sl->sl_str;
+
+	/* NOTE: is it a dirty hack or not? */
+	free(sl);	
+	return (0);
+}
+
+static void 
+dump_group(struct group *result)
+{
+	if (result != NULL) {
+		char buffer[1024];
+		sdump_group(result, buffer, sizeof(buffer));
+		printf("%s\n", buffer);
+	} else
+		printf("(null)\n");
+}
+
+static int
+group_fill_test_data(struct group_test_data *td)
+{
+	struct group *grp;
+		
+	setgroupent(1);
+	while ((grp = getgrent()) != NULL) {
+		if (group_test_correctness(grp, NULL) == 0)
+			TEST_DATA_APPEND(group, td, grp);
+		else
+			return (-1);
+	}
+	endgrent();
+	
+	return (0);
+}
+
+static int
+group_test_correctness(struct group *grp, void *mdata)
+{
+	if (debug) {
+		printf("testing correctness with the following data:\n");
+		dump_group(grp);
+	}
+	
+	if (grp == NULL)
+		goto errfin;
+	
+	if (grp->gr_name == NULL)
+		goto errfin;
+	
+	if (grp->gr_passwd == NULL)
+		goto errfin;
+	
+	if (grp->gr_mem == NULL)
+		goto errfin;
+	
+	if (debug)
+		printf("correct\n");
+	
+	return (0);	
+errfin:
+	if (debug)
+		printf("incorrect\n");
+	
+	return (-1);
+}
+
+/* group_check_ambiguity() is needed here because when doing the getgrent()
+ * calls sequence, records from different nsswitch sources can be different, 
+ * though having the same pw_name/pw_uid */
+static int
+group_check_ambiguity(struct group_test_data *td, struct group *pwd)
+{
+	
+	return (TEST_DATA_FIND(group, td, pwd, compare_group,
+		NULL) != NULL ? 0 : -1);
+}
+
+static int
+group_test_getgrnam(struct group *grp_model, void *mdata)
+{
+	struct group *grp;
+		
+	if (debug) {
+		printf("testing getgrnam() with the following data:\n");
+		dump_group(grp_model);
+	}
+
+	grp = getgrnam(grp_model->gr_name);
+	if (group_test_correctness(grp, NULL) != 0)
+		goto errfin;
+	
+	if ((compare_group(grp, grp_model, NULL) != 0) &&
+	    (group_check_ambiguity((struct group_test_data *)mdata, grp) 
+	    !=0))
+	    goto errfin;
+		
+	if (debug)
+		printf("ok\n");
+	return (0);
+	
+errfin:
+	if (debug)
+		printf("not ok\n");
+	
+	return (-1);
+}
+
+static int
+group_test_getgrgid(struct group *grp_model, void *mdata)
+{
+	struct group *grp;
+		
+	if (debug) {
+		printf("testing getgrgid() with the following data...\n");
+		dump_group(grp_model);
+	}	
+	
+	grp = getgrgid(grp_model->gr_gid);
+	if ((group_test_correctness(grp, NULL) != 0) || 
+	    ((compare_group(grp, grp_model, NULL) != 0) &&
+	    (group_check_ambiguity((struct group_test_data *)mdata, grp)
+	    != 0))) {
+	    if (debug)
+		printf("not ok\n");
+	    return (-1);
+	} else {
+	    if (debug)
+		printf("ok\n");
+	    return (0);
+	}
+}
+
+static int 
+group_test_getgrent(struct group *grp, void *mdata)
+{
+	/* Only correctness can be checked when doing 1-pass test for
+	 * getgrent(). */
+	return (group_test_correctness(grp, NULL));
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr,
+	    "Usage: %s [-dnge2] [-s <file>]\n",
+	    getprogname());
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct group_test_data td, td_snap, td_2pass;
+	char *snapshot_file;
+	int rv;
+	int c;
+	
+	if (argc < 2)
+		usage();
+		
+	snapshot_file = NULL;
+	while ((c = getopt(argc, argv, "nge2ds:")) != -1)
+		switch (c) {
+		case 'd':
+			debug++;
+			break;
+		case 'n':
+			method = TEST_GETGRNAM;
+			break;
+		case 'g':
+			method = TEST_GETGRGID;
+			break;
+		case 'e':
+			method = TEST_GETGRENT;
+			break;
+		case '2':
+			method = TEST_GETGRENT_2PASS;
+			break;
+		case 's':
+			snapshot_file = strdup(optarg);
+			break;
+		default:
+			usage();
+		}
+	
+	TEST_DATA_INIT(group, &td, clone_group, free_group);
+	TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
+	if (snapshot_file != NULL) {
+		if (access(snapshot_file, W_OK | R_OK) != 0) {		
+			if (errno == ENOENT)
+				method = TEST_BUILD_SNAPSHOT;
+			else {
+				if (debug)
+					printf("can't access the file %s\n",
+				snapshot_file);
+			
+				rv = -1;
+				goto fin;
+			}
+		} else {
+			if (method == TEST_BUILD_SNAPSHOT) {
+				rv = 0;
+				goto fin;
+			}
+			
+			TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
+				&td_snap, group_read_snapshot_func);
+		}
+	}
+		
+	rv = group_fill_test_data(&td);
+	if (rv == -1)
+		return (-1);
+	switch (method) {
+	case TEST_GETGRNAM:
+		if (snapshot_file == NULL)
+			rv = DO_1PASS_TEST(group, &td,
+				group_test_getgrnam, (void *)&td);
+		else
+			rv = DO_1PASS_TEST(group, &td_snap, 
+				group_test_getgrnam, (void *)&td_snap);
+		break;
+	case TEST_GETGRGID:
+		if (snapshot_file == NULL)
+			rv = DO_1PASS_TEST(group, &td,
+				group_test_getgrgid, (void *)&td);
+		else
+			rv = DO_1PASS_TEST(group, &td_snap, 
+				group_test_getgrgid, (void *)&td_snap);
+		break;
+	case TEST_GETGRENT:
+		if (snapshot_file == NULL)
+			rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
+				(void *)&td);
+		else
+			rv = DO_2PASS_TEST(group, &td, &td_snap,
+				compare_group, NULL);
+		break;
+	case TEST_GETGRENT_2PASS:
+			TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
+			rv = group_fill_test_data(&td_2pass);			
+			if (rv != -1)
+				rv = DO_2PASS_TEST(group, &td, &td_2pass,
+					compare_group, NULL);
+			TEST_DATA_DESTROY(group, &td_2pass);
+		break;
+	case TEST_BUILD_SNAPSHOT:
+		if (snapshot_file != NULL)
+		    rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td, 
+			sdump_group);
+		break;
+	default:
+		rv = 0;
+		break;
+	};
+
+fin:
+	TEST_DATA_DESTROY(group, &td_snap);
+	TEST_DATA_DESTROY(group, &td);
+	free(snapshot_file);	
+	return (rv);
+}

==== //depot/projects/soc2006/nss_ldap_cached/src/tools/regression/lib/libc/nss/test-getpw.c#3 (text+ko) ====

@@ -1,0 +1,489 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman at freebsd.org>
+ * All rights repwded.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "testutil.h"
+
+enum test_methods {
+	TEST_GETPWENT,
+	TEST_GETPWNAM,
+	TEST_GETPWUID,
+	TEST_GETPWENT_2PASS,
+	TEST_BUILD_SNAPSHOT
+};
+
+static int debug = 0;
+static enum test_methods method = TEST_BUILD_SNAPSHOT;
+
+DECLARE_TEST_DATA(passwd)
+DECLARE_TEST_FILE_SNAPSHOT(passwd)
+DECLARE_1PASS_TEST(passwd)
+DECLARE_2PASS_TEST(passwd)
+
+static void clone_passwd(struct passwd *, struct passwd const *);
+static int compare_passwd(struct passwd *, struct passwd *, void *);
+static void free_passwd(struct passwd *);
+
+static void sdump_passwd(struct passwd *, char *, size_t);
+static void dump_passwd(struct passwd *);
+
+static int passwd_read_snapshot_func(struct passwd *, char *);
+
+static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *);
+static int passwd_fill_test_data(struct passwd_test_data *);
+static int passwd_test_correctness(struct passwd *, void *);
+static int passwd_test_getpwnam(struct passwd *, void *);
+static int passwd_test_getpwuid(struct passwd *, void *);
+static int passwd_test_getpwent(struct passwd *, void *);
+	
+static void usage(void)  __attribute__((__noreturn__));
+
+IMPLEMENT_TEST_DATA(passwd)
+IMPLEMENT_TEST_FILE_SNAPSHOT(passwd)
+IMPLEMENT_1PASS_TEST(passwd)
+IMPLEMENT_2PASS_TEST(passwd)
+
+static void 
+clone_passwd(struct passwd *dest, struct passwd const *src)
+{
+	assert(dest != NULL);
+	assert(src != NULL);
+	
+	memcpy(dest, src, sizeof(struct passwd));
+	if (src->pw_name != NULL)
+		dest->pw_name = strdup(src->pw_name);
+	if (src->pw_passwd != NULL)
+		dest->pw_passwd = strdup(src->pw_passwd);
+	if (src->pw_class != NULL)
+		dest->pw_class = strdup(src->pw_class);
+	if (src->pw_gecos != NULL)
+		dest->pw_gecos = strdup(src->pw_gecos);
+	if (src->pw_dir != NULL)
+		dest->pw_dir = strdup(src->pw_dir);
+	if (src->pw_shell != NULL)
+		dest->pw_shell = strdup(dest->pw_shell);
+}
+
+static int 
+compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata)
+{
+	assert(pwd1 != NULL);
+	assert(pwd2 != NULL);
+	
+	if (pwd1 == pwd2)
+		return (0);
+	
+	if ((pwd1->pw_uid != pwd2->pw_uid) ||
+		(pwd1->pw_gid != pwd2->pw_gid) ||
+		(pwd1->pw_change != pwd2->pw_change) ||
+		(pwd1->pw_expire != pwd2->pw_expire) ||
+		(pwd1->pw_fields != pwd2->pw_fields) ||
+		(strcmp(pwd1->pw_name, pwd2->pw_name) != 0) ||
+		(strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0) ||
+		(strcmp(pwd1->pw_class, pwd2->pw_class) != 0) ||
+		(strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0) ||
+		(strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0) ||
+		(strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0)	
+		)
+		return (-1);
+	else
+		return (0);
+}
+
+static void 
+free_passwd(struct passwd *pwd)
+{
+	free(pwd->pw_name);
+	free(pwd->pw_passwd);
+	free(pwd->pw_class);
+	free(pwd->pw_gecos);
+	free(pwd->pw_dir);
+	free(pwd->pw_shell);
+}
+
+static void 
+sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen)
+{
+	snprintf(buffer, buflen, "%s:%s:%d:%d:%d:%s:%s:%s:%s:%d:%d",
+		pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
+		pwd->pw_change, pwd->pw_class, pwd->pw_gecos, pwd->pw_dir,
+		pwd->pw_shell, pwd->pw_expire, pwd->pw_fields);
+}
+
+static void
+dump_passwd(struct passwd *pwd)
+{
+	if (pwd != NULL) {
+		char buffer[2048];
+		sdump_passwd(pwd, buffer, sizeof(buffer));
+		printf("%s\n", buffer);
+	} else
+		printf("(null)\n");
+}
+
+static int 
+passwd_read_snapshot_func(struct passwd *pwd, char *line)
+{
+	char *s, *ps, *ts;
+	int i;
+
+	if (debug)
+		printf("1 line read from snapshot:\n%s\n", line);
+	
+	i = 0;
+	ps = line;
+	memset(pwd, 0, sizeof(struct passwd));
+	while ( (s = strsep(&ps, ":")) != NULL) {
+		switch (i) {
+			case 0:
+				pwd->pw_name = strdup(s);
+				assert(pwd->pw_name != NULL);
+			break;
+			case 1:
+				pwd->pw_passwd = strdup(s);
+				assert(pwd->pw_passwd != NULL);				
+			break;
+			case 2:
+				pwd->pw_uid = (uid_t)strtol(s, &ts, 10);
+				if (*ts != '\0')
+					goto fin;
+			break;
+			case 3:
+				pwd->pw_gid = (gid_t)strtol(s, &ts, 10);
+				if (*ts != '\0')
+					goto fin;
+			break;
+			case 4:
+				pwd->pw_change = (time_t)strtol(s, &ts, 10);
+				if (*ts != '\0')
+					goto fin;
+			break;
+			case 5:
+				pwd->pw_class = strdup(s);
+				assert(pwd->pw_class != NULL);
+			break;
+			case 6:
+				pwd->pw_gecos = strdup(s);
+				assert(pwd->pw_gecos != NULL);
+			break;
+			case 7:
+				pwd->pw_dir = strdup(s);
+				assert(pwd->pw_dir != NULL);
+			break;
+			case 8:
+				pwd->pw_shell = strdup(s);
+				assert(pwd->pw_shell != NULL);
+			break;
+			case 9:
+				pwd->pw_expire = (time_t)strtol(s, &ts, 10);
+				if (*ts != '\0')
+					goto fin;
+			break;
+			case 10:
+				pwd->pw_fields = (int)strtol(s, &ts, 10);
+				if (*ts != '\0')
+					goto fin;
+			break;
+			default:
+			break;			
+		};
+		++i;
+	}
+
+fin:
+	if (i != 11) {
+		free_passwd(pwd);
+		memset(pwd, 0, sizeof(struct passwd));
+		return (-1);
+	}
+	
+	return (0);
+}
+
+static int
+passwd_fill_test_data(struct passwd_test_data *td)
+{
+	struct passwd *pwd;
+		
+	setpassent(1);
+	while ((pwd = getpwent()) != NULL) {
+		if (passwd_test_correctness(pwd, NULL) == 0)
+			TEST_DATA_APPEND(passwd, td, pwd);
+		else
+			return (-1);
+	}
+	endpwent();
+	
+	return (0);
+}
+
+static int
+passwd_test_correctness(struct passwd *pwd, void *mdata)
+{
+	if (debug) {
+		printf("testing correctness with the following data:\n");
+		dump_passwd(pwd);
+	}
+	
+	if (pwd == NULL)
+		return (-1);	
+
+	if (pwd->pw_name == NULL)
+		goto errfin;
+
+	if (pwd->pw_passwd == NULL)
+		goto errfin;
+
+	if (pwd->pw_class == NULL)
+		goto errfin;
+
+	if (pwd->pw_gecos == NULL)
+		goto errfin;
+
+	if (pwd->pw_dir == NULL)
+		goto errfin;
+
+	if (pwd->pw_shell == NULL)
+		goto errfin;
+	
+	if (debug)
+		printf("correct\n");
+	
+	return (0);	
+errfin:
+	if (debug)
+		printf("incorrect\n");
+	
+	return (-1);
+}
+
+/* passwd_check_ambiguity() is needed here because when doing the getpwent()
+ * calls sequence, records from different nsswitch sources can be different, 
+ * though having the same pw_name/pw_uid */
+static int
+passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd)
+{
+	
+	return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd,
+		NULL) != NULL ? 0 : -1);
+}
+
+static int
+passwd_test_getpwnam(struct passwd *pwd_model, void *mdata)
+{
+	struct passwd *pwd;
+		
+	if (debug) {
+		printf("testing getpwnam() with the following data:\n");
+		dump_passwd(pwd_model);
+	}
+
+	pwd = getpwnam(pwd_model->pw_name);
+	if (passwd_test_correctness(pwd, NULL) != 0)
+		goto errfin;
+	
+	if ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
+	    (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) 
+	    !=0))
+	    goto errfin;
+		
+	if (debug)
+		printf("ok\n");
+	return (0);
+	
+errfin:
+	if (debug)
+		printf("not ok\n");
+	
+	return (-1);
+}
+
+static int
+passwd_test_getpwuid(struct passwd *pwd_model, void *mdata)
+{
+	struct passwd *pwd;
+		
+	if (debug) {
+		printf("testing getpwuid() with the following data...\n");
+		dump_passwd(pwd_model);
+	}	
+	
+	pwd = getpwuid(pwd_model->pw_uid);
+	if ((passwd_test_correctness(pwd, NULL) != 0) || 
+	    ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
+	    (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
+	    != 0))) {
+	    if (debug)
+		printf("not ok\n");
+	    return (-1);
+	} else {
+	    if (debug)
+		printf("ok\n");
+	    return (0);
+	}
+}
+
+static int 
+passwd_test_getpwent(struct passwd *pwd, void *mdata)
+{
+	/* Only correctness can be checked when doing 1-pass test for
+	 * getpwent(). */
+	return (passwd_test_correctness(pwd, NULL));
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr,
+	    "Usage: %s [-dnue2] [-s <file>]\n",
+	    getprogname());
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct passwd_test_data td, td_snap, td_2pass;
+	char *snapshot_file;
+	int rv;
+	int c;
+	
+	if (argc < 2)
+		usage();
+		
+	snapshot_file = NULL;
+	while ((c = getopt(argc, argv, "nue2ds:")) != -1)
+		switch (c) {
+		case 'd':
+			debug++;
+			break;
+		case 'n':
+			method = TEST_GETPWNAM;
+			break;
+		case 'u':
+			method = TEST_GETPWUID;
+			break;
+		case 'e':
+			method = TEST_GETPWENT;
+			break;
+		case '2':
+			method = TEST_GETPWENT_2PASS;
+			break;
+		case 's':
+			snapshot_file = strdup(optarg);
+			break;
+		default:
+			usage();
+		}
+	
+	TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd);
+	TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd);
+	if (snapshot_file != NULL) {
+		if (access(snapshot_file, W_OK | R_OK) != 0) {		
+			if (errno == ENOENT)
+				method = TEST_BUILD_SNAPSHOT;
+			else {
+				if (debug)
+					printf("can't access the file %s\n",
+				snapshot_file);
+			
+				rv = -1;
+				goto fin;
+			}
+		} else {
+			if (method == TEST_BUILD_SNAPSHOT) {
+				rv = 0;
+				goto fin;
+			}

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list