Committing regression tests for all implemented nsswitch databases.
Detailed description and instructions are in the README file. This work had been basically done during GSoC 2006. Approved by: brooks (mentor)
This commit is contained in:
parent
1e51d3c721
commit
31175191f1
12
tools/regression/lib/libc/nss/Makefile
Normal file
12
tools/regression/lib/libc/nss/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
TESTS= test-getaddr test-getgr test-gethostby test-getpw test-getproto\
|
||||
test-getrpc test-getserv test-getusershell
|
||||
CFLAGS+= -g -Wall
|
||||
|
||||
.PHONY: tests
|
||||
tests: ${TESTS}
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -f ${TESTS}
|
203
tools/regression/lib/libc/nss/README
Normal file
203
tools/regression/lib/libc/nss/README
Normal file
@ -0,0 +1,203 @@
|
||||
$FreeBSD$
|
||||
|
||||
A brief how-to
|
||||
--------------
|
||||
|
||||
Each nsswitch regression test does 2 kinds of actions:
|
||||
1. It runs a series of queries and tests the correctness of results.
|
||||
There are 2 basic criterias which are used for that:
|
||||
- numbers must be in the correct range
|
||||
- certain pointers should not be NULL
|
||||
|
||||
2. It makes a snapshot of the results of all queries that were made.
|
||||
The idea of snapshots is to test that nsswitch-related function
|
||||
calls behave equally (i.e. return same results for the same queries)
|
||||
between system upgrades. When the test is executed and the snapshot is
|
||||
already created, the test will compare the result of each query with
|
||||
the appropriate result from the snapshot and will signal if they
|
||||
differ.
|
||||
|
||||
In order for nsswitch tests to be as useful as possible you should use
|
||||
them in the following way:
|
||||
|
||||
Step 1 (before upgrading your system).
|
||||
Build the tests with "make" command and execute them with "prove -v"
|
||||
command. If there are errors during the execution, then appropriate
|
||||
nsswitch functions should be checked. Note, that errors on this state
|
||||
can happen only if the particular function return incorrect data.
|
||||
|
||||
After the stage 1 a number of "snapshot_[test name]" files will appear
|
||||
in your test folder.
|
||||
|
||||
Step 2 (after upgrading you system).
|
||||
Rebuild the tests with "make clean; make" command and execute them
|
||||
again with "prove -v" (check that "snapshot_[test name]" files
|
||||
are in the same folder with tests). On this stage regression tests
|
||||
will catch not only the correctness errors, but will also determine
|
||||
the changes in nsswitch functions behaviour.
|
||||
|
||||
In case of the test failure you will get the following message:
|
||||
|
||||
To get more details about the error you should do the following:
|
||||
Step 1. Run the test alone with debug output enabled.
|
||||
Step 2. Mail the snapshot file and the debug test output to the
|
||||
freebsd-current@ mailing list.
|
||||
|
||||
Example testing session for getpwXXX() family of functions
|
||||
----------------------------------------------------------
|
||||
1. make
|
||||
|
||||
2. prove -v ./test-getpw.t
|
||||
|
||||
test-getpw....1..8
|
||||
ok 1 - getpwnam()
|
||||
ok 2 - getpwuid()
|
||||
ok 3 - getpwent()
|
||||
ok 4 - getpwent() 2-pass
|
||||
ok 5 - building snapshot, if needed
|
||||
ok 6 - getpwnam() snapshot
|
||||
ok 7 - getpwuid() snapshot
|
||||
ok 8 - getpwent() snapshot
|
||||
ok
|
||||
All tests successful.
|
||||
Files=1, Tests=8, 1 wallclock secs ( 0.00 cusr + 0.20 csys = 0.20 CPU)
|
||||
|
||||
|
||||
3. Upgrading the system.
|
||||
|
||||
4. make clean; make
|
||||
|
||||
5. prove -v ./test-getpw.t (suppose that something has gone wrong)
|
||||
|
||||
test-getpw....1..8
|
||||
ok 1 - getpwnam()
|
||||
ok 2 - getpwuid()
|
||||
ok 3 - getpwent()
|
||||
ok 4 - getpwent() 2-pass
|
||||
ok 5 - building snapshot, if needed
|
||||
not ok 6 - getpwnam() snapshot
|
||||
ok 7 - getpwuid() snapshot
|
||||
not ok 8 - getpwent() snapshot
|
||||
FAILED tests 6, 8
|
||||
Failed 2/8 tests, 75.00% okay
|
||||
Failed 1/1 test scripts, 0.00% okay. 2/8 subtests failed, 75.00% okay.
|
||||
|
||||
6. We see that test number 6 failed. According to get-getpw.t, this test
|
||||
is executed like this:
|
||||
do_test 6 'getpwnam() snapshot' '-n -s snapshot_pwd'
|
||||
|
||||
To determine why the test has failed, we need to run it in debug mode -
|
||||
it means adding "-d" to the options list.
|
||||
|
||||
7. ./test-getpw -dn -s snapshot_pwd
|
||||
...
|
||||
testing getpwnam() with the following data:
|
||||
toor:*:0:0:0::ne-again Superuser:/root::0:4831
|
||||
testing correctness with the following data:
|
||||
toor:*:0:0:0::Bourne-again Superuser:/root::0:4831
|
||||
correct
|
||||
not ok
|
||||
|
||||
8. Here we can see that the data from snapshot (first "toor" line) and
|
||||
the data received from the getpwnam() call (second "toor" line) are
|
||||
different. It is the reason why the test has failed. If you can't
|
||||
(or don't want) to investigate the problem by yourself, mail
|
||||
the test debug output and the snapshot file to the developers list.
|
||||
|
||||
Notes on using standalone nsswitch tests
|
||||
----------------------------------------
|
||||
|
||||
All nsswitch tests have [-d] optional command line argument which enables
|
||||
debug output. The debug output can be extremely helpful to determine the
|
||||
cause of test failure.
|
||||
|
||||
In all nsswitch tests -s <file> command line argument specifies the
|
||||
snapshot file. If this file doesn't exist, it would be built during
|
||||
test execution. If it already exists then it will be used to check
|
||||
the results of particular function calls. This argument is mostly
|
||||
optional, but some tests (test-getaddr and test-getusershell) force
|
||||
it to be specified.
|
||||
|
||||
test-gethostby and test-getaddr require the list of hostnames, that should
|
||||
be queried during the test. This list must be specified via -f <file>
|
||||
command line argument. Each hostname should occupy exactly one line
|
||||
in the file.
|
||||
|
||||
Detailed tests description
|
||||
--------------------------
|
||||
|
||||
./test-getaddr - tests the getaddrinfo() function.
|
||||
Usage: test-getaddr [-d] [-46] [-s <file>] -f <file>
|
||||
-d - enable debug output
|
||||
-4 - force IPv4 usage
|
||||
-6 - force IPv6 usage
|
||||
-s - build/use specified snapshot file
|
||||
-f - use specified hostnames list for testing
|
||||
|
||||
./test-getgr
|
||||
Usage: test-getgr -nge2 [-d] [-s <file>]
|
||||
-d - enable debug output
|
||||
-n - test getgrnam(3)
|
||||
-g - test getgrgid(3)
|
||||
-e - test getgrent(3)
|
||||
-2 - test getgrent(3) in 2-pass mode
|
||||
-s - build/use specified snapshot file
|
||||
|
||||
./test-gethostby
|
||||
Usage: test-gethostby -na2i [-o] [-d] [-m46] [-s <file>] -f <file>
|
||||
-n - test gethostbyname2(3)
|
||||
-a - test gethostbyaddr(3)
|
||||
-2 - test gethostbyname2(3) results to be equal with getaddrinfo(3)
|
||||
results for the similar query
|
||||
-i - test gethostbyaddr(3) results to be equal with getnameinfo(3)
|
||||
results for the similar query
|
||||
-o - use getipnodebyname(3)/getipnodebyaddr(3) for testing instead of
|
||||
gethostbyname2(3)/gethostbyaddr(3)
|
||||
-d - enable debug output
|
||||
-m - force IPv4-to-IPv6 mapping
|
||||
-4 - force IPv4 usage
|
||||
-6 - force IPv6 usage
|
||||
-s - build/use specified snapshot file
|
||||
-f - use specified hostnames list for testing
|
||||
|
||||
./test-getproto
|
||||
Usage: test-getproto -nve2 [-d] [-s <file>]
|
||||
-d - enable debug output
|
||||
-n - test getprotobyname(3)
|
||||
-v - test getprotobynumber(3)
|
||||
-e - test getprotoent(3)
|
||||
-2 - test getprotoent(3) in 2-pass mode
|
||||
-s - build/use specified snapshot file
|
||||
|
||||
./test-getpw
|
||||
Usage: test-getpw -nue2 [-d] [-s <file>]
|
||||
-d - enable debug output
|
||||
-n - test getpwnam(3)
|
||||
-u - test getpwuid(3)
|
||||
-e - test getpwent(3)
|
||||
-2 - test getpwent(3) in 2-pass mode
|
||||
-s - build/use snapshot file
|
||||
|
||||
./test-getrpc
|
||||
Usage: test-getrpc -nve2 [-d] [-s <file>]
|
||||
-d - enable debug output
|
||||
-n - test getrpcbyname(3)
|
||||
-v - test getrpcbynumber(3)
|
||||
-e - test getrpcent(3)
|
||||
-2 - test getrpcent(3) in 2-pass mode
|
||||
-s - build/use specified snapshot file
|
||||
|
||||
./test-getserv
|
||||
Usage: test-getserv -npe2 [-d] [-s <file>]
|
||||
-d - enable debug output
|
||||
-n - test getservbyname(3)
|
||||
-p - test getservbyport(3)
|
||||
-e - test getservent(3)
|
||||
-2 - test getservent(3) in 2-pass mode
|
||||
-s - build/use specified snapshot file
|
||||
|
||||
./test-getusershell
|
||||
Usage: test-getusershell [-d] -s <file>
|
||||
-d - enable debug output
|
||||
-s - build/use specified snapshot file
|
||||
|
94
tools/regression/lib/libc/nss/mach
Normal file
94
tools/regression/lib/libc/nss/mach
Normal file
@ -0,0 +1,94 @@
|
||||
# $FreeBSD$
|
||||
localhost
|
||||
above.warped.net
|
||||
anoncvs.cirr.com
|
||||
anoncvs.isc.netbsd.org
|
||||
anoncvs.leo.org
|
||||
anoncvs.netbsd.lt
|
||||
anoncvs.netbsd.ro
|
||||
anoncvs.netbsd.se
|
||||
antioche.antioche.eu.org
|
||||
boulder.tele.dk
|
||||
centaurus.4web.cz
|
||||
chur.math.ntnu.no
|
||||
cnftp.bjpu.edu.cn
|
||||
console.netbsd.org
|
||||
cvs.fi.netbsd.org
|
||||
cvs.mikrolahti.fi
|
||||
cvs.netbsd.org
|
||||
cvsup-netbsd.leo.org
|
||||
cvsup.netbsd.se
|
||||
cvsup.pasta.cs.uit.no
|
||||
ftp.bitcon.no
|
||||
ftp.chg.ru
|
||||
ftp.duth.gr
|
||||
ftp.estpak.ee
|
||||
ftp.fsn.hu
|
||||
ftp.funet.fi
|
||||
ftp.grondar.za
|
||||
ftp.leo.org
|
||||
ftp.netbsd.lt
|
||||
ftp.netbsd.org
|
||||
ftp.nluug.nl
|
||||
ftp.plig.org
|
||||
ftp.uni-erlangen.de
|
||||
ftp.xgate.co.kr
|
||||
gd.tuwien.ac.at
|
||||
gort.ludd.luth.se
|
||||
grappa.unix-ag.uni-kl.de
|
||||
info.wins.uva.nl
|
||||
irc.warped.net
|
||||
knug.youn.co.kr
|
||||
lala.iri.co.jp
|
||||
mail.jp.netbsd.org
|
||||
mail.kr.netbsd.org
|
||||
mail.netbsd.org
|
||||
melanoma.cs.rmit.edu.au
|
||||
mirror.aarnet.edu.au
|
||||
mirror.netbsd.com.br
|
||||
mirror03.inet.tele.dk
|
||||
moon.vub.ac.be
|
||||
nbwww.sergei.cc
|
||||
net.bsd.cz
|
||||
netbsd.3miasto.net
|
||||
netbsd.4ka.mipt.ru
|
||||
netbsd.apk.od.ua
|
||||
netbsd.csie.nctu.edu.tw
|
||||
netbsd.enderunix.org
|
||||
netbsd.ftp.fu-berlin.de
|
||||
netbsd.netlead.com.au
|
||||
netbsd.nsysu.edu.tw
|
||||
netbsd.pair.com
|
||||
netbsd.stevens-tech.edu
|
||||
netbsd.triada.bg
|
||||
netbsd.unix.net.nz
|
||||
netbsd.unixtech.be
|
||||
netbsd.vejas.lt
|
||||
netbsd.wagener-consulting.lu
|
||||
netbsd.zarco.org
|
||||
netbsdiso.interoute.net.uk
|
||||
netbsdwww.bitcon.no
|
||||
netbsdwww.cordef.com.pl
|
||||
netbsdwww.cs.rmit.edu.au
|
||||
netbsdwww.interoute.net.uk
|
||||
news.gw.com
|
||||
ns.netbsd.org
|
||||
pigu.iri.co.jp
|
||||
pluto.cdpa.nsysu.edu.tw
|
||||
projects.slowass.net
|
||||
server6.pasta.cs.uit.no
|
||||
skeleton.phys.spbu.ru
|
||||
snoopy.allbsd.org
|
||||
spike.allbsd.org
|
||||
sundry.netbsd.org
|
||||
tanya.sergei.cc
|
||||
web-a.fi.gw.com
|
||||
web-a.us.gw.com
|
||||
web.netbsd.mirror.arhea.net
|
||||
www.en.netbsd.de
|
||||
www.netbsd.cl
|
||||
www.netbsd.nl
|
||||
www.netbsd.org
|
||||
www.netbsd.ro
|
||||
zathras.netbsd.org
|
||||
zeppo.rediris.es
|
538
tools/regression/lib/libc/nss/test-getaddr.c
Normal file
538
tools/regression/lib/libc/nss/test-getaddr.c
Normal file
@ -0,0 +1,538 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
|
||||
* All rights rehted.
|
||||
*
|
||||
* 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 <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <unistd.h>
|
||||
#include "testutil.h"
|
||||
|
||||
enum test_methods {
|
||||
TEST_GETADDRINFO,
|
||||
TEST_BUILD_SNAPSHOT
|
||||
};
|
||||
|
||||
static int debug = 0;
|
||||
static struct addrinfo hints;
|
||||
static enum test_methods method = TEST_GETADDRINFO;
|
||||
|
||||
DECLARE_TEST_DATA(addrinfo)
|
||||
DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
|
||||
DECLARE_2PASS_TEST(addrinfo)
|
||||
|
||||
static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
|
||||
static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
|
||||
static void dump_addrinfo(struct addrinfo *);
|
||||
static void free_addrinfo(struct addrinfo *);
|
||||
|
||||
static void sdump_addrinfo(struct addrinfo *, char *, size_t);
|
||||
|
||||
IMPLEMENT_TEST_DATA(addrinfo)
|
||||
IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
|
||||
IMPLEMENT_2PASS_TEST(addrinfo)
|
||||
|
||||
static void
|
||||
clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
memcpy(dest, src, sizeof(struct addrinfo));
|
||||
if (src->ai_canonname != NULL)
|
||||
dest->ai_canonname = strdup(src->ai_canonname);
|
||||
|
||||
if (src->ai_addr != NULL) {
|
||||
dest->ai_addr = (struct sockaddr *)malloc(src->ai_addrlen);
|
||||
assert(dest->ai_addr != NULL);
|
||||
memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
|
||||
}
|
||||
|
||||
if (src->ai_next != NULL) {
|
||||
dest->ai_next = (struct addrinfo *)malloc(
|
||||
sizeof(struct addrinfo));
|
||||
assert(dest->ai_next != NULL);
|
||||
clone_addrinfo(dest->ai_next, src->ai_next);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
|
||||
{
|
||||
if ((ai1 == NULL) || (ai2 == NULL))
|
||||
return (-1);
|
||||
|
||||
if ((ai1->ai_flags != ai2->ai_flags) ||
|
||||
(ai1->ai_family != ai2->ai_family) ||
|
||||
(ai1->ai_socktype != ai2->ai_socktype) ||
|
||||
(ai1->ai_protocol != ai2->ai_protocol) ||
|
||||
(ai1->ai_addrlen != ai2->ai_addrlen) ||
|
||||
(((ai1->ai_addr == NULL) || (ai2->ai_addr == NULL)) &&
|
||||
(ai1->ai_addr != ai2->ai_addr)) ||
|
||||
(((ai1->ai_canonname == NULL) || (ai2->ai_canonname == NULL)) &&
|
||||
(ai1->ai_canonname != ai2->ai_canonname)))
|
||||
return (-1);
|
||||
|
||||
if ((ai1->ai_canonname != NULL) &&
|
||||
(strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0))
|
||||
return (-1);
|
||||
|
||||
if ((ai1->ai_addr != NULL) &&
|
||||
(memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0))
|
||||
return (-1);
|
||||
|
||||
if ((ai1->ai_next == NULL) && (ai2->ai_next == NULL))
|
||||
return (0);
|
||||
else
|
||||
return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
|
||||
}
|
||||
|
||||
static int
|
||||
compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (debug) {
|
||||
printf("testing equality of 2 addrinfo structures\n");
|
||||
}
|
||||
|
||||
rv = compare_addrinfo_(ai1, ai2);
|
||||
|
||||
if (debug) {
|
||||
if (rv == 0)
|
||||
printf("equal\n");
|
||||
else {
|
||||
dump_addrinfo(ai1);
|
||||
dump_addrinfo(ai2);
|
||||
printf("not equal\n");
|
||||
}
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
void
|
||||
free_addrinfo(struct addrinfo *ai)
|
||||
{
|
||||
if (ai == NULL)
|
||||
return;
|
||||
|
||||
free(ai->ai_addr);
|
||||
free(ai->ai_canonname);
|
||||
free_addrinfo(ai->ai_next);
|
||||
}
|
||||
|
||||
void
|
||||
sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
|
||||
{
|
||||
int written, i;
|
||||
|
||||
written = snprintf(buffer, buflen, "%d %d %d %d %d ",
|
||||
ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
|
||||
ai->ai_addrlen);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
written = snprintf(buffer, buflen, "%s ",
|
||||
ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (ai->ai_addr == NULL) {
|
||||
written = snprintf(buffer, buflen, "(null)");
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
} else {
|
||||
for (i = 0; i < ai->ai_addrlen; ++i ) {
|
||||
written = snprintf(buffer, buflen,
|
||||
i + 1 != ai->ai_addrlen ? "%d." : "%d",
|
||||
((unsigned char *)ai->ai_addr)[i]);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (buflen == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ai->ai_next != NULL) {
|
||||
written = snprintf(buffer, buflen, ":");
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
sdump_addrinfo(ai->ai_next, buffer, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_addrinfo(struct addrinfo *result)
|
||||
{
|
||||
if (result != NULL) {
|
||||
char buffer[2048];
|
||||
sdump_addrinfo(result, buffer, sizeof(buffer));
|
||||
printf("%s\n", buffer);
|
||||
} else
|
||||
printf("(null)\n");
|
||||
}
|
||||
|
||||
static int
|
||||
addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
|
||||
{
|
||||
char *s, *ps, *ts;
|
||||
|
||||
ps = addr;
|
||||
while ( (s = strsep(&ps, ".")) != NULL) {
|
||||
if (len == 0)
|
||||
return (-1);
|
||||
|
||||
*result = (unsigned char)strtol(s, &ts, 10);
|
||||
++result;
|
||||
if (*ts != '\0')
|
||||
return (-1);
|
||||
|
||||
--len;
|
||||
}
|
||||
if (len != 0)
|
||||
return (-1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
|
||||
{
|
||||
char *s, *ps, *ts;
|
||||
int i, rv, *pi;
|
||||
|
||||
rv = 0;
|
||||
i = 0;
|
||||
ps = line;
|
||||
memset(ai, 0, sizeof(struct addrinfo));
|
||||
while ( (s = strsep(&ps, " ")) != NULL) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
pi = &ai->ai_flags + i;
|
||||
*pi = (int)strtol(s, &ts, 10);
|
||||
if (*ts != '\0')
|
||||
goto fin;
|
||||
break;
|
||||
case 4:
|
||||
ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
|
||||
if (*ts != '\0')
|
||||
goto fin;
|
||||
break;
|
||||
case 5:
|
||||
if (strcmp(s, "(null)") != 0) {
|
||||
ai->ai_canonname = strdup(s);
|
||||
assert(ai->ai_canonname != NULL);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (strcmp(s, "(null)") != 0) {
|
||||
ai->ai_addr = (struct sockaddr *)malloc(
|
||||
ai->ai_addrlen);
|
||||
assert(ai->ai_addr != NULL);
|
||||
memset(ai->ai_addr, 0, ai->ai_addrlen);
|
||||
rv = addrinfo_read_snapshot_addr(s,
|
||||
(unsigned char *)ai->ai_addr,
|
||||
ai->ai_addrlen);
|
||||
|
||||
if (rv != 0)
|
||||
goto fin;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* NOTE: should not be reachable */
|
||||
rv = -1;
|
||||
goto fin;
|
||||
};
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
fin:
|
||||
if ((i != 7) || (rv != 0)) {
|
||||
free_addrinfo(ai);
|
||||
memset(ai, 0, sizeof(struct addrinfo));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
|
||||
{
|
||||
struct addrinfo *ai2;
|
||||
char *s, *ps;
|
||||
int i, rv;
|
||||
|
||||
if (debug)
|
||||
printf("1 line read from snapshot:\n%s\n", line);
|
||||
|
||||
rv = 0;
|
||||
i = 0;
|
||||
ps = line;
|
||||
|
||||
s = strsep(&ps, ":");
|
||||
if (s == NULL)
|
||||
return (-1);
|
||||
|
||||
rv = addrinfo_read_snapshot_ai(ai, s);
|
||||
if (rv != 0)
|
||||
return (-1);
|
||||
|
||||
ai2 = ai;
|
||||
while ( (s = strsep(&ps, ":")) != NULL) {
|
||||
ai2->ai_next = (struct addrinfo *)malloc(
|
||||
sizeof(struct addrinfo));
|
||||
assert(ai2->ai_next != NULL);
|
||||
memset(ai2->ai_next, 0, sizeof(struct addrinfo));
|
||||
|
||||
rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
|
||||
if (rv != 0) {
|
||||
free_addrinfo(ai);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ai2 = ai2->ai_next;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
addrinfo_test_correctness(struct addrinfo *ai, void *mdata)
|
||||
{
|
||||
if (debug) {
|
||||
printf("testing correctness with the following data:\n");
|
||||
dump_addrinfo(ai);
|
||||
}
|
||||
|
||||
if (ai == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (!((ai->ai_family >= 0) && (ai->ai_family < AF_MAX)))
|
||||
goto errfin;
|
||||
|
||||
if ((ai->ai_socktype != 0) && (ai->ai_socktype != SOCK_STREAM) &&
|
||||
(ai->ai_socktype != SOCK_DGRAM) && (ai->ai_socktype != SOCK_RAW))
|
||||
goto errfin;
|
||||
|
||||
if ((ai->ai_protocol != 0) && (ai->ai_protocol != IPPROTO_UDP) &&
|
||||
(ai->ai_protocol != IPPROTO_TCP))
|
||||
goto errfin;
|
||||
|
||||
if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((ai->ai_addrlen != ai->ai_addr->sa_len) ||
|
||||
(ai->ai_family != ai->ai_addr->sa_family))
|
||||
goto errfin;
|
||||
|
||||
if (debug)
|
||||
printf("correct\n");
|
||||
|
||||
return (0);
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("incorrect\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
|
||||
{
|
||||
struct addrinfo *result;
|
||||
int rv;
|
||||
|
||||
if (debug)
|
||||
printf("resolving %s: ", line);
|
||||
rv = getaddrinfo(line, NULL, &hints, &result);
|
||||
if (rv == 0) {
|
||||
if (debug)
|
||||
printf("found\n");
|
||||
|
||||
rv = addrinfo_test_correctness(result, NULL);
|
||||
if (rv != 0) {
|
||||
freeaddrinfo(result);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
clone_addrinfo(ai, result);
|
||||
freeaddrinfo(result);
|
||||
} else {
|
||||
if (debug)
|
||||
printf("not found\n");
|
||||
|
||||
memset(ai, 0, sizeof(struct addrinfo));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s [-d] [-46] [-s <file]> -f <file>\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct addrinfo_test_data td, td_snap;
|
||||
char *snapshot_file, *hostlist_file;
|
||||
int rv;
|
||||
int c;
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
snapshot_file = NULL;
|
||||
hostlist_file = NULL;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
while ((c = getopt(argc, argv, "46dns:f:")) != -1)
|
||||
switch (c) {
|
||||
case '4':
|
||||
hints.ai_family = PF_INET;
|
||||
case '6':
|
||||
hints.ai_family = PF_INET6;
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 's':
|
||||
snapshot_file = strdup(optarg);
|
||||
method = TEST_BUILD_SNAPSHOT;
|
||||
break;
|
||||
case 'f':
|
||||
hostlist_file = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
|
||||
TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
|
||||
|
||||
if (hostlist_file == NULL)
|
||||
usage();
|
||||
|
||||
if (access(hostlist_file, R_OK) != 0) {
|
||||
if (debug)
|
||||
printf("can't access the hostlist file %s\n",
|
||||
hostlist_file);
|
||||
|
||||
usage();
|
||||
}
|
||||
|
||||
if (debug)
|
||||
printf("building host lists from %s\n", hostlist_file);
|
||||
|
||||
rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
|
||||
addrinfo_read_hostlist_func);
|
||||
if (rv != 0)
|
||||
goto fin;
|
||||
|
||||
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 snapshot file %s\n",
|
||||
snapshot_file);
|
||||
|
||||
rv = -1;
|
||||
goto fin;
|
||||
}
|
||||
} else {
|
||||
rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
|
||||
&td_snap, addrinfo_read_snapshot_func);
|
||||
if (rv != 0) {
|
||||
if (debug)
|
||||
printf("error reading snapshot file\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case TEST_GETADDRINFO:
|
||||
if (snapshot_file != NULL)
|
||||
rv = DO_2PASS_TEST(addrinfo, &td, &td_snap,
|
||||
compare_addrinfo, NULL);
|
||||
break;
|
||||
case TEST_BUILD_SNAPSHOT:
|
||||
if (snapshot_file != NULL) {
|
||||
rv = TEST_SNAPSHOT_FILE_WRITE(addrinfo, snapshot_file, &td,
|
||||
sdump_addrinfo);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
fin:
|
||||
TEST_DATA_DESTROY(addrinfo, &td_snap);
|
||||
TEST_DATA_DESTROY(addrinfo, &td);
|
||||
free(hostlist_file);
|
||||
free(snapshot_file);
|
||||
return (rv);
|
||||
|
||||
}
|
||||
|
33
tools/regression/lib/libc/nss/test-getaddr.t
Normal file
33
tools/regression/lib/libc/nss/test-getaddr.t
Normal file
@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..6
|
||||
#Tests with hints.ai_family is set to PF_UNSPEC
|
||||
do_test 1 'getaddrinfo() (PF_UNSPEC)' '-f mach'
|
||||
do_test 2 'getaddrinfo() snapshot (PF_UNSPEC)' '-f mach -s snapshot_ai'
|
||||
|
||||
#Tests with hints.ai_family is set to PF_INET
|
||||
do_test 3 'getaddrinfo() (PF_INET)' '-f mach'
|
||||
do_test 4 'getaddrinfo() snapshot (PF_INET)' '-4 -f mach -s snapshot_ai4'
|
||||
|
||||
#Tests with hints.ai_family is set to PF_INET6
|
||||
do_test 5 'getaddrinfo() (PF_INET6)' '-f mach'
|
||||
do_test 6 'getaddrinfo() snapshot (PF_INET6)' '-6 -f mach -s snapshot_ai6'
|
||||
|
534
tools/regression/lib/libc/nss/test-getgr.c
Normal file
534
tools/regression/lib/libc/nss/test-getgr.c
Normal file
@ -0,0 +1,534 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@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 -nge2 [-d] [-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);
|
||||
}
|
29
tools/regression/lib/libc/nss/test-getgr.t
Normal file
29
tools/regression/lib/libc/nss/test-getgr.t
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..8
|
||||
do_test 1 'getgrnam()' '-n'
|
||||
do_test 2 'getgrgid()' '-g'
|
||||
do_test 3 'getgrent()' '-e'
|
||||
do_test 4 'getgrent() 2-pass' '-2'
|
||||
do_test 5 'building snapshot, if needed' '-s snapshot_grp'
|
||||
do_test 6 'getgrnam() snapshot' '-n -s snapshot_grp'
|
||||
do_test 7 'getgrgid() snapshot' '-g -s snapshot_grp'
|
||||
do_test 8 'getgrent() snapshot' '-e -s snapshot_grp'
|
1051
tools/regression/lib/libc/nss/test-gethostby.c
Normal file
1051
tools/regression/lib/libc/nss/test-gethostby.c
Normal file
File diff suppressed because it is too large
Load Diff
78
tools/regression/lib/libc/nss/test-gethostby.t
Normal file
78
tools/regression/lib/libc/nss/test-gethostby.t
Normal file
@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..32
|
||||
#Tests for gethostby***() functions
|
||||
#IPv4-driven testing
|
||||
do_test 1 'gethostbyname2() (IPv4)' '-4 -n -f mach'
|
||||
do_test 2 'gethostbyaddr() (IPv4)' '-4 -a -f mach'
|
||||
do_test 3 'gethostbyname2()-getaddrinfo() (IPv4)' '-4 -2 -f mach'
|
||||
do_test 4 'gethostbyaddr()-getnameinfo() (IPv4)' '-4 -i -f mach'
|
||||
do_test 5 'gethostbyname2() snapshot (IPv4)'\
|
||||
'-4 -n -s snapshot_htname4 -f mach'
|
||||
do_test 6 'gethostbyaddr() snapshot (IPv4)'\
|
||||
'-4 -a -s snapshot_htaddr4 -f mach'
|
||||
|
||||
#IPv6-driven testing
|
||||
do_test 7 'gethostbyname2() (IPv6)' '-6 -n -f mach'
|
||||
do_test 8 'gethostbyaddr() (IPv6)' '-6 -a -f mach'
|
||||
do_test 9 'gethostbyname2()-getaddrinfo() (IPv6)' '-6 -2 -f mach'
|
||||
do_test 10 'gethostbyaddr()-getnameinfo() (IPv6)' '-6 -i -f mach'
|
||||
do_test 11 'gethostbyname2() snapshot (IPv6)'\
|
||||
'-6 -n -s snapshot_htname6 -f mach'
|
||||
do_test 12 'gethostbyaddr() snapshot (IPv6)'\
|
||||
'-6 -a -s snapshot_htaddr6 -f mach'
|
||||
|
||||
#Mapped IPv6-driven testing (getaddrinfo() equality test is useless here)
|
||||
do_test 13 'gethostbyname2() (IPv6 mapped)' '-m -n -f mach'
|
||||
do_test 14 'gethostbyaddr() (IPv6 mapped)' '-m -a -f mach'
|
||||
do_test 15 'gethostbyname2() snapshot (IPv6 mapped)'\
|
||||
'-m -n -s snapshot_htname6map -f mach'
|
||||
do_test 16 'gethostbyaddr() snapshot (IPv6 mapped)'\
|
||||
'-m -a -s snapshot_htaddr6map -f mach'
|
||||
|
||||
#Tests for getipnodeby***() functions
|
||||
#IPv4-driven testing
|
||||
do_test 17 'getipnodebyname() (IPv4)' '-o -4 -n -f mach'
|
||||
do_test 18 'getipnodebyaddr() (IPv4)' '-o -4 -a -f mach'
|
||||
do_test 19 'getipnodebyname()-getaddrinfo() (IPv4)' '-o -4 -2 -f mach'
|
||||
do_test 20 'getipnodebyaddr()-getnameinfo() (IPv4)' '-o -4 -i -f mach'
|
||||
do_test 21 'getipnodebyname() snapshot (IPv4)'\
|
||||
'-o -4 -n -s snapshot_ipnodename4 -f mach'
|
||||
do_test 22 'getipnodebyname() snapshot (IPv4)'\
|
||||
'-o -4 -a -s snapshot_ipnodeaddr4 -f mach'
|
||||
|
||||
#IPv6-driven testing
|
||||
do_test 23 'getipnodebyname() (IPv6)' '-o -6 -n -f mach'
|
||||
do_test 24 'getipnodebyaddr() (IPv6)' '-o -6 -a -f mach'
|
||||
do_test 25 'getipnodebyname()-getaddrinfo() (IPv6)' '-o -6 -2 -f mach'
|
||||
do_test 26 'getipnodebyaddr()-getnameinfo() (IPv6)' '-o -6 -i -f mach'
|
||||
do_test 27 'getipnodebyname() snapshot (IPv6)'\
|
||||
'-o -6 -n -s snapshot_ipnodename6 -f mach'
|
||||
do_test 28 'getipnodebyaddr() snapshot (IPv6)'\
|
||||
'-o -6 -a -s snapshot_ipnodeaddr6 -f mach'
|
||||
|
||||
#Mapped IPv6-driven testing (getaddrinfo() equality test is useless here)
|
||||
do_test 29 'getipnodebyname() (IPv6)' '-o -m -n -f mach'
|
||||
do_test 30 'getipnodebyaddr() (IPv6)' '-o -m -a -f mach'
|
||||
do_test 31 'getipnodebyname() snapshot (IPv6)'\
|
||||
'-o -m -n -s snapshot_ipnodename6map -f mach'
|
||||
do_test 32 'getipnodebyaddr() snapshot (IPv6)'\
|
||||
'-o -m -a -s snapshot_ipnodeaddr6map -f mach'
|
536
tools/regression/lib/libc/nss/test-getproto.c
Normal file
536
tools/regression/lib/libc/nss/test-getproto.c
Normal file
@ -0,0 +1,536 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
|
||||
* All rights repeed.
|
||||
*
|
||||
* 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 <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <unistd.h>
|
||||
#include "testutil.h"
|
||||
|
||||
enum test_methods {
|
||||
TEST_GETPROTOENT,
|
||||
TEST_GETPROTOBYNAME,
|
||||
TEST_GETPROTOBYNUMBER,
|
||||
TEST_GETPROTOENT_2PASS,
|
||||
TEST_BUILD_SNAPSHOT
|
||||
};
|
||||
|
||||
static int debug = 0;
|
||||
static enum test_methods method = TEST_BUILD_SNAPSHOT;
|
||||
|
||||
DECLARE_TEST_DATA(protoent)
|
||||
DECLARE_TEST_FILE_SNAPSHOT(protoent)
|
||||
DECLARE_1PASS_TEST(protoent)
|
||||
DECLARE_2PASS_TEST(protoent)
|
||||
|
||||
static void clone_protoent(struct protoent *, struct protoent const *);
|
||||
static int compare_protoent(struct protoent *, struct protoent *, void *);
|
||||
static void dump_protoent(struct protoent *);
|
||||
static void free_protoent(struct protoent *);
|
||||
|
||||
static void sdump_protoent(struct protoent *, char *, size_t);
|
||||
static int protoent_read_snapshot_func(struct protoent *, char *);
|
||||
|
||||
static int protoent_check_ambiguity(struct protoent_test_data *,
|
||||
struct protoent *);
|
||||
static int protoent_fill_test_data(struct protoent_test_data *);
|
||||
static int protoent_test_correctness(struct protoent *, void *);
|
||||
static int protoent_test_getprotobyname(struct protoent *, void *);
|
||||
static int protoent_test_getprotobynumber(struct protoent *, void *);
|
||||
static int protoent_test_getprotoent(struct protoent *, void *);
|
||||
|
||||
static void usage(void) __attribute__((__noreturn__));
|
||||
|
||||
IMPLEMENT_TEST_DATA(protoent)
|
||||
IMPLEMENT_TEST_FILE_SNAPSHOT(protoent)
|
||||
IMPLEMENT_1PASS_TEST(protoent)
|
||||
IMPLEMENT_2PASS_TEST(protoent)
|
||||
|
||||
static void
|
||||
clone_protoent(struct protoent *dest, struct protoent const *src)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
char **cp;
|
||||
int aliases_num;
|
||||
|
||||
memset(dest, 0, sizeof(struct protoent));
|
||||
|
||||
if (src->p_name != NULL) {
|
||||
dest->p_name = strdup(src->p_name);
|
||||
assert(dest->p_name != NULL);
|
||||
}
|
||||
|
||||
dest->p_proto = src->p_proto;
|
||||
|
||||
if (src->p_aliases != NULL) {
|
||||
aliases_num = 0;
|
||||
for (cp = src->p_aliases; *cp; ++cp)
|
||||
++aliases_num;
|
||||
|
||||
dest->p_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
|
||||
assert(dest->p_aliases != NULL);
|
||||
memset(dest->p_aliases, 0, (aliases_num+1) * (sizeof(char *)));
|
||||
|
||||
for (cp = src->p_aliases; *cp; ++cp) {
|
||||
dest->p_aliases[cp - src->p_aliases] = strdup(*cp);
|
||||
assert(dest->p_aliases[cp - src->p_aliases] != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_protoent(struct protoent *pe)
|
||||
{
|
||||
char **cp;
|
||||
|
||||
assert(pe != NULL);
|
||||
|
||||
free(pe->p_name);
|
||||
|
||||
for (cp = pe->p_aliases; *cp; ++cp)
|
||||
free(*cp);
|
||||
free(pe->p_aliases);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata)
|
||||
{
|
||||
char **c1, **c2;
|
||||
|
||||
if (pe1 == pe2)
|
||||
return 0;
|
||||
|
||||
if ((pe1 == NULL) || (pe2 == NULL))
|
||||
goto errfin;
|
||||
|
||||
if ((strcmp(pe1->p_name, pe2->p_name) != 0) ||
|
||||
(pe1->p_proto != pe2->p_proto))
|
||||
goto errfin;
|
||||
|
||||
c1 = pe1->p_aliases;
|
||||
c2 = pe2->p_aliases;
|
||||
|
||||
if ((pe1->p_aliases == NULL) || (pe2->p_aliases == 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_protoent(pe1);
|
||||
dump_protoent(pe2);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
sdump_protoent(struct protoent *pe, char *buffer, size_t buflen)
|
||||
{
|
||||
char **cp;
|
||||
int written;
|
||||
|
||||
written = snprintf(buffer, buflen, "%s %d",
|
||||
pe->p_name, pe->p_proto);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (pe->p_aliases != NULL) {
|
||||
if (*(pe->p_aliases) != '\0') {
|
||||
for (cp = pe->p_aliases; *cp; ++cp) {
|
||||
written = snprintf(buffer, buflen, " %s",*cp);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (buflen == 0)
|
||||
return;
|
||||
}
|
||||
} else
|
||||
snprintf(buffer, buflen, " noaliases");
|
||||
} else
|
||||
snprintf(buffer, buflen, " (null)");
|
||||
}
|
||||
|
||||
static int
|
||||
protoent_read_snapshot_func(struct protoent *pe, 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(pe, 0, sizeof(struct protoent));
|
||||
while ( (s = strsep(&ps, " ")) != NULL) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
pe->p_name = strdup(s);
|
||||
assert(pe->p_name != NULL);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pe->p_proto = (int)strtol(s, &ts, 10);
|
||||
if (*ts != '\0') {
|
||||
free(pe->p_name);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sl == NULL) {
|
||||
if (strcmp(s, "(null)") == 0)
|
||||
return (0);
|
||||
|
||||
sl = sl_init();
|
||||
assert(sl != NULL);
|
||||
|
||||
if (strcmp(s, "noaliases") != 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(pe->p_name);
|
||||
memset(pe, 0, sizeof(struct protoent));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
sl_add(sl, NULL);
|
||||
pe->p_aliases = sl->sl_str;
|
||||
|
||||
/* NOTE: is it a dirty hack or not? */
|
||||
free(sl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_protoent(struct protoent *result)
|
||||
{
|
||||
if (result != NULL) {
|
||||
char buffer[1024];
|
||||
sdump_protoent(result, buffer, sizeof(buffer));
|
||||
printf("%s\n", buffer);
|
||||
} else
|
||||
printf("(null)\n");
|
||||
}
|
||||
|
||||
static int
|
||||
protoent_fill_test_data(struct protoent_test_data *td)
|
||||
{
|
||||
struct protoent *pe;
|
||||
|
||||
setprotoent(1);
|
||||
while ((pe = getprotoent()) != NULL) {
|
||||
if (protoent_test_correctness(pe, NULL) == 0)
|
||||
TEST_DATA_APPEND(protoent, td, pe);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
endprotoent();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
protoent_test_correctness(struct protoent *pe, void *mdata)
|
||||
{
|
||||
if (debug) {
|
||||
printf("testing correctness with the following data:\n");
|
||||
dump_protoent(pe);
|
||||
}
|
||||
|
||||
if (pe == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (pe->p_name == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (pe->p_proto < 0)
|
||||
goto errfin;
|
||||
|
||||
if (pe->p_aliases == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (debug)
|
||||
printf("correct\n");
|
||||
|
||||
return (0);
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("incorrect\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* protoent_check_ambiguity() is needed when one port+proto is associated with
|
||||
* more than one peice (these cases are usually marked as PROBLEM in
|
||||
* /etc/peices. This functions is needed also when one peice+proto is
|
||||
* associated with several ports. We have to check all the protoent structures
|
||||
* to make sure that pe really exists and correct */
|
||||
static int
|
||||
protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe)
|
||||
{
|
||||
|
||||
return (TEST_DATA_FIND(protoent, td, pe, compare_protoent,
|
||||
NULL) != NULL ? 0 : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
protoent_test_getprotobyname(struct protoent *pe_model, void *mdata)
|
||||
{
|
||||
char **alias;
|
||||
struct protoent *pe;
|
||||
|
||||
if (debug) {
|
||||
printf("testing getprotobyname() with the following data:\n");
|
||||
dump_protoent(pe_model);
|
||||
}
|
||||
|
||||
pe = getprotobyname(pe_model->p_name);
|
||||
if (protoent_test_correctness(pe, NULL) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((compare_protoent(pe, pe_model, NULL) != 0) &&
|
||||
(protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
|
||||
!=0))
|
||||
goto errfin;
|
||||
|
||||
for (alias = pe_model->p_aliases; *alias; ++alias) {
|
||||
pe = getprotobyname(*alias);
|
||||
|
||||
if (protoent_test_correctness(pe, NULL) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((compare_protoent(pe, pe_model, NULL) != 0) &&
|
||||
(protoent_check_ambiguity(
|
||||
(struct protoent_test_data *)mdata, pe) != 0))
|
||||
goto errfin;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
printf("ok\n");
|
||||
return (0);
|
||||
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("not ok\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata)
|
||||
{
|
||||
struct protoent *pe;
|
||||
|
||||
if (debug) {
|
||||
printf("testing getprotobyport() with the following data...\n");
|
||||
dump_protoent(pe_model);
|
||||
}
|
||||
|
||||
pe = getprotobynumber(pe_model->p_proto);
|
||||
if ((protoent_test_correctness(pe, NULL) != 0) ||
|
||||
((compare_protoent(pe, pe_model, NULL) != 0) &&
|
||||
(protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
|
||||
!= 0))) {
|
||||
if (debug)
|
||||
printf("not ok\n");
|
||||
return (-1);
|
||||
} else {
|
||||
if (debug)
|
||||
printf("ok\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
protoent_test_getprotoent(struct protoent *pe, void *mdata)
|
||||
{
|
||||
/* Only correctness can be checked when doing 1-pass test for
|
||||
* getprotoent(). */
|
||||
return (protoent_test_correctness(pe, NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s -nve2 [-d] [-s <file>]\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct protoent_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, "nve2ds:")) != -1)
|
||||
switch (c) {
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
case 'n':
|
||||
method = TEST_GETPROTOBYNAME;
|
||||
break;
|
||||
case 'v':
|
||||
method = TEST_GETPROTOBYNUMBER;
|
||||
break;
|
||||
case 'e':
|
||||
method = TEST_GETPROTOENT;
|
||||
break;
|
||||
case '2':
|
||||
method = TEST_GETPROTOENT_2PASS;
|
||||
break;
|
||||
case 's':
|
||||
snapshot_file = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent);
|
||||
TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent);
|
||||
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(protoent, snapshot_file,
|
||||
&td_snap, protoent_read_snapshot_func);
|
||||
}
|
||||
}
|
||||
|
||||
rv = protoent_fill_test_data(&td);
|
||||
if (rv == -1)
|
||||
return (-1);
|
||||
switch (method) {
|
||||
case TEST_GETPROTOBYNAME:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(protoent, &td,
|
||||
protoent_test_getprotobyname, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(protoent, &td_snap,
|
||||
protoent_test_getprotobyname, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETPROTOBYNUMBER:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(protoent, &td,
|
||||
protoent_test_getprotobynumber, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(protoent, &td_snap,
|
||||
protoent_test_getprotobynumber, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETPROTOENT:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(protoent, &td,
|
||||
protoent_test_getprotoent, (void *)&td);
|
||||
else
|
||||
rv = DO_2PASS_TEST(protoent, &td, &td_snap,
|
||||
compare_protoent, NULL);
|
||||
break;
|
||||
case TEST_GETPROTOENT_2PASS:
|
||||
TEST_DATA_INIT(protoent, &td_2pass, clone_protoent,
|
||||
free_protoent);
|
||||
rv = protoent_fill_test_data(&td_2pass);
|
||||
if (rv != -1)
|
||||
rv = DO_2PASS_TEST(protoent, &td, &td_2pass,
|
||||
compare_protoent, NULL);
|
||||
TEST_DATA_DESTROY(protoent, &td_2pass);
|
||||
break;
|
||||
case TEST_BUILD_SNAPSHOT:
|
||||
if (snapshot_file != NULL)
|
||||
rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file, &td,
|
||||
sdump_protoent);
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
fin:
|
||||
TEST_DATA_DESTROY(protoent, &td_snap);
|
||||
TEST_DATA_DESTROY(protoent, &td);
|
||||
free(snapshot_file);
|
||||
return (rv);
|
||||
}
|
29
tools/regression/lib/libc/nss/test-getproto.t
Normal file
29
tools/regression/lib/libc/nss/test-getproto.t
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..8
|
||||
do_test 1 'getprotobyname()' '-n'
|
||||
do_test 2 'getprotobynumber()' '-v'
|
||||
do_test 3 'getprotoent()' '-e'
|
||||
do_test 4 'getprotoent() 2-pass' '-2'
|
||||
do_test 5 'building snapshot, if needed' '-s snapshot_proto'
|
||||
do_test 6 'getprotobyname() snapshot' '-n -s snapshot_proto'
|
||||
do_test 7 'getprotobynumber() snapshot' '-v -s snapshot_proto'
|
||||
do_test 8 'getprotoent() snapshot' '-e -s snapshot_proto'
|
489
tools/regression/lib/libc/nss/test-getpw.c
Normal file
489
tools/regression/lib/libc/nss/test-getpw.c
Normal file
@ -0,0 +1,489 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@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 -nue2 [-d] [-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;
|
||||
}
|
||||
|
||||
TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file,
|
||||
&td_snap, passwd_read_snapshot_func);
|
||||
}
|
||||
}
|
||||
|
||||
rv = passwd_fill_test_data(&td);
|
||||
if (rv == -1)
|
||||
return (-1);
|
||||
|
||||
switch (method) {
|
||||
case TEST_GETPWNAM:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(passwd, &td,
|
||||
passwd_test_getpwnam, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(passwd, &td_snap,
|
||||
passwd_test_getpwnam, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETPWUID:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(passwd, &td,
|
||||
passwd_test_getpwuid, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(passwd, &td_snap,
|
||||
passwd_test_getpwuid, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETPWENT:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent,
|
||||
(void *)&td);
|
||||
else
|
||||
rv = DO_2PASS_TEST(passwd, &td, &td_snap,
|
||||
compare_passwd, NULL);
|
||||
break;
|
||||
case TEST_GETPWENT_2PASS:
|
||||
TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd);
|
||||
rv = passwd_fill_test_data(&td_2pass);
|
||||
if (rv != -1)
|
||||
rv = DO_2PASS_TEST(passwd, &td, &td_2pass,
|
||||
compare_passwd, NULL);
|
||||
TEST_DATA_DESTROY(passwd, &td_2pass);
|
||||
break;
|
||||
case TEST_BUILD_SNAPSHOT:
|
||||
if (snapshot_file != NULL)
|
||||
rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file, &td,
|
||||
sdump_passwd);
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
fin:
|
||||
TEST_DATA_DESTROY(passwd, &td_snap);
|
||||
TEST_DATA_DESTROY(passwd, &td);
|
||||
free(snapshot_file);
|
||||
return (rv);
|
||||
}
|
29
tools/regression/lib/libc/nss/test-getpw.t
Normal file
29
tools/regression/lib/libc/nss/test-getpw.t
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..8
|
||||
do_test 1 'getpwnam()' '-n'
|
||||
do_test 2 'getpwuid()' '-u'
|
||||
do_test 3 'getpwent()' '-e'
|
||||
do_test 4 'getpwent() 2-pass' '-2'
|
||||
do_test 5 'building snapshot, if needed' '-s snapshot_pwd'
|
||||
do_test 6 'getpwnam() snapshot' '-n -s snapshot_pwd'
|
||||
do_test 7 'getpwuid() snapshot' '-u -s snapshot_pwd'
|
||||
do_test 8 'getpwent() snapshot' '-e -s snapshot_pwd'
|
535
tools/regression/lib/libc/nss/test-getrpc.c
Normal file
535
tools/regression/lib/libc/nss/test-getrpc.c
Normal file
@ -0,0 +1,535 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
|
||||
* All rights repeed.
|
||||
*
|
||||
* 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 <rpc/rpc.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <unistd.h>
|
||||
#include "testutil.h"
|
||||
|
||||
enum test_methods {
|
||||
TEST_GETRPCENT,
|
||||
TEST_GETRPCBYNAME,
|
||||
TEST_GETRPCBYNUMBER,
|
||||
TEST_GETRPCENT_2PASS,
|
||||
TEST_BUILD_SNAPSHOT
|
||||
};
|
||||
|
||||
static int debug = 0;
|
||||
static enum test_methods method = TEST_BUILD_SNAPSHOT;
|
||||
|
||||
DECLARE_TEST_DATA(rpcent)
|
||||
DECLARE_TEST_FILE_SNAPSHOT(rpcent)
|
||||
DECLARE_1PASS_TEST(rpcent)
|
||||
DECLARE_2PASS_TEST(rpcent)
|
||||
|
||||
static void clone_rpcent(struct rpcent *, struct rpcent const *);
|
||||
static int compare_rpcent(struct rpcent *, struct rpcent *, void *);
|
||||
static void dump_rpcent(struct rpcent *);
|
||||
static void free_rpcent(struct rpcent *);
|
||||
|
||||
static void sdump_rpcent(struct rpcent *, char *, size_t);
|
||||
static int rpcent_read_snapshot_func(struct rpcent *, char *);
|
||||
|
||||
static int rpcent_check_ambiguity(struct rpcent_test_data *,
|
||||
struct rpcent *);
|
||||
static int rpcent_fill_test_data(struct rpcent_test_data *);
|
||||
static int rpcent_test_correctness(struct rpcent *, void *);
|
||||
static int rpcent_test_getrpcbyname(struct rpcent *, void *);
|
||||
static int rpcent_test_getrpcbynumber(struct rpcent *, void *);
|
||||
static int rpcent_test_getrpcent(struct rpcent *, void *);
|
||||
|
||||
static void usage(void) __attribute__((__noreturn__));
|
||||
|
||||
IMPLEMENT_TEST_DATA(rpcent)
|
||||
IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
|
||||
IMPLEMENT_1PASS_TEST(rpcent)
|
||||
IMPLEMENT_2PASS_TEST(rpcent)
|
||||
|
||||
static void
|
||||
clone_rpcent(struct rpcent *dest, struct rpcent const *src)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
char **cp;
|
||||
int aliases_num;
|
||||
|
||||
memset(dest, 0, sizeof(struct rpcent));
|
||||
|
||||
if (src->r_name != NULL) {
|
||||
dest->r_name = strdup(src->r_name);
|
||||
assert(dest->r_name != NULL);
|
||||
}
|
||||
|
||||
dest->r_number = src->r_number;
|
||||
|
||||
if (src->r_aliases != NULL) {
|
||||
aliases_num = 0;
|
||||
for (cp = src->r_aliases; *cp; ++cp)
|
||||
++aliases_num;
|
||||
|
||||
dest->r_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
|
||||
assert(dest->r_aliases != NULL);
|
||||
memset(dest->r_aliases, 0, (aliases_num+1) * (sizeof(char *)));
|
||||
|
||||
for (cp = src->r_aliases; *cp; ++cp) {
|
||||
dest->r_aliases[cp - src->r_aliases] = strdup(*cp);
|
||||
assert(dest->r_aliases[cp - src->r_aliases] != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_rpcent(struct rpcent *rpc)
|
||||
{
|
||||
char **cp;
|
||||
|
||||
assert(rpc != NULL);
|
||||
|
||||
free(rpc->r_name);
|
||||
|
||||
for (cp = rpc->r_aliases; *cp; ++cp)
|
||||
free(*cp);
|
||||
free(rpc->r_aliases);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata)
|
||||
{
|
||||
char **c1, **c2;
|
||||
|
||||
if (rpc1 == rpc2)
|
||||
return 0;
|
||||
|
||||
if ((rpc1 == NULL) || (rpc2 == NULL))
|
||||
goto errfin;
|
||||
|
||||
if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) ||
|
||||
(rpc1->r_number != rpc2->r_number))
|
||||
goto errfin;
|
||||
|
||||
c1 = rpc1->r_aliases;
|
||||
c2 = rpc2->r_aliases;
|
||||
|
||||
if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == 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_rpcent(rpc1);
|
||||
dump_rpcent(rpc2);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen)
|
||||
{
|
||||
char **cp;
|
||||
int written;
|
||||
|
||||
written = snprintf(buffer, buflen, "%s %d",
|
||||
rpc->r_name, rpc->r_number);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (rpc->r_aliases != NULL) {
|
||||
if (*(rpc->r_aliases) != '\0') {
|
||||
for (cp = rpc->r_aliases; *cp; ++cp) {
|
||||
written = snprintf(buffer, buflen, " %s",*cp);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (buflen == 0)
|
||||
return;
|
||||
}
|
||||
} else
|
||||
snprintf(buffer, buflen, " noaliases");
|
||||
} else
|
||||
snprintf(buffer, buflen, " (null)");
|
||||
}
|
||||
|
||||
static int
|
||||
rpcent_read_snapshot_func(struct rpcent *rpc, 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(rpc, 0, sizeof(struct rpcent));
|
||||
while ( (s = strsep(&ps, " ")) != NULL) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
rpc->r_name = strdup(s);
|
||||
assert(rpc->r_name != NULL);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
rpc->r_number = (int)strtol(s, &ts, 10);
|
||||
if (*ts != '\0') {
|
||||
free(rpc->r_name);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sl == NULL) {
|
||||
if (strcmp(s, "(null)") == 0)
|
||||
return (0);
|
||||
|
||||
sl = sl_init();
|
||||
assert(sl != NULL);
|
||||
|
||||
if (strcmp(s, "noaliases") != 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(rpc->r_name);
|
||||
memset(rpc, 0, sizeof(struct rpcent));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
sl_add(sl, NULL);
|
||||
rpc->r_aliases = sl->sl_str;
|
||||
|
||||
/* NOTE: is it a dirty hack or not? */
|
||||
free(sl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_rpcent(struct rpcent *result)
|
||||
{
|
||||
if (result != NULL) {
|
||||
char buffer[1024];
|
||||
sdump_rpcent(result, buffer, sizeof(buffer));
|
||||
printf("%s\n", buffer);
|
||||
} else
|
||||
printf("(null)\n");
|
||||
}
|
||||
|
||||
static int
|
||||
rpcent_fill_test_data(struct rpcent_test_data *td)
|
||||
{
|
||||
struct rpcent *rpc;
|
||||
|
||||
setrpcent(1);
|
||||
while ((rpc = getrpcent()) != NULL) {
|
||||
if (rpcent_test_correctness(rpc, NULL) == 0)
|
||||
TEST_DATA_APPEND(rpcent, td, rpc);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
endrpcent();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
rpcent_test_correctness(struct rpcent *rpc, void *mdata)
|
||||
{
|
||||
if (debug) {
|
||||
printf("testing correctness with the following data:\n");
|
||||
dump_rpcent(rpc);
|
||||
}
|
||||
|
||||
if (rpc == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (rpc->r_name == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (rpc->r_number < 0)
|
||||
goto errfin;
|
||||
|
||||
if (rpc->r_aliases == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (debug)
|
||||
printf("correct\n");
|
||||
|
||||
return (0);
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("incorrect\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* rpcent_check_ambiguity() is needed when one port+rpc is associated with
|
||||
* more than one peice (these cases are usually marked as PROBLEM in
|
||||
* /etc/peices. This functions is needed also when one peice+rpc is
|
||||
* associated with several ports. We have to check all the rpcent structures
|
||||
* to make sure that rpc really exists and correct */
|
||||
static int
|
||||
rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc)
|
||||
{
|
||||
|
||||
return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent,
|
||||
NULL) != NULL ? 0 : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata)
|
||||
{
|
||||
char **alias;
|
||||
struct rpcent *rpc;
|
||||
|
||||
if (debug) {
|
||||
printf("testing getrpcbyname() with the following data:\n");
|
||||
dump_rpcent(rpc_model);
|
||||
}
|
||||
|
||||
rpc = getrpcbyname(rpc_model->r_name);
|
||||
if (rpcent_test_correctness(rpc, NULL) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
|
||||
(rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
|
||||
!=0))
|
||||
goto errfin;
|
||||
|
||||
for (alias = rpc_model->r_aliases; *alias; ++alias) {
|
||||
rpc = getrpcbyname(*alias);
|
||||
|
||||
if (rpcent_test_correctness(rpc, NULL) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
|
||||
(rpcent_check_ambiguity(
|
||||
(struct rpcent_test_data *)mdata, rpc) != 0))
|
||||
goto errfin;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
printf("ok\n");
|
||||
return (0);
|
||||
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("not ok\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata)
|
||||
{
|
||||
struct rpcent *rpc;
|
||||
|
||||
if (debug) {
|
||||
printf("testing getrpcbyport() with the following data...\n");
|
||||
dump_rpcent(rpc_model);
|
||||
}
|
||||
|
||||
rpc = getrpcbynumber(rpc_model->r_number);
|
||||
if ((rpcent_test_correctness(rpc, NULL) != 0) ||
|
||||
((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
|
||||
(rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
|
||||
!= 0))) {
|
||||
if (debug)
|
||||
printf("not ok\n");
|
||||
return (-1);
|
||||
} else {
|
||||
if (debug)
|
||||
printf("ok\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rpcent_test_getrpcent(struct rpcent *rpc, void *mdata)
|
||||
{
|
||||
/* Only correctness can be checked when doing 1-pass test for
|
||||
* getrpcent(). */
|
||||
return (rpcent_test_correctness(rpc, NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s -nve2 [-d] [-s <file>]\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct rpcent_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, "nve2ds:")) != -1)
|
||||
switch (c) {
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
case 'n':
|
||||
method = TEST_GETRPCBYNAME;
|
||||
break;
|
||||
case 'v':
|
||||
method = TEST_GETRPCBYNUMBER;
|
||||
break;
|
||||
case 'e':
|
||||
method = TEST_GETRPCENT;
|
||||
break;
|
||||
case '2':
|
||||
method = TEST_GETRPCENT_2PASS;
|
||||
break;
|
||||
case 's':
|
||||
snapshot_file = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent);
|
||||
TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent);
|
||||
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(rpcent, snapshot_file,
|
||||
&td_snap, rpcent_read_snapshot_func);
|
||||
}
|
||||
}
|
||||
|
||||
rv = rpcent_fill_test_data(&td);
|
||||
if (rv == -1)
|
||||
return (-1);
|
||||
switch (method) {
|
||||
case TEST_GETRPCBYNAME:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(rpcent, &td,
|
||||
rpcent_test_getrpcbyname, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(rpcent, &td_snap,
|
||||
rpcent_test_getrpcbyname, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETRPCBYNUMBER:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(rpcent, &td,
|
||||
rpcent_test_getrpcbynumber, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(rpcent, &td_snap,
|
||||
rpcent_test_getrpcbynumber, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETRPCENT:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent,
|
||||
(void *)&td);
|
||||
else
|
||||
rv = DO_2PASS_TEST(rpcent, &td, &td_snap,
|
||||
compare_rpcent, NULL);
|
||||
break;
|
||||
case TEST_GETRPCENT_2PASS:
|
||||
TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent);
|
||||
rv = rpcent_fill_test_data(&td_2pass);
|
||||
if (rv != -1)
|
||||
rv = DO_2PASS_TEST(rpcent, &td, &td_2pass,
|
||||
compare_rpcent, NULL);
|
||||
TEST_DATA_DESTROY(rpcent, &td_2pass);
|
||||
break;
|
||||
case TEST_BUILD_SNAPSHOT:
|
||||
if (snapshot_file != NULL)
|
||||
rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td,
|
||||
sdump_rpcent);
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
fin:
|
||||
TEST_DATA_DESTROY(rpcent, &td_snap);
|
||||
TEST_DATA_DESTROY(rpcent, &td);
|
||||
free(snapshot_file);
|
||||
return (rv);
|
||||
}
|
29
tools/regression/lib/libc/nss/test-getrpc.t
Normal file
29
tools/regression/lib/libc/nss/test-getrpc.t
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..8
|
||||
do_test 1 'getrpcbyname()' '-n'
|
||||
do_test 2 'getrpcbynumber()' '-v'
|
||||
do_test 3 'getrpcent()' '-e'
|
||||
do_test 4 'getrpcent() 2-pass' '-2'
|
||||
do_test 5 'building snapshot, if needed' '-s snapshot_rpc'
|
||||
do_test 6 'getrpcbyname() snapshot' '-n -s snapshot_rpc'
|
||||
do_test 7 'getrpcbynumber() snapshot' '-v -s snapshot_rpc'
|
||||
do_test 8 'getrpcent() snapshot' '-e -s snapshot_rpc'
|
551
tools/regression/lib/libc/nss/test-getserv.c
Normal file
551
tools/regression/lib/libc/nss/test-getserv.c
Normal file
@ -0,0 +1,551 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stringlist.h>
|
||||
#include <unistd.h>
|
||||
#include "testutil.h"
|
||||
|
||||
enum test_methods {
|
||||
TEST_GETSERVENT,
|
||||
TEST_GETSERVBYNAME,
|
||||
TEST_GETSERVBYPORT,
|
||||
TEST_GETSERVENT_2PASS,
|
||||
TEST_BUILD_SNAPSHOT
|
||||
};
|
||||
|
||||
static int debug = 0;
|
||||
static enum test_methods method = TEST_BUILD_SNAPSHOT;
|
||||
|
||||
DECLARE_TEST_DATA(servent)
|
||||
DECLARE_TEST_FILE_SNAPSHOT(servent)
|
||||
DECLARE_1PASS_TEST(servent)
|
||||
DECLARE_2PASS_TEST(servent)
|
||||
|
||||
static void clone_servent(struct servent *, struct servent const *);
|
||||
static int compare_servent(struct servent *, struct servent *, void *);
|
||||
static void dump_servent(struct servent *);
|
||||
static void free_servent(struct servent *);
|
||||
|
||||
static void sdump_servent(struct servent *, char *, size_t);
|
||||
static int servent_read_snapshot_func(struct servent *, char *);
|
||||
|
||||
static int servent_check_ambiguity(struct servent_test_data *,
|
||||
struct servent *);
|
||||
static int servent_fill_test_data(struct servent_test_data *);
|
||||
static int servent_test_correctness(struct servent *, void *);
|
||||
static int servent_test_getservbyname(struct servent *, void *);
|
||||
static int servent_test_getservbyport(struct servent *, void *);
|
||||
static int servent_test_getservent(struct servent *, void *);
|
||||
|
||||
static void usage(void) __attribute__((__noreturn__));
|
||||
|
||||
IMPLEMENT_TEST_DATA(servent)
|
||||
IMPLEMENT_TEST_FILE_SNAPSHOT(servent)
|
||||
IMPLEMENT_1PASS_TEST(servent)
|
||||
IMPLEMENT_2PASS_TEST(servent)
|
||||
|
||||
static void
|
||||
clone_servent(struct servent *dest, struct servent const *src)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
char **cp;
|
||||
int aliases_num;
|
||||
|
||||
memset(dest, 0, sizeof(struct servent));
|
||||
|
||||
if (src->s_name != NULL) {
|
||||
dest->s_name = strdup(src->s_name);
|
||||
assert(dest->s_name != NULL);
|
||||
}
|
||||
|
||||
if (src->s_proto != NULL) {
|
||||
dest->s_proto = strdup(src->s_proto);
|
||||
assert(dest->s_proto != NULL);
|
||||
}
|
||||
dest->s_port = src->s_port;
|
||||
|
||||
if (src->s_aliases != NULL) {
|
||||
aliases_num = 0;
|
||||
for (cp = src->s_aliases; *cp; ++cp)
|
||||
++aliases_num;
|
||||
|
||||
dest->s_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
|
||||
assert(dest->s_aliases != NULL);
|
||||
memset(dest->s_aliases, 0, (aliases_num+1) * (sizeof(char *)));
|
||||
|
||||
for (cp = src->s_aliases; *cp; ++cp) {
|
||||
dest->s_aliases[cp - src->s_aliases] = strdup(*cp);
|
||||
assert(dest->s_aliases[cp - src->s_aliases] != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_servent(struct servent *serv)
|
||||
{
|
||||
char **cp;
|
||||
|
||||
assert(serv != NULL);
|
||||
|
||||
free(serv->s_name);
|
||||
free(serv->s_proto);
|
||||
|
||||
for (cp = serv->s_aliases; *cp; ++cp)
|
||||
free(*cp);
|
||||
free(serv->s_aliases);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_servent(struct servent *serv1, struct servent *serv2, void *mdata)
|
||||
{
|
||||
char **c1, **c2;
|
||||
|
||||
if (serv1 == serv2)
|
||||
return 0;
|
||||
|
||||
if ((serv1 == NULL) || (serv2 == NULL))
|
||||
goto errfin;
|
||||
|
||||
if ((strcmp(serv1->s_name, serv2->s_name) != 0) ||
|
||||
(strcmp(serv1->s_proto, serv2->s_proto) != 0) ||
|
||||
(serv1->s_port != serv2->s_port))
|
||||
goto errfin;
|
||||
|
||||
c1 = serv1->s_aliases;
|
||||
c2 = serv2->s_aliases;
|
||||
|
||||
if ((serv1->s_aliases == NULL) || (serv2->s_aliases == 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_servent(serv1);
|
||||
dump_servent(serv2);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
sdump_servent(struct servent *serv, char *buffer, size_t buflen)
|
||||
{
|
||||
char **cp;
|
||||
int written;
|
||||
|
||||
written = snprintf(buffer, buflen, "%s %d %s",
|
||||
serv->s_name, ntohs(serv->s_port), serv->s_proto);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (serv->s_aliases != NULL) {
|
||||
if (*(serv->s_aliases) != '\0') {
|
||||
for (cp = serv->s_aliases; *cp; ++cp) {
|
||||
written = snprintf(buffer, buflen, " %s",*cp);
|
||||
buffer += written;
|
||||
if (written > buflen)
|
||||
return;
|
||||
buflen -= written;
|
||||
|
||||
if (buflen == 0)
|
||||
return;
|
||||
}
|
||||
} else
|
||||
snprintf(buffer, buflen, " noaliases");
|
||||
} else
|
||||
snprintf(buffer, buflen, " (null)");
|
||||
}
|
||||
|
||||
static int
|
||||
servent_read_snapshot_func(struct servent *serv, 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(serv, 0, sizeof(struct servent));
|
||||
while ( (s = strsep(&ps, " ")) != NULL) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
serv->s_name = strdup(s);
|
||||
assert(serv->s_name != NULL);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
serv->s_port = htons(
|
||||
(int)strtol(s, &ts, 10));
|
||||
if (*ts != '\0') {
|
||||
free(serv->s_name);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
serv->s_proto = strdup(s);
|
||||
assert(serv->s_proto != NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sl == NULL) {
|
||||
if (strcmp(s, "(null)") == 0)
|
||||
return (0);
|
||||
|
||||
sl = sl_init();
|
||||
assert(sl != NULL);
|
||||
|
||||
if (strcmp(s, "noaliases") != 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(serv->s_name);
|
||||
free(serv->s_proto);
|
||||
memset(serv, 0, sizeof(struct servent));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
sl_add(sl, NULL);
|
||||
serv->s_aliases = sl->sl_str;
|
||||
|
||||
/* NOTE: is it a dirty hack or not? */
|
||||
free(sl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_servent(struct servent *result)
|
||||
{
|
||||
if (result != NULL) {
|
||||
char buffer[1024];
|
||||
sdump_servent(result, buffer, sizeof(buffer));
|
||||
printf("%s\n", buffer);
|
||||
} else
|
||||
printf("(null)\n");
|
||||
}
|
||||
|
||||
static int
|
||||
servent_fill_test_data(struct servent_test_data *td)
|
||||
{
|
||||
struct servent *serv;
|
||||
|
||||
setservent(1);
|
||||
while ((serv = getservent()) != NULL) {
|
||||
if (servent_test_correctness(serv, NULL) == 0)
|
||||
TEST_DATA_APPEND(servent, td, serv);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
endservent();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
servent_test_correctness(struct servent *serv, void *mdata)
|
||||
{
|
||||
if (debug) {
|
||||
printf("testing correctness with the following data:\n");
|
||||
dump_servent(serv);
|
||||
}
|
||||
|
||||
if (serv == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (serv->s_name == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (serv->s_proto == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (ntohs(serv->s_port < 0))
|
||||
goto errfin;
|
||||
|
||||
if (serv->s_aliases == NULL)
|
||||
goto errfin;
|
||||
|
||||
if (debug)
|
||||
printf("correct\n");
|
||||
|
||||
return (0);
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("incorrect\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* servent_check_ambiguity() is needed when one port+proto is associated with
|
||||
* more than one service (these cases are usually marked as PROBLEM in
|
||||
* /etc/services. This functions is needed also when one service+proto is
|
||||
* associated with several ports. We have to check all the servent structures
|
||||
* to make sure that serv really exists and correct */
|
||||
static int
|
||||
servent_check_ambiguity(struct servent_test_data *td, struct servent *serv)
|
||||
{
|
||||
|
||||
return (TEST_DATA_FIND(servent, td, serv, compare_servent,
|
||||
NULL) != NULL ? 0 : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
servent_test_getservbyname(struct servent *serv_model, void *mdata)
|
||||
{
|
||||
char **alias;
|
||||
struct servent *serv;
|
||||
|
||||
if (debug) {
|
||||
printf("testing getservbyname() with the following data:\n");
|
||||
dump_servent(serv_model);
|
||||
}
|
||||
|
||||
serv = getservbyname(serv_model->s_name, serv_model->s_proto);
|
||||
if (servent_test_correctness(serv, NULL) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((compare_servent(serv, serv_model, NULL) != 0) &&
|
||||
(servent_check_ambiguity((struct servent_test_data *)mdata, serv)
|
||||
!=0))
|
||||
goto errfin;
|
||||
|
||||
for (alias = serv_model->s_aliases; *alias; ++alias) {
|
||||
serv = getservbyname(*alias, serv_model->s_proto);
|
||||
|
||||
if (servent_test_correctness(serv, NULL) != 0)
|
||||
goto errfin;
|
||||
|
||||
if ((compare_servent(serv, serv_model, NULL) != 0) &&
|
||||
(servent_check_ambiguity(
|
||||
(struct servent_test_data *)mdata, serv) != 0))
|
||||
goto errfin;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
printf("ok\n");
|
||||
return (0);
|
||||
|
||||
errfin:
|
||||
if (debug)
|
||||
printf("not ok\n");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
servent_test_getservbyport(struct servent *serv_model, void *mdata)
|
||||
{
|
||||
struct servent *serv;
|
||||
|
||||
if (debug) {
|
||||
printf("testing getservbyport() with the following data...\n");
|
||||
dump_servent(serv_model);
|
||||
}
|
||||
|
||||
serv = getservbyport(serv_model->s_port, serv_model->s_proto);
|
||||
if ((servent_test_correctness(serv, NULL) != 0) ||
|
||||
((compare_servent(serv, serv_model, NULL) != 0) &&
|
||||
(servent_check_ambiguity((struct servent_test_data *)mdata, serv)
|
||||
!= 0))) {
|
||||
if (debug)
|
||||
printf("not ok\n");
|
||||
return (-1);
|
||||
} else {
|
||||
if (debug)
|
||||
printf("ok\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
servent_test_getservent(struct servent *serv, void *mdata)
|
||||
{
|
||||
/* Only correctness can be checked when doing 1-pass test for
|
||||
* getservent(). */
|
||||
return (servent_test_correctness(serv, NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s -npe2 [-d] [-s <file>]\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct servent_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, "npe2ds:")) != -1)
|
||||
switch (c) {
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
case 'n':
|
||||
method = TEST_GETSERVBYNAME;
|
||||
break;
|
||||
case 'p':
|
||||
method = TEST_GETSERVBYPORT;
|
||||
break;
|
||||
case 'e':
|
||||
method = TEST_GETSERVENT;
|
||||
break;
|
||||
case '2':
|
||||
method = TEST_GETSERVENT_2PASS;
|
||||
break;
|
||||
case 's':
|
||||
snapshot_file = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
TEST_DATA_INIT(servent, &td, clone_servent, free_servent);
|
||||
TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent);
|
||||
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(servent, snapshot_file,
|
||||
&td_snap, servent_read_snapshot_func);
|
||||
}
|
||||
}
|
||||
|
||||
rv = servent_fill_test_data(&td);
|
||||
if (rv == -1)
|
||||
return (-1);
|
||||
switch (method) {
|
||||
case TEST_GETSERVBYNAME:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(servent, &td,
|
||||
servent_test_getservbyname, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(servent, &td_snap,
|
||||
servent_test_getservbyname, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETSERVBYPORT:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(servent, &td,
|
||||
servent_test_getservbyport, (void *)&td);
|
||||
else
|
||||
rv = DO_1PASS_TEST(servent, &td_snap,
|
||||
servent_test_getservbyport, (void *)&td_snap);
|
||||
break;
|
||||
case TEST_GETSERVENT:
|
||||
if (snapshot_file == NULL)
|
||||
rv = DO_1PASS_TEST(servent, &td, servent_test_getservent,
|
||||
(void *)&td);
|
||||
else
|
||||
rv = DO_2PASS_TEST(servent, &td, &td_snap,
|
||||
compare_servent, NULL);
|
||||
break;
|
||||
case TEST_GETSERVENT_2PASS:
|
||||
TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent);
|
||||
rv = servent_fill_test_data(&td_2pass);
|
||||
if (rv != -1)
|
||||
rv = DO_2PASS_TEST(servent, &td, &td_2pass,
|
||||
compare_servent, NULL);
|
||||
TEST_DATA_DESTROY(servent, &td_2pass);
|
||||
break;
|
||||
case TEST_BUILD_SNAPSHOT:
|
||||
if (snapshot_file != NULL)
|
||||
rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td,
|
||||
sdump_servent);
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
fin:
|
||||
TEST_DATA_DESTROY(servent, &td_snap);
|
||||
TEST_DATA_DESTROY(servent, &td);
|
||||
free(snapshot_file);
|
||||
return (rv);
|
||||
}
|
29
tools/regression/lib/libc/nss/test-getserv.t
Normal file
29
tools/regression/lib/libc/nss/test-getserv.t
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..8
|
||||
do_test 1 'getservbyname()' '-n'
|
||||
do_test 2 'getservbyport()' '-p'
|
||||
do_test 3 'getservent()' '-e'
|
||||
do_test 4 'getservent() 2-pass' '-2'
|
||||
do_test 5 'building snapshot, if needed' '-s snapshot_serv'
|
||||
do_test 6 'getservbyname() snapshot' '-n -s snapshot_serv'
|
||||
do_test 7 'getservbyport() snapshot' '-p -s snapshot_serv'
|
||||
do_test 8 'getservent() snapshot' '-e -s snapshot_serv'
|
235
tools/regression/lib/libc/nss/test-getusershell.c
Normal file
235
tools/regression/lib/libc/nss/test-getusershell.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "testutil.h"
|
||||
|
||||
enum test_methods {
|
||||
TEST_GETUSERSHELL,
|
||||
TEST_BUILD_SNAPSHOT
|
||||
};
|
||||
|
||||
struct usershell {
|
||||
char *path;
|
||||
};
|
||||
|
||||
static int debug = 0;
|
||||
static enum test_methods method = TEST_GETUSERSHELL;
|
||||
|
||||
DECLARE_TEST_DATA(usershell)
|
||||
DECLARE_TEST_FILE_SNAPSHOT(usershell)
|
||||
DECLARE_2PASS_TEST(usershell)
|
||||
|
||||
static void clone_usershell(struct usershell *, struct usershell const *);
|
||||
static int compare_usershell(struct usershell *, struct usershell *, void *);
|
||||
static void free_usershell(struct usershell *);
|
||||
|
||||
static void sdump_usershell(struct usershell *, char *, size_t);
|
||||
static void dump_usershell(struct usershell *);
|
||||
|
||||
static int usershell_read_snapshot_func(struct usershell *, char *);
|
||||
|
||||
static void usage(void) __attribute__((__noreturn__));
|
||||
|
||||
IMPLEMENT_TEST_DATA(usershell)
|
||||
IMPLEMENT_TEST_FILE_SNAPSHOT(usershell)
|
||||
IMPLEMENT_2PASS_TEST(usershell)
|
||||
|
||||
static void
|
||||
clone_usershell(struct usershell *dest, struct usershell const *src)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
if (src->path != NULL) {
|
||||
dest->path = strdup(src->path);
|
||||
assert(dest->path != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compare_usershell(struct usershell *us1, struct usershell *us2, void *mdata)
|
||||
{
|
||||
int rv;
|
||||
|
||||
assert(us1 != NULL);
|
||||
assert(us2 != NULL);
|
||||
|
||||
dump_usershell(us1);
|
||||
dump_usershell(us2);
|
||||
|
||||
if (us1 == us2)
|
||||
return (0);
|
||||
|
||||
rv = strcmp(us1->path, us2->path);
|
||||
if (rv != 0) {
|
||||
printf("following structures are not equal:\n");
|
||||
dump_usershell(us1);
|
||||
dump_usershell(us2);
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static void
|
||||
free_usershell(struct usershell *us)
|
||||
{
|
||||
free(us->path);
|
||||
}
|
||||
|
||||
static void
|
||||
sdump_usershell(struct usershell *us, char *buffer, size_t buflen)
|
||||
{
|
||||
snprintf(buffer, buflen, "%s", us->path);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_usershell(struct usershell *us)
|
||||
{
|
||||
if (us != NULL) {
|
||||
char buffer[2048];
|
||||
sdump_usershell(us, buffer, sizeof(buffer));
|
||||
printf("%s\n", buffer);
|
||||
} else
|
||||
printf("(null)\n");
|
||||
}
|
||||
|
||||
static int
|
||||
usershell_read_snapshot_func(struct usershell *us, char *line)
|
||||
{
|
||||
us->path = strdup(line);
|
||||
assert(us->path != NULL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s [-d] -s <file>\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct usershell_test_data td, td_snap;
|
||||
struct usershell ushell;
|
||||
char *snapshot_file;
|
||||
int rv;
|
||||
int c;
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
rv = 0;
|
||||
snapshot_file = NULL;
|
||||
while ((c = getopt(argc, argv, "ds:")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 's':
|
||||
snapshot_file = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_DATA_INIT(usershell, &td, clone_usershell, free_usershell);
|
||||
TEST_DATA_INIT(usershell, &td_snap, clone_usershell, free_usershell);
|
||||
|
||||
setusershell();
|
||||
while ((ushell.path = getusershell()) != NULL) {
|
||||
if (debug) {
|
||||
printf("usershell found:\n");
|
||||
dump_usershell(&ushell);
|
||||
}
|
||||
TEST_DATA_APPEND(usershell, &td, &ushell);
|
||||
}
|
||||
endusershell();
|
||||
|
||||
|
||||
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 snapshot file %s\n",
|
||||
snapshot_file);
|
||||
|
||||
rv = -1;
|
||||
goto fin;
|
||||
}
|
||||
} else {
|
||||
rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file,
|
||||
&td_snap, usershell_read_snapshot_func);
|
||||
if (rv != 0) {
|
||||
if (debug)
|
||||
printf("error reading snapshot file\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case TEST_GETUSERSHELL:
|
||||
if (snapshot_file != NULL) {
|
||||
rv = DO_2PASS_TEST(usershell, &td, &td_snap,
|
||||
compare_usershell, NULL);
|
||||
}
|
||||
break;
|
||||
case TEST_BUILD_SNAPSHOT:
|
||||
if (snapshot_file != NULL) {
|
||||
rv = TEST_SNAPSHOT_FILE_WRITE(usershell, snapshot_file, &td,
|
||||
sdump_usershell);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
fin:
|
||||
TEST_DATA_DESTROY(usershell, &td_snap);
|
||||
TEST_DATA_DESTROY(usershell, &td);
|
||||
free(snapshot_file);
|
||||
return (rv);
|
||||
|
||||
}
|
22
tools/regression/lib/libc/nss/test-getusershell.t
Normal file
22
tools/regression/lib/libc/nss/test-getusershell.t
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
# $FreeBSD$
|
||||
|
||||
do_test() {
|
||||
number=$1
|
||||
comment=$2
|
||||
opt=$3
|
||||
if ./$executable $opt; then
|
||||
echo "ok $number - $comment"
|
||||
else
|
||||
echo "not ok $number - $comment"
|
||||
fi
|
||||
}
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
executable=`basename $0 .t`
|
||||
|
||||
make $executable 2>&1 > /dev/null
|
||||
|
||||
echo 1..1
|
||||
do_test 1 'getusershell() snapshot' '-s snapshot_usershell'
|
334
tools/regression/lib/libc/nss/testutil.h
Normal file
334
tools/regression/lib/libc/nss/testutil.h
Normal file
@ -0,0 +1,334 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define DECLARE_TEST_DATA(ent) \
|
||||
struct ent##_entry { \
|
||||
struct ent data; \
|
||||
STAILQ_ENTRY(ent##_entry) entries; \
|
||||
}; \
|
||||
\
|
||||
struct ent##_test_data { \
|
||||
void (*clone_func)(struct ent *, struct ent const *); \
|
||||
void (*free_func)(struct ent *); \
|
||||
\
|
||||
STAILQ_HEAD(ent_head, ent##_entry) snapshot_data; \
|
||||
}; \
|
||||
\
|
||||
void __##ent##_test_data_init(struct ent##_test_data *, \
|
||||
void (*)(struct ent *, struct ent const *), \
|
||||
void (*freef)(struct ent *)); \
|
||||
void __##ent##_test_data_destroy(struct ent##_test_data *); \
|
||||
\
|
||||
void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
|
||||
int __##ent##_test_data_foreach(struct ent##_test_data *, \
|
||||
int (*)(struct ent *, void *), void *); \
|
||||
int __##ent##_test_data_compare(struct ent##_test_data *, \
|
||||
struct ent##_test_data *, int (*)(struct ent *, struct ent *, \
|
||||
void *), void *); \
|
||||
struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
|
||||
int (*)(struct ent *, struct ent *, void *), void *); \
|
||||
void __##ent##_test_data_clear(struct ent##_test_data *);
|
||||
|
||||
#define TEST_DATA_INIT(ent, td, clonef, freef)\
|
||||
__##ent##_test_data_init(td, clonef, freef)
|
||||
#define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
|
||||
#define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
|
||||
#define TEST_DATA_FOREACH(ent, td, f, mdata)\
|
||||
__##ent##_test_data_foreach(td, f, mdata)
|
||||
#define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
|
||||
__##ent##_test_data_compare(td1, td2, fcmp, mdata);
|
||||
#define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
|
||||
__##ent##_test_data_find(td, d, fcmp, mdata)
|
||||
#define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
|
||||
|
||||
#define IMPLEMENT_TEST_DATA(ent) \
|
||||
void \
|
||||
__##ent##_test_data_init(struct ent##_test_data *td, \
|
||||
void (*clonef)(struct ent *, struct ent const *), \
|
||||
void (*freef)(struct ent *)) \
|
||||
{ \
|
||||
assert(td != NULL); \
|
||||
assert(clonef != NULL); \
|
||||
assert(freef != NULL); \
|
||||
\
|
||||
memset(td, 0, sizeof(*td)); \
|
||||
td->clone_func = clonef; \
|
||||
td->free_func = freef; \
|
||||
STAILQ_INIT(&td->snapshot_data); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
__##ent##_test_data_destroy(struct ent##_test_data *td) \
|
||||
{ \
|
||||
__##ent##_test_data_clear(td); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
__##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
|
||||
{ \
|
||||
struct ent##_entry *e; \
|
||||
\
|
||||
assert(td != NULL); \
|
||||
assert(app_data != NULL); \
|
||||
\
|
||||
e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \
|
||||
assert(e != NULL); \
|
||||
memset(e, 0, sizeof(struct ent##_entry)); \
|
||||
\
|
||||
td->clone_func(&e->data, app_data); \
|
||||
STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries); \
|
||||
} \
|
||||
\
|
||||
int \
|
||||
__##ent##_test_data_foreach(struct ent##_test_data *td, \
|
||||
int (*forf)(struct ent *, void *), void *mdata) \
|
||||
{ \
|
||||
struct ent##_entry *e; \
|
||||
int rv; \
|
||||
\
|
||||
assert(td != NULL); \
|
||||
assert(forf != NULL); \
|
||||
\
|
||||
rv = 0; \
|
||||
STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
|
||||
rv = forf(&e->data, mdata); \
|
||||
if (rv != 0) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
return (rv); \
|
||||
} \
|
||||
\
|
||||
int \
|
||||
__##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
|
||||
int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
|
||||
{ \
|
||||
struct ent##_entry *e1, *e2; \
|
||||
int rv; \
|
||||
\
|
||||
assert(td1 != NULL); \
|
||||
assert(td2 != NULL); \
|
||||
assert(cmp_func != NULL); \
|
||||
\
|
||||
e1 = STAILQ_FIRST(&td1->snapshot_data); \
|
||||
e2 = STAILQ_FIRST(&td2->snapshot_data); \
|
||||
\
|
||||
rv = 0; \
|
||||
do { \
|
||||
if ((e1 == NULL) || (e2 == NULL)) { \
|
||||
if (e1 == e2) \
|
||||
return (0); \
|
||||
else \
|
||||
return (-1); \
|
||||
} \
|
||||
\
|
||||
rv = cmp_func(&e1->data, &e2->data, mdata); \
|
||||
e1 = STAILQ_NEXT(e1, entries); \
|
||||
e2 = STAILQ_NEXT(e2, entries); \
|
||||
} while (rv == 0); \
|
||||
\
|
||||
return (rv); \
|
||||
} \
|
||||
\
|
||||
struct ent * \
|
||||
__##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \
|
||||
int (*cmp)(struct ent *, struct ent *, void *), void *mdata) \
|
||||
{ \
|
||||
struct ent##_entry *e; \
|
||||
struct ent *result; \
|
||||
\
|
||||
assert(td != NULL); \
|
||||
assert(cmp != NULL); \
|
||||
\
|
||||
result = NULL; \
|
||||
STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
|
||||
if (cmp(&e->data, data, mdata) == 0) { \
|
||||
result = &e->data; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return (result); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
void \
|
||||
__##ent##_test_data_clear(struct ent##_test_data *td) \
|
||||
{ \
|
||||
struct ent##_entry *e; \
|
||||
assert(td != NULL); \
|
||||
\
|
||||
while (!STAILQ_EMPTY(&td->snapshot_data)) { \
|
||||
e = STAILQ_FIRST(&td->snapshot_data); \
|
||||
STAILQ_REMOVE_HEAD(&td->snapshot_data, entries); \
|
||||
\
|
||||
td->free_func(&e->data); \
|
||||
free(e); \
|
||||
} \
|
||||
}
|
||||
|
||||
\
|
||||
#define DECLARE_TEST_FILE_SNAPSHOT(ent) \
|
||||
struct ent##_snp_param { \
|
||||
FILE *fp; \
|
||||
void (*sdump_func)(struct ent *, char *, size_t); \
|
||||
}; \
|
||||
\
|
||||
int __##ent##_snapshot_write_func(struct ent *, void *); \
|
||||
int __##ent##_snapshot_write(char const *, struct ent##_test_data *, \
|
||||
void (*)(struct ent *, char *, size_t)); \
|
||||
int __##ent##_snapshot_read(char const *, struct ent##_test_data *, \
|
||||
int (*)(struct ent *, char *));
|
||||
|
||||
#define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f) \
|
||||
__##ent##_snapshot_write(fname, td, f)
|
||||
#define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f) \
|
||||
__##ent##_snapshot_read(fname, td, f)
|
||||
|
||||
#define IMPLEMENT_TEST_FILE_SNAPSHOT(ent) \
|
||||
int \
|
||||
__##ent##_snapshot_write_func(struct ent *data, void *mdata) \
|
||||
{ \
|
||||
char buffer[1024]; \
|
||||
struct ent##_snp_param *param; \
|
||||
\
|
||||
assert(data != NULL); \
|
||||
\
|
||||
param = (struct ent##_snp_param *)mdata; \
|
||||
param->sdump_func(data, buffer, sizeof(buffer)); \
|
||||
fputs(buffer, param->fp); \
|
||||
fputc('\n', param->fp); \
|
||||
\
|
||||
return (0); \
|
||||
} \
|
||||
\
|
||||
int \
|
||||
__##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \
|
||||
void (*sdump_func)(struct ent *, char *, size_t)) \
|
||||
{ \
|
||||
struct ent##_snp_param param; \
|
||||
\
|
||||
assert(fname != NULL); \
|
||||
assert(td != NULL); \
|
||||
\
|
||||
param.fp = fopen(fname, "w"); \
|
||||
if (param.fp == NULL) \
|
||||
return (-1); \
|
||||
\
|
||||
param.sdump_func = sdump_func; \
|
||||
__##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, ¶m);\
|
||||
fclose(param.fp); \
|
||||
\
|
||||
return (0); \
|
||||
} \
|
||||
\
|
||||
int \
|
||||
__##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \
|
||||
int (*read_func)(struct ent *, char *)) \
|
||||
{ \
|
||||
char buffer[1024]; \
|
||||
struct ent data; \
|
||||
char *s; \
|
||||
FILE *fi; \
|
||||
size_t len; \
|
||||
int rv; \
|
||||
\
|
||||
assert(fname != NULL); \
|
||||
assert(td != NULL); \
|
||||
\
|
||||
fi = fopen(fname, "r"); \
|
||||
if (fi == NULL) \
|
||||
return (-1); \
|
||||
\
|
||||
rv = 0; \
|
||||
memset(buffer, 0, sizeof(buffer)); \
|
||||
while (!feof(fi)) { \
|
||||
s = fgets(buffer, sizeof(buffer), fi); \
|
||||
if (s != NULL && s[0] != '#') { \
|
||||
len = strlen(s); \
|
||||
if (len == 0) \
|
||||
continue; \
|
||||
if (buffer[len - 1] == '\n') \
|
||||
buffer[len -1] = '\0'; \
|
||||
\
|
||||
rv = read_func(&data, s); \
|
||||
if (rv == 0) { \
|
||||
__##ent##_test_data_append(td, &data); \
|
||||
td->free_func(&data); \
|
||||
} else \
|
||||
goto fin; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
fin: \
|
||||
fclose(fi); \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define DECLARE_1PASS_TEST(ent) \
|
||||
int __##ent##_1pass_test(struct ent##_test_data *, \
|
||||
int (*)(struct ent *, void *), \
|
||||
void *);
|
||||
|
||||
#define DO_1PASS_TEST(ent, td, f, mdata) \
|
||||
__##ent##_1pass_test(td, f, mdata)
|
||||
|
||||
#define IMPLEMENT_1PASS_TEST(ent) \
|
||||
int \
|
||||
__##ent##_1pass_test(struct ent##_test_data *td, \
|
||||
int (*tf)(struct ent *, void *), \
|
||||
void *mdata) \
|
||||
{ \
|
||||
int rv; \
|
||||
rv = __##ent##_test_data_foreach(td, tf, mdata); \
|
||||
\
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define DECLARE_2PASS_TEST(ent) \
|
||||
int __##ent##_2pass_test(struct ent##_test_data *, \
|
||||
struct ent##_test_data *, \
|
||||
int (*)(struct ent *, struct ent *, void *), void *);
|
||||
|
||||
#define DO_2PASS_TEST(ent, td1, td2, f, mdata) \
|
||||
__##ent##_2pass_test(td1, td2, f, mdata)
|
||||
|
||||
#define IMPLEMENT_2PASS_TEST(ent) \
|
||||
int \
|
||||
__##ent##_2pass_test(struct ent##_test_data *td1, \
|
||||
struct ent##_test_data *td2, \
|
||||
int (*cmp_func)(struct ent *, struct ent *, void *), \
|
||||
void *cmp_mdata) \
|
||||
{ \
|
||||
int rv; \
|
||||
\
|
||||
rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata); \
|
||||
return (rv); \
|
||||
}
|
Loading…
Reference in New Issue
Block a user