gwyn@BRL.ARPA (07/07/86)
#!/bin/sh # Self-unpacking archive format. To unbundle, sh this file. echo 'dir_test.c' 1>&2 cat >'dir_test.c' <<'END OF dir_test.c' /* dir_test -- mkdir, rmdir function test last edit: 86/07/05 D A Gwyn SCCS ID: @(#)dir_test.c 1.1 */ #include <stdio.h> #include <string.h> extern void _exit(); extern int access(); static char Dirname[] = "/tmp/dir.tst"; /* test directory */ extern int mkdir(), rmdir(); /*ARGSUSED*/ main( argc, argv ) int argc; char *argv[]; { char buf[BUFSIZ]; /* for constructing strings */ (void)system( strcat( strcpy( buf, "mkdir " ), Dirname ) ); if ( access( Dirname, 0 ) != 0 ) _exit( 1 ); if ( mkdir( Dirname, 0777 ) == 0 ) _exit( 2 ); if ( rmdir( Dirname ) != 0 ) _exit( 3 ); (void)umask( 0200 ); if ( mkdir( Dirname, 0777 ) != 0 ) _exit( 4 ); if ( access( Dirname, 0 ) != 0 ) _exit( 5 ); if ( access( Dirname, 02 ) == 0 ) _exit( 6 ); if ( access( Dirname, 05 ) != 0 ) _exit( 7 ); if ( rmdir( Dirname ) != 0 ) _exit( 8 ); return 0; } END OF dir_test.c echo 'mkdir.3' 1>&2 cat >'mkdir.3' <<'END OF mkdir.3' .TH MKDIR 3V VMB '\" last edit: 86/07/05 D A Gwyn '\" SCCS ID: @(#)mkdir.3 1.1 .SH NAME mkdir \- create a directory .SH SYNOPSIS .B int mkdir(path,mode); .br .B char *path; .br .B int mode; .SH DESCRIPTION The .I mkdir\^ function creates a new directory with name .IR path\^ . The mode of the new directory is initialized from .IR mode\^ . The protection part of the .I mode\^ argument is modified by the process's file creation mask (see .IR umask\^ (2)). .P The directory's owner .SM ID is set to the process's effective user ID. Depending on the host system, the directory group ID is set either to the group ID of its parent directory or to the process's effective group ID. .P The newly created directory is empty except that it may contain entries for ``\s+2.\s0'' and ``\s+2..\s0''. .SH "RETURN VALUE" A return value of 0 indicates success. A return value of \-1 indicated that an error has occurred and an appropriate error code is stored in .IR errno\^ . No directory is created if the return value is \-1. .SH NOTE This function is compatible with the definition in the IEEE 1003.1 standard. .SH EXAMPLE The following program is compiled by the command .br $ \fIcc \|\-I/vld/include \|example.c \|/vld/lib/libVMB.a\fP .sp .P #include <stdio.h> .br extern int mkdir(); .br main( argc, argv ) .br int argc; .br char *argv[\|]; .br { .br if ( argc < 2 \|||\| mkdir( argv[1], 0777 ) != 0 ) .br { .br (void) fputs( ``mkdir failed'', stderr ); .br exit( 1 ); .br } .br return 0; .br } .SH FILES /bin/mkdir system directory creation utility .br /vld/lib/libVMB.a VLD-VMB programmer support library .SH "SEE ALSO" mkdir(1), mknod(2), rmdir(3V), umask(2). .SH AUTHOR Douglas A. Gwyn, BRL/VLD-VMB END OF mkdir.3 echo 'mkdir.c' 1>&2 cat >'mkdir.c' <<'END OF mkdir.c' /* mkdir -- create a directory last edit: 86/07/05 D A Gwyn SCCS ID: @(#)mkdir.c 1.1 compatible with IEEE 1003.1 returns zero iff operation succeeds */ #include <errno.h> #include <fcntl.h> #include <signal.h> extern void _exit(); extern int access(), chmod(), close(), execv(), fcntl(), open(), rmdir(), umask(), wait(); #ifndef F_OK #define F_OK 0 /* access -- test existence */ #endif #ifndef NULL #define NULL 0 #endif int mkdir( path, mode ) /* returns 0 iff successful */ char *path; /* name of new directory */ int mode; /* desired access mode */ { register int pid; /* process ID from fork() */ register int save; /* temporary */ save = errno; if ( path == NULL ) /* usually the best we can do */ { errno = EFAULT; /* path outside address space */ return -1; } else if ( path[0] == '\0' ) { errno = ENOENT; /* path points to null string */ return -1; } else if ( access( path, F_OK ) == 0 ) { errno = EEXIST; /* directory already exists */ return -1; } else if ( errno == EACCES /* search denied on prefix */ || errno == ENOTDIR /* path component not dir */ ) return -1; errno = save; /* access() changed errno */ switch ( pid = fork() ) { case -1: /* can't fork; too bad */ return -1; /* report fork errno */ case 0: /* child process */ { static char *mkdir_args[] = /* args for exec */ { "/bin/mkdir", /* system "mkdir" command */ (char *)0, /* directory name goes here */ (char *)0 /* list terminator */ }; mkdir_args[1] = path; /* be careful to avoid "mkdir" I/O side-effects */ (void)close( 0 ); (void)close( 1 ); (void)close( 2 ); if ( open( "/dev/null", O_RDWR ) != 0 || fcntl( 0, F_DUPFD, 1 ) != 1 || fcntl( 0, F_DUPFD, 2 ) != 2 || execv( mkdir_args[0], mkdir_args ) != 0 ) ; /* _exit in all cases */ _exit( 255 ); /*NOTREACHED*/ } default: /* parent process */ { int status; /* child termination status */ register int w; /* PID returned from wait() */ #ifdef SIGCLD register void (*oldcld)() = signal( SIGCLD, SIG_DFL ); /* avoid wait on all children */ #endif while ( (w = wait( &status )) != pid && (w != -1 || errno == EINTR) ) ; /* wait for proper child */ #ifdef SIGCLD if ( oldcld != SIG_DFL ) /* restore catcher */ (void)signal( SIGCLD, oldcld ); #endif if ( w == -1 || status != 0 ) { errno = EACCES; /* can't write on parent? */ return -1; } } } save = umask( 0 ); if ( chmod( path, mode & ~save ) != 0 ) /* "can't happen" */ { (void)umask( save ); (void)rmdir( path ); /* comply with spec */ return -1; /* report chmod | rmdir errno */ } else { (void)umask( save ); return 0; /* success */ } } END OF mkdir.c echo 'rmdir.3' 1>&2 cat >'rmdir.3' <<'END OF rmdir.3' .TH RMDIR 3V VMB '\" last edit: 86/07/05 D A Gwyn '\" SCCS ID: @(#)rmdir.3 1.1 .SH NAME rmdir \- remove a directory .SH SYNOPSIS .B int rmdir(path); .br .B char *path; .SH DESCRIPTION The .I rmdir\^ function removes a directory whose name is given by .IR path\^ . The directory must not have any entries other than, possibly, ``\s+2.\s0'' and ``\s+2..\s0''. .P Depending on the host system, it may be possible to remove the root or current working directory. .SH "RETURN VALUE" A return value of 0 indicates success. A return value of \-1 indicated that an error has occurred and an appropriate error code is stored in .IR errno\^ . .SH NOTE This function is compatible with the definition in the IEEE 1003.1 standard. .SH EXAMPLE The following program is compiled by the command .br $ \fIcc \|\-I/vld/include \|example.c \|/vld/lib/libVMB.a\fP .sp .P #include <stdio.h> .br extern int rmdir(); .br main( argc, argv ) .br int argc; .br char *argv[\|]; .br { .br if ( argc < 2 \|||\| rmdir( argv[1] ) != 0 ) .br { .br (void) fputs( ``rmdir failed'', stderr ); .br exit( 1 ); .br } .br return 0; .br } .SH FILES /bin/rmdir system directory creation utility .br /vld/lib/libVMB.a VLD-VMB programmer support library .SH "SEE ALSO" mkdir(3V), remove(3V), rmdir(1). .SH AUTHOR Douglas A. Gwyn, BRL/VLD-VMB END OF rmdir.3 echo 'rmdir.c' 1>&2 cat >'rmdir.c' <<'END OF rmdir.c' /* rmdir -- remove a directory last edit: 86/07/05 D A Gwyn SCCS ID: @(#)rmdir.c 1.1 compatible with IEEE 1003.1 returns zero iff operation succeeds */ #include <errno.h> #include <fcntl.h> #include <signal.h> extern void _exit(); extern int access(), close(), execv(), fcntl(), open(), wait(); #ifndef F_OK #define F_OK 0 /* access -- test existence */ #endif #ifndef NULL #define NULL 0 #endif int rmdir( path ) /* returns 0 iff successful */ char *path; /* name of directory */ { register int pid; /* process ID from fork() */ if ( path == NULL ) /* usually the best we can do */ { errno = EFAULT; /* path outside address space */ return -1; } else if ( path[0] == '\0' ) { errno = ENOENT; /* path points to null string */ return -1; } else if ( access( path, F_OK ) != 0 ) return -1; /* EACCES, ENOTDIR, ENOENT */ switch ( pid = fork() ) { case -1: /* can't fork; too bad */ return -1; /* report fork errno */ case 0: /* child process */ { static char *rmdir_args[] = /* args for exec */ { "/bin/rmdir", /* system "rmdir" command */ (char *)0, /* directory name goes here */ (char *)0 /* list terminator */ }; rmdir_args[1] = path; /* be careful to avoid "rmdir" I/O side-effects */ (void)close( 0 ); (void)close( 1 ); (void)close( 2 ); if ( open( "/dev/null", O_RDWR ) != 0 || fcntl( 0, F_DUPFD, 1 ) != 1 || fcntl( 0, F_DUPFD, 2 ) != 2 || execv( rmdir_args[0], rmdir_args ) != 0 ) ; /* _exit in all cases */ _exit( 255 ); /*NOTREACHED*/ } default: /* parent process */ { int status; /* child termination status */ register int w; /* PID returned from wait() */ #ifdef SIGCLD register void (*oldcld)() = signal( SIGCLD, SIG_DFL ); /* avoid wait on all children */ #endif while ( (w = wait( &status )) != pid && (w != -1 || errno == EINTR) ) ; /* wait for proper child */ #ifdef SIGCLD if ( oldcld != SIG_DFL ) /* restore catcher */ (void)signal( SIGCLD, oldcld ); #endif if ( w == -1 || status != 0 ) { errno = EACCES; /* can't write on parent? */ return -1; } else return 0; /* success */ } } /*NOTREACHED*/ } END OF rmdir.c
ahby@meccts.UUCP (Shane P. McCarron) (07/08/86)
In article <1981@brl-smoke.ARPA> gwyn@BRL.ARPA writes: >This function is compatible with the definition in the >IEEE 1003.1 Since this standard is not finished, and has only been published in a Trial Use Document, is this compatible with the trial use, or with the in progress document being developed by the working committee. -- Shane P. McCarron UUCP ihnp4!meccts!ahby MECC Technical Services ATT (612) 481-3589 "Sinners can repent, but stupid is forever."
gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/08/86)
In article <438@meccts.UUCP> ahby@meccts.UUCP (Shane P. McCarron) writes: -In article <1981@brl-smoke.ARPA> gwyn@BRL.ARPA writes: ->This function is compatible with the definition in the ->IEEE 1003.1 -Since this standard is not finished, and has only been published in a -Trial Use Document, is this compatible with the trial use, or with the -in progress document being developed by the working committee. Trial use, but I expect this interface won't change much. Note that it is not a precisely conforming implementation, since it cheats on some of the error conditions. If /bin/mkdir and /bin/rmdir return distinct exit status for different failure modes, this could be improved. Also note that, as Chris Torek pointed out, it would be better to move the SIGCLD reset to before the fork(). I have a similar rename() implementation if anyone needs it and can't figure out how to modify rmdir.c to get it.