petty.c 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * petty - Manage a TTY.
  7. *
  8. * Wraps a serial port (or other dumb connection) with a pty
  9. * and manages a login for it.
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>
  14. #include <fcntl.h>
  15. #include <pty.h>
  16. #include <sys/wait.h>
  17. #include <sys/fswait.h>
  18. int main(int argc, char * argv[]) {
  19. int fd_master, fd_slave, fd_serial;
  20. char * file = "/dev/ttyS0";
  21. char * user = NULL;
  22. if (getuid() != 0) {
  23. fprintf(stderr, "%s: only root can do that\n", argv[0]);
  24. return 1;
  25. }
  26. int opt;
  27. while ((opt = getopt(argc, argv, "a:")) != -1) {
  28. switch (opt) {
  29. case 'a':
  30. user = optarg;
  31. break;
  32. }
  33. }
  34. if (optind < argc) {
  35. file = argv[optind];
  36. }
  37. openpty(&fd_master, &fd_slave, NULL, NULL, NULL);
  38. fd_serial = open(file, O_RDWR);
  39. pid_t child = fork();
  40. if (!child) {
  41. setsid();
  42. dup2(fd_slave, 0);
  43. dup2(fd_slave, 1);
  44. dup2(fd_slave, 2);
  45. system("ttysize -q");
  46. char * tokens[] = {"/bin/login",NULL,NULL,NULL};
  47. if (user) {
  48. tokens[1] = "-f";
  49. tokens[2] = user;
  50. }
  51. execvp(tokens[0], tokens);
  52. exit(1);
  53. } else {
  54. int fds[2] = {fd_serial, fd_master};
  55. while (1) {
  56. int index = fswait2(2,fds,200);
  57. char buf[1024];
  58. int r;
  59. switch (index) {
  60. case 0: /* fd_serial */
  61. r = read(fd_serial, buf, 1);
  62. write(fd_master, buf, 1);
  63. break;
  64. case 1: /* fd_master */
  65. r = read(fd_master, buf, 1024);
  66. write(fd_serial, buf, r);
  67. break;
  68. default: /* timeout */
  69. {
  70. int result = waitpid(child, NULL, WNOHANG);
  71. if (result > 0) {
  72. /* Child login shell has returned (session ended) */
  73. return 0;
  74. }
  75. }
  76. break;
  77. }
  78. }
  79. }
  80. return 0;
  81. }