[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Feedback on lsb fhs test suite



On Mar 30,  3:01pm in "Feedback on lsb fhs ", Christopher Yeoh wrote:
> Hi,
>
> I've been trying out the lsb fhs test suite on a few different distros
> (Debian (woody), Redhat 6.0 & Redhat 6.1) and ran into a few issues
> along the way and was wondering if other people had the same problems
> or if I was doing something differently.
>
> In all the tests I used the 3.3f version of tet.
>
> Release (fhs-1.0)
> -----------------
>
> On the debian install when doing the `config.sh' step it detects
> /usr/bin/c89 as the compiler to use by default. This causes some
> compile problems in the later make stage. Setting it to use
> /usr/bin/cc instead makes it work.
>
For these modes of testing , its fine to select cc rather than c89.
For certain modes of testing, such as when the generic vsxgen
framework is used for UNIX certification (where the POSIX.2
commands are mandatory) c89 is required.
I expect that using c89 on debian may cause the namespace to
be restricted and you may need to add extra feature test macros
to enable things.

I've attached a default vsxparams file for use with Redhat 6.0
you can place this in the directory
SRC/install/params.data and it will be presented as a file
from which to set config.sh defaults. We should probably
create a few of these for different distributions.


> Development (fhs-1.02)
> ----------------------
>
> Some of the install doco (INSTALL.LSB-FHS) needs updating:
> - profile in the tgz file has been renamed to lsb.profile
Yes I changed these to allow the merger of multiple testsets
under the vsxgen framework so that files won't clobber each other.
(For those who don't know use of the vsxgen framework allows
us to merge testsets or just run them separately).
> - The TET_EXECUTE path in the lsb.profile file is out of sync with
>   the instructions and should be set to:
>   TET_EXECUTE=$TET_ROOT/vsx4/TESTROOT
Ok, maybe Nick has fixed this.
>
> On all the distros I tried, I got a compile error when doing the `su
> root -c make' step and had to fiddle a bit with nonposix.c to get the
> prototypes consistent with header files which it includes.
The file nonposix.c contains routines outside of POSIX that the
harness requires and needs to be tuned to the particular platform -
we use these suites on many different platforms. I've attached
a nonposix.c that i use here on Redhat 6.0 (also userintf.c which
is another file you are expected to tune for the platform).
>
> On the debian distro I had trouble compiling c-parse.y. Andrew Josey
> pointed out that debian links yacc to bison. Compiling up byacc.1.9
> and getting it to use that instead fixed the problem.
>
Yes it seems bison does not hack it in all instances.
> Chris.
> --
> cyeoh@linuxcare.com

I've also found that using pax works better for the tar and cpio
tests than those utilities on RH6.0
regards
Andrew


#VSX_OPER - the name of the person running the VSX test suite
VSX_OPER="Unknown"

#VSX_ORG - the name of the organisation for whom VSX is being run
VSX_ORG="Unknown"

#VSX_SYS - the name of the system (hardware and software) on which the VSX
#	verification is being performed
VSX_SYS="Linux Redhat 6.0 2.2.5-15 #1 Mon Apr 19 22:21:09 EDT 1999 gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)"

#TEST_MODE - the VSX test mode to be used
TEST_MODE="UNIX98"

#TEST_XNFS - indicates whether to test the XNFS specification
#	The value should be "y" for XNFS testing, "n" for XSH testing.
TEST_XNFS="n"

#SUBSETS - a space-separated list of the subsets of VSX to be installed
#	For example: "base dm"
SUBSETS="base"

#VSXDIR - this parameter defines the source directory for the VSX software.
#	The value given to this parameter must be a full pathname
VSXDIR="/home/tet/vsx4/SRC"

#TET_EXECUTE - this parameter defines the directory from which the VSX tests
#	will be executed.
#	The value given to this parameter must be a full pathname
TET_EXECUTE="/home/tet/vsx4/TESTROOT"

#SPEED - this parameter defines the speed of the machine on a 1-10 scale
#	A speed of 1 is given to a very fast machine and 10 to a very 
#	slow machine
SPEED="5"

#PATH - the command search path to be used when installing and building VSX.
#	Normally set to the PATH in effect when config.sh was run.
#	Must contain the directories where commands specified in other
#	parameters reside (if full path names are not given).
PATH="/bin:/usr/bin:/usr/sbin:/usr/local/bin:/home/tet/bin:/home/tet/vsx4/BIN:/home/tet/vsx4/SRC/BIN:.:"

#INCDIRS - this parameter defines the directories which contain the include
#	files for the system being tested, in order of searching.
#	This parameter is normally set to /usr/include
INCDIRS="/usr/include /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include "

#CC - this parameter defines the C compiler to be used in building the suite.
#	This parameter is normally set to a pathname for c89 or cc.
#	It must be set to (a pathname for) c89 for UNIX98 registration runs.
CC="/usr/bin/cc"

#COPTS - this parameter defines any special command line options needed by the
#	C compiler.
#	This parameter is normally set to ""
COPTS=""

#THR_COPTS - this parameter defines C compiler options to be used instead of
#	COPTS when compiling code that will be linked with the TETware
#	thread-safe API library.  The options must be compatible with those
#	used in THR_COPTS in the TETware defines.mk file.
#	This parameter is only needed by some subsets.
THR_COPTS=""

#DEFINES - feature test macros appropriate for the test mode
#	This parameter is set automatically and should not need to be changed.
DEFINES="-D_XOPEN_SOURCE=500"

#LDFLAGS - this parameter defines any special link editor (loader) options 
#	needed by the C compiler link edit phase.
#	This parameter is normally set to ""
LDFLAGS=""

#CFPURE -  this parameter defines the link editor option used to produce a
#	pure executable (shared text) program.
#	This parameter is only needed by some subsets, and is not used
#	when testing XNFS.  Some systems require this parameter to be set
#	to -n (non-X/Open option).  Normally it is set to "".
CFPURE=""

#LORDER - this parameter defines the sequential object library ordering program.
#	If the system has an archiver which does not need lorder this
#	parameter should be set to "echo".
LORDER="echo"

#TSORT - topological sort program used in library ordering.
#	If LORDER has been set to "echo", this parameter should be set to "cat".
#	Otherwise this parameter should be set to "tsort"
TSORT="cat"

#RANLIB - this parameter defines the random object library ordering program.
#	If this parameter is set to "ranlib", LORDER should be set to "echo"
#	and TSORT set to "cat".
#	Otherwise this parameter should be set to "echo"
RANLIB="ranlib"

#AR - the command (and options) used to create a library archive.
#	This parameter is normally set to "ar cr"
AR="ar cr"

#CHOWN - the command used to change the ownership of files.
#	This parameter is normally set to "chown" or "/etc/chown"
CHOWN="chown"

#CHGRP - the command used to change the group ownership of files.
#	This parameter is normally set to "chgrp"
CHGRP="chgrp"

#CHMOD - the command used to change the mode of files
#	This parameter is normally set to "chmod"
CHMOD="chmod"

#MLIB - the name of the mathematics library
#	This parameter is only needed by some subsets, and is not used
#	when testing XNFS.  It is typically set to "/usr/lib/libm.a".
MLIB="-lm"

#RPCLIB - the name of the RPC library
#	This parameter is only used when testing XNFS.
RPCLIB=".../SRC/LIB/xnfs_socket.a"

#RPC_TYPE - whether the RPC library is TLI or socket-based
#	This parameter must be set to "TLI" or "socket".
#	This parameter is only used when testing XNFS.
RPC_TYPE=""

#SYSLIBS - the names of additional libraries needed to compile VSX
#	These library names should be full path names.
#	Typical libraries needed on this line are:-
#		The library containing the directory routines
#		The library containing the enhanced memory allocation routines
#		The library containing the vprintf function
#		The library containing the NLS routines
#	The parameter should be of the form "/usr/lib/libnam1.a /lib/libnam3.a"
#	This parameter will often be set to ""
SYSLIBS="-lcrypt"

#XNFS_CLIENT - the name of the XNFS client system
#	This parameter is only used when testing XNFS.
XNFS_CLIENT=""

#XNFS_SERVER - the name of the XNFS server system
#	This parameter is only used when testing XNFS.
XNFS_SERVER=""

#SERVER_TET_ROOT - the pathname of the TET_ROOT directory on the server
#	This parameter is only used when testing XNFS.
SERVER_TET_ROOT=""

#NOSPC_DEV - the mountable device to be used for ENOSPC testing
#	This parameter is only needed by some subsets, and is not used
#	when testing XNFS.
NOSPC_DEV="/dev/fd0"

#VPRINTF_SUPP - indicates whether the ANSI function vprintf() is supported
#	This parameter must be "y" in X/Open modes but may be "n" in
#	POSIX and FIPS modes.
VPRINTF_SUPP="y"

#LONG_DOUBLE_SUPP - whether the compiler supports the "long double" type
#	This parameter is not used when testing XNFS.
#	This parameter must be set to "y" if long double is supported
LONG_DOUBLE_SUPP="y"

#SIGNAL_SUPP - indicates whether the ANSI function signal() is supported
#	This parameter is not used when testing XNFS.
#	This parameter must be "y" in X/Open modes but may be "n" in
#	POSIX and FIPS modes.
SIGNAL_SUPP="y"
/*
*      SCCS:   @(#)common/vport(nonposix.c)	4.1 (01/21/97)  VSXgen release 1.3
*
*	UniSoft Ltd., London, England
*
* (C) Copyright 1991 X/Open Company Limited
*
* All rights reserved.  No part of this source code may be reproduced,
* stored in a retrieval system, or transmitted, in any form or by any
* means, electronic, mechanical, photocopying, recording or otherwise,
* except as stated in the end-user licence agreement, without the prior
* permission of the copyright owners.
*
* X/Open and the 'X' symbol are trademarks of X/Open Company Limited in
* the UK and other countries.
*/
/***********************************************************************

NAME:		nonposix.c - non-POSIX interfaces used in POSIX testsets

PROJECT:	VSX (X/OPEN Validation Suite)

MODULE CONTAINS:
		getopt(), optind, optarg, opterr,
		isnan(),
		memchr(), memcmp(), memcpy(), memset(),
		popen(), pclose(),
		strtol(),
		system(),
		vprintf(), vfprintf(), vsprintf().
SYNOPSIS:
		as XPG3

DESCRIPTION:
	If VSX is built in a POSIX mode (i.e. with _XOPEN_SOURCE not
	defined) the suite cannot use any non-POSIX interfaces as they
	may not be available on the system.  Therefore portable versions
	of those interfaces which are used are provided here.

AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	24 May 1989
MODIFICATIONS:
		Geoff Clare, 13 Feb 1990
			Change execl("/bin/sh", ...) to execlp("sh", ...)
		
		Geoff Clare, 4 May 1990
			Don't supply ANSI functions if using ANSI compiler
		
		Geoff Clare, 25 May 1990
			Allow for unlimited OPEN_MAX

		Geoff Clare, 07 Dec 1990
			Fix malloc() problem in popen().

		Geoff Clare, 27 Jan 1992
			Fix use of NULL as an integer in getopt().

		Geoff Clare, 21 May 1992
			Add vprintf() et al.

************************************************************************/

#ifdef _XOPEN_SOURCE

static int dummy;

#else /* _XOPEN_SOURCE */

#include <std.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#if !(__STDC__ > 0)
#include <varargs.h>
#endif
#include <sysdep.h>

#undef	getopt
#undef	optind
#undef	optarg
#undef	opterr
#undef	isnan
#undef	memchr
#undef	memcmp
#undef	memcpy
#undef	memset
#undef	popen
#undef	pclose
#undef	strtol
#undef	system
#undef	vprintf
#undef	vfprintf
#undef	vsprintf

#if !(__STDC__ > 0)

/*
 *  Some compilers don't grok (void *) as a formal parameter, hence
 *  the use of (char *) instead for the memory functions.  This will
 *  blow up old version of "lint" which don't know that they are
 *  required to have the same representation.
 */

public void *
memchr(s, c, n)
char *s;
int c;
size_t n;
{
	unsigned char *sp = (unsigned char *)s;

	while (n-- > 0)
		if (*sp++ == (unsigned char)c)
			return (void *)(--sp);
	return NULL;
}

public int
memcmp(s1, s2, n)
char *s1, *s2;
size_t n;
{
	unsigned char *sp1 = (unsigned char *)s1;
	unsigned char *sp2 = (unsigned char *)s2;

	if (s1 != s2)
		while (n-- > 0)
			if (*sp1++ != *sp2++)
			{
				if (*--sp1 > *--sp2)
					return 1;
				else
					return -1;
			}
	return 0;
}

public void *
memcpy(s1, s2, n)
char *s1, *s2;
size_t n;
{
	char *os1 = s1;

	while (n-- > 0)
		*s1++ = *s2++;

	return (void *)os1;
}

public void *
memset(s, c, n)
char *s;
int c;
size_t n;
{
	unsigned char *sp = (unsigned char *)s;

	while (n-- > 0)
		*sp++ = c;

	return (void *)s;
}

#define DIGIT(x)	(isdigit(x) ? (x) - '0' : \
			islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
#define MBASE	('z' - 'a' + 1 + 10)

public long
strtol(str, ptr, base)
char *str;
char **ptr;
int base;
{
	char *oldloc;
	long val;
	int c;
	int xx, neg = 0;

	if (ptr != (char **)0)
		*ptr = str; /* in case no number is formed */
	if (base < 0 || base > MBASE)
	{
		errno = EINVAL;
		return 0;
	}

	/* switch to C locale temporarily for <ctype.h> functions */
	oldloc = setlocale(LC_CTYPE, "C");

	if (!isalnum(c = *str))
	{
		while (isspace(c))
			c = *++str;
		switch (c)
		{
		case '-':
			neg++;
		case '+': /* fall-through */
			c = *++str;
		}
	}
	if (base == 0)
	{
		if (c != '0')
			base = 10;
		else if (str[1] == 'x' || str[1] == 'X')
			base = 16;
		else
			base = 8;
	}
	/*
	 * for any base > 10, the digits incrementally following
	 *	9 are assumed to be "abc...z" or "ABC...Z"
	 */
	if (!isalnum(c) || (xx = DIGIT(c)) >= base)
	{
		(void) setlocale(LC_CTYPE, oldloc);
		return 0; /* no number formed */
	}
	if (base == 16 && c == '0' && isxdigit(str[2]) &&
	    (str[1] == 'x' || str[1] == 'X'))
		c = *(str += 2); /* skip over leading "0x" or "0X" */
	for (val = -DIGIT(c); isalnum(c = *++str) && (xx = DIGIT(c)) < base; )
		/* accumulate neg avoids surprises near LONG_MAX */
		val = base * val - xx;
	if (ptr != (char **)0)
		*ptr = str;
	(void) setlocale(LC_CTYPE, oldloc);
	return (neg ? val : -val);
}

public int
system(s)
char	*s;
{
	int	status, err = errno;
	pid_t	pid;
	sigset_t set, oset;

	if ((pid = fork()) == 0)
	{
		(void) execlp("sh", "sh", "-c", s, (char *)0);
		_exit(127);
	}
	else if (pid == SYSERROR)
		return SYSERROR;

	(void) sigemptyset(&set);
	(void) sigaddset(&set, SIGHUP);
	(void) sigaddset(&set, SIGINT);
	(void) sigaddset(&set, SIGQUIT);
	(void) sigprocmask(SIG_BLOCK, &set, &oset);

	if (waitpid(pid, &status, 0) != pid)
	{
		status = SYSERROR;
		err = errno;
	}

	(void) sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
	if (sigpending(&set) != SYSERROR &&
	   (sigismember(&set, SIGHUP) ||
	    sigismember(&set, SIGINT) ||
	    sigismember(&set, SIGQUIT)))
	{
		(void) sigsuspend(&oset);
		err = errno;
	}

	errno = err;
	return status;
}

#endif /* __STDC__ */

#ifndef __linux__

public	int	opterr = 1;
public	int	optind = 1;
public	char	*optarg;

public int
getopt(argc, argv, opts)
int	argc;
char	**argv, *opts;
{
	static int sp = 1;
	int c;
	char *cp;

	if (sp == 1)
	{
		if (optind >= argc ||
		   argv[optind][0] != '-' || argv[optind][1] == '\0')
			return EOF;
		else if(strcmp(argv[optind], "--") == 0)
		{
			optind++;
			return EOF;
		}
	}

	c = argv[optind][sp];
	if (c == ':' || (cp=strchr(opts, c)) == NULL)
	{
		if (opterr)
			(void) fprintf(stderr, "%s: illegal option -- %c\n",
				argv[0], c);
		if (argv[optind][++sp] == '\0')
		{
			optind++;
			sp = 1;
		}
		return '?';
	}
	if (*++cp == ':')
	{
		if (argv[optind][sp+1] != '\0')
			optarg = &argv[optind++][sp+1];
		else if(++optind >= argc)
		{
			if (opterr)
				(void) fprintf(stderr,
				    "%s: option requires an argument -- %c\n",
				    argv[0], c);
			sp = 1;
			return '?';
		} else
			optarg = argv[optind++];
		sp = 1;
	}
	else
	{
		if (argv[optind][++sp] == '\0')
		{
			sp = 1;
			optind++;
		}
		optarg = NULL;
	}
	return c;
}

#endif /* __linux__ */

public int
isnan(x)
double x;
{
	return (x != x);
}

#ifndef __linux__

#define	tst(a, b) (*mode == 'r' ? (b) : (a))

static pid_t *popen_pid = NULL;

public FILE *
popen(cmd, mode)
char	*cmd, *mode;
{
	int	p[2];
	int	myside, yourside;
	pid_t	*poptr, pid;

	static long open_max;

	if (popen_pid == NULL)
	{
		errno = 0;
		open_max = sysconf(_SC_OPEN_MAX);
		if (open_max < 0 && errno == 0)
			open_max = 256;
		if (open_max < 0 ||
		   (popen_pid = (pid_t *)calloc((size_t) open_max,
		   sizeof(pid_t))) == NULL)
			return NULL;
	}

	if (pipe(p) < 0)
		return NULL;

	myside = tst(p[1], p[0]);
	yourside = tst(p[0], p[1]);

	if ((pid = fork()) == 0)
	{
		/* myside and yourside reverse roles in child */
		int	stdio;

		/* close all pipes from other popen's */
		poptr = &popen_pid[open_max];
		while (poptr > popen_pid)
		{
			if (*--poptr != 0)
				(void) close(poptr - popen_pid);
		}
		stdio = tst(0, 1);
		(void) close(myside);
		(void) close(stdio);
		(void) fcntl(yourside, F_DUPFD, stdio);
		(void) close(yourside);
		(void) execlp("sh", "sh", "-c", cmd, (char *)0);
		_exit(1);
	}
	else if (pid == -1)
		return NULL;

	popen_pid[myside] = pid;
	(void) close(yourside);

	return fdopen(myside, mode);
}

public int
pclose(ptr)
FILE	*ptr;
{
	int f, status, err = errno;
	pid_t p;
	sigset_t set, oset;

	if (popen_pid == NULL)
	{
		/* no popen() calls made */
		errno = ECHILD;
		return SYSERROR;
	}

	f = fileno(ptr);
	p = popen_pid[f];
	(void) fclose(ptr);
	popen_pid[f] = 0;

	if (p <= 0)
	{
		/* no child to wait for */
		errno = ECHILD;
		return SYSERROR;
	}

	(void) sigemptyset(&set);
	(void) sigaddset(&set, SIGHUP);
	(void) sigaddset(&set, SIGINT);
	(void) sigaddset(&set, SIGQUIT);
	(void) sigprocmask(SIG_BLOCK, &set, &oset);

	if (waitpid(p, &status, 0) != p)
	{
		status = SYSERROR;
		err = errno;
	}

	(void) sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
	if (sigpending(&set) != SYSERROR &&
	   (sigismember(&set, SIGHUP) ||
	    sigismember(&set, SIGINT) ||
	    sigismember(&set, SIGQUIT)))
	{
		(void) sigsuspend(&oset);
		err = errno;
	}

	errno = err;
	return status;
}

#endif /* __linux__ */

#if !(__STDC__ > 0) && !ANSI_VPRINTF_FUNC 

#define PUTCH(c) { \
	if (buf != NULL) { \
		*buf++ = (c); \
		*buf = '\0'; \
		count++; \
	} else { \
		ret = putc((c), fp); \
		if (ret == EOF) \
			return (count > 0 ? count : -1); \
		else \
			count++; \
	} \
}

