602 lines
14 KiB
C
602 lines
14 KiB
C
/*
|
|
* 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 <xiuos.h>
|
|
|
|
#if defined(TOOL_SHELL) && defined(FS_VFS)
|
|
#include "shell.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <iot-vfs_posix.h>
|
|
|
|
#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", "<DIR>");
|
|
}
|
|
|
|
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 *parent, const char *filename);
|
|
|
|
abs_from = GetAbsolutePath(NULL, from);
|
|
abs_to = GetAbsolutePath(NULL, 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
|
|
|