source: mainline/uspace/app/bdsh/cmds/modules/ls/ls.c@ 72fda53

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 72fda53 was a701812, checked in by Jakub Jermar <jakub@…>, 14 years ago

Use str_size() instead of str_length() in ls.

  • Property mode set to 100644
File size: 6.9 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 <stdio.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <dirent.h>
37#include <fcntl.h>
38#include <getopt.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <str.h>
42#include <sort.h>
43
44#include "errors.h"
45#include "config.h"
46#include "util.h"
47#include "entry.h"
48#include "cmds.h"
49
50/* Various values that can be returned by ls_scope() */
51#define LS_BOGUS 0
52#define LS_FILE 1
53#define LS_DIR 2
54
55/** Structure to represent a directory entry.
56 *
57 * Useful to keep together important information
58 * for sorting directory entries.
59 */
60struct dir_elem_t {
61 char *name;
62 struct stat s;
63};
64
65static const char *cmdname = "ls";
66
67static struct option const long_options[] = {
68 { "help", no_argument, 0, 'h' },
69 { "unsort", no_argument, 0, 'u' },
70 { 0, 0, 0, 0 }
71};
72
73/** Print an entry.
74 *
75 * ls_print currently does nothing more than print the entry.
76 * In the future, we will likely pass the absolute path, and
77 * some sort of ls_options structure that controls how each
78 * entry is printed and what is printed about it.
79 *
80 * Now we just print basic DOS style lists.
81 *
82 * @param de Directory element.
83 */
84static void ls_print(struct dir_elem_t *de)
85{
86 if (de->s.is_file)
87 printf("%-40s\t%llu\n", de->name, (long long) de->s.size);
88 else if (de->s.is_directory)
89 printf("%-40s\t<dir>\n", de->name);
90 else
91 printf("%-40s\n", de->name);
92}
93
94
95/** Compare 2 directory elements.
96 *
97 * It compares 2 elements of a directory : a file is considered
98 * as bigger than a directory, and if they have the same type,
99 * they are compared alphabetically.
100 *
101 * @param a Pointer to the structure of the first element.
102 * @param b Pointer to the structure of the second element.
103 * @param arg Pointer for an other and optionnal argument.
104 *
105 * @return -1 if a < b, 1 otherwise.
106 */
107static int ls_cmp(void *a, void *b, void *arg)
108{
109 struct dir_elem_t *da = a;
110 struct dir_elem_t *db = b;
111
112 if ((da->s.is_directory && db->s.is_file) ||
113 ((da->s.is_directory == db->s.is_directory) &&
114 str_cmp(da->name, db->name) < 0))
115 return -1;
116 else
117 return 1;
118}
119
120/** Scan a directory.
121 *
122 * Scan the content of a directory and print it.
123 *
124 * @param d Name of the directory.
125 * @param dirp Directory stream.
126 * @param sort 1 if the output must be sorted,
127 * 0 otherwise.
128 */
129static void ls_scan_dir(const char *d, DIR *dirp, int sort)
130{
131 int alloc_blocks = 20;
132 int i;
133 int nbdirs = 0;
134 int rc;
135 int len;
136 char *buff;
137 struct dir_elem_t *tmp;
138 struct dir_elem_t *tosort;
139 struct dirent *dp;
140
141 if (!dirp)
142 return;
143
144 buff = (char *) malloc(PATH_MAX);
145 if (!buff) {
146 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
147 return;
148 }
149
150 tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
151 if (!tosort) {
152 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
153 free(buff);
154 return;
155 }
156
157 while ((dp = readdir(dirp))) {
158 if (nbdirs + 1 > alloc_blocks) {
159 alloc_blocks += alloc_blocks;
160
161 tmp = (struct dir_elem_t *) realloc(tosort,
162 alloc_blocks * sizeof(struct dir_elem_t));
163 if (!tmp) {
164 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
165 goto out;
166 }
167 tosort = tmp;
168 }
169
170 /* fill the name field */
171 tosort[nbdirs].name = (char *) malloc(str_size(dp->d_name) + 1);
172 if (!tosort[nbdirs].name) {
173 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
174 goto out;
175 }
176
177 str_cpy(tosort[nbdirs].name, str_size(dp->d_name) + 1, dp->d_name);
178 len = snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs].name);
179 buff[len] = '\0';
180
181 rc = stat(buff, &tosort[nbdirs++].s);
182 if (rc != 0) {
183 printf("ls: skipping bogus node %s\n", buff);
184 printf("rc=%d\n", rc);
185 goto out;
186 }
187 }
188
189 if (sort) {
190 if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t),
191 ls_cmp, NULL)) {
192 printf("Sorting error.\n");
193 }
194 }
195
196 for (i = 0; i < nbdirs; i++)
197 ls_print(&tosort[i]);
198
199out:
200 for(i = 0; i < nbdirs; i++)
201 free(tosort[i].name);
202 free(tosort);
203 free(buff);
204}
205
206void help_cmd_ls(unsigned int level)
207{
208 if (level == HELP_SHORT) {
209 printf("`%s' lists files and directories.\n", cmdname);
210 } else {
211 help_cmd_ls(HELP_SHORT);
212 printf(
213 "Usage: %s [options] [path]\n"
214 "If not path is given, the current working directory is used.\n"
215 "Options:\n"
216 " -h, --help A short option summary\n"
217 " -u, --unsort Do not sort directory entries\n",
218 cmdname);
219 }
220
221 return;
222}
223
224int cmd_ls(char **argv)
225{
226 unsigned int argc;
227 struct dir_elem_t de;
228 DIR *dirp;
229 int c, opt_ind;
230 int sort = 1;
231
232 argc = cli_count_args(argv);
233
234 for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
235 c = getopt_long(argc, argv, "hu", long_options, &opt_ind);
236 switch (c) {
237 case 'h':
238 help_cmd_ls(HELP_LONG);
239 return CMD_SUCCESS;
240 case 'u':
241 sort = 0;
242 break;
243 }
244 }
245
246 argc -= optind;
247
248 de.name = (char *) malloc(PATH_MAX);
249 if (!de.name) {
250 cli_error(CL_ENOMEM, "%s: ", cmdname);
251 return CMD_FAILURE;
252 }
253 memset(de.name, 0, sizeof(PATH_MAX));
254
255 if (argc == 0)
256 getcwd(de.name, PATH_MAX);
257 else
258 str_cpy(de.name, PATH_MAX, argv[optind]);
259
260 if (stat(de.name, &de.s)) {
261 cli_error(CL_ENOENT, de.name);
262 free(de.name);
263 return CMD_FAILURE;
264 }
265
266 if (de.s.is_file) {
267 ls_print(&de);
268 } else {
269 dirp = opendir(de.name);
270 if (!dirp) {
271 /* May have been deleted between scoping it and opening it */
272 cli_error(CL_EFAIL, "Could not stat %s", de.name);
273 free(de.name);
274 return CMD_FAILURE;
275 }
276 ls_scan_dir(de.name, dirp, sort);
277 closedir(dirp);
278 }
279
280 free(de.name);
281
282 return CMD_SUCCESS;
283}
284
Note: See TracBrowser for help on using the repository browser.