source: mainline/uspace/app/bdsh/cmds/modules/mkdir/mkdir.c@ ac897e8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ac897e8 was 19f857a, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Rename string.h to str.h to avoid header conflict with standard C string.h.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of the original program's authors nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <dirent.h>
35#include <fcntl.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <getopt.h>
39#include <stdarg.h>
40#include <str.h>
41
42#include "config.h"
43#include "errors.h"
44#include "util.h"
45#include "entry.h"
46#include "mkdir.h"
47#include "cmds.h"
48
49#define MKDIR_VERSION "0.0.1"
50
51static const char *cmdname = "mkdir";
52
53static struct option const long_options[] = {
54 {"parents", no_argument, 0, 'p'},
55 {"verbose", no_argument, 0, 'v'},
56 {"mode", required_argument, 0, 'm'},
57 {"help", no_argument, 0, 'h'},
58 {"version", no_argument, 0, 'V'},
59 {"follow", no_argument, 0, 'f'},
60 {0, 0, 0, 0}
61};
62
63
64void help_cmd_mkdir(unsigned int level)
65{
66 if (level == HELP_SHORT) {
67 printf("`%s' creates a new directory\n", cmdname);
68 } else {
69 help_cmd_mkdir(HELP_SHORT);
70 printf(
71 "Usage: %s [options] <path>\n"
72 "Options:\n"
73 " -h, --help A short option summary\n"
74 " -V, --version Print version information and exit\n"
75 " -p, --parents Create needed parents for <path>\n"
76 " -m, --mode Set permissions to [mode] (UNUSED)\n"
77 " -v, --verbose Be extremely noisy about what is happening\n"
78 " -f, --follow Go to the new directory once created\n"
79 "Currently, %s is under development, some options don't work.\n",
80 cmdname, cmdname);
81 }
82
83 return;
84}
85
86/* This is kind of clunky, but effective for now */
87static unsigned int
88create_directory(const char *path, unsigned int p)
89{
90 DIR *dirp;
91 char *tmp = NULL, *buff = NULL, *wdp = NULL;
92 char *dirs[255];
93 unsigned int absolute = 0, i = 0, ret = 0;
94
95 /* Its a good idea to allocate path, plus we (may) need a copy of
96 * path to tokenize if parents are specified */
97 if (NULL == (tmp = str_dup(path))) {
98 cli_error(CL_ENOMEM, "%s: path too big?", cmdname);
99 return 1;
100 }
101
102 if (NULL == (wdp = (char *) malloc(PATH_MAX))) {
103 cli_error(CL_ENOMEM, "%s: could not alloc cwd", cmdname);
104 free(tmp);
105 return 1;
106 }
107
108 /* The only reason for wdp is to be (optionally) verbose */
109 getcwd(wdp, PATH_MAX);
110
111 /* Typical use without specifying the creation of parents */
112 if (p == 0) {
113 dirp = opendir(tmp);
114 if (dirp) {
115 cli_error(CL_EEXISTS, "%s: can not create %s, try -p", cmdname, path);
116 closedir(dirp);
117 goto finit;
118 }
119 if (-1 == (mkdir(tmp, 0))) {
120 cli_error(CL_EFAIL, "%s: could not create %s", cmdname, path);
121 goto finit;
122 }
123 }
124
125 /* Parents need to be created, path has to be broken up */
126
127 /* See if path[0] is a slash, if so we have to remember to append it */
128 if (tmp[0] == '/')
129 absolute = 1;
130
131 /* TODO: Canonify the path prior to tokenizing it, see below */
132 dirs[i] = strtok(tmp, "/");
133 while (dirs[i] && i < 255)
134 dirs[++i] = strtok(NULL, "/");
135
136 if (NULL == dirs[0])
137 return 1;
138
139 if (absolute == 1) {
140 asprintf(&buff, "/%s", dirs[0]);
141 mkdir(buff, 0);
142 chdir(buff);
143 free(buff);
144 getcwd(wdp, PATH_MAX);
145 i = 1;
146 } else {
147 i = 0;
148 }
149
150 while (dirs[i] != NULL) {
151 /* Sometimes make or scripts conjoin odd paths. Account for something
152 * like this: ../../foo/bar/../foo/foofoo/./bar */
153 if (!str_cmp(dirs[i], "..") || !str_cmp(dirs[i], ".")) {
154 if (0 != (chdir(dirs[i]))) {
155 cli_error(CL_EFAIL, "%s: impossible path: %s",
156 cmdname, path);
157 ret ++;
158 goto finit;
159 }
160 getcwd(wdp, PATH_MAX);
161 } else {
162 if (-1 == (mkdir(dirs[i], 0))) {
163 cli_error(CL_EFAIL,
164 "%s: failed at %s/%s", wdp, dirs[i]);
165 ret ++;
166 goto finit;
167 }
168 if (0 != (chdir(dirs[i]))) {
169 cli_error(CL_EFAIL, "%s: failed creating %s\n",
170 cmdname, dirs[i]);
171 ret ++;
172 break;
173 }
174 }
175 i++;
176 }
177 goto finit;
178
179finit:
180 free(wdp);
181 free(tmp);
182 return ret;
183}
184
185int cmd_mkdir(char **argv)
186{
187 unsigned int argc, create_parents = 0, i, ret = 0, follow = 0;
188 unsigned int verbose = 0;
189 int c, opt_ind;
190 char *cwd;
191
192 argc = cli_count_args(argv);
193
194 for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
195 c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
196 switch (c) {
197 case 'p':
198 create_parents = 1;
199 break;
200 case 'v':
201 verbose = 1;
202 break;
203 case 'h':
204 help_cmd_mkdir(HELP_LONG);
205 return CMD_SUCCESS;
206 case 'V':
207 printf("%s\n", MKDIR_VERSION);
208 return CMD_SUCCESS;
209 case 'f':
210 follow = 1;
211 break;
212 case 'm':
213 printf("%s: [W] Ignoring mode %s\n", cmdname, optarg);
214 break;
215 }
216 }
217
218 argc -= optind;
219
220 if (argc < 1) {
221 printf("%s - incorrect number of arguments. Try `%s --help'\n",
222 cmdname, cmdname);
223 return CMD_FAILURE;
224 }
225
226 if (NULL == (cwd = (char *) malloc(PATH_MAX))) {
227 cli_error(CL_ENOMEM, "%s: could not allocate cwd", cmdname);
228 return CMD_FAILURE;
229 }
230
231 memset(cwd, 0, sizeof(cwd));
232 getcwd(cwd, PATH_MAX);
233
234 for (i = optind; argv[i] != NULL; i++) {
235 if (verbose == 1)
236 printf("%s: creating %s%s\n",
237 cmdname, argv[i],
238 create_parents ? " (and all parents)" : "");
239 ret += create_directory(argv[i], create_parents);
240 }
241
242 if (follow == 0)
243 chdir(cwd);
244
245 free(cwd);
246
247 if (ret)
248 return CMD_FAILURE;
249 else
250 return CMD_SUCCESS;
251}
252
Note: See TracBrowser for help on using the repository browser.