commit 12f9c4274bc4373e847acfcf0969e13c28862a3a Author: lily Date: Mon Jan 12 23:08:19 2026 +1100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6dd29b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ \ No newline at end of file diff --git a/examples/1 b/examples/1 new file mode 100644 index 0000000..a241e8f --- /dev/null +++ b/examples/1 @@ -0,0 +1,2 @@ +logging.sh +network.sh diff --git a/examples/1.logging.sh b/examples/1.logging.sh new file mode 120000 index 0000000..0aa0cad --- /dev/null +++ b/examples/1.logging.sh @@ -0,0 +1 @@ +logging.sh \ No newline at end of file diff --git a/examples/1.network.sh b/examples/1.network.sh new file mode 120000 index 0000000..cad3e41 --- /dev/null +++ b/examples/1.network.sh @@ -0,0 +1 @@ +network.sh \ No newline at end of file diff --git a/examples/3 b/examples/3 new file mode 100644 index 0000000..386da9e --- /dev/null +++ b/examples/3 @@ -0,0 +1,4 @@ +logging.sh +network.sh +db.sh +app.sh diff --git a/examples/3.app.sh b/examples/3.app.sh new file mode 120000 index 0000000..6b7477e --- /dev/null +++ b/examples/3.app.sh @@ -0,0 +1 @@ +app.sh \ No newline at end of file diff --git a/examples/3.db.sh b/examples/3.db.sh new file mode 120000 index 0000000..e43b4f2 --- /dev/null +++ b/examples/3.db.sh @@ -0,0 +1 @@ +db.sh \ No newline at end of file diff --git a/examples/3.logging.sh b/examples/3.logging.sh new file mode 120000 index 0000000..0aa0cad --- /dev/null +++ b/examples/3.logging.sh @@ -0,0 +1 @@ +logging.sh \ No newline at end of file diff --git a/examples/3.network.sh b/examples/3.network.sh new file mode 120000 index 0000000..cad3e41 --- /dev/null +++ b/examples/3.network.sh @@ -0,0 +1 @@ +network.sh \ No newline at end of file diff --git a/examples/app.sh b/examples/app.sh new file mode 100644 index 0000000..f70f8bb --- /dev/null +++ b/examples/app.sh @@ -0,0 +1,2 @@ +db.sh network.sh +echo "Application service started" diff --git a/examples/db.sh b/examples/db.sh new file mode 100644 index 0000000..e92e8b4 --- /dev/null +++ b/examples/db.sh @@ -0,0 +1,2 @@ +network.sh +echo "Database service started" diff --git a/examples/logging.sh b/examples/logging.sh new file mode 100644 index 0000000..23c1d4c --- /dev/null +++ b/examples/logging.sh @@ -0,0 +1,2 @@ +# This script has no dependencies +echo "Logging service started" diff --git a/examples/network.sh b/examples/network.sh new file mode 100644 index 0000000..2d58303 --- /dev/null +++ b/examples/network.sh @@ -0,0 +1,2 @@ +logging.sh +echo "Network service started" diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..fd46a32 --- /dev/null +++ b/src/config.h @@ -0,0 +1 @@ +#define INIT_DIRECTORY "/home/lily/init/examples" diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..be9f559 --- /dev/null +++ b/src/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include "config.h" + +void check_init() { + + const char* init_directory; + init_directory=INIT_DIRECTORY; + struct stat sb; + + if (stat(init_directory, &sb) == 0 && S_ISDIR(sb.st_mode)) { + printf("Init directory found! Continuing.\n"); + } else { + printf ("Init directory not found!\n"); + exit(1); + } + +} + +int has_char_before_dot(const char *filename, char c) { + int found_c = 0; + for (int i = 0; filename[i] != '\0'; i++) { + if (filename[i] == '.') return found_c; + if (filename[i] == c) { + found_c = 1; + } + } + return 0; +} + +void parse_names(char runlevel) { + DIR *d; + struct dirent *dir; + d = opendir(INIT_DIRECTORY); + if (d) { + while ((dir = readdir(d)) != NULL) { + // Use 8 if DT_REG is not defined (standard on most Linux systems) + #ifndef DT_REG + #define DT_REG 8 + #endif + #ifndef DT_LNK + #define DT_LNK 10 + #endif + if (dir->d_type == DT_REG || dir->d_type == DT_LNK) { + if (has_char_before_dot(dir->d_name, runlevel)) { + printf("File: %s, Number: %c\n", dir->d_name, runlevel); + } + } + } + closedir(d); + } +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + char runlevel = argv[1][0]; + + check_init(); + parse_names(runlevel); + return 0; +} diff --git a/src/solver.c b/src/solver.c new file mode 100644 index 0000000..2922041 --- /dev/null +++ b/src/solver.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include "config.h" + +#define MAX_SCRIPTS 1000 +#define MAX_NAME 256 +#define MAX_DEPS 200 + +typedef struct { + char generic_name[MAX_NAME]; + char full_name[MAX_NAME]; + char dependencies[MAX_DEPS][MAX_NAME]; + int num_dependencies; + int in_degree; + int processed; +} Script; + +static Script scripts[MAX_SCRIPTS]; +static int num_scripts = 0; + +void check_init() { + const char* init_directory = INIT_DIRECTORY; + struct stat sb; + + if (stat(init_directory, &sb) == 0 && S_ISDIR(sb.st_mode)) { + printf("Init directory found! Continuing.\n"); + } else { + printf("Init directory not found!\n"); + exit(1); + } +} + +static int has_char_before_dot(const char *filename, char c) { + int found_c = 0; + for (int i = 0; filename[i] != '\0'; i++) { + if (filename[i] == '.') return found_c; + if (filename[i] == c) found_c = 1; + } + return 0; +} + +static void get_generic_name(const char *filename, char *dest) { + const char *dot = strchr(filename, '.'); + if (dot) { + strcpy(dest, dot + 1); + } else { + strcpy(dest, filename); + } +} + +static int find_script_idx(const char *generic_name) { + for (int i = 0; i < num_scripts; i++) { + if (strcmp(scripts[i].generic_name, generic_name) == 0) { + return i; + } + } + return -1; +} + +void solve_dependencies(char runlevel) { + DIR *d; + struct dirent *dir; + num_scripts = 0; + + d = opendir(INIT_DIRECTORY); + if (!d) { + perror("opendir"); + return; + } + + while ((dir = readdir(d)) != NULL) { + #ifndef DT_REG + #define DT_REG 8 + #endif + #ifndef DT_LNK + #define DT_LNK 10 + #endif + if ((dir->d_type == DT_REG || dir->d_type == DT_LNK) && has_char_before_dot(dir->d_name, runlevel)) { + if (num_scripts >= MAX_SCRIPTS) break; + + Script *s = &scripts[num_scripts]; + strncpy(s->full_name, dir->d_name, MAX_NAME); + get_generic_name(dir->d_name, s->generic_name); + s->num_dependencies = 0; + s->in_degree = 0; + s->processed = 0; + + char path[512]; + snprintf(path, sizeof(path), "%s/%s", INIT_DIRECTORY, dir->d_name); + FILE *f = fopen(path, "r"); + if (f) { + char line[1024]; + if (fgets(line, sizeof(line), f)) { + char *token = strtok(line, " \t\n\r"); + while (token && s->num_dependencies < MAX_DEPS) { + strncpy(s->dependencies[s->num_dependencies++], token, MAX_NAME); + token = strtok(NULL, " \t\n\r"); + } + } + fclose(f); + } + num_scripts++; + } + } + closedir(d); + + for (int i = 0; i < num_scripts; i++) { + for (int j = 0; j < scripts[i].num_dependencies; j++) { + int dep_idx = find_script_idx(scripts[i].dependencies[j]); + if (dep_idx != -1) { + scripts[i].in_degree++; + } + } + } + + char out_path[512]; + snprintf(out_path, sizeof(out_path), "%s/%c", INIT_DIRECTORY, runlevel); + FILE *out = fopen(out_path, "w"); + if (!out) { + perror("fopen output"); + return; + } + + int resolved = 0; + while (resolved < num_scripts) { + int found = 0; + for (int i = 0; i < num_scripts; i++) { + if (!scripts[i].processed && scripts[i].in_degree == 0) { + fprintf(out, "%s\n", scripts[i].generic_name); + scripts[i].processed = 1; + found = 1; + resolved++; + + for (int j = 0; j < num_scripts; j++) { + if (!scripts[j].processed) { + for (int k = 0; k < scripts[j].num_dependencies; k++) { + if (strcmp(scripts[j].dependencies[k], scripts[i].generic_name) == 0) { + scripts[j].in_degree--; + } + } + } + } + break; + } + } + if (!found) { + fprintf(stderr, "Cycle detected or missing dependency in runlevel %c\n", runlevel); + break; + } + } + fclose(out); +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + char runlevel = argv[1][0]; + + check_init(); + solve_dependencies(runlevel); + return 0; +}