#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "shell-builtin.h" #include "xwrap.h" #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> const RasShellBuiltin ras_shell_builtins[] = { RAS_SHELL_BUILTIN_ENTRY (cd), RAS_SHELL_BUILTIN_ENTRY (echo), RAS_SHELL_BUILTIN_ENTRY (exit), RAS_SHELL_BUILTIN_ENTRY (false), RAS_SHELL_BUILTIN_ENTRY (logout), RAS_SHELL_BUILTIN_ENTRY (printenv), RAS_SHELL_BUILTIN_ENTRY (pwd), RAS_SHELL_BUILTIN_ENTRY (set), RAS_SHELL_BUILTIN_ENTRY (setenv), RAS_SHELL_BUILTIN_ENTRY (shopt), RAS_SHELL_BUILTIN_ENTRY (tacat), RAS_SHELL_BUILTIN_ENTRY (tapipe), RAS_SHELL_BUILTIN_ENTRY (true), RAS_SHELL_BUILTIN_ENTRY (tty), RAS_SHELL_BUILTIN_ENTRY (type), RAS_SHELL_BUILTIN_ENTRY (umask), RAS_SHELL_BUILTIN_ENTRY (unset), RAS_SHELL_BUILTIN_ENTRY (unsetenv), RAS_SHELL_BUILTIN_ENTRY_NULL }; int ras_shell_builtin_cd (int argc, char* argv[], RasShell* shell) { if (shell->attr_rshell) { fprintf (stderr, "%s: you are not permitted to run this command\n", argv[0]); return 1; } char* dest = argv[1]; if (dest == NULL) { dest = getenv ("HOME"); if (dest == NULL) { dest = "."; } } if (chdir (dest) < 0) { fprintf (stderr, "cd: %s: %s\n", dest, strerror (errno)); return 1; } return 0; } int ras_shell_builtin_echo (int argc, char* argv[], RasShell* shell) { for (int i = 1; argv[i] != NULL; i++) { if (i > 1) { putchar (' '); } fputs (argv[i], stdout); } putchar ('\n'); return 0; } int ras_shell_builtin_exit (int argc, char* argv[], RasShell* shell) { if (argc > 2) { fprintf (stderr, "%s: too many arguments\n", argv[0]); return 1; } if (argc < 2) { shell->req_exit_status = 0; } else if (sscanf (argv[1], "%d", &shell->req_exit_status) < 1) { fprintf (stderr, "%s: `%s\' is not a number\n", argv[0], argv[1]); return 1; } shell->req_exit = true; return 0; } int ras_shell_builtin_false (int argc, char* argv[], RasShell* shell) { return 1; } int ras_shell_builtin_logout (int argc, char* argv[], RasShell* shell) { if (!shell->attr_login) { fprintf (stderr, "%s: not a login shell\n", argv[0]); return 1; } return ras_shell_builtin_exit (argc, argv, shell); } int ras_shell_builtin_printenv (int argc, char* argv[], RasShell* shell) { if (argc > 2) { fprintf (stderr, "%s: too many arguments\n", argv[0]); return 1; } if (argc < 2) { extern char** environ; for (int i = 0; environ[i] != NULL; i++) { puts (environ[i]); } } else { char* res = getenv (argv[1]); if (res == NULL) { return 1; } puts (res); } return 0; } int ras_shell_builtin_pwd (int argc, char* argv[], RasShell* shell) { char* cwd = xgetcwd (); if (cwd == NULL) { fprintf (stderr, "%s: cannot get working directory: %s\n", argv[0], strerror (errno)); return 1; } puts (cwd); free (cwd); return 0; } int ras_shell_builtin_set (int argc, char* argv[], RasShell* shell) { fputs ("This command has not been implemented. Try `setenv\' or `shopt\'.\n", stderr); return 1; } int ras_shell_builtin_setenv (int argc, char* argv[], RasShell* shell) { if (argc != 3) { fprintf ( stderr, "%s: too %s arguments\n", argv[0], argc > 3 ? "many" : "few"); return 1; } return - setenv (argv[1], argv[2], 1); } static inline const char* bstr (bool b) { return b ? "on" : "off"; } int ras_shell_builtin_shopt (int argc, char* argv[], RasShell* shell) { if (argc > 3) { fprintf (stderr, "%s: too many arguments\n", argv[0]); return 1; } bool printall = argc == 1; bool print = argc <= 2; bool value; int rval = 0; if (argc == 3) { if (strcmp (argv[2], "on") == 0) { value = true; } else if (strcmp (argv[2], "off") == 0) { value = false; } else { fprintf (stderr, "%s: invalid value `%s\'\n", argv[0], argv[2]); return 1; } } if (printall || strcmp (argv[1], "login_shell") == 0) { if (print) { printf ("login_shell %s\n", bstr (shell->attr_login)); } else { fputs ("login_shell attribute cannot be modified.\n", stderr); rval = 1; } } if (printall || strcmp (argv[1], "restricted") == 0) { if (print) { printf ("restricted %s\n", bstr (shell->attr_rshell)); } else { fputs ("restricted attribute cannot be modified.\n", stderr); rval = 1; } } if (printall || strcmp (argv[1], "debug") == 0) { if (print) { printf ("debug %s\n", bstr (shell->attr_debug)); } else { shell->attr_debug = value; } } if (printall || strcmp (argv[1], "is_term") == 0) { if (print) { printf ("is_term %s\n", bstr (shell->attr_isterm)); } else { fputs ("is_term attribute cannot be modified.\n", stderr); rval = 1; } } return rval; } int ras_shell_builtin_umask (int argc, char* argv[], RasShell* shell) { if (argc > 2) { fprintf (stderr, "%s: too many arguments\n", argv[0]); return 1; } if (argc < 2) { mode_t old_mode = umask (0777); umask (old_mode); printf ("%04o\n", old_mode); } else { int mode_int; if (sscanf (argv[1], "%o", &mode_int) < 0) { fprintf (stderr, "%s: `%s\' is not a valid octal number\n", argv[0], argv[1]); return 1; } mode_t new_mode = mode_int; umask (new_mode); } return 0; } int ras_shell_builtin_tacat (int argc, char* argv[], RasShell* shell) { int rval = 0; for (int i = 1; i < argc; i++) { char* f = xstrcat (shell->saved_tmpdir, "/", argv[i], NULL); int fd = open (f, O_RDONLY); if (fd < 0) { fprintf (stderr, "%s: fail to open `%s\': %s\n", argv[0], argv[i], strerror (errno)); rval = 1; free (f); break; } char buf[8192]; int readval; while ((readval = read (fd, &buf, 8192)) > 0) { write (STDOUT_FILENO, &buf, readval); } free (f); } return rval; } int ras_shell_builtin_tapipe (int argc, char* argv[], RasShell* shell) { ListNode* iter = list_node_front (shell->saved_list); for (; iter != NULL; iter = list_next (iter)) { RasShellSaved* saved = list_data (iter); printf ("Command %" PRIu64 " input == " "Command %" PRIu64 " output (%s)\n", saved->to, saved->from, saved->cmdorg); } return 0; } int ras_shell_builtin_true (int argc, char* argv[], RasShell* shell) { return 0; } int ras_shell_builtin_tty (int argc, char* argv[], RasShell* shell) { char* ttyn = ttyname (STDIN_FILENO); if (ttyn == NULL) { puts ("not a tty"); return 1; } puts (ttyn); return 0; } int ras_shell_builtin_type (int argc, char* argv[], RasShell* shell) { if (argv[1] == NULL) { return 0; } for (int i = 0; ras_shell_builtins[i].cmd != NULL; i++) { if (strcmp (ras_shell_builtins[i].cmd, argv[1]) == 0) { printf ("%s is a shell builtin\n", argv[1]); return 0; } } printf ( "%s is not understood by the shell ... Is it an external command?\n", argv[1]); return 1; } int ras_shell_builtin_unset (int argc, char* argv[], RasShell* shell) { fputs ("This command has not been implemented. Try `unsetenv\'.\n", stderr); return 1; } int ras_shell_builtin_unsetenv (int argc, char* argv[], RasShell* shell) { for (int i = 1; i < argc; i++) { if (unsetenv (argv[i]) < 0) { fprintf (stderr, "%s: %s: %s\n", argv[0], argv[i], strerror (errno)); return 1; } } return 0; }