summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-10-23 23:58:37 +0800
committerLAN-TW <lantw44@gmail.com>2013-10-23 23:58:37 +0800
commit246435b6ac1acd202eb6a3eff10cfc5a43a0781b (patch)
treefbaba706ef0e8146093a8e16b7ee9666950e6a07
parent0cd8997ea2de12bf7da2cabc6956f4a008e18c7c (diff)
downloadcn2013-246435b6ac1acd202eb6a3eff10cfc5a43a0781b.tar.gz
cn2013-246435b6ac1acd202eb6a3eff10cfc5a43a0781b.tar.zst
cn2013-246435b6ac1acd202eb6a3eff10cfc5a43a0781b.zip
HW1: RasSession 已準備好可以啟動 RasShell
-rw-r--r--hw1/Makefile.am14
-rw-r--r--hw1/configure.ac7
-rw-r--r--hw1/server-main.c21
-rw-r--r--hw1/session.c156
-rw-r--r--hw1/shell-main.c9
-rw-r--r--hw1/shell.c11
-rw-r--r--hw1/shell.h6
-rw-r--r--hw1/socktool.c45
-rw-r--r--hw1/socktool.h4
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 */