📄 getty.c
字号:
debug("open(2)\n"); if (open(tty, O_RDWR | O_NONBLOCK, 0) != 0) error("/dev/%s: cannot open as standard input: %m", tty); } else { /* * Standard input should already be connected to an open port. Make * sure it is open for read/write. */ if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) error("%s: not open for read/write", tty); } /* Set up standard output and standard error file descriptors. */ debug("duping\n"); if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */ error("%s: dup problem: %m", tty); /* we have a problem */ /* * The following ioctl will fail if stdin is not a tty, but also when * there is noise on the modem control lines. In the latter case, the * common course of action is (1) fix your cables (2) give the modem more * time to properly reset after hanging up. SunOS users can achieve (2) * by patching the SunOS kernel variable "zsadtrlow" to a larger value; * 5 seconds seems to be a good value. */ if (ioctl(0, TCGETA, tp) < 0) error("%s: ioctl: %m", tty); /* * It seems to be a terminal. Set proper protections and ownership. Mode * 0622 is suitable for SYSV <4 because /bin/login does not change * protections. SunOS 4 login will change the protections to 0620 (write * access for group tty) after the login has succeeded. */#ifdef DEBIAN { /* tty to root.dialout 660 */ struct group *gr; int id; id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0; chown(tty, 0, id); chmod(tty, 0660); /* vcs,vcsa to root.sys 600 */ if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) { char *vcs, *vcsa; if (!(vcs = strdup(tty))) error("Can't malloc for vcs"); if (!(vcsa = malloc(strlen(tty) + 2))) error("Can't malloc for vcsa"); strcpy(vcs, "vcs"); strcpy(vcs + 3, tty + 3); strcpy(vcsa, "vcsa"); strcpy(vcsa + 4, tty + 3); id = (gr = getgrnam("sys")) ? gr->gr_gid : 0; chown(vcs, 0, id); chmod(vcs, 0600); chown(vcsa, 0, id); chmod(vcs, 0600); free(vcs); free(vcsa); } }#else (void) chown(tty, 0, 0); /* root, sys */ (void) chmod(tty, 0622); /* crw--w--w- */ errno = 0; /* ignore above errors */#endif}/* termio_init - initialize termio settings */static void termio_init(struct termio *tp, int speed, struct options *op){ /* * Initial termio settings: 8-bit characters, raw-mode, blocking i/o. * Special characters are set after we have read the login name; all * reads will be done in raw mode anyway. Errors will be dealt with * lateron. */#ifdef __linux__ /* flush input and output queues, important for modems! */ (void) ioctl(0, TCFLSH, TCIOFLUSH);#endif tp->c_cflag = CS8 | HUPCL | CREAD | speed; if (op->flags & F_LOCAL) { tp->c_cflag |= CLOCAL; } tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0; tp->c_cc[VMIN] = 1; tp->c_cc[VTIME] = 0; /* Optionally enable hardware flow control */#ifdef CRTSCTS if (op->flags & F_RTSCTS) tp->c_cflag |= CRTSCTS;#endif (void) ioctl(0, TCSETA, tp); /* go to blocking input even in local mode */ fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK); debug("term_io 2\n");}/* auto_baud - extract baud rate from modem status message */static void auto_baud(struct termio *tp){ int speed; int vmin; unsigned iflag; char buf[BUFSIZ]; char *bp; int nread; /* * This works only if the modem produces its status code AFTER raising * the DCD line, and if the computer is fast enough to set the proper * baud rate before the message has gone by. We expect a message of the * following format: * * <junk><number><junk> * * The number is interpreted as the baud rate of the incoming call. If the * modem does not tell us the baud rate within one second, we will keep * using the current baud rate. It is advisable to enable BREAK * processing (comma-separated list of baud rates) if the processing of * modem status messages is enabled. */ /* * Use 7-bit characters, don't block if input queue is empty. Errors will * be dealt with lateron. */ iflag = tp->c_iflag; tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ vmin = tp->c_cc[VMIN]; tp->c_cc[VMIN] = 0; /* don't block if queue empty */ (void) ioctl(0, TCSETA, tp); /* * Wait for a while, then read everything the modem has said so far and * try to extract the speed of the dial-in call. */ (void) sleep(1); if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) { buf[nread] = '\0'; for (bp = buf; bp < buf + nread; bp++) { if (isascii(*bp) && isdigit(*bp)) { if ((speed = bcode(bp))) { tp->c_cflag &= ~CBAUD; tp->c_cflag |= speed; } break; } } } /* Restore terminal settings. Errors will be dealt with lateron. */ tp->c_iflag = iflag; tp->c_cc[VMIN] = vmin; (void) ioctl(0, TCSETA, tp);}/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */static void do_prompt(struct options *op, struct termio *tp){#ifdef ISSUE FILE *fd; int oflag; int c; struct utsname uts; (void) uname(&uts);#endif (void) write(1, "\r\n", 2); /* start a new line */#ifdef ISSUE /* optional: show /etc/issue */ if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) { oflag = tp->c_oflag; /* save current setting */ tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */ (void) ioctl(0, TCSETAW, tp); while ((c = getc(fd)) != EOF) { if (c == '\\') { c = getc(fd); switch (c) { case 's': (void) printf("%s", uts.sysname); break; case 'n': (void) printf("%s", uts.nodename); break; case 'r': (void) printf("%s", uts.release); break; case 'v': (void) printf("%s", uts.version); break; case 'm': (void) printf("%s", uts.machine); break; case 'o': { char domainname[256]; getdomainname(domainname, sizeof(domainname)); domainname[sizeof(domainname) - 1] = '\0'; printf("%s", domainname); } break; case 'd': case 't': { char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; time_t now; struct tm *tm; (void) time(&now); tm = localtime(&now); if (c == 'd') (void) printf("%s %s %d %d", weekday[tm->tm_wday], month[tm->tm_mon], tm->tm_mday, tm->tm_year < 70 ? tm->tm_year + 2000 : tm->tm_year + 1900); else (void) printf("%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); break; } case 'l': (void) printf("%s", op->tty); break; case 'b': { int i; for (i = 0; speedtab[i].speed; i++) { if (speedtab[i].code == (tp->c_cflag & CBAUD)) { printf("%ld", speedtab[i].speed); break; } } break; } case 'u': case 'U': { int users = 0; struct utmp *ut; setutent(); while ((ut = getutent())) if (ut->ut_type == USER_PROCESS) users++; endutent(); printf("%d ", users); if (c == 'U') printf((users == 1) ? "user" : "users"); break; } default: (void) putchar(c); } } else (void) putchar(c); } fflush(stdout); tp->c_oflag = oflag; /* restore settings */ (void) ioctl(0, TCSETAW, tp); /* wait till output is gone */ (void) fclose(fd); }#endif#ifdef __linux__ { char hn[MAXHOSTNAMELEN + 1]; (void) gethostname(hn, MAXHOSTNAMELEN); write(1, hn, strlen(hn)); }#endif (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* always show login prompt */}/* next_speed - select next baud rate */static void next_speed(struct termio *tp, struct options *op){ static int baud_index = FIRST_SPEED; /* current speed index */ baud_index = (baud_index + 1) % op->numspeed; tp->c_cflag &= ~CBAUD; tp->c_cflag |= op->speeds[baud_index]; (void) ioctl(0, TCSETA, tp);}/* get_logname - get user name, establish parity, speed, erase, kill, eol *//* return NULL on failure, logname on success */static char *get_logname(struct options *op, struct chardata *cp, struct termio *tp){ static char logname[BUFSIZ]; char *bp; char c; /* input character, full eight bits */ char ascval; /* low 7 bits of input character */ int bits; /* # of "1" bits per character */ int mask; /* mask with 1 bit up */ static char *erase[] = { /* backspace-space-backspace */ "\010\040\010", /* space parity */ "\010\040\010", /* odd parity */ "\210\240\210", /* even parity */ "\210\240\210", /* no parity */ }; /* Initialize kill, erase, parity etc. (also after switching speeds). */ *cp = init_chardata; /* Flush pending input (esp. after parsing or switching the baud rate). */ (void) sleep(1); (void) ioctl(0, TCFLSH, TCIFLUSH); /* Prompt for and read a login name. */ for (*logname = 0; *logname == 0; /* void */ ) { /* Write issue file and prompt, with "parity" bit == 0. */ do_prompt(op, tp); /* Read name, watch for break, parity, erase, kill, end-of-line. */ for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) { /* Do not report trivial EINTR/EIO errors. */ if (read(0, &c, 1) < 1) { if (errno == EINTR || errno == EIO) exit(0); error("%s: read: %m", op->tty); } /* Do BREAK handling elsewhere. */ if ((c == 0) && op->numspeed > 1) /* return (0); */ return NULL; /* Do parity bit handling. */ if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */ for (bits = 1, mask = 1; mask & 0177; mask <<= 1) if (mask & ascval) bits++; /* count "1" bits */ cp->parity |= ((bits & 1) ? 1 : 2); } /* Do erase, kill and end-of-line processing. */ switch (ascval) { case CR: case NL: *bp = 0; /* terminate logname */ cp->eol = ascval; /* set end-of-line char */ break; case BS: case DEL: case '#': cp->erase = ascval; /* set erase character */ if (bp > logname) { (void) write(1, erase[cp->parity], 3); bp--; } break; case CTL('U'): case '@': cp->kill = ascval; /* set kill character */ while (bp > logname) { (void) write(1, erase[cp->parity], 3); bp--; } break; case CTL('D'): exit(0); default: if (!isascii(ascval) || !isprint(ascval)) { /* ignore garbage characters */ ; } else if (bp - logname >= sizeof(logname) - 1) { error("%s: input overrun", op->tty); } else { (void) write(1, &c, 1); /* echo the character */ *bp++ = ascval; /* and store it */ } break; } } } /* Handle names with upper case and no lower case. */ if ((cp->capslock = caps_lock(logname))) { for (bp = logname; *bp; bp++) if (isupper(*bp)) *bp = tolower(*bp); /* map name to lower case */ } return (logname);}/* termio_final - set the final tty mode bits */static void termio_final(struct options *op, struct termio *tp, struct chardata *cp){ /* General terminal-independent stuff. */ tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; /* no longer| ECHOCTL | ECHOPRT */ tp->c_oflag |= OPOST; /* tp->c_cflag = 0; */ tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ tp->c_cc[VEOL] = DEF_EOL;#ifdef __linux__ tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */#else tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */#endif /* Account for special characters seen in input. */ if (cp->eol == CR) { tp->c_iflag |= ICRNL; /* map CR in input to NL */ tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ } tp->c_cc[VERASE] = cp->erase; /* set erase character */ tp->c_cc[VKILL] = cp->kill; /* set kill character */ /* Account for the presence or absence of parity bits in input. */ switch (cp->parity) { case 0: /* space (always 0) parity */ break; case 1: /* odd parity */ tp->c_cflag |= PARODD; /* FALLTHROUGH */ case 2: /* even parity */ tp->c_cflag |= PARENB; tp->c_iflag |= INPCK | ISTRIP; /* FALLTHROUGH */ case (1 | 2): /* no parity bit */ tp->c_cflag &= ~CSIZE; tp->c_cflag |= CS7; break; } /* Account for upper case without lower case. */ if (cp->capslock) { tp->c_iflag |= IUCLC; tp->c_lflag |= XCASE; tp->c_oflag |= OLCUC; } /* Optionally enable hardware flow control */#ifdef CRTSCTS if (op->flags & F_RTSCTS) tp->c_cflag |= CRTSCTS;#endif /* Finally, make the new settings effective */ if (ioctl(0, TCSETA, tp) < 0) error("%s: ioctl: TCSETA: %m", op->tty);}/* caps_lock - string contains upper case without lower case *//* returns 1 if true, 0 if false */static int caps_lock(const char *s){ int capslock; for (capslock = 0; *s; s++) { if (islower(*s)) return (0); if (capslock == 0) capslock = isupper(*s); } return (capslock);}/* bcode - convert speed string to speed code; return 0 on failure */static int bcode(const char *s){ struct Speedtab *sp; long speed = atol(s); for (sp = speedtab; sp->speed; sp++) if (sp->speed == speed) return (sp->code); return (0);}/* error - report errors to console or syslog; only understands %s and %m */#define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)/* * output error messages */static void error(const char *fmt, ...){ va_list va_alist; char buf[256], *bp;#ifndef USE_SYSLOG int fd;#endif#ifdef USE_SYSLOG buf[0] = '\0'; bp = buf;#else strncpy(buf, applet_name, 256); strncat(buf, ": ", 256); buf[255] = 0; bp = buf + strlen(buf);#endif va_start(va_alist, fmt); vsnprintf(bp, 256 - strlen(buf), fmt, va_alist); buf[255] = 0; va_end(va_alist);#ifdef USE_SYSLOG syslog_msg(LOG_AUTH, LOG_ERR, buf);#else strncat(bp, "\r\n", 256 - strlen(buf)); buf[255] = 0; if ((fd = open("/dev/console", 1)) >= 0) { write(fd, buf, strlen(buf)); close(fd); }#endif (void) sleep((unsigned) 10); /* be kind to init(8) */ exit(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -