Project Overview
This project involves creating a minimal shell implementation in Linux that supports basic file and directory operations. The shell should provide an interactive command-line interface and execute common system commands.
Core Functionality Requirements
- Display command prompt with current directory
- Process user input commands
- Parse command strings and agruments
- Implement basic file operations: ls, touch, rm, mkdir, rmdir, cd, cp, mv, pwd, cat, chmod, ln
- Log command execution with timestamps
- Integrate all functions into a cohesive application
- Package the final executable
Command Prompt Display
The shell displays the current working directory in a simplified format, showing only the last subdirectory component.
int display_prompt(void)
{
char path_buffer[1024] = {0};
char *path_ptr = NULL;
getcwd(path_buffer, sizeof(path_buffer));
path_ptr = path_buffer;
while(*path_ptr != '\0') {
path_ptr++;
}
while(*path_ptr != '/') {
path_ptr--;
}
if(strcmp(path_buffer, "/") != 0) {
path_ptr++;
}
printf("[user@linux:%s]$ ", path_ptr);
return 0;
}
Input Processing
User input is captured and processed, with logging functionality to record commands with timestamps.
int get_input(char *command_buffer, int buffer_size)
{
FILE *log_file = NULL;
time_t current_time;
struct tm *time_info = NULL;
fgets(command_buffer, buffer_size, stdin);
command_buffer[strlen(command_buffer)-1] = '\0';
time(¤t_time);
time_info = localtime(¤t_time);
log_file = fopen("command_log.txt", "a+");
fprintf(log_file, "[%04d-%02d-%02d %02d:%02d:%02d] ",
time_info->tm_year+1900, time_info->tm_mon+1,
time_info->tm_mday, time_info->tm_hour,
time_info->tm_min, time_info->tm_sec);
fwrite(command_buffer, strlen(command_buffer), 1, log_file);
fputc('\n', log_file);
fclose(log_file);
return 0;
}
Command Parsing and Execution
Input commands are parsed and routed to appropriate handler functions.
int parse_and_execute(char *input_cmd)
{
if(!strcmp(input_cmd, "exit")) {
return -1;
}
if(!strncmp(input_cmd, "cd", 2)) {
char *token = strtok(input_cmd, " ");
token = strtok(NULL, " ");
change_directory(token);
}
else if(!strncmp(input_cmd, "cp", 2)) {
char *source = NULL;
char *destination = NULL;
char *token = strtok(input_cmd, " ");
source = strtok(NULL, " ");
destination = strtok(NULL, " ");
copy_file(source, destination);
}
else if(!strncmp(input_cmd, "chmod", 5)) {
char *filename = NULL;
char *mode_str = NULL;
char *token = strtok(input_cmd, " ");
filename = strtok(NULL, " ");
mode_str = strtok(NULL, " ");
change_permissions(filename, mode_str);
}
else if(!strcmp(input_cmd, "ls")) {
list_directory();
}
else if(!strncmp(input_cmd, "ls -a", 5)) {
list_all_files();
}
else if(!strncmp(input_cmd, "mkdir", 5)) {
char *token = strtok(input_cmd, " ");
token = strtok(NULL, " ");
create_directory(token);
}
else if(!strcmp(input_cmd, "pwd")) {
print_working_directory();
}
return 0;
}
Core Command Implementations
Directory Listing
int list_directory(void)
{
char current_path[256] = {0};
DIR *dir_stream = NULL;
struct dirent *dir_entry = NULL;
getcwd(current_path, sizeof(current_path));
dir_stream = opendir(current_path);
while((dir_entry = readdir(dir_stream)) != NULL) {
if(dir_entry->d_name[0] == '.') {
continue;
}
printf("%s ", dir_entry->d_name);
}
printf("\n");
closedir(dir_stream);
return 0;
}
File Creation
int create_file(char *filename)
{
FILE *file_handle = fopen(filename, "w");
if(file_handle != NULL) {
fclose(file_handle);
}
return 0;
}
File Copy
int copy_file(char *source_file, char *dest_file)
{
FILE *source = fopen(source_file, "r");
FILE *destination = fopen(dest_file, "w");
int character;
while((character = fgetc(source)) != EOF) {
fputc(character, destination);
}
fclose(source);
fclose(destination);
return 0;
}
File Display
int display_file(char *filename)
{
FILE *file_handle = fopen(filename, "r");
int character;
while((character = fgetc(file_handle)) != EOF) {
fputc(character, stdout);
}
printf("\n");
fclose(file_handle);
return 0;
}
Permission Modification
int change_permissions(char *filename, char *mode_string)
{
mode_t permission_mode = strtol(mode_string, NULL, 8);
chmod(filename, permission_mode);
return 0;
}
Header File Integration
#ifndef __SHELL_HEADER_H__
#define __SHELL_HEADER_H__
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
#include <string.h>
extern int list_directory(void);
extern int list_all_files(void);
extern int create_file(char *filename);
extern int remove_file(char *filename);
extern int create_directory(char *dirname);
extern int remove_directory(char *dirname);
extern int change_directory(char *path);
extern int copy_file(char *source, char *destination);
extern int move_file(char *source, char *destination);
extern int print_working_directory(void);
extern int change_permissions(char *filename, char *mode);
extern int display_file(char *filename);
extern int create_link(char *source, char *linkname);
#endif
Build Configuration
TARGET = minishell
SOURCES = main.c file_ops.c dir_ops.c utils.c
$(TARGET): $(SOURCES)
gcc $^ -o $@
clean:
rm -f $(TARGET)
Applicaiton Packaging
The final executable can be packaged using tar compression:
tar -czf minishell.tar.gz minishell