[comp.os.minix] POSIX

aj-mberg@dasys1.UUCP (Micha Berger) (07/19/89)

The header said it all, what is POSIX?
				micha

-- 
					Micha Berger

"Always should [the child of] Adam have awe of G-d in secret and in public,
admit the truth, and speak truth in his heart." 

ast@cs.vu.nl (Andy Tanenbaum) (07/19/89)

In article <10284@dasys1.UUCP> aj-mberg@dasys1.UUCP (Micha Berger) writes:
> what is POSIX?

POSIX is the IEEE P1003 standard.   It is an attempt to get rid of the the
4.3/5.3 split in the UNIX world and come to a single standard.  What the
standardization committee did was take all those features that were in Both
4.3 and 5.3 and put them in POSIX.  Of course, that was basically V7.
Ioctl and signals are different, and there is a little bit of new stuff,
but semantically, it is moderately close to V7.

That is why I like POSIX so much.  It is real UNIX, stripped of all the
barnacles that both AT&T and Berkeley have added to it.

Andy Tanenbaum (ast@cs.vu.nl)

ast@cs.vu.nl (Andy Tanenbaum) (10/26/89)

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 <sys/types.h>) 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 <sys/types.h>
X#include <dirent.h>
X#include <unistd.h>
X#include <errno.h>
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

madd@world.std.com (jim frost) (10/26/89)

In article <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
|When running the test program, I found a gross bug in Doug Gwyn's directory
|package.  However, if you call closedir()
|with a dirp that has already been closed, closedir() assumes that dirp
|points to a valid DIR

I'm not certain I'd call this a directory package bug, although an
attempt to trap it is certainly a feature.  GIGO and all.  A
legitimate closedir bug is something like the one in the SysV
closedir.  Paraphrased:

	closedir(dir)
	  DIRP *dir;
	{
	  free(dir);
	  return(close(dir->dirf));
	}

|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.

I'd be happy to.  It's kind of annoying to have to migrate up to that
top row all the time.  :-)

Happy hacking,

jim frost
software tool & die
madd@std.com

rsalz@bbn.com (Rich Salz) (10/27/89)

In <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) says he found a
"gross bug" ross bug in Doug Gwyn's directory: "if you call closedir()
with a dirp that has already been closed" the free inside closedir()
will bomb.  He then says he "fixed" it by putting a magic number which
is checked, then cleared, by closedir(). 

Well gee, strcpy() can blow up if either parameter is a null pointer.
Gonna fix that?  fprintf("%d", 5) can blow up.  Gonna fix that?
The point is that you're if you call closedir() twice you've broken the
rules.  Don't do that, and don't slow down standard library routines by
bullet-proofing that way.  You just do a half-way, inconsistent job, that
helps hide bugs when code is ported.  BSD did NOT do the world a favor
by making it legal to deference location zero -- ask anyone who's ported
poor code from BSD to Sun, for example.

As a minor point, the "fix" mentioned above isn't bulletproof, either.
It is not impossible that I pass a garbage pointer into closedir() that
just happens to point to some place with the same magic number.

Please don't distribute these changes.
	/r$
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.

ast@cs.vu.nl (Andy Tanenbaum) (10/27/89)

In article <1989Oct26.143100.4916@world.std.com> madd@world.UUCP (jim frost) writes:
>In article <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>|When running the test program, I found a gross bug in Doug Gwyn's directory
>|package.  However, if you call closedir()
>|with a dirp that has already been closed, closedir() assumes that dirp
>|points to a valid DIR
>
>I'm not certain I'd call this a directory package bug, 

Perhaps it wasn't a bug previously, but has to be regarded as a bug now
because POSIX explicitly requires a call to closedir() with a rotten
argument to return EBADF, not to crash, trap or do anything else. (See
Sec. 5.1.2.4 of P1003.1).

Andy Tanenbaum (ast@cs.vu.nl)

michaelb@vms.macc.wisc.edu (MICHAEL BLOXHAM) (10/27/89)

In article <3819@ast.cs.vu.nl>, ast@cs.vu.nl (Andy Tanenbaum) writes...

> 
>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

The reason for the volume of the dosread.c discussion is that the original 
posting was cross-posted to comp.sys.ibm.pc.  So everyone there is getting
bent outta shape over AST's reply which also got cross-posted, probably 
unknowingly.  This reply of no DOS interest to a mainly DOS related group 
caused a lot of eye raising.


so much for the obvious,

mike

truesdel@sun217..nas.nasa.gov (David A. Truesdell) (10/27/89)

ast@cs.vu.nl (Andy Tanenbaum) writes:
>Perhaps it wasn't a bug previously, but has to be regarded as a bug now
>because POSIX explicitly requires a call to closedir() with a rotten
>argument to return EBADF, not to crash, trap or do anything else. (See
>Sec. 5.1.2.4 of P1003.1).

I bet to differ!  I consider this to be pointing out a bug in the implementation
of free().  Calling free(), with a grabage pointer, shouldn't result in a
trap either.  It shouldn't be layed at the feet of a portable library package
to work around possible bugs in the underlying environment.

A call to free() should (IMHO) result in either the storage being added
to the free pool, if a valid looking header is found, or no action at all
if garbage is presented.


T.T.F.N.,
dave truesdell (truesdel@prandtl.nas.nasa.gov)

rsalz@bbn.com (Rich Salz) (10/27/89)

In article <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>with a dirp that has already been closed, closedir() assumes that dirp
>points to a valid DIR

Both Jim Frost (<1989Oct26.143100.4916@world.std.com>) and I (<something>)
don't think this is a bug.

In <3842@math.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>Perhaps it wasn't a bug previously, but has to be regarded as a bug now
>because POSIX explicitly requires a call to closedir() with a rotten
>argument to return EBADF, not to crash, trap or do anything else. (See
>Sec. 5.1.2.4 of P1003.1).

If closedir() is not implemented as a syscall, then the only portable
way to handle this is to keep a list of everything you ever opendir'd,
and a flag as to whether it's still valid or not.

Magic numbers just ain't foolproof.

Posix blew it on this one; they should have defined it to be undefined
action.
	/r$
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.

ast@cs.vu.nl (Andy Tanenbaum) (10/28/89)

In article <3600@amelia.nas.nasa.gov> truesdel@sun217..nas.nasa.gov (David A. Truesdell) writes:
>I bet to differ!  I consider this to be pointing out a bug in the implementation
>of free().  Calling free(), with a grabage pointer, shouldn't result in a
>trap either.  It shouldn't be layed at the feet of a portable library package
>to work around possible bugs in the underlying environment.

I disagree.  A proper, portable library package should not make invalid
calls to other library routines in the expectation that they will detect
their bad arguments and give a polite reply.  If you maintain that the
called library routine (free) should check for bad arguments, then the
directory package should also check for bad arguments.  As a library
implementer you can hardly say "Everybody else should check for bad
arguments are complain when found, but I don't have to check."

Andy Tanenbaum (ast@cs.vu.nl)

ast@cs.vu.nl (Andy Tanenbaum) (10/28/89)

In article <2091@prune.bbn.com> rsalz@bbn.com (Rich Salz) writes:
>If closedir() is not implemented as a syscall, then the only portable
>way to handle this is to keep a list of everything you ever opendir'd,
>and a flag as to whether it's still valid or not.

No.  It is sufficient to keep a list of all the ones that are still open.
When someone does a close, you check the list and if it is not on it,
you return EBADF.  My quickie solution is only 65535/65536-ths correct,
but I find the code too hairy to change in any serious way.

>Posix blew it on this one; they should have defined it to be undefined
I disagree.  I think every incorrect call should return an error and the
standard should specify which error it is, to allow applications to test
for that specific error.  In almost all other parts of the standard they
specified the error returns, so why not here.

Andy Tanenbaum (ast@cs.vu.nl)

johnz@grapevine.uucp (John Zolnowsky ext. 33230) (10/28/89)

In article <2091@prune.bbn.com>, rsalz@bbn.com (Rich Salz) writes:
> In <3842@math.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
> >Perhaps it wasn't a bug previously, but has to be regarded as a bug now
> >because POSIX explicitly requires a call to closedir() with a rotten
> >argument to return EBADF, not to crash, trap or do anything else. (See
> >Sec. 5.1.2.4 of P1003.1).
> 
> If closedir() is not implemented as a syscall, then the only portable
> way to handle this is to keep a list of everything you ever opendir'd,
> and a flag as to whether it's still valid or not.
> 
> Posix blew it on this one; they should have defined it to be undefined
> action.

POSIX is full of "legalese" for these cases.  The EBADF case mentioned
above, for instance, is prefaced by the conditional:
	"For each of the following conditions, *when* [emphasis added -JZ]
	the condition is detected, the closedir() function shall return
	-1 and set errno ..."

Section 2.5 Error Numbers further clarifies this in the fourth paragraph:
	"Implementations may support additional errors not included in
	this list, may generate errors in this list under circumstances
	other than those described here, or may contain extensions or
	*limitations* [emphasis added -JZ] that prevent some errors
	from occurring."

POSIX defines the behavior of a conforming program.  A program which
closedirs a DIR pointer twice is non-conforming, and the behavior of
the implementation need not be meaningful, useful, or even helpful.
						-JZ
----------------------------------------------------------------------
John Zolnowsky		johnz@EBay.Sun.COM or ...!sun!johnz

dal@syntel.mn.org (Dale Schumacher) (10/28/89)

truesdel@sun217..nas.nasa.gov (David A. Truesdell) writes:
|ast@cs.vu.nl (Andy Tanenbaum) writes:
|>Perhaps it wasn't a bug previously, but has to be regarded as a bug now
|>because POSIX explicitly requires a call to closedir() with a rotten
|>argument to return EBADF, not to crash, trap or do anything else. (See
|>Sec. 5.1.2.4 of P1003.1).
|
|I bet to differ!  I consider this to be pointing out a bug in the implementation
|of free().  Calling free(), with a grabage pointer, shouldn't result in a
|trap either.  It shouldn't be layed at the feet of a portable library package
|to work around possible bugs in the underlying environment.
|
|A call to free() should (IMHO) result in either the storage being added
|to the free pool, if a valid looking header is found, or no action at all
|if garbage is presented.

Sorry, but this is not free()'s job.  Section 4.10.3.2, describing the
'free' function, states:

	The 'free' function causes the space pointed to by 'ptr' to be
	deallocated, that is, made available for further allocation.
	If 'ptr' is a null pointer, no action occurs.  Otherwise, if the
	argument does not match a pointer earlier returned by the
	'calloc', 'malloc', or 'realloc' function, or if the space has
	been deallocated by a call to 'free' or 'realloc', the behaviour
	is undefined.

"Undefined" behaviour means it can do ANYTHING if that situation occurs.
Now that we have standards (or nearly so, in the case of C), personal
opinions are moot.  Also, P1003.1 says about closedir():

	For each of the following conditions, when the condition is
	detected, the closedir() function shall return -1 and set
	'errno' to the corresponding value:
	
	[EBADF]	The 'dirp' argument does not refer to an open directory
	stream.

Thus the bug is really a bug, and Doug probably already is aware of it,
though perhaps Andy should send him a note to be sure.

\\   /  Dale Schumacher                         399 Beacon Ave.
 \\ /   (alias: Dalnefre')                      St. Paul, MN  55104-3527
  ><    ...umn-cs!midgard.mn.org!syntel!dal     United States of America
 / \\   "What is wanted is not the will to believe, but the will to find out,
/   \\  which is the exact opposite." -Bertrand Russell

peter@ficc.uu.net (Peter da Silva) (10/28/89)

In article <4128@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
> If you maintain that the
> called library routine (free) should check for bad arguments, then the
> directory package should also check for bad arguments.

Malloc/free are normally expected to track allocated memory, so it is
reasonable to expect them to be able to check their arguments... they
already have the information they need.

A directory package doesn't, so you eithet have to maintain a list of
allocated chunks, duplicating free's work, or go to an unreliable system
like a flag word. Or pre-allocate the structures and use descriptors.

An argument-checking library is a good idea. But the amount of overhead
needed to do this right is prohibitive, and doing it wrong gives a false
sense of security. A production library should not even try unless the
right set of checks are cheap... like in malloc/free.

It's not something for POSIX to specify, and in fact they don't specify
it. They merely say that *when an error is detected* the error code should
be EBADF.
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.hackercorp.com>.
 'U`  --------------  +1 713 274 5180.
"That particular mistake will not be repeated.  There are plenty of mistakes
 left that have not yet been used." -- Andy Tanenbaum (ast@cs.vu.nl)

peter@ficc.uu.net (Peter da Silva) (10/29/89)

In article <092789A7523@syntel.mn.org> dal@syntel.mn.org (Dale Schumacher) writes:
! 	For each of the following conditions, WHEN THE CONDITION IS
! 	DETECTED, the closedir() function shall return -1 and set
> 	'errno' to the corresponding value:

> 	[EBADF]	The 'dirp' argument does not refer to an open directory
> 	stream.

[emphasis mine -- pds]

And if the condition is not detected?
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.hackercorp.com>.
 'U`  --------------  +1 713 274 5180.
"That particular mistake will not be repeated.  There are plenty of mistakes
 left that have not yet been used." -- Andy Tanenbaum (ast@cs.vu.nl)

ast@cs.vu.nl (Andy Tanenbaum) (10/30/89)

In article <34633@grapevine.uucp> johnz@grapevine.uucp (John Zolnowsky ext. 33230) writes:
>POSIX is full of "legalese" for these cases.  The EBADF case mentioned
>above, for instance, is prefaced by the conditional:
>	"For each of the following conditions, *when* [emphasis added -JZ]
>	the condition is detected, the closedir() function shall return
>	-1 and set errno ..."

Thanks you for your explanation.  I had assumed that "when" meant "at the
time that" rather than "if," but you may well be right.  I only hope that
the guys making conformance tests understand this.  The little test program
I posted actually checks for it.  If you are right, the test program is
overzealous.

Andy Tanenbaum (ast@cs.vu.nl)

henry@utzoo.uucp (Henry Spencer) (10/31/89)

In article <6716@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>! 	For each of the following conditions, WHEN THE CONDITION IS
>! 	DETECTED, the closedir() function shall return -1 and set
>> 	'errno' ...
>
>And if the condition is not detected?

Then the ball is in the implementor's court, and all bets are off.
-- 
A bit of tolerance is worth a  |     Henry Spencer at U of Toronto Zoology
megabyte of flaming.           | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

truesdel@sun217..nas.nasa.gov (David A. Truesdell) (10/31/89)

In comp.os.minix you write:

>truesdel@sun217..nas.nasa.gov (David A. Truesdell) writes:
>Sorry, but this is not free()'s job.  Section 4.10.3.2, describing the
>'free' function, states:
>
>	                     . . .                    if the space has
>	been deallocated by a call to 'free' or 'realloc', the behaviour
>	is undefined.
>
>"Undefined" behaviour means it can do ANYTHING if that situation occurs.
>Now that we have standards (or nearly so, in the case of C), personal
>opinions are moot.

True, "Undefined" does mean you could do anything, but there is something to
be said for the "Principle of Least Astonishment".

Would you use a system on which the "undefined" behaviour meant "destroy all
data on disk"?  I sure wouldn't, but it is permitted by the standard.
But then, I don't like library routines dumping core, either.  Guess I'm just
too conservative.


T.T.F.N.,
dave truesdell (truesdel@prandtl.nas.nasa.gov)

cechew@bruce.OZ (Earl Chew) (11/13/89)

From article <12288@fluke.COM>, by dcd@tc.fluke.COM (David Dyck):
> "Std 1003.3 - Draft 7.0 TEST METHODS for MEASURING CONFORMANCE to POSIX 1003.1"
> (NOTE: this is still in DRAFT form)
> and looked up the documentation for closedir that ast mentioned October 25th.
> It states (under section 5.1.2.4 Errors)
> 
> "On a call to closedir(dirp) when the dirp argument does not refer to an open
> directory streem, shall return a value of -1 and set "errno" to {EBADF}."

This is in direct contradiction to Std 1003.1-1988 Sec B.5.1.2:

"Since the strcutre and buffer allocation, if any, for directory operations are
defined by the implementation, the standard imposes no portability requirements
for erroneous program constructs, erroneous data, or the use of indeterminate
values such as the use or referencing of a dirp value or a dirent structure
value after a directory stream has been closed or after a fork() or one of the
exec function calls."

The wording *very* clear on this point.

Furthermore, Std 1003.1-1988 Sec 5.1.1.2:

"If the dirp argument passed to any of these functions does not refer to a
currently-open directory stream, the effect is undefined."

Thus the implementation (Minix) can do whatever it likes (ie check or not
check).

Earl
-- 
Earl Chew, Dept of Computer Science, Monash University, Australia 3168
ARPA: cechew%bruce.cs.monash.oz.au@uunet.uu.net  ACS : cechew@bruce.oz
----------------------------------------------------------------------