From 12ca7b35b0956c78120878bddfd0797f32b209a9 Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Sun, 22 Sep 2024 23:34:10 -0700 Subject: [PATCH 1/7] basic watch func setup --- Makefile | 1 + user/watch.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 user/watch.c diff --git a/Makefile b/Makefile index 2584e4a..a016c8f 100644 --- a/Makefile +++ b/Makefile @@ -131,6 +131,7 @@ UPROGS=\ $U/_usertests\ $U/_grind\ $U/_wc\ + $U/_watch\ $U/_zombie\ fs.img: mkfs/mkfs README.md $(UPROGS) diff --git a/user/watch.c b/user/watch.c new file mode 100644 index 0000000..7363cd6 --- /dev/null +++ b/user/watch.c @@ -0,0 +1,41 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + + + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: watch \n"); + exit(1); + } + // Run the provided command in an infinite loop + printf("%d\n",argc); + printf("%s\n",argv); + while (1) { + + int command = fork(); + if (command < 0) { + // Fork failed + printf("Failed to fork\n"); + } + + if (command == 0) { + // Child process + exec(argv[1], &argv[1]); + // If exec fails, print an error and exit the child + printf("Failed to execute command: %s\n", argv[1]); + exit(1); + } else { + // Parent process waits for the child to finish + int status; + wait(&status); + + // Sleep for 2 seconds (sleep takes argument in ticks, 1 tick = 100ms, so 20 ticks = 2 seconds) + sleep(10); + } + + exit(0); // Exit with success status + } + +} From 4788f2944ae3f2f4ae79bf3ab59f85236055f8f6 Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Fri, 27 Sep 2024 16:22:51 -0700 Subject: [PATCH 2/7] test pause func --- kernel/console.c | 5 +++++ kernel/defs.h | 2 +- kernel/proc.c | 23 +++++++++++++++++++++++ kernel/trap.c | 2 ++ user/watch.c | 7 ++++--- 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/kernel/console.c b/kernel/console.c index 05dc526..dce84a2 100644 --- a/kernel/console.c +++ b/kernel/console.c @@ -155,6 +155,11 @@ consoleintr(int c) consputc(BACKSPACE); } break; + case C('C'): + killwithname("watch"); + + break; + default: if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){ c = (c == '\r') ? '\n' : c; diff --git a/kernel/defs.h b/kernel/defs.h index a3c962b..1ac072b 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -106,7 +106,7 @@ void yield(void); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len); void procdump(void); - +void killwithname(char *name); // swtch.S void swtch(struct context*, struct context*); diff --git a/kernel/proc.c b/kernel/proc.c index 031eeb5..1983814 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -688,3 +688,26 @@ procdump(void) printf("\n"); } } + + +static int +strcmp(const char *p, const char *q) +{ + while (*p && *q == *q){ + p++, q++; + }return (uchar)*p - (uchar)*q; +} + +void killwithname(char *name) +{ + struct proc *p; + for(p = proc; p < &proc[NPROC]; p++){ + if(p->state == UNUSED){ + continue; + if(p->state >= 0 && strcmp((const char*) name, (const char*)(p->name))==0){ + kill(p->pid); + break; + } + } + } +} diff --git a/kernel/trap.c b/kernel/trap.c index 512c850..d12beb2 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -6,6 +6,8 @@ #include "proc.h" #include "defs.h" +#define CTRL_C_KEY 0x3 //define ctrl+c in ascii value + struct spinlock tickslock; uint ticks; diff --git a/user/watch.c b/user/watch.c index 7363cd6..7ec1a29 100644 --- a/user/watch.c +++ b/user/watch.c @@ -12,6 +12,7 @@ int main(int argc, char *argv[]) { // Run the provided command in an infinite loop printf("%d\n",argc); printf("%s\n",argv); + while (1) { int command = fork(); @@ -32,10 +33,10 @@ int main(int argc, char *argv[]) { wait(&status); // Sleep for 2 seconds (sleep takes argument in ticks, 1 tick = 100ms, so 20 ticks = 2 seconds) - sleep(10); - } + sleep(10); + } + } exit(0); // Exit with success status - } } From 94a2768a899f3055749bce10e766a79ec7c43a7b Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Fri, 27 Sep 2024 19:10:56 -0700 Subject: [PATCH 3/7] pause works --- kernel/console.c | 2 +- kernel/proc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/console.c b/kernel/console.c index dce84a2..968c474 100644 --- a/kernel/console.c +++ b/kernel/console.c @@ -157,7 +157,7 @@ consoleintr(int c) break; case C('C'): killwithname("watch"); - + break; break; default: diff --git a/kernel/proc.c b/kernel/proc.c index 1983814..5f483ac 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -693,7 +693,7 @@ procdump(void) static int strcmp(const char *p, const char *q) { - while (*p && *q == *q){ + while (*p && *p == *q){ p++, q++; }return (uchar)*p - (uchar)*q; } @@ -704,10 +704,10 @@ void killwithname(char *name) for(p = proc; p < &proc[NPROC]; p++){ if(p->state == UNUSED){ continue; + } if(p->state >= 0 && strcmp((const char*) name, (const char*)(p->name))==0){ kill(p->pid); break; } } - } } From e1305c013528b3baa8505788c47f2a0c412d9205 Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Mon, 30 Sep 2024 17:25:58 -0700 Subject: [PATCH 4/7] test merge --- README.md | 24 +++++++++ user/watch.c | 147 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 144 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 8524b54..46f0801 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,27 @@ ![FogOS](docs/fogos.gif) +Watch Command Documentation + +Overview: +The custom watch command in OS4 executes a specified command repeatedly at set intervals with optional features for logging and displaying a header. + +Features: +Customizable Interval (-n): Specify interval in seconds between executions (default is 2 seconds). +Display Header (-h): Show current timestamp before each execution. +Log Output (-o): Write command output to a file instead of the console. +Pause and Quit: Using ctrl + c to pause and quit execution. + +Command Options: +-n : Set interval in seconds between command executions. +-h: Display a timesztamped header before each execution. +-o : Write output to a file instead of the console. + +Examples: +watch ls +watch -n 5 ls +watch -h -n 3 echo "Hello" +watch -o log.txt ls +watch -n 5 -h -o date_log.txt date + + diff --git a/user/watch.c b/user/watch.c index 7ec1a29..65c1fee 100644 --- a/user/watch.c +++ b/user/watch.c @@ -1,42 +1,135 @@ #include "kernel/types.h" -#include "kernel/stat.h" -#include "user/user.h" - +#include "kernel/stat.h" +#include "user/user.h" +#include "kernel/fcntl.h" +#include "kernel/fs.h" +void print_header(char *command, int fd) { + int time = uptime(); // Get current time in ticks +// char buf[100]; + int len = 0; + char *header = "\n--- "; + len += strlen(header); + write(fd, header, len); + + // Convert time to string + char time_str[20]; + int time_len = 0; + int temp = time; + do { + time_str[time_len++] = (temp % 10) + '0'; + temp /= 10; + } while (temp > 0); + // Reverse the string + for (int i = 0; i < time_len / 2; i++) { + char t = time_str[i]; + time_str[i] = time_str[time_len - 1 - i]; + time_str[time_len - 1 - i] = t; + } + write(fd, time_str, time_len); + + char *ticks = " ticks: "; + write(fd, ticks, strlen(ticks)); + write(fd, command, strlen(command)); + write(fd, " ---\n", 5); +} int main(int argc, char *argv[]) { if (argc < 2) { - printf("Usage: watch \n"); + printf("Usage: watch [-n seconds] [-h] [-o output_file] \n"); exit(1); } - // Run the provided command in an infinite loop - printf("%d\n",argc); - printf("%s\n",argv); - while (1) { - - int command = fork(); - if (command < 0) { - // Fork failed - printf("Failed to fork\n"); - } + int interval = 2; // Default interval + int command_start = 1; + int show_header = 0; + char *output_file = 0; - if (command == 0) { - // Child process - exec(argv[1], &argv[1]); - // If exec fails, print an error and exit the child - printf("Failed to execute command: %s\n", argv[1]); - exit(1); + // Parse options + while (command_start < argc && argv[command_start][0] == '-') { + if (strcmp(argv[command_start], "-n") == 0 && command_start + 1 < argc) { + interval = atoi(argv[command_start + 1]); + if (interval <= 0) { + printf("Invalid interval. Using default (2 seconds).\n"); + interval = 2; + } + command_start += 2; + } else if (strcmp(argv[command_start], "-h") == 0) { + show_header = 1; + command_start++; + } else if (strcmp(argv[command_start], "-o") == 0 && command_start + 1 < argc) { + output_file = argv[command_start + 1]; + command_start += 2; } else { - // Parent process waits for the child to finish - int status; - wait(&status); + printf("Unknown option: %s\n", argv[command_start]); + exit(1); + } + } - // Sleep for 2 seconds (sleep takes argument in ticks, 1 tick = 100ms, so 20 ticks = 2 seconds) - sleep(10); - } + if (command_start >= argc) { + printf("No command specified.\n"); + exit(1); } - exit(0); // Exit with success status + int log_fd = 1; // Default to stdout + if (output_file) { + log_fd = open(output_file, O_WRONLY | O_CREATE | O_TRUNC); + if (log_fd < 0) { + printf("Failed to open output file: %s\n", output_file); + exit(1); + } + } + + int paused = 0; + printf("Watch started. Press 'p' to pause/unpause, 'q' to quit.\n"); + + while (1) { + // Check for user input + char input; + if (read(0, &input, 1) > 0) { + if (input == 'p' || input == 'P') { + paused = !paused; + printf(paused ? "Paused. Press 'p' to resume.\n" : "Resumed.\n"); + continue; + } else if (input == 'q' || input == 'Q') { + printf("Quitting...\n"); + break; + } + } + + if (!paused) { + if (show_header) { + print_header(argv[command_start], log_fd); + } + int pid = fork(); + if (pid < 0) { + printf("Failed to fork\n"); + exit(1); + } + + if (pid == 0) { + // Child process + if (output_file) { + // Redirect stdout and stderr to the log file + close(1); + close(2); + dup(log_fd); + dup(log_fd); + } + exec(argv[command_start], &argv[command_start]); + printf("Failed to execute command: %s\n", argv[command_start]); + exit(1); + } else { + // Parent process + wait(0); + } + } + sleep(interval * 10); // sleep takes ticks, 1 second = 10 ticks + } + + if (output_file) { + close(log_fd); + } + exit(0); } From cb77e98bb633baf51d68333c476f544fa5ebd4f4 Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Mon, 30 Sep 2024 19:25:39 -0700 Subject: [PATCH 5/7] test watch pause fixed --- user/watch.c | 58 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/user/watch.c b/user/watch.c index 65c1fee..1a99833 100644 --- a/user/watch.c +++ b/user/watch.c @@ -80,10 +80,10 @@ int main(int argc, char *argv[]) { } } - int paused = 0; - printf("Watch started. Press 'p' to pause/unpause, 'q' to quit.\n"); - + // int paused = 0; + printf("Watch started. Press 'Ctrl-c' to pause and quit.\n"); while (1) { + /* // Check for user input char input; if (read(0, &input, 1) > 0) { @@ -96,35 +96,35 @@ int main(int argc, char *argv[]) { break; } } + */ + + if (show_header) { + print_header(argv[command_start], log_fd); + } - if (!paused) { - if (show_header) { - print_header(argv[command_start], log_fd); - } - - int pid = fork(); - if (pid < 0) { - printf("Failed to fork\n"); - exit(1); - } + int pid = fork(); + if (pid < 0) { + printf("Failed to fork\n"); + exit(1); + } - if (pid == 0) { - // Child process - if (output_file) { - // Redirect stdout and stderr to the log file - close(1); - close(2); - dup(log_fd); - dup(log_fd); - } - exec(argv[command_start], &argv[command_start]); - printf("Failed to execute command: %s\n", argv[command_start]); - exit(1); - } else { - // Parent process - wait(0); + if (pid == 0) { + // Child process + if (output_file) { + // Redirect stdout and stderr to the log file + close(1); + close(2); + dup(log_fd); + dup(log_fd); } - } + exec(argv[command_start], &argv[command_start]); + printf("Failed to execute command: %s\n", argv[command_start]); + exit(1); + } else { + // Parent process + wait(0); + } + sleep(interval * 10); // sleep takes ticks, 1 second = 10 ticks } From 8c25c176455eb8f6b7b2493964b8fa4abf70e921 Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Mon, 30 Sep 2024 23:44:51 -0700 Subject: [PATCH 6/7] readme update --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 46f0801..4c7a5d5 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,59 @@ ![FogOS](docs/fogos.gif) -Watch Command Documentation +# Watch Command Documentation -Overview: -The custom watch command in OS4 executes a specified command repeatedly at set intervals with optional features for logging and displaying a header. +@author zguo18 +@author yhatnagar -Features: -Customizable Interval (-n): Specify interval in seconds between executions (default is 2 seconds). -Display Header (-h): Show current timestamp before each execution. -Log Output (-o): Write command output to a file instead of the console. -Pause and Quit: Using ctrl + c to pause and quit execution. +## Overview + +The custom `watch` command implemented in OS4 allows you to execute a specified command repeatedly at set intervals. The command comes with optional features for logging the output, displaying a header, and controlling the execution through pause and quit options. + +## Features + +1. Customizable Interval (`-n`): Specify the interval in seconds between command executions. The default interval is 2 seconds. + +2. Display Header (`-h`): Option to display the current timestamp in ticks before each command execution. + +3. Log Output (`-o`): Write the output of the command to a specified file instead of displaying it in the console. + +Pause and Quit (Ctrl+C): Press Ctrl+C to both pause and quit the command. When Ctrl+C is pressed, the system interrupts and stops the execution entirely. + +## Command Options implemented -Command Options: -n : Set interval in seconds between command executions. --h: Display a timesztamped header before each execution. +-h: Display a timestamped header before each execution. -o : Write output to a file instead of the console. -Examples: -watch ls -watch -n 5 ls -watch -h -n 3 echo "Hello" -watch -o log.txt ls -watch -n 5 -h -o date_log.txt date +## Command Examples + +Here are some examples of how to use the custom `watch` command: + +- watch ls + +This runs the `ls` command every 2 seconds and prints the output to the console. + +- watch -n 5 ls + +This runs the `ls` command every 5 seconds instead of the default 2 seconds. + + +- watch -h -n 3 echo "Hello" + + This runs the `echo "Hello"` command every 3 seconds and displays a timestamp header before each execution. + + +- watch -o log.txt ls + +This runs the `ls` command every 2 seconds and writes the output to `log.txt` instead of printing it to the console. + +- watch -n 5 -h -o date_log.txt date + +This runs the `date` command every 5 seconds, displays a timestamped header, and logs the output to `date_log.txt`. + + +The watch command was implemented in C in an OS environment. It uses system calls such as fork(), exec(), and uptime() to execute the commands at set intervals, manage processes, and retrieve system time in ticks. +The command also supports logging output to files by redirecting standard output and error streams to the specified file. For the pause and quit functionality, user input handling is employed to capture keypresses, though some functionality may depend on the specific OS shell configuration. From 795e9ac6a70e02ddfd62dfd8dc458d225bc6af17 Mon Sep 17 00:00:00 2001 From: Zijie Guo Date: Sun, 10 Nov 2024 21:56:30 -0800 Subject: [PATCH 7/7] clean up code and xv6 style --- kernel/memlayout.h | 2 ++ kernel/syscall.c | 2 ++ kernel/syscall.h | 1 + kernel/sysproc.c | 8 +++++++ user/user.h | 1 + user/watch.c | 52 ++++++---------------------------------------- 6 files changed, 20 insertions(+), 46 deletions(-) diff --git a/kernel/memlayout.h b/kernel/memlayout.h index 776f98c..0bc72c2 100644 --- a/kernel/memlayout.h +++ b/kernel/memlayout.h @@ -65,3 +65,5 @@ // TRAPFRAME (p->trapframe, used by the trampoline) // TRAMPOLINE (the same page as in the kernel) #define TRAPFRAME (TRAMPOLINE - PGSIZE) +//define goldfish mem add +#define GOLDFISH_RTC 0x101000 diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..993c1d2 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,6 +101,7 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_gettime(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +127,7 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_gettime] sys_gettime, }; void diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..6d6c224 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,4 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_gettime 22 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 1de184e..02e43e2 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -89,3 +89,11 @@ sys_uptime(void) release(&tickslock); return xticks; } + +//get time stamp +uint64 +sys_gettime(void){ + volatile uint64 *test_dev = (uint64 *)GOLDFISH_RTC; + uint64 time = *test_dev; + return time; +} diff --git a/user/user.h b/user/user.h index 2e6fc55..0e88def 100644 --- a/user/user.h +++ b/user/user.h @@ -22,6 +22,7 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +uint64 gettime(void); // ulib.c int stat(const char*, struct stat*); diff --git a/user/watch.c b/user/watch.c index 1a99833..8867451 100644 --- a/user/watch.c +++ b/user/watch.c @@ -4,36 +4,11 @@ #include "kernel/fcntl.h" #include "kernel/fs.h" -void print_header(char *command, int fd) { - int time = uptime(); // Get current time in ticks -// char buf[100]; - int len = 0; - char *header = "\n--- "; - len += strlen(header); - write(fd, header, len); - - // Convert time to string - char time_str[20]; - int time_len = 0; - int temp = time; - do { - time_str[time_len++] = (temp % 10) + '0'; - temp /= 10; - } while (temp > 0); - // Reverse the string - for (int i = 0; i < time_len / 2; i++) { - char t = time_str[i]; - time_str[i] = time_str[time_len - 1 - i]; - time_str[time_len - 1 - i] = t; - } - write(fd, time_str, time_len); - - char *ticks = " ticks: "; - write(fd, ticks, strlen(ticks)); - write(fd, command, strlen(command)); - write(fd, " ---\n", 5); +void print_header(char *command, int fd, uint64 start_time) { + fprintf(fd,"\n---%d ms:%s ---\n",(uptime()-start_time)*100,command); } + int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: watch [-n seconds] [-h] [-o output_file] \n"); @@ -44,6 +19,7 @@ int main(int argc, char *argv[]) { int command_start = 1; int show_header = 0; char *output_file = 0; + uint64 start_time=uptime(); // Parse options while (command_start < argc && argv[command_start][0] == '-') { @@ -83,23 +59,8 @@ int main(int argc, char *argv[]) { // int paused = 0; printf("Watch started. Press 'Ctrl-c' to pause and quit.\n"); while (1) { - /* - // Check for user input - char input; - if (read(0, &input, 1) > 0) { - if (input == 'p' || input == 'P') { - paused = !paused; - printf(paused ? "Paused. Press 'p' to resume.\n" : "Resumed.\n"); - continue; - } else if (input == 'q' || input == 'Q') { - printf("Quitting...\n"); - break; - } - } - */ - if (show_header) { - print_header(argv[command_start], log_fd); + print_header(argv[command_start], log_fd, start_time); } int pid = fork(); @@ -123,8 +84,7 @@ int main(int argc, char *argv[]) { } else { // Parent process wait(0); - } - + } sleep(interval * 10); // sleep takes ticks, 1 second = 10 ticks }