]>
Commit | Line | Data |
---|---|---|
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 | ||
35 | static const struct grub_arg_option options[] = | |
36 | { | |
37 | {"long", 'l', 0, N_("Show a long list with more detailed information."), 0, 0}, | |
38 | {"human-readable", 'h', 0, N_("Print sizes in a human readable format."), 0, 0}, | |
39 | {"all", 'a', 0, N_("List all files."), 0, 0}, | |
40 | {0, 0, 0, 0, 0, 0} | |
41 | }; | |
42 | ||
43 | static const char grub_human_sizes[] = {' ', 'K', 'M', 'G', 'T'}; | |
44 | ||
45 | static grub_err_t | |
46 | grub_ls_list_devices (int longlist) | |
47 | { | |
48 | auto int grub_ls_print_devices (const char *name); | |
49 | int grub_ls_print_devices (const char *name) | |
50 | { | |
51 | if (longlist) | |
52 | grub_normal_print_device_info (name); | |
53 | else | |
54 | grub_printf ("(%s) ", name); | |
55 | ||
56 | return 0; | |
57 | } | |
58 | ||
59 | grub_device_iterate (grub_ls_print_devices); | |
60 | grub_xputs ("\n"); | |
61 | grub_refresh (); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static grub_err_t | |
67 | grub_ls_list_files (char *dirname, int longlist, int all, int human) | |
68 | { | |
69 | char *device_name; | |
70 | grub_fs_t fs; | |
71 | const char *path; | |
72 | grub_device_t dev; | |
73 | ||
74 | auto int print_files (const char *filename, | |
75 | const struct grub_dirhook_info *info); | |
76 | auto int print_files_long (const char *filename, | |
77 | const struct grub_dirhook_info *info); | |
78 | ||
79 | int print_files (const char *filename, const struct grub_dirhook_info *info) | |
80 | { | |
81 | if (all || filename[0] != '.') | |
82 | grub_printf ("%s%s ", filename, info->dir ? "/" : ""); | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | int print_files_long (const char *filename, | |
88 | const struct grub_dirhook_info *info) | |
89 | { | |
90 | if ((! all) && (filename[0] == '.')) | |
91 | return 0; | |
92 | ||
93 | if (! info->dir) | |
94 | { | |
95 | grub_file_t file; | |
96 | char *pathname; | |
97 | ||
98 | if (dirname[grub_strlen (dirname) - 1] == '/') | |
99 | pathname = grub_xasprintf ("%s%s", dirname, filename); | |
100 | else | |
101 | pathname = grub_xasprintf ("%s/%s", dirname, filename); | |
102 | ||
103 | if (!pathname) | |
104 | return 1; | |
105 | ||
106 | /* XXX: For ext2fs symlinks are detected as files while they | |
107 | should be reported as directories. */ | |
108 | grub_file_filter_disable_compression (); | |
109 | file = grub_file_open (pathname); | |
110 | if (! file) | |
111 | { | |
112 | grub_errno = 0; | |
113 | grub_free (pathname); | |
114 | return 0; | |
115 | } | |
116 | ||
117 | if (! human) | |
118 | grub_printf ("%-12llu", (unsigned long long) file->size); | |
119 | else | |
120 | { | |
121 | grub_uint64_t fsize = file->size * 100ULL; | |
122 | int fsz = file->size; | |
123 | int units = 0; | |
124 | char buf[20]; | |
125 | ||
126 | while (fsz / 1024) | |
127 | { | |
128 | fsize = (fsize + 512) / 1024; | |
129 | fsz /= 1024; | |
130 | units++; | |
131 | } | |
132 | ||
133 | if (units) | |
134 | { | |
135 | grub_uint32_t whole, fraction; | |
136 | ||
137 | whole = grub_divmod64 (fsize, 100, &fraction); | |
138 | grub_snprintf (buf, sizeof (buf), | |
139 | "%u.%02u%c", whole, fraction, | |
140 | grub_human_sizes[units]); | |
141 | grub_printf ("%-12s", buf); | |
142 | } | |
143 | else | |
144 | grub_printf ("%-12llu", (unsigned long long) file->size); | |
145 | ||
146 | } | |
147 | grub_file_close (file); | |
148 | grub_free (pathname); | |
149 | } | |
150 | else | |
151 | grub_printf ("%-12s", "DIR"); | |
152 | ||
153 | if (info->mtimeset) | |
154 | { | |
155 | struct grub_datetime datetime; | |
156 | grub_unixtime2datetime (info->mtime, &datetime); | |
157 | if (human) | |
158 | grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ", | |
159 | datetime.year, datetime.month, datetime.day, | |
160 | datetime.hour, datetime.minute, | |
161 | datetime.second, | |
162 | grub_get_weekday_name (&datetime)); | |
163 | else | |
164 | grub_printf (" %04d%02d%02d%02d%02d%02d ", | |
165 | datetime.year, datetime.month, | |
166 | datetime.day, datetime.hour, | |
167 | datetime.minute, datetime.second); | |
168 | } | |
169 | grub_printf ("%s%s\n", filename, info->dir ? "/" : ""); | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | device_name = grub_file_get_device_name (dirname); | |
175 | dev = grub_device_open (device_name); | |
176 | if (! dev) | |
177 | goto fail; | |
178 | ||
179 | fs = grub_fs_probe (dev); | |
180 | path = grub_strchr (dirname, ')'); | |
181 | if (! path) | |
182 | path = dirname; | |
183 | else | |
184 | path++; | |
185 | ||
186 | if (! path && ! device_name) | |
187 | { | |
188 | grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); | |
189 | goto fail; | |
190 | } | |
191 | ||
192 | if (! *path) | |
193 | { | |
194 | if (grub_errno == GRUB_ERR_UNKNOWN_FS) | |
195 | grub_errno = GRUB_ERR_NONE; | |
196 | ||
197 | grub_normal_print_device_info (device_name); | |
198 | } | |
199 | else if (fs) | |
200 | { | |
201 | if (longlist) | |
202 | (fs->dir) (dev, path, print_files_long); | |
203 | else | |
204 | (fs->dir) (dev, path, print_files); | |
205 | ||
206 | if (grub_errno == GRUB_ERR_BAD_FILE_TYPE | |
207 | && path[grub_strlen (path) - 1] != '/') | |
208 | { | |
209 | /* PATH might be a regular file. */ | |
210 | char *p; | |
211 | grub_file_t file; | |
212 | struct grub_dirhook_info info; | |
213 | grub_errno = 0; | |
214 | ||
215 | grub_file_filter_disable_compression (); | |
216 | file = grub_file_open (dirname); | |
217 | if (! file) | |
218 | goto fail; | |
219 | ||
220 | grub_file_close (file); | |
221 | ||
222 | p = grub_strrchr (dirname, '/') + 1; | |
223 | dirname = grub_strndup (dirname, p - dirname); | |
224 | if (! dirname) | |
225 | goto fail; | |
226 | ||
227 | all = 1; | |
228 | grub_memset (&info, 0, sizeof (info)); | |
229 | if (longlist) | |
230 | print_files_long (p, &info); | |
231 | else | |
232 | print_files (p, &info); | |
233 | ||
234 | grub_free (dirname); | |
235 | } | |
236 | ||
237 | if (grub_errno == GRUB_ERR_NONE) | |
238 | grub_xputs ("\n"); | |
239 | ||
240 | grub_refresh (); | |
241 | } | |
242 | ||
243 | fail: | |
244 | if (dev) | |
245 | grub_device_close (dev); | |
246 | ||
247 | grub_free (device_name); | |
248 | ||
249 | return 0; | |
250 | } | |
251 | ||
252 | static grub_err_t | |
253 | grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args) | |
254 | { | |
255 | struct grub_arg_list *state = ctxt->state; | |
256 | int i; | |
257 | ||
258 | if (argc == 0) | |
259 | grub_ls_list_devices (state[0].set); | |
260 | else | |
261 | for (i = 0; i < argc; i++) | |
262 | grub_ls_list_files (args[i], state[0].set, state[2].set, | |
263 | state[1].set); | |
264 | ||
265 | return 0; | |
266 | } | |
267 | ||
268 | static grub_extcmd_t cmd; | |
269 | ||
270 | GRUB_MOD_INIT(ls) | |
271 | { | |
272 | cmd = grub_register_extcmd ("ls", grub_cmd_ls, GRUB_COMMAND_FLAG_BOTH, | |
273 | N_("[-l|-h|-a] [FILE]"), | |
274 | N_("List devices and files."), options); | |
275 | } | |
276 | ||
277 | GRUB_MOD_FINI(ls) | |
278 | { | |
279 | grub_unregister_extcmd (cmd); | |
280 | } |