523feb68ce10ce7c4e763da48c743163f28aac4b
[mmh] / sbr / makedir.c
1
2 /*
3  * makedir.c -- make a directory
4  *
5  * $Id$
6  *
7  * This code is Copyright (c) 2002, by the authors of nmh.  See the
8  * COPYRIGHT file in the root directory of the nmh distribution for
9  * complete copyright information.
10  */
11
12 /*
13  * Modified to try recursive create.
14  */
15
16 #include <h/mh.h>
17 #include <errno.h>
18 #include <sys/param.h>
19 #include <sys/file.h>
20
21 extern int errno;
22         
23 int
24 makedir (char *dir)
25 {
26     char            path[PATH_MAX];
27     char*           folder_perms_ASCII;
28     int             had_an_error = 0;
29     mode_t          folder_perms, saved_umask;
30     pid_t           pid;
31     register char*  c;
32
33     context_save();     /* save the context file */
34     fflush(stdout);
35
36     if (!(folder_perms_ASCII = context_find ("folder-protect")))
37         folder_perms_ASCII = foldprot;  /* defaults to "700" */
38     
39     /* Because mh-profile.man documents "Folder-Protect:" as an octal constant,
40        and we don't want to force the user to remember to include a leading
41        zero, we call atooi(folder_perms_ASCII) here rather than
42        strtoul(folder_perms_ASCII, NULL, 0).  Therefore, if anyone ever tries to
43        specify a mode in say, hex, they'll get garbage.  (I guess nmh uses its
44        atooi() function rather than calling strtoul() with a radix of 8 because
45        some ancient platforms are missing that functionality. */
46     folder_perms = atooi(folder_perms_ASCII);
47
48     /* Folders have definite desired permissions that are set -- we don't want
49        to interact with the umask.  Clear it temporarily. */
50     saved_umask = umask(0);
51
52     if (getuid () == geteuid ()) {
53         c = strncpy(path, dir, sizeof(path));     
54         
55         while (!had_an_error && (c = strchr((c + 1), '/')) != NULL) {   
56             *c = (char)0;
57             if (access(path, X_OK)) {
58                 if (errno != ENOENT){
59                     advise (dir, "unable to create directory");
60                     had_an_error = 1;
61                 }
62                 /* Create an outer directory. */
63                 if (mkdir(path, folder_perms)) {
64                     advise (dir, "unable to create directory");
65                     had_an_error = 1;
66                 }
67             }
68             *c = '/';
69         }
70
71         if (!had_an_error) {
72             /* Create the innermost nested subdirectory of the path we're being
73                asked to create. */
74             if (mkdir (dir, folder_perms) == -1) {
75                 advise (dir, "unable to create directory");
76                 had_an_error = 1;
77             }
78         }
79     }
80     else {
81         /* Ummm, why do we want to avoid creating directories with the effective
82            user ID?  None of the nmh tools are installed such that the effective
83            should be different from the real, and if some parent process made
84            the two be different, I don't see why it should be our job to enforce
85            the real UID.  Also, why the heck do we call the mkdir executable
86            rather than the library function in this case??  If we do want to
87            call the mkdir executable, we should at least be giving it -p (and
88            change the single chmod() call below) so it can successfully create
89            nested directories like the above code can.
90
91            -- Dan Harkless <dan-nmh@dilvish.speed.net> */
92         switch (pid = vfork()) {
93             case -1: 
94                 advise ("fork", "unable to");
95                 return 0;
96                 
97             case 0: 
98                 setgid (getgid ());
99                 setuid (getuid ());
100                 
101                 execl ("/bin/mkdir", "mkdir", dir, NULL);
102                 execl ("/usr/bin/mkdir", "mkdir", dir, NULL);
103                 fprintf (stderr, "unable to exec ");
104                 perror ("mkdir");
105                 _exit (-1);
106                 
107             default: 
108                 if (pidXwait(pid, "mkdir"))
109                     return 0;
110                 break;
111         }
112
113         chmod (dir, folder_perms);
114     }
115
116     umask(saved_umask);  /* put the user's umask back */
117
118     if (had_an_error)
119         return 0;  /* opposite of UNIX error return convention */
120     else
121         return 1;
122 }