master xplshn/aruu / cmd / pseudo / getty.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <sys/ioctl.h>
  4#include <sys/stat.h>
  5#include <sys/types.h>
  6
  7#include <fcntl.h>
  8#include <limits.h>
  9#include <signal.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <string.h>
 13#include <unistd.h>
 14#include <utmp.h>
 15
 16#include "config.h"
 17#include "util.h"
 18#include "wexec.h"
 19
 20static char *tty         = "/dev/tty1";
 21static char *defaultterm = "linux";
 22
 23static void
 24usage(void)
 25{
 26  eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0);
 27}
 28
 29// ?man getty: set terminal mode
 30// ?man arguments: tty [term] [cmd] [args ...]
 31// ?man set terminal line discipline, speed, and mode
 32int
 33main(int argc, char *argv[])
 34{
 35  char             term[128], logname[LOGIN_NAME_MAX], c;
 36  char             hostname[HOST_NAME_MAX + 1];
 37  char             ut_line_buf[UT_LINESIZE + 1];
 38  struct utmp      usr;
 39  struct sigaction sa;
 40  FILE            *fp;
 41  int              fd;
 42  unsigned int     i = 0;
 43  ssize_t          n;
 44  long             pos;
 45
 46  ARGBEGIN
 47  {
 48    default:
 49      usage();
 50  }
 51  ARGEND;
 52
 53  strlcpy(term, defaultterm, sizeof(term));
 54  if (argc > 0) {
 55    tty = argv[0];
 56    if (argc > 1)
 57      strlcpy(term, argv[1], sizeof(term));
 58  }
 59
 60  sa.sa_handler = SIG_IGN;
 61  sa.sa_flags   = 0;
 62  sigemptyset(&sa.sa_mask);
 63  sigaction(SIGHUP, &sa, NULL);
 64
 65  setenv("TERM", term, 1);
 66
 67  setsid();
 68
 69  fd = open(tty, O_RDWR);
 70  if (fd < 0)
 71    eprintf("open %s:", tty);
 72  if (isatty(fd) == 0)
 73    eprintf("%s is not a tty\n", tty);
 74
 75  /* steal the controlling terminal if necessary */
 76  if (ioctl(fd, TIOCSCTTY, (void *)1) != 0)
 77    weprintf("TIOCSCTTY: could not set controlling tty\n");
 78  vhangup();
 79  close(fd);
 80
 81  fd = open(tty, O_RDWR);
 82  if (fd < 0)
 83    eprintf("open %s:", tty);
 84  dup2(fd, 0);
 85  dup2(fd, 1);
 86  dup2(fd, 2);
 87  if (fchown(fd, 0, 0) < 0)
 88    weprintf("fchown %s:", tty);
 89  if (fchmod(fd, 0600) < 0)
 90    weprintf("fchmod %s:", tty);
 91  if (fd > 2)
 92    close(fd);
 93
 94  sa.sa_handler = SIG_DFL;
 95  sa.sa_flags   = 0;
 96  sigemptyset(&sa.sa_mask);
 97  sigaction(SIGHUP, &sa, NULL);
 98
 99  /* Clear all utmp entries for this tty */
100  fp = fopen(UTMP_PATH, "r+");
101  if (fp) {
102    do {
103      pos = ftell(fp);
104      if (fread(&usr, sizeof(usr), 1, fp) != 1)
105        break;
106      if (usr.ut_line[0] == '\0')
107        continue;
108      memcpy(ut_line_buf, usr.ut_line, UT_LINESIZE);
109      ut_line_buf[UT_LINESIZE] = '\0';
110      if (strcmp(ut_line_buf, tty) != 0)
111        continue;
112      memset(&usr, 0, sizeof(usr));
113      fseek(fp, pos, SEEK_SET);
114      if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
115        break;
116    } while (1);
117    if (ferror(fp))
118      weprintf("%s: I/O error:", UTMP_PATH);
119    fclose(fp);
120  }
121
122  if (argc > 2) {
123    wexecvp_self(argv[2], argv + 2);
124    return 0;
125  }
126
127  if (gethostname(hostname, sizeof(hostname)) == 0)
128    printf("%s ", hostname);
129  printf("login: ");
130  fflush(stdout);
131
132  /* Flush pending input */
133  ioctl(0, TCFLSH, (void *)0);
134  memset(logname, 0, sizeof(logname));
135  while (1) {
136    n = read(0, &c, 1);
137    if (n < 0)
138      eprintf("read:");
139    if (n == 0)
140      return 1;
141    if (i >= sizeof(logname) - 1)
142      eprintf("login name too long\n");
143    if (c == '\n' || c == '\r')
144      break;
145    logname[i++] = c;
146  }
147  if (logname[0] == '-')
148    eprintf("login name cannot start with '-'\n");
149  if (logname[0] == '\0')
150    return 1;
151  wexecvp_self("login", (char *const[]){"login", "-p", logname, NULL});
152  return 0;
153}