[bug #4302] errno is not always an extern int
[mmh] / sbr / makedir.c
index 6cf9e03..c5332ca 100644 (file)
@@ -3,6 +3,10 @@
  * makedir.c -- make a directory
  *
  * $Id$
+ *
+ * This code is Copyright (c) 2002, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
  */
 
 /*
 #include <errno.h>
 #include <sys/param.h>
 #include <sys/file.h>
-
-extern int errno;
        
 int
 makedir (char *dir)
 {
-    pid_t pid;
-    register char *cp;
-    register char *c;
-    char path[PATH_MAX];
+    char            path[PATH_MAX];
+    char*           folder_perms_ASCII;
+    int             had_an_error = 0;
+    mode_t          folder_perms, saved_umask;
+    pid_t           pid;
+    register char*  c;
 
     context_save();    /* save the context file */
     fflush(stdout);
 
-    if (getuid () == geteuid ()) {
-           c = strncpy(path, dir, sizeof(path));     
+    if (!(folder_perms_ASCII = context_find ("folder-protect")))
+       folder_perms_ASCII = foldprot;  /* defaults to "700" */
+    
+    /* Because mh-profile.man documents "Folder-Protect:" as an octal constant,
+       and we don't want to force the user to remember to include a leading
+       zero, we call atooi(folder_perms_ASCII) here rather than
+       strtoul(folder_perms_ASCII, NULL, 0).  Therefore, if anyone ever tries to
+       specify a mode in say, hex, they'll get garbage.  (I guess nmh uses its
+       atooi() function rather than calling strtoul() with a radix of 8 because
+       some ancient platforms are missing that functionality. */
+    folder_perms = atooi(folder_perms_ASCII);
 
-           while ((c = strchr((c + 1), '/')) != NULL) {        
-                   *c = (char)0;
-                   if (access(path, X_OK)) {
-                           if (errno != ENOENT){
-                                   advise (dir, "unable to create directory");
-                                   return 0;
-                           }                       
-                           if (mkdir(path, 0775)) {
-                                   advise (dir, "unable to create directory");
-                                   return 0;
-                           }
-                   }
-                   *c = '/';
-           }
-           if (mkdir (dir, 0755) == -1) {
+    /* Folders have definite desired permissions that are set -- we don't want
+       to interact with the umask.  Clear it temporarily. */
+    saved_umask = umask(0);
+
+    if (getuid () == geteuid ()) {
+       c = strncpy(path, dir, sizeof(path));     
+       
+       while (!had_an_error && (c = strchr((c + 1), '/')) != NULL) {   
+           *c = (char)0;
+           if (access(path, X_OK)) {
+               if (errno != ENOENT){
                    advise (dir, "unable to create directory");
-                   return 0;
+                   had_an_error = 1;
+               }
+               /* Create an outer directory. */
+               if (mkdir(path, folder_perms)) {
+                   advise (dir, "unable to create directory");
+                   had_an_error = 1;
+               }
            }
-    } else {
-       switch (pid = vfork()) {
-       case -1: 
-           advise ("fork", "unable to");
-           return 0;
-
-       case 0: 
-           setgid (getgid ());
-           setuid (getuid ());
+           *c = '/';
+       }
 
-           execl ("/bin/mkdir", "mkdir", dir, NULL);
-           execl ("/usr/bin/mkdir", "mkdir", dir, NULL);
-           fprintf (stderr, "unable to exec ");
-           perror ("mkdir");
-           _exit (-1);
+       if (!had_an_error) {
+           /* Create the innermost nested subdirectory of the path we're being
+              asked to create. */
+           if (mkdir (dir, folder_perms) == -1) {
+               advise (dir, "unable to create directory");
+               had_an_error = 1;
+           }
+       }
+    }
+    else {
+       /* Ummm, why do we want to avoid creating directories with the effective
+          user ID?  None of the nmh tools are installed such that the effective
+          should be different from the real, and if some parent process made
+          the two be different, I don't see why it should be our job to enforce
+          the real UID.  Also, why the heck do we call the mkdir executable
+          rather than the library function in this case??  If we do want to
+          call the mkdir executable, we should at least be giving it -p (and
+          change the single chmod() call below) so it can successfully create
+          nested directories like the above code can.
 
-       default: 
-           if (pidXwait(pid, "mkdir"))
+          -- Dan Harkless <dan-nmh@dilvish.speed.net> */
+       switch (pid = vfork()) {
+           case -1: 
+               advise ("fork", "unable to");
                return 0;
-           break;
+               
+           case 0: 
+               setgid (getgid ());
+               setuid (getuid ());
+               
+               execl ("/bin/mkdir", "mkdir", dir, NULL);
+               execl ("/usr/bin/mkdir", "mkdir", dir, NULL);
+               fprintf (stderr, "unable to exec ");
+               perror ("mkdir");
+               _exit (-1);
+               
+           default: 
+               if (pidXwait(pid, "mkdir"))
+                   return 0;
+               break;
        }
+
+       chmod (dir, folder_perms);
     }
 
-    if (!(cp = context_find ("folder-protect")))
-       cp = foldprot;
-    chmod (dir, atooi (cp));
-    return 1;
+    umask(saved_umask);  /* put the user's umask back */
+
+    if (had_an_error)
+       return 0;  /* opposite of UNIX error return convention */
+    else
+       return 1;
 }