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