diff options
author | LAN-TW <lantw44@gmail.com> | 2013-11-08 15:01:44 +0800 |
---|---|---|
committer | b01902062 <b01902062@linux5.csie.ntu.edu.tw> | 2013-11-08 15:01:44 +0800 |
commit | 2b896398274fbb2f47526c6a5607e5591801660d (patch) | |
tree | e3eeddfabc54868badc7eb6319cda5bea36565c0 | |
parent | 4fe722d31f139f21cde77536027c2c4abd86b585 (diff) | |
download | cn2013-2b896398274fbb2f47526c6a5607e5591801660d.tar.gz cn2013-2b896398274fbb2f47526c6a5607e5591801660d.tar.zst cn2013-2b896398274fbb2f47526c6a5607e5591801660d.zip |
HW1: 更新 shell parser 並將 builtin command 移出 shell.c
-rw-r--r-- | hw1/Makefile.am | 1 | ||||
-rw-r--r-- | hw1/shell-builtin.c | 143 | ||||
-rw-r--r-- | hw1/shell-builtin.h | 22 | ||||
-rw-r--r-- | hw1/shell.c | 169 | ||||
-rw-r--r-- | hw1/shell.h | 30 |
5 files changed, 202 insertions, 163 deletions
diff --git a/hw1/Makefile.am b/hw1/Makefile.am index 70e2fb9..82ecd78 100644 --- a/hw1/Makefile.am +++ b/hw1/Makefile.am @@ -18,6 +18,7 @@ libras_a_SOURCES = \ shell_sources = \ shell.c shell.h \ + shell-builtin.c shell-builtin.h \ $(NULL) ras_server_SOURCES = \ diff --git a/hw1/shell-builtin.c b/hw1/shell-builtin.c new file mode 100644 index 0000000..87d0632 --- /dev/null +++ b/hw1/shell-builtin.c @@ -0,0 +1,143 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "shell-builtin.h" + +#include "xwrap.h" + +#include <errno.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[] = { + { "cd", ras_shell_builtin_cd }, + { "echo", ras_shell_builtin_echo }, + { "exit", ras_shell_builtin_exit }, + { "logout", ras_shell_builtin_logout }, + { "printenv", ras_shell_builtin_printenv }, + { "pwd", ras_shell_builtin_pwd }, + { "setenv", ras_shell_builtin_setenv }, + { "umask", ras_shell_builtin_umask }, + { NULL, 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_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_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); +} + +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; +} diff --git a/hw1/shell-builtin.h b/hw1/shell-builtin.h new file mode 100644 index 0000000..ebdec2f --- /dev/null +++ b/hw1/shell-builtin.h @@ -0,0 +1,22 @@ +#ifndef RAS_SHELL_BUILTIN_H +#define RAS_SHELL_BUILTIN_H + +#include "shell.h" + +typedef struct { + char* cmd; + RasShellFunc func; +} RasShellBuiltin; + +extern const RasShellBuiltin ras_shell_builtins[]; + +int ras_shell_builtin_cd (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_echo (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_exit (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_logout (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_printenv (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_pwd (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_setenv (int argc, char* argv[], RasShell* shell); +int ras_shell_builtin_umask (int argc, char* argv[], RasShell* shell); + +#endif /* RAS_SHELL_BUILTIN_H */ diff --git a/hw1/shell.c b/hw1/shell.c index a9095d7..7c67d91 100644 --- a/hw1/shell.c +++ b/hw1/shell.c @@ -2,9 +2,12 @@ # include "config.h" #endif +#include "shell.h" + #include "basic-array.h" #include "basic-list.h" #include "xwrap.h" +#include "shell-builtin.h" #include <ctype.h> #include <errno.h> @@ -52,34 +55,6 @@ typedef struct { pid_t pgid; /* process group ID */ } RasShellCmd; -typedef struct { - char* name; /* This is argv[0]. Do not modify or free it. */ - uint64_t count; - List* saved_list; /* A list of RasShellSaved */ - char* saved_tmpdir; - int last_rval; - pid_t pid; - pid_t pgid; - int attr_login : 1; /* login shell */ - int attr_rshell : 1; /* restricted shell */ - int attr_debug : 1; /* debug message */ - int attr_isterm : 1; /* shell is run in a terminal */ - char* user_name; - char user_ps; - int req_exit : 1; /* request for exit */ - int req_exit_status; /* requested exit status */ - int term_fd; /* shell terminal fd */ - struct termios tmode; /* shell terminal mode */ -} RasShell; - -typedef int (*RasShellFunc) (int argc, char* argv[], RasShell* shell); -typedef char* (*RasShellRead) (void* data); - -typedef struct { - char* cmd; - RasShellFunc func; -} RasShellBuiltin; - #define PARSE_QUOTE_REGULAR '\"' #define PARSE_QUOTE_SUPER '\'' #define PARSE_ESCAPE '\\' @@ -93,121 +68,6 @@ typedef enum { APPEND_LAST } RasShellCmdMode; -static 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; -} - -static 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; -} - -static 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; -} - -static 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); -} - -static 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; -} - -static 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; -} - -static 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 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; -} - static void ras_shell_cmd_comp_init (RasShellCmdComp* comp) { comp->arg = array_create (sizeof (char*), 0); comp->redir_stdin = array_create (sizeof (char), 0); @@ -230,10 +90,6 @@ static void ras_shell_cmd_comp_destroy (RasShellCmdComp* comp) { static void complete_string (Array*** ws, int* append, RasShellCmdComp* comp, bool reinit) { - if (array_getmax (*ws[*append]) <= 0) { - return; - } - char zero = '\0'; array_pushback (*ws[*append], &zero); if (*append == APPEND_STR) { @@ -294,8 +150,6 @@ static int ras_shell_cmd_parse ( } if (is_quoted) { if (*p == quote_char) { - /* complete a string */ - complete_string (ws, &append, &comp, true); is_quoted = false; is_escaped = false; ignore_esc = false; @@ -378,17 +232,6 @@ static void ras_shell_cmd_print (RasShellCmd* cmd) { } static int ras_shell_cmd_run (RasShellCmd* cmd, RasShell* shell) { - const static RasShellBuiltin builtins[] = { - { "cd", ras_shell_builtin_cd }, - { "echo", ras_shell_builtin_echo }, - { "exit", ras_shell_builtin_exit }, - { "logout", ras_shell_builtin_logout }, - { "printenv", ras_shell_builtin_printenv }, - { "pwd", ras_shell_builtin_pwd }, - { "setenv", ras_shell_builtin_setenv }, - { "umask", ras_shell_builtin_umask }, - { NULL, NULL } - }; ListNode* iter = list_node_front (cmd->argrp); pid_t child; @@ -407,13 +250,13 @@ static int ras_shell_cmd_run (RasShellCmd* cmd, RasShell* shell) { RasShellCmdComp* comp = list_data (iter); RasShellFunc builtin_func = NULL; - for (int j = 0; builtins[j].cmd != NULL; j++) { + for (int j = 0; ras_shell_builtins[j].cmd != NULL; j++) { char* cmd = STRV (array_data (comp->arg))[0]; if (cmd == NULL) { continue; } - if (strcmp (builtins[j].cmd, cmd) == 0) { - builtin_func = builtins[j].func; + if (strcmp (ras_shell_builtins[j].cmd, cmd) == 0) { + builtin_func = ras_shell_builtins[j].func; break; } } diff --git a/hw1/shell.h b/hw1/shell.h index 1b73d35..4b9e343 100644 --- a/hw1/shell.h +++ b/hw1/shell.h @@ -1,6 +1,36 @@ #ifndef RAS_SHELL_H #define RAS_SHELL_H +#include "basic-list.h" + +#include <stdint.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> + +typedef struct { + char* name; /* This is argv[0]. Do not modify or free it. */ + uint64_t count; + List* saved_list; /* A list of RasShellSaved */ + char* saved_tmpdir; + int last_rval; + pid_t pid; + pid_t pgid; + int attr_login : 1; /* login shell */ + int attr_rshell : 1; /* restricted shell */ + int attr_debug : 1; /* debug message */ + int attr_isterm : 1; /* shell is run in a terminal */ + char* user_name; + char user_ps; + int req_exit : 1; /* request for exit */ + int req_exit_status; /* requested exit status */ + int term_fd; /* shell terminal fd */ + struct termios tmode; /* shell terminal mode */ +} RasShell; + +typedef int (*RasShellFunc) (int argc, char* argv[], RasShell* shell); +typedef char* (*RasShellRead) (void* data); + int ras_shell_main (int argc, char* argv[]); #endif /* RAS_SHELL_H */ |