nfs@notecnirp.Princeton.EDU (Norbert Schlenker) (01/09/90)
Here are three POSIX routines to go along with the new Minix (they'll work with the old one too). A Makefile and a shell script that will turn them into something approaching Tanenbaum standard format is included. Included are: sysconf() - an analogue of [f]pathconf() for non-file limits execve() - rewritten version ttyname() - rewritten version Motivations for these routines: sysconf() - missing from the 1.5.0 postings execve() - I wanted to see if my fast string routines would help in copying the environment and arguments - they did, but a simple cleanup of the existing code did just as well ttyname() - I want to get rid of <sys/dir.h> and Terrence Holm's version used it - the new routine uses the POSIX *dir() functions On my PC, execve() saves 30%-50% over the old routine (that doesn't mean that the program you execute runs that much faster :-)). Ttyname() is about 60% faster (real and system time), due to buffering in the *dir() routines, but uses more user time and more space. For those who are willing, I'd like comments on the format of the files included here. I haven't included with this posting the headers that turn the _*.c files into working copies, but I think all the library routines should make use of something like the __[A-Z]* macros (my standard whine). Norbert ----------------------------- cut here -------------------------------- #!/bin/sh echo x - Makefile sed '/^X/s///' > Makefile << '/' Xall: X sh make_normal _execve.c execve.c X sh make_normal _sysconf.c sysconf.c X sh make_normal _ttyname.c ttyname.c / echo x - make_normal sed '/^X/s///' > make_normal << '/' Xsed '/#include <sys\/types.h>/d; X /#include <errno.h>/d; X /#include <limits.h>/d; X /#include <minix\/callnr.h>/d; X s/_ttyname/ttyname/; X s/_execve/execve/; X s/_sysconf/sysconf/; X s/ (underware)//; X s/_PRIVATE/PRIVATE/; X s/_PUBLIC/PUBLIC/; X s/_MM/MM/; X s/_FS/FS/; X s/__TTYNAME/ttyname/; X s/__EXECVE/execve/; X s/__SYSCONF/sysconf/; X s/__FSTAT/fstat/; X s/__STAT/stat/; X s/__OPENDIR/opendir/; X s/__READDIR/readdir/; X s/__CLOSEDIR/closedir/; X s/__CALL1/callm1/; X s/__CALL3/callm3/' <$1 >$2 / echo x - _execve.c sed '/^X/s///' > _execve.c << '/' X/* _execve.c POSIX 3.1.2 (underware) X * int __EXECVE(char *path, char *argv[], char *envp[]); X * X * Executes a file. X */ X X#include <lib.h> X#include <errno.h> X#include <limits.h> X#include <sys/types.h> X#include <unistd.h> X#include <minix/callnr.h> X X#define PTRSIZE sizeof(char *) X X_PRIVATE int count_pointers(p) Xregister char **p; X{ X register int n = 0; X X while (*p++ != (char *) NULL) X ++n; X return n; X} X X_PUBLIC int __EXECVE(path, argv, envp) Xchar *path; /* pointer to name of file to be executed */ Xchar *argv[]; /* pointer to argument array */ Xchar *envp[]; /* pointer to environment */ X{ X char stack[ARG_MAX]; X char **ap; X register char *hp, *p; X int nargs, nenvps, stackbytes; X X /* Count the argument pointers and environment pointers. */ X nargs = count_pointers(argv); X nenvps = count_pointers(envp); X X /* Prepare to set up the initial stack. */ X hp = &stack[(nargs + nenvps + 3) * PTRSIZE]; X if (hp + nargs + nenvps >= &stack[ARG_MAX]) { X errno = E2BIG; X return -1; X } X ap = (char **) stack; X *ap++ = (char *) nargs; X X /* Prepare the argument pointers and strings. */ X while (*argv != (char *) NULL) { X *ap++ = (char *) (hp - stack); X p = *argv++; X while (*p) { X *hp++ = *p++; X if (hp >= &stack[ARG_MAX]) { X errno = E2BIG; X return -1; X } X } X *hp++ = '\0'; X } X *ap++ = (char *) NULL; X X /* Prepare the environment pointers and strings. */ X while (*envp != (char *) NULL) { X *ap++ = (char *) (hp - stack); X p = *envp++; X while (*p) { X *hp++ = *p++; X if (hp >= &stack[ARG_MAX]) { X errno = E2BIG; X return -1; X } X } X *hp++ = '\0'; X } X *ap++ = (char *) NULL; X stackbytes = (((int) (hp - stack) + PTRSIZE - 1) / PTRSIZE) * PTRSIZE; X return __CALL1(_MM, EXEC, strlen(path) + 1, stackbytes, 0, path, stack, NULL); X} / echo x - _sysconf.c sed '/^X/s///' > _sysconf.c << '/' X/* _sysconf.c POSIX 4.8.1 (underware) X * long int __SYSCONF(int name); X * X * POSIX allows some of the values in <limits.h> to be increased at X * run time. The sysconf() function allows such values to be checked X * at run time. MINIX does not use this facility - the run time X * limits are those given in <limits.h>. X */ X X#include <lib.h> X#include <sys/types.h> X#include <errno.h> X#include <limits.h> X#include <unistd.h> X X_PUBLIC long int __SYSCONF(name) Xint name; /* property being inspected */ X{ X switch(name) { X case _SC_ARG_MAX: X return (long) ARG_MAX; X X case _SC_CHILD_MAX: X return (long) CHILD_MAX; X X case _SC_CLK_TCK: X return (long) CLK_TCK; X X case _SC_NGROUPS_MAX: X return (long) NGROUPS_MAX; X X case _SC_OPEN_MAX: X return (long) OPEN_MAX; X X case _SC_JOB_CONTROL: X return -1L; /* no job control */ X X case _SC_SAVED_IDS: X return -1L; /* no saved uid/gid */ X X case _SC_VERSION: X return (long) _POSIX_VERSION; X X default: X errno = EINVAL; X return -1L; X } X} / echo x - _ttyname.c sed '/^X/s///' > _ttyname.c << '/' X/* _ttyname.c POSIX 4.7.2 (underware) X * char *__TTYNAME(int fildes); X * X * Determines name of a terminal device. X */ X X#include <lib.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <dirent.h> X#include <fcntl.h> X#include <limits.h> X#include <stddef.h> X#include <string.h> X#include <unistd.h> X X_PRIVATE char base[] = "/dev"; X_PRIVATE char path[sizeof(base) + 1 + NAME_MAX]; /* extra 1 for '/' */ X X_PUBLIC char *__TTYNAME(fildes) Xint fildes; X{ X DIR *devices; X struct dirent *entry; X struct stat tty_stat; X struct stat dev_stat; X X /* Simple first test: file descriptor must be a character device */ X if (__FSTAT(fildes, &tty_stat) < 0 || !S_ISCHR(tty_stat.st_mode)) X return (char *) NULL; X X /* Open device directory for reading */ X if ((devices = __OPENDIR(base)) == (DIR *) NULL) X return (char *) NULL; X X /* Scan the entries for one that matches perfectly */ X while ((entry = __READDIR(devices)) != (struct dirent *) NULL) { X if (tty_stat.st_ino != entry->d_ino) X continue; X strcpy(path, base); X strcat(path, "/"); X strcat(path, entry->d_name); X if (__STAT(path, &dev_stat) < 0 || !S_ISCHR(dev_stat.st_mode)) X continue; X if (tty_stat.st_ino == dev_stat.st_ino && X tty_stat.st_dev == dev_stat.st_dev && X tty_stat.st_rdev == dev_stat.st_rdev) { X __CLOSEDIR(devices); X return path; X } X } X X __CLOSEDIR(devices); X return (char *) NULL; X} /