/* * Copyright (c) 2020 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ #include #if defined(TOOL_SHELL) && defined(FS_VFS) #include "shell.h" #include #include #include #include "utility.h" extern char working_dir[]; void ls(const char *path) { DIR *dir; struct dirent *dirent; struct stat statbuf; if (path == NULL) { path = strdup(working_dir); if (path == NULL) return; } else { path = (char *)path; } if ((dir = opendir(path)) == NULL) { KPrintf("Failed to open directory %s\n", path); return; } KPrintf("Directory: %s\n", path); while ((dirent = readdir(dir)) != NULL) { stat(dirent->d_name, &statbuf); KPrintf("%-20s", dirent->d_name); if (S_ISREG(statbuf.st_mode)) KPrintf("%-25lu\n", (unsigned long)statbuf.st_size); else KPrintf("%-25s\n", ""); } closedir(dir); } int cmd_ls(int argc, char **argv) { if (argc == 1) ls(working_dir); else ls(argv[1]); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, ls,cmd_ls, List information about the FILES .); static int CopyRecursive(const char *from, const char *to, char *buf, size_t buf_size) { struct stat statbuf; int ret; if (strcmp(from, to) == 0) return 0; ret = stat(from, &statbuf); if (ret < 0) { KPrintf("Failed to read %s\n", from); return -1; } if (S_ISREG(statbuf.st_mode)) { int fd_from, fd_to; int size_read; int total_size_written = 0; fd_from = open(from, O_RDONLY); if (fd_from < 0) { KPrintf("Failed to open %s\n", from); return -1; } fd_to = open(to, O_WRONLY); if (fd_to < 0) { KPrintf("Failed to open %s\n", to); close(fd_from); return -1; } while ((size_read = read(fd_from, buf, buf_size)) > 0) total_size_written += write(fd_to, buf, size_read); close(fd_from); close(fd_to); if (total_size_written != statbuf.st_size) { KPrintf("Error copying %s to %s\n", from, to); return -1; } return 0; } DIR *dirp; struct dirent *dirent; char *sub_from, *sub_to; ret = mkdir(to, 0777); if (ret < 0) { KPrintf("Failed to create directory %s\n", to); return -1; } dirp = opendir(from); if (dirp == NULL) { KPrintf("Failed to open directory %s\n", from); return -1; } ret = 0; while ((dirent = readdir(dirp)) != NULL) { sub_from = malloc(strlen(from) + strlen(dirent->d_name) + 2); sub_to = malloc(strlen(to) + strlen(dirent->d_name) + 2); if (sub_from == NULL || sub_to == NULL) { KPrintf("Out of memory\n"); ret = -1; goto err; } sprintf(sub_from, "%s/%s", from, dirent->d_name); sprintf(sub_to, "%s/%s", to, dirent->d_name); if (CopyRecursive(sub_from, sub_to, buf, buf_size) < 0) { ret = -1; goto err; } free(sub_from); free(sub_to); } err: closedir(dirp); free(sub_from); free(sub_to); return ret; } static int copy(const char *from, const char *to) { struct stat statbuf; char buf[128]; char *abs_from, *abs_to; int abs_from_len, abs_to_len; char *last_name; int last_name_len; char *GetAbsolutePath(const char *path); abs_from = GetAbsolutePath(from); abs_to = GetAbsolutePath(to); if (abs_from == NULL || abs_to == NULL) goto err; abs_from_len = strlen(abs_from); abs_to_len = strlen(abs_to); last_name = abs_from + abs_from_len - 1; while (*last_name != '/') last_name--; last_name_len = abs_from + abs_from_len - last_name; if (stat(abs_to, &statbuf) == 0) { if (S_ISDIR(statbuf.st_mode)) { if (strcmp(abs_to, "/") == 0) { last_name++; last_name_len--; } abs_to = realloc(abs_to, abs_to_len + last_name_len + 1); if (abs_to == NULL) goto err; strcat(abs_to, last_name); } else { unlink(abs_to); } } return CopyRecursive(abs_from, abs_to, buf, sizeof(buf)) < 0; err: free(abs_from); free(abs_to); return -1; } int CmdCp(int argc, char *argv[]) { if (argc != 3) { KPrintf("Usage: cp SOURCE DEST\n"); KPrintf("Copy SOURCE to DEST\n"); return 0; } copy(argv[1], argv[2]); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, cp,CmdCp, Copy source to dest.); static void RmRecursive(char *file_name, int recursive) { struct stat statbuf; if (stat(file_name, &statbuf) < 0) return; if (recursive && S_ISDIR(statbuf.st_mode)) { DIR *dir; struct dirent *dirent; dir = opendir(file_name); while ((dirent = readdir(dir)) != NULL) { char *sub_file_name = malloc(strlen(file_name) + strlen(dirent->d_name) + 2); if (sub_file_name == NULL) { KPrintf("Memory not enough\n"); return; } sprintf(sub_file_name, "%s/%s", file_name, dirent->d_name); RmRecursive(sub_file_name, recursive); free(sub_file_name); } closedir(dir); } unlink(file_name); } int CmdMv(int argc, char *argv[]) { if (argc != 3) { KPrintf("Usage: mv SOURCE DEST\n"); KPrintf("Move SOURCE to DESn"); return 0; } if (rename(argv[1], argv[2]) != 0) if (copy(argv[1], argv[2]) == 0) RmRecursive(argv[1], 1); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, mv,CmdMv, Move frome source to dest.); void cat(const char *filename) { int size; char buf[128]; int fd; if ((fd = open(filename, O_RDONLY)) < 0) { KPrintf("Failed to open file %s\n", filename); return; } while ((size = read(fd, buf, 128)) > 0) for (int i = 0; i < size; i++) putchar(buf[i]); close(fd); } int cmd_cat(int argc, char **argv) { int index; extern void cat(const char *filename); if (argc == 1) { KPrintf("Usage: cat [FILE]...\n"); KPrintf("Concatenate FILE(s)\n"); return 0; } for (index = 1; index < argc; index ++) { cat(argv[index]); } return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, cat,cmd_cat,Concatenate FILE(s).); int cmd_rm(int argc, char **argv) { int recursive = 0; if (argc == 1) { KPrintf("Usage: rm FILE...\n"); KPrintf("Remove (unlink) the FILE(s).\n"); KPrintf("Suppported option flags:\n"); KPrintf(" r recursively remove folders\n"); return 0; } if (argv[1][0] == '-') { if (strcmp(argv[1], "-r") != 0) KPrintf("Unknown options\n"); recursive = 1; argc--; argv++; } for (int i = 1; i < argc; i++) RmRecursive(argv[i], recursive); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, rm,cmd_rm,Remove (unlink) the File(s).); #ifdef VFS_USING_WORKDIR int cmd_cd(int argc, char **argv) { if (argc == 1) { KPrintf("%s\n", working_dir); } else if (argc == 2) { if (chdir(argv[1]) != 0) { KPrintf("No such directory: %s\n", argv[1]); } } return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, cd,cmd_cd, Chage the shell wroking directory.); int CmdPwd(int argc, char **argv) { KPrintf("%s\n", working_dir); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, pwd,CmdPwd, print the name of the current working directory.); #endif int cmd_mkdir(int argc, char **argv) { if (argc == 1) { KPrintf("Usage: mkdir [OPTION] DIRECTORY\n"); KPrintf("Create the DIRECTORY, if they do not already exist.\n"); } else { mkdir(argv[1], 0); } return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, mkdir,cmd_mkdir, Create a directory.); int cmd_df(int argc, char **argv) { struct statfs buf; char *path = argc < 2 ? "/" : argv[1]; static char *unit[] = {"B", "KB", "MB", "GB"}; uint64_t integer, decimal = 0; int i; if (statfs(path, &buf) < 0) { KPrintf("statfs failed: %s\n", path); return -1; } integer = (uint64_t)buf.f_bsize * buf.f_bfree; for (i = 0; i < 4; i++) { if (integer < 1024) break; decimal = (integer % 1024) * 10 / 1024; integer /= 1024; } if (i >= 4) i = 3; KPrintf("Free disk space: %d.%d %s " "[ %d blocks, %d free blocks, %d bytes per block ]\n", (int)integer, (int)decimal, unit[i], buf.f_blocks, buf.f_bfree, buf.f_bsize); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, df,cmd_df,disk free); int cmd_echo(int argc, char** argv) { if (argc == 2) { KPrintf("%s\n", argv[1]); } else if (argc == 3) { int fd; fd = open(argv[2], O_RDWR | O_APPEND | O_CREAT, 0); if (fd >= 0) { write (fd, argv[1], strlen(argv[1])); close(fd); } else { KPrintf("open file:%s failed!\n", argv[2]); } } else { KPrintf("Usage: echo \"string\" [filename]\n"); } return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, echo,cmd_echo,echo string to file.); static void FindRecursive(char *name, char *path) { struct stat statbuf; DIR *dir = opendir(path); struct dirent *dirent; while ((dirent = readdir(dir)) != NULL) { char *sub_path = malloc(strlen(path) + strlen(dirent->d_name) + 2); if (sub_path == NULL) { KPrintf("Memory not enough\n"); return; } sprintf(sub_path, "%s/%s", path, dirent->d_name); if (stat(sub_path, &statbuf) < 0) { KPrintf("Failed to access %s\n", sub_path); free(sub_path); continue; } if (strstr(dirent->d_name, name) != NULL) KPrintf("%s\n", sub_path); if (S_ISDIR(statbuf.st_mode)) FindRecursive(name, sub_path); free(sub_path); } } static void FindPrintUsage() { KPrintf("Usage: find NAME PATH\n"); } int cmd_find(int argc, char **argv) { struct stat statbuf; if (argc != 3) { FindPrintUsage(); return 0; } TruncateExtension(argv[2], "/"); if (strcmp(argv[2], "/") == 0) argv[2][0] = '\0'; if (stat(argv[2], &statbuf) < 0 || !S_ISDIR(statbuf.st_mode)) { KPrintf("No such directory: %s\n", argv[2]); return 0; } if (strstr(argv[1], "/") != NULL) { KPrintf("Invalid file name: %s\n", argv[1]); return 0; } FindRecursive(argv[1], argv[2]); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, find,cmd_find,search file with given name in specified path.); int cmd_tar(int argc, char **argv) { extern int tar(int argc, char **argv); tar(argc, argv); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, tar,cmd_tar,create or extarct tar archive.); int CmdGzip(int argc, char **argv) { extern int gzip(int argc, char **argv); gzip(argc, argv); return 0; } SHELL_EXPORT_CMD( SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, gzip,CmdGzip, creat or extart gzip compressed files); int CmdGunzip(int argc, char **argv) { extern int gunzip(int argc, char **argv); gunzip(argc, argv); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, gunzip,CmdGunzip,decompress gzip files.); int CmdUnzip(int argc, char **argv) { extern int unzip(int argc, char **argv); unzip(argc, argv); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, unzip,CmdUnzip, decompress zip files.); int cmd_bzip2(int argc, char **argv) { extern int bzip2(int argc, char **argv); bzip2(argc, argv); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, bzip2,cmd_bzip2,create or extract bzip2 compressed files.); int cmd_bunzip2(int argc, char **argv) { extern int bunzip2(int argc, char **argv); bunzip2(argc, argv); return 0; } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, bunzip2,cmd_bunzip2,decompress bzip2 files.); #endif