#define DOARG(var,type) { \
	argdone = 1; \
	var = va_arg(args, type); \
	*strp++ = *endp; \
	*strp = '\0'; \
	if (buf != NULL) { \
		ret = sprintf(buf, fstr, var); \
		count += ret; \
		buf += strlen(buf); \
	} else { \
		ret = fprintf(fp, fstr, var); \
		if (ret < 0) \
			return (count > 0 ? count : -1); \
		else \
			count += ret; \
	} \
}

private int
dovprnt(buf, fp, fmt, args)
char *buf;
FILE *fp;
char *fmt;
va_list args;
{
	/*
	 * if (buf != NULL) do a vsprintf(buf, fmt, args),
	 * otherwise do a vfprintf(fp, fmt, args).
	 */

#if LONG_DOUBLE_SUPPORTED
	long double	ld;
#endif
	double		d;
	char		*strp;
	char		*endp;
	char		*cp;
	long		l;
	unsigned long	ul;
	int		i;
	unsigned int	ui;
	int		shortflag;
	int		longflag;
	int		longdflag;
	int		ret;
	int		argdone;
	int		count = 0;
	char		fstr[256];

	if (buf != NULL)
		*buf = '\0';

	while (*fmt != '\0')
	{
		if (*fmt != '%')
		{
			PUTCH(*fmt)
			++fmt;
			continue;
		}

		shortflag = longflag = longdflag = 0;
		strp = fstr;
		*strp++ = '%';

		/*
		 * Find the next conversion character and use
		 * sprintf/fprintf to process the piece of format
		 * string from here up to the character.
		 */

		for (endp = fmt + 1; *endp != '\0'; endp++)
		{
			argdone = 0;
			switch (*endp)
			{
			case 'h':
				shortflag++;
				break;

			case 'l':
				longflag++;
				break;

			case 'L':
				longdflag++;
				break;

			case '*':
				i = va_arg(args, int);
				(void) sprintf(strp, "%d", i);
				strp += strlen(strp);
				break;

			case 'd':
			case 'i':
				if (longflag)
					DOARG(l, long)
				else
					DOARG(i, int)
				break;

			case 'o':
			case 'u':
			case 'x':
			case 'X':
				if (longflag)
					DOARG(ul, unsigned long)
				else
					DOARG(ui, unsigned int)
				break;

			case 'e':
			case 'E':
			case 'f':
			case 'g':
			case 'G':
#if LONG_DOUBLE_SUPPORTED
				if (longdflag)
					DOARG(ld, long double)
				else
#endif
					DOARG(d, double)
				break;

			case 'c':
				DOARG(i, int)
				break;

			case 's':
			case 'p':
				DOARG(cp, char *)
				break;

			case 'n':
				argdone = 1;
				if (longflag)
					*(va_arg(args, long int *)) = count;
				else if (shortflag)
					*(va_arg(args, short int *)) = count;
				else
					*(va_arg(args, int *)) = count;
				break;

			case '%':
				argdone = 1;
				PUTCH('%')
				break;

			default:
				*strp++ = *endp;
				break;
			}
			if (argdone)
				break;
		}
		if (*endp == '\0')
			return count;

		fmt = endp + 1;
	}

	return count;
}

