Hust - OS - TinyShell
Chào các bạn lại đến với bài viết của mình. Sau hơn một tuần tìm hiểu cũng như là tham khảo các bài trên mạng và các khóa đi trước thì mình cùng mấy đứa trong nhóm đã làm được một chiếc TinyShell nên hôm nay mình quyết định đăng lên đây để chia sẻ cho mọi người cũng như lưu lại những công sức mà chúng mình đã làm được.
Hust-OS-TinyShell Bài Tập Lớn Môn Nguyên Lý Hệ Điều Hành |
Nội Dung
Công cụ Shell ra đời từ đó dưới dạng giả lập hệ điều hành MS-DOS của Microsoft trên Windows. Dự án Tiny Shell là một dự án giúp sinh viên có thể tìm hiểu cách quản lý tiến trình đó.
Giới Thiệu Về TinyShell:
Đề Tài:
- TinyShell: tìm hiểu về quản lý tiến trình sử dụng Win32 API
- Ngôn ngữ: C/C++
- Phát hành: 05/06/2021
Tính Năng:
- Shell nhận lệnh ,phân tích và tạo tiến trình con thực hiện
- Shell chứa các câu lệnh quản lý tiến trình
- Shell thực hiện một số lệnh đặc biệt
- Shell nhận tín hiệu từ bàn phím để hủy bỏ Foreground Processes đang thực hiện (CTRL +C)
- Shell có thể thực thi được file *.bat
Tác Giả:
- Phạm Văn Linh - 20194094
- Lê Trọng Khánh - 20194082
- Nguyễn Văn An - 20193974
- Lê Hồng Ưng - 20194211
- Hà Mạnh Hùng - 20194066
Video Demo:


