0eaf836527944ba69d499050ad080f919d3e57ef
[grub.git] / grub-core / commands / ls.c
1 /* ls.c - command to list files and devices */
2 /*
3  *  GRUB  --  GRand Unified Bootloader
4  *  Copyright (C) 2003,2005,2007,2008,2009  Free Software Foundation, Inc.
5  *
6  *  GRUB is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  GRUB is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <grub/types.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/err.h>
24 #include <grub/dl.h>
25 #include <grub/disk.h>
26 #include <grub/device.h>
27 #include <grub/term.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
30 #include <grub/normal.h>
31 #include <grub/extcmd.h>
32 #include <grub/datetime.h>
33 #include <grub/i18n.h>
34 #include <grub/net.h>
35
36 GRUB_MOD_LICENSE ("GPLv3+");
37
38 static const struct grub_arg_option options[] =
39   {
40     {"long", 'l', 0, N_("Show a long list with more detailed information."), 0, 0},
41     {"human-readable", 'h', 0, N_("Print sizes in a human readable format."), 0, 0},
42     {"all", 'a', 0, N_("List all files."), 0, 0},
43     {0, 0, 0, 0, 0, 0}
44   };
45
46 /* Helper for grub_ls_list_devices.  */
47 static int
48 grub_ls_print_devices (const char *name, void *data)
49 {
50   int *longlist = data;
51
52   if (*longlist)
53     grub_normal_print_device_info (name);
54   else
55     grub_printf ("(%s) ", name);
56
57   return 0;
58 }
59
60 static grub_err_t
61 grub_ls_list_devices (int longlist)
62 {
63   grub_device_iterate (grub_ls_print_devices, &longlist);
64   grub_xputs ("\n");
65
66 #if 0
67   {
68     grub_net_app_level_t proto;
69     int first = 1;
70     FOR_NET_APP_LEVEL (proto)
71     {
72       if (first)
73         grub_puts_ (N_ ("Network protocols:"));
74       first = 0;
75       grub_printf ("%s ", proto->name);
76     }
77     grub_xputs ("\n");
78   }
79 #endif
80
81   grub_refresh ();
82
83   return 0;
84 }
85
86 /* Context for grub_ls_list_files.  */
87 struct grub_ls_list_files_ctx
88 {
89   char *dirname;
90   int all;
91   int human;
92 };
93
94 /* Helper for grub_ls_list_files.  */
95 static int
96 print_files (const char *filename, const struct grub_dirhook_info *info,
97              void *data)
98 {
99   struct grub_ls_list_files_ctx *ctx = data;
100
101   if (ctx->all || filename[0] != '.')
102     grub_printf ("%s%s ", filename, info->dir ? "/" : "");
103
104   return 0;
105 }
106
107 /* Helper for grub_ls_list_files.  */
108 static int
109 print_files_long (const char *filename, const struct grub_dirhook_info *info,
110                   void *data)
111 {
112   struct grub_ls_list_files_ctx *ctx = data;
113
114   if ((! ctx->all) && (filename[0] == '.'))
115     return 0;
116
117   if (! info->dir)
118     {
119       grub_file_t file;
120       char *pathname;
121
122       if (ctx->dirname[grub_strlen (ctx->dirname) - 1] == '/')
123         pathname = grub_xasprintf ("%s%s", ctx->dirname, filename);
124       else
125         pathname = grub_xasprintf ("%s/%s", ctx->dirname, filename);
126
127       if (!pathname)
128         return 1;
129
130       /* XXX: For ext2fs symlinks are detected as files while they
131          should be reported as directories.  */
132       grub_file_filter_disable_compression ();
133       file = grub_file_open (pathname);
134       if (! file)
135         {
136           grub_errno = 0;
137           grub_free (pathname);
138           return 0;
139         }
140
141       if (! ctx->human)
142         grub_printf ("%-12llu", (unsigned long long) file->size);
143       else
144         grub_printf ("%-12s", grub_get_human_size (file->size,
145                                                    GRUB_HUMAN_SIZE_SHORT));
146       grub_file_close (file);
147       grub_free (pathname);
148     }
149   else
150     grub_printf ("%-12s", _("DIR"));
151
152   if (info->mtimeset)
153     {
154       struct grub_datetime datetime;
155       grub_unixtime2datetime (info->mtime, &datetime);
156       if (ctx->human)
157         grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
158                      datetime.year, datetime.month, datetime.day,
159                      datetime.hour, datetime.minute,
160                      datetime.second,
161                      grub_get_weekday_name (&datetime));
162       else
163         grub_printf (" %04d%02d%02d%02d%02d%02d ",
164                      datetime.year, datetime.month,
165                      datetime.day, datetime.hour,
166                      datetime.minute, datetime.second);
167     }
168   grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
169
170   return 0;
171 }
172
173 static grub_err_t
174 grub_ls_list_files (char *dirname, int longlist, int all, int human)
175 {
176   char *device_name;
177   grub_fs_t fs;
178   const char *path;
179   grub_device_t dev;
180
181   device_name = grub_file_get_device_name (dirname);
182   dev = grub_device_open (device_name);
183   if (! dev)
184     goto fail;
185
186   fs = grub_fs_probe (dev);
187   path = grub_strchr (dirname, ')');
188   if (! path)
189     path = dirname;
190   else
191     path++;
192
193   if (! path && ! device_name)
194     {
195       grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
196       goto fail;
197     }
198
199   if (! *path)
200     {
201       if (grub_errno == GRUB_ERR_UNKNOWN_FS)
202         grub_errno = GRUB_ERR_NONE;
203
204       grub_normal_print_device_info (device_name);
205     }
206   else if (fs)
207     {
208       struct grub_ls_list_files_ctx ctx = {
209         .dirname = dirname,
210         .all = all,
211         .human = human
212       };
213
214       if (longlist)
215         (fs->dir) (dev, path, print_files_long, &ctx);
216       else
217         (fs->dir) (dev, path, print_files, &ctx);
218
219       if (grub_errno == GRUB_ERR_BAD_FILE_TYPE
220           && path[grub_strlen (path) - 1] != '/')
221         {
222           /* PATH might be a regular file.  */
223           char *p;
224           grub_file_t file;
225           struct grub_dirhook_info info;
226           grub_errno = 0;
227
228           grub_file_filter_disable_compression ();
229           file = grub_file_open (dirname);
230           if (! file)
231             goto fail;
232
233           grub_file_close (file);
234
235           p = grub_strrchr (dirname, '/') + 1;
236           dirname = grub_strndup (dirname, p - dirname);
237           if (! dirname)
238             goto fail;
239
240           all = 1;
241           grub_memset (&info, 0, sizeof (info));
242           if (longlist)
243             print_files_long (p, &info, &ctx);
244           else
245             print_files (p, &info, &ctx);
246
247           grub_free (dirname);
248         }
249
250       if (grub_errno == GRUB_ERR_NONE)
251         grub_xputs ("\n");
252
253       grub_refresh ();
254     }
255
256  fail:
257   if (dev)
258     grub_device_close (dev);
259
260   grub_free (device_name);
261
262   return 0;
263 }
264
265 static grub_err_t
266 grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args)
267 {
268   struct grub_arg_list *state = ctxt->state;
269   int i;
270
271   if (argc == 0)
272     grub_ls_list_devices (state[0].set);
273   else
274     for (i = 0; i < argc; i++)
275       grub_ls_list_files (args[i], state[0].set, state[2].set,
276                           state[1].set);
277
278   return 0;
279 }
280
281 static grub_extcmd_t cmd;
282
283 GRUB_MOD_INIT(ls)
284 {
285   cmd = grub_register_extcmd ("ls", grub_cmd_ls, 0,
286                               N_("[-l|-h|-a] [FILE ...]"),
287                               N_("List devices and files."), options);
288 }
289
290 GRUB_MOD_FINI(ls)
291 {
292   grub_unregister_extcmd (cmd);
293 }