samperi@mancol.UUCP (Dominick Samperi) (03/24/88)
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@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@NYU.EDU ihnp4!rutgers!nyu.edu!manhat!samperi philabs!cmcl2!manhat!samperi ihnp4!rutgers!hombre!samperi (^ that's an ell) uunet!swlabs!mancol!samperi