diff --git a/librz/core/cmd/cmd_shell.c b/librz/core/cmd/cmd_shell.c index cffcc6fb9b..e55e1c5854 100644 --- a/librz/core/cmd/cmd_shell.c +++ b/librz/core/cmd/cmd_shell.c @@ -3,6 +3,234 @@ #include +#define FMT_NONE 0 +#define FMT_RAW 1 +#define FMT_JSON 2 + +static char *showfile(char *res, const int nth, const char *fpath, const char *name, int printfmt) { + static int needs_newline = 0; +#if __UNIX__ + struct stat sb; +#endif + const char *n = fpath; + char *nn, *u_rwx = NULL; + int sz = rz_file_size(n); + int perm, uid = 0, gid = 0; + int fch = '-'; + if (!strncmp(fpath, "./", 2)) { + fpath = fpath + 2; + } + const bool isdir = rz_file_is_directory(n); + if (isdir) { + nn = rz_str_append(strdup(fpath), "/"); + } else { + nn = strdup(fpath); + } + if (!*nn) { + free(nn); + return res; + } + perm = isdir ? 0755 : 0644; + if (!printfmt) { + needs_newline = ((nth + 1) % 4) ? 1 : 0; + res = rz_str_appendf(res, "%18s%s", nn, needs_newline ? " " : "\n"); + free(nn); + return res; + } + // TODO: escape non-printable chars in filenames + // TODO: Implement more real info in ls -l + // TODO: handle suid +#if __UNIX__ + if (lstat(n, &sb) != -1) { + ut32 ifmt = sb.st_mode & S_IFMT; + uid = sb.st_uid; + gid = sb.st_gid; + perm = sb.st_mode & 0777; + if (!(u_rwx = strdup(rz_str_rwx_i(perm >> 6)))) { + free(nn); + return res; + } + if (sb.st_mode & S_ISUID) { + u_rwx[2] = (sb.st_mode & S_IXUSR) ? 's' : 'S'; + } + if (isdir) { + fch = 'd'; + } else { + switch (ifmt) { + case S_IFCHR: fch = 'c'; break; + case S_IFBLK: fch = 'b'; break; + case S_IFLNK: fch = 'l'; break; + case S_IFIFO: fch = 'p'; break; +#ifdef S_IFSOCK + case S_IFSOCK: fch = 's'; break; +#endif + } + } + } +#else + u_rwx = strdup("-"); + fch = isdir ? 'd' : '-'; +#endif + if (printfmt == 'q') { + res = rz_str_appendf(res, "%s\n", nn); + } else if (printfmt == 'e') { + const char *eDIR = "📁"; + const char *eIMG = "🌅"; + const char *eHID = "👀"; + const char *eANY = " "; + // -- + const char *icon = eANY; + if (isdir) { + icon = eDIR; +#if __UNIX__ + } else if ((sb.st_mode & S_IFMT) == S_IFLNK) { + const char *eLNK = "📎"; + icon = eLNK; + } else if (sb.st_mode & S_ISUID) { + const char *eUID = "🔼"; + icon = eUID; +#endif + } else if (rz_str_casestr(nn, ".jpg") || rz_str_casestr(nn, ".png") || rz_str_casestr(nn, ".gif")) { + icon = eIMG; + } else if (*nn == '.') { + icon = eHID; + } + res = rz_str_appendf(res, "%s %s\n", icon, nn); + } else if (printfmt == FMT_RAW) { + res = rz_str_appendf(res, "%c%s%s%s 1 %4d:%-4d %-10d %s\n", + isdir ? 'd' : fch, + u_rwx ? u_rwx : "-", + rz_str_rwx_i((perm >> 3) & 7), + rz_str_rwx_i(perm & 7), + uid, gid, sz, nn); + } else if (printfmt == FMT_JSON) { + if (nth > 0) { + res = rz_str_append(res, ","); + } + res = rz_str_appendf(res, "{\"name\":\"%s\",\"size\":%d,\"uid\":%d," + "\"gid\":%d,\"perm\":%d,\"isdir\":%s}", + name, sz, uid, gid, perm, isdir ? "true" : "false"); + } + free(nn); + free(u_rwx); + return res; +} + +static char *syscmd_ls(RZ_NONNULL const int argc, const char **argv) { + static int needs_newline = 0; + char *res = NULL; + const char *path = "."; + char *d = NULL; + char *p = NULL; + char *homepath = NULL; + char *pattern = NULL; + int printfmt = 0; + RzListIter *iter; + RzList *files; + char *name; + char *dir; + int off; + int path_in_second_arg = 0; + if (argc > 1) { + if ((!strncmp(argv[1], "-h", 2))) { + eprintf("Usage: ls ([-e,-l,-j,-q]) ([path]) # long, json, quiet\n"); + return NULL; + } else if ((!strncmp(argv[1], "-e", 2))) { + printfmt = 'e'; + } else if ((!strncmp(argv[1], "-q", 2))) { + printfmt = 'q'; + } else if ((!strncmp(argv[1], "-l", 2)) || (!strncmp(argv[1], "-j", 2))) { + printfmt = (argv[1][1] == 'j') ? FMT_JSON : FMT_RAW; + } else { + path = argv[1]; + path_in_second_arg = 1; + } + if (argc >= 3) { + if (!path_in_second_arg) { + path = argv[2]; + } + } + } + if (RZ_STR_ISEMPTY(path)) { + path = "."; + } else if (rz_str_startswith(path, "~")) { + homepath = rz_path_home_expand(path); + if (homepath) { + path = (const char *)homepath; + } + } else if (*path == '$') { + if (!strncmp(path + 1, "home", 4) || !strncmp(path + 1, "HOME", 4)) { + homepath = rz_str_home((strlen(path) > 5) ? path + 6 : NULL); + if (homepath) { + path = (const char *)homepath; + } + } + } + if (!rz_file_is_directory(path)) { + p = strrchr(path, '/'); + if (p) { + off = p - path; + d = (char *)calloc(1, off + 1); + if (!d) { + free(homepath); + return NULL; + } + memcpy(d, path, off); + path = (const char *)d; + pattern = strdup(p + 1); + } else { + pattern = strdup(path); + path = "."; + } + } else { + pattern = strdup("*"); + } + if (rz_file_is_regular(path)) { + res = showfile(res, 0, path, path, printfmt); + free(homepath); + free(pattern); + free(d); + return res; + } + files = rz_sys_dir(path); + + if (path[strlen(path) - 1] == '/') { + dir = strdup(path); + } else { + dir = rz_str_append(strdup(path), "/"); + } + int nth = 0; + if (printfmt == FMT_JSON) { + res = strdup("["); + } + needs_newline = 0; + rz_list_foreach (files, iter, name) { + char *n = rz_str_append(strdup(dir), name); + if (!n) { + break; + } + if (rz_str_glob(name, pattern)) { + if (*n) { + res = showfile(res, nth, n, name, printfmt); + } + nth++; + } + free(n); + } + if (printfmt == FMT_JSON) { + res = rz_str_append(res, "]"); + } + if (needs_newline) { + res = rz_str_append(res, "\n"); + } + free(dir); + free(d); + free(homepath); + free(pattern); + rz_list_free(files); + return res; +} + static const char *findBreakChar(const char *s) { while (*s) { if (!rz_name_validate_char(*s, true)) { @@ -111,9 +339,7 @@ RZ_IPI RzCmdStatus rz_cmd_shell_exit_handler(RzCore *core, int argc, const char // ls RZ_IPI RzCmdStatus rz_cmd_shell_ls_handler(RzCore *core, int argc, const char **argv) { - char *arg = rz_str_array_join(argv + 1, argc - 1, " "); - char *res = rz_syscmd_ls(arg); - free(arg); + char *res = syscmd_ls(argc, argv); if (!res) { return RZ_CMD_STATUS_ERROR; } diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index dd31d302a4..26deda7764 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -806,7 +806,7 @@ static const RzCmdDescArg yank_paste_args[2]; static const RzCmdDescArg yank_string_args[2]; static const RzCmdDescArg cmd_shell_diff_args[3]; static const RzCmdDescArg cmd_shell_env_args[3]; -static const RzCmdDescArg cmd_shell_ls_args[2]; +static const RzCmdDescArg cmd_shell_ls_args[6]; static const RzCmdDescArg cmd_shell_rm_args[2]; static const RzCmdDescArg cmd_shell_sleep_args[2]; static const RzCmdDescArg cmd_shell_uniq_args[2]; @@ -18003,9 +18003,36 @@ static const RzCmdDescHelp cmd_shell_exit_help = { static const RzCmdDescArg cmd_shell_ls_args[] = { { - .name = "arg", - .type = RZ_CMD_ARG_TYPE_STRING, - .flags = RZ_CMD_ARG_FLAG_ARRAY, + .name = "e", + .type = RZ_CMD_ARG_TYPE_OPTION, + .flags = RZ_CMD_ARG_FLAG_OPTION, + .optional = true, + + }, + { + .name = "q", + .type = RZ_CMD_ARG_TYPE_OPTION, + .flags = RZ_CMD_ARG_FLAG_OPTION, + .optional = true, + + }, + { + .name = "l", + .type = RZ_CMD_ARG_TYPE_OPTION, + .flags = RZ_CMD_ARG_FLAG_OPTION, + .optional = true, + + }, + { + .name = "j", + .type = RZ_CMD_ARG_TYPE_OPTION, + .flags = RZ_CMD_ARG_FLAG_OPTION, + .optional = true, + + }, + { + .name = "path", + .type = RZ_CMD_ARG_TYPE_FILE, .optional = true, }, @@ -18013,6 +18040,7 @@ static const RzCmdDescArg cmd_shell_ls_args[] = { }; static const RzCmdDescHelp cmd_shell_ls_help = { .summary = "List files and directories", + .args_str = " [-e -q -l -j] ", .args = cmd_shell_ls_args, }; diff --git a/librz/core/cmd_descs/cmd_shell.yaml b/librz/core/cmd_descs/cmd_shell.yaml index fd65c8af0e..293bfd1620 100644 --- a/librz/core/cmd_descs/cmd_shell.yaml +++ b/librz/core/cmd_descs/cmd_shell.yaml @@ -78,10 +78,26 @@ commands: - name: ls cname: cmd_shell_ls summary: List files and directories + args_str: " [-e -q -l -j] " args: - - name: arg - type: RZ_CMD_ARG_TYPE_STRING - flags: RZ_CMD_ARG_FLAG_ARRAY + - name: e + type: RZ_CMD_ARG_TYPE_OPTION + flags: RZ_CMD_ARG_FLAG_OPTION + optional: true + - name: q + type: RZ_CMD_ARG_TYPE_OPTION + flags: RZ_CMD_ARG_FLAG_OPTION + optional: true + - name: l + type: RZ_CMD_ARG_TYPE_OPTION + flags: RZ_CMD_ARG_FLAG_OPTION + optional: true + - name: j + type: RZ_CMD_ARG_TYPE_OPTION + flags: RZ_CMD_ARG_FLAG_OPTION + optional: true + - name: path + type: RZ_CMD_ARG_TYPE_FILE optional: true - name: rm cname: cmd_shell_rm diff --git a/librz/include/rz_util/rz_sys.h b/librz/include/rz_util/rz_sys.h index 7409757e44..885ed4aca9 100644 --- a/librz/include/rz_util/rz_sys.h +++ b/librz/include/rz_util/rz_sys.h @@ -194,7 +194,6 @@ RZ_API void rz_sys_backtrace(void); #endif /* syscmd */ -RZ_API RZ_OWN char *rz_syscmd_ls(RZ_NONNULL const char *input); RZ_API RZ_OWN char *rz_syscmd_cat(RZ_NONNULL const char *file); RZ_API RZ_OWN char *rz_syscmd_mkdir(RZ_NONNULL const char *dir); RZ_API RZ_OWN char *rz_syscmd_uniq(RZ_NONNULL const char *file); diff --git a/librz/util/syscmd.c b/librz/util/syscmd.c index 08326943ca..4bf69fb1ae 100644 --- a/librz/util/syscmd.c +++ b/librz/util/syscmd.c @@ -4,243 +4,6 @@ #include #include -#define FMT_NONE 0 -#define FMT_RAW 1 -#define FMT_JSON 2 - -static int needs_newline = 0; - -static char *showfile(char *res, const int nth, const char *fpath, const char *name, int printfmt) { -#if __UNIX__ - struct stat sb; -#endif - const char *n = fpath; - char *nn, *u_rwx = NULL; - int sz = rz_file_size(n); - int perm, uid = 0, gid = 0; - int fch = '-'; - if (!strncmp(fpath, "./", 2)) { - fpath = fpath + 2; - } - const bool isdir = rz_file_is_directory(n); - if (isdir) { - nn = rz_str_append(strdup(fpath), "/"); - } else { - nn = strdup(fpath); - } - if (!*nn) { - free(nn); - return res; - } - perm = isdir ? 0755 : 0644; - if (!printfmt) { - needs_newline = ((nth + 1) % 4) ? 1 : 0; - res = rz_str_appendf(res, "%18s%s", nn, needs_newline ? " " : "\n"); - free(nn); - return res; - } - // TODO: escape non-printable chars in filenames - // TODO: Implement more real info in ls -l - // TODO: handle suid -#if __UNIX__ - if (lstat(n, &sb) != -1) { - ut32 ifmt = sb.st_mode & S_IFMT; - uid = sb.st_uid; - gid = sb.st_gid; - perm = sb.st_mode & 0777; - if (!(u_rwx = strdup(rz_str_rwx_i(perm >> 6)))) { - free(nn); - return res; - } - if (sb.st_mode & S_ISUID) { - u_rwx[2] = (sb.st_mode & S_IXUSR) ? 's' : 'S'; - } - if (isdir) { - fch = 'd'; - } else { - switch (ifmt) { - case S_IFCHR: fch = 'c'; break; - case S_IFBLK: fch = 'b'; break; - case S_IFLNK: fch = 'l'; break; - case S_IFIFO: fch = 'p'; break; -#ifdef S_IFSOCK - case S_IFSOCK: fch = 's'; break; -#endif - } - } - } -#else - u_rwx = strdup("-"); - fch = isdir ? 'd' : '-'; -#endif - if (printfmt == 'q') { - res = rz_str_appendf(res, "%s\n", nn); - } else if (printfmt == 'e') { - const char *eDIR = "📁"; - const char *eIMG = "🌅"; - const char *eHID = "👀"; - const char *eANY = " "; - // -- - const char *icon = eANY; - if (isdir) { - icon = eDIR; -#if __UNIX__ - } else if ((sb.st_mode & S_IFMT) == S_IFLNK) { - const char *eLNK = "📎"; - icon = eLNK; - } else if (sb.st_mode & S_ISUID) { - const char *eUID = "🔼"; - icon = eUID; -#endif - } else if (rz_str_casestr(nn, ".jpg") || rz_str_casestr(nn, ".png") || rz_str_casestr(nn, ".gif")) { - icon = eIMG; - } else if (*nn == '.') { - icon = eHID; - } - res = rz_str_appendf(res, "%s %s\n", icon, nn); - } else if (printfmt == FMT_RAW) { - res = rz_str_appendf(res, "%c%s%s%s 1 %4d:%-4d %-10d %s\n", - isdir ? 'd' : fch, - u_rwx ? u_rwx : "-", - rz_str_rwx_i((perm >> 3) & 7), - rz_str_rwx_i(perm & 7), - uid, gid, sz, nn); - } else if (printfmt == FMT_JSON) { - if (nth > 0) { - res = rz_str_append(res, ","); - } - res = rz_str_appendf(res, "{\"name\":\"%s\",\"size\":%d,\"uid\":%d," - "\"gid\":%d,\"perm\":%d,\"isdir\":%s}", - name, sz, uid, gid, perm, isdir ? "true" : "false"); - } - free(nn); - free(u_rwx); - return res; -} - -RZ_API RZ_OWN char *rz_syscmd_ls(RZ_NONNULL const char *input) { - char *res = NULL; - const char *path = "."; - char *d = NULL; - char *p = NULL; - char *homepath = NULL; - char *pattern = NULL; - int printfmt = 0; - RzListIter *iter; - RzList *files; - char *name; - char *dir; - int off; - if (!input) { - input = ""; - path = "."; - } - if (*input == 'q') { - printfmt = 'q'; - input++; - } - if (*input && input[0] == ' ') { - input++; - } - if (*input) { - if ((!strncmp(input, "-h", 2))) { - eprintf("Usage: ls ([-e,-l,-j,-q]) ([path]) # long, json, quiet\n"); - } else if ((!strncmp(input, "-e", 2))) { - printfmt = 'e'; - path = rz_str_trim_head_ro(input + 2); - } else if ((!strncmp(input, "-q", 2))) { - printfmt = 'q'; - path = rz_str_trim_head_ro(input + 2); - } else if ((!strncmp(input, "-l", 2)) || (!strncmp(input, "-j", 2))) { - printfmt = (input[1] == 'j') ? FMT_JSON : FMT_RAW; - path = rz_str_trim_head_ro(input + 2); - if (!*path) { - path = "."; - } - } else { - path = input; - } - } - if (!path || !*path) { - path = "."; - } else if (rz_str_startswith(path, "~")) { - homepath = rz_path_home_expand(path); - if (homepath) { - path = (const char *)homepath; - } - } else if (*path == '$') { - if (!strncmp(path + 1, "home", 4) || !strncmp(path + 1, "HOME", 4)) { - homepath = rz_str_home((strlen(path) > 5) ? path + 6 : NULL); - if (homepath) { - path = (const char *)homepath; - } - } - } - if (!rz_file_is_directory(path)) { - p = strrchr(path, '/'); - if (p) { - off = p - path; - d = (char *)calloc(1, off + 1); - if (!d) { - free(homepath); - return NULL; - } - memcpy(d, path, off); - path = (const char *)d; - pattern = strdup(p + 1); - } else { - pattern = strdup(path); - path = "."; - } - } else { - pattern = strdup("*"); - } - if (rz_file_is_regular(path)) { - res = showfile(res, 0, path, path, printfmt); - free(homepath); - free(pattern); - free(d); - return res; - } - files = rz_sys_dir(path); - - if (path[strlen(path) - 1] == '/') { - dir = strdup(path); - } else { - dir = rz_str_append(strdup(path), "/"); - } - int nth = 0; - if (printfmt == FMT_JSON) { - res = strdup("["); - } - needs_newline = 0; - rz_list_foreach (files, iter, name) { - char *n = rz_str_append(strdup(dir), name); - if (!n) { - break; - } - if (rz_str_glob(name, pattern)) { - if (*n) { - res = showfile(res, nth, n, name, printfmt); - } - nth++; - } - free(n); - } - if (printfmt == FMT_JSON) { - res = rz_str_append(res, "]"); - } - if (needs_newline) { - res = rz_str_append(res, "\n"); - } - free(dir); - free(d); - free(homepath); - free(pattern); - rz_list_free(files); - return res; -} - static int cmpstr(const void *_a, const void *_b) { const char *a = _a, *b = _b; return (int)strcmp(a, b);