]>
Commit | Line | Data |
---|---|---|
db1771cf | 1 | /* ls.c - command to list files and devices */ |
2 | /* | |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
f36cc108 | 4 | * Copyright (C) 2003,2005,2007,2008 Free Software Foundation, Inc. |
db1771cf | 5 | * |
5a79f472 | 6 | * GRUB is free software: you can redistribute it and/or modify |
db1771cf | 7 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 8 | * the Free Software Foundation, either version 3 of the License, or |
db1771cf | 9 | * (at your option) any later version. |
10 | * | |
5a79f472 | 11 | * GRUB is distributed in the hope that it will be useful, |
db1771cf | 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 | |
5a79f472 | 17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
db1771cf | 18 | */ |
19 | ||
4b13b216 | 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> | |
4b13b216 | 25 | #include <grub/disk.h> |
26 | #include <grub/device.h> | |
27 | #include <grub/term.h> | |
3f1578fe | 28 | #include <grub/partition.h> |
4b13b216 | 29 | #include <grub/file.h> |
b1b797cb | 30 | #include <grub/normal.h> |
31 | #include <grub/extcmd.h> | |
05aaebfb | 32 | #include <grub/datetime.h> |
db1771cf | 33 | |
4b13b216 | 34 | static const struct grub_arg_option options[] = |
db1771cf | 35 | { |
502c87e8 | 36 | {"long", 'l', 0, "show a long list with more detailed information", 0, 0}, |
37 | {"human-readable", 'h', 0, "print sizes in a human readable format", 0, 0}, | |
38 | {"all", 'a', 0, "list all files", 0, 0}, | |
db1771cf | 39 | {0, 0, 0, 0, 0, 0} |
40 | }; | |
41 | ||
4b13b216 | 42 | static const char grub_human_sizes[] = {' ', 'K', 'M', 'G', 'T'}; |
db1771cf | 43 | |
4b13b216 | 44 | static grub_err_t |
6a85ce79 | 45 | grub_ls_list_devices (int longlist) |
db1771cf | 46 | { |
6a85ce79 | 47 | auto int grub_ls_print_devices (const char *name); |
48 | int grub_ls_print_devices (const char *name) | |
db1771cf | 49 | { |
6a85ce79 | 50 | if (longlist) |
51 | grub_normal_print_device_info (name); | |
52 | else | |
53 | grub_printf ("(%s) ", name); | |
db1771cf | 54 | |
55 | return 0; | |
56 | } | |
57 | ||
6a85ce79 | 58 | grub_device_iterate (grub_ls_print_devices); |
4b13b216 | 59 | grub_putchar ('\n'); |
60 | grub_refresh (); | |
db1771cf | 61 | |
db1771cf | 62 | return 0; |
63 | } | |
64 | ||
4b13b216 | 65 | static grub_err_t |
5f968e1e | 66 | grub_ls_list_files (char *dirname, int longlist, int all, int human) |
db1771cf | 67 | { |
68 | char *device_name; | |
4b13b216 | 69 | grub_fs_t fs; |
8a572cd7 | 70 | const char *path; |
4b13b216 | 71 | grub_device_t dev; |
05aaebfb | 72 | |
73 | auto int print_files (const char *filename, | |
74 | const struct grub_dirhook_info *info); | |
75 | auto int print_files_long (const char *filename, | |
76 | const struct grub_dirhook_info *info); | |
5f968e1e | 77 | |
05aaebfb | 78 | int print_files (const char *filename, const struct grub_dirhook_info *info) |
db1771cf | 79 | { |
80 | if (all || filename[0] != '.') | |
05aaebfb | 81 | grub_printf ("%s%s ", filename, info->dir ? "/" : ""); |
db1771cf | 82 | |
83 | return 0; | |
84 | } | |
85 | ||
05aaebfb | 86 | int print_files_long (const char *filename, |
87 | const struct grub_dirhook_info *info) | |
db1771cf | 88 | { |
4b13b216 | 89 | char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1]; |
db1771cf | 90 | |
91 | if ((! all) && (filename[0] == '.')) | |
92 | return 0; | |
93 | ||
05aaebfb | 94 | if (! info->dir) |
db1771cf | 95 | { |
4b13b216 | 96 | grub_file_t file; |
db1771cf | 97 | |
4b13b216 | 98 | if (dirname[grub_strlen (dirname) - 1] == '/') |
99 | grub_sprintf (pathname, "%s%s", dirname, filename); | |
db1771cf | 100 | else |
4b13b216 | 101 | grub_sprintf (pathname, "%s/%s", dirname, filename); |
db1771cf | 102 | |
103 | /* XXX: For ext2fs symlinks are detected as files while they | |
104 | should be reported as directories. */ | |
4b13b216 | 105 | file = grub_file_open (pathname); |
db1771cf | 106 | if (! file) |
107 | { | |
4b13b216 | 108 | grub_errno = 0; |
db1771cf | 109 | return 0; |
110 | } | |
111 | ||
112 | if (! human) | |
d687651c | 113 | grub_printf ("%-12llu", (unsigned long long) file->size); |
db1771cf | 114 | else |
115 | { | |
95614c84 | 116 | grub_uint64_t fsize = file->size * 100ULL; |
db1771cf | 117 | int fsz = file->size; |
118 | int units = 0; | |
119 | char buf[20]; | |
120 | ||
121 | while (fsz / 1024) | |
122 | { | |
95614c84 | 123 | fsize = (fsize + 512) / 1024; |
db1771cf | 124 | fsz /= 1024; |
125 | units++; | |
126 | } | |
127 | ||
128 | if (units) | |
129 | { | |
95614c84 | 130 | grub_uint32_t whole, fraction; |
131 | ||
132 | whole = grub_divmod64 (fsize, 100, &fraction); | |
133 | grub_sprintf (buf, "%u.%02u%c", whole, fraction, | |
134 | grub_human_sizes[units]); | |
4b13b216 | 135 | grub_printf ("%-12s", buf); |
db1771cf | 136 | } |
137 | else | |
d687651c | 138 | grub_printf ("%-12llu", (unsigned long long) file->size); |
db1771cf | 139 | |
140 | } | |
25fe6f03 | 141 | grub_file_close (file); |
b1b797cb | 142 | } |
db1771cf | 143 | else |
4b13b216 | 144 | grub_printf ("%-12s", "DIR"); |
db1771cf | 145 | |
05aaebfb | 146 | if (info->mtimeset) |
147 | { | |
148 | struct grub_datetime datetime; | |
149 | grub_unixtime2datetime (info->mtime, &datetime); | |
150 | if (human) | |
151 | grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ", | |
152 | datetime.year, datetime.month, datetime.day, | |
153 | datetime.hour, datetime.minute, | |
154 | datetime.second, | |
155 | grub_get_weekday_name (&datetime)); | |
156 | else | |
157 | grub_printf (" %04d%02d%02d%02d%02d%02d ", | |
158 | datetime.year, datetime.month, | |
159 | datetime.day, datetime.hour, | |
160 | datetime.minute, datetime.second); | |
161 | } | |
162 | grub_printf ("%s%s\n", filename, info->dir ? "/" : ""); | |
db1771cf | 163 | |
164 | return 0; | |
165 | } | |
166 | ||
4b13b216 | 167 | device_name = grub_file_get_device_name (dirname); |
168 | dev = grub_device_open (device_name); | |
db1771cf | 169 | if (! dev) |
170 | goto fail; | |
171 | ||
4b13b216 | 172 | fs = grub_fs_probe (dev); |
8a572cd7 | 173 | path = grub_strchr (dirname, ')'); |
174 | if (! path) | |
175 | path = dirname; | |
176 | else | |
177 | path++; | |
178 | ||
db1771cf | 179 | if (! path && ! device_name) |
180 | { | |
4b13b216 | 181 | grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); |
db1771cf | 182 | goto fail; |
183 | } | |
184 | ||
7224189a | 185 | if (! *path) |
db1771cf | 186 | { |
4b13b216 | 187 | if (grub_errno == GRUB_ERR_UNKNOWN_FS) |
188 | grub_errno = GRUB_ERR_NONE; | |
992ffbbe | 189 | |
190 | grub_normal_print_device_info (device_name); | |
db1771cf | 191 | } |
192 | else if (fs) | |
193 | { | |
194 | if (longlist) | |
195 | (fs->dir) (dev, path, print_files_long); | |
196 | else | |
197 | (fs->dir) (dev, path, print_files); | |
5f968e1e | 198 | |
199 | if (grub_errno == GRUB_ERR_BAD_FILE_TYPE | |
200 | && path[grub_strlen (path) - 1] != '/') | |
201 | { | |
202 | /* PATH might be a regular file. */ | |
203 | char *p; | |
204 | grub_file_t file; | |
05aaebfb | 205 | struct grub_dirhook_info info; |
5f968e1e | 206 | grub_errno = 0; |
207 | ||
208 | file = grub_file_open (dirname); | |
209 | if (! file) | |
210 | goto fail; | |
211 | ||
212 | grub_file_close (file); | |
213 | ||
214 | p = grub_strrchr (dirname, '/') + 1; | |
215 | dirname = grub_strndup (dirname, p - dirname); | |
216 | if (! dirname) | |
217 | goto fail; | |
218 | ||
219 | all = 1; | |
05aaebfb | 220 | grub_memset (&info, 0, sizeof (info)); |
5f968e1e | 221 | if (longlist) |
05aaebfb | 222 | print_files_long (p, &info); |
5f968e1e | 223 | else |
05aaebfb | 224 | print_files (p, &info); |
5f968e1e | 225 | |
226 | grub_free (dirname); | |
227 | } | |
228 | ||
229 | if (grub_errno == GRUB_ERR_NONE) | |
230 | grub_putchar ('\n'); | |
231 | ||
4b13b216 | 232 | grub_refresh (); |
db1771cf | 233 | } |
234 | ||
235 | fail: | |
236 | if (dev) | |
4b13b216 | 237 | grub_device_close (dev); |
db1771cf | 238 | |
4b13b216 | 239 | grub_free (device_name); |
db1771cf | 240 | |
241 | return 0; | |
242 | } | |
243 | ||
4b13b216 | 244 | static grub_err_t |
b1b797cb | 245 | grub_cmd_ls (grub_extcmd_t cmd, int argc, char **args) |
db1771cf | 246 | { |
b1b797cb | 247 | struct grub_arg_list *state = cmd->state; |
248 | ||
db1771cf | 249 | if (argc == 0) |
6a85ce79 | 250 | grub_ls_list_devices (state[0].set); |
db1771cf | 251 | else |
4b13b216 | 252 | grub_ls_list_files (args[0], state[0].set, state[2].set, |
db1771cf | 253 | state[1].set); |
254 | ||
255 | return 0; | |
256 | } | |
257 | ||
b1b797cb | 258 | static grub_extcmd_t cmd; |
259 | ||
6d099807 | 260 | GRUB_MOD_INIT(ls) |
db1771cf | 261 | { |
262 | (void)mod; /* To stop warning. */ | |
b1b797cb | 263 | cmd = grub_register_extcmd ("ls", grub_cmd_ls, GRUB_COMMAND_FLAG_BOTH, |
264 | "ls [-l|-h|-a] [FILE]", | |
265 | "List devices and files.", options); | |
db1771cf | 266 | } |
267 | ||
6d099807 | 268 | GRUB_MOD_FINI(ls) |
db1771cf | 269 | { |
b1b797cb | 270 | grub_unregister_extcmd (cmd); |
db1771cf | 271 | } |