diff --git a/.gitignore b/.gitignore
index c6127b3..b231303 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,52 +1,31 @@
-# Prerequisites
-*.d
-
-# Object files
+*
+!/**/
+!*.*
+# Compiled Object files
+*.slo
+*.lo
*.o
-*.ko
*.obj
-*.elf
-
-# Linker output
-*.ilk
-*.map
-*.exp
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
# Executables
*.exe
*.out
*.app
-*.i*86
-*.x86_64
-*.hex
+**/*.out
+*/outDebug
+
+#
+*/build/Debug/outDebug
+*/output.txt
+*.exe
+*.out
+*.app
-# Debug files
-*.dSYM/
-*.su
-*.idb
-*.pdb
+*.Identifier
+gcc_errors.txt
+*tests*
+*old
+*.txt*
+*.csv
-# Kernel Module Compile Results
-*.mod*
-*.cmd
-.tmp_versions/
-modules.order
-Module.symvers
-Mkfile.old
-dkms.conf
+!makefile
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..fad9002
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,18 @@
+{
+ "configurations": [
+ {
+ "name": "linux-gcc-x64",
+ "includePath": [
+ "${workspaceFolder}/**"
+ ],
+ "compilerPath": "/usr/bin/gcc",
+ "cStandard": "${default}",
+ "cppStandard": "${default}",
+ "intelliSenseMode": "linux-gcc-x64",
+ "compilerArgs": [
+ "-lpthread"
+ ]
+ }
+ ],
+ "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..a6f0071
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,74 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "bashdb",
+ "request": "launch",
+ "name": "pick",
+ "cwd": "${workspaceFolder}",
+ "program": "${command:SelectScriptName}",
+ "args": []
+ },
+ {
+ "type": "bashdb",
+ "request": "launch",
+ "name": "gccfind",
+ "cwd": "${workspaceFolder}",
+ "terminalKind": "integrated",
+ "showDebugOutput": true,
+ "trace": true,
+ "program": "/home/bar/projects/OpSys/OpSystems/hw1/gccfind.sh",
+ "args": [
+ "hw1/ex-files",
+ "execvp",
+ "-r"
+ ]
+ },
+ {
+ "type": "bashdb",
+ "request": "launch",
+ "name": "Bash-Debug (simplest configuration)",
+ "program": "${file}"
+ },
+ {
+ "name": "prodcast",
+ "type": "cppdbg",
+ "request": "launch",
+ "args": [
+ "config.txt"
+ ],
+ "stopAtEntry": false,
+ "externalConsole": false,
+ "cwd": "/home/bar/projects/OpSys/OpSystems/hw3",
+ "program": "/home/bar/projects/OpSys/OpSystems/hw3/build/Debug/outDebug",
+ "MIMode": "gdb",
+ "miDebuggerPath": "/usr/bin/gdb",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ }
+ ]
+ },
+ {
+ "name": "C/C++ Runner: Debug Session",
+ "type": "cppdbg",
+ "request": "launch",
+ "args": [],
+ "stopAtEntry": false,
+ "externalConsole": false,
+ "cwd": "/home/bar/projects/OpSys/OpSystems/hw3",
+ "program": "/home/bar/projects/OpSys/OpSystems/hw3/build/Debug/outDebug",
+ "MIMode": "gdb",
+ "miDebuggerPath": "/usr/bin/gdb",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..4a0d339
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,90 @@
+{
+ "C_Cpp_Runner.cCompilerPath": "/usr/bin/gcc",
+ "C_Cpp_Runner.cppCompilerPath": "/usr/bin/g++",
+ "C_Cpp_Runner.debuggerPath": "/usr/bin/gdb",
+ "C_Cpp_Runner.cStandard": "",
+ "C_Cpp_Runner.cppStandard": "",
+ "C_Cpp_Runner.msvcBatchPath": "",
+ "C_Cpp_Runner.warnings": [
+ "-Wall",
+ "-Wextra",
+ "-Wpedantic"
+ ],
+ "C_Cpp_Runner.enableWarnings": true,
+ "C_Cpp_Runner.warningsAsError": false,
+ "C_Cpp_Runner.compilerArgs": [
+ "-lpthread"
+ ],
+ "C_Cpp_Runner.linkerArgs": [
+ "-lpthread"
+ ],
+ "C_Cpp_Runner.includePaths": [],
+ "C_Cpp_Runner.includeSearch": [
+ "*",
+ "**/*"
+ ],
+ "C_Cpp_Runner.excludeSearch": [
+ "**/build",
+ "**/build/**",
+ "**/.*",
+ "**/.*/**",
+ "**/.vscode",
+ "**/.vscode/**"
+ ],
+ "files.associations": {
+ "cmath": "c",
+ "*.tcc": "c",
+ "condition_variable": "cpp",
+ "mutex": "cpp",
+ "array": "cpp",
+ "atomic": "cpp",
+ "bit": "cpp",
+ "cctype": "cpp",
+ "chrono": "cpp",
+ "clocale": "cpp",
+ "cstdarg": "cpp",
+ "cstddef": "cpp",
+ "cstdint": "cpp",
+ "cstdio": "cpp",
+ "cstdlib": "cpp",
+ "ctime": "cpp",
+ "cwchar": "cpp",
+ "cwctype": "cpp",
+ "deque": "cpp",
+ "unordered_map": "cpp",
+ "vector": "cpp",
+ "exception": "cpp",
+ "algorithm": "cpp",
+ "functional": "cpp",
+ "iterator": "cpp",
+ "memory": "cpp",
+ "memory_resource": "cpp",
+ "numeric": "cpp",
+ "optional": "cpp",
+ "random": "cpp",
+ "ratio": "cpp",
+ "string": "cpp",
+ "string_view": "cpp",
+ "system_error": "cpp",
+ "tuple": "cpp",
+ "type_traits": "cpp",
+ "utility": "cpp",
+ "fstream": "cpp",
+ "initializer_list": "cpp",
+ "iosfwd": "cpp",
+ "iostream": "cpp",
+ "istream": "cpp",
+ "limits": "cpp",
+ "new": "cpp",
+ "ostream": "cpp",
+ "sstream": "cpp",
+ "stdexcept": "cpp",
+ "streambuf": "cpp",
+ "thread": "cpp",
+ "typeinfo": "cpp"
+ },
+ "cSpell.words": [
+ "qutex"
+ ],
+ "C_Cpp_Runner.useMsvc": false
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..749658a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,105 @@
+# OpSystems
+
+1. Ex1: ⚒️ Gcc Find; 🎾 Tennis ; 💲Shell
+
+
+ _____________________________________
+ > ⚒️ Gcc Find:
+ > a nice little script for compiling all the c files in the folder that contains a specific word. You can turn on th -r flag for recessiveness
+ >
⚙️How To⚙️
+ > - Clone the script to a folder of your choice
+ > - Run the gcc.sh file with the following params:
+ > 1. folder name to be compiled
+ > 2. a word. only files that contains the given word will be complied ::must!
+ > 3. optional: -r flag, if you want to compile the inner files as well.
+ >
+ >⚡ > ./gccfind.sh myFolder main -r
+
+ _____________________________________
+
+ > 🎾 Tennis (paper game):
+ > a funny little [tennis paper game](https://en.wikipedia.org/wiki/Tennis_(paper_game)), terminal styled.
+ > #### ⚙️How To⚙️
+ > There are two options for the game: in place game, and logged history game
+ > You can choose what to use by simply run the game with flags:
+ > * __for in place game:__ --in-place | -p
+ > * __for logged game :__ --l | -log
+ > * The default version is logged
+ >
+ > ⚡ > ./tennis.sh -p
+ _____________________________________
+ > 💲 Shell:
+ > a shell program that can be loaded with your custom commands
+ >
⚙️How To⚙️
+ > - compile myshell.c
gcc -o shell myshell.c
+ > - There are two options:
+ > you can run the runnable script without any other params.
+ > The program will act as you expect from a normal shell
+ > Or you can send path to a folder, which contains custom scrits. The folder be then added temporarily to your env variables,
+ > so you can can any script that is defined there by simply typing it's name.
+ > for example:
+ > if inside a folder named 'myCommands' you have a script named 'do-somthing.sh'
+ > you can run the shell with the path to 'myCommads', then you can just type
+ > do-something.sh
,
no matter what pwd you are in.
+ >
+ > ⚡ > ./myshell ~/myCommands
+ _____________________________________
+
+
+
+
+_______________________________________________________
+
+2. Ex2: 📂 File Comperator & Grader
+
+
+ _____________________________________
+ > 2.1: Files Comperator
+ > a program that get two arguments of file pathes and determines the similarity:
+ > 🔖 1: The files are identical
+ > 🔖 2: The files are different
+ > 🔖 3: The files are similar
+ >
+ > ⚡ > ./comp.out /home/os20 12 /code/1.txt /home/os20 12 /code/2.txt
+ >
+ >
+
+ _____________________________________
+ > 2.2: Grader
+ > A program that gets config path and grades the folders by that
+ > The config file contains 3 rows:
+ > ✏️ 1: Path to parent folder which contains sub-folders for grade. Each folder is a user folder.
+ > ✏️ 2: Path to an input file for will-be executed program
+ > ✏️ 3: Path to correct output file
+ > The program iterates through the users' folders, compiles(if exists) the c file in that folder.
+ > Then runs the compiled program with the input file and comperes the results to the correct output from the config file.
+ > If anything in the way is getting wrong, the grade will be affected as listing here:
+ > > > > > > ✨ NO_C_FILE : 0
+ > > > > > > ✨ COMPILATION_ERROR: 10
+ > > > > > > ✨ TIMEOUT: 20
+ > > > > > > ✨ WRONG: 50
+ > > > > > > ✨ SIMILAR: 75
+ > The grade will be written into an excel file, named results.csv, which will be created inside the running folder.
+ >
+ > ⚡ > ./a.out /home/os20 12 /conf.txt
+ >
+ >
+ _____________________________________
+
+
+
+_______________________________________________________
+
+3. Ex3: 🗞️ Publisher: content producer-distributer-coeditor Threads Synchronization
+
+
+ _____________________________________
+ > A program that gets a config file for products per procuder, and coediting abilities.
+ > The program syncronizing the work of everyone by threads
+ >
To create executable you can use the makefile
+ > ⚡ > ./ex3.out config.txt
+ _____________________________________
+
+
+
+_______________________________________________________
diff --git a/eg.code/Code-1/T6_1.c b/eg.code/Code-1/T6_1.c
new file mode 100644
index 0000000..003c8ef
--- /dev/null
+++ b/eg.code/Code-1/T6_1.c
@@ -0,0 +1,34 @@
+//To compile: gcc -l pthread T6_1.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid;
+
+void printids(const char *s)
+{
+ pid_t pid;
+ pthread_t tid;
+
+ pid = getpid();
+ tid = pthread_self();
+ printf("%s pid %u tid %u\n", s, (unsigned int)pid,(unsigned int)tid);
+}
+
+void* thr_fn(void *arg)
+{
+ printids("new thread: ");
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ err = pthread_create(&ntid, NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+ printids("main thread:");
+ sleep(1);
+ exit(0);
+}
diff --git a/eg.code/Code-1/T6_2.c b/eg.code/Code-1/T6_2.c
new file mode 100644
index 0000000..fdf9221
--- /dev/null
+++ b/eg.code/Code-1/T6_2.c
@@ -0,0 +1,47 @@
+//To compile: gcc -l pthread T6_2.c
+#include
+#include
+
+int int_Val[5] = {0,0,0,0,0};
+pthread_t th[5];
+
+void *add_to_value(void *arg) { // arg = 0, 1, 2, 3 ,4
+ int inData = *((int*)arg);
+ int i;
+ for(i = 0; i < 10000; i++){
+ int_Val[i % 5] += inData; /* ? */
+ }
+
+ /* Expectation (under the incorrect assumption that threads will run one after another for sure):
+ thread 0: [0,0,0,0,0] (+0 to each cell)
+ thread 1: [2000,2000,2000,2000,2000] (+1*2000=2000 to each cell)
+ thread 2: [6000,6000,6000,6000,6000] (+2*2000=4000 to each cell)
+ thread 3: [12000,12000,12000,12000,12000] (+3*2000=6000 to each cell)
+ thread 4: [20000,20000,20000,20000,20000] (+4*2000=8000 to each cell)
+ */
+
+ return (NULL);
+}
+
+int main(void) {
+ int i, retcode;
+
+ /* Create the threads */
+ for(i = 0; i < 5; i++) {
+ retcode = pthread_create(&th[i], NULL, add_to_value, (void *)&i);
+ if (retcode != 0)
+ printf("Create thread failed with error %d\n", retcode);
+ }
+
+ /* Wait until all threads have finished */
+ void* retVal[5];
+ for(i = 0; i < 5; i++){
+ pthread_join(th[i], &retVal[i]);
+ }
+
+ /* Print the results */
+ printf("Final values:\n");
+ for(i = 0; i < 5; i++)
+ printf("Integer value[%d] = \t%d\n", i, int_Val[i]);
+ return 0;
+}
diff --git a/eg.code/Code-1/T6_3.c b/eg.code/Code-1/T6_3.c
new file mode 100644
index 0000000..7860268
--- /dev/null
+++ b/eg.code/Code-1/T6_3.c
@@ -0,0 +1,35 @@
+//To compile: gcc -l pthread T6_3.c
+#include
+#include
+#include
+#include
+#include
+
+pthread_t ntid[2];
+
+void* thr_fn(void *arg)
+{
+ int i;
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(1);
+ }
+
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ int i;
+ for(i=0;i<2;i++)
+ {
+ err = pthread_create(&ntid[i], NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+ }
+
+ sleep(1);
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/Code-1/T6_4.c b/eg.code/Code-1/T6_4.c
new file mode 100644
index 0000000..3c6668a
--- /dev/null
+++ b/eg.code/Code-1/T6_4.c
@@ -0,0 +1,38 @@
+//To compile: gcc -l pthread T6_4.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid;
+
+void* thr_fn(void *arg)
+{
+ int i,x;
+ x=fork();
+ if(x==0){ // run this code twice: with > and with ==
+ return((void *)0);
+ }
+
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(1);
+ }
+
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ void *retVal;
+ int i;
+ err = pthread_create(&ntid, NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+
+ pthread_join(ntid, &retVal);
+ printf("returned\n");
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/Code-1/T6_4_New.c b/eg.code/Code-1/T6_4_New.c
new file mode 100644
index 0000000..aa28e5e
--- /dev/null
+++ b/eg.code/Code-1/T6_4_New.c
@@ -0,0 +1,38 @@
+//To compile: gcc -l pthread t6_4_New.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid;
+
+void* thr_fn(void *arg)
+{
+ int i,x;
+ x=fork();
+ if(x>0){ // run this code twice: with > and with ==
+ return((void *)0);
+ }
+
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(1);
+ }
+
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ void *retVal;
+ int i;
+ err = pthread_create(&ntid, NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+
+ pthread_join(ntid, &retVal);
+ printf("returned\n");
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/Code-1/T6_5.c b/eg.code/Code-1/T6_5.c
new file mode 100644
index 0000000..ac45aaa
--- /dev/null
+++ b/eg.code/Code-1/T6_5.c
@@ -0,0 +1,39 @@
+//To compile: gcc -l pthread T6_5.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid[2];
+pthread_t ltid;
+void* thr_fn(void *arg)
+{
+ int i;
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(2);
+ }
+
+ return((void *)0);
+}
+void* thr_fn2(void *arg)
+{
+ execl("/bin/ls", "ls", (char*)NULL);
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ int i;
+ for(i=0;i<2;i++)
+ err = pthread_create(&ntid[i], NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+
+ sleep(1);
+ pthread_create(<id, NULL, thr_fn2, NULL);
+ printf("I'm done\n");
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/Code-1/T6_6.c b/eg.code/Code-1/T6_6.c
new file mode 100644
index 0000000..c4d6982
--- /dev/null
+++ b/eg.code/Code-1/T6_6.c
@@ -0,0 +1,43 @@
+// To compile: gcc -l pthread T6_6.c
+// thread synchronization problem
+
+#include
+#include
+#include
+#include
+#include
+
+pthread_t tid[10];
+int counter=0;
+
+void* doSomeThing(void *arg)
+{
+ unsigned long i = 0;
+
+ for(i=0; i<1000000;i++)
+ counter++;
+
+ return NULL;
+}
+
+int main(void)
+{
+ int i = 0;
+ int err;
+
+ while(i < 10)
+ {
+ err = pthread_create(&tid[i], NULL, doSomeThing, NULL);
+ if (err != 0)
+ printf("\ncan't create thread :[%s]", strerror(err));
+ i++;
+ }
+
+ for (i=0;i<10;i++)
+ pthread_join(tid[i], NULL);
+
+
+ printf("counter value is: %d\n",counter);
+
+ return 0;
+}
diff --git a/eg.code/Code-1/T6_7.c b/eg.code/Code-1/T6_7.c
new file mode 100644
index 0000000..a06e039
--- /dev/null
+++ b/eg.code/Code-1/T6_7.c
@@ -0,0 +1,51 @@
+//To compile: gcc -l pthread T6_7.c
+//thread synchronization problem - mutex solution
+#include
+#include
+#include
+#include
+#include
+
+pthread_t tid[10];
+int counter=0;
+
+pthread_mutex_t lock;
+
+void* doSomeThing(void *arg)
+{
+ unsigned long i = 0;
+ pthread_mutex_lock(&lock);
+ for(i=0; i<1000000;i++)
+ counter++;
+ pthread_mutex_unlock(&lock);
+
+ return NULL;
+}
+
+int main(void)
+{
+ int i = 0;
+ int err;
+
+ if (pthread_mutex_init(&lock, NULL) != 0)
+ {
+ printf("\n mutex init failed\n");
+ return 1;
+ }
+
+ while(i < 10)
+ {
+ err = pthread_create(&tid[i], NULL, doSomeThing, NULL);
+ //printf("created\n");
+ if (err != 0)
+ printf("\ncan't create thread :[%s]", strerror(err));
+ i++;
+ }
+ for (i=0;i<10;i++)
+ pthread_join(tid[i], NULL);
+ printf("counter value is: %d\n",counter);
+
+ pthread_mutex_destroy(&lock);
+
+ return 0;
+}
diff --git a/eg.code/Code/T4_1.c b/eg.code/Code/T4_1.c
new file mode 100644
index 0000000..47d8fb9
--- /dev/null
+++ b/eg.code/Code/T4_1.c
@@ -0,0 +1,29 @@
+#include
+#include
+#include
+
+int main (int argc, char* argv[])
+{
+ char* filename = argv[1];
+ char msg[64];
+
+ struct stat stat_p;
+
+ if(stat(filename, &stat_p) == -1)
+ {
+ sprintf(msg," Error occurred attempting to stat %s\n", filename); // printf
+ perror(msg);
+ return 1;
+ }
+
+ printf("Stats for %s \n", filename);
+ printf("File size is %ld bytes\n", stat_p.st_size);
+
+ if(S_ISREG(stat_p.st_mode))
+ printf("This is a regular file\n");
+
+ if(S_ISDIR(stat_p.st_mode))
+ printf("This is a directory\n");
+
+ return 0;
+}
diff --git a/eg.code/Code/T4_2.c b/eg.code/Code/T4_2.c
new file mode 100644
index 0000000..6d78975
--- /dev/null
+++ b/eg.code/Code/T4_2.c
@@ -0,0 +1,58 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ struct stat sb;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s \n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(argv[1], &sb) == -1) {
+ perror("stat");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("File type: ");
+
+ if(S_ISBLK(sb.st_mode))
+ printf("block device\n");
+ else if(S_ISCHR(sb.st_mode))
+ printf("character device\n");
+ else if(S_ISDIR(sb.st_mode))
+ printf("directory\n");
+ else if(S_ISFIFO(sb.st_mode))
+ printf("FIFO/pipe\n");
+ else if(S_ISLNK(sb.st_mode))
+ printf("symlink\n");
+ else if(S_ISREG(sb.st_mode))
+ printf("regular file\n");
+ else if(S_ISSOCK(sb.st_mode))
+ printf("socket\n");
+ else
+ printf ("unknown\n");
+
+
+ printf("I-node number: %ld\n", (long) sb.st_ino);
+
+ printf("Mode: %lo (octal)\n", (unsigned long) sb.st_mode);
+
+ printf("Link count: %ld\n", (long) sb.st_nlink);
+ printf("Ownership: UID=%ld GID=%ld\n",(long) sb.st_uid, (long) sb.st_gid);
+
+ printf("Preferred I/O block size: %ld bytes\n", (long) sb.st_blksize);
+ printf("File size: %lld bytes\n", (long long) sb.st_size);
+ printf("Blocks allocated: %lld\n",(long long) sb.st_blocks);
+
+ printf("Last status change: %s", ctime(&sb.st_ctime));
+ printf("Last file access: %s", ctime(&sb.st_atime));
+ printf("Last file modification: %s", ctime(&sb.st_mtime));
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/eg.code/T5code/Code/T5_2.c b/eg.code/T5code/Code/T5_2.c
new file mode 100644
index 0000000..d07ee62
--- /dev/null
+++ b/eg.code/T5code/Code/T5_2.c
@@ -0,0 +1,43 @@
+#include
+#include
+#include
+#include
+#define SIZE 10
+
+main(int argc , char argv)
+{
+ int fdin; /* input file descriptor */
+ int fdout; /* out file descriptor */
+ char buf[SIZE+1]; /* input (output) buffer */
+ int charsr; /* how many chars were actually red */
+ int charsw; /* how many chars were actually written */
+
+
+ fdin = open("dugma1.txt",O_RDONLY);
+ if (fdin < 0) /* means file open did not take place */
+ {
+ perror("after open "); /* text explaining why */
+ exit(-1);
+ }
+ /* create the file with read-write premissions */
+ fdout = open("dugma2.txt", O_CREAT | O_RDWR, 0666);
+ if (fdout < 0) /* means file open did not take place */
+ {
+ perror("after create "); /* text explaining why */
+ exit(-1);
+ }
+
+ do
+ {
+ charsr = read(fdin,buf,SIZE);
+ /* why writing SIZE can be wrong...*/
+ charsw = write(fdout,buf,charsr);
+ if (charsw < charsr)
+ {
+ printf("error reading\n");
+ }
+ }while ( (charsr == SIZE) && (charsw == SIZE));
+ close(fdin); /* free allocated structures */
+ close(fdout); /* free allocated structures */
+}
+
diff --git a/eg.code/T5code/Code/T5_3.c b/eg.code/T5code/Code/T5_3.c
new file mode 100644
index 0000000..efca4e1
--- /dev/null
+++ b/eg.code/T5code/Code/T5_3.c
@@ -0,0 +1,27 @@
+#include
+#include
+#include
+int main(int argc, char **argv)
+{
+ int pid, status;
+ int newfd; /* new file descriptor */
+ if (argc != 2)
+ {
+ fprintf(stderr, "usage: %s output_file\n", argv[0]);
+ exit(1);
+ }
+ if ((newfd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY, 0644)) < 0)
+ {
+ perror(argv[1]); /* open failed */
+ exit(1);
+ }
+ printf("This goes to the standard output.\n");
+ printf("Now the standard output will go to \"%s\".\n", argv[1]);
+ /* this new file will become the standard output */
+ /*standard output is file descriptor 1, so we use dup2 */
+ /* to copy the new file descriptor onto file descriptor 1 */
+ /* dup2 will close the current standard output */
+ dup2(newfd, 1);
+ printf("This goes to the file.\n");
+ exit(0);
+}
diff --git a/eg.code/T5code/Code/T5_4.c b/eg.code/T5code/Code/T5_4.c
new file mode 100644
index 0000000..bed0778
--- /dev/null
+++ b/eg.code/T5code/Code/T5_4.c
@@ -0,0 +1,47 @@
+#include
+#include
+#include
+#include
+#include
+
+#define NEWFILE (O_WRONLY | O_CREAT | O_TRUNC )
+#define MODE600 (S_IRUSR | S_IWUSR)
+#define SIZE 10
+
+void fileCopy(char* inPath, char* outPath)
+{
+ char buf[SIZE];
+ int in,out,count;
+
+ if((in=open(inPath,O_RDONLY))==-1)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ if((out=open(outPath,NEWFILE,MODE600))==-1)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ while((count=read(in,buf,sizeof(buf)))>0)
+ {
+ if(write(out,buf,count)!=count)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ }
+ if(count==-1)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ close(in);
+ close(out);
+}
+
+
+int main()
+{
+ fileCopy("in.txt","out.txt");
+}
diff --git a/eg.code/T5code/Code/T5_5.c b/eg.code/T5code/Code/T5_5.c
new file mode 100644
index 0000000..d7f0c0d
--- /dev/null
+++ b/eg.code/T5code/Code/T5_5.c
@@ -0,0 +1,101 @@
+#include
+#include
+#include
+#include
+
+#define NEWFILE (O_WRONLY | O_CREAT | O_TRUNC )
+#define MODE600 (S_IRUSR | S_IWUSR)
+#define SIZE 10
+#define BUF_SIZE 1024
+
+int my_read(int fd,char *buf,size_t count)
+{
+ static char read_buf[BUF_SIZE];
+ static int read_offset =BUF_SIZE;
+ static int read_max=BUF_SIZE;
+ int i;
+ for(i=0;i0)
+ write(fd,write_buf,write_offset);
+
+ write_offset=0;
+ return close(fd);
+}
+
+void fileCopy(char* inPath, char* outPath)
+{
+ char buf[SIZE];
+ int in,out,count;
+
+ if((in=open(inPath,O_RDONLY))==-1)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ if((out=open(outPath,NEWFILE,MODE600))==-1)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ while((count=my_read(in,buf,sizeof(buf)))>0)
+ {
+ if(my_write(out,buf,count)!=count)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ }
+ if(count==-1)
+ {
+ printf("error\n");
+ exit(0);
+ }
+ close(in);
+ write_close(out);
+}
+
+
+int main()
+{
+ fileCopy("in.txt","out.txt");
+}
diff --git a/eg.code/T5code/Code/dup_exec_example.c b/eg.code/T5code/Code/dup_exec_example.c
new file mode 100644
index 0000000..ba665a3
--- /dev/null
+++ b/eg.code/T5code/Code/dup_exec_example.c
@@ -0,0 +1,28 @@
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char** argv)
+{
+ int in, out;
+ char* grep_args[] = {"grep", "Villanova", NULL};
+
+ // open input and output files
+ in = open("scores", O_RDONLY);
+ out = open("out", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWGRP | S_IWUSR);
+
+ // replace standard input with input file
+ dup2(in, 0);
+
+ // replace standard output with output file
+ dup2(out, 1);
+
+ // close unused file descriptors
+ close(in);
+ close(out);
+
+ // execute grep
+ execvp("grep", grep_args);
+}
diff --git a/eg.code/T5code/Code/ls_implementation.c b/eg.code/T5code/Code/ls_implementation.c
new file mode 100644
index 0000000..d077e55
--- /dev/null
+++ b/eg.code/T5code/Code/ls_implementation.c
@@ -0,0 +1,41 @@
+#include
+#include
+
+int listdir(const char* path)
+{
+ struct dirent* entry;
+ DIR* dp;
+
+ dp = opendir(path);
+ if(dp == NULL)
+ {
+ perror("opendir");
+ return -1;
+ }
+
+ while((entry = readdir(dp)) != NULL)
+ {
+ puts(entry->d_name);
+ }
+
+ closedir(dp);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int counter = 1;
+
+ if(argc == 1)
+ {
+ listdir(".");
+ }
+
+ while(++counter <= argc)
+ {
+ printf("\nListing %s...\n", argv[counter - 1]);
+ listdir(argv[counter - 1]);
+ }
+
+ return 0;
+}
diff --git a/eg.code/T5code/Code/scan_dir_example.c b/eg.code/T5code/Code/scan_dir_example.c
new file mode 100644
index 0000000..7dcf4d5
--- /dev/null
+++ b/eg.code/T5code/Code/scan_dir_example.c
@@ -0,0 +1,40 @@
+#include
+#include
+#include
+#include
+
+int main(int argc, char* argv[])
+{
+ DIR* dip;
+ struct dirent* dit;
+ int i = 0;
+
+ if(argc < 2)
+ {
+ printf("Usage: %s \n", argv[0]);
+ return 0;
+ }
+
+ if((dip = opendir(argv[1])) == NULL)
+ {
+ perror("opendir");
+ return 0;
+ }
+
+ printf("Directory stream is now open\n");
+
+ while((dit = readdir(dip)) != NULL)
+ {
+ i++;
+ printf("\n%s", dit->d_name);
+ }
+
+ if(closedir(dip) == -1)
+ {
+ perror("closedir");
+ return 0;
+ }
+
+ printf("\nDirectory stream is now closed\n");
+ return 1;
+}
diff --git a/eg.code/T6Code/T6_1.c b/eg.code/T6Code/T6_1.c
new file mode 100644
index 0000000..003c8ef
--- /dev/null
+++ b/eg.code/T6Code/T6_1.c
@@ -0,0 +1,34 @@
+//To compile: gcc -l pthread T6_1.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid;
+
+void printids(const char *s)
+{
+ pid_t pid;
+ pthread_t tid;
+
+ pid = getpid();
+ tid = pthread_self();
+ printf("%s pid %u tid %u\n", s, (unsigned int)pid,(unsigned int)tid);
+}
+
+void* thr_fn(void *arg)
+{
+ printids("new thread: ");
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ err = pthread_create(&ntid, NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+ printids("main thread:");
+ sleep(1);
+ exit(0);
+}
diff --git a/eg.code/T6Code/T6_2.c b/eg.code/T6Code/T6_2.c
new file mode 100644
index 0000000..fdf9221
--- /dev/null
+++ b/eg.code/T6Code/T6_2.c
@@ -0,0 +1,47 @@
+//To compile: gcc -l pthread T6_2.c
+#include
+#include
+
+int int_Val[5] = {0,0,0,0,0};
+pthread_t th[5];
+
+void *add_to_value(void *arg) { // arg = 0, 1, 2, 3 ,4
+ int inData = *((int*)arg);
+ int i;
+ for(i = 0; i < 10000; i++){
+ int_Val[i % 5] += inData; /* ? */
+ }
+
+ /* Expectation (under the incorrect assumption that threads will run one after another for sure):
+ thread 0: [0,0,0,0,0] (+0 to each cell)
+ thread 1: [2000,2000,2000,2000,2000] (+1*2000=2000 to each cell)
+ thread 2: [6000,6000,6000,6000,6000] (+2*2000=4000 to each cell)
+ thread 3: [12000,12000,12000,12000,12000] (+3*2000=6000 to each cell)
+ thread 4: [20000,20000,20000,20000,20000] (+4*2000=8000 to each cell)
+ */
+
+ return (NULL);
+}
+
+int main(void) {
+ int i, retcode;
+
+ /* Create the threads */
+ for(i = 0; i < 5; i++) {
+ retcode = pthread_create(&th[i], NULL, add_to_value, (void *)&i);
+ if (retcode != 0)
+ printf("Create thread failed with error %d\n", retcode);
+ }
+
+ /* Wait until all threads have finished */
+ void* retVal[5];
+ for(i = 0; i < 5; i++){
+ pthread_join(th[i], &retVal[i]);
+ }
+
+ /* Print the results */
+ printf("Final values:\n");
+ for(i = 0; i < 5; i++)
+ printf("Integer value[%d] = \t%d\n", i, int_Val[i]);
+ return 0;
+}
diff --git a/eg.code/T6Code/T6_3.c b/eg.code/T6Code/T6_3.c
new file mode 100644
index 0000000..7860268
--- /dev/null
+++ b/eg.code/T6Code/T6_3.c
@@ -0,0 +1,35 @@
+//To compile: gcc -l pthread T6_3.c
+#include
+#include
+#include
+#include
+#include
+
+pthread_t ntid[2];
+
+void* thr_fn(void *arg)
+{
+ int i;
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(1);
+ }
+
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ int i;
+ for(i=0;i<2;i++)
+ {
+ err = pthread_create(&ntid[i], NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+ }
+
+ sleep(1);
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/T6Code/T6_4.c b/eg.code/T6Code/T6_4.c
new file mode 100644
index 0000000..3c6668a
--- /dev/null
+++ b/eg.code/T6Code/T6_4.c
@@ -0,0 +1,38 @@
+//To compile: gcc -l pthread T6_4.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid;
+
+void* thr_fn(void *arg)
+{
+ int i,x;
+ x=fork();
+ if(x==0){ // run this code twice: with > and with ==
+ return((void *)0);
+ }
+
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(1);
+ }
+
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ void *retVal;
+ int i;
+ err = pthread_create(&ntid, NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+
+ pthread_join(ntid, &retVal);
+ printf("returned\n");
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/T6Code/T6_4_New.c b/eg.code/T6Code/T6_4_New.c
new file mode 100644
index 0000000..aa28e5e
--- /dev/null
+++ b/eg.code/T6Code/T6_4_New.c
@@ -0,0 +1,38 @@
+//To compile: gcc -l pthread t6_4_New.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid;
+
+void* thr_fn(void *arg)
+{
+ int i,x;
+ x=fork();
+ if(x>0){ // run this code twice: with > and with ==
+ return((void *)0);
+ }
+
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(1);
+ }
+
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ void *retVal;
+ int i;
+ err = pthread_create(&ntid, NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+
+ pthread_join(ntid, &retVal);
+ printf("returned\n");
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/T6Code/T6_5.c b/eg.code/T6Code/T6_5.c
new file mode 100644
index 0000000..ac45aaa
--- /dev/null
+++ b/eg.code/T6Code/T6_5.c
@@ -0,0 +1,39 @@
+//To compile: gcc -l pthread T6_5.c
+#include
+#include
+#include
+#include
+#include
+pthread_t ntid[2];
+pthread_t ltid;
+void* thr_fn(void *arg)
+{
+ int i;
+ for(i=0;i<3;i++)
+ {
+ printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i);
+ sleep(2);
+ }
+
+ return((void *)0);
+}
+void* thr_fn2(void *arg)
+{
+ execl("/bin/ls", "ls", (char*)NULL);
+ return((void *)0);
+}
+
+int main(void)
+{
+ int err;
+ int i;
+ for(i=0;i<2;i++)
+ err = pthread_create(&ntid[i], NULL, thr_fn, NULL);
+ if (err != 0)
+ perror("can't create thread\n");
+
+ sleep(1);
+ pthread_create(<id, NULL, thr_fn2, NULL);
+ printf("I'm done\n");
+ pthread_exit((void*)0);
+}
diff --git a/eg.code/T6Code/T6_6.c b/eg.code/T6Code/T6_6.c
new file mode 100644
index 0000000..c4d6982
--- /dev/null
+++ b/eg.code/T6Code/T6_6.c
@@ -0,0 +1,43 @@
+// To compile: gcc -l pthread T6_6.c
+// thread synchronization problem
+
+#include
+#include
+#include
+#include
+#include
+
+pthread_t tid[10];
+int counter=0;
+
+void* doSomeThing(void *arg)
+{
+ unsigned long i = 0;
+
+ for(i=0; i<1000000;i++)
+ counter++;
+
+ return NULL;
+}
+
+int main(void)
+{
+ int i = 0;
+ int err;
+
+ while(i < 10)
+ {
+ err = pthread_create(&tid[i], NULL, doSomeThing, NULL);
+ if (err != 0)
+ printf("\ncan't create thread :[%s]", strerror(err));
+ i++;
+ }
+
+ for (i=0;i<10;i++)
+ pthread_join(tid[i], NULL);
+
+
+ printf("counter value is: %d\n",counter);
+
+ return 0;
+}
diff --git a/eg.code/T6Code/T6_7.c b/eg.code/T6Code/T6_7.c
new file mode 100644
index 0000000..a06e039
--- /dev/null
+++ b/eg.code/T6Code/T6_7.c
@@ -0,0 +1,51 @@
+//To compile: gcc -l pthread T6_7.c
+//thread synchronization problem - mutex solution
+#include
+#include
+#include
+#include
+#include
+
+pthread_t tid[10];
+int counter=0;
+
+pthread_mutex_t lock;
+
+void* doSomeThing(void *arg)
+{
+ unsigned long i = 0;
+ pthread_mutex_lock(&lock);
+ for(i=0; i<1000000;i++)
+ counter++;
+ pthread_mutex_unlock(&lock);
+
+ return NULL;
+}
+
+int main(void)
+{
+ int i = 0;
+ int err;
+
+ if (pthread_mutex_init(&lock, NULL) != 0)
+ {
+ printf("\n mutex init failed\n");
+ return 1;
+ }
+
+ while(i < 10)
+ {
+ err = pthread_create(&tid[i], NULL, doSomeThing, NULL);
+ //printf("created\n");
+ if (err != 0)
+ printf("\ncan't create thread :[%s]", strerror(err));
+ i++;
+ }
+ for (i=0;i<10;i++)
+ pthread_join(tid[i], NULL);
+ printf("counter value is: %d\n",counter);
+
+ pthread_mutex_destroy(&lock);
+
+ return 0;
+}
diff --git "a/eg.code/\360\237\220\207/statChild.c" "b/eg.code/\360\237\220\207/statChild.c"
new file mode 100644
index 0000000..a6f1be0
--- /dev/null
+++ "b/eg.code/\360\237\220\207/statChild.c"
@@ -0,0 +1,22 @@
+#include
+#include
+#include
+#include
+
+int main() {
+ int number, statval;
+ printf("%d: I'm the parent !\n", getpid());
+ if (fork() == 0) {
+ number = 5;
+ printf("PID %d: exiting with number %d\n", getpid(), number);
+ exit(number);
+ } else {
+ printf("PID %d: waiting for child\n", getpid());
+ wait(&statval);
+ if (WIFEXITED(statval))
+ printf("Child's exit code %d\n", WEXITSTATUS(statval));
+ else
+ printf("Child did not terminate with exit\n");
+ }
+ return 0;
+}
\ No newline at end of file
diff --git "a/eg.code/\360\237\220\207/withExc.c" "b/eg.code/\360\237\220\207/withExc.c"
new file mode 100644
index 0000000..89d9239
--- /dev/null
+++ "b/eg.code/\360\237\220\207/withExc.c"
@@ -0,0 +1,40 @@
+#include
+#include
+#include
+#include
+
+int main(void) {
+ int pid = fork();
+
+ if (pid == -1) {
+ perror("fork() failed");
+ exit(EXIT_FAILURE);
+ } else if (pid == 0) {
+ execlp("./child", "child", "1", "5", (char *)NULL);
+ perror("execlp() failed");
+ exit(EXIT_FAILURE);
+ } else {
+ printf("Coordinator: forked and waiting for process %d\n", pid);
+
+ int status;
+ if (waitpid(pid, &status, 0) != -1) {
+ if (WIFEXITED(status)) {
+ int returned = WEXITSTATUS(status);
+ printf("Exited normally with status %d\n", returned);
+ } else if (WIFSIGNALED(status)) {
+ int signum = WTERMSIG(status);
+ printf("Exited due to receiving signal %d\n", signum);
+ } else if (WIFSTOPPED(status)) {
+ int signum = WSTOPSIG(status);
+ printf("Stopped due to receiving signal %d\n", signum);
+ } else {
+ printf("Something strange just happened.\n");
+ }
+ } else {
+ perror("waitpid() failed");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/hw1/ex-files/0/1/3/atexit_example_1.c b/hw1/ex-files/0/1/3/atexit_example_1.c
new file mode 100644
index 0000000..90d0efd
--- /dev/null
+++ b/hw1/ex-files/0/1/3/atexit_example_1.c
@@ -0,0 +1,19 @@
+#include
+#include
+#include
+ void fnExit1 (void) {
+ puts ("Exit function 1.");
+}
+
+void fnExit2 (void) {
+ puts ("Exit function 2.");
+}
+
+int main () {
+ atexit (fnExit1);
+ atexit (fnExit2);
+ atexit (fnExit2);
+ puts ("Main function.");
+ return 0;
+}
+
diff --git a/hw1/ex-files/0/1/3/atexit_example_2.c b/hw1/ex-files/0/1/3/atexit_example_2.c
new file mode 100644
index 0000000..a925d36
--- /dev/null
+++ b/hw1/ex-files/0/1/3/atexit_example_2.c
@@ -0,0 +1,23 @@
+#include
+#include
+#include
+
+void bye(void) {
+ printf("Let’s go home, we learned enough today\n");
+}
+
+int main(void)
+{
+ long a;
+ int i;
+ a = sysconf(_SC_ATEXIT_MAX);
+ printf("ATEXIT_MAX = %ld\n", a);
+ i = atexit(bye);
+ if (i != 0)
+ {
+ fprintf(stderr, "cannot set exit function\n");
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+}
+
diff --git a/hw1/ex-files/0/1/4/execvp_wait_example.c b/hw1/ex-files/0/1/4/execvp_wait_example.c
new file mode 100644
index 0000000..46f09d5
--- /dev/null
+++ b/hw1/ex-files/0/1/4/execvp_wait_example.c
@@ -0,0 +1,28 @@
+#include
+#include
+#include
+#include
+
+int main(int argc, char* argv[])
+{
+ int stat,waited,ret_code;
+ pid_t pid;
+ pid = fork();
+ if (pid == 0)
+ { /* Child */
+ ret_code = execvp(argv[1],&argv[1]);
+ if (ret_code == -1)
+ {
+ perror("exec failed ");
+ exit(-1);
+ }
+ else
+ printf("Banana");
+ }
+ else
+ { /* Parent */
+ printf("Father: after fork, son proc id is %d \n",pid);
+ waited = wait(&stat); /* stat can tell what happened */
+ printf("Father: Son proc completed, id is %d \n", waited);
+ }
+}
diff --git a/hw1/ex-files/0/1/4/fork_example_1.c b/hw1/ex-files/0/1/4/fork_example_1.c
new file mode 100644
index 0000000..dbf3585
--- /dev/null
+++ b/hw1/ex-files/0/1/4/fork_example_1.c
@@ -0,0 +1,14 @@
+#include
+#include
+#include
+
+void main()
+{
+ pid_t pid;
+ if ((pid = fork()) == 0)
+ printf("1");
+ else
+ printf("2");
+ printf("3");
+}
+
diff --git a/hw1/ex-files/0/1/4/fork_example_2.c b/hw1/ex-files/0/1/4/fork_example_2.c
new file mode 100644
index 0000000..2fd4489
--- /dev/null
+++ b/hw1/ex-files/0/1/4/fork_example_2.c
@@ -0,0 +1,7 @@
+int main(){
+ int i;
+ for (i = 0; i < 3; i++)
+ if (fork() == 0)
+ while(1);
+}
+
diff --git a/hw1/ex-files/0/1/execl_example.c b/hw1/ex-files/0/1/execl_example.c
new file mode 100644
index 0000000..84cee5f
--- /dev/null
+++ b/hw1/ex-files/0/1/execl_example.c
@@ -0,0 +1,8 @@
+#include
+#include
+int main()
+{
+ execl("/bin/ls","/bin/ls","-l", NULL);
+ printf("can only get here on error\n");
+}
+
diff --git a/hw1/ex-files/0/1/execv_example.c b/hw1/ex-files/0/1/execv_example.c
new file mode 100644
index 0000000..bacdc06
--- /dev/null
+++ b/hw1/ex-files/0/1/execv_example.c
@@ -0,0 +1,10 @@
+#include
+#include
+
+int main() {
+ char *argv[] = {"date", NULL};
+ execv("/bin/date", argv);
+ printf("hello");
+ return 0;
+}
+
diff --git a/hw1/ex-files/0/2/5/6/t2_2.c b/hw1/ex-files/0/2/5/6/t2_2.c
new file mode 100644
index 0000000..c5924a3
--- /dev/null
+++ b/hw1/ex-files/0/2/5/6/t2_2.c
@@ -0,0 +1,20 @@
+#include
+#include
+
+int main(void)
+{
+ int status;
+ char *argv[] = { "/bin/env", 0 };
+ char *envp[] =
+ {
+ "HOME=/",
+ "PATH=/bin:/usr/bin",
+ "TZ=UTC0",
+ "USER=beelzebub",
+ "LOGNAME=tarzan",
+ 0
+ };
+ status=execve(argv[0], &argv[0], envp);
+ printf("exec failed\n");
+ return -1;
+}
diff --git a/hw1/ex-files/0/2/5/6/t2_3.c b/hw1/ex-files/0/2/5/6/t2_3.c
new file mode 100644
index 0000000..d04403e
--- /dev/null
+++ b/hw1/ex-files/0/2/5/6/t2_3.c
@@ -0,0 +1,21 @@
+#include
+#include
+#include
+
+void done(){
+ printf("see ya!\n");
+}
+int main(){
+ int status;
+ atexit(done);
+ if(fork())
+ {
+ wait(&status);
+ printf("parent PID = %d\n",getpid());
+ printf("exit status= %d\n",WEXITSTATUS(status)); _Exit(73);
+ }else{
+ sleep(2);
+ printf("child PID = %d\n",getpid());
+ exit(55);
+ }
+}
diff --git a/hw1/ex-files/0/2/5/t2_1.c b/hw1/ex-files/0/2/5/t2_1.c
new file mode 100644
index 0000000..d00c4fb
--- /dev/null
+++ b/hw1/ex-files/0/2/5/t2_1.c
@@ -0,0 +1,34 @@
+#include
+#include
+#include
+#include
+
+int glob = 6; /* global variable */
+char buf[] = "a write to stdout";
+
+int main(void)
+{
+ int var; /* automatic variable on the stack */
+ pid_t pid;
+
+ var = 88;
+ if(puts(buf)==EOF)
+ printf("error in writing to stdout");
+ printf("before fork\n");
+
+ if ( (pid = fork()) < 0)
+ printf("fork error");
+ else{
+ if (pid == 0)
+ { /* child */
+ glob++; /* modify variables */
+ var++;
+ }else
+ { /* parent */
+ sleep(2);
+ }
+ printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
+ exit(0);
+ }
+}
+
diff --git a/hw1/ex-files/0/2/fork_example_3.c b/hw1/ex-files/0/2/fork_example_3.c
new file mode 100644
index 0000000..a9d2099
--- /dev/null
+++ b/hw1/ex-files/0/2/fork_example_3.c
@@ -0,0 +1,18 @@
+#include
+#include
+#include
+
+int main()
+{
+ pid_t val;
+ printf("PID before fork: %d\n",(int)getpid());
+ val = fork();
+ if(val>0)
+ printf("parent PID: %d\n",(int)getpid());
+ else if(val ==0)
+ printf("child PID: %d\n",(int)getpid());
+ else {
+ //if val==-1 print error to screen
+ }
+}
+
diff --git a/hw1/ex-files/0/4.c b/hw1/ex-files/0/4.c
new file mode 100644
index 0000000..8569322
--- /dev/null
+++ b/hw1/ex-files/0/4.c
@@ -0,0 +1,13 @@
+#include
+#include
+#include
+int main() {
+ pid_t bll;
+ int stat;
+ if ((bll = fork()) == 0)
+ printf("1\n");
+ else {
+ wait(&stat);
+ printf("2\n");
+ }
+}
diff --git a/hw1/ex-files/0/wait_example_1.c b/hw1/ex-files/0/wait_example_1.c
new file mode 100644
index 0000000..7119a2d
--- /dev/null
+++ b/hw1/ex-files/0/wait_example_1.c
@@ -0,0 +1,14 @@
+#include
+#include
+#include
+int main()
+{
+ pid_t pid;
+ int stat;
+ if ((pid = fork()) == 0)
+ printf("1\n"); else {
+ wait(&stat);
+ printf("2\n");
+ }
+}
+
diff --git a/hw1/ex-files/0/wait_example_2.c b/hw1/ex-files/0/wait_example_2.c
new file mode 100644
index 0000000..540e5a4
--- /dev/null
+++ b/hw1/ex-files/0/wait_example_2.c
@@ -0,0 +1,27 @@
+#include
+#include
+
+int main()
+{
+ int status;
+ pid_t pid, pid1, pid2;
+ if ((pid1 = fork()) == 0)
+ printf("in child 1\n");
+ else
+ if ((pid2 = fork()) == 0)
+ printf("in child 2\n");
+ else
+ {
+ pid = wait(&status);
+ if (pid == pid1)
+ printf("child 1 finished\n");
+ if (pid == pid2)
+ printf("child 2 finished\n");
+ pid = wait(&status);
+ if (pid == pid1)
+ printf("child 1 finished\n");
+ if (pid == pid2)
+ printf("child 2 finished\n");
+ }
+}
+
diff --git a/hw1/ex-files/0/waitpid_example.c b/hw1/ex-files/0/waitpid_example.c
new file mode 100644
index 0000000..5a85e67
--- /dev/null
+++ b/hw1/ex-files/0/waitpid_example.c
@@ -0,0 +1,34 @@
+#include
+#include
+#include
+
+int main(void){
+ pid_t pid;
+ if ((pid = fork()) < 0)
+ printf("fork error");
+ else {
+ if (pid == 0) { /* first child */
+ printf("first child\n");
+ if ((pid = fork()) < 0)
+ printf ("fork error");
+ else {
+ if (pid > 0){
+ /* parent from second fork == first child */
+ if (waitpid(pid, NULL, 0) != pid)
+ printf("waitpid error");
+ exit(0);
+ }
+ /* We're the second child; */
+ sleep(2);
+ printf("second child, parent pid = %d\n", getppid());
+ exit(0);
+ }
+ }
+ if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
+ printf("waitpid error");
+ /** We're the parent (the original process); we continue executing, knowing that we're not the parent of the second child.*/
+ printf("original parent done\n");
+ exit(0);
+ }
+}
+
diff --git a/hw1/ex-files/3.c b/hw1/ex-files/3.c
new file mode 100644
index 0000000..4c3098e
--- /dev/null
+++ b/hw1/ex-files/3.c
@@ -0,0 +1,13 @@
+#include
+#include
+#include
+int main() {
+ pid_t bll;
+ int stat;
+ if ((bll = fork()) == 0)
+ printf("bin\n");
+ else {
+ wait(&stat);
+ printf("2\n");
+ }
+}
diff --git "a/hw1/ex-files/\327\252\327\250\327\222\327\231\327\234 1.pdf" "b/hw1/ex-files/\327\252\327\250\327\222\327\231\327\234 1.pdf"
new file mode 100644
index 0000000..b82163a
Binary files /dev/null and "b/hw1/ex-files/\327\252\327\250\327\222\327\231\327\234 1.pdf" differ
diff --git a/hw1/gccfind.sh b/hw1/gccfind.sh
new file mode 100755
index 0000000..90dad28
--- /dev/null
+++ b/hw1/gccfind.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+dirPath=$1
+wordToFind=$2
+isRecursive=$3
+COMPILED_EX="*.out"
+C_FILE="*.c"
+
+if [ "$isRecursive" == "-r" ]
+then
+ isRecursive=true
+else
+ isRecursive=false
+fi
+
+# check if there is enough params
+if [[ -z "$wordToFind" || "$wordToFind" == "-r" ]]
+then
+ echo "Not enough parameters"
+else
+
+ files=$(find $dirPath -maxdepth 1)
+
+ for file in $files
+ do
+ if [[ -d $file ]] && [ "$isRecursive" = true ] && [ $file != $dirPath ]
+ then
+ $($0 $file $wordToFind "-r")
+ else
+ if [[ $file == $COMPILED_EX ]]
+ then
+ rm $file
+ fi
+ fi
+
+ done
+
+ cd $dirPath
+
+ for FILE in $(grep -liw "${wordToFind}" *.c )
+ do
+ gcc -w -o ${FILE%.*}.out $FILE
+ done
+
+fi
diff --git a/hw1/myshell.c b/hw1/myshell.c
new file mode 100644
index 0000000..710ed2b
--- /dev/null
+++ b/hw1/myshell.c
@@ -0,0 +1,150 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define PROMPT "💲 "
+#define TERMINATE_STR '\0'
+#define EXIT "exit"
+#define HISTORY "history"
+#define CD "cd"
+
+typedef enum { false, true } bool;
+char* logCmd[100];
+int excRun = 0;
+
+char** splitStringToArray(char* str) {
+ char** res = NULL;
+ char* p = strtok(str, " ");
+ int n_spaces = 0;
+
+ /* split string and append tokens to 'res' */
+
+ while (p) {
+ res = realloc(res, sizeof(char*) * ++n_spaces);
+
+ if (res == NULL) exit(-1); /* memory allocation failed */
+
+ res[n_spaces - 1] = p;
+
+ p = strtok(NULL, " ");
+ }
+
+ /* realloc one extra element for the last NULL */
+
+ res = realloc(res, sizeof(char*) * (n_spaces + 1));
+ res[n_spaces] = 0;
+ return res;
+}
+
+/**
+ * Remove trailing white space characters from string
+ */
+void trimTrailing(char* str) {
+ int index, i;
+
+ /* Set default index */
+ index = -1;
+
+ /* Find last index of non-white space character */
+ i = 0;
+ while (str[i] != '\0') {
+ if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') {
+ index = i;
+ }
+
+ i++;
+ }
+
+ /* Mark next character to last non-white space character as NULL */
+ str[index + 1] = '\0';
+}
+
+void printHIstory() {
+ int i;
+ for (i = 0; i <= excRun; ++i) {
+ printf(" %s\n", logCmd[i]);
+ }
+}
+
+void logHistory(int pid, char* a) {
+ char entry[100] = "";
+ sprintf(entry, "%d ", pid);
+ strcat(entry, a);
+ logCmd[excRun] = malloc(100);
+ strcpy(logCmd[excRun], entry);
+}
+
+int main(int argc, char const* argv[]) {
+ pid_t pid = getpid();
+ char envs[100] = "";
+ int i;
+ for (i = 1; i < argc; ++i) {
+ strcat(strcat(envs, ":"), argv[i]);
+ }
+ char* allenv = getenv("PATH");
+ strcat(allenv, envs);
+ setenv("PATH", allenv, 0);
+ char a[100];
+ char* token;
+
+ while (1) {
+ char* str = malloc(100);
+ printf(PROMPT);
+ fflush(stdout);
+ fgets(a, sizeof(a), stdin);
+ trimTrailing(a);
+ strcpy(str, a);
+
+ if (!strcmp(a, EXIT)) {
+ int i;
+ for (i = 0; i < excRun; i++) {
+ char* currentPtr = logCmd[i];
+ free(currentPtr);
+ }
+ exit(1);
+ }
+
+ token = strtok(a, " ");
+ if (token == NULL) {
+ logHistory(pid, a);
+ } else if (!strcmp(token, HISTORY)) {
+ logHistory(pid, a);
+ printHIstory();
+ } else if (!strcmp(token, CD)) {
+ logHistory(pid, str);
+
+ token = a + strlen(token) + 1;
+ int res = chdir(token);
+ if (res != 0) {
+ perror(strcat(token, " failed"));
+ }
+
+ } else {
+ pid_t child = fork();
+ int stat;
+ logHistory(child, str);
+ if (child == 0) {
+ // split params
+ char** argv = splitStringToArray(str);
+ int res = execvp(token, argv);
+ if (res != 0) {
+ perror(strcat(token, " failed"));
+ }
+ break;
+ } else {
+ // wait for child to finish execute
+ wait(&stat);
+ }
+ }
+ if (str != NULL) {
+ free(str);
+ }
+
+ excRun++;
+ }
+ return 0;
+}
diff --git a/hw1/tennis.sh b/hw1/tennis.sh
new file mode 100755
index 0000000..0ace990
--- /dev/null
+++ b/hw1/tennis.sh
@@ -0,0 +1,177 @@
+#!/bin/bash
+
+winner=0
+players=( 50 50)
+guesses=( 0 0 )
+
+ballState=0
+ballField=0
+turnState=1
+isGameOn=true
+
+isInPlace=false
+
+for arg in "$@"
+do
+ case $arg in
+ --in-place|-p)
+ isInPlace=true
+ shift
+ ;;
+ -l|--log|--print-all)
+ isInPlace=false
+ shift
+ ;;
+ esac
+done
+
+
+printBoard () {
+ if [[ $isInPlace == true ]]; then clear; fi
+ echo " Player 1: ${players[0]} 🎾 Player 2: ${players[1]}"
+ echo " --------------------------------- "
+ echo " | | # | | "
+ echo " | | # | | "
+ case $ballState in
+ -3)
+ echo "O| | # | | "
+ ;;
+ -2)
+ echo " | O | # | | "
+ ;;
+ -1)
+ echo " | | O # | | "
+ ;;
+ 0)
+ echo " | | O | | "
+ ;;
+ 1)
+ echo " | | # O | | "
+ ;;
+ 2)
+ echo " | | # | O | "
+ ;;
+ 3)
+ echo " | | # | |O"
+ ;;
+ *)
+ echo " | | # | | "
+ ;;
+ esac
+ echo " | | # | | "
+ echo " | | # | | "
+ echo " --------------------------------- "
+
+}
+
+setTurn () {
+ if [[ $turnState == 1 ]]
+ then
+ turnState=2
+ else
+ turnState=1
+ fi
+}
+
+printState () {
+ echo -e " Player 1 played: ${guesses[0]}\n Player 2 played: ${guesses[1]}\n\n"
+}
+
+pickANumber () {
+ player=$turnState-1;
+ echo "PLAYER $turnState PICK A NUMBER: "
+ read -s guess
+
+ # validate pick
+ if [[ ! $guess =~ ^-?[0-9]+$ ]] || (( $guess > ${players[($player)]} ))
+ then
+ echo "NOT A VALID MOVE !"
+ pickANumber
+ else # set guess and update score
+ guesses[($player)]=$guess
+ if (( $turnState == 2 ))
+ then
+ calculateState
+ fi
+ players[($player)]=$((${players[($player)]}-$guess))
+ setTurn
+ fi
+}
+
+calculateState () {
+ handLoser=0
+ # if palyer 2 guessed smaller hand
+ if (( ${guesses[1]} < ${guesses[0]} ))
+ then
+ handLoser=2
+ else if (( ${guesses[1]} > ${guesses[0]} ))
+ then
+ handLoser=1
+ fi
+ fi
+ # checkWinner
+ if (( $handLoser == 0 )); then return; fi
+
+ if (( $handLoser == $ballField ))
+ then
+ ballState=$(( $ballState < 0 ? $ballState-1 : $ballState+1 ))
+ else
+ ballField=$handLoser
+ ballState=$(( $handLoser == 1 ? -1 : 1 ))
+ fi
+}
+
+checkWinner () {
+ if (( $ballState == 3 || $ballState == -3 ))
+ then
+ winner=$(( 3-$ballField ))
+ isGameOn=false
+ else
+ if (( ${players[0]} == 0 ))
+ then
+ isGameOn=false
+ if (( ${players[1]} > 0 )); then
+ winner=2
+ else
+ winner=$(( $ballField == 0 ? 0 : 3-$ballField ))
+ fi
+ else
+ if (( ${players[1]} == 0 ))
+ then
+ winner=1
+ isGameOn=false
+ fi
+ fi
+ fi
+}
+
+printWinner () {
+if [ $isGameOn == false ]
+ then
+ case $winner in
+ 0)
+ echo "IT'S A DRAW !"
+ ;;
+ 1)
+ echo "PLAYER 1 WINS !"
+ ;;
+ 2)
+ echo "PLAYER 2 WINS !"
+ ;;
+ *)
+ echo "$winner"
+ ;;
+ esac
+ fi
+}
+
+printBoard
+while $isGameOn
+do
+ pickANumber
+ pickANumber
+ printBoard
+ printState
+ checkWinner
+done
+printWinner
\ No newline at end of file
diff --git a/hw1/tic-tac-toe.sh b/hw1/tic-tac-toe.sh
new file mode 100755
index 0000000..d309daa
--- /dev/null
+++ b/hw1/tic-tac-toe.sh
@@ -0,0 +1,102 @@
+# tic-tac-toe.sh
+
+#!/usr/bin/bash
+
+player_1="❌"
+player_2="🟢"
+
+turn=1
+game_on=true
+
+moves=( 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ )
+
+welcome_message() {
+ clear
+ echo "========================"
+ echo "=== LETS PLAY A GAME ==="
+ echo "========================"
+ sleep 3
+}
+print_board () {
+ clear
+ echo " ${moves[0]} ❕ ${moves[1]} ❕ ${moves[2]} "
+ echo "➖➖➖➖➖➖"
+ echo " ${moves[3]} ❕ ${moves[4]} ❕ ${moves[5]} "
+ echo ➖➖➖➖➖➖
+ echo " ${moves[6]} ❕ ${moves[7]} ❕ ${moves[8]} "
+}
+
+player_pick(){
+ if [[ $(($turn % 2)) == 0 ]]
+ then
+ play=$player_2
+ echo -n "PLAYER 2 PICK A SQUARE: "
+ else
+ echo -n "PLAYER 1 PICK A SQUARE: "
+ play=$player_1
+ fi
+
+ read square
+
+# space=${moves[($square -1)]}
+
+ if [[ ! $square =~ ^-?[0-9]+$ ]]
+ then
+ echo "Not a valid square."
+ player_pick
+ else
+ moves[($square -1)]=$play
+ ((turn=turn+1))
+ fi
+ space=${moves[($square-1)]}
+}
+
+check_match() {
+ if [[ ${moves[$1]} == ${moves[$2]} ]]&& \
+ [[ ${moves[$2]} == ${moves[$3]} ]]; then
+ game_on=false
+ fi
+ if [ $game_on == false ]; then
+ if [ ${moves[$1]} == '❌' ];then
+ echo "Player one wins!"
+ return
+ else
+ echo "player two wins!"
+ return
+ fi
+ fi
+}
+
+check_winner(){
+ if [ $game_on == false ]; then return; fi
+ check_match 0 1 2
+ if [ $game_on == false ]; then return; fi
+ check_match 3 4 5
+ if [ $game_on == false ]; then return; fi
+ check_match 6 7 8
+ if [ $game_on == false ]; then return; fi
+ check_match 0 4 8
+ if [ $game_on == false ]; then return; fi
+ check_match 2 4 6
+ if [ $game_on == false ]; then return; fi
+ check_match 0 3 6
+ if [ $game_on == false ]; then return; fi
+ check_match 1 4 7
+ if [ $game_on == false ]; then return; fi
+ check_match 2 5 8
+ if [ $game_on == false ]; then return; fi
+
+ if [ $turn -gt 9 ]; then
+ $game_on=false
+ echo "Its a draw!"
+ fi
+}
+
+welcome_message
+print_board
+while $game_on
+do
+ player_pick
+ print_board
+ check_winner
+done
\ No newline at end of file
diff --git a/hw2/compare/ex21.c b/hw2/compare/ex21.c
new file mode 100644
index 0000000..d04a61b
--- /dev/null
+++ b/hw2/compare/ex21.c
@@ -0,0 +1,216 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum resemblanceStatus {
+ identical = 1, // identical files
+ different = 2, // different files
+ similar = 3, // similar files
+};
+
+int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead);
+
+// This function closes the file descriptor and set iteration to false
+void handleExit(int fd1, int fd2, int* keepRead, int isErr) {
+ if (isErr) {
+ perror("Error occurred");
+ }
+ if (fd1 != -1) {
+ close(fd1);
+ }
+ if (fd2 != -1) {
+ close(fd2);
+ }
+ *keepRead = 0;
+}
+
+int handleSpaces(int fd1, int fd2, char chr1, char chr2, int* keepRead) {
+ int isSpace, byteRes, res = 0;
+ if (isspace(chr1)) {
+ byteRes = read(fd1, &chr1, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(fd1, fd2, keepRead, 1);
+ *keepRead = 0;
+ res = different;
+ }
+ isSpace = 1;
+ }
+
+ if (isspace(chr2)) {
+ byteRes = read(fd2, &chr2, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(fd1, fd2, keepRead, 1);
+ exit(1);
+ // *keepRead = 0;
+ // res = different;
+ }
+ isSpace = 1;
+ }
+ if (isSpace) {
+ if (chr1 != chr2) {
+ res = handleSpaces(fd1, fd2, chr1, chr2, keepRead);
+ } else {
+ res = similar;
+ }
+ }
+ return res; // return resemblance status
+}
+
+int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead) {
+ int res;
+ if (tolower(chr1) != tolower(chr2) && !isspace(chr1) && !isspace(chr2)) {
+ handleExit(fd1, fd2, keepRead, 0);
+ res = different;
+ } else {
+ res = handleSpaces(fd1, fd2, chr1, chr2, keepRead);
+ }
+ return res;
+}
+
+int checkLeft(int left, char lastChr, int* keepRead) {
+ int byteRes, dirty = 0;
+ int res;
+ char chr;
+ while (keepRead) {
+ byteRes = read(left, &chr, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(left, -1, keepRead, 1);
+ *keepRead = 0;
+ return different;
+ }
+
+ if (byteRes == 0) {
+ *keepRead = 0;
+ break;
+ }
+ if (!isspace(chr)) {
+ if (chr != lastChr || dirty) {
+ return different;
+ } else {
+ dirty = 1;
+ res = similar;
+ }
+ }
+ }
+ if ((!isspace(chr) && tolower(lastChr) == tolower(chr)) ||
+ (isspace(chr) && isspace(lastChr)) || (isspace(lastChr) && !dirty)) {
+ res = similar;
+ } else
+ res = different;
+
+ return res;
+}
+
+int startsWith(const char* a, const char* b) {
+ if (strncmp(a, b, strlen(b)) == 0) return 1;
+ return 0;
+}
+
+void getFileName(char* path) {
+ if (!startsWith(path, "/")) {
+ char fullpath[1024] = "";
+ if (getcwd(fullpath, sizeof(fullpath)) != NULL) {
+ // printf("%s/%s\n", fullpath, path);
+ strcat(fullpath, path);
+ strcpy(fullpath, path);
+ }
+ }
+}
+
+// compare two files and return resemblance status
+// if the files content is exactly the same, return identical (1)
+// else, if the files content is different in spaces, capitals, or line break,
+// return similar (3)
+// otherwise, return different (2)
+int main(int argc, char* argv[]) {
+ if (argc < 3) {
+ printf("Error: not enough arguments\n");
+ return 1;
+ }
+ // retrive file names
+ getFileName(argv[1]);
+ char* file1 = argv[1];
+ if (file1 == NULL) return 1;
+ getFileName(argv[2]);
+ char* file2 = argv[2];
+ if (file2 == NULL) return 1;
+
+ int fd1, fd2;
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 == -1) {
+ printf("Error opening file\n");
+ return 1;
+ }
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 == -1) {
+ printf("Error opening file\n");
+ close(fd1);
+ return 1;
+ }
+
+ enum resemblanceStatus res = 0;
+ char chr1, chr2;
+ int byteRes1, byteRes2;
+ int keepRead = 1;
+
+ // reading the files char by char
+ while (keepRead) {
+ byteRes1 = read(fd1, &chr1, 1);
+ // if byteRes == -1 then error
+ if (byteRes1 == -1) {
+ handleExit(fd1, fd2, &keepRead, byteRes1 == -1);
+ exit(1);
+ break;
+ }
+ byteRes2 = read(fd2, &chr2, 1);
+ // if byteRes == -1 then error
+ if (byteRes2 == -1) {
+ handleExit(fd1, fd2, &keepRead, byteRes2 == -1);
+ exit(1);
+ break;
+ }
+ // if byteRes == 0 then end of file
+ if (byteRes1 == 0 && byteRes2 == 0) {
+ res = !res ? identical : res;
+ handleExit(fd1, fd2, &keepRead, 0);
+
+ break;
+ }
+ if ((byteRes1 == 0 && isspace(chr2)) ||
+ (byteRes2 == 0 && isspace(chr1))) {
+ res = different;
+ int left = byteRes1 == 0 ? fd2 : fd1;
+ char lastChr = byteRes1 == 0 ? chr2 : chr1;
+ res = checkLeft(left, lastChr, &keepRead);
+ handleExit(fd1, fd2, &keepRead, 0);
+ break;
+ }
+ if (byteRes1 == 0 || byteRes2 == 0) {
+ res = different;
+ handleExit(fd1, fd2, &keepRead, 0);
+ break;
+ }
+ if (chr1 != chr2) {
+ if (tolower(chr1) == tolower(chr2)) {
+ res = similar;
+ // break;
+ } else
+ res = checkSimilarity(fd1, fd2, chr1, chr2, &keepRead);
+ }
+ }
+ if (fd1 != -1) {
+ close(fd1);
+ }
+ if (fd2 != -1) {
+ close(fd2);
+ }
+ return res;
+}
diff --git a/hw2/ex2.docx b/hw2/ex2.docx
new file mode 100644
index 0000000..4138451
Binary files /dev/null and b/hw2/ex2.docx differ
diff --git a/hw2/ex2.pdf b/hw2/ex2.pdf
new file mode 100644
index 0000000..232bd3e
Binary files /dev/null and b/hw2/ex2.pdf differ
diff --git a/hw2/ex21.c b/hw2/ex21.c
new file mode 100644
index 0000000..d04a61b
--- /dev/null
+++ b/hw2/ex21.c
@@ -0,0 +1,216 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum resemblanceStatus {
+ identical = 1, // identical files
+ different = 2, // different files
+ similar = 3, // similar files
+};
+
+int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead);
+
+// This function closes the file descriptor and set iteration to false
+void handleExit(int fd1, int fd2, int* keepRead, int isErr) {
+ if (isErr) {
+ perror("Error occurred");
+ }
+ if (fd1 != -1) {
+ close(fd1);
+ }
+ if (fd2 != -1) {
+ close(fd2);
+ }
+ *keepRead = 0;
+}
+
+int handleSpaces(int fd1, int fd2, char chr1, char chr2, int* keepRead) {
+ int isSpace, byteRes, res = 0;
+ if (isspace(chr1)) {
+ byteRes = read(fd1, &chr1, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(fd1, fd2, keepRead, 1);
+ *keepRead = 0;
+ res = different;
+ }
+ isSpace = 1;
+ }
+
+ if (isspace(chr2)) {
+ byteRes = read(fd2, &chr2, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(fd1, fd2, keepRead, 1);
+ exit(1);
+ // *keepRead = 0;
+ // res = different;
+ }
+ isSpace = 1;
+ }
+ if (isSpace) {
+ if (chr1 != chr2) {
+ res = handleSpaces(fd1, fd2, chr1, chr2, keepRead);
+ } else {
+ res = similar;
+ }
+ }
+ return res; // return resemblance status
+}
+
+int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead) {
+ int res;
+ if (tolower(chr1) != tolower(chr2) && !isspace(chr1) && !isspace(chr2)) {
+ handleExit(fd1, fd2, keepRead, 0);
+ res = different;
+ } else {
+ res = handleSpaces(fd1, fd2, chr1, chr2, keepRead);
+ }
+ return res;
+}
+
+int checkLeft(int left, char lastChr, int* keepRead) {
+ int byteRes, dirty = 0;
+ int res;
+ char chr;
+ while (keepRead) {
+ byteRes = read(left, &chr, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(left, -1, keepRead, 1);
+ *keepRead = 0;
+ return different;
+ }
+
+ if (byteRes == 0) {
+ *keepRead = 0;
+ break;
+ }
+ if (!isspace(chr)) {
+ if (chr != lastChr || dirty) {
+ return different;
+ } else {
+ dirty = 1;
+ res = similar;
+ }
+ }
+ }
+ if ((!isspace(chr) && tolower(lastChr) == tolower(chr)) ||
+ (isspace(chr) && isspace(lastChr)) || (isspace(lastChr) && !dirty)) {
+ res = similar;
+ } else
+ res = different;
+
+ return res;
+}
+
+int startsWith(const char* a, const char* b) {
+ if (strncmp(a, b, strlen(b)) == 0) return 1;
+ return 0;
+}
+
+void getFileName(char* path) {
+ if (!startsWith(path, "/")) {
+ char fullpath[1024] = "";
+ if (getcwd(fullpath, sizeof(fullpath)) != NULL) {
+ // printf("%s/%s\n", fullpath, path);
+ strcat(fullpath, path);
+ strcpy(fullpath, path);
+ }
+ }
+}
+
+// compare two files and return resemblance status
+// if the files content is exactly the same, return identical (1)
+// else, if the files content is different in spaces, capitals, or line break,
+// return similar (3)
+// otherwise, return different (2)
+int main(int argc, char* argv[]) {
+ if (argc < 3) {
+ printf("Error: not enough arguments\n");
+ return 1;
+ }
+ // retrive file names
+ getFileName(argv[1]);
+ char* file1 = argv[1];
+ if (file1 == NULL) return 1;
+ getFileName(argv[2]);
+ char* file2 = argv[2];
+ if (file2 == NULL) return 1;
+
+ int fd1, fd2;
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 == -1) {
+ printf("Error opening file\n");
+ return 1;
+ }
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 == -1) {
+ printf("Error opening file\n");
+ close(fd1);
+ return 1;
+ }
+
+ enum resemblanceStatus res = 0;
+ char chr1, chr2;
+ int byteRes1, byteRes2;
+ int keepRead = 1;
+
+ // reading the files char by char
+ while (keepRead) {
+ byteRes1 = read(fd1, &chr1, 1);
+ // if byteRes == -1 then error
+ if (byteRes1 == -1) {
+ handleExit(fd1, fd2, &keepRead, byteRes1 == -1);
+ exit(1);
+ break;
+ }
+ byteRes2 = read(fd2, &chr2, 1);
+ // if byteRes == -1 then error
+ if (byteRes2 == -1) {
+ handleExit(fd1, fd2, &keepRead, byteRes2 == -1);
+ exit(1);
+ break;
+ }
+ // if byteRes == 0 then end of file
+ if (byteRes1 == 0 && byteRes2 == 0) {
+ res = !res ? identical : res;
+ handleExit(fd1, fd2, &keepRead, 0);
+
+ break;
+ }
+ if ((byteRes1 == 0 && isspace(chr2)) ||
+ (byteRes2 == 0 && isspace(chr1))) {
+ res = different;
+ int left = byteRes1 == 0 ? fd2 : fd1;
+ char lastChr = byteRes1 == 0 ? chr2 : chr1;
+ res = checkLeft(left, lastChr, &keepRead);
+ handleExit(fd1, fd2, &keepRead, 0);
+ break;
+ }
+ if (byteRes1 == 0 || byteRes2 == 0) {
+ res = different;
+ handleExit(fd1, fd2, &keepRead, 0);
+ break;
+ }
+ if (chr1 != chr2) {
+ if (tolower(chr1) == tolower(chr2)) {
+ res = similar;
+ // break;
+ } else
+ res = checkSimilarity(fd1, fd2, chr1, chr2, &keepRead);
+ }
+ }
+ if (fd1 != -1) {
+ close(fd1);
+ }
+ if (fd2 != -1) {
+ close(fd2);
+ }
+ return res;
+}
diff --git a/hw2/ex22.c b/hw2/ex22.c
new file mode 100644
index 0000000..6b0938e
--- /dev/null
+++ b/hw2/ex22.c
@@ -0,0 +1,380 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define CONFIG_FILES_MISSING "file not exist"
+
+#define COMPILE_C "/usr/bin/gcc"
+#define COMPILED_PNAME "output"
+#define RUNNABLE "./output"
+#define GCC_ERROR_FILE "gcc_errors.txt"
+#define OUTPUT_FILE "user_output.txt"
+#define TIMEOUT 5
+#define COMPARE "./comp.out"
+#define LAST_RES "/usr/bin/echo"
+#define ERRORS "errors.txt"
+#define RES(CHR) "RES" CHR ".txt"
+
+char* getFullPath(char* path, char* fileName) {
+ char* fullPath = malloc(strlen(path) + strlen(fileName) + 2);
+ strcpy(fullPath, path);
+ strcat(fullPath, "/");
+ strcat(fullPath, fileName);
+ return fullPath;
+}
+
+int startsWith(const char* a, const char* b) {
+ if (strncmp(a, b, strlen(b)) == 0) return 1;
+ return 0;
+}
+void getFileName(char* path) {
+ if (!startsWith(path, "/")) {
+ char fullpath[1024] = "";
+ if (getcwd(fullpath, sizeof(fullpath)) != NULL) {
+ strcat(strcat(fullpath, "/"), path);
+ strcpy(path, fullpath);
+ }
+ }
+}
+
+void trimTrailing(char* str) {
+ int index, i;
+ /* Set default index */
+ index = -1;
+
+ /* Find last index of non-white space character */
+ i = 0;
+ while (str[i] != '\0') {
+ if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') {
+ index = i;
+ }
+ i++;
+ }
+ /* Mark next character to last non-white space character as NULL */
+ str[index + 1] = '\0';
+}
+
+void freeConfigOnExit(char* config[3]) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (config[i] != NULL) {
+ free(config[i]);
+ }
+ }
+}
+
+void extractConfig(char* configFile, char* config[3]) {
+ // char* config[3] = {NULL, NULL, NULL};
+ char* line_buf = NULL;
+ size_t line_buf_size = 0;
+ int line_count = 0;
+ ssize_t line_size;
+ FILE* fp = fopen(configFile, "r");
+ if (!fp) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get the first line of the file. */
+ line_size = getline(&line_buf, &line_buf_size, fp);
+ while (line_size >= 0) {
+ /* Increment our line count */
+ line_count++;
+ getFileName(line_buf);
+
+ config[line_count - 1] = malloc(sizeof(char) * (strlen(line_buf) + 1));
+ strcpy(config[line_count - 1], line_buf);
+ trimTrailing(config[line_count - 1]);
+ // VALIDATE PATH EXISTS
+ int fd = access(config[line_count - 1], F_OK);
+ if (fd == -1) {
+ if (line_count == 2)
+ printf("Input %s", CONFIG_FILES_MISSING);
+ else
+ printf("Output %s", CONFIG_FILES_MISSING);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get the next line */
+ line_size = getline(&line_buf, &line_buf_size, fp);
+ }
+ /* Free the allocated line buffer */
+ free(line_buf);
+ line_buf = NULL;
+
+ /* Close the file now that we are done with it */
+ fclose(fp);
+ // return config;
+}
+
+char* gradeMap(char* name, int gradeIndex) {
+ char* grade = NULL;
+
+ switch (gradeIndex) {
+ case 1:
+ grade = ",0,NO_C_FILE\n";
+ break;
+ case 2:
+ grade = ",10,COMPILATION_ERROR\n";
+ break;
+ case 3:
+ grade = ",20,TIMEOUT\n";
+ break;
+ case 4:
+ grade = ",50,WRONG\n";
+ break;
+ case 5:
+ grade = ",75,SIMILAR\n";
+ break;
+ case 6:
+ grade = ",100,EXCELLENT\n";
+ break;
+ default:
+ grade = "?\n";
+ }
+ char* record = malloc(sizeof(char) * strlen(name) + strlen(grade) + 2);
+ strcpy(record, name);
+ strcat(record, grade);
+ return record;
+}
+
+int compileFile(char* fileName) {
+ // Compile the file
+ int isCompiled = 0;
+ pid_t pid;
+ int st;
+ if ((pid = fork()) < 0)
+ perror("fork");
+ else {
+ if (pid == 0) {
+ // remove(COMPILED_PNAME);
+ // replace standard output with output file
+ int gccerr_fd = open(GCC_ERROR_FILE, O_CREAT | O_WRONLY);
+ if (gccerr_fd > 0) {
+ dup2(gccerr_fd, 2);
+ close(gccerr_fd);
+ }
+
+ char* args[] = {COMPILE_C, "-o", COMPILED_PNAME, fileName, NULL};
+ int res = execvp(COMPILE_C, args);
+ if (res != 0) {
+ perror("execvp");
+ }
+ exit(0);
+ }
+ wait(&st);
+ // int gccerr_fd = access(COMPILED_PNAME, F_OK);
+ struct stat stat_p;
+ stat(GCC_ERROR_FILE, &stat_p);
+
+ if (stat_p.st_size == 0)
+ isCompiled = 1;
+ else
+ isCompiled = 0;
+ remove(GCC_ERROR_FILE);
+ // remove(COMPILED_PNAME);
+ return isCompiled;
+ }
+ return -1;
+}
+
+int runCompiledProgWithFile(char* inputFile) {
+ pid_t pid = fork();
+ time_t start = time(NULL);
+ int runTime;
+ int st;
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else {
+ if (pid == 0) {
+ // replace standard input with input file
+ int in_fd = open(inputFile, O_RDONLY);
+ dup2(in_fd, 0);
+ // replace standard output with output file
+ int out_fd = open(OUTPUT_FILE, O_WRONLY | O_TRUNC | O_CREAT,
+ S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
+ dup2(out_fd, 1);
+ close(in_fd);
+ close(out_fd);
+ char* args[] = {RUNNABLE, NULL};
+ int res = execvp(RUNNABLE, args);
+ if (res != 0) {
+ perror("execvp");
+ }
+ exit(0);
+ }
+ waitpid(pid, &st, 0);
+ runTime = time(NULL) - start;
+
+ if (runTime >= TIMEOUT)
+ st = 3;
+ else
+ st = 4;
+ }
+
+ return st;
+}
+
+int comare(char* outputFile) {
+ pid_t pid = fork();
+ int st, res;
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else {
+ if (pid == 0) {
+ char* args[] = {COMPARE, outputFile, OUTPUT_FILE, NULL};
+ execvp(COMPARE, args);
+ exit(0);
+
+ } else {
+ wait(&st);
+ if (WIFEXITED(st)) {
+ // printf("Child's exit code %d\n", WEXITSTATUS(st));
+ st = WEXITSTATUS(st);
+ }
+ if (st == 1)
+ res = 6;
+ else if (st == 2)
+ res = 4;
+ else if (st == 3)
+ res = 5;
+ }
+
+ // if output file exists remove it
+ int fd = access(OUTPUT_FILE, F_OK);
+ // if (fd != -1) remove(OUTPUT_FILE); //TODO: REMOVE OUTPUT FILE
+ }
+
+ return res;
+}
+
+int calcUserGrade(char* userDir, char* inputFile, char* outputFile) {
+ DIR* dip;
+ struct dirent* entry;
+
+ // open users directory
+ dip = opendir(userDir);
+ if (dip == NULL) {
+ perror("opendir");
+ exit(EXIT_FAILURE);
+ }
+ int grade = 0;
+ int fileToCompile = 0;
+ while ((entry = readdir(dip)) != NULL && !fileToCompile) {
+ const char* dot = strrchr(entry->d_name, '.');
+ if (dot && !strcmp(dot + 1, "c")) {
+ // ⚒️ build the c program inside the directory
+ fileToCompile = 1;
+
+ char* filePath = getFullPath(userDir, entry->d_name);
+
+ int isCompiled = compileFile(filePath);
+ if (isCompiled) {
+ // ⚒️ run the c program with the input file
+ grade = runCompiledProgWithFile(inputFile);
+ if (grade != 3) {
+ // ⚒️ compare the output file with the output file
+ // in the directory
+ grade = comare(outputFile);
+ }
+
+ } else
+ grade = 2;
+
+ if (filePath != NULL) free(filePath);
+ }
+ }
+
+ if (!fileToCompile) grade = 1;
+
+ closedir(dip);
+
+ // ⚒️ calculate the grade: 1-6
+ // ⚒️ clear exe & output files
+ // ⚒️ return the grade
+ return grade;
+}
+
+void logGrade(int fd, char* record) {
+ int res = write(fd, record, strlen(record));
+ if (res < 0) {
+ perror("write");
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void handleError(char* config[3], int resFd) {
+ freeConfigOnExit(config);
+ close(resFd);
+ exit(EXIT_FAILURE);
+}
+
+void grade(char* config[3], int resFd) {
+ DIR* dip;
+ struct dirent* dit;
+ // open users directory
+ dip = opendir(config[0]);
+ if (dip == NULL) {
+ perror("opendir");
+ handleError(config, resFd);
+ }
+ // int pathlen = strlen(config[0]);
+ // loop through users directory
+ while ((dit = readdir(dip)) != NULL) {
+ struct stat stat_p;
+ char* userFolder = getFullPath(config[0], dit->d_name);
+ stat(userFolder, &stat_p);
+ if (S_ISDIR(stat_p.st_mode) && strcmp(dit->d_name, ".") != 0 &&
+ strcmp(dit->d_name, "..") != 0) {
+ int grade = calcUserGrade(userFolder, config[1], config[2]);
+
+ char* record = gradeMap(dit->d_name, grade);
+ logGrade(resFd, record);
+
+ free(record);
+ free(userFolder);
+ }
+ }
+ // close users directory
+ if (closedir(dip) == -1) {
+ perror("closedir");
+ handleError(config, resFd);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ if (argc < 2) {
+ printf("Error: not enough arguments\n");
+ return 1;
+ }
+ char* configFile = argv[1];
+ char* config[3] = {NULL, NULL, NULL};
+ extractConfig(configFile, config);
+ int newFd = open("results.csv", O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ if (newFd == -1) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+ // open user folder (config[0])
+ // for each subfolder: fork and compile the only c file in there
+ // if compilation is successful, run the executable on child process with
+ // the input file (config[1]) and compare the output with the expected
+ // output (config[2]) on another fork
+ grade(config, newFd);
+
+ close(newFd);
+ freeConfigOnExit(config);
+ exit(EXIT_SUCCESS);
+}
diff --git a/hw2/files/student/Similar_output_gets_75/Example.c b/hw2/files/student/Similar_output_gets_75/Example.c
new file mode 100644
index 0000000..382b903
--- /dev/null
+++ b/hw2/files/student/Similar_output_gets_75/Example.c
@@ -0,0 +1,9 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d\n", n1+n2);
+}
diff --git a/hw2/files/students/Compilation_Error_gets_10/error1.c b/hw2/files/students/Compilation_Error_gets_10/error1.c
new file mode 100644
index 0000000..ede91b1
--- /dev/null
+++ b/hw2/files/students/Compilation_Error_gets_10/error1.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ printf("dfg");
+
diff --git a/hw2/files/students/Similar_output_gets_75/Example.c b/hw2/files/students/Similar_output_gets_75/Example.c
new file mode 100644
index 0000000..382b903
--- /dev/null
+++ b/hw2/files/students/Similar_output_gets_75/Example.c
@@ -0,0 +1,9 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d\n", n1+n2);
+}
diff --git a/hw2/files/students/TIMEOUT_gets_20/Example.c b/hw2/files/students/TIMEOUT_gets_20/Example.c
new file mode 100644
index 0000000..759ae94
--- /dev/null
+++ b/hw2/files/students/TIMEOUT_gets_20/Example.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ sleep(8);
+}
diff --git a/hw2/files/students/Wrong_output_gets_50/Example.c b/hw2/files/students/Wrong_output_gets_50/Example.c
new file mode 100644
index 0000000..660c4bd
--- /dev/null
+++ b/hw2/files/students/Wrong_output_gets_50/Example.c
@@ -0,0 +1,6 @@
+#include
+
+int main() {
+ printf("This is not the correct output!\n");
+ return 0;
+}
diff --git a/hw2/files/students/test.md b/hw2/files/students/test.md
new file mode 100644
index 0000000..e69de29
diff --git a/hw2/grade/ex22.c b/hw2/grade/ex22.c
new file mode 100644
index 0000000..0e262c2
--- /dev/null
+++ b/hw2/grade/ex22.c
@@ -0,0 +1,381 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define CONFIG_FILES_MISSING "file not exist"
+
+#define COMPILE_C "/usr/bin/gcc"
+#define COMPILED_PNAME "output"
+#define RUNNABLE "./output"
+#define GCC_ERROR_FILE "errors.txt"
+#define OUTPUT_FILE "user_output.txt"
+#define TIMEOUT 5
+#define COMPARE "./comp.out"
+#define LAST_RES "/usr/bin/echo"
+// #define ERRORS "errors.txt"
+#define RES(CHR) "RES" CHR ".txt"
+
+char* getFullPath(char* path, char* fileName) {
+ char* fullPath = malloc(strlen(path) + strlen(fileName) + 2);
+ strcpy(fullPath, path);
+ strcat(fullPath, "/");
+ strcat(fullPath, fileName);
+ return fullPath;
+}
+
+int startsWith(const char* a, const char* b) {
+ if (strncmp(a, b, strlen(b)) == 0) return 1;
+ return 0;
+}
+void getFileName(char* path) {
+ if (!startsWith(path, "/")) {
+ char fullpath[1024] = "";
+ if (getcwd(fullpath, sizeof(fullpath)) != NULL) {
+ strcat(strcat(fullpath, "/"), path);
+ strcpy(path, fullpath);
+ }
+ }
+}
+
+void trimTrailing(char* str) {
+ int index, i;
+ /* Set default index */
+ index = -1;
+
+ /* Find last index of non-white space character */
+ i = 0;
+ while (str[i] != '\0') {
+ if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') {
+ index = i;
+ }
+ i++;
+ }
+ /* Mark next character to last non-white space character as NULL */
+ str[index + 1] = '\0';
+}
+
+void freeConfigOnExit(char* config[3]) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (config[i] != NULL) {
+ free(config[i]);
+ }
+ }
+}
+
+void extractConfig(char* configFile, char* config[3]) {
+ // char* config[3] = {NULL, NULL, NULL};
+ char* line_buf = NULL;
+ size_t line_buf_size = 0;
+ int line_count = 0;
+ size_t line_size;
+ FILE* fp = fopen(configFile, "r");
+ if (!fp) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get the first line of the file. */
+ line_size = getline(&line_buf, &line_buf_size, fp);
+
+ while (line_size > 0 && line_count < 3) {
+ /* Increment our line count */
+ line_count++;
+ if (line_buf != NULL) getFileName(line_buf);
+
+ config[line_count - 1] = malloc(sizeof(char) * (strlen(line_buf) + 1));
+ strcpy(config[line_count - 1], line_buf);
+ trimTrailing(config[line_count - 1]);
+ // VALIDATE PATH EXISTS
+ int fd = access(config[line_count - 1], F_OK);
+ if (fd == -1) {
+ if (line_count == 2)
+ printf("Input %s", CONFIG_FILES_MISSING);
+ else
+ printf("Output %s", CONFIG_FILES_MISSING);
+
+ exit(EXIT_FAILURE);
+ }
+ /* Get the next line */
+ line_size = getline(&line_buf, &line_buf_size, fp);
+ }
+ /* Free the allocated line buffer */
+ if (line_buf != NULL) free(line_buf);
+ line_buf = NULL;
+
+ /* Close the file now that we are done with it */
+ fclose(fp);
+ // return config;
+}
+
+char* gradeMap(char* name, int gradeIndex) {
+ char* grade = NULL;
+
+ switch (gradeIndex) {
+ case 1:
+ grade = ",0,NO_C_FILE\n";
+ break;
+ case 2:
+ grade = ",10,COMPILATION_ERROR\n";
+ break;
+ case 3:
+ grade = ",20,TIMEOUT\n";
+ break;
+ case 4:
+ grade = ",50,WRONG\n";
+ break;
+ case 5:
+ grade = ",75,SIMILAR\n";
+ break;
+ case 6:
+ grade = ",100,EXCELLENT\n";
+ break;
+ default:
+ grade = "?\n";
+ }
+ char* record = malloc(sizeof(char) * strlen(name) + strlen(grade) + 2);
+ strcpy(record, name);
+ strcat(record, grade);
+ return record;
+}
+
+int compileFile(char* fileName) {
+ // Compile the file
+ int isCompiled = 0;
+ pid_t pid;
+ int st;
+ if ((pid = fork()) < 0)
+ perror("fork");
+ else {
+ if (pid == 0) {
+ char* args[] = {COMPILE_C, "-o", COMPILED_PNAME, fileName, NULL};
+ int res = execvp(COMPILE_C, args);
+ if (res != 0) {
+ perror("execvp");
+ }
+ exit(0);
+ }
+ wait(&st);
+ if (WIFEXITED(st)) {
+ st = WEXITSTATUS(st);
+ }
+
+ if (st == 0)
+ isCompiled = 1;
+ else
+ isCompiled = 0;
+
+ return isCompiled;
+ }
+ return -1;
+}
+
+int runCompiledProgWithFile(char* inputFile) {
+ pid_t pid = fork();
+ time_t start = time(NULL);
+ int runTime;
+ int st;
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else {
+ if (pid == 0) {
+ // replace standard input with input file
+ int in_fd = open(inputFile, O_RDONLY);
+ dup2(in_fd, 0);
+ // replace standard output with output file
+ int out_fd = open(OUTPUT_FILE, O_WRONLY | O_TRUNC | O_CREAT,
+ S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
+ dup2(out_fd, 1);
+ close(in_fd);
+ close(out_fd);
+ char* args[] = {RUNNABLE, NULL};
+ int res = execvp(RUNNABLE, args);
+ if (res != 0) {
+ perror("execvp");
+ }
+ exit(0);
+ }
+ waitpid(pid, &st, 0);
+ runTime = time(NULL) - start;
+
+ if (runTime >= TIMEOUT)
+ st = 3;
+ else
+ st = 4;
+ }
+
+ return st;
+}
+
+int comare(char* outputFile) {
+ pid_t pid = fork();
+ int st, res;
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else {
+ if (pid == 0) {
+ char* args[] = {COMPARE, outputFile, OUTPUT_FILE, NULL};
+ execvp(COMPARE, args);
+ exit(0);
+
+ } else {
+ wait(&st);
+ if (WIFEXITED(st)) {
+ st = WEXITSTATUS(st);
+ }
+ if (st == 1)
+ res = 6;
+ else if (st == 2)
+ res = 4;
+ else if (st == 3)
+ res = 5;
+ }
+
+ // if output file exists remove it
+ int fd = access(OUTPUT_FILE, F_OK);
+ if (fd != -1) remove(OUTPUT_FILE);
+ }
+
+ return res;
+}
+
+int calcUserGrade(char* userDir, char* inputFile, char* outputFile) {
+ DIR* dip;
+ struct dirent* entry;
+
+ // open users directory
+ dip = opendir(userDir);
+ if (dip == NULL) {
+ perror("opendir");
+ exit(EXIT_FAILURE);
+ }
+ int grade = 0;
+ int fileToCompile = 0;
+ while ((entry = readdir(dip)) != NULL && !fileToCompile) {
+ const char* dot = strrchr(entry->d_name, '.');
+ if (dot && !strcmp(dot + 1, "c")) {
+ // ⚒️ build the c program inside the directory
+ fileToCompile = 1;
+
+ char* filePath = getFullPath(userDir, entry->d_name);
+
+ int isCompiled = compileFile(filePath);
+ if (isCompiled) {
+ // ⚒️ run the c program with the input file
+ grade = runCompiledProgWithFile(inputFile);
+ if (grade != 3) {
+ // ⚒️ compare the output file with the output file
+ // in the directory
+ grade = comare(outputFile);
+ }
+
+ } else
+ grade = 2;
+
+ if (filePath != NULL) free(filePath);
+ }
+ }
+
+ if (!fileToCompile) grade = 1;
+
+ closedir(dip);
+ remove(COMPILED_PNAME);
+ // a function to delete the output file
+
+ // ⚒️ calculate the grade: 1-6
+ // ⚒️ clear exe & output files
+ // ⚒️ return the grade
+ return grade;
+}
+
+void logGrade(int fd, char* record) {
+ int res = write(fd, record, strlen(record));
+ if (res < 0) {
+ perror("write");
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void handleError(char* config[3], int resFd) {
+ freeConfigOnExit(config);
+ close(resFd);
+ exit(EXIT_FAILURE);
+}
+
+void grade(char* config[3], int resFd) {
+ DIR* dip;
+ struct dirent* dit;
+ // open users directory
+ dip = opendir(config[0]);
+ if (dip == NULL) {
+ perror("opendir");
+ handleError(config, resFd);
+ }
+
+ // int pathlen = strlen(config[0]);
+ // loop through users directory
+ while ((dit = readdir(dip)) != NULL) {
+ struct stat stat_p;
+ char* userFolder = getFullPath(config[0], dit->d_name);
+ stat(userFolder, &stat_p);
+ if (S_ISDIR(stat_p.st_mode) && strcmp(dit->d_name, ".") != 0 &&
+ strcmp(dit->d_name, "..") != 0) {
+ int grade = calcUserGrade(userFolder, config[1], config[2]);
+
+ char* record = gradeMap(dit->d_name, grade);
+ logGrade(resFd, record);
+
+ free(record);
+ free(userFolder);
+ }
+ }
+ // close users directory
+ if (closedir(dip) == -1) {
+ perror("closedir");
+ handleError(config, resFd);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ if (argc < 2) {
+ printf("Error: not enough arguments\n");
+ return 1;
+ }
+ char* configFile = argv[1];
+ char* config[3] = {NULL, NULL, NULL};
+
+ extractConfig(configFile, config);
+
+ int newFd = open("results.csv", O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ if (newFd == -1) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+ // open user folder (config[0])
+ // for each subfolder: fork and compile the only c file in there
+ // if compilation is successful, run the executable on child process with
+ // the input file (config[1]) and compare the output with the expected
+ // output (config[2]) on another fork
+ int gccerr_fd = open(GCC_ERROR_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+
+ dup2(gccerr_fd, 2);
+ close(gccerr_fd);
+
+ grade(config, newFd);
+
+ close(newFd);
+ freeConfigOnExit(config);
+ exit(EXIT_SUCCESS);
+}
diff --git a/hw2/grade/messing/up/students/Compilation_Error_gets_10/error1.c b/hw2/grade/messing/up/students/Compilation_Error_gets_10/error1.c
new file mode 100644
index 0000000..ede91b1
--- /dev/null
+++ b/hw2/grade/messing/up/students/Compilation_Error_gets_10/error1.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ printf("dfg");
+
diff --git a/hw2/grade/moodle/students/Compilation_Error_gets_10/error1.c b/hw2/grade/moodle/students/Compilation_Error_gets_10/error1.c
new file mode 100644
index 0000000..ede91b1
--- /dev/null
+++ b/hw2/grade/moodle/students/Compilation_Error_gets_10/error1.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ printf("dfg");
+
diff --git a/hw2/grade/moodle/students/Similar_output_gets_75/Example.c b/hw2/grade/moodle/students/Similar_output_gets_75/Example.c
new file mode 100644
index 0000000..382b903
--- /dev/null
+++ b/hw2/grade/moodle/students/Similar_output_gets_75/Example.c
@@ -0,0 +1,9 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d\n", n1+n2);
+}
diff --git a/hw2/grade/moodle/students/Wrong_output_gets_50/Example.c b/hw2/grade/moodle/students/Wrong_output_gets_50/Example.c
new file mode 100644
index 0000000..660c4bd
--- /dev/null
+++ b/hw2/grade/moodle/students/Wrong_output_gets_50/Example.c
@@ -0,0 +1,6 @@
+#include
+
+int main() {
+ printf("This is not the correct output!\n");
+ return 0;
+}
diff --git a/hw2/grade/students/biu_student_different/you_hate_recursion_i_love_it.c b/hw2/grade/students/biu_student_different/you_hate_recursion_i_love_it.c
new file mode 100644
index 0000000..3f96c1b
--- /dev/null
+++ b/hw2/grade/students/biu_student_different/you_hate_recursion_i_love_it.c
@@ -0,0 +1,10 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("I love recursion. Can you guess what my algorithm is?\n");
+ printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d", n1+n2);
+}
diff --git a/hw2/grade/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c b/hw2/grade/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c
new file mode 100644
index 0000000..d90cdd8
--- /dev/null
+++ b/hw2/grade/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ You shouldn't compile me!!!!
+}
\ No newline at end of file
diff --git a/hw2/grade/students/biu_student_great/zzz_im_tired.c b/hw2/grade/students/biu_student_great/zzz_im_tired.c
new file mode 100644
index 0000000..a3c79f4
--- /dev/null
+++ b/hw2/grade/students/biu_student_great/zzz_im_tired.c
@@ -0,0 +1,10 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("I hate recursion. Can you guess what my algorithm is?\n");
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d", n1+n2);
+}
diff --git a/hw2/grade/students/biu_student_insensitive/close_but_no.c b/hw2/grade/students/biu_student_insensitive/close_but_no.c
new file mode 100644
index 0000000..195b160
--- /dev/null
+++ b/hw2/grade/students/biu_student_insensitive/close_but_no.c
@@ -0,0 +1,10 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("I hate recursion. Can you guess what my algorithm is?\n");
+ printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d", n1+n2);
+}
diff --git a/hw2/grade/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c b/hw2/grade/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c
new file mode 100644
index 0000000..a3c79f4
--- /dev/null
+++ b/hw2/grade/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c
@@ -0,0 +1,10 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("I hate recursion. Can you guess what my algorithm is?\n");
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d", n1+n2);
+}
diff --git a/hw2/grade/students/biu_student_terrible/cccgcc.c b/hw2/grade/students/biu_student_terrible/cccgcc.c
new file mode 100644
index 0000000..381cb20
--- /dev/null
+++ b/hw2/grade/students/biu_student_terrible/cccgcc.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ printf("I'm a terrible student. See? I don't know basic syntax...");
+}}
\ No newline at end of file
diff --git a/hw2/to-prod/ex21.c b/hw2/to-prod/ex21.c
new file mode 100644
index 0000000..844a77a
--- /dev/null
+++ b/hw2/to-prod/ex21.c
@@ -0,0 +1,218 @@
+// 315394874 Bareket Damari
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum resemblanceStatus {
+ identical = 1, // identical files
+ different = 2, // different files
+ similar = 3, // similar files
+};
+
+int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead);
+
+// This function closes the file descriptor and set iteration to false
+void handleExit(int fd1, int fd2, int* keepRead, int isErr) {
+ if (isErr) {
+ perror("Error occurred");
+ }
+ if (fd1 != -1) {
+ close(fd1);
+ }
+ if (fd2 != -1) {
+ close(fd2);
+ }
+ *keepRead = 0;
+}
+
+int handleSpaces(int fd1, int fd2, char chr1, char chr2, int* keepRead) {
+ int isSpace, byteRes, res = 0;
+ if (isspace(chr1)) {
+ byteRes = read(fd1, &chr1, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(fd1, fd2, keepRead, 1);
+ *keepRead = 0;
+ res = different;
+ }
+ isSpace = 1;
+ }
+
+ if (isspace(chr2)) {
+ byteRes = read(fd2, &chr2, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(fd1, fd2, keepRead, 1);
+ exit(1);
+ // *keepRead = 0;
+ // res = different;
+ }
+ isSpace = 1;
+ }
+ if (isSpace) {
+ if (chr1 != chr2) {
+ res = handleSpaces(fd1, fd2, chr1, chr2, keepRead);
+ } else {
+ res = similar;
+ }
+ }
+ return res; // return resemblance status
+}
+
+int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead) {
+ int res;
+ if (tolower(chr1) != tolower(chr2) && !isspace(chr1) && !isspace(chr2)) {
+ handleExit(fd1, fd2, keepRead, 0);
+ res = different;
+ } else {
+ res = handleSpaces(fd1, fd2, chr1, chr2, keepRead);
+ }
+ return res;
+}
+
+int checkLeft(int left, char lastChr, int* keepRead) {
+ int byteRes, dirty = 0;
+ int res;
+ char chr;
+ while (keepRead) {
+ byteRes = read(left, &chr, 1);
+ if (byteRes == -1) {
+ // close files and exit with error
+ handleExit(left, -1, keepRead, 1);
+ *keepRead = 0;
+ return different;
+ }
+
+ if (byteRes == 0) {
+ *keepRead = 0;
+ break;
+ }
+ if (!isspace(chr)) {
+ if (chr != lastChr || dirty) {
+ return different;
+ } else {
+ dirty = 1;
+ res = similar;
+ }
+ }
+ }
+ if ((!isspace(chr) && tolower(lastChr) == tolower(chr)) ||
+ (isspace(chr) && isspace(lastChr)) || (isspace(lastChr) && !dirty)) {
+ res = similar;
+ } else
+ res = different;
+
+ return res;
+}
+
+int startsWith(const char* a, const char* b) {
+ if (strncmp(a, b, strlen(b)) == 0) return 1;
+ return 0;
+}
+
+void getFileName(char* path) {
+ if (!startsWith(path, "/")) {
+ char fullpath[1024] = "";
+ if (getcwd(fullpath, sizeof(fullpath)) != NULL) {
+ // printf("%s/%s\n", fullpath, path);
+ strcat(fullpath, path);
+ strcpy(fullpath, path);
+ }
+ }
+}
+
+// compare two files and return resemblance status
+// if the files content is exactly the same, return identical (1)
+// else, if the files content is different in spaces, capitals, or line break,
+// return similar (3)
+// otherwise, return different (2)
+int main(int argc, char* argv[]) {
+ if (argc < 3) {
+ printf("Error: not enough arguments\n");
+ return 1;
+ }
+ // retrive file names
+ getFileName(argv[1]);
+ char* file1 = argv[1];
+ if (file1 == NULL) return 1;
+ getFileName(argv[2]);
+ char* file2 = argv[2];
+ if (file2 == NULL) return 1;
+
+ int fd1, fd2;
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 == -1) {
+ printf("Error opening file\n");
+ return 1;
+ }
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 == -1) {
+ printf("Error opening file\n");
+ close(fd1);
+ return 1;
+ }
+
+ enum resemblanceStatus res = 0;
+ char chr1, chr2;
+ int byteRes1, byteRes2;
+ int keepRead = 1;
+
+ // reading the files char by char
+ while (keepRead) {
+ byteRes1 = read(fd1, &chr1, 1);
+ // if byteRes == -1 then error
+ if (byteRes1 == -1) {
+ handleExit(fd1, fd2, &keepRead, byteRes1 == -1);
+ exit(1);
+ break;
+ }
+ byteRes2 = read(fd2, &chr2, 1);
+ // if byteRes == -1 then error
+ if (byteRes2 == -1) {
+ handleExit(fd1, fd2, &keepRead, byteRes2 == -1);
+ exit(1);
+ break;
+ }
+ // if byteRes == 0 then end of file
+ if (byteRes1 == 0 && byteRes2 == 0) {
+ res = !res ? identical : res;
+ handleExit(fd1, fd2, &keepRead, 0);
+
+ break;
+ }
+ if ((byteRes1 == 0 && isspace(chr2)) ||
+ (byteRes2 == 0 && isspace(chr1))) {
+ res = different;
+ int left = byteRes1 == 0 ? fd2 : fd1;
+ char lastChr = byteRes1 == 0 ? chr2 : chr1;
+ res = checkLeft(left, lastChr, &keepRead);
+ handleExit(fd1, fd2, &keepRead, 0);
+ break;
+ }
+ if (byteRes1 == 0 || byteRes2 == 0) {
+ res = different;
+ handleExit(fd1, fd2, &keepRead, 0);
+ break;
+ }
+ if (chr1 != chr2) {
+ if (tolower(chr1) == tolower(chr2)) {
+ res = similar;
+ // break;
+ } else
+ res = checkSimilarity(fd1, fd2, chr1, chr2, &keepRead);
+ }
+ }
+ if (fd1 != -1) {
+ close(fd1);
+ }
+ if (fd2 != -1) {
+ close(fd2);
+ }
+ return res;
+}
diff --git a/hw2/to-prod/ex22.c b/hw2/to-prod/ex22.c
new file mode 100644
index 0000000..4668c62
--- /dev/null
+++ b/hw2/to-prod/ex22.c
@@ -0,0 +1,382 @@
+// 315394874 Bareket Damari
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define CONFIG_FILES_MISSING "file not exist"
+
+#define COMPILE_C "/usr/bin/gcc"
+#define COMPILED_PNAME "output"
+#define RUNNABLE "./output"
+#define GCC_ERROR_FILE "errors.txt"
+#define OUTPUT_FILE "user_output.txt"
+#define TIMEOUT 5
+#define COMPARE "./comp.out"
+#define LAST_RES "/usr/bin/echo"
+// #define ERRORS "errors.txt"
+#define RES(CHR) "RES" CHR ".txt"
+
+char* getFullPath(char* path, char* fileName) {
+ char* fullPath = malloc(strlen(path) + strlen(fileName) + 2);
+ strcpy(fullPath, path);
+ strcat(fullPath, "/");
+ strcat(fullPath, fileName);
+ return fullPath;
+}
+
+int startsWith(const char* a, const char* b) {
+ if (strncmp(a, b, strlen(b)) == 0) return 1;
+ return 0;
+}
+void getFileName(char* path) {
+ if (!startsWith(path, "/")) {
+ char fullpath[1024] = "";
+ if (getcwd(fullpath, sizeof(fullpath)) != NULL) {
+ strcat(strcat(fullpath, "/"), path);
+ strcpy(path, fullpath);
+ }
+ }
+}
+
+void trimTrailing(char* str) {
+ int index, i;
+ /* Set default index */
+ index = -1;
+
+ /* Find last index of non-white space character */
+ i = 0;
+ while (str[i] != '\0') {
+ if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') {
+ index = i;
+ }
+ i++;
+ }
+ /* Mark next character to last non-white space character as NULL */
+ str[index + 1] = '\0';
+}
+
+void freeConfigOnExit(char* config[3]) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (config[i] != NULL) {
+ free(config[i]);
+ }
+ }
+}
+
+void extractConfig(char* configFile, char* config[3]) {
+ // char* config[3] = {NULL, NULL, NULL};
+ char* line_buf = NULL;
+ size_t line_buf_size = 0;
+ int line_count = 0;
+ size_t line_size;
+ FILE* fp = fopen(configFile, "r");
+ if (!fp) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Get the first line of the file. */
+ line_size = getline(&line_buf, &line_buf_size, fp);
+
+ while (line_size > 0 && line_count < 3) {
+ /* Increment our line count */
+ line_count++;
+ if (line_buf != NULL) getFileName(line_buf);
+
+ config[line_count - 1] = malloc(sizeof(char) * (strlen(line_buf) + 1));
+ strcpy(config[line_count - 1], line_buf);
+ trimTrailing(config[line_count - 1]);
+ // VALIDATE PATH EXISTS
+ int fd = access(config[line_count - 1], F_OK);
+ if (fd == -1) {
+ if (line_count == 2)
+ printf("Input %s", CONFIG_FILES_MISSING);
+ else
+ printf("Output %s", CONFIG_FILES_MISSING);
+
+ exit(EXIT_FAILURE);
+ }
+ /* Get the next line */
+ line_size = getline(&line_buf, &line_buf_size, fp);
+ }
+ /* Free the allocated line buffer */
+ if (line_buf != NULL) free(line_buf);
+ line_buf = NULL;
+
+ /* Close the file now that we are done with it */
+ fclose(fp);
+ // return config;
+}
+
+char* gradeMap(char* name, int gradeIndex) {
+ char* grade = NULL;
+
+ switch (gradeIndex) {
+ case 1:
+ grade = ",0,NO_C_FILE\n";
+ break;
+ case 2:
+ grade = ",10,COMPILATION_ERROR\n";
+ break;
+ case 3:
+ grade = ",20,TIMEOUT\n";
+ break;
+ case 4:
+ grade = ",50,WRONG\n";
+ break;
+ case 5:
+ grade = ",75,SIMILAR\n";
+ break;
+ case 6:
+ grade = ",100,EXCELLENT\n";
+ break;
+ default:
+ grade = "?\n";
+ }
+ char* record = malloc(sizeof(char) * strlen(name) + strlen(grade) + 2);
+ strcpy(record, name);
+ strcat(record, grade);
+ return record;
+}
+
+int compileFile(char* fileName) {
+ // Compile the file
+ int isCompiled = 0;
+ pid_t pid;
+ int st;
+ if ((pid = fork()) < 0)
+ perror("fork");
+ else {
+ if (pid == 0) {
+ char* args[] = {COMPILE_C, "-o", COMPILED_PNAME, fileName, NULL};
+ int res = execvp(COMPILE_C, args);
+ if (res != 0) {
+ perror("execvp");
+ }
+ exit(0);
+ }
+ wait(&st);
+ if (WIFEXITED(st)) {
+ st = WEXITSTATUS(st);
+ }
+
+ if (st == 0)
+ isCompiled = 1;
+ else
+ isCompiled = 0;
+
+ return isCompiled;
+ }
+ return -1;
+}
+
+int runCompiledProgWithFile(char* inputFile) {
+ pid_t pid = fork();
+ time_t start = time(NULL);
+ int runTime;
+ int st;
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else {
+ if (pid == 0) {
+ // replace standard input with input file
+ int in_fd = open(inputFile, O_RDONLY);
+ dup2(in_fd, 0);
+ // replace standard output with output file
+ int out_fd = open(OUTPUT_FILE, O_WRONLY | O_TRUNC | O_CREAT,
+ S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
+ dup2(out_fd, 1);
+ close(in_fd);
+ close(out_fd);
+ char* args[] = {RUNNABLE, NULL};
+ int res = execvp(RUNNABLE, args);
+ if (res != 0) {
+ perror("execvp");
+ }
+ exit(0);
+ }
+ waitpid(pid, &st, 0);
+ runTime = time(NULL) - start;
+
+ if (runTime >= TIMEOUT)
+ st = 3;
+ else
+ st = 4;
+ }
+
+ return st;
+}
+
+int comare(char* outputFile) {
+ pid_t pid = fork();
+ int st, res;
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else {
+ if (pid == 0) {
+ char* args[] = {COMPARE, outputFile, OUTPUT_FILE, NULL};
+ execvp(COMPARE, args);
+ exit(0);
+
+ } else {
+ wait(&st);
+ if (WIFEXITED(st)) {
+ st = WEXITSTATUS(st);
+ }
+ if (st == 1)
+ res = 6;
+ else if (st == 2)
+ res = 4;
+ else if (st == 3)
+ res = 5;
+ }
+
+ // if output file exists remove it
+ int fd = access(OUTPUT_FILE, F_OK);
+ if (fd != -1) remove(OUTPUT_FILE);
+ }
+
+ return res;
+}
+
+int calcUserGrade(char* userDir, char* inputFile, char* outputFile) {
+ DIR* dip;
+ struct dirent* entry;
+
+ // open users directory
+ dip = opendir(userDir);
+ if (dip == NULL) {
+ perror("opendir");
+ exit(EXIT_FAILURE);
+ }
+ int grade = 0;
+ int fileToCompile = 0;
+ while ((entry = readdir(dip)) != NULL && !fileToCompile) {
+ const char* dot = strrchr(entry->d_name, '.');
+ if (dot && !strcmp(dot + 1, "c")) {
+ // ⚒️ build the c program inside the directory
+ fileToCompile = 1;
+
+ char* filePath = getFullPath(userDir, entry->d_name);
+
+ int isCompiled = compileFile(filePath);
+ if (isCompiled) {
+ // ⚒️ run the c program with the input file
+ grade = runCompiledProgWithFile(inputFile);
+ if (grade != 3) {
+ // ⚒️ compare the output file with the output file
+ // in the directory
+ grade = comare(outputFile);
+ }
+
+ } else
+ grade = 2;
+
+ if (filePath != NULL) free(filePath);
+ }
+ }
+
+ if (!fileToCompile) grade = 1;
+
+ closedir(dip);
+ remove(COMPILED_PNAME);
+ // a function to delete the output file
+
+ // ⚒️ calculate the grade: 1-6
+ // ⚒️ clear exe & output files
+ // ⚒️ return the grade
+ return grade;
+}
+
+void logGrade(int fd, char* record) {
+ int res = write(fd, record, strlen(record));
+ if (res < 0) {
+ perror("write");
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void handleError(char* config[3], int resFd) {
+ freeConfigOnExit(config);
+ close(resFd);
+ exit(EXIT_FAILURE);
+}
+
+void grade(char* config[3], int resFd) {
+ DIR* dip;
+ struct dirent* dit;
+ // open users directory
+ dip = opendir(config[0]);
+ if (dip == NULL) {
+ perror("opendir");
+ handleError(config, resFd);
+ }
+
+ // int pathlen = strlen(config[0]);
+ // loop through users directory
+ while ((dit = readdir(dip)) != NULL) {
+ struct stat stat_p;
+ char* userFolder = getFullPath(config[0], dit->d_name);
+ stat(userFolder, &stat_p);
+ if (S_ISDIR(stat_p.st_mode) && strcmp(dit->d_name, ".") != 0 &&
+ strcmp(dit->d_name, "..") != 0) {
+ int grade = calcUserGrade(userFolder, config[1], config[2]);
+
+ char* record = gradeMap(dit->d_name, grade);
+ logGrade(resFd, record);
+
+ free(record);
+ free(userFolder);
+ }
+ }
+ // close users directory
+ if (closedir(dip) == -1) {
+ perror("closedir");
+ handleError(config, resFd);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ if (argc < 2) {
+ printf("Error: not enough arguments\n");
+ return 1;
+ }
+ int gccerr_fd = open(GCC_ERROR_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ dup2(gccerr_fd, 2);
+ close(gccerr_fd);
+
+ char* configFile = argv[1];
+ char* config[3] = {NULL, NULL, NULL};
+
+ extractConfig(configFile, config);
+
+ int newFd = open("results.csv", O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ if (newFd == -1) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+ // open user folder (config[0])
+ // for each subfolder: fork and compile the only c file in there
+ // if compilation is successful, run the executable on child process with
+ // the input file (config[1]) and compare the output with the expected
+ // output (config[2]) on another fork
+
+ grade(config, newFd);
+
+ close(newFd);
+ freeConfigOnExit(config);
+ exit(EXIT_SUCCESS);
+}
diff --git a/hw2/to-prod/mess/messing/up/students/Compilation_Error_gets_10/error1.c b/hw2/to-prod/mess/messing/up/students/Compilation_Error_gets_10/error1.c
new file mode 100644
index 0000000..ede91b1
--- /dev/null
+++ b/hw2/to-prod/mess/messing/up/students/Compilation_Error_gets_10/error1.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ printf("dfg");
+
diff --git a/hw2/to-prod/moodle/students/Compilation_Error_gets_10/error1.c b/hw2/to-prod/moodle/students/Compilation_Error_gets_10/error1.c
new file mode 100644
index 0000000..ede91b1
--- /dev/null
+++ b/hw2/to-prod/moodle/students/Compilation_Error_gets_10/error1.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ printf("dfg");
+
diff --git a/hw2/to-prod/moodle/students/Similar_output_gets_75/Example.c b/hw2/to-prod/moodle/students/Similar_output_gets_75/Example.c
new file mode 100644
index 0000000..382b903
--- /dev/null
+++ b/hw2/to-prod/moodle/students/Similar_output_gets_75/Example.c
@@ -0,0 +1,9 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d\n", n1+n2);
+}
diff --git a/hw2/to-prod/moodle/students/Wrong_output_gets_50/Example.c b/hw2/to-prod/moodle/students/Wrong_output_gets_50/Example.c
new file mode 100644
index 0000000..660c4bd
--- /dev/null
+++ b/hw2/to-prod/moodle/students/Wrong_output_gets_50/Example.c
@@ -0,0 +1,6 @@
+#include
+
+int main() {
+ printf("This is not the correct output!\n");
+ return 0;
+}
diff --git a/hw2/to-prod/tough/students/biu_student_different/you_hate_recursion_i_love_it.c b/hw2/to-prod/tough/students/biu_student_different/you_hate_recursion_i_love_it.c
new file mode 100644
index 0000000..3f96c1b
--- /dev/null
+++ b/hw2/to-prod/tough/students/biu_student_different/you_hate_recursion_i_love_it.c
@@ -0,0 +1,10 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("I love recursion. Can you guess what my algorithm is?\n");
+ printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d", n1+n2);
+}
diff --git a/hw2/to-prod/tough/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c b/hw2/to-prod/tough/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c
new file mode 100644
index 0000000..d90cdd8
--- /dev/null
+++ b/hw2/to-prod/tough/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c
@@ -0,0 +1,6 @@
+#include
+
+int main()
+{
+ You shouldn't compile me!!!!
+}
\ No newline at end of file
diff --git a/hw2/to-prod/tough/students/biu_student_great/zzz_im_tired.c b/hw2/to-prod/tough/students/biu_student_great/zzz_im_tired.c
new file mode 100644
index 0000000..a3c79f4
--- /dev/null
+++ b/hw2/to-prod/tough/students/biu_student_great/zzz_im_tired.c
@@ -0,0 +1,10 @@
+#include
+
+int main()
+{
+ int n1, n2;
+ printf("I hate recursion. Can you guess what my algorithm is?\n");
+ printf("Please enter two numbers\n");
+ scanf ("%d %d",&n1, &n2);
+ printf("%d", n1+n2);
+}
diff --git a/hw2/to-prod/tough/students/biu_student_insensitive/close_but_no.c b/hw2/to-prod/tough/students/biu_student_insensitive/close_but_no.c
new file mode 100644
index 0000000..195b160
--- /dev/null
+++ b/hw2/to-prod/tough/students/biu_student_insensitive/close_but_no.c
@@ -0,0 +1,10 @@
+#include