SysV.3 mkdir for Release < 3
Dominick Samperi
samperi at mancol.UUCP
Thu Mar 24 05:58:00 AEST 1988
Here is a SystemV.3-compatible mkdir(1) that can be used with
Release < 3. It also has an effective group id option that is useful
to use in conjunction with setgid programs.
I'm placing it into the public domain.
Dominick Samperi, Manhattan College, NYC
manhat!samperi at NYU.EDU ihnp4!rutgers!nyu.edu!manhat!samperi
philabs!cmcl2!manhat!samperi ihnp4!rutgers!hombre!samperi
(^ that's an ell) uunet!swlabs!mancol!samperi
---- cut here ------------- cut here ------------ cut here ------------
/*
* mkdir.c - System V.3-compatible /bin/mkdir, with
* effective group id option.
*
* Author: Dominick Samperi, March 19, 1988.
* nyu.edu!manhat!samperi
* rutgers!hombre!samperi
*
* Usage: mkdir [-pg] [-m mode] dirnames
*
* -p => make intermediate directories, if necessary.
* -g => use process effective group id instead of the real group id.
* -m mode => set the mode of the created directory.
*
* Installation:
*
* cc -O mkdir.c -o mkdir
* mv /bin/mkdir /bin/OLDmkdir
* mv mkdir /bin/mkdir
* chown root mkdir
* chmod 4511 mkdir
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define TRUE 1
#define FALSE 0
#define not !
#define is_dir(statp) ((statp->st_mode & S_IFMT) == S_IFDIR)
#define writable(statp, uid, gid) (uid == 0 || (statp->st_mode & 02) \
|| (uid == statp->st_uid && (statp->st_mode & 0200)) \
|| (gid == statp->st_gid && (statp->st_mode & 0020)))
int build = FALSE ; /* Build intermediate directories if TRUE. */
int setmod = FALSE ; /* Set mode from command line. */
int uid, gid ; /* User and group ids for the directory. */
main(argc, argv)
int argc ;
char *argv[] ;
/*
* mkdir [-m mode] [-pg] dirnames
*/
{
int i, gotname = FALSE, status = 0, mode = -1, mask ;
char *p ;
uid = getuid() ; gid = getgid() ;
gotname = FALSE ; i = 1 ;
while(i < argc && not gotname)
if(argv[i][0] == '-')
{
p = argv[i] + 1 ;
while(*p != '\0')
switch(*p++)
{
case 'm': /* Set directory mode. */
if(sscanf(argv[i+1], "%o", &mode) != 1
|| mode > 0777)
{
fprintf(stderr, "Bad mode\n") ;
exit(1) ;
}
i++ ;
break ;
case 'p': /* Build intermediate subdirectories. */
build = TRUE ;
break ;
case 'g': /* Use effective group id. */
gid = getegid() ;
break ;
default:
fprintf(stderr,
"Bad option: -%c\n", argv[i][1]) ;
exit(1) ;
}
i++ ;
}
else
gotname = TRUE ;
if(not gotname)
{
fprintf(stderr, "Usage: mkdir [-m mode] [-pg] dirnames\n") ;
exit(0) ;
}
if(mode == -1)
mode = 040777 ; /* Use umask. */
else
{
mode |= 040000 ;
setmod = TRUE ;
}
for(; i < argc ; i++)
if(mkdir(argv[i], mode) < 0)
status = 1 ;
exit(status) ;
}
mkdir(dirname, mode)
char *dirname ;
int mode ;
{
char *root, *parent, *self, *p, *s ;
int len, status, exists ;
struct stat Stat_buf, *statp = &Stat_buf ;
/* Remove trailing '/', if present. */
len = strlen(dirname) ;
if(dirname[len-1] == '/')
{
dirname[len-1] = '\0' ;
len-- ;
}
/* Trying to create '/' ? */
if(len == 0)
{
fprintf(stderr, "Cannot make directory: '/'\n") ;
return(-1) ;
}
/* Does it already exist? */
if((status = stat(dirname, statp)) == 0
&& not is_dir(statp))
{
fprintf(stderr, "Not a directory: %s\n", dirname) ;
return(-1) ;
}
else if(status == 0)
{
fprintf(stderr, "Directory already exists: %s\n", dirname) ;
return(-1) ;
}
root = (char *) malloc(strlen(dirname)) ; /* Immediate parent. */
parent = (char *) malloc(strlen(dirname) + 4) ; /* dirname/.. */
self = (char *) malloc(strlen(dirname) + 3) ; /* dirname/. */
if((s = strrchr(dirname, '/')) != NULL)
{
if(s == dirname)
strcpy(root, "/") ;
else
{
strcpy(root, dirname) ;
root[s - dirname] = '\0' ;
}
}
else
strcpy(root, "./") ;
if((status = stat(root, statp)) == -1 && not build)
{
fprintf(stderr, "Couldn't access: %s\n", root) ;
return(-1) ;
}
else if(status == 0 && not is_dir(statp))
{
fprintf(stderr, "Not a directory: %s\n", root) ;
return(-1) ;
}
else if(status == 0 && not writable(statp, uid, gid))
{
fprintf(stderr, "No write access: %s\n", root) ;
return(-1) ;
}
else if(status == 0) /* Root exists and is accessible. */
{
if(mknod(dirname, mode, 0) < 0)
{
fprintf(stderr, "Couldn't mknod: %s\n", dirname) ;
return(-1) ;
}
strcpy(parent, dirname) ;
strcat(parent, "/..") ;
strcpy(self, dirname) ;
strcat(self, "/.") ;
if(link(root, parent) != 0 || link(dirname, self) != 0)
{
fprintf(stderr, "Couldn't create '.' and '..': %s\n",
dirname) ;
return(-1) ;
}
chown(dirname, uid, gid) ;
if(setmod)
chmod(dirname, mode) ;
}
else if(status == -1) /* No root, so we build. */
{
/* Skip over directories that already exist. */
exists = TRUE ;
p = strtok(dirname, "/") ;
while(p && exists)
{
if((status = stat(dirname, statp)) == 0
&& not is_dir(statp))
{
fprintf(stderr, "Not a directory: %s\n",
dirname) ;
return(-1) ;
}
else if(status == 0)
{
/* Check next larger path. */
p = strtok(NULL, "/") ;
if(p) p[-1] = '/' ;
}
else
/* Doesn't exist, or inaccessible. */
exists = FALSE ;
}
/* Then make intermediate directories. */
while(p)
{
if((status = stat(dirname, statp)) == 0
&& not is_dir(statp))
{
fprintf(stderr, "Not a directory: %s\n",
dirname) ;
return(-1) ;
}
else if(status == 0
&& not writable(statp, uid, gid))
{
fprintf(stderr, "No write access: %s\n",
dirname) ;
return(-1) ;
}
else if(status == -1
&& mknod(dirname, mode, 0) < 0)
{
fprintf(stderr, "Couldn't access: %s\n",
dirname) ;
return(-1) ;
}
else if(status == -1)
{
/* mknod() ok, add '.' and '..' */
if((s = strrchr(dirname, '/')) != NULL)
{
if(s == dirname)
strcpy(root, "/") ;
else
{
strcpy(root, dirname) ;
root[s - dirname] = '\0' ;
}
}
else
strcpy(root, "./") ;
strcpy(parent, dirname) ;
strcat(parent, "/..") ;
strcpy(self, dirname) ;
strcat(self, "/.") ;
if(link(root, parent) != 0
|| link(dirname, self) != 0)
{
fprintf(stderr,
"Couldn't make '.' and '..': %s\n",
dirname) ;
return(-1) ;
}
/* Set owner/group, and mode, if specified. */
chown(dirname, uid, gid) ;
if(setmod)
chmod(dirname, mode) ;
}
p = strtok(NULL, "/") ;
if(p) p[-1] = '/' ;
}
}
free(root) ; free(parent) ; free(self) ;
}
--
Dominick Samperi, Manhattan College, NYC
manhat!samperi at NYU.EDU ihnp4!rutgers!nyu.edu!manhat!samperi
philabs!cmcl2!manhat!samperi ihnp4!rutgers!hombre!samperi
(^ that's an ell) uunet!swlabs!mancol!samperi
More information about the Comp.unix.microport
mailing list