]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/lxc_console.c
From: Daniel Lezcano <daniel.lezcano@free.fr>
[mirror_lxc.git] / src / lxc / lxc_console.c
index b16b29fc0516323aa064561024f6db3f9db49115..6a9881a4f0321b3572d60e184f3c6142cbe75340 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+
+#define _GNU_SOURCE
 #include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
 #include <unistd.h>
+#include <signal.h>
+#include <libgen.h>
+#include <sys/param.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
 
-#include <lxc/lxc.h>
+#include "error.h"
+#include "lxc.h"
 
-int main(int argc, char *argv[])
+void usage(char *cmd)
 {
-       return 0;
+       fprintf(stderr, "%s <command>\n", basename(cmd));
+       fprintf(stderr, "\t -n <name>   : name of the container\n");
+       fprintf(stderr, "\t -t <tty#>   : tty number\n");
+       _exit(1);
 }
 
+int main(int argc, char *argv[])
+{
+       char opt;
+       char *name = NULL;
+       int ttynum = 0;
+       int nbargs = 0;
+       int master = -1;
+       int wait4q = 0;
+       int err = LXC_ERROR_INTERNAL;
+       struct termios tios, oldtios;
+
+       while ((opt = getopt(argc, argv, "t:n:")) != -1) {
+               switch (opt) {
+               case 'n':
+                       name = optarg;
+                       break;
+               case 't':
+                       ttynum = atoi(optarg);
+                       break;
+               }
+
+               nbargs++;
+       }
+
+       if (!name || !ttynum)
+               usage(argv[0]);
+
+       /* Get current termios */
+       if (tcgetattr(0, &tios)) {
+               lxc_log_error("failed to get current terminal settings");
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               return 1;
+       }
+
+       oldtios = tios;
+
+       /* Remove the echo characters and signal reception, the echo
+        * will be done below with master proxying */
+       tios.c_iflag &= ~IGNBRK;
+       tios.c_iflag &= BRKINT;
+       tios.c_lflag &= ~(ECHO|ICANON|ISIG);
+       tios.c_cc[VMIN] = 1;
+       tios.c_cc[VTIME] = 0;
+
+       /* Set new attributes */
+       if (tcsetattr(0, TCSAFLUSH, &tios)) {
+               lxc_log_syserror("failed to set new terminal settings");
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               return 1;
+       }
+
+       err = lxc_console(name, ttynum, &master);
+       if (err) {
+               fprintf(stderr, "%s\n", lxc_strerror(err));
+               goto out;
+       }
+
+       fprintf(stderr, "\nType <Ctrl+a q> to exit the console\n");
+
+       setsid();
+
+       err = 0;
+
+       /* let's proxy the tty */
+       for (;;) {
+               char c;
+               struct pollfd pfd[2] = {
+                       { .fd = 0,
+                         .events = POLLIN|POLLPRI,
+                         .revents = 0 },
+                       { .fd = master,
+                         .events = POLLIN|POLLPRI,
+                         .revents = 0 },
+               };
+
+               if (poll(pfd, 2, -1) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       lxc_log_syserror("failed to poll");
+                       goto out_err;
+               }
+               
+               /* read the "stdin" and write that to the master
+                */
+               if (pfd[0].revents & POLLIN) {
+                       read(0, &c, 1);
+
+                       /* we want to exit the console with Ctrl+a q */
+                       if (c == 1) {
+                               wait4q = !wait4q;
+                               continue;
+                       }
+
+                       if (c == 'q' && wait4q)
+                               goto out;
+
+                       wait4q = 0;
+                       write(master, &c, 1);
+               }
+
+               /* other side has closed the connection */
+               if (pfd[1].revents & POLLHUP)
+                       goto out;
+
+               /* read the master and write to "stdout" */
+               if (pfd[1].revents & POLLIN) {
+                       read(master, &c, 1);
+                       printf("%c", c);
+                       fflush(stdout);
+               }
+       }
+out:
+       /* Restore previous terminal parameter */
+       tcsetattr(0, TCSAFLUSH, &oldtios);
+       
+       /* Return to line it is */
+       printf("\n");
+
+       close(master);
+
+       return err;
+
+out_err:
+       fprintf(stderr, "%s\n", lxc_strerror(-LXC_ERROR_INTERNAL));
+       err = 1;
+       goto out;
+}