public int
vfprintf(fp, fmt, ap)
FILE *fp;
char *fmt;
va_list ap;
{
	return dovprnt((char *)0, fp, fmt, ap);
}

public int
vprintf(fmt, ap)
char *fmt;
va_list ap;
{
	return dovprnt((char *)0, stdout, fmt, ap);
}

public int
vsprintf(buf, fmt, ap)
char *buf;
char *fmt;
va_list ap;
{
	return dovprnt(buf, (FILE *)0, fmt, ap);
}
#endif /* !(__STDC__ > 0) && !ANSI_VPRINTF_FUNC */

#endif /* _XOPEN_SOURCE */
/*
*      SCCS:   @(#)common/vport(userintf.top)	4.2 (04/22/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		userintf.c - user-modifiable interface routines

PROJECT:	VSX (X/OPEN Validation Suite)

DESCRIPTION:
	This file contains functions which perform test-setup tasks in
	an implementation-defined manner.  The contents of this template
	vary according to the subsets selected by the user.  Only
	the functions needed by testsets in the selected subsets are
	included.

	As supplied these routines make use of system calls commonly
	found on many UNIX systems.  If these are not appropriate the
	routines should be modified as necessary before the VSX test
	suite is installed.

	Descriptions of the individual interfaces may be found
	with the corresponding function code below.

AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

#undef _POSIX_SOURCE	/* don't want namespace restrictions in here */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE

#define _ALL_SOURCE	/* change to suitable feature test macro */

#include <std.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <setprv.h>
#include <xnfs.h>

/*
 *	Setprv() provides the current process with "appropriate privileges".
 *	The argument specifies what privilege is being requested.
 *	It returns 0 for success, -1 for failure.
 */

public int
setprv(prvtype)
int prvtype;
{
	switch (prvtype)
	{
	case PRV_DEVICE :	/* access device files */
		/* no privilege required */
		return 0;

	case PRV_SETID :	/* change to any uid/gid */
		/* fallthrough */

	case PRV_MOUNT :	/* mount and unmount file systems */
		/* fallthrough */

	case PRV_LINKDIR :	/* create links to directories */
		/* fallthrough */

	case PRV_ACCESS :	/* unrestricted access to files */
		/* fallthrough */

	case PRV_CHOWN :	/* change owner/group/mode of ANY file */
		/* fallthrough */

	case PRV_SETGRPS :	/* set supplementary group IDs */
		/* fallthrough */

	case PRV_NEWROOT :	/* set root directory of process */
		/* fallthrough */

	case PRV_NICE :		/* change process priority */
		/* fallthrough */

	case PRV_KILL :		/* send signal to any process */
		/* fallthrough */

	case PRV_IPC :		/* allow unrestricted IPC access */
		/* fallthrough */

	case PRV_ULIMIT :	/* increase file size limit */
		/* fallthrough */

	case PRV_LIMITS :	/* privileged setrlimit() */
		/* fallthrough */

	case PRV_MEMLOCK :	/* memory locking */
		/* fallthrough */

	case PRV_SETTIME :	/* set (real-time) clocks */
		/* fallthrough */

	case PRV_SETRTSCHED :	/* set (real-time) process scheduling params */
		/* fallthrough */

	case PRV_GETRTSCHED :	/* get (real-time) process scheduling params */
		/* fallthrough */

	case PRV_SETTHRSCHED :	/* set threads scheduling params */
		/* fallthrough */

	case PRV_GETTHRSCHED :	/* get threads scheduling params */
		/* fallthrough */

	case PRV_ASSIGN :	/* assign privileges to an executable file */

		if (geteuid() == 0)
			return 0;
		break;
	
	default :
		(void) fprintf(stderr,
			"Error in vport/userintf: unknown privilege request (%d) in setprv()\n",
			prvtype);
		break;
	}

	return -1;
}

