- Rohan G - CS22B1093
- Reddipalli Sai Charish - CS22B1095
- Thumula Pratyek - CS22B1096
- G Vivek Vardhan Reddy - CS22B1097
To try out xv6CustomizeSystemCalls, clone the repository and compile the code as follows:
# Clone the repository
git clone https://github.com/rzeta-10/OS-Project.git
cd Project1_xv6CustomizeSystemCalls
# Compile xv6
make qemu
// System call numbers
#define SYS_fork 1
..........
#define SYS_close 21
#define SYS_ps 22// proc.c
void exit(void);
......
void yield(void);
int ps ( void ); // system calls
int fork(void);
.....
int uptime(void);
int ps ( void );uint64
sys_ps ( void )
{
return cps ();
} .global ps
ps:
li a7, SYS_ps
ecall
retSYS_psextern int sys_chdir(void);
.....
extern int sys_ps(void);
.....
static int (*syscalls[])(void) = {
[SYS_fork] sys_fork,
.....
[SYS_close] sys_close,
[SYS_ps] sys_ps,
}; //current process status
int
ps()
{
struct proc *p;
// Enable interrupts on this processor.
sti();
// Loop over process table looking for process with pid.
acquire(&wait_lock);
printf("name \t pid \t state \n");
for(p = proc; p < &proc[NPROC]; p++){
if ( p->state == SLEEPING )
printf("%s \t %d \t SLEEPING \n ", p->name, p->pid );
else if ( p->state == RUNNING )
printf("%s \t %d \t RUNNING \n", p->name, p->pid );
else if ( p->state == RUNNABLE )
printf("%s \t %d \t RUNNABLE \n", p->name, p->pid );
else if ( p->state == ZOMBIE )
printf("%s \t %d \t ZOMBIE \n", p->name, p->pid );
else if ( p->state == USED )
printf("%s \t %d \t USED \n", p->name, p->pid );
}
release(&wait_lock);
return 22;
}#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"
int
main(int argc, char *argv[])
{
ps();
exit(0);
}ps// System call numbers
#define SYS_fork 1
..........
#define SYS_ps 22
#define SYS_fork2 23 // system calls
int fork(void);
.....
int uptime(void);
int fork2(int priority);uint64
sys_fork2(void)
{
int priority;
argint(0, &priority);
return fork_with_priority(priority);
}.global fork2
fork2:
li a7, SYS_fork2
ecall
retextern int sys_chdir(void);
.....
extern uint64 sys_fork2(void);
.....
static int (*syscalls[])(void) = {
[SYS_fork] sys_fork,
.....
[SYS_close] sys_close,
[SYS_fork2] sys_fork2,
}; int fork_with_priority(int priority);int fork_with_priority(int priority) {
struct proc *np;
struct proc *curproc = myproc();
// Allocate a new process. This function acquires the process lock.
if ((np = allocproc()) == 0)
return -1;
// Copy the parent process's address space to the child.
if (uvmcopy(curproc->pagetable, np->pagetable, curproc->sz) < 0) {
freeproc(np);
return -1;
}
// Set up the new process's state based on the parent process.
np->sz = curproc->sz;
np->parent = curproc;
*np->trapframe = *curproc->trapframe; // Copy the trapframe
// Set the priority for the new process.
np->priority = priority;
// Copy file descriptors from parent to child.
for (int i = 0; i < NOFILE; i++) {
if (curproc->ofile[i])
np->ofile[i] = filedup(curproc->ofile[i]);
}
// Copy the current working directory.
np->cwd = idup(curproc->cwd);
safestrcpy(np->name, curproc->name, sizeof(curproc->name));
int pid = np->pid;
// The process lock is already held here (from allocproc), so we just set the state.
np->state = RUNNABLE;
// Release the lock before returning.
release(&np->lock);
return pid;
}
#include "../kernel/types.h"
#include "user.h"
#include "printf.h"
int main() {
int pid = fork2(10); // Create a child process with priority 10
if (pid < 0) {
printf("fork2 failed\n");
exit(1);
}
if (pid == 0) {
// This is the child process
printf("Child process with priority 10\n");
exit(0);
} else {
// Parent waits for the child to finish
wait(0); // Wait for the child process to complete
printf("Parent process created child with PID: %d\n", pid);
}
exit(0);
}
test_fork2// System call numbers
#define SYS_fork 1
..........
#define SYS_fork2 23
#define SYS_get_ppid 24 // proc.c
void exit(void);
......
void yield(void);
int ps ( void ); // system calls
int fork(void);
.....
int uptime(void);
int get_ppid(void);uint64
sys_get_ppid(void)
{
struct proc *p = myproc(); // Get the current process
if (p->parent) {
return p->parent->pid; // Return parent PID
}
return -1; // No parent (e.g., init process)
}.global get_ppid
get_ppid:
li a7, SYS_get_ppid
ecall
retextern int sys_chdir(void);
.....
extern uint64 sys_get_ppid(void);
.....
static int (*syscalls[])(void) = {
[SYS_fork] sys_fork,
.....
[SYS_fork2] sys_fork2,
[SYS_get_ppid] sys_get_ppid,
}; #include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(void)
{
int ppid = get_ppid();
printf("Parent Process ID: %d\n", ppid);
exit(0);
}
get_ppid_test.
βββ kernel
β βββ defs.h # Permission definitions
β βββ proc.h # Added perm_flags to struct proc
β βββ sysproc.c # set_perm implementation
β βββ syscall.c # Added set_perm to dispatch table
β βββ syscall.h # Added SYS_set_perm
βββ user
β βββ user.h # User-space prototype for set_perm
β βββ usys.S # Assembly stub for set_perm
β βββ set_perm_test.c # Test program for set_perm
β βββ ...
βββ Makefile # Added _set_perm_test to UPROGS
βββ README.md # This file
set_permSystem Call:- Assigns custom permissions to a process based on its PID.
- Allows extending xv6 with process-level access control.
Define the system call number in kernel/syscall.h:
#define SYS_set_perm 23int set_perm(int pid, int perm_flags);int set_perm(int pid, int perm_flags);uint64
sys_set_perm(void)
{
int pid, perm_flags;
// Retrieve arguments using argint
argint(0, &pid);
argint(1, &perm_flags);
struct proc *p;
// Loop through the process table to find the process with the given PID
for (p = proc; p < &proc[NPROC]; p++) {
if (p->pid == pid) {
p->perm_flags = perm_flags; // Set the permission flags
return 0; // Success
}
}
return -1; // Process not found
}Add a new field to struct proc:
struct proc {
...
int perm_flags; // Permissions for the process
};-
Declare the system call:
extern uint64 sys_set_perm(void);
-
Add it to the
syscallsarray:[SYS_set_perm] sys_set_perm,
.global set_perm
set_perm:
li a7, SYS_set_perm
ecall
ret#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Usage: set_perm <pid> <perm_flags>\n");
exit(1);
}
int pid = atoi(argv[1]);
int perm_flags = atoi(argv[2]);
if (set_perm(pid, perm_flags) < 0) {
printf("Error: Unable to set permissions for process %d\n", pid);
} else {
printf("Permissions set for process %d\n", pid);
}
exit(0);
}Add the test program to the user programs in the Makefile:
UPROGS = \
...
$U/_set_perm_test \-
Build xv6:
make qemu
-
Run the Test Program: Inside the xv6 shell:
$ set_perm_test <pid> <perm_flags>
- If the process exists:
Permissions set for process <pid> - If the process does not exist:
Error: Unable to set permissions for process <pid>
Below is the output of running the set_perm_test program in the xv6 shell:
$ set_perm_test 2 4
Permissions set for process 2$ set_perm_test 999 5
Error: Unable to set permissions for process 999Welcome to csh, a custom shell written in C that brings the power of basic UNIX-like commands right to your fingertips! Designed to provide a smooth and intuitive command-line experience, csh supports essential file and text manipulation commands, making it a great project for exploring low-level system programming.
ls- List directory contentscat- Display file contentsgrep- Search for patterns within fileswc- Count words, lines, and characters in filesmv- Move or rename filesrm- Remove filesdate- Display the current date and timecalc- Perform arithmetic calculationstodo- Manage a to-do listtouch- Create a filedf- Displays disk memory usagehead- Output first 5 lines of a filetail- Output last 5 lines of a filefind- Search for patterns within filenames
To try out Csh, clone the repository and compile the code as follows:
# Clone the repository
git clone https://github.com/rzeta-10/OS-Project.git
cd Project2_Csh
# Compile the shell program
make clean
make
# Run the shell
./cshellOnce csh is running, you can start using the supported commands just as you would in a typical UNIX shell. Here are a few examples with images of each command in action:
You can use the Up Arrow (β) and Down Arrow (β) keys to navigate through previously executed commands
lsls -lcat filename.txtgrep 'pattern' filename.txtwc filename.txtmv oldname.txt newname.txtrm filename.txtdatecalc 10 + 5
calc 15 / 3
calc 7 * 8todo add "Finish homework"
todo list
todo delete 1touch filename df head filenametail filenamefind . "pattern"main.c- Launches a new terminal instance and executes the custom shellshell.cshell.c- Core implementation of the shell.Makefile- For building the project with ease.README.md- Youβre reading it!
- C - For low-level system programming and managing system calls.
- UNIX System Calls - For executing commands, handling files, and managing processes.
This project is a deep dive into understanding how a shell operates at a fundamental level, making it a great hands-on experience with system-level programming. Itβs compact, practical, and covers essential shell functionality, perfect for anyone curious about what goes on behind the scenes of a command-line interface.