Patch-ID: bash32-032
[bash.git] / examples / loadables / mkdir.c
blobcd6e5f96db2d2fd83b0455489571b6e5c9a6be1f
1 /* mkdir - make directories */
3 /* See Makefile for compilation details. */
5 #include <config.h>
7 #include "bashtypes.h"
8 #include "posixstat.h"
9 #include <errno.h>
10 #include <stdio.h>
11 #include "bashansi.h"
12 #if defined (HAVE_UNISTD_H)
13 # include <unistd.h>
14 #endif
16 #include "builtins.h"
17 #include "shell.h"
18 #include "bashgetopt.h"
20 #if !defined (errno)
21 extern int errno;
22 #endif
24 #define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
26 extern int parse_symbolic_mode ();
28 static int make_path ();
30 static int original_umask;
32 int
33 mkdir_builtin (list)
34 WORD_LIST *list;
36 int opt, pflag, omode, rval, octal, nmode, parent_mode, um;
37 char *mode;
38 WORD_LIST *l;
40 reset_internal_getopt ();
41 pflag = 0;
42 mode = (char *)NULL;
43 while ((opt = internal_getopt(list, "m:p")) != -1)
44 switch (opt)
46 case 'p':
47 pflag = 1;
48 break;
49 case 'm':
50 mode = list_optarg;
51 break;
52 default:
53 builtin_usage();
54 return (EX_USAGE);
56 list = loptend;
58 if (list == 0)
60 builtin_usage ();
61 return (EX_USAGE);
64 if (mode == NULL)
65 omode = S_IRWXU | S_IRWXG | S_IRWXO; /* a=rwx */
66 else if (ISOCTAL (*mode)) /* octal number */
68 omode = read_octal (mode);
69 if (omode < 0)
71 builtin_error ("invalid file mode: %s", mode);
72 return (EXECUTION_FAILURE);
74 octal = 1;
76 else if (mode)
78 /* initial bits are a=rwx; the mode argument modifies them */
79 omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
80 if (omode < 0)
82 builtin_error ("invalid file mode: %s", mode);
83 return (EXECUTION_FAILURE);
85 octal = 0;
88 /* Make the new mode */
89 original_umask = umask (0);
90 umask (original_umask);
92 nmode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask;
93 parent_mode = nmode | (S_IWRITE|S_IEXEC); /* u+wx */
95 /* Adjust new mode based on mode argument */
96 nmode &= omode;
98 for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
100 if (pflag && make_path (l->word->word, nmode, parent_mode))
102 rval = EXECUTION_FAILURE;
103 continue;
105 else if (pflag == 0 && mkdir (l->word->word, nmode) < 0)
107 builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno));
108 rval = EXECUTION_FAILURE;
111 return rval;
114 /* Make all the directories leading up to PATH, then create PATH. Note that
115 this changes the process's umask; make sure that all paths leading to a
116 return reset it to ORIGINAL_UMASK */
117 static int
118 make_path (path, nmode, parent_mode)
119 char *path;
120 int nmode, parent_mode;
122 int oumask;
123 struct stat sb;
124 char *p, *npath;
126 if (stat (path, &sb) == 0)
128 if (S_ISDIR (sb.st_mode) == 0)
130 builtin_error ("`%s': file exists but is not a directory", path);
131 return 1;
134 if (chmod (path, nmode))
136 builtin_error ("%s: %s", path, strerror (errno));
137 return 1;
140 return 0;
143 oumask = umask (0);
144 npath = savestring (path); /* So we can write to it. */
146 /* Check whether or not we need to do anything with intermediate dirs. */
148 /* Skip leading slashes. */
149 p = npath;
150 while (*p == '/')
151 p++;
153 while (p = strchr (p, '/'))
155 *p = '\0';
156 if (stat (npath, &sb) != 0)
158 if (mkdir (npath, parent_mode))
160 builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
161 umask (original_umask);
162 free (npath);
163 return 1;
166 else if (S_ISDIR (sb.st_mode) == 0)
168 builtin_error ("`%s': file exists but is not a directory", npath);
169 umask (original_umask);
170 free (npath);
171 return 1;
174 *p++ = '/'; /* restore slash */
175 while (*p == '/')
176 p++;
179 /* Create the final directory component. */
180 if (stat (npath, &sb) && mkdir (npath, nmode))
182 builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
183 umask (original_umask);
184 free (npath);
185 return 1;
188 umask (original_umask);
189 free (npath);
190 return 0;
193 char *mkdir_doc[] = {
194 "Make directories. Create the directories named as arguments, in",
195 "the order specified, using mode rwxrwxrwx as modified by the current",
196 "umask (see `help umask'). The -m option causes the file permission",
197 "bits of the final directory to be MODE. The MODE argument may be",
198 "an octal number or a symbolic mode like that used by chmod(1). If",
199 "a symbolic mode is used, the operations are interpreted relative to",
200 "an initial mode of \"a=rwx\". The -p option causes any required",
201 "intermediate directories in PATH to be created. The directories",
202 "are created with permssion bits of rwxrwxrwx as modified by the current",
203 "umask, plus write and search permissions for the owner. mkdir",
204 "returns 0 if the directories are created successfully, and non-zero",
205 "if an error occurs.",
206 (char *)NULL
209 struct builtin mkdir_struct = {
210 "mkdir",
211 mkdir_builtin,
212 BUILTIN_ENABLED,
213 mkdir_doc,
214 "mkdir [-p] [-m mode] directory [directory ...]",