/*
 *	Unsetprv() removes the specified privilege from the current process.
 *	The argument specifies what privilege is to be removed.
 *	It returns 0 for success, -1 for failure.  (If the process already
 *	does not have the privilege, this is considered success).
 */

public int
unsetprv(prvtype)
int prvtype;
{
	switch (prvtype)
	{
	case PRV_DEVICE :	/* access device files */
		/* no privilege required */
		return 0;

	case PRV_SETID :	/* change to any uid/gid */
		/* fallthrough */

	case PRV_MOUNT :	/* mount and unmount file systems */
		/* fallthrough */

	case PRV_LINKDIR :	/* create links to directories */
		/* fallthrough */

	case PRV_ACCESS :	/* unrestricted access to files */
		/* fallthrough */

	case PRV_CHOWN :	/* change owner/group/mode of ANY file */
		/* fallthrough */

	case PRV_SETGRPS :	/* set supplementary group IDs */
		/* fallthrough */

	case PRV_NEWROOT :	/* set root directory of process */
		/* fallthrough */

	case PRV_NICE :		/* change process priority */
		/* fallthrough */

	case PRV_KILL :		/* send signal to any process */
		/* fallthrough */

	case PRV_IPC :		/* allow unrestricted IPC access */
		/* fallthrough */

	case PRV_ULIMIT :	/* increase file size limit */
		/* fallthrough */

	case PRV_LIMITS :	/* privileged setrlimit() */
		/* fallthrough */

	case PRV_MEMLOCK :	/* memory locking */
		/* fallthrough */

	case PRV_SETTIME :	/* set (real-time) clocks */
		/* fallthrough */

	case PRV_SETRTSCHED :	/* set (real-time) process scheduling params */
		/* fallthrough */

	case PRV_GETRTSCHED :	/* get (real-time) process scheduling params */
		/* fallthrough */

	case PRV_SETTHRSCHED :	/* set threads scheduling params */
		/* fallthrough */

	case PRV_GETTHRSCHED :	/* get threads scheduling params */
		/* fallthrough */

	case PRV_ASSIGN :	/* assign privileges to an executable file */

		if (setuid(getuid()) != -1)
			return 0;
		break;
	
	default :
		(void) fprintf(stderr,
			"Error in vport/userintf: unknown privilege request (%d) in unsetprv()\n",
			prvtype);
		break;
	}

	return -1;
}

