source: mainline/uspace/app/bdsh/cmds/modules/ls/ls.c@ 5b61171

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5b61171 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 * Copyright (c) 2008 Tim Post
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/* NOTE:
30 * This is a bit of an ugly hack, working around the absence of fstat / etc.
31 * As more stuff is completed and exposed in libc, this will improve */
32
33#include <errno.h>
34#include <str_error.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stdint.h>
38#include <dirent.h>
39#include <getopt.h>
40#include <vfs/vfs.h>
41#include <str.h>
42
43#include "ls.h"
44#include "errors.h"
45#include "config.h"
46#include "util.h"
47#include "entry.h"
48#include "cmds.h"
49
50static const char *cmdname = "ls";
51
52static ls_job_t ls;
53
54static struct option const long_options[] = {
55 { "help", no_argument, 0, 'h' },
56 { "unsort", no_argument, 0, 'u' },
57 { "recursive", no_argument, 0, 'r' },
58 { 0, 0, 0, 0 }
59};
60
61/* Prototypes for the ls command, excluding entry points. */
62static unsigned int ls_start(ls_job_t *);
63static void ls_print(struct dir_elem_t *);
64static int ls_cmp(const void *, const void *);
65static signed int ls_scan_dir(const char *, DIR *, struct dir_elem_t **);
66static unsigned int ls_recursive(const char *, DIR *);
67static unsigned int ls_scope(const char *, struct dir_elem_t *);
68
69static unsigned int ls_start(ls_job_t *ls)
70{
71 ls->recursive = 0;
72 ls->sort = 1;
73
74 return 1;
75}
76
77/** Print an entry.
78 *
79 * ls_print currently does nothing more than print the entry.
80 * In the future, we will likely pass the absolute path, and
81 * some sort of ls_options structure that controls how each
82 * entry is printed and what is printed about it.
83 *
84 * Now we just print basic DOS style lists.
85 *
86 * @param de Directory element.
87 */
88static void ls_print(struct dir_elem_t *de)
89{
90 if (de->s.is_file)
91 printf("%-40s\t%llu\n", de->name, (long long) de->s.size);
92 else if (de->s.is_directory)
93 printf("%-40s\t<dir>\n", de->name);
94 else
95 printf("%-40s\n", de->name);
96}
97
98/** Compare 2 directory elements.
99 *
100 * It compares 2 elements of a directory : a file is considered
101 * as bigger than a directory, and if they have the same type,
102 * they are compared alphabetically.
103 *
104 * @param a Pointer to the structure of the first element.
105 * @param b Pointer to the structure of the second element.
106 *
107 * @return -1 if a < b, 1 otherwise.
108 */
109static int ls_cmp(const void *a, const void *b)
110{
111 struct dir_elem_t const *da = a;
112 struct dir_elem_t const *db = b;
113
114 if ((da->s.is_directory && db->s.is_file) ||
115 ((da->s.is_directory == db->s.is_directory) &&
116 str_cmp(da->name, db->name) < 0))
117 return -1;
118 else
119 return 1;
120}
121
122/** Scan a directory.
123 *
124 * Scan the content of a directory and print it.
125 *
126 * @param d Name of the directory.
127 * @param dirp Directory stream.
128 * @param sort 1 if the output must be sorted,
129 * 0 otherwise.
130 */
131static signed int ls_scan_dir(const char *d, DIR *dirp,
132 struct dir_elem_t **dir_list_ptr)
133{
134 int alloc_blocks = 20;
135 int i;
136 int nbdirs = 0;
137 errno_t rc;
138 int len;
139 char *buff;
140 struct dir_elem_t *tmp;
141 struct dir_elem_t *tosort;
142 struct dirent *dp;
143
144 if (!dirp)
145 return -1;
146
147 buff = (char *) malloc(PATH_MAX);
148 if (!buff) {
149 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
150 return -1;
151 }
152
153 tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
154 if (!tosort) {
155 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
156 free(buff);
157 return -1;
158 }
159
160 while ((dp = readdir(dirp))) {
161 if (nbdirs + 1 > alloc_blocks) {
162 alloc_blocks += alloc_blocks;
163
164 tmp = (struct dir_elem_t *) realloc(tosort,
165 alloc_blocks * sizeof(struct dir_elem_t));
166 if (!tmp) {
167 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
168 goto out;
169 }
170 tosort = tmp;
171 }
172
173 /* fill the name field */
174 tosort[nbdirs].name = (char *) malloc(str_size(dp->d_name) + 1);
175 if (!tosort[nbdirs].name) {
176 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
177 goto out;
178 }
179
180 str_cpy(tosort[nbdirs].name, str_size(dp->d_name) + 1, dp->d_name);
181 len = snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs].name);
182 buff[len] = '\0';
183
184 rc = vfs_stat_path(buff, &tosort[nbdirs++].s);
185 if (rc != EOK) {
186 printf("ls: skipping bogus node %s\n", buff);
187 printf("error=%s\n", str_error_name(rc));
188 goto out;
189 }
190 }
191
192 if (ls.sort)
193 qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t), ls_cmp);
194
195 for (i = 0; i < nbdirs; i++)
196 ls_print(&tosort[i]);
197
198 /* Populate the directory list. */
199 if (ls.recursive) {
200 tmp = (struct dir_elem_t *) realloc(*dir_list_ptr,
201 nbdirs * sizeof(struct dir_elem_t));
202 if (!tmp) {
203 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
204 goto out;
205 }
206 *dir_list_ptr = tmp;
207
208 for (i = 0; i < nbdirs; i++) {
209 (*dir_list_ptr)[i].name = str_dup(tosort[i].name);
210 if (!(*dir_list_ptr)[i].name) {
211 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
212 goto out;
213 }
214 }
215 }
216
217out:
218 for(i = 0; i < nbdirs; i++)
219 free(tosort[i].name);
220 free(tosort);
221 free(buff);
222
223 return nbdirs;
224}
225
226/** Visit a directory recursively.
227 *
228 * ls_recursive visits all the subdirectories recursively and
229 * prints the files and directories in them.
230 *
231 * @param path Path the current directory being visited.
232 * @param dirp Directory stream.
233 */
234static unsigned int ls_recursive(const char *path, DIR *dirp)
235{
236 int i, nbdirs, ret;
237 unsigned int scope;
238 char *subdir_path;
239 DIR *subdirp;
240 struct dir_elem_t *dir_list;
241
242 const char * const trailing_slash = "/";
243
244 nbdirs = 0;
245 dir_list = (struct dir_elem_t *) malloc(sizeof(struct dir_elem_t));
246
247 printf("\n%s:\n", path);
248
249 subdir_path = (char *) malloc(PATH_MAX);
250 if (!subdir_path) {
251 ret = CMD_FAILURE;
252 goto out;
253 }
254
255 nbdirs = ls_scan_dir(path, dirp, &dir_list);
256 if (nbdirs == -1) {
257 ret = CMD_FAILURE;
258 goto out;
259 }
260
261 for (i = 0; i < nbdirs; ++i) {
262 memset(subdir_path, 0, PATH_MAX);
263
264 if (str_size(subdir_path) + str_size(path) + 1 <= PATH_MAX)
265 str_append(subdir_path, PATH_MAX, path);
266 if (path[str_size(path)-1] != '/' &&
267 str_size(subdir_path) + str_size(trailing_slash) + 1 <= PATH_MAX)
268 str_append(subdir_path, PATH_MAX, trailing_slash);
269 if (str_size(subdir_path) +
270 str_size(dir_list[i].name) + 1 <= PATH_MAX)
271 str_append(subdir_path, PATH_MAX, dir_list[i].name);
272
273 scope = ls_scope(subdir_path, &dir_list[i]);
274 switch (scope) {
275 case LS_FILE:
276 break;
277 case LS_DIR:
278 subdirp = opendir(subdir_path);
279 if (!subdirp) {
280 /* May have been deleted between scoping it and opening it */
281 cli_error(CL_EFAIL, "Could not stat %s", dir_list[i].name);
282 ret = CMD_FAILURE;
283 goto out;
284 }
285
286 ret = ls_recursive(subdir_path, subdirp);
287 closedir(subdirp);
288 if (ret == CMD_FAILURE)
289 goto out;
290 break;
291 case LS_BOGUS:
292 ret = CMD_FAILURE;
293 goto out;
294 }
295 }
296
297 ret = CMD_SUCCESS;
298
299out:
300 for (i = 0; i < nbdirs; i++)
301 free(dir_list[i].name);
302 free(dir_list);
303 free(subdir_path);
304
305 return ret;
306}
307
308static unsigned int ls_scope(const char *path, struct dir_elem_t *de)
309{
310 if (vfs_stat_path(path, &de->s) != EOK) {
311 cli_error(CL_ENOENT, "%s", path);
312 return LS_BOGUS;
313 }
314
315 if (de->s.is_file)
316 return LS_FILE;
317 else if (de->s.is_directory)
318 return LS_DIR;
319
320 return LS_BOGUS;
321}
322
323void help_cmd_ls(unsigned int level)
324{
325 if (level == HELP_SHORT) {
326 printf("`%s' lists files and directories.\n", cmdname);
327 } else {
328 help_cmd_ls(HELP_SHORT);
329 printf(
330 "Usage: %s [options] [path]\n"
331 "If not path is given, the current working directory is used.\n"
332 "Options:\n"
333 " -h, --help A short option summary\n"
334 " -u, --unsort Do not sort directory entries\n"
335 " -r, --recursive List subdirectories recursively\n",
336 cmdname);
337 }
338
339 return;
340}
341
342int cmd_ls(char **argv)
343{
344 unsigned int argc;
345 struct dir_elem_t de;
346 DIR *dirp;
347 int c, opt_ind;
348 int ret = 0;
349 unsigned int scope;
350
351 if (!ls_start(&ls)) {
352 cli_error(CL_EFAIL, "%s: Could not initialize", cmdname);
353 return CMD_FAILURE;
354 }
355
356 argc = cli_count_args(argv);
357
358 for (c = 0, optreset = 1, optind = 0, opt_ind = 0; c != -1;) {
359 c = getopt_long(argc, argv, "hur", long_options, &opt_ind);
360 switch (c) {
361 case 'h':
362 help_cmd_ls(HELP_LONG);
363 return CMD_SUCCESS;
364 case 'u':
365 ls.sort = 0;
366 break;
367 case 'r':
368 ls.recursive = 1;
369 break;
370 }
371 }
372
373 argc -= optind;
374
375 de.name = (char *) malloc(PATH_MAX);
376 if (!de.name) {
377 cli_error(CL_ENOMEM, "%s: Out of memory", cmdname);
378 return CMD_FAILURE;
379 }
380 memset(de.name, 0, PATH_MAX);
381
382 if (argc == 0) {
383 if (vfs_cwd_get(de.name, PATH_MAX) != EOK) {
384 cli_error(CL_EFAIL, "%s: Failed determining working "
385 "directory", cmdname);
386 return CMD_FAILURE;
387 }
388 } else {
389 str_cpy(de.name, PATH_MAX, argv[optind]);
390 }
391
392 scope = ls_scope(de.name, &de);
393 switch (scope) {
394 case LS_FILE:
395 ls_print(&de);
396 break;
397 case LS_DIR:
398 dirp = opendir(de.name);
399 if (!dirp) {
400 /* May have been deleted between scoping it and opening it */
401 cli_error(CL_EFAIL, "Could not stat %s", de.name);
402 free(de.name);
403 return CMD_FAILURE;
404 }
405 if (ls.recursive)
406 ret = ls_recursive(de.name, dirp);
407 else
408 ret = ls_scan_dir(de.name, dirp, NULL);
409
410 closedir(dirp);
411 break;
412 case LS_BOGUS:
413 return CMD_FAILURE;
414 }
415
416 free(de.name);
417
418 if (ret == -1 || ret == CMD_FAILURE)
419 return CMD_FAILURE;
420 else
421 return CMD_SUCCESS;
422}
423
Note: See TracBrowser for help on using the repository browser.