diff options
author | LAN-TW <lantw44@gmail.com> | 2013-10-23 23:58:37 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-10-23 23:58:37 +0800 |
commit | 246435b6ac1acd202eb6a3eff10cfc5a43a0781b (patch) | |
tree | fbaba706ef0e8146093a8e16b7ee9666950e6a07 | |
parent | 0cd8997ea2de12bf7da2cabc6956f4a008e18c7c (diff) | |
download | cn2013-246435b6ac1acd202eb6a3eff10cfc5a43a0781b.tar.gz cn2013-246435b6ac1acd202eb6a3eff10cfc5a43a0781b.tar.zst cn2013-246435b6ac1acd202eb6a3eff10cfc5a43a0781b.zip |
HW1: RasSession 已準備好可以啟動 RasShell
-rw-r--r-- | hw1/Makefile.am | 14 | ||||
-rw-r--r-- | hw1/configure.ac | 7 | ||||
-rw-r--r-- | hw1/server-main.c | 21 | ||||
-rw-r--r-- | hw1/session.c | 156 | ||||
-rw-r--r-- | hw1/shell-main.c | 9 | ||||
-rw-r--r-- | hw1/shell.c | 11 | ||||
-rw-r--r-- | hw1/shell.h | 6 | ||||
-rw-r--r-- | hw1/socktool.c | 45 | ||||
-rw-r--r-- | hw1/socktool.h | 4 |
9 files changed, 264 insertions, 9 deletions
diff --git a/hw1/Makefile.am b/hw1/Makefile.am index a35e644..a72eb45 100644 --- a/hw1/Makefile.am +++ b/hw1/Makefile.am @@ -2,7 +2,7 @@ NULL = EXTRA_DIST = autogen.sh -bin_PROGRAMS = ras-server +bin_PROGRAMS = ras-server ras-shell noinst_LIBRARIES = libbasic.a libras.a libbasic_a_SOURCES = \ @@ -16,10 +16,20 @@ libras_a_SOURCES = \ connection.c connection.h \ $(NULL) +shell_sources = \ + shell.c shell.h \ + $(NULL) + ras_server_SOURCES = \ server.c server.h \ session.c session.h \ + $(shell_sources) \ server-main.c \ $(NULL) - ras_server_LDADD = $(top_builddir)/libbasic.a $(top_builddir)/libras.a + +ras_shell_SOURCES = \ + $(shell_sources) \ + shell-main.c \ + $(NULL) +ras_shell_LDADD = $(top_builddir)/libbasic.a $(top_builddir)/libras.a diff --git a/hw1/configure.ac b/hw1/configure.ac index e13206a..40a8113 100644 --- a/hw1/configure.ac +++ b/hw1/configure.ac @@ -22,12 +22,15 @@ AC_C_VOLATILE AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_PID_T -AC_TYPE_UINT16_T +AC_TYPE_OFF_T +AC_TYPE_UID_T # Checks for library functions. +AC_FUNC_FORK +test x"$ac_cv_func_fork_works" != xyes && AC_MSG_ERROR([We need a working fork]) AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS([setgroups initgroups]) +AC_CHECK_FUNCS([setgroups initgroups getdtablesize]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/hw1/server-main.c b/hw1/server-main.c index 4a7bfb0..e313c0e 100644 --- a/hw1/server-main.c +++ b/hw1/server-main.c @@ -22,11 +22,11 @@ #include <unistd.h> static volatile sig_atomic_t quit_request = false; -static void quit_request_setter (int signo) { +static void server_quit_request_setter (int signo) { quit_request = true; } -static void cleanup_child (int signo) { +static void server_cleanup_child (int signo) { while (waitpid (-1, NULL, WUNTRACED | WNOHANG) > 0); } @@ -73,17 +73,26 @@ int main (int argc, char* argv[]) { }; sigemptyset (&action.sa_mask); sigaction (SIGPIPE, &action, NULL); - action.sa_handler = cleanup_child; + sigaction (SIGHUP, &action, NULL); + action.sa_handler = server_cleanup_child; sigaction (SIGCHLD, &action, NULL); - action.sa_handler = quit_request_setter; + action.sa_handler = server_quit_request_setter; sigaction (SIGINT, &action, NULL); sigaction (SIGQUIT, &action, NULL); sigaction (SIGTERM, &action, NULL); + /* XXX 設定 standard I/O buffer mode,為後面的 shell 做準備 */ + setvbuf (stdin, NULL, _IOLBF, 0); + setvbuf (stdout, NULL, _IOLBF, 0); + setvbuf (stderr, NULL, _IONBF, 0); + List* svrlist = list_create (); int sid = 0, cid = 0; RasServer svr; + /* XXX Check before unlink */ + unlink ("/tmp/ras-server.sock"); + ras_server_init (&svr, RAS_CONN_PERM_ADMIN, AF_LOCAL, NULL, sid), sid++; if (ras_server_listen (&svr, "/tmp/ras-server.sock", 0600) < 0) { return 1; @@ -169,6 +178,10 @@ int main (int argc, char* argv[]) { sigaction (SIGINT, &action, NULL); sigaction (SIGQUIT, &action, NULL); sigaction (SIGTERM, &action, NULL); + /* detach from the controlling terminal */ + if (setsid () < 0) { + exit (1); + } if (ras_session_init (&session, server, session_fd, cid) < 0) { ras_session_destroy (&session); exit (1); diff --git a/hw1/session.c b/hw1/session.c index 40a0e65..b8e122e 100644 --- a/hw1/session.c +++ b/hw1/session.c @@ -2,21 +2,29 @@ # include "config.h" #endif +#define _XOPEN_SOURCE 600 +#define _BSD_SOURCE + #include "session.h" #include "xwrap.h" #include "socktool.h" #include "connection.h" #include "server.h" +#include "shell.h" #include "basic-array.h" +#include <fcntl.h> #include <errno.h> #include <grp.h> #include <pwd.h> +#include <signal.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> +#include <sys/select.h> #include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> int ras_session_init (RasSession* session, RasServer* server, int fd, int id) { @@ -192,9 +200,155 @@ int ras_session_read_header (RasSession* session) { } } - return 0; } +static volatile sig_atomic_t child_terminated; +static pid_t child_pid; +static void session_child_terminated_setter (int signo) { + int status; + if (waitpid (child_pid, &status, WUNTRACED | WNOHANG) < 0) { + return; + } + if (WIFEXITED (status) || WIFSIGNALED (status)) { + child_terminated = true; + } else if (WIFSTOPPED (status)) { + kill (child_pid, SIGCONT); + } +} + int ras_session_start_shell (RasSession* session) { + const char noshell_msg[] = "Error: Unable to start shell.\n"; + const int noshell_len = STATIC_STRLEN (noshell_msg); + const char nopty_msg[] = "Error: Cannot allocate a pseudo-tty.\n"; + const int nopty_len = STATIC_STRLEN (nopty_msg); + int sockpair[2]; /* parent = 0, child = 1 */ + char* slave_dev = NULL; + + child_terminated = false; + child_pid = -1; + struct sigaction session_action = { + .sa_handler = session_child_terminated_setter, + .sa_flags = 0 + }; + sigaction (SIGCHLD, &session_action, NULL); + + if (session->shell_use_pty) { + session->shell_stdio = posix_openpt (O_RDWR | O_NOCTTY); + if (session->shell_stdio < 0) { + write (RAS_CONN (session)->fd, nopty_msg, nopty_len); + ras_session_log (session, "cannot posix_openpt: %s", strerror (errno)); + return -1; + } + if (grantpt (session->shell_stdio) < 0) { + write (RAS_CONN (session)->fd, nopty_msg, nopty_len); + ras_session_log (session, "cannot grantpt: %s", strerror (errno)); + close (session->shell_stdio); + return -1; + } + if (unlockpt (session->shell_stdio) < 0) { + write (RAS_CONN (session)->fd, nopty_msg, nopty_len); + ras_session_log (session, "cannot unlockpt: %s", strerror (errno)); + close (session->shell_stdio); + return -1; + } + if ((slave_dev = ptsname (session->shell_stdio)) == NULL) { + write (RAS_CONN (session)->fd, nopty_msg, nopty_len); + ras_session_log (session, "cannot ptsname: %s", strerror (errno)); + close (session->shell_stdio); + return -1; + } + } else { + if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sockpair) < 0) { + write (RAS_CONN (session)->fd, noshell_msg, noshell_len); + ras_session_log (session, "cannot socketpair: %s", strerror (errno)); + return -1; + } + session->shell_stdio = sockpair[0]; + } + + fflush (stdout); + fflush (stderr); + + session->shell_pid = fork (); + if (session->shell_pid < 0) { + write (RAS_CONN (session)->fd, noshell_msg, noshell_len); + ras_session_log (session, "cannot fork to run shell: %s", strerror (errno)); + return -1; + } else if (session->shell_pid > 0) { + /* parent process */ + fd_set rset, rresult; + int child, sock, nfds; + + child_pid = session->shell_pid; + child = session->shell_stdio; + sock = RAS_CONN (session)->fd; + nfds = xmax (child, sock) + 1; + + FD_ZERO (&rset); + FD_SET (child, &rset); + FD_SET (sock, &rset); + + while (!child_terminated) { + rresult = rset; + if (select (nfds, &rresult, NULL, NULL, NULL) >= 0) { + if (session->buffer.buf_len == 0) { + if (FD_ISSET (child, &rresult)) { + int rval = read (child, session->buffer.buf, RAS_BUFFER_SIZE); + if (rval <= 0) { + continue; + } + ras_socktool_write_string (sock, session->buffer.buf, rval); + } + if (FD_ISSET (sock, &rresult)) { + int rval = read (sock, session->buffer.buf, RAS_BUFFER_SIZE); + if (rval <= 0) { + continue; + } + ras_socktool_write_string (child, session->buffer.buf, rval); + } + } else { + ras_socktool_write_string ( + child, + session->buffer.buf + session->buffer.buf_start, + session->buffer.buf_len); + session->buffer.buf_len = 0; + } + } + } + } else { + /* child process */ + int child_stdio; + + if (slave_dev != NULL) { + child_stdio = open (slave_dev, O_RDWR); + if (child_stdio < 0) { + write (RAS_CONN (session)->fd, nopty_msg, nopty_len); + ras_session_log (session, "cannot open slave pty: %s", strerror (errno)); + exit (1); + } +#ifdef BSD + if (ioctl (child_stdio, TIOCSCTTY, NULL) < 0) { + write (RAS_CONN (session)->fd, nopty_msg, nopty_len); + ras_session_log (session, "cannot set controlling terminal: %s", strerror (errno)); + exit (1); + } +#endif + } else { + child_stdio = sockpair[1]; + } + + ras_socktool_reset_signals (); + + ras_socktool_close_except (child_stdio); + dup2 (child_stdio, STDIN_FILENO); + dup2 (child_stdio, STDOUT_FILENO); + dup2 (child_stdio, STDERR_FILENO); + close (child_stdio); + + char* argv[] = { "-ras-shell", NULL }; + exit (ras_shell_main (1, argv)); + } + + return 0; } diff --git a/hw1/shell-main.c b/hw1/shell-main.c new file mode 100644 index 0000000..d46aea7 --- /dev/null +++ b/hw1/shell-main.c @@ -0,0 +1,9 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "shell.h" + +int main (int argc, char* argv[]) { + return ras_shell_main (argc, argv); +} diff --git a/hw1/shell.c b/hw1/shell.c new file mode 100644 index 0000000..1060054 --- /dev/null +++ b/hw1/shell.c @@ -0,0 +1,11 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> + +int ras_shell_main (int argc, char* argv[]) { + printf ("Hello World\n"); + return 0; +} diff --git a/hw1/shell.h b/hw1/shell.h new file mode 100644 index 0000000..1b73d35 --- /dev/null +++ b/hw1/shell.h @@ -0,0 +1,6 @@ +#ifndef RAS_SHELL_H +#define RAS_SHELL_H + +int ras_shell_main (int argc, char* argv[]); + +#endif /* RAS_SHELL_H */ diff --git a/hw1/socktool.c b/hw1/socktool.c index c554775..cf60b31 100644 --- a/hw1/socktool.c +++ b/hw1/socktool.c @@ -8,6 +8,7 @@ #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> +#include <signal.h> #include <stdbool.h> #include <string.h> #include <sys/socket.h> @@ -160,3 +161,47 @@ int ras_socktool_write_string (int sockfd, const char* str, size_t size) { rem = rem > 0 ? rem : 0; return size - rem; } + +void ras_socktool_reset_signals (void) { + const int must_reset[] = { SIGHUP, SIGINT, SIGQUIT, SIGABRT, + SIGFPE, SIGTERM, SIGCHLD, SIGTSTP, SIGTTIN, SIGTTOU }; + struct sigaction action = { + .sa_handler = SIG_DFL, + .sa_flags = 0 + }; + sigemptyset (&action.sa_mask); +#if defined(SIGRTMIN) && defined(SIGRTMAX) + int signal_max = xmax (SIGRTMIN, SIGRTMAX); + for (int i = 1; i < signal_max; i++) { + sigaction (i, &action, NULL); + } +#endif + for (int i = 0; i < sizeof (must_reset) / sizeof (int); i++) { + sigaction (must_reset[i], &action, NULL); + } +} + +int ras_socktool_getdtablesize (void) { +#ifdef HAVE_GETDTABLESIZE + return getdtablesize (); +#else + long rval = sysconf (_SC_OPEN_MAX); + if (rval < 0) { +# ifdef _POSIX_OPEN_MAX + rval = _POSIX_OPEN_MAX +# else + rval = 20; +# endif + } + return rval; +#endif +} + +void ras_socktool_close_except (int dontclose) { + int dtsize = ras_socktool_getdtablesize (); + for (int i = 0; i < dtsize; i++) { + if (i != dontclose) { + close (i); + } + } +} diff --git a/hw1/socktool.h b/hw1/socktool.h index 4cf4383..543a188 100644 --- a/hw1/socktool.h +++ b/hw1/socktool.h @@ -30,4 +30,8 @@ void ras_socktool_buffer_free_line (RasBuffer* buf); char* ras_socktool_getline (int sockfd, RasBuffer* buf, int delim, int* len); int ras_socktool_write_string (int sockfd, const char* str, size_t size); +void ras_socktool_reset_signals (void); +int ras_socktool_getdtablesize (void); +void ras_socktool_close_except (int dontclose); + #endif /* RAS_SOCKTOOL_H */ |