/*
 *	Prv_assign() assigns "appropriate privileges" to an executable file.
 *	The arguments are the file name and a zero-terminated array of the
 *	privileges to be assigned.
 *	It returns 0 for success, -1 for failure.
 */

public int
prv_assign(file, prvtypes)
char *file;
int *prvtypes;
{
	int prvtype, ret = 0;

	while ((prvtype = *prvtypes++) != 0)
	{
		switch (prvtype)
		{
		case PRV_DEVICE :	/* access device files */
			/* no privilege required */
			break;

		case PRV_SETID :	/* change to any uid/gid */
			/* fallthrough */

		case PRV_MOUNT :	/* mount and unmount file systems */
			/* fallthrough */

		case PRV_LINKDIR :	/* create links to directories */
			/* fallthrough */

		case PRV_ACCESS :	/* unrestricted access to files */
			/* fallthrough */

		case PRV_CHOWN :	/* change owner/group/mode of ANY file */
			/* fallthrough */

		case PRV_SETGRPS :	/* set supplementary group IDs */
			/* fallthrough */

		case PRV_NEWROOT :	/* set root directory of process */
			/* fallthrough */

		case PRV_NICE :		/* change process priority */
			/* fallthrough */

		case PRV_KILL :		/* send signal to any process */
			/* fallthrough */

		case PRV_IPC :		/* allow unrestricted IPC access */
			/* fallthrough */

		case PRV_ULIMIT :	/* increase file size limit */
			/* fallthrough */

		case PRV_LIMITS :	/* privileged setrlimit() */
			/* fallthrough */

		case PRV_MEMLOCK :	/* memory locking */
			/* fallthrough */

		case PRV_SETTIME :	/* set (real-time) clocks */
			/* fallthrough */

		case PRV_SETRTSCHED :	/* set (real-time) process scheduling params */
			/* fallthrough */

		case PRV_GETRTSCHED :	/* get (real-time) process scheduling params */
			/* fallthrough */

		case PRV_SETTHRSCHED :	/* set threads scheduling params */
			/* fallthrough */

		case PRV_GETTHRSCHED :	/* get threads scheduling params */
		    /* fallthrough */

		case PRV_ASSIGN :	/* assign privileges to an executable file */

			break;
		
		default :
			(void) fprintf(stderr,
				"Error in vport/userintf: unknown privilege request (%d) in prv_assign()\n",
				prvtype);
			ret = -1;
			break;
		}
	}


	return ret;
}

/*
*      SCCS:   @(#)install/userintf/gen_mnt	1.1 (01/21/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		gen_mnt - user-modifiable mount/unmount routines
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Mnt_rw() mounts the file system specified by "spec" onto the
 *	directory "dir" for reading and writing.
 *	It returns 0 for success, -1 for failure.
 */
#define FSINDEPMOUNT
#ifdef FSINDEPMOUNT
#include <sys/mount.h>
/* from linux/fs.h */
/*#define MS_MGC_VAL 0xC0ED0000 */
/*#define MS_RDONLY 1*/
#endif

public int
mnt_rw(spec, dir)
char *spec;
char *dir;
{
	int ret;

#ifdef FSINDEPMOUNT
        /* file system independent mount for filesystem */
        ret = mount(spec, dir, (char *) "ext2", MS_MGC_VAL, 0);
#else
	ret = mount(spec, dir, 0);
#endif
	if (ret == -1 && errno == EBUSY)
	{
		(void) unmnt(spec, dir);
		errno = 0;
#ifdef FSINDEPMOUNT
        /* file system independent mount for filesystem */
        ret = mount(spec, dir, "ext2", MS_MGC_VAL, 0);
#else
		ret = mount(spec, dir, 0);
#endif
	}

	return ret;
}

/*
 *	Mnt_ro() mounts the file system specified by "spec" onto the
 *	directory "dir" for reading only.
 *	It returns 0 for success, -1 for failure.
 */

