/* * menunix_clone.c * * A simple Menunix-style menu interface for UNIX-like systems (terminal). * * Build: * gcc -o menunix_clone menunix_clone.c * * Run: * ./menunix_clone * * Notes: * - Uses system() to run shell commands (simple and portable). * - Uses $EDITOR environment variable for text editing (falls back to vi/nano). * - Designed as a small demo; not production security-hardened. */ #include #include #include #include #define LINEBUF 512 /* Utility to read a line of input */ static void read_line(char *buf, size_t n) { if (!fgets(buf, n, stdin)) { buf[0] = '\0'; return; } /* strip newline */ size_t len = strlen(buf); if (len && buf[len-1] == '\n') buf[len-1] = '\0'; } /* Wait for Enter */ static void wait_return(void) { printf("\nPress to continue..."); fflush(stdout); char tmp[8]; read_line(tmp, sizeof(tmp)); } /* Run a shell command and display output (system() shows output directly) */ static int run_command(const char *cmd) { if (!cmd || !cmd[0]) return -1; int rc = system(cmd); return rc; } /* File operations submenu */ static void menu_file_ops(void) { char choice[16], arg[LINEBUF], cmd[LINEBUF]; for (;;) { printf("\n----- File Operations -----\n\n"); printf(" 1. List files in current directory\n"); printf(" 2. Copy a file\n"); printf(" 3. Move or rename a file\n"); printf(" 4. Delete a file\n"); printf(" 5. Change directory\n"); printf(" 6. Show current directory\n"); printf(" 7. Return to Main Menu\n\n"); printf("Enter choice (1-7): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { printf("\nExecuting: ls -l\n\n"); run_command("ls -l"); wait_return(); } else if (!strcmp(choice, "2")) { printf("Source file: "); read_line(arg, sizeof(arg)); if (!arg[0]) { printf("Cancelled.\n"); wait_return(); continue; } printf("Destination: "); char dest[LINEBUF]; read_line(dest, sizeof(dest)); if (!dest[0]) { printf("Cancelled.\n"); wait_return(); continue; } snprintf(cmd, sizeof(cmd), "cp -i -- '%s' '%s'", arg, dest); run_command(cmd); wait_return(); } else if (!strcmp(choice, "3")) { printf("Source (or current name): "); read_line(arg, sizeof(arg)); if (!arg[0]) { printf("Cancelled.\n"); wait_return(); continue; } char dest[LINEBUF]; printf("Destination (new name): "); read_line(dest, sizeof(dest)); if (!dest[0]) { printf("Cancelled.\n"); wait_return(); continue; } snprintf(cmd, sizeof(cmd), "mv -i -- '%s' '%s'", arg, dest); run_command(cmd); wait_return(); } else if (!strcmp(choice, "4")) { printf("File to delete: "); read_line(arg, sizeof(arg)); if (!arg[0]) { printf("Cancelled.\n"); wait_return(); continue; } snprintf(cmd, sizeof(cmd), "rm -i -- '%s'", arg); run_command(cmd); wait_return(); } else if (!strcmp(choice, "5")) { printf("Change directory to: "); read_line(arg, sizeof(arg)); if (!arg[0]) { printf("Cancelled.\n"); wait_return(); continue; } if (chdir(arg) == 0) { printf("Directory changed to: "); run_command("pwd"); } else { perror("chdir"); } wait_return(); } else if (!strcmp(choice, "6")) { run_command("pwd"); wait_return(); } else if (!strcmp(choice, "7") || choice[0] == '\0') { break; } else { printf("Invalid choice.\n"); } } } /* Text editing submenu */ static void menu_text_editing(void) { char choice[16], filename[LINEBUF], cmd[LINEBUF]; for (;;) { printf("\n----- Text Editing -----\n\n"); printf(" 1. Edit file (open in $EDITOR)\n"); printf(" 2. View file (pager)\n"); printf(" 3. Return to Main Menu\n\n"); printf("Enter choice (1-3): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { printf("Filename to edit: "); read_line(filename, sizeof(filename)); if (!filename[0]) { printf("Cancelled.\n"); wait_return(); continue; } const char *editor = getenv("EDITOR"); if (!editor || !editor[0]) editor = "vi"; snprintf(cmd, sizeof(cmd), "%s '%s'", editor, filename); run_command(cmd); wait_return(); } else if (!strcmp(choice, "2")) { printf("Filename to view: "); read_line(filename, sizeof(filename)); if (!filename[0]) { printf("Cancelled.\n"); wait_return(); continue; } const char *pager = getenv("PAGER"); if (!pager || !pager[0]) pager = "less"; snprintf(cmd, sizeof(cmd), "%s '%s'", pager, filename); run_command(cmd); wait_return(); } else if (!strcmp(choice, "3") || choice[0] == '\0') { break; } else { printf("Invalid choice.\n"); } } } /* Printing submenu */ static void menu_printing(void) { char choice[16], filename[LINEBUF], cmd[LINEBUF]; for (;;) { printf("\n----- Printing -----\n\n"); printf(" 1. Print a file (lpr or lp)\n"); printf(" 2. List print queue (lpstat/lpq)\n"); printf(" 3. Return to Main Menu\n\n"); printf("Enter choice (1-3): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { printf("Filename to print: "); read_line(filename, sizeof(filename)); if (!filename[0]) { printf("Cancelled.\n"); wait_return(); continue; } /* try lpr then lp */ if (access("/usr/bin/lpr", X_OK) == 0 || access("/bin/lpr", X_OK) == 0) { snprintf(cmd, sizeof(cmd), "lpr '%s'", filename); } else { snprintf(cmd, sizeof(cmd), "lp '%s'", filename); } run_command(cmd); wait_return(); } else if (!strcmp(choice, "2")) { if (access("/usr/bin/lpq", X_OK) == 0 || access("/bin/lpq", X_OK) == 0) { run_command("lpq"); } else { run_command("lpstat -o"); } wait_return(); } else if (!strcmp(choice, "3") || choice[0] == '\0') { break; } else { printf("Invalid choice.\n"); } } } /* Compile and Run submenu */ static void menu_compile_run(void) { char choice[16], filename[LINEBUF], cmd[LINEBUF], outname[LINEBUF]; for (;;) { printf("\n----- Compile and Run Programs -----\n\n"); printf(" 1. Compile C program\n"); printf(" 2. Run executable\n"); printf(" 3. Compile and run in one step\n"); printf(" 4. Return to Main Menu\n\n"); printf("Enter choice (1-4): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { printf("Source filename (e.g., prog.c): "); read_line(filename, sizeof(filename)); if (!filename[0]) { printf("Cancelled.\n"); wait_return(); continue; } printf("Output executable name (or blank for 'a.out'): "); read_line(outname, sizeof(outname)); if (!outname[0]) strcpy(outname, "a.out"); snprintf(cmd, sizeof(cmd), "cc -Wall -o '%s' '%s'", outname, filename); run_command(cmd); wait_return(); } else if (!strcmp(choice, "2")) { printf("Executable name (path): "); read_line(filename, sizeof(filename)); if (!filename[0]) { printf("Cancelled.\n"); wait_return(); continue; } snprintf(cmd, sizeof(cmd), "'%s'", filename); run_command(cmd); wait_return(); } else if (!strcmp(choice, "3")) { printf("Source filename (e.g., prog.c): "); read_line(filename, sizeof(filename)); if (!filename[0]) { printf("Cancelled.\n"); wait_return(); continue; } printf("Output executable name (or blank for 'a.out'): "); read_line(outname, sizeof(outname)); if (!outname[0]) strcpy(outname, "a.out"); snprintf(cmd, sizeof(cmd), "cc -Wall -o '%s' '%s' && './%s'", outname, filename, outname); run_command(cmd); wait_return(); } else if (!strcmp(choice, "4") || choice[0] == '\0') { break; } else { printf("Invalid choice.\n"); } } } /* Mail and messaging submenu */ static void menu_mail(void) { char choice[16], cmd[LINEBUF], to[LINEBUF], subj[LINEBUF], bodyfile[LINEBUF]; for (;;) { printf("\n----- Mail and Messaging -----\n\n"); printf(" 1. Send a simple mail\n"); printf(" 2. Check mail (mailx/mail)\n"); printf(" 3. Return to Main Menu\n\n"); printf("Enter choice (1-3): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { printf("To (username@host): "); read_line(to, sizeof(to)); if (!to[0]) { printf("Cancelled.\n"); wait_return(); continue; } printf("Subject: "); read_line(subj, sizeof(subj)); printf("Enter message body filename (temporary file): "); read_line(bodyfile, sizeof(bodyfile)); if (!bodyfile[0]) { /* if no file provided, create a temp with input until EOF */ char tmpname[] = "/tmp/menunix_msg_XXXXXX"; int fd = mkstemp(tmpname); if (fd == -1) { perror("mkstemp"); wait_return(); continue; } printf("Enter message. End with a single line containing only a dot '.'\n"); FILE *tf = fdopen(fd, "w"); if (!tf) { perror("fdopen"); close(fd); wait_return(); continue; } char line[LINEBUF]; for (;;) { read_line(line, sizeof(line)); if (!strcmp(line, ".")) break; fprintf(tf, "%s\n", line); } fclose(tf); snprintf(cmd, sizeof(cmd), "cat '%s' | mail -s '%s' %s", tmpname, subj, to); run_command(cmd); snprintf(cmd, sizeof(cmd), "rm -f '%s'", tmpname); run_command(cmd); } else { snprintf(cmd, sizeof(cmd), "cat '%s' | mail -s '%s' %s", bodyfile, subj, to); run_command(cmd); } wait_return(); } else if (!strcmp(choice, "2")) { if (access("/usr/bin/mail", X_OK) == 0 || access("/bin/mail", X_OK) == 0) { run_command("mail"); } else if (access("/usr/bin/mailx", X_OK) == 0 || access("/bin/mailx", X_OK) == 0) { run_command("mailx"); } else { printf("No 'mail' client found on PATH.\n"); } wait_return(); } else if (!strcmp(choice, "3") || choice[0] == '\0') { break; } else { printf("Invalid choice.\n"); } } } /* System information submenu */ static void menu_system_info(void) { char choice[16]; for (;;) { printf("\n----- System Information -----\n\n"); printf(" 1. Show uname (system name)\n"); printf(" 2. Show uptime\n"); printf(" 3. Show disk usage (df -h)\n"); printf(" 4. Show memory (free or vmstat)\n"); printf(" 5. Return to Main Menu\n\n"); printf("Enter choice (1-5): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { run_command("uname -a"); wait_return(); } else if (!strcmp(choice, "2")) { run_command("uptime"); wait_return(); } else if (!strcmp(choice, "3")) { run_command("df -h"); wait_return(); } else if (!strcmp(choice, "4")) { if (access("/usr/bin/free", X_OK) == 0 || access("/bin/free", X_OK) == 0) { run_command("free -h"); } else { run_command("vmstat -s"); } wait_return(); } else if (!strcmp(choice, "5") || choice[0] == '\0') { break; } else { printf("Invalid choice.\n"); } } } /* Change password (calls passwd) */ static void menu_change_password(void) { printf("\n----- Change Password -----\n\n"); if (access("/usr/bin/passwd", X_OK) == 0 || access("/bin/passwd", X_OK) == 0) { run_command("passwd"); } else { printf("'passwd' not found on this system.\n"); } wait_return(); } /* Main */ int main(int argc, char *argv[]) { char choice[16]; /* Greeting */ char *user = getenv("USER"); if (!user) user = getenv("LOGNAME"); if (!user) user = "user"; printf("**********************************************\n"); printf("* M E N U N I X *\n"); printf("* A Menu Interface for the UNIX System *\n"); printf("**********************************************\n\n"); printf("Welcome to Menunix (clone), user: %s\n\n", user); for (;;) { printf("\nPlease choose from the following:\n\n"); printf(" 1. File Operations\n"); printf(" 2. Text Editing\n"); printf(" 3. Printing\n"); printf(" 4. Compile and Run Programs\n"); printf(" 5. Mail and Messaging\n"); printf(" 6. System Information\n"); printf(" 7. Change Password\n"); printf(" 8. Exit to UNIX shell\n\n"); printf("Enter choice (1-8): "); read_line(choice, sizeof(choice)); if (!strcmp(choice, "1")) { menu_file_ops(); } else if (!strcmp(choice, "2")) { menu_text_editing(); } else if (!strcmp(choice, "3")) { menu_printing(); } else if (!strcmp(choice, "4")) { menu_compile_run(); } else if (!strcmp(choice, "5")) { menu_mail(); } else if (!strcmp(choice, "6")) { menu_system_info(); } else if (!strcmp(choice, "7")) { menu_change_password(); } else if (!strcmp(choice, "8")) { printf("\nExiting Menunix... returning to UNIX shell.\n\n"); break; } else if (choice[0] == '\0') { /* treat Enter as redisplay */ continue; } else { printf("Invalid choice.\n"); } } /* Hand control back to user's shell */ printf("$ "); fflush(stdout); /* Exec a shell (respect SHELL env var) */ const char *shell = getenv("SHELL"); if (!shell) shell = "/bin/sh"; execlp(shell, shell, (char *)NULL); /* If execlp fails, fall back to exit */ perror("execlp"); return 0; }