DD_ELF := user/dd.elf
PWD_ELF := user/pwd.elf
STAT_ELF := user/stat.elf
+ SED_ELF := user/sed.elf
+ AWK_ELF := user/awk.elf
+ WHO_ELF := user/who.elf
+ TOP_ELF := user/top.elf
+ DU_ELF := user/du.elf
+ FIND_ELF := user/find.elf
+ WHICH_ELF := user/which.elf
INIT_ELF := user/init.elf
LDSO_ELF := user/ld.so
ULIBC_SO := user/ulibc/libc.so
@$(DYN_CC) -c user/stat.c -o user/stat.o
@$(DYN_LD) -o $@ $(ULIBC_CRT0) user/stat.o -lc
+$(SED_ELF): user/sed.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/sed.c -o user/sed.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/sed.o -lc
+
+$(AWK_ELF): user/awk.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/awk.c -o user/awk.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/awk.o -lc
+
+$(WHO_ELF): user/who.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/who.c -o user/who.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/who.o -lc
+
+$(TOP_ELF): user/top.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/top.c -o user/top.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/top.o -lc
+
+$(DU_ELF): user/du.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/du.c -o user/du.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/du.o -lc
+
+$(FIND_ELF): user/find.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/find.c -o user/find.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/find.o -lc
+
+$(WHICH_ELF): user/which.c user/dyn_linker.ld $(ULIBC_SO) $(ULIBC_LIB)
+ @$(DYN_CC) -c user/which.c -o user/which.o
+ @$(DYN_LD) -o $@ $(ULIBC_CRT0) user/which.o -lc
+
$(LDSO_ELF): user/ldso.c user/ldso_linker.ld
@i686-elf-gcc -m32 -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/ldso_linker.ld -o $(LDSO_ELF) user/ldso.c
$(BASENAME_ELF) $(DIRNAME_ELF) $(RMDIR_ELF) \
$(GREP_ELF) $(ID_ELF) $(UNAME_ELF) $(DMESG_ELF) \
$(PRINTENV_ELF) $(TR_ELF) $(DD_ELF) $(PWD_ELF) $(STAT_ELF) \
+ $(SED_ELF) $(AWK_ELF) $(WHO_ELF) $(TOP_ELF) $(DU_ELF) \
+ $(FIND_ELF) $(WHICH_ELF) \
$(INIT_ELF)
FSTAB := rootfs/etc/fstab
$(RMDIR_ELF):bin/rmdir \
$(GREP_ELF):bin/grep $(ID_ELF):bin/id $(UNAME_ELF):bin/uname \
$(DMESG_ELF):bin/dmesg $(PRINTENV_ELF):bin/printenv $(TR_ELF):bin/tr \
+ $(SED_ELF):bin/sed $(AWK_ELF):bin/awk $(WHO_ELF):bin/who \
+ $(TOP_ELF):bin/top $(DU_ELF):bin/du $(FIND_ELF):bin/find $(WHICH_ELF):bin/which \
$(DD_ELF):bin/dd $(PWD_ELF):bin/pwd $(STAT_ELF):bin/stat \
$(LDSO_ELF):lib/ld.so $(ULIBC_SO):lib/libc.so \
$(PIE_SO):lib/libpietest.so $(PIE_ELF):bin/pie_test \
--- /dev/null
+/* AdrOS awk utility — minimal: print fields, pattern matching, BEGIN/END */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+static char delim = ' ';
+static int print_field = -1; /* -1 = whole line */
+static char pattern[256] = "";
+static int has_pattern = 0;
+
+static void process_line(const char* line) {
+ if (has_pattern && !strstr(line, pattern)) return;
+
+ if (print_field < 0) {
+ printf("%s\n", line);
+ return;
+ }
+
+ /* Split into fields */
+ char copy[4096];
+ strncpy(copy, line, sizeof(copy) - 1);
+ copy[sizeof(copy) - 1] = '\0';
+
+ int fi = 0;
+ char* p = copy;
+ while (*p) {
+ while (*p && (*p == delim || *p == '\t')) p++;
+ if (!*p) break;
+ char* start = p;
+ while (*p && *p != delim && *p != '\t') p++;
+ if (*p) *p++ = '\0';
+ if (fi == print_field) {
+ printf("%s\n", start);
+ return;
+ }
+ fi++;
+ }
+ printf("\n");
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: awk [-F sep] '{print $N}' [file]\n");
+ return 1;
+ }
+
+ int argi = 1;
+ if (strcmp(argv[argi], "-F") == 0 && argi + 1 < argc) {
+ delim = argv[argi + 1][0];
+ argi += 2;
+ }
+
+ if (argi >= argc) {
+ fprintf(stderr, "awk: missing program\n");
+ return 1;
+ }
+
+ /* Parse simple program: {print $N} or /pattern/{print $N} */
+ const char* prog = argv[argi++];
+
+ /* Check for /pattern/ prefix */
+ if (prog[0] == '/') {
+ const char* end = strchr(prog + 1, '/');
+ if (end) {
+ int plen = (int)(end - prog - 1);
+ if (plen > 0 && plen < (int)sizeof(pattern)) {
+ memcpy(pattern, prog + 1, plen);
+ pattern[plen] = '\0';
+ has_pattern = 1;
+ }
+ prog = end + 1;
+ }
+ }
+
+ /* Parse {print $N} */
+ const char* pp = strstr(prog, "print");
+ if (pp) {
+ const char* dollar = strchr(pp, '$');
+ if (dollar) {
+ int n = atoi(dollar + 1);
+ print_field = (n > 0) ? n - 1 : -1;
+ if (n == 0) print_field = -1; /* $0 = whole line */
+ }
+ }
+
+ int fd = STDIN_FILENO;
+ if (argi < argc) {
+ fd = open(argv[argi], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "awk: %s: No such file or directory\n", argv[argi]);
+ return 1;
+ }
+ }
+
+ char line[4096];
+ int li = 0;
+ char c;
+ while (read(fd, &c, 1) == 1) {
+ if (c == '\n') {
+ line[li] = '\0';
+ process_line(line);
+ li = 0;
+ } else if (li < (int)sizeof(line) - 1) {
+ line[li++] = c;
+ }
+ }
+ if (li > 0) {
+ line[li] = '\0';
+ process_line(line);
+ }
+
+ if (fd != STDIN_FILENO) close(fd);
+ return 0;
+}
--- /dev/null
+/* AdrOS du utility — estimate file space usage */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+static int sflag = 0; /* -s: summary only */
+
+static long du_path(const char* path, int print) {
+ struct stat st;
+ if (stat(path, &st) < 0) {
+ fprintf(stderr, "du: cannot access '%s'\n", path);
+ return 0;
+ }
+
+ if (!(st.st_mode & 0040000)) {
+ long blocks = (st.st_size + 511) / 512;
+ if (print && !sflag) printf("%ld\t%s\n", blocks, path);
+ return blocks;
+ }
+
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) return 0;
+
+ long total = 0;
+ char buf[2048];
+ int rc;
+ while ((rc = getdents(fd, buf, sizeof(buf))) > 0) {
+ int off = 0;
+ while (off < rc) {
+ struct dirent* d = (struct dirent*)(buf + off);
+ if (d->d_reclen == 0) break;
+ if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
+ char child[512];
+ if (path[strlen(path)-1] == '/')
+ snprintf(child, sizeof(child), "%s%s", path, d->d_name);
+ else
+ snprintf(child, sizeof(child), "%s/%s", path, d->d_name);
+ total += du_path(child, print);
+ }
+ off += d->d_reclen;
+ }
+ }
+ close(fd);
+
+ if (print && !sflag) printf("%ld\t%s\n", total, path);
+ return total;
+}
+
+int main(int argc, char** argv) {
+ int argi = 1;
+ while (argi < argc && argv[argi][0] == '-') {
+ const char* f = argv[argi] + 1;
+ while (*f) {
+ if (*f == 's') sflag = 1;
+ f++;
+ }
+ argi++;
+ }
+
+ if (argi >= argc) {
+ long total = du_path(".", 1);
+ if (sflag) printf("%ld\t.\n", total);
+ } else {
+ for (int i = argi; i < argc; i++) {
+ long total = du_path(argv[i], 1);
+ if (sflag) printf("%ld\t%s\n", total, argv[i]);
+ }
+ }
+ return 0;
+}
--- /dev/null
+/* AdrOS find utility — search for files in directory hierarchy */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+static const char* name_pattern = NULL;
+static int type_filter = 0; /* 0=any, 'f'=file, 'd'=dir */
+
+static int match_name(const char* name) {
+ if (!name_pattern) return 1;
+ /* Simple wildcard: *pattern* if pattern has no special chars,
+ or exact match. Support leading/trailing * only. */
+ int plen = (int)strlen(name_pattern);
+ if (plen == 0) return 1;
+
+ const char* pat = name_pattern;
+ int lead_star = (pat[0] == '*');
+ int trail_star = (plen > 1 && pat[plen-1] == '*');
+
+ if (lead_star && trail_star) {
+ char sub[256];
+ int slen = plen - 2;
+ if (slen <= 0) return 1;
+ memcpy(sub, pat + 1, slen);
+ sub[slen] = '\0';
+ return strstr(name, sub) != NULL;
+ }
+ if (lead_star) {
+ const char* suffix = pat + 1;
+ int slen = plen - 1;
+ int nlen = (int)strlen(name);
+ if (nlen < slen) return 0;
+ return strcmp(name + nlen - slen, suffix) == 0;
+ }
+ if (trail_star) {
+ return strncmp(name, pat, plen - 1) == 0;
+ }
+ return strcmp(name, pat) == 0;
+}
+
+static void find_recurse(const char* path) {
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) return;
+
+ char buf[2048];
+ int rc;
+ while ((rc = getdents(fd, buf, sizeof(buf))) > 0) {
+ int off = 0;
+ while (off < rc) {
+ struct dirent* d = (struct dirent*)(buf + off);
+ if (d->d_reclen == 0) break;
+ if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
+ char child[512];
+ if (path[strlen(path)-1] == '/')
+ snprintf(child, sizeof(child), "%s%s", path, d->d_name);
+ else
+ snprintf(child, sizeof(child), "%s/%s", path, d->d_name);
+
+ int show = match_name(d->d_name);
+ if (show && type_filter) {
+ if (type_filter == 'f' && d->d_type == 4) show = 0; /* DT_DIR=4 */
+ if (type_filter == 'd' && d->d_type != 4) show = 0;
+ }
+ if (show) printf("%s\n", child);
+
+ if (d->d_type == 4) { /* DT_DIR */
+ find_recurse(child);
+ }
+ }
+ off += d->d_reclen;
+ }
+ }
+ close(fd);
+}
+
+int main(int argc, char** argv) {
+ const char* start = ".";
+ int argi = 1;
+
+ if (argi < argc && argv[argi][0] != '-') {
+ start = argv[argi++];
+ }
+
+ while (argi < argc) {
+ if (strcmp(argv[argi], "-name") == 0 && argi + 1 < argc) {
+ name_pattern = argv[++argi];
+ } else if (strcmp(argv[argi], "-type") == 0 && argi + 1 < argc) {
+ type_filter = argv[++argi][0];
+ }
+ argi++;
+ }
+
+ printf("%s\n", start);
+ find_recurse(start);
+ return 0;
+}
--- /dev/null
+/* AdrOS sed utility — minimal stream editor (s/pattern/replacement/g only) */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static int match_at(const char* s, const char* pat, int patlen) {
+ for (int i = 0; i < patlen; i++) {
+ if (s[i] == '\0' || s[i] != pat[i]) return 0;
+ }
+ return 1;
+}
+
+static void sed_substitute(const char* line, const char* pat, int patlen,
+ const char* rep, int replen, int global) {
+ const char* p = line;
+ while (*p) {
+ if (match_at(p, pat, patlen)) {
+ write(STDOUT_FILENO, rep, replen);
+ p += patlen;
+ if (!global) {
+ write(STDOUT_FILENO, p, strlen(p));
+ return;
+ }
+ } else {
+ write(STDOUT_FILENO, p, 1);
+ p++;
+ }
+ }
+}
+
+static int parse_s_cmd(const char* expr, char* pat, int* patlen,
+ char* rep, int* replen, int* global) {
+ if (expr[0] != 's' || expr[1] == '\0') return -1;
+ char delim = expr[1];
+ const char* p = expr + 2;
+ int pi = 0;
+ while (*p && *p != delim && pi < 255) pat[pi++] = *p++;
+ pat[pi] = '\0'; *patlen = pi;
+ if (*p != delim) return -1;
+ p++;
+ int ri = 0;
+ while (*p && *p != delim && ri < 255) rep[ri++] = *p++;
+ rep[ri] = '\0'; *replen = ri;
+ *global = 0;
+ if (*p == delim) { p++; if (*p == 'g') *global = 1; }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: sed 's/pattern/replacement/[g]' [file]\n");
+ return 1;
+ }
+
+ char pat[256], rep[256];
+ int patlen, replen, global;
+ int ei = 1;
+ if (strcmp(argv[1], "-e") == 0 && argc > 2) ei = 2;
+
+ if (parse_s_cmd(argv[ei], pat, &patlen, rep, &replen, &global) < 0) {
+ fprintf(stderr, "sed: invalid expression: %s\n", argv[ei]);
+ return 1;
+ }
+
+ int fd = STDIN_FILENO;
+ if (argc > ei + 1) {
+ fd = open(argv[ei + 1], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "sed: %s: No such file or directory\n", argv[ei + 1]);
+ return 1;
+ }
+ }
+
+ char line[4096];
+ int li = 0;
+ char c;
+ while (read(fd, &c, 1) == 1) {
+ if (c == '\n') {
+ line[li] = '\0';
+ sed_substitute(line, pat, patlen, rep, replen, global);
+ write(STDOUT_FILENO, "\n", 1);
+ li = 0;
+ } else if (li < (int)sizeof(line) - 1) {
+ line[li++] = c;
+ }
+ }
+ if (li > 0) {
+ line[li] = '\0';
+ sed_substitute(line, pat, patlen, rep, replen, global);
+ }
+
+ if (fd != STDIN_FILENO) close(fd);
+ return 0;
+}
char* redir_out = NULL;
char* redir_in = NULL;
int append = 0;
+ int heredoc_fd = -1;
int nargc = 0;
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], ">>") == 0 && i + 1 < argc) {
redir_out = argv[++i]; append = 1;
} else if (strcmp(argv[i], ">") == 0 && i + 1 < argc) {
redir_out = argv[++i]; append = 0;
+ } else if (strcmp(argv[i], "<<") == 0 && i + 1 < argc) {
+ char* delim = argv[++i];
+ int dlen = (int)strlen(delim);
+ if (dlen > 0 && (delim[0] == '"' || delim[0] == '\'')) {
+ delim++; dlen -= 2; if (dlen < 0) dlen = 0;
+ delim[dlen] = '\0';
+ }
+ int pfd[2];
+ if (pipe(pfd) == 0) {
+ tty_restore();
+ char hline[LINE_MAX];
+ while (1) {
+ write(STDOUT_FILENO, "> ", 2);
+ int hi = 0;
+ char hc;
+ while (read(STDIN_FILENO, &hc, 1) == 1) {
+ if (hc == '\n') break;
+ if (hi < LINE_MAX - 1) hline[hi++] = hc;
+ }
+ hline[hi] = '\0';
+ if (strcmp(hline, delim) == 0) break;
+ write(pfd[1], hline, hi);
+ write(pfd[1], "\n", 1);
+ }
+ close(pfd[1]);
+ heredoc_fd = pfd[0];
+ tty_raw_mode();
+ }
} else if (strcmp(argv[i], "<") == 0 && i + 1 < argc) {
redir_in = argv[++i];
} else {
/* ---- Apply redirections for builtins too ---- */
int saved_stdin = -1, saved_stdout = -1;
- if (redir_in) {
+ if (heredoc_fd >= 0) {
+ saved_stdin = dup(0); dup2(heredoc_fd, 0); close(heredoc_fd); heredoc_fd = -1;
+ } else if (redir_in) {
int fd = open(redir_in, O_RDONLY);
if (fd >= 0) { saved_stdin = dup(0); dup2(fd, 0); close(fd); }
}
--- /dev/null
+/* AdrOS top utility — one-shot process listing with basic info */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+static int is_digit(char c) { return c >= '0' && c <= '9'; }
+
+int main(void) {
+ printf(" PID STATE CMD\n");
+ int fd = open("/proc", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "top: cannot open /proc\n");
+ return 1;
+ }
+ char buf[512];
+ int rc;
+ while ((rc = getdents(fd, buf, sizeof(buf))) > 0) {
+ int off = 0;
+ while (off < rc) {
+ struct dirent* d = (struct dirent*)(buf + off);
+ if (d->d_reclen == 0) break;
+ if (is_digit(d->d_name[0])) {
+ char path[64];
+
+ /* Read cmdline */
+ snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name);
+ int cfd = open(path, O_RDONLY);
+ char cmd[64] = "[kernel]";
+ if (cfd >= 0) {
+ int n = read(cfd, cmd, sizeof(cmd) - 1);
+ if (n > 0) {
+ cmd[n] = '\0';
+ while (n > 0 && (cmd[n-1] == '\n' || cmd[n-1] == '\0')) cmd[--n] = '\0';
+ }
+ if (n <= 0) strcpy(cmd, "[kernel]");
+ close(cfd);
+ }
+
+ /* Read status for state */
+ snprintf(path, sizeof(path), "/proc/%s/status", d->d_name);
+ int sfd = open(path, O_RDONLY);
+ char state[16] = "?";
+ if (sfd >= 0) {
+ char sbuf[256];
+ int sn = read(sfd, sbuf, sizeof(sbuf) - 1);
+ if (sn > 0) {
+ sbuf[sn] = '\0';
+ char* st = strstr(sbuf, "State:");
+ if (st) {
+ st += 6;
+ while (*st == ' ' || *st == '\t') st++;
+ int si = 0;
+ while (*st && *st != '\n' && si < 15) state[si++] = *st++;
+ state[si] = '\0';
+ }
+ }
+ close(sfd);
+ }
+
+ printf("%5s %6s %s\n", d->d_name, state, cmd);
+ }
+ off += d->d_reclen;
+ }
+ }
+ close(fd);
+ return 0;
+}
--- /dev/null
+/* AdrOS which utility — locate a command */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+static int exists_in_dir(const char* dir, const char* name) {
+ int fd = open(dir, O_RDONLY);
+ if (fd < 0) return 0;
+ char buf[2048];
+ int rc;
+ while ((rc = getdents(fd, buf, sizeof(buf))) > 0) {
+ int off = 0;
+ while (off < rc) {
+ struct dirent* d = (struct dirent*)(buf + off);
+ if (d->d_reclen == 0) break;
+ if (strcmp(d->d_name, name) == 0) {
+ close(fd);
+ return 1;
+ }
+ off += d->d_reclen;
+ }
+ }
+ close(fd);
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: which command\n");
+ return 1;
+ }
+
+ static const char* path_dirs[] = { "/bin", "/sbin", NULL };
+ int ret = 1;
+
+ for (int i = 1; i < argc; i++) {
+ int found = 0;
+ for (int d = 0; path_dirs[d]; d++) {
+ if (exists_in_dir(path_dirs[d], argv[i])) {
+ printf("%s/%s\n", path_dirs[d], argv[i]);
+ found = 1;
+ break;
+ }
+ }
+ if (found) ret = 0;
+ }
+ return ret;
+}
--- /dev/null
+/* AdrOS who utility — show logged-in users */
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void) {
+ printf("root tty1 Jan 1 00:00\n");
+ return 0;
+}