/* ls.c - command to list files and devices */ /* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2003,2005,2007,2008,2009 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include VAS_EBOOT_MOD_LICENSE ("GPLv3+"); static const struct VasEBoot_arg_option options[] = { {"long", 'l', 0, N_("Show a long list with more detailed information."), 0, 0}, {"human-readable", 'h', 0, N_("Print sizes in a human readable format."), 0, 0}, {"all", 'a', 0, N_("List all files."), 0, 0}, {0, 0, 0, 0, 0, 0} }; /* Helper for VasEBoot_ls_list_devices. */ static int VasEBoot_ls_print_devices (const char *name, void *data) { int *longlist = data; if (*longlist) VasEBoot_normal_print_device_info (name); else VasEBoot_printf ("(%s) ", name); return 0; } static VasEBoot_err_t VasEBoot_ls_list_devices (int longlist) { VasEBoot_device_iterate (VasEBoot_ls_print_devices, &longlist); VasEBoot_xputs ("\n"); #if 0 { VasEBoot_net_app_level_t proto; int first = 1; FOR_NET_APP_LEVEL (proto) { if (first) VasEBoot_puts_ (N_("Network protocols:")); first = 0; VasEBoot_printf ("%s ", proto->name); } VasEBoot_xputs ("\n"); } #endif VasEBoot_refresh (); return 0; } /* Context for VasEBoot_ls_list_files. */ struct VasEBoot_ls_list_files_ctx { char *dirname; char *filename; int all; int human; int longlist; int print_dirhdr; }; /* Helper for VasEBoot_ls_list_files. */ static int print_file (const char *filename, const struct VasEBoot_dirhook_info *info, void *data) { char *pathname = NULL; struct VasEBoot_ls_list_files_ctx *ctx = data; if ((! ctx->all) && (filename[0] == '.')) return 0; if ((ctx->filename != NULL) && (VasEBoot_strcmp (filename, ctx->filename) != 0)) return 0; if (ctx->print_dirhdr) { VasEBoot_printf ("%s:\n", ctx->dirname); ctx->print_dirhdr = 0; } if (! ctx->longlist) { if (ctx->filename != NULL) VasEBoot_xputs (ctx->dirname); VasEBoot_printf ("%s%s ", filename, info->dir ? "/" : ""); return 0; } if (! info->dir) { VasEBoot_file_t file; if (ctx->dirname[VasEBoot_strlen (ctx->dirname) - 1] == '/') pathname = VasEBoot_xasprintf ("%s%s", ctx->dirname, filename); else pathname = VasEBoot_xasprintf ("%s/%s", ctx->dirname, filename); if (!pathname) return 1; /* XXX: For ext2fs symlinks are detected as files while they should be reported as directories. */ file = VasEBoot_file_open (pathname, VAS_EBOOT_FILE_TYPE_GET_SIZE | VAS_EBOOT_FILE_TYPE_NO_DECOMPRESS); if (file) { if (! ctx->human) VasEBoot_printf ("%-12llu", (unsigned long long) file->size); else VasEBoot_printf ("%-12s", VasEBoot_get_human_size (file->size, VAS_EBOOT_HUMAN_SIZE_SHORT)); VasEBoot_file_close (file); } else VasEBoot_xputs ("????????????"); VasEBoot_errno = VAS_EBOOT_ERR_NONE; } else VasEBoot_printf ("%-12s", _("DIR")); if (info->mtimeset) { struct VasEBoot_datetime datetime; VasEBoot_unixtime2datetime (info->mtime, &datetime); if (ctx->human) VasEBoot_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ", datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, VasEBoot_get_weekday_name (&datetime)); else VasEBoot_printf (" %04d%02d%02d%02d%02d%02d ", datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second); } /* * Only print the full path when listing a file path given as an argument * to ls, i.e. when ctx->filename != NULL. File listings that are printed * due to showing the contents of a directory do not need a full path because * the full path to the directory will have already been printed. */ VasEBoot_printf ("%s%s\n", (ctx->filename != NULL) ? pathname : filename, info->dir ? "/" : ""); VasEBoot_free (pathname); return 0; } static VasEBoot_err_t VasEBoot_ls_list_files (char *dirname, int longlist, int all, int human, int dirhdr) { char *device_name; VasEBoot_fs_t fs; const char *path; VasEBoot_device_t dev; device_name = VasEBoot_file_get_device_name (dirname); dev = VasEBoot_device_open (device_name); if (! dev) goto fail; fs = VasEBoot_fs_probe (dev); path = VasEBoot_strchr (dirname, ')'); if (! path) path = dirname; else path++; if (! path && ! device_name) { VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, "invalid argument"); goto fail; } if (! *path && device_name) { if (VasEBoot_errno == VAS_EBOOT_ERR_UNKNOWN_FS) VasEBoot_errno = VAS_EBOOT_ERR_NONE; #ifdef VAS_EBOOT_MACHINE_IEEE1275 /* * Close device to prevent a double open in VasEBoot_normal_print_device_info(). * Otherwise it may lead to hangs on some IEEE 1275 platforms. */ VasEBoot_device_close (dev); dev = NULL; #endif VasEBoot_normal_print_device_info (device_name); } else if (fs) { struct VasEBoot_ls_list_files_ctx ctx = { .dirname = dirname, .filename = NULL, .all = all, .human = human, .longlist = longlist, .print_dirhdr = dirhdr }; (fs->fs_dir) (dev, path, print_file, &ctx); if (VasEBoot_errno == VAS_EBOOT_ERR_BAD_FILE_TYPE && path[VasEBoot_strlen (path) - 1] != '/') { /* * Reset errno as it is currently set, but will cause subsequent code * to think there is an error. */ VasEBoot_errno = VAS_EBOOT_ERR_NONE; /* PATH might be a regular file. */ ctx.print_dirhdr = 0; ctx.filename = VasEBoot_strrchr (dirname, '/'); if (ctx.filename == NULL) goto fail; ++(ctx.filename); ctx.dirname = VasEBoot_strndup (dirname, ctx.filename - dirname); if (ctx.dirname == NULL) goto fail; (fs->fs_dir) (dev, ctx.dirname + (path - dirname), print_file, &ctx); VasEBoot_free (ctx.dirname); } if (VasEBoot_errno == VAS_EBOOT_ERR_NONE) VasEBoot_xputs ("\n"); VasEBoot_refresh (); } fail: if (dev) VasEBoot_device_close (dev); VasEBoot_free (device_name); return VAS_EBOOT_ERR_NONE; } static VasEBoot_err_t VasEBoot_cmd_ls (VasEBoot_extcmd_context_t ctxt, int argc, char **args) { struct VasEBoot_arg_list *state = ctxt->state; int i; if (argc == 0) VasEBoot_ls_list_devices (state[0].set); else for (i = 0; i < argc; i++) VasEBoot_ls_list_files (args[i], state[0].set, state[2].set, state[1].set, argc > 1); return VAS_EBOOT_ERR_NONE; } static VasEBoot_extcmd_t cmd; VAS_EBOOT_MOD_INIT(ls) { cmd = VasEBoot_register_extcmd ("ls", VasEBoot_cmd_ls, 0, N_("[-l|-h|-a] [FILE ...]"), N_("List devices and files."), options); } VAS_EBOOT_MOD_FINI(ls) { VasEBoot_unregister_extcmd (cmd); }