447cafc566fd6f2f807f2b1cb95b9b317a6bb49a
[platform/upstream/coreutils.git] / src / mkdir.c
1 /* mkdir -- make directories
2    Copyright (C) 90, 1995-2002, 2004, 2005, 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* David MacKenzie <djm@ai.mit.edu>  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24
25 #include "system.h"
26 #include "dirname.h"
27 #include "error.h"
28 #include "lchmod.h"
29 #include "mkdir-p.h"
30 #include "modechange.h"
31 #include "quote.h"
32
33 /* The official name of this program (e.g., no `g' prefix).  */
34 #define PROGRAM_NAME "mkdir"
35
36 #define AUTHORS "David MacKenzie"
37
38 /* The name this program was run with. */
39 char *program_name;
40
41 static struct option const longopts[] =
42 {
43   {"mode", required_argument, NULL, 'm'},
44   {"parents", no_argument, NULL, 'p'},
45   {"verbose", no_argument, NULL, 'v'},
46   {GETOPT_HELP_OPTION_DECL},
47   {GETOPT_VERSION_OPTION_DECL},
48   {NULL, 0, NULL, 0}
49 };
50
51 void
52 usage (int status)
53 {
54   if (status != EXIT_SUCCESS)
55     fprintf (stderr, _("Try `%s --help' for more information.\n"),
56              program_name);
57   else
58     {
59       printf (_("Usage: %s [OPTION] DIRECTORY...\n"), program_name);
60       fputs (_("\
61 Create the DIRECTORY(ies), if they do not already exist.\n\
62 \n\
63 "), stdout);
64       fputs (_("\
65 Mandatory arguments to long options are mandatory for short options too.\n\
66 "), stdout);
67       fputs (_("\
68   -m, --mode=MODE   set file mode (as in chmod), not a=rwx - umask\n\
69   -p, --parents     no error if existing, make parent directories as needed\n\
70   -v, --verbose     print a message for each created directory\n\
71 "), stdout);
72       fputs (HELP_OPTION_DESCRIPTION, stdout);
73       fputs (VERSION_OPTION_DESCRIPTION, stdout);
74       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
75     }
76   exit (status);
77 }
78
79 /* Options for announce_mkdir and make_ancestor.  */
80 struct mkdir_options
81 {
82   /* Mode for ancestor directory.  */
83   mode_t ancestor_mode;
84
85   /* If not null, format to use when reporting newly made directories.  */
86   char const *created_directory_format;
87 };
88
89 /* Report that directory DIR was made, if OPTIONS requests this.  */
90 static void
91 announce_mkdir (char const *dir, void *options)
92 {
93   struct mkdir_options const *o = options;
94   if (o->created_directory_format)
95     error (0, 0, o->created_directory_format, quote (dir));
96 }
97
98 /* Make ancestor directory DIR, with options OPTIONS.  */
99 static int
100 make_ancestor (char const *dir, void *options)
101 {
102   struct mkdir_options const *o = options;
103   int r = mkdir (dir, o->ancestor_mode);
104   if (r == 0)
105     announce_mkdir (dir, options);
106   return r;
107 }
108
109 int
110 main (int argc, char **argv)
111 {
112   mode_t mode = S_IRWXUGO;
113   mode_t mode_bits = 0;
114   int (*make_ancestor_function) (char const *, void *) = NULL;
115   const char *specified_mode = NULL;
116   int exit_status = EXIT_SUCCESS;
117   int optc;
118   struct mkdir_options options;
119   options.created_directory_format = NULL;
120
121   initialize_main (&argc, &argv);
122   program_name = argv[0];
123   setlocale (LC_ALL, "");
124   bindtextdomain (PACKAGE, LOCALEDIR);
125   textdomain (PACKAGE);
126
127   atexit (close_stdout);
128
129   while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1)
130     {
131       switch (optc)
132         {
133         case 'p':
134           make_ancestor_function = make_ancestor;
135           break;
136         case 'm':
137           specified_mode = optarg;
138           break;
139         case 'v': /* --verbose  */
140           options.created_directory_format = _("created directory %s");
141           break;
142         case_GETOPT_HELP_CHAR;
143         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
144         default:
145           usage (EXIT_FAILURE);
146         }
147     }
148
149   if (optind == argc)
150     {
151       error (0, 0, _("missing operand"));
152       usage (EXIT_FAILURE);
153     }
154
155   if (make_ancestor_function || specified_mode)
156     {
157       mode_t umask_value = umask (0);
158
159       options.ancestor_mode = (S_IRWXUGO & ~umask_value) | (S_IWUSR | S_IXUSR);
160
161       if (specified_mode)
162         {
163           struct mode_change *change = mode_compile (specified_mode);
164           if (!change)
165             error (EXIT_FAILURE, 0, _("invalid mode %s"),
166                    quote (specified_mode));
167           mode = mode_adjust (S_IRWXUGO, true, umask_value, change,
168                               &mode_bits);
169           free (change);
170         }
171       else
172         mode &= ~umask_value;
173     }
174
175   for (; optind < argc; ++optind)
176     if (! make_dir_parents (argv[optind], make_ancestor_function, &options,
177                             mode, announce_mkdir,
178                             mode_bits, (uid_t) -1, (gid_t) -1, true))
179       exit_status = EXIT_FAILURE;
180
181   exit (exit_status);
182 }