Mã Nguồn:
TinyShell.cpp
Như Command Prompt hay PowerShell thì TinyShell cũng cần có phần nhập vào từ bàn phím.
/****************************************************************** | |
* ------------------- WELCOME TO OUR TINYSHELL ------------------- | |
* @author: Le Trong Khanh, | |
* Pham Van Linh, | |
* Nguyen Van An, | |
* Ha Manh Hung, | |
* Le Hong Ung | |
* @name of Program: Tiny Shell | |
* @IT1-01-K64 | |
* @05-06-2021 | |
* ---------------------------------------------------------------- | |
******************************************************************/ | |
#include "Analyse.h" | |
#include "Command.h" | |
#include "Process.h" | |
using namespace std; | |
int main (int argc, char** argv) { | |
char cur_dir[MAX_CWD_LENS]; | |
/* Ctrl + C => STOP */ | |
signal(SIGINT, sighandler); | |
/* set màu chữ cho shell */ | |
char color[] = "green"; | |
setColor(color); | |
char *cmd = (char*)calloc(MAX_BUFFER_SIZE,sizeof(char)); /*Cấp phát bộ nhớ để nhập dòng lệnh command VD: cd, dir, ....*/ | |
int stop = 0; /**/ | |
while(!stop) { /* Nếu vẫn chưa stop thì thực hiện nhập và chạy lệnh */ | |
if(printPrompt(cur_dir) == -1){ /* Kiểm tra, in ra đường dẫn VD: C:\Users\Admin\> $ .....*/ | |
break; | |
} | |
fflush(stdin); | |
cin.getline(cmd, MAX_BUFFER_SIZE); /* Nhập lệnh command */ | |
cin.clear(); | |
// cout << "HUST" << endl; | |
// sleep(1); | |
// fixCmd(cmd); /* Chỉnh sửa câu lệnh tránh các lỗi nhập cách khoảng */ | |
char **args = separate_line(cmd); /* Chia câu lệnh */ | |
/** | |
* VD: dir C:\Users\Admin ..... | |
* => args[0] : dir | |
* => args[1] : C:\Users\Admin | |
* ..... | |
**/ | |
stop = execute(args); /* Thực hiện lệnh, trả về 0 nếu tiếp tục, trả về 1 để thoát*/ | |
free(args); /*Giải phóng các con trỏ lệnh*/ | |
} | |
free(cmd); /*Giải phóng lệnh*/ | |
return EXIT_SUCCESS; | |
} |
Analyse.cpp
Tiếp theo là phần này để xử lí câu lệnh vừa nhập ở trên VD: tách các câu lệnh đã nhập, xóa bỏ các dấu cách thừa, ghép lại các câu lệnh để thực hiện các bước tiếp theo.
#include <iostream> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
#include "Command.h" | |
#define MAX_CWD_LENS 128 | |
#define MAX_BUFFER_SIZE 64 | |
#define MAX_TOK_BUFSIZE 64 | |
#define TOKEN_DELIMETERS " \t\r\n\a" | |
using namespace std; | |
///////////////////////////////////// | |
////////// Xử lý câu lệnh /////////// | |
///////////////////////////////////// | |
/** | |
* Sửa lỗi gõ cách câu lệnh | |
* VD: C:\Users\Admin> $ cd E:\ | |
* ==> C:\Users\Admin> $ cd E:\ | |
* | |
**/ | |
void fixCmd(char* cmd){ | |
/** | |
* Sửa lỗi gõ cách câu lệnh | |
* VD: C:\Users\Admin> $ cd E:\ | |
* ==> C:\Users\Admin> $ cd E:\ | |
* | |
**/ | |
int length = strlen(cmd); | |
int first; | |
for(int i=0; i<length; i++){ | |
if((cmd)[i] != ' '){ | |
first = i; | |
break; | |
} | |
} | |
int real_len = length - first, i=0; | |
// " Ta Ton" -> "Ta Tona Ton" | |
while(real_len--){ | |
(cmd)[i] = (cmd)[i+first]; | |
i++; | |
} | |
(cmd)[length - first] = '\0'; //"Ta Tona Ton" -> "Ta Ton" | |
} | |
/** | |
* In ra màn hình console đường dẫn | |
* (VD: C:\Users\Admin\.....> $ *phần tiếp này là lệnh*) | |
**/ | |
int printPrompt(char *cur_directory){ | |
/** | |
* In ra màn hình console đường dẫn | |
* (VD: C:\Users\Admin\.....> $ *phần tiếp này là lệnh*) | |
**/ | |
if(GetCurrentDirectory(MAX_CWD_LENS,cur_directory) == 0){ | |
cout << "Reading of current working directory failed.\n"; | |
return -1; | |
} | |
cout << cur_directory << "> $"; | |
return 1; | |
} | |
/** | |
* Chia câu lệnh thành các đoạn ngăn cách bởi ký tự ngăn (" ","\t","\r","\n","\a") | |
* | |
**/ | |
char **separate_line(char *line){ | |
/** | |
* Chia câu lệnh thành các đoạn ngăn cách bởi ký tự ngăn (" ","\t","\r","\n","\a") | |
* | |
**/ | |
int bufsize = MAX_TOK_BUFSIZE; | |
int position = 0; | |
char **tokens = (char**)malloc(bufsize*sizeof(char*)); | |
char *token; | |
if(!tokens){ | |
cout << "Allocation Failed" << endl; /* Không đủ bộ nhớ cấp phát */ | |
exit(EXIT_FAILURE); | |
} | |
token = strtok(line, TOKEN_DELIMETERS); /*Con trỏ trỏ tới args[0] của lệnh cmd VD: cd, dir*/ | |
while(token != NULL){ | |
tokens[position] = token; /* Lưu các con trỏ chứa thành phần của lệnh cmd */ | |
// cout << tokens[position] << endl; | |
position++; | |
if(position >= bufsize){ /* số thành phần args[i] trong lệnh cmd lớn hơn số bufsize dự tính*/ | |
bufsize += MAX_TOK_BUFSIZE; /* Tăng số bufsize */ | |
tokens = (char**)realloc(tokens, bufsize); /* Cấp phát thêm bộ nhớ cho tokens */ | |
if(!tokens){ | |
cout << "Allocation Failed" << endl; /* Không đủ bộ nhớ cấp phát */ | |
exit(EXIT_FAILURE); | |
} | |
} | |
token = strtok(NULL,TOKEN_DELIMETERS); /* Trỏ token tới thành phần args tiếp theo trong của cmd*/ | |
} | |
tokens[position] = NULL; /*Kết thúc danh sách mã*/ | |
return tokens; | |
} | |
/** | |
* Chuẩn hóa đường dẫn [path], tránh trường hợp như: | |
* VD: cd E:\New folder\ => [path] = 'E:\New' | |
**/ | |
char *combinePath(char **args, int start){ | |
/** | |
* Chuẩn hóa đường dẫn [path], tránh trường hợp có dấu ngăn cách như: | |
* VD: cd E:\New folder\ => [path] = 'E:\New' | |
**/ | |
char *path = (char *)calloc(MAX_CWD_LENS,sizeof(char)); /*Các thành phần không bị ngăn cách*/ | |
char *pivot = (char*)" "; /* Dấu ngăn cách */ | |
/* Kết hợp từng thành phần trong path */ | |
path = strcat(path, args[start]); | |
int i = start + 1; | |
while(args[i] != NULL){ | |
path = strcat(path,pivot); | |
path = strcat(path, args[i]); | |
++i; | |
} | |
return path; | |
} | |
/** | |
* Đổi màu chữ (Có thể có hoặc k cơ bản là cũng k có ảnh hưởng gì chỉ là trang trí ) | |
* | |
**/ | |
void setColor(char* color) { | |
/* | |
* Đổi màu lời gọi đầu | |
*/ | |
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); | |
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; | |
WORD saved_attributes; | |
/* Lưu các thuộc tính */ | |
// GetConsoleScreenBufferInfo(hConsole, &consoleInfo); | |
// saved_attributes = consoleInfo.wAttributes; | |
if (strcmp(color,"green")==0) { | |
SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN | FOREGROUND_INTENSITY); | |
} | |
} |
#pragma once | |
#ifndef _ANALYSE_H | |
#define _ANALYSE_H | |
#include <iostream> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
#include "Command.h" | |
#define MAX_CWD_LENS 128 | |
#define MAX_BUFFER_SIZE 64 | |
#define MAX_TOK_BUFSIZE 64 | |
#define TOKEN_DELIMETERS " \t\r\n\a" | |
void fixCmd(char *cmd); | |
void sighandler(int); | |
void setColor(char* color); | |
char **separate_line(char *line); | |
char *combinePath(char **args, int start); | |
#endif |
Command.cpp
Sau khi có câu lệnh thì phần này sẽ đọc câu lệnh và thực hiện các lệnh đó trên Shell. VD: cd, dir, help, date, time, pc, ... các bạn dùng câu lệnh help để biết các câu lệnh mà Shell hỗ trợ cũng như chức năng của nó.
#include <iostream> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
#include "Analyse.h" | |
#include "Process.h" | |
#define MAX_CWD_LENS 128 | |
#define MAX_BUFFER_SIZE 64 | |
#define MAX_TOK_BUFSIZE 64 | |
#define TOKEN_DELIMETERS " \t\r\n\a" | |
using namespace std; | |
/* Mảng các câu lệnh command được hỗ trợ */ | |
const char *command[] = { | |
"cd", | |
"cls", | |
"echo", | |
"exit", | |
"help", | |
"del", | |
"dir", | |
"mkdir", | |
"date", | |
"time", | |
"pc", | |
"calc", | |
"run" | |
}; | |
/* Mảng các lệnh command*/ | |
int (*activate_command[])(char **) = { | |
&cd, | |
&cls, | |
&echo, | |
&exit, | |
&help, | |
&del, | |
&dir, | |
&mk_dir, | |
&date, | |
&time_cmd, | |
&pc, | |
&calc, | |
&runbat | |
}; | |
/** | |
* Chạy lệnh với lệnh là arg[0] như cd, dir, exit, help | |
**/ | |
int execute(char ** args){ | |
/** | |
* Chạy lệnh với lệnh là arg[0] như cd, dir, exit, help | |
**/ | |
if (args[0] == NULL){ | |
return 0; | |
} | |
for(int i=0; i < size_of_command() ; i++){ | |
if(strcmp(args[0],command[i]) == 0){ /* Kiểm tra xem người dùng nhập lệnh nào trong tập lệnh */ | |
return (*activate_command[i])(args); | |
} | |
} | |
return 0; | |
} | |
/** | |
* Trả về số câu lệnh trong tập các lệnh | |
**/ | |
int size_of_command(){ | |
/** | |
* Trả về số câu lệnh trong tập các lệnh | |
**/ | |
return sizeof(command) / sizeof(char *); | |
} | |
////////////////////////////////////////// | |
////////// Danh sách câu lệnh //////////// | |
////////////////////////////////////////// | |
int help(char **args){ | |
if (args[1] == NULL) { | |
printf("Type \"help [command]\" for more information about a specific command.\n"); | |
printf("Suppoted commands:\n cd\n date\n time\n dir\n cls\n echo\n del\n mkdir\n pc\n exit\n "); | |
printf("Usage:\n\t <command> [option]\n\tEXAMPLE: help cd\n"); | |
printf("%-30s%s\n%-30s%s", " cd", | |
"Change the current directory. You must write the new directory after this command.", | |
" ", "EXAMPLES: \"cd C:/\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " date", | |
"Show the today's date.", | |
" ", "EXAMPLES: \"date\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " time", | |
"Show the current time.", | |
" ", "EXAMPLES: \"time\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " dir", | |
"Show all files and folders in the current directory.", | |
" ", "EXAMPLES: \"dir\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " cls", | |
"Clear the console screen.", | |
" ", "EXAMPLES: \"cls\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " echo", | |
"Print a message on the screen.", | |
" ", "EXAMPLES: \"echo [message]\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " del", | |
"Delete a file or folder in the current directory.", | |
" ", "EXAMPLES: \"del [Folder/Filename]\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " mkdir", | |
"Make a new directory.", | |
" ", "EXAMPLES: \"mkdir[Foldername]\"\n\n"); | |
printf("%-30s%s\n%-30s%s", " run", | |
"Run .bat file only.", | |
" ", "EXAMPLES: \"run [filename.bat]\"\n\n"); | |
printf("%-30s%s\n%-30s%s\n%-30s%s", " pc", | |
"Process.", " ", | |
"You must enter the options in the 2nd argument, such as fg, bg, all, find, kill, killid, suspend, resume", | |
" ", "EXAMPLES: \"pc bg\"\n\n"); | |
printf("%-30s%s", " exit", "Exit this tiny shell :((((\n"); | |
} | |
else if(!strcmp(args[1],"cd")) { | |
cout << "Change the current directory." << endl; | |
cout << " cd : Show the current directory" << endl; | |
cout << " cd .. : Show the parent directory of the current directory" << endl; | |
cout << " cd [path] : Change the current directory to [path]" << endl; | |
cout << "EXAMPLE: cd C:\\Users\\Admin\\ => change current directory to C:\\User\\Admin" << endl; | |
} | |
else if(!strcmp(args[1],"date")) { | |
cout << "Display the current date to screen." << endl; | |
cout << "This command does not support any options." << endl; | |
} | |
else if(!strcmp(args[1],"time")){ | |
cout << "Diplay the current time to screen." << endl; | |
cout << "This command does not support any options." << endl; | |
} | |
else if(!strcmp(args[1],"dir")){ | |
cout << "Display the list of files and folder in the directory to the screen." << endl; | |
cout << " dir : Show the files and folders in the current directory" << endl; | |
cout << " dir [path] : Show the files and folders in the [path]" << endl; | |
cout << "EXAMPLE: \"dir\", \"dir C:\\Users\\Admin\"" << endl; | |
} | |
else if(!strcmp(args[1],"cls")){ | |
cout << "Clear all line displaying on the console screen." << endl; | |
cout << "This command does not support any options." << endl; | |
} | |
else if(!strcmp(args[1],"echo")){ | |
cout << "Print the message on the screen." << endl; | |
cout << "This command does not support any options." << endl; | |
cout << "EXAMPLE: \"echo Hello World\"" << endl; | |
cout << " => \"Hello World\"" << endl; | |
} | |
else if(!strcmp(args[1],"del")){ | |
cout << "Delete file or folder in the current directory." << endl; | |
cout << "Recommend: Folder/File name contains no space." << endl; | |
cout << " del [Folder/Filename] : Delete folder/file (Folder/Filename) in the current dirrectory" << endl; | |
cout << "EXAMPLE: \"del ABC\"" << endl; | |
} | |
else if(!strcmp(args[1],"mkdir")){ | |
cout << "Make a new directory in the current directory." << endl; | |
cout << "Recommend: Foldername contains no space." << endl; | |
cout << " mkdir [Foldername] : Make folder [Foldername] in the current directory" << endl; | |
cout << "EXAMPLE: \"mkdir ABC\"" << endl; | |
} | |
else if (!strcmp(args[1], "run")){ | |
cout << "Run .bat file only with commands which our shell supports" << endl; | |
cout << " run [Filename.bat] : Run .bat file with commands which our shell supports " << endl; | |
cout << "EXAMPLE: \"run command.bat\"" << endl; | |
} | |
else if(!strcmp(args[1],"pc")){ | |
cout << "Supported options:" << endl; | |
cout << " all Show list of all running processes" << endl; | |
cout << " find Get pid of specific program(s) by name" << endl; | |
cout << " suspend Suspend a program by process id" << endl; | |
cout << " resume Resume a program by process id" << endl; | |
cout << " kill Terminate all program by name" << endl; | |
cout << " killid Terminate a program by process id" << endl; | |
cout << " bg Run a program in background mode by path to program" << endl; | |
cout << " fg Run a program in foregound mode by path to program" << endl; | |
cout << "EXAMPLE: \"pc fg C:\\Users\\Admin\\ABC\"" << endl; | |
} | |
else if(!strcmp(args[1],"exit")){ | |
cout << "Exit the TinyShell." << endl; | |
cout << "This command does not support any options." << endl; | |
} | |
return 0; | |
} | |
/** | |
* Chuyển directory hiện tại sang directory mới | |
* Câu lệnh: cd [path] | |
* cd : trả về đường dẫn directory hiện tại | |
* cd .. :trả về đường dẫn directory cha | |
* cd [path]: chuyển current working directory sang directory mới | |
* | |
**/ | |
int cd(char **args){ | |
/** | |
* Chuyển directory hiện tại sang directory mới | |
* Câu lệnh: cd [path] | |
* cd : trả về đường dẫn directory hiện tại | |
* cd .. :trả về đường dẫn directory cha | |
* cd [path]: chuyển current working directory sang directory mới | |
* | |
**/ | |
if(args[1] == NULL){ /* Nếu chỉ gõ lệnh cd */ | |
system("cd"); /* Dùng luôn lệnh cd có sẵn của Windows (Chơi bẩn nhưng kệ) */ | |
cout << endl; | |
return EXIT_SUCCESS; | |
} | |
/* Nếu cd [path] */ | |
else { | |
char* path = combinePath(args,1); /* Chuẩn hóa path */ | |
if(SetCurrentDirectory(path)==FALSE){ /* Tìm đường dẫn nếu có */ | |
// cout << args[1] << endl; | |
fprintf(stdout,"Not able to set current working directory\n"); | |
} | |
} | |
return 0; | |
} | |
/** | |
* Liệt kê các folder, file trong directory | |
* Câu lệnh: dir [path] | |
* | |
**/ | |
int dir(char **args){ | |
/** | |
* Liệt kê các folder, file trong directory | |
* Câu lệnh: dir [path] | |
* | |
**/ | |
/* Đống này chôm chỉa về sửa một chút t cx chưa hiểu hết :)))))) */ | |
char *cur_dir = (char*)malloc(MAX_CWD_LENS*sizeof(char)); | |
GetCurrentDirectory(MAX_CWD_LENS, cur_dir); | |
WIN32_FIND_DATA data; | |
_FILETIME time_lastwrite; | |
_SYSTEMTIME convert_time; | |
string date; | |
string time; | |
char *char_date = (char *)calloc(15, sizeof(char)); | |
char *char_time = (char *)calloc(15, sizeof(char)); | |
const char add[] = "\\*"; | |
char *path = (char*)malloc(MAX_CWD_LENS*sizeof(char)); | |
if(args[1] == NULL){ | |
strcpy(path, cur_dir); | |
strcat(path,"\\*"); | |
} | |
else { | |
path = combinePath(args,1); | |
strcat(path,"\\*"); | |
} | |
HANDLE han = FindFirstFile(path, &data); | |
printf("%-15s%-15s%-15s%-15s\n", "Date", "Time", "Type", "Name"); | |
printf("=========================================================================\n"); | |
if (han != INVALID_HANDLE_VALUE) { | |
do { | |
time_lastwrite = data.ftLastWriteTime; | |
FileTimeToSystemTime(&time_lastwrite, &convert_time); | |
date = to_string(convert_time.wDay) + '/' + to_string(convert_time.wMonth) + '/' + to_string(convert_time.wYear); | |
time = to_string(convert_time.wHour) + ':' + to_string(convert_time.wMinute); | |
strcpy(char_date, date.c_str()); | |
strcpy(char_time, time.c_str()); | |
if (data.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) { | |
printf("%-15s%-15s%-15s%-15s\n", char_date, char_time, "<FILE>", data.cFileName); | |
} | |
if (data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { | |
printf("%-15s%-15s%-15s%-15s\n", char_date, char_time, "<FOLDER>", data.cFileName); | |
} | |
} while (FindNextFileA(han, &data) != 0); | |
FindClose(han); | |
delete char_time; | |
delete char_date; | |
return EXIT_SUCCESS; | |
} | |
else{ | |
return EXIT_FAILURE; | |
} | |
} | |
/** | |
* Tạo folder trong directory hiện tại | |
* Câu lệnh: mkdir [foldername] | |
* | |
**/ | |
int mk_dir(char **args){ | |
/** | |
* Tạo folder trong directory hiện tại | |
* Câu lệnh: mkdir [foldername] | |
* | |
**/ | |
if(args[1] == NULL){ /* Chỉ gõ lệnh mkdir */ | |
cout << "ERROR: Command mk_dir need filename" << endl; | |
cout << "Command: mkdir [filename]" << endl; | |
cout << "Recommend: filename should not have any space" << endl; | |
return 0; | |
} | |
mkdir(args[1]); /* Lệnh mkdir tạo folder có sẵn */ | |
return 0; | |
} | |
/** | |
* In ra message đi kèm với echo | |
* Câu lệnh: echo [message] | |
* | |
**/ | |
int echo(char **args){ | |
/** | |
* In ra message đi kèm với echo | |
* Câu lệnh: echo [message] | |
* | |
**/ | |
if(args[1] == NULL){ | |
cout << "ERROR: Echo + [message]" << endl; | |
return 0; | |
} | |
int i=0; | |
while(args[++i] != NULL){ | |
for(int j=0; j<strlen(args[i]); j++){ | |
cout << args[i][j]; | |
} | |
cout << " "; | |
} | |
cout << endl; | |
return 0; | |
} | |
/** | |
* Clear toàn màn hình console | |
* Câu lệnh: cls | |
**/ | |
int cls(char **args){ | |
/** | |
* Clear toàn màn hình console | |
* Câu lệnh: cls | |
* | |
* Cũng chôm chỉa về nốt :))) | |
**/ | |
if(strcmp(args[0],"cls") == 0){ | |
HANDLE hConsole; | |
hConsole = GetStdHandle(STD_OUTPUT_HANDLE); | |
CONSOLE_SCREEN_BUFFER_INFO csbi; | |
SMALL_RECT scrollRect; | |
COORD scrollTarget; | |
CHAR_INFO fill; | |
// Get the number of character cells in the current buffer. | |
if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) | |
{ | |
return 0; | |
} | |
// Scroll the rectangle of the entire buffer. | |
scrollRect.Left = 0; | |
scrollRect.Top = 0; | |
scrollRect.Right = csbi.dwSize.X; | |
scrollRect.Bottom = csbi.dwSize.Y; | |
// Scroll it upwards off the top of the buffer with a magnitude of the entire height. | |
scrollTarget.X = 0; | |
scrollTarget.Y = (SHORT)(0 - csbi.dwSize.Y); | |
// Fill with empty spaces with the buffer's default text attribute. | |
fill.Char.UnicodeChar = TEXT(' '); | |
fill.Attributes = csbi.wAttributes; | |
// Do the scroll | |
ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, scrollTarget, &fill); | |
// Move the cursor to the top left corner too. | |
csbi.dwCursorPosition.X = 0; | |
csbi.dwCursorPosition.Y = 0; | |
SetConsoleCursorPosition(hConsole, csbi.dwCursorPosition); | |
} | |
return 0; | |
} | |
/** | |
* In ra màn hình ngày hiện tại | |
* Câu lệnh: date | |
* | |
**/ | |
int date(char **args){ | |
if (args[1] != NULL) | |
{ | |
cout << "Command \"date\" does not support any option !\n"; | |
return EXIT_FAILURE; | |
} | |
time_t t = time(0); | |
struct tm * now = localtime(&t); | |
cout << "Current Date: " << now->tm_mday << '/' | |
<< (now->tm_mon + 1) << '/' | |
<< (now->tm_year + 1900) | |
<< endl; | |
return 0; | |
} | |
/** | |
* In ra màn hình thời gian (giờ:phút:giây) hiện tại | |
* Câu lệnh: time | |
* | |
*/ | |
int time_cmd(char **args){ | |
if (args[1] != NULL) | |
{ | |
cout << "Command \"time\" does not support any option !\n"; | |
return EXIT_FAILURE; | |
} | |
time_t t = time(0); | |
struct tm * now = localtime(&t); | |
cout << "Current time: " << now->tm_hour << ':' << now->tm_min << ':' << now->tm_sec << endl; | |
return 0; | |
} | |
/** | |
* Delete file hoặc folder | |
* Câu lệnh: del [file/foldername] | |
* | |
**/ | |
int del(char **args){ | |
/** | |
* Delete file hoặc folder | |
* Câu lệnh: del [file/foldername] | |
* | |
**/ | |
if(args[1] == NULL){ | |
cout << "ERROR: Command 'del' need path" << endl; | |
cout << "Command: del [path]" << endl; | |
return 0; | |
} | |
else if (args[2] != NULL){ | |
cout << "ERROR: Command 'del' cannot delete more than 1 file" << endl; | |
cout << "Command: del [path]" << endl; | |
return 0; | |
} | |
if(remove(args[1]) == -1 && rmdir(args[1]) == -1){ /* Nếu arg[1] là file thì xóa file, folder thì xóa folder. Nếu k có thì in chỗ dưới */ | |
cout << "ERROR: Unable to find file to be deleted. Try again" << endl; | |
cout << "Command: del [path]" << endl; | |
return 0; | |
} | |
return 0; | |
} | |
/** | |
* Thoát chương trình | |
* Câu lệnh: exit | |
* | |
**/ | |
int exit(char **args){ | |
/** | |
* Thoát chương trình | |
* Câu lệnh: exit | |
* | |
**/ | |
char* term = (char*)malloc(64*sizeof(char)); | |
if(args[1] != NULL){ | |
term = combinePath(args,1); | |
cout << "ERROR: Term " << term << "is not recognized for EXIT" << endl; | |
cout << "Command: exit" << endl; | |
return 0; | |
} | |
/* Trả 1 về cho biết stop trong main */ | |
return 1; | |
} | |
/** | |
* Các lệnh với tiến trình | |
* Câu lệnh: pc (Process) | |
* | |
**/ | |
int pc(char **args) { | |
if (args[1] == NULL) { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} | |
if (strcmp(args[1], "all") == 0) { | |
if (getProcessListAll()) { | |
return 0; | |
} | |
return 1; | |
} | |
if (strcmp(args[1], "find") == 0){ | |
if (args[2] == NULL) | |
{ | |
printf("ERROR: Too few arguments\n"); | |
return 0; | |
} | |
// Tìm ID Process | |
if (findProcessID(args[2])) | |
return 0; | |
return 1; | |
} | |
if (strcmp(args[1], "kill") == 0) { | |
if (args[2] == NULL) { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} | |
if (killProcess(args[2])) { | |
return 0; | |
} | |
return 1; | |
} | |
if (strcmp(args[1], "killid") == 0) { | |
if (args[2] == NULL) { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} | |
DWORD process_id = atoi(args[2]); | |
if (killProcessID(process_id)) { | |
return 0; | |
} | |
return 1; | |
} | |
if (strcmp(args[1], "suspend") == 0) { | |
if (args[2] == NULL) { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} | |
DWORD process_id = atoi(args[2]); | |
suspendProcess(process_id); | |
return 0; | |
} | |
if (strcmp(args[1], "resume") == 0) { | |
if (args[2] == NULL) { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} | |
DWORD process_id = atoi(args[2]); | |
resumeProcess(process_id); | |
return 0; | |
} | |
if (strcmp(args[1], "bg") == 0 || strcmp(args[1], "fg") == 0) { | |
if(args[2] == NULL) { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} else { | |
createNewProcess(args); | |
} | |
return 0; | |
} | |
else { | |
cout << "ERROR: Too few argument" << endl; | |
return 0; | |
} | |
} | |
int calc(char **args){ | |
system("calc"); | |
return 0; | |
} | |
////////////////////////////////////////// | |
//////// Dành riêng cho file .bat //////// | |
////////////////////////////////////////// | |
/** | |
* Kiểm tra xem câu lệnh có được hỗ trợ trong shell không | |
* | |
**/ | |
bool cmdCheck(char **args){ | |
if (args[0] == NULL){ | |
return 0; | |
} | |
for(int i=0; i < size_of_command() ; i++){ | |
if(strcmp(args[0],command[i]) == 0){ /* Kiểm tra xem người dùng nhập lệnh nào trong tập lệnh */ | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Chạy riêng cho file .bat | |
* Câu lệnh: run [Filename.bat] | |
* | |
**/ | |
int runbat(char **args){ | |
char w[255],a[255]; | |
char *run_file = combinePath(args, 1); | |
FILE *f=fopen(run_file,"rt"); | |
if(f==NULL) { | |
printf("\nLoi doc file.\n"); | |
// getch(); | |
return 0; | |
} | |
else { | |
while(!feof(f)) { | |
fgets(w,255,f); | |
strcpy(a,w); | |
char **arg = separate_line(a); | |
printf(""); | |
// cout << w << endl; | |
if(cmdCheck(arg)){ | |
int stop = execute(arg); // system ??? | |
} | |
else { | |
system(w); | |
} | |
} | |
fclose(f); | |
} | |
return 0; | |
} |
#pragma once | |
#ifndef _COMMAND_H | |
#define _COMMAND_H | |
#include <iostream> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
#define MAX_CWD_LENS 128 | |
#define MAX_BUFFER_SIZE 64 | |
#define MAX_TOK_BUFSIZE 64 | |
#define TOKEN_DELIMETERS " \t\r\n\a" | |
// char cur_directory[MAX_CWD_LENS]; | |
/* Các câu lệnh thực hiện command */ | |
int cd(char **args); | |
int cls(char **args); | |
int dir(char **args); | |
int echo(char **args); | |
int exit(char **args); | |
int help(char **args); | |
int mk_dir(char **args); | |
int del(char **args); | |
int date(char **args); | |
int time_cmd(char **args); | |
int pc(char **args); | |
int calc(char **args); | |
int runbat(char **args); | |
bool cmdCheck(char **args); | |
int execute(char ** args); | |
int size_of_command(); | |
int printPrompt(char* cur_dir); | |
#endif |
Process.cpp
Sau khi nhận được câu lệnh liên quan đến xử lí tiến trình pc ở phần command ta sẽ có phần process để xử lí tiếp các câu lệnh đằng sau. Để biết các câu lệnh được hỗ trợ các bạn nhập help pc.
#include <iostream> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
#include "Analyse.h" | |
#include "Command.h" | |
using namespace std; | |
#define MAX_CWD_LENS 128 | |
#define MAX_BUFFER_SIZE 64 | |
#define MAX_TOK_BUFSIZE 64 | |
#define TOKEN_DELIMETERS " \t\r\n\a" | |
HANDLE hForeProcess; | |
/////////////////////////////////// | |
//////// Xử lí tiến trình ///////// | |
/////////////////////////////////// | |
/** | |
* Đón tín hiệu ngắt Ctrl + C | |
**/ | |
void sighandler(int signum) { | |
/** | |
* Đón tín hiệu ngắt Ctrl + C | |
**/ | |
// printf("Caught signal %d, coming out...\n", signum); | |
if (hForeProcess != NULL) { | |
TerminateProcess(hForeProcess, 0); | |
hForeProcess = NULL; | |
} | |
exit(1); | |
} | |
/** | |
* In ra các tiến trình đang hoạt động | |
* In ra màn hình tên tiến trình, Process ID, Parent PID | |
* Câu lệnh: pc all | |
* | |
**/ | |
int getProcessListAll() { | |
HANDLE hProcessSnap; | |
PROCESSENTRY32 pe32; // Cấu trúc của tiến trình khi được gọi snapshot | |
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // Chụp lại các tiến trình | |
// Nếu hProcessSnap trả về lỗi return 0 | |
if (hProcessSnap == INVALID_HANDLE_VALUE) { | |
cout << "ERROR: CreateToolhelp32Snapshot Fail " << GetLastError() << endl; | |
return 0; | |
} | |
pe32.dwSize = sizeof(PROCESSENTRY32); | |
// Kiểm tra thằng đầu tiên | |
if (!Process32First(hProcessSnap, &pe32)) { | |
// Nếu lỗi in ra... | |
cout << "ERROR: Process32First Fail " << GetLastError() << endl; | |
return 0; | |
} | |
printf("%-50s%-20s%-20s\n", "Process Name", "Process ID", "Parent Process ID"); | |
printf("%-50s%-20s%-20s\n", "----------------------------------", "----------", "-----------"); | |
do { | |
printf("%-50s%-20d%-20d\n", pe32.szExeFile, pe32.th32ProcessID, pe32.th32ParentProcessID); | |
} while (Process32Next(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); | |
return 1; | |
} | |
/** | |
* Tìm tiến trình bằng tên | |
* In ra màn hình tên tiến trình, Process ID, Parent PID | |
* Câu lệnh pc find [name_process] | |
* | |
**/ | |
int findProcessID(char *name_process) { | |
HANDLE hProcessSnap; | |
PROCESSENTRY32 pe32; // Cấu trúc của tiến trình khi được gọi snap | |
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // Chụp lại các tiến trình | |
// Nếu trả về lỗi return 0 | |
if (hProcessSnap == INVALID_HANDLE_VALUE) { | |
return 0; | |
} | |
pe32.dwSize = sizeof(PROCESSENTRY32); | |
// Kiểm tra thằng đầu tiên | |
if (!Process32First(hProcessSnap, &pe32)) { | |
return 0; | |
} | |
printf("%-50s%-20s%-20s\n", "Process Name", "Process ID", "Parent Process ID"); | |
printf("%-50s%-20s%-20s\n", "----------------------------------", "----------", "-----------"); | |
do { | |
if (strcmp(name_process, pe32.szExeFile) == 0) { | |
// Nếu pe32.szExeFile trùng với tên tiến trình thì in ra | |
printf("%-50s%-20d%-20d\n", pe32.szExeFile, pe32.th32ProcessID, pe32.th32ParentProcessID); | |
} | |
} while (Process32Next(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); | |
return 1; | |
} | |
/** | |
* Đóng tiến trình bằng Process ID | |
* Câu lệnh: pc kill [process_id] | |
* | |
**/ | |
int killProcessID(DWORD process_id) { | |
// Mở tiến trình đang chạy có Process ID là... | |
HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id); | |
// Nếu hProcess trả về NULL thì báo lỗi | |
if (hprocess == NULL) { | |
cout << "ERROR: Failed!" << endl; | |
return 1; | |
} | |
// Đóng tiến trình hProcess | |
if (!TerminateProcess(hprocess, 0)) { | |
return 0; | |
} | |
return 1; | |
} | |
/** | |
* Đóng tất cả tiến trình có tên là name_process | |
* Câu lệnh pc kill [Name_Process] | |
* | |
* */ | |
int killProcess(char *name_process) { | |
HANDLE hProcessSnap; | |
PROCESSENTRY32 pe32; // Cấu trúc của tiến trình khi được gọi snapshot | |
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // Chụp lại các tiến trình | |
// Nếu trả về lỗi return 0 | |
if (hProcessSnap == INVALID_HANDLE_VALUE) { | |
return 0; | |
} | |
pe32.dwSize = sizeof(PROCESSENTRY32); | |
// Kiểm tra thằng đầu tiên | |
if (!Process32First(hProcessSnap, &pe32)) { | |
return 0; | |
} | |
do { | |
if (strcmp(name_process, pe32.szExeFile) == 0) { | |
killProcessID(pe32.th32ProcessID); | |
} | |
} while (Process32Next(hProcessSnap, &pe32)); | |
CloseHandle(hProcessSnap); | |
return 1; | |
} | |
/** | |
* Đình chỉ một tiến trình đang thực hiện | |
* Câu lệnh pc suspend [process_id] | |
* | |
**/ | |
int suspendProcess(DWORD process_id) { | |
// Chụp lại tất cả các luồng | |
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); | |
THREADENTRY32 th32; // Cấu trúc của luồng khi được gọi snapshot | |
HANDLE hthread; | |
// Kiểm tra xem hThreadSnap có lỗi không nếu có thì in ra lỗi | |
if (hThreadSnap == INVALID_HANDLE_VALUE) { | |
cout << "ERROR: CreateToolhelp32Snapshot" << GetLastError(); | |
return 0; | |
} | |
th32.dwSize = sizeof(THREADENTRY32); | |
// Kiểm tra thông tin của luồng đầu tiên | |
if (!Thread32First(hThreadSnap, &th32)) { | |
cout << "Thread32First Fail " << GetLastError(); // Nếu lỗi in ra lỗi | |
CloseHandle(hThreadSnap); // Đóng Handle snapshot | |
return 0; | |
} | |
// Duyệt các luồng khác | |
do { | |
// Kiểm tra xem các luồng này có thuộc tiến trình cần dừng không | |
if (th32.th32OwnerProcessID == process_id) { | |
hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, th32.th32ThreadID); // Mở một luồng đang chạy | |
// Đình chỉ luồng đó | |
if (SuspendThread(hthread) == -1) { | |
return 0; | |
} | |
} | |
} while (Thread32Next(hThreadSnap, &th32)); CloseHandle(hThreadSnap); | |
return 1; | |
} | |
/** | |
* Tiếp tục một tiến trình bị đình chỉ | |
* Câu lệnh pc resume [process_id] | |
* | |
**/ | |
int resumeProcess(DWORD process_id) { | |
// Chụp lại tất cả các luồng | |
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); | |
THREADENTRY32 th32; // Cấu trúc của luồng khi được gọi snapshot | |
HANDLE hthread; | |
// Kiểm tra xem hThreadSnap có lỗi không nếu có thì in ra lỗi | |
if (hThreadSnap == INVALID_HANDLE_VALUE) { | |
cout << "ERROR: CreateToolhelp32Snapshot" << GetLastError(); | |
return 0; | |
} | |
th32.dwSize = sizeof(THREADENTRY32); | |
// Kiểm tra thông tin của luồng đầu tiên | |
if (!Thread32First(hThreadSnap, &th32) { | |
cout << "Thread32First Fail " << GetLastError(); // Nếu lỗi in ra lỗi | |
CloseHandle(hThreadSnap); // Đóng Handle snapshot | |
return 0; | |
} | |
// Duyệt các luồng khác | |
do { | |
// Kiểm tra xem các luồng này có thuộc tiến trình cần dừng không | |
if (th32.th32OwnerProcessID == process_id) { | |
hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, th32.th32ThreadID); // Mở một luồng đang chạy | |
// Đình chỉ luồng đó | |
if (ResumeThread(hthread) == -1) { | |
return 0; | |
} | |
} | |
} while (Thread32Next(hThreadSnap, &th32)); CloseHandle(hThreadSnap); | |
return 1; | |
} | |
/** | |
* Tạo một tiến trình con | |
* Câu lệnh: pc bg [name_process/path](background mode) | |
* pc fg [name_process/path](foreground mode) | |
* | |
**/ | |
int createNewProcess(char **args) { | |
// Cài wait time cho các tiến trình | |
int wait_time; | |
if (strcmp(args[1], "bg") == 0) { | |
wait_time = 0; | |
} else { | |
wait_time = INFINITE; | |
} | |
char *run_file = combinePath(args, 2); // Ghép lại tên tiến trình hoặc đường dẫn | |
STARTUPINFO si; | |
PROCESS_INFORMATION pi; | |
ZeroMemory(&si, sizeof(si)); | |
si.cb = sizeof(si); | |
si.wShowWindow = SW_SHOW; | |
si.dwFlags = STARTF_USESHOWWINDOW; | |
si.lpTitle = args[1]; | |
ZeroMemory(&pi, sizeof(pi)); | |
// Khởi tạo tiến trình con | |
if (!CreateProcess(NULL, run_file, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { | |
int error = GetLastError(); // Kiểm tra lỗi | |
if (error == 2) | |
cout << "The batch file or execute file '" << run_file << "' is not found." << endl; | |
else | |
cout << "Can't run this file" << endl; | |
return 1; | |
} | |
// gán handle cho tiến trình con vừa tạo | |
if (strcmp(args[1], "fg") == 0) { | |
hForeProcess = pi.hProcess; | |
} | |
// Thời gian đợi 1 tiến trình con | |
WaitForSingleObject(pi.hProcess, wait_time); | |
// Đóng các handle | |
CloseHandle(pi.hProcess); | |
CloseHandle(pi.hThread); | |
return 1; | |
} |
#pragma once | |
#ifndef _PROCESS_H | |
#define _PROCESS_H | |
#include <iostream> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
#include "Analyse.h" | |
#define MAX_CWD_LENS 128 | |
#define MAX_BUFFER_SIZE 64 | |
#define MAX_TOK_BUFSIZE 64 | |
#define TOKEN_DELIMETERS " \t\r\n\a" | |
/* Các câu lệnh liên quan đến tiến trình */ | |
int findProcessID(char *name_process); | |
int getProcessListAll(); | |
int killProcessID(DWORD process_id); | |
int killProcess(char *name_process); | |
int suspendProcess(DWORD process_id); | |
int resumeProcess(DWORD process_id); | |
int createNewProcess(char **args); | |
#endif |