public int
mnt_ro(spec, dir)
char *spec;
char *dir;
{
	int ret;

#ifdef FSINDEPMOUNT
        /* file system independent mount for filesystem */
        ret = mount(spec, dir, "ext2", MS_MGC_VAL|MS_RDONLY, 0);
#else
	ret = mount(spec, dir, 1);
#endif
	if (ret == -1 && errno == EBUSY)
	{
		(void) unmnt(spec, dir);
		errno = 0;
#ifdef FSINDEPMOUNT
        ret = mount(spec, dir, "ext2", MS_MGC_VAL|MS_RDONLY, 0);
#else
		ret = mount(spec, dir, 1);
#endif
	}

	return ret;
}

/*
 *	Unmnt() unmounts the file system specified by "spec" from the
 *	directory "dir" where it has previously been mounted.
 *	It returns 0 for success, -1 for failure.
 */

/* ARGSUSED */
public int
unmnt(spec, dir)
char *spec;
char *dir;
{
	return umount(spec);
}

/*
*      SCCS:   @(#)install/userintf/gen_termios	1.1 (01/21/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		gen_termios - user-modifiable terminal interface routines
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Openctl() opens the terminal device "spec" with the specified flags.
 *	This then becomes the controlling terminal for the current process.
 *	If it cannot become the controlling terminal, openctl() must still
 *	open the device as an ordinary terminal.
 *	Openctl() returns the open file descriptor to the terminal,
 *	or -1 on failure.
 */
		
public int
openctl(spec, oflag)
char *spec;
int  oflag;
{
	/* Note: setsid() will have been called before this routine */

	int fd;

	/* allow for modem line delay if there has just been a close() */
	(void) sleep(1);

	fd = open(spec, oflag, 0);

	/* Make sure failure is not just because the device cannot
	   become the controlling terminal */
	
	if (fd < 0 && errno != EINTR)
		fd = open(spec, oflag|O_NOCTTY, 0);

	return fd;
}

/*
 *	Openpty() opens the master and slave sides of a pseudo-terminal.
 *	Both device names are supplied, but if master pty's are obtained
 *	from a clone device the slave name is a dummy which must be
 *	overwritten with the real device name.  If cntrl is true
 *	the slave must be opened as a controlling terminal by calling
 *	openctl() instead of plain open().  Both devices must be opened
 *	for reading and writing.  On many systems master devices can
 *	only be opened once, giving EBUSY for example on subsequent
 *	opens.  If openpty() encounters a busy master device, it must
 *	simply open the slave.
 *
 *	The open file descriptors are returned via the pointers mfdp and
 *	sfdp.  Openpty() returns 0 for success or -1 for failure.
 *
 *	This routine is only called if the VSX_MASTER_TTY and
 *	VSX_MASTER_LOOP parameters are set.
 */

/* #define CLONE_MPTY	/* uncomment if master pty's are obtained from a
		 	   clone device (e.g. /dev/ptmx) */
/* #define STREAMS_PTY	/* uncomment if pty's use STREAMS */

#ifdef STREAMS_PTY
#include <sys/stropts.h>
#endif

public int
openpty(master, slave, mfdp, sfdp, cntrl)
char *master;
char *slave;
int *mfdp;
int *sfdp;
int cntrl;
{
	*mfdp = open(master, O_RDWR|O_NOCTTY);
	if (*mfdp < 0 && errno != EBUSY)
		return -1;

#ifdef CLONE_MPTY
	if (*mfdp >= 0)
	{
		char *newslave;
		size_t len;
		static struct { char *ptr; size_t len; } slavelen[2];
		extern char *ptsname();

		(void) grantpt(*mfdp);   /* change permission of slave */
		(void) unlockpt(*mfdp);  /* unlock slave */
		newslave=ptsname(*mfdp); /* get a slave */
		if (slavelen[0].ptr == NULL)
		{
			/* remember length of original dummy name
			   to be used if called again */
			slavelen[0].ptr = slave;
			slavelen[0].len = strlen(slave);
		}
		else if (slave != slavelen[0].ptr && slavelen[1].ptr == NULL)
		{
			/* remember length of original dummy name
			   to be used if called again */
			slavelen[1].ptr = slave;
			slavelen[1].len = strlen(slave);
		}
		if (slave == slavelen[0].ptr)
			len = slavelen[0].len;
		else
			len = slavelen[1].len;
		if (strlen(newslave) > len)
		{
			(void) fprintf(stderr,
				"Error in vport/userintf: dummy slave name too short to take \"%s\" in openpty()\n",
				newslave);
			return -1;
		}
		(void) strcpy(slave, newslave);
	}
#endif

	if (cntrl)
		*sfdp = openctl(slave, O_RDWR);
	else
		*sfdp = open(slave, O_RDWR|O_NOCTTY);

	if (*sfdp < 0)
		return -1;

#ifdef STREAMS_PTY
	if (*mfdp >= 0)
	{
		(void) ioctl(*sfdp, I_PUSH, "ptem");   /* pseudo tty emulator */
		(void) ioctl(*sfdp, I_PUSH, "ldterm"); /* line discipline */
	}
#endif
	
	return 0;
}

/*
 *	Ptygetattr() obtains terminal attributes for the slave pseudo-
 *	terminal corresponding to the master device addressed by mfd.
 *	It returns 0 for success, -1 for failure.
 */

public int
ptygetattr(mfd, termios_p)
int mfd;
struct termios *termios_p;
{
#ifdef STREAMS_PTY
	extern char *ptsname();
	char *slave;
	int ret, sfd = -1;
	
