Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!snorkelwacker!bloom-beacon!eru!luth!sunic!mcsun!hp4nl!star.cs.vu.nl!ast@cs.vu.nl From: ast@cs.vu.nl (Andy Tanenbaum) Newsgroups: comp.os.minix Subject: POSIX Message-ID: <3819@ast.cs.vu.nl> Date: 25 Oct 89 23:24:46 GMT Sender: ast@cs.vu.nl Reply-To: ast@cs.vu.nl (Andy Tanenbaum) Organization: VU Informatica, Amsterdam Lines: 413 I am beginning to get a little sick about the dosread.c again discussion. At least the discussion about the PDP-11 MMU was technical, even though somewhat irrelevant for this group. I interpret the DOS lovers/haters discussion to mean that we have run out of material to talk about. Let me inject some fresh material. For those people who don't have a POSIX standard, here is what I believe to be a complete list of all the function calls required by P1003.1. Run it off using tbl and troff. If somebody wants to write tbl and troff for MINIX, by all means please do so. For the uninitiated, POSIX defines a set of function calls that must be available. Whether they are system calls are library calls is up to the implementer. I, for example, intend to implement sigemptyset as the folloing library routine: sigemptyset(set) sigset_t *set; { *set = 0; } I suspect there will be a lot of discussion of POSIX in the coming months. The reason I suspect this is that I intend to generate some of it. If you want to follow what is going on, order the P1003.1 standard from IEEE by calling them at (201) 981-0060 in Piscatawy NJ. It costs $20 for IEEE members and $36 for nonmembers. They take credit card phone orders. I am also going to post the preliminary MINIX 2.0 (probably also 1.4b) headers right now. This is the complete set. It is my hope that they all conform to ANSI and POSIX. Fat chance. Will the language lawyers please go over them and post comments. Then we can have philosophical discussions about things like mandatory options (including time_t in ) and the like. If you are itching to hack MINIX and learn about POSIX at the same time, may I suggest a project: get the standard and write some POSIX test programs. Test programs are an area where one cannot have too many. In the shar file below is a sample test program, for P1003.1 Section 5.1. I rather like this style, and would encourage others to use it. Note that I also test for the error conditions required by the standard. When running the test program, I found a gross bug in Doug Gwyn's directory package. When you call opendir(), a DIR struct is malloc'ed. This struct contains a buffer pointer. When you closedir(), the buffer and the struct are returned. However, if you call closedir() with a dirp that has already been closed, closedir() assumes that dirp points to a valid DIR, finds the pointer to the buffer, and calls free() to release the storage. To make a long story short, free() is not enamoured of being called with essentially a random number as argument. It makes its unhappiness known in an unpleasant way--by dumping core. I have fixed the bug by putting a magic number in DIR, so all the calls can see if the dirp points to something valid. Closedir() erases the magic number (see _DIR_MAGIC in dirent.h). I will post the corrected routines along with 1.4b. If you don't like all the stupid underscores in the headers, may I congratulate you on your good taste. Maybe we underscore-haters could join X3J11 en masse and vote the underscore-lovers down. Andy Tanenbaum (ast@cs.vu.nl) : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'posix.calls' sed 's/^X//' > 'posix.calls' << '+ END-OF-FILE ''posix.calls' X.tr _\(ru X.PP XBelow is a complete list of the POSIX functions (excluding the XC library functions required by Chap. 8). A prototype and description Xis given for each one. XNext comes a phrase about the implementation. The designation "V1.4" means Xthat the MINIX V1.4b version is pretty close. In no case is it exact however. XThe last column tells whether the function is a system call (S) or a library Xroutine that makes other system calls (L). X.sp 2 X.TS Xcenter allbox tab(;); Xl l l l . XPOSIX Chap. 3 Functions;Description;Implementation;SL X_ Xpid_t fork();Fork;V1.4;S Xint exec(...);Execl, execv, etc.;V1.4;S Xpid_t wait(int *stat_loc);Wait for child;Just call waitpid();L Xpid_t waitpid(pid_t pid, int *stat_loc, int options);Wait for child;New call;S Xvoid _exit(int status);Terminate process;V1.4 exit();S Xint kill(pid_t pid, int sig);Send a signal;Modified V1.4;S Xint sigemptyset(sigset_t *set);Create signal set;New lib;L Xint sigfillset(sigset_t *set);Create signal set;New lib;L Xint sigaddset(sigset_t *set, int signo);Add sig to set;New lib;L Xint sigdelset(sigset_t *set, int signo);Remove sig from set;New lib;L Xint sigismember(sigset_t *set, int signo);Test for membership;New lib;L Xint sigaction(int sig, struct sigaction *act, *oact);Replaces signal;New call;S Xint sigprocmask(int how, sigset *set, *oset);Manipulate mask;New call;S Xint sigpending(sigset_t *set);Inspect pending sigs;New call;S Xint sigsuspend(sigset_t *sigmask);Replace sig mask;New call;S Xunsigned int alarm(unsigned int sec);Set timer;V1.4;S Xint pause();Suspend caller;V1.4;S Xunsigned int sleep(int sleep);Sleep;Truly hairy lib;L X.TE X.sp X.TS Xcenter allbox tab(;); Xl l l l . XPOSIX Chap. 4 Functions;Description;Implementation;SL X_ Xpid_t getpid();Get process id;V1.4;S Xpid_t getppid();Get parent's id;New call;S Xuid_t getuid();Get user id;V1.4;S Xuid_t geteuid();Get effective user id;V1.4;S Xgid_t getgid();Get group id;V1.4;S Xgid_t getegid();Get effective group id;V1.4;S Xint setuid(uid_t uid);Set uid;Modified V1.4;S Xint setgid(gid_t gid);Set gid;Modified V1.4;S Xint getgroups(int gidsetsize, gid_t grouplist[]);Get groups;No-op;L Xchar *getlogin();Get login name;V1.4 lib;L Xchar *cuserid(char *s);Get current user id;V1.4 lib;L Xpid_t getpgrp();Get process group;New call;S Xpid_t setsid();Set session id;New call;S Xpid_t setpgid(pid_t pid, pid_t pgid);Set process group;New call;S Xint uname(struct utsname *name);Get system id;New lib;L Xtime_t time(time_t *loc);Get time since 1970;V1.4;S Xclock_t times(struct tms *buffer);Get accounting;V1.4;S Xchar *getenv(char *name);Search environment;V1.4 lib;L Xchar *ctermid(char *s);Get controlling tty name;V1.4 lib;L Xchar *ttyname(int fd);Get tty name;V1.4 lib;L Xchar *isatty(int fd);See if fd is tty;V1.4 lib;L Xlong sysconf(int name);Get config params;New lib;L X.TE X.bp X.TS Xcenter allbox tab(;); Xl l l l . XPOSIX Chap. 5 Functions;Description;Implementation;SL X_ XDIR *opendir(char *dirname);Open a dir;Doug Gwynn's lib routine;L Xstruct dirent *readdir(DIR *dirp);Read dir entry;Doug Gwynn's lib routine;L Xvoid rewinddir(DIR *dirp);Rewind dir;Doug Gwynn's lib routine;L Xint closedir(DIR *dirp);Close dir;Doug Gwynn's lib routine;L Xint chdir(char *path);Change dir;V1.4 syscall;S Xchar *getcwd(char *buf, int size);Get working dir;V1.4 lib routine;L Xint open(char *path, int oflag, mode_t mode);Open a file;Modified V1.4;S Xint creat(char *path, mode_t mode);Create file;Just call open();L Xmode_t umask(mode_t cmask);Set file mask;V1.4;S Xint link(char *path1, char *path2);Link file;V1.4;S Xint mkdir(char *path, mode_t mode);Make dir;New call;S Xint mkfifo(char *path, mode_t mode);Make FIFO;Use mknod();S Xint unlink(char *path);Unlink file;V1.4;S Xint rmdir(char *path);Remove dir;New call;S Xint rename(char *old, char *new);Rename file;New call;S Xint stat(char *path, struct stat *buf);Stat file;V1.4;S Xint fstat(int fd, struct stat *buf);Stat file;V1.4;S Xint access(char *path, int amode);Determine access;V1.4;S Xint chmod(char *path, mode-t mode);Change mode;V1.4;S Xint chown(char *path, uid_t owner, gid_t group);Change group;Modified V1.4;S Xint utime(char *path, struct utimbuf *times);Set times;V1.4;S Xlong pathconf(char *path, int name);Get values;Trivial lib;L Xlong fpathconf(int fd, int name);Get values;Trivial lib;L X.TE X.sp 0.5 X.TS Xcenter allbox tab(;); Xl l l l . XPOSIX Chap. 6 Functions;Description;Implementation;SL X_ Xint pipe(int fd[]);Create pipe;V1.4;S Xint dup(int fd);Duplicate file descr.;Lib call to fcntl;L Xint dup2(int fd);Duplicate file descr.;Lib call to fcnl;L Xint close(int fd);Close file;V1.4;S Xint read(int fd, char *buf, unsigned nbyte);Read data;Modified V1.4;S Xint write(int fd, char *buf, unsigned nbyte);Write data;Modified V1.4;S Xint fcntl(int fd, int cmd, int arg);Misc. junk;New call;S Xoff_t lseek(int fd, off_t offset, int whence);Seek;V1.4;S X.TE X.sp 0.5 X.TS Xcenter allbox tab(;); Xl l l l . XPOSIX Chap. 7 Functions;Description;Implementation;SL X_ Xspeed_t cfgetospeed(struct termios ptr);Get output speed;New call;S Xint cfsetospeed(struct termios ptr, int speed);Set output speed;New call;S Xspeed_t cfgetispeed(struct termios ptr);Get input speed;New call;S Xint cfsetispeed(struct termios ptr, int speed);Set input speed;New call;S Xint tcgetattr(int fd, struct termios ptr);Get tty attributes;New call;S Xint tcsetattr(int fd, int act, struct termios ptr);Set tty attributes;New call;S Xtcsendbreak(int fd, int duration);Send a break;New call;S Xint tcdrain(int fd);Wait until output done;New call;S Xint tcflush(int fd, int queue_selctor);Purge input/output;New call;S Xint tcflow(int fd, int action);Start/stop tty line;New call;S Xpid_t tcgetpgrp(int fd);Get process group;New call;S Xint tcsetpgrp(int fd, pid_t pgrp_id);Set process group;New call;S X.TE + END-OF-FILE posix.calls chmod 'u=rw,g=r,o=r' 'posix.calls' set `wc -c 'posix.calls'` count=$1 case $count in 5700) :;; *) echo 'Bad character count in ''posix.calls' >&2 echo 'Count should be 5700' >&2 esac echo Extracting 'test20.c' sed 's/^X//' > 'test20.c' << '+ END-OF-FILE ''test20.c' X/* Test POSIX directory operations. */ X X#include X#include X#include X#include X X#define DIR_NULL (DIR *) NULL X#define ITERATIONS 15 X#define MAX_FD 100 /* must be large enough to cause error */ X Xint subtest, errct; Xextern errno; X Xmain() X{ X X int i; X X sync(); X printf("Test 20 "); X X for (i = 0; i < ITERATIONS; i++) { X test20a(); /* test for correct operation */ X test20b(); /* test general error handling */ X test20c(); /* test for EMFILE error */ X } X if (errct == 0) X printf("ok\n"); X else X printf(" %d errors\n", errct); X exit(0); X} X Xtest20a() X{ X/* Subtest 1. Correct operation */ X X int f1, f2, f3, f4, f5; X DIR *dirp; X X /* Remove any residue of previous tests. */ X subtest = 1; X system("rm -rf foo"); X X /* Create a directory foo with 5 files in it. */ X system("mkdir foo"); X if ( (f1 = creat("foo/f1", 0666)) < 0) e(1); X if ( (f2 = creat("foo/f2", 0666)) < 0) e(2); X if ( (f3 = creat("foo/f3", 0666)) < 0) e(3); X if ( (f4 = creat("foo/f4", 0666)) < 0) e(4); X if ( (f5 = creat("foo/f5", 0666)) < 0) e(5); X X /* Now remove 2 files to create holes in the directory. */ X if (unlink("foo/f2") < 0) e(6); X if (unlink("foo/f4") < 0) e(7); X X /* Close the files. */ X close(f1); X close(f2); X close(f3); X close(f4); X close(f5); X X /* Open the directory. */ X dirp = opendir("./foo"); X if (dirp == DIR_NULL) e(6); X X /* Read the 5 files from it. X checkdir(dirp, 2); X X /* Rewind dir and test again. */ X rewinddir(dirp); X checkdir(dirp, 3); X X /* We're done. Close the directory stream. */ X if (closedir(dirp) < 0) e(7); X X /* Remove dir for next time. */ X system("rm -rf foo"); X} X Xcheckdir(dirp, t) XDIR *dirp; /* poinrter to directory stream */ Xint t; /* subtest number to use */ X{ X X int i, f1, f2, f3, f4, f5, dot, dotdot, subt; X struct dirent *d; X char *s; X X /* Save subtest number */ X subt = subtest; X subtest = t; X X /* Clear the counters. */ X f1 = 0; X f2 = 0; X f3 = 0; X f4 = 0; X f5 = 0; X dot = 0; X dotdot = 0; X X /* Read the directory. It should contain 5 entries, ".", ".." and 3 files.*/ X for (i = 0; i < 5; i++) { X d = readdir(dirp); X if (d == (struct dirent *) NULL) { X e(1); X subtest = subt; /* restore subtest number */ X return; X } X s = d->d_name; X if (strcmp(s, "." ) == 0) dot++; X if (strcmp(s, "..") == 0) dotdot++; X if (strcmp(s, "f1") == 0) f1++; X if (strcmp(s, "f2") == 0) f2++; X if (strcmp(s, "f3") == 0) f3++; X if (strcmp(s, "f4") == 0) f4++; X if (strcmp(s, "f5") == 0) f5++; X } X X /* Check results. */ X d = readdir(dirp); X if (d != (struct dirent *) NULL) e(2); X if (f1 != 1 || f3 != 1 || f5 != 1) e(3); X if (f2 != 0 || f4 != 0) e(4); X if (dot != 1 || dotdot != 1) e(5); X subtest = subt; X return; X} X X Xtest20b() X{ X/* Subtest 4. Test error handling. */ X X int fd, fd2; X DIR *dirp; X X subtest = 4; X X if (opendir("foo/xyz/---") != DIR_NULL) e(1); X if (errno != ENOENT) e(2); X if (system("mkdir foo") < 0) e(3); X if (chmod("foo", 0) < 0) e(4); X if (opendir("foo/xyz/--") != DIR_NULL) e(5); X if (errno != EACCES) e(6); X if (system("rmdir foo") < 0) e(7); X if ( (fd = creat("abc", 0666)) < 0) e(8); X if (close(fd) < 0) e(9); X if (opendir("abc/xyz") != DIR_NULL) e(10); X if (errno != ENOTDIR) e(11); X if ( (dirp = opendir(".")) == DIR_NULL) e(12); X if (closedir(dirp) != 0) e(13); X if (closedir(dirp) >= 0) e(14); X if (readdir(dirp) != (struct dirent *) NULL) e(15); X if (errno != EBADF) e(16); X if (readdir( (DIR *) -1) != (struct dirent *) NULL) e(17); X if (errno != EBADF) e(18); X X} X X Xtest20c() X{ X/* Subtest 5. See what happens if we open too many directory streams. */ X X int i, j; X DIR *dirp[MAX_FD]; X X subtest = 5; X X for (i = 0; i < MAX_FD; i++) { X dirp[i] = opendir("."); X if (dirp[i] == NULL) { X /* We have hit the limit. */ X if (errno != EMFILE) e(1); X for (j = 0; j < i; j++) X if (closedir(dirp[j]) != 0) e(2); /* close */ X return; X } X } X X /* Control should never come here. This is an error. */ X e(3); X for (i = 0; i < MAX_FD; i++) closedir(dirp[i]); /* don't check */ X} X X Xe(n) Xint n; X{ X printf("\n\tSubtest %d, error %d, errno=%d ", subtest, n, errno); X perror(""); X errct++; X} X + END-OF-FILE test20.c chmod 'u=rw,g=r,o=r' 'test20.c' set `wc -c 'test20.c'` count=$1 case $count in 4163) :;; *) echo 'Bad character count in ''test20.c' >&2 echo 'Count should be 4163' >&2 esac exit 0