	/* Obtain slave device name and call tcgetattr() on the slave */
	slave = ptsname(mfd);
	if (slave && (sfd = open(slave, O_RDWR)) >= 0)
		ret = tcgetattr(sfd, termios_p);
	else
		ret = -1;
	if (sfd >= 0)
		(void) close(sfd);
	return ret;
#else
	/* This code assumes tcgetattr() on the master returns the
	   settings of the slave (true for BSD-style pseudo-terminals) */
	return tcgetattr(mfd, termios_p);
#endif
}

/*
*      SCCS:   @(#)install/userintf/gen_newroot	1.1 (01/21/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		gen_newroot - user-modifiable newroot() routine
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Newroot() causes "path" to become the root directory for the
 *	current process.
 *	Newroot() is only called after setprv(PRV_NEWROOT) since setting
 *	the root directory is usually a privileged operation.
 *	It returns 0 for success, -1 for failure.
 */

public int
newroot(path)
char *path;
{
	return chroot(path);
}

/*
*      SCCS:   @(#)install/userintf/gen_setlimit	1.1 (01/21/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		gen_setlimit - user-modifiable setlimit() routine
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Setlimit() is used to reduce the output file size limit for 
 *	the process.  The argument is the value to be set in units of
 *	512 byte blocks, and will always be >= VSX_ULIMIT_BLKS.
 *	If the system supports the SIGXFSZ signal, setlimit() should
 *	set it to be ignored.
 *	Setlimit() returns the new limit, or -1L for failure.
 */

#include <signal.h>
#include <ulimit.h>

public long
setlimit(lim)
long lim;
{
#ifdef SIGXFSZ
	struct sigaction sact;
	sact.sa_handler = SIG_IGN;
	sact.sa_flags = 0;
	(void) sigemptyset(&sact.sa_mask);
	if (sigaction(SIGXFSZ, &sact, (struct sigaction *)0) == -1)
		return -1L;
#endif
	return ulimit(UL_SETFSIZE, lim);
}

/*
*      SCCS:   @(#)install/userintf/gen_pathres	1.1 (01/21/97)  VSXgen release 1.4
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		gen_pathres - user-modifiable pathname resolution routines
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Pathdepth() is used to determine the depth of pathnames
 *	beginning with "//" below the root directory of the process.
 *	The return value is such that a path equivalent to "/usr"
 *	gives a value of 1, one equivalent to "/usr/bin" gives 2, etc.
 *	The default code supplied is suitable for systems which use
 *	"//" to refer to a directory level above the root, i.e. when
 *	the root directory is referred to by "//somename".
 */

public int
pathdepth(path)
char *path;
{
	char *p;
	int dircnt = 0;

	/* count '/' characters after the initial "//" */
	for (p = &path[2]; *p != '\0'; p++)
	{
		if (*p == '/')
		{
			++dircnt;
			/* skip multiple '/'s */
			while (*(p+1) == '/')
				++p;
			/* watch out for trailing '/' */
			if (*(p+1) == '\0')
				--dircnt;
		}
	
	}

	return dircnt;
}

/*
*      SCCS:   @(#)install/userintf/base_setgrps	Rel 4.4.1 (06/09/97)
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		base_setgrps - user-modifiable setgrps() routine
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

************************************************************************/

/*
 *	Setgrps() sets the current groups list to the group id's in
 *	"grparray".  This array should contain "ngrps" entries.
 *	Setgrps() is only called after setprv(PRV_SETGRPS) since setting
 *	groups is usually a privileged operation.
 *	It returns 0 for success, -1 for failure.
 *
 *	If the implementation does not support setting the supplementary
 *	groups list, then setgrps() must return -1 with errno set to ENOSYS.
 */

public int
setgrps(ngrps, grparray)
int   ngrps;
gid_t grparray[];
{
	/* If setting supplementary groups is not supported replace
	   the line below with:

		errno = ENOSYS;
		return -1;
	*/

	return setgroups(ngrps, grparray);

	/* If setgroups() takes an array of integers of a different
	   size to gid_t, the gid_t array will need to be copied.
	   In this case, remove the line above and the #if/#endif
	   around the following, and alter the typedef as necesary:
	 */

#if 0
	typedef int GID_T;
	GID_T *gcopy, gdummy;
	int i, rval;

	if (ngrps > 0)
	{
		gcopy = (GID_T *)malloc((size_t)(ngrps * sizeof(GID_T)));
		if (gcopy == NULL)
			return -1;
	}
	else
		gcopy = &gdummy;

	for (i=0; i<ngrps; i++)
		gcopy[i] = grparray[i];

	rval = setgroups(ngrps, gcopy);

	if (ngrps > 0)
		free((void *)gcopy);

	return rval;
#endif /* 0 */
}

/*
*      SCCS:   @(#)install/userintf/base_cputime	Rel 4.4.3 (07/20/98)
*
*	UniSoft Ltd., London, England
*/
/***********************************************************************

NAME:		base_cputime - user-modifiable use-CPU-time routines
PROJECT:	VSX (X/OPEN Validation Suite)
AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	December 1996
MODIFICATIONS:

	Geoff Clare, October 1997
		Increase default amount of processing performed.

************************************************************************/

/*
 *	Sys_call() makes one or more calls to an interface which is
 *	known to be a system call.  I.e. after several calls the system
 *	CPU time for the process will have increased measurably.
 *	It returns 0 for success, -1 for failure.
 */

public int
sys_call()
{
	int i, ret;

	for (i = 0; i < 10; i++)
		ret = access("/", F_OK);

	return ret;
}

/*
 *	Use_time() performs processing which will accumulate
 *	user CPU time.  The number of iterations may be	adjusted
 *	if necessary.
 */

public void
use_time()
{
	int i;
	unsigned int dummy = 0;

	for (i = 0; i < 1000; i++)
		dummy = dummy + i / (dummy + 1) * (dummy % 3);
}


Reply to: