Next cleanup, that is split off special character parsing in do_prompt() and parse_args(), handle name of line of virtual console and use it in utmp update as well as the session id. Also move the initial TERM variable to open_tty() as we use this later in open_tty(). Signed-off-by: Werner Fink <werner@xxxxxxx> --- term-utils/agetty.c | 458 ++++++++++++++++++++++++++++----------------------- 1 files changed, 255 insertions(+), 203 deletions(-) diff --git a/term-utils/agetty.c b/term-utils/agetty.c index 15998df..35ef1c2 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -27,6 +27,7 @@ #include <sys/file.h> #include <sys/socket.h> #include <netdb.h> +#include <langinfo.h> #include "strutils.h" #include "nls.h" @@ -37,6 +38,19 @@ #ifdef __linux__ # include <sys/param.h> # define USE_SYSLOG +# ifndef DEFAULT_VCTERM +# define DEFAULT_VCTERM "linux" +# endif +# ifndef DEFAULT_STERM +# define DEFAULT_STERM "vt102" +# endif +#else +# ifndef DEFAULT_VCTERM +# define DEFAULT_VCTERM "vt100" +# endif +# ifndef DEFAULT_STERM +# define DEFAULT_STERM "vt100" +# endif #endif /* If USE_SYSLOG is undefined all diagnostics go to /dev/console. */ @@ -112,6 +126,8 @@ struct options { int timeout; /* time-out period */ char *login; /* login program */ char *tty; /* name of tty */ + char *vcline; /* line of virtual console */ + char *term; /* terminal type */ char *initstring; /* modem init string */ char *issue; /* alternative issue file */ int numspeed; /* number of baud rates to try */ @@ -194,12 +210,14 @@ static struct Speedtab speedtab[] = { #undef warn #undef error +static void init_special_char(char* arg, struct options *op); static void parse_args(int argc, char **argv, struct options *op); static void parse_speeds(struct options *op, char *arg); -static void update_utmp(char *line); -static void open_tty(char *tty, struct termios *tp, int local); +static void update_utmp(struct options *op); +static void open_tty(char *tty, struct termios *tp, struct options *op); static void termio_init(struct options *op, struct termios *tp); static void auto_baud(struct termios *tp); +static void output_special_char (unsigned char c, struct options *op, struct termios *tp); static void do_prompt(struct options *op, struct termios *tp); static void next_speed(struct options *op, struct termios *tp); static char *get_logname(struct options *op, @@ -211,6 +229,7 @@ static speed_t bcode(char *s); static void usage(FILE * out) __attribute__((__noreturn__)); static void error(const char *, ...) __attribute__((__noreturn__)) __attribute__((__format__(printf, 1, 2))); static void warn (const char *, ...) __attribute__((__format__(printf, 1, 2))); +static ssize_t safe_write (int fd, const char *buffer, size_t count); /* Fake hostname for ut_host specified on command line. */ static char *fakehost; @@ -232,6 +251,8 @@ int main(int argc, char **argv) 0, /* no timeout */ _PATH_LOGIN, /* default login program */ "tty1", /* default tty line */ + 0, /* line of virtual console */ + DEFAULT_VCTERM, /* terminal type */ "", /* modem init string */ ISSUE, /* default issue file */ 0, /* no baud rates known yet */ @@ -257,13 +278,13 @@ int main(int argc, char **argv) /* Update the utmp file. */ #ifdef SYSV_STYLE - update_utmp(options.tty); + update_utmp(&options); #endif debug("calling open_tty\n"); /* Open the tty as standard { input, output, error }. */ - open_tty(options.tty, &termios, options.flags & F_LOCAL); + open_tty(options.tty, &termios, &options); tcsetpgrp(STDIN_FILENO, getpid()); /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ @@ -273,9 +294,8 @@ int main(int argc, char **argv) /* Write the modem init string and DO NOT flush the buffers. */ if (options.flags & F_INITSTRING) { debug("writing init string\n"); - ignore_result(write - (STDIN_FILENO, options.initstring, - strlen(options.initstring))); + safe_write(STDIN_FILENO, options.initstring, + strlen(options.initstring)); } if (!(options.flags & F_LOCAL)) @@ -325,7 +345,7 @@ int main(int argc, char **argv) termio_final(&options, &termios, &chardata); /* Now the newline character should be properly written. */ - ignore_result(write(STDOUT_FILENO, "\n", 1)); + safe_write(STDOUT_FILENO, "\n", 1); /* Let the login program take care of password validation. */ execl(options.login, options.login, "--", logname, NULL); @@ -392,50 +412,9 @@ static void parse_args(int argc, char **argv, struct options *op) op->flags &= ~F_ISSUE; break; case 'I': - /* - * FIXME: It would be better to use a separate - * function for this task. - */ - { - char ch, *p, *q; - int i; - - op->initstring = xmalloc(strlen(optarg) + 1); - - /* - * Copy optarg into op->initstring decoding \ddd octal - * codes into chars. - */ - q = op->initstring; - p = optarg; - while (*p) { - /* The \\ is converted to \ */ - if (*p == '\\') { - p++; - if (*p == '\\') { - ch = '\\'; - p++; - } else { - /* Handle \000 - \177. */ - ch = 0; - for (i = 1; i <= 3; i++) { - if (*p >= '0' && *p <= '7') { - ch <<= 3; - ch += *p - '0'; - p++; - } else { - break; - } - } - } - *q++ = ch; - } else - *q++ = *p++; - } - *q = '\0'; - op->flags |= F_INITSTRING; - break; - } + init_special_char(optarg, op); + op->flags |= F_INITSTRING; + break; case 'l': op->login = optarg; break; @@ -483,15 +462,29 @@ static void parse_args(int argc, char **argv, struct options *op) if ('0' <= argv[optind][0] && argv[optind][0] <= '9') { /* Assume BSD style speed. */ parse_speeds(op, argv[optind++]); - op->tty = argv[optind]; + if (argc < optind + 1) { + warn(_("not enough arguments")); + usage(stderr); + } + op->tty = argv[optind++]; } else { op->tty = argv[optind++]; - parse_speeds(op, argv[optind]); + if (argc > optind) { + char *v = argv[optind++]; + if ('0' <= *v && *v <= '9') + parse_speeds(op, v); + else + op->speeds[op->numspeed++] = bcode("9600"); + } } - optind++; + /* On virtual console remember the line which is used for */ + if (strncmp(op->tty, "tty", 3) == 0 && + strspn(op->tty + 3, "0123456789") == strlen(op->tty+3)) + op->vcline = op->tty+3; + if (argc > optind && argv[optind]) - setenv("TERM", argv[optind], 1); + op->term = argv[optind]; #ifdef DO_DEVFS_FIDDLING /* @@ -547,11 +540,14 @@ static void parse_speeds(struct options *op, char *arg) #ifdef SYSV_STYLE /* Update our utmp entry. */ -static void update_utmp(char *line) +static void update_utmp(struct options *op) { struct utmp ut; time_t t; - int mypid = getpid(); + pid_t pid = getpid(); + pid_t sid = getsid(0); + char *vcline = op->vcline; + char *line = op->tty; struct utmp *utp; /* @@ -566,7 +562,7 @@ static void update_utmp(char *line) setutent(); /* - * Find mypid in utmp. + * Find my pid in utmp. * * FIXME: Earlier (when was that?) code here tested only utp->ut_type != * INIT_PROCESS, so maybe the >= here should be >. @@ -575,7 +571,7 @@ static void update_utmp(char *line) * maybe login has to be changed as well (is this true?). */ while ((utp = getutent())) - if (utp->ut_pid == mypid + if (utp->ut_pid == pid && utp->ut_type >= INIT_PROCESS && utp->ut_type <= DEAD_PROCESS) break; @@ -585,7 +581,18 @@ static void update_utmp(char *line) } else { /* Some inits do not initialize utmp. */ memset(&ut, 0, sizeof(ut)); - strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); + if (vcline && *vcline) + /* Standard virtual console devices */ + strncpy (ut.ut_id, vcline, sizeof (ut.ut_id)); + else { + size_t len = strlen(line); + char * ptr; + if (len >= sizeof (ut.ut_id)) + ptr = line + len - sizeof (ut.ut_id); + else + ptr = line; + strncpy (ut.ut_id, ptr, sizeof(ut.ut_id)); + } } strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user)); @@ -595,7 +602,8 @@ static void update_utmp(char *line) time(&t); ut.ut_time = t; ut.ut_type = LOGIN_PROCESS; - ut.ut_pid = mypid; + ut.ut_pid = pid; + ut.ut_session = sid; pututline(&ut); endutent(); @@ -611,7 +619,7 @@ static void update_utmp(char *line) flock(lf, LOCK_EX); if ((ut_fd = open(_PATH_WTMP, O_APPEND | O_WRONLY)) >= 0) { - ignore_result(write(ut_fd, &ut, sizeof(ut))); + safe_write(ut_fd, &ut, sizeof(ut)); close(ut_fd); } flock(lf, LOCK_UN); @@ -624,7 +632,7 @@ static void update_utmp(char *line) #endif /* SYSV_STYLE */ /* Set up tty as stdin, stdout & stderr. */ -static void open_tty(char *tty, struct termios *tp, int __attribute__((__unused__)) local) +static void open_tty(char *tty, struct termios *tp, struct options *op) { /* Get rid of the present outputs. */ close(STDOUT_FILENO); @@ -690,6 +698,8 @@ static void open_tty(char *tty, struct termios *tp, int __attribute__((__unused_ ignore_result(chown(tty, 0, 0)); ignore_result(chmod(tty, 0600)); errno = 0; + + setenv("TERM", op->term, 1); } /* Initialize termios settings. */ @@ -816,14 +826,14 @@ static void do_prompt(struct options *op, struct termios *tp) #ifdef ISSUE FILE *fd; int oflag; - int c, i; + int c; struct utsname uts; uname(&uts); #endif /* ISSUE */ /* Issue not in use, start with a new line. */ - ignore_result(write(STDOUT_FILENO, "\r\n", 2)); + safe_write(STDOUT_FILENO, "\r\n", 2); #ifdef ISSUE if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) { /* Save current setting. */ @@ -833,132 +843,10 @@ static void do_prompt(struct options *op, struct termios *tp) tcsetattr(STDIN_FILENO, TCSADRAIN, tp); while ((c = getc(fd)) != EOF) { - if (c == '\\') { - c = getc(fd); - - switch (c) { - case 's': - printf("%s", uts.sysname); - break; - case 'n': - printf("%s", uts.nodename); - break; - case 'r': - printf("%s", uts.release); - break; - case 'v': - printf("%s", uts.version); - break; - case 'm': - printf("%s", uts.machine); - break; - case 'o': - /* - * FIXME: It would be better to use a - * separate function for this task. - */ - { - char domainname[MAXHOSTNAMELEN + 1]; -#ifdef HAVE_GETDOMAINNAME - if (getdomainname(domainname, sizeof(domainname))) -#endif /* HAVE_GETDOMAINNAME */ - strcpy(domainname, "unknown_domain"); - domainname[sizeof(domainname) - 1] = '\0'; - printf("%s", domainname); - break; - } - case 'O': - /* - * FIXME: It would be better to use a - * separate function for this task. - */ - { - char *dom = "unknown_domain"; - char host[MAXHOSTNAMELEN + 1]; - struct addrinfo hints, *info = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - - if (gethostname(host, sizeof(host)) - || getaddrinfo(host, NULL, &hints, &info) - || info == NULL) { - fputs(dom, stdout); - } else { - char *canon; - - if (info->ai_canonname - && (canon = - strchr(info->ai_canonname, '.'))) { - dom = canon + 1; - } - fputs(dom, stdout); - freeaddrinfo(info); - } - break; - } - case 'd': - case 't': - /* - * FIXME: It would be better to use a - * separate function for this task. - */ - { - time_t now; - struct tm *tm; - - time(&now); - tm = localtime(&now); - - if (c == 'd') - printf - ("%s %s %d %d", - nl_langinfo(ABDAY_1 + tm->tm_wday), - nl_langinfo(ABMON_1 + tm->tm_mon), - tm->tm_mday, - /* FIXME: y2070 bug */ - tm->tm_year < 70 ? - tm->tm_year + 2000 : - tm->tm_year + 1900); - else - printf("%02d:%02d:%02d", - tm->tm_hour, tm->tm_min, tm->tm_sec); - break; - } - case 'l': - printf("%s", op->tty); - break; - case 'b': - for (i = 0; speedtab[i].speed; i++) - if (speedtab[i].code == cfgetispeed(tp)) - printf("%ld", speedtab[i].speed); - break; - break; - case 'u': - case 'U': - /* - * FIXME: It would be better to use a - * separate function for this task. - */ - { - 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: - putchar(c); - } - } else - putchar(c); + if (c == '\\') + output_special_char(getc(fd), op, tp); + else + (void) putchar(c); } fflush(stdout); @@ -972,10 +860,10 @@ static void do_prompt(struct options *op, struct termios *tp) { char hn[MAXHOSTNAMELEN + 1]; if (gethostname(hn, sizeof(hn)) == 0) - ignore_result(write(STDIN_FILENO, hn, strlen(hn))); + safe_write(STDIN_FILENO, hn, strlen(hn)); } /* Always show login prompt. */ - ignore_result(write(STDOUT_FILENO, LOGIN, sizeof(LOGIN) - 1)); + safe_write(STDOUT_FILENO, LOGIN, sizeof(LOGIN) - 1); } /* Select next baud rate. */ @@ -1070,9 +958,8 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata /* Set erase character. */ cp->erase = ascval; if (bp > logname) { - ignore_result(write - (STDIN_FILENO, - erase[cp->parity], 3)); + safe_write(STDIN_FILENO, + erase[cp->parity], 3); bp--; } break; @@ -1081,9 +968,8 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata /* Set kill character. */ cp->kill = ascval; while (bp > logname) { - ignore_result(write - (STDIN_FILENO, - erase[cp->parity], 3)); + safe_write(STDIN_FILENO, + erase[cp->parity], 3); bp--; } break; @@ -1096,8 +982,7 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata error(_("%s: input overrun"), op->tty); } else { /* Echo the character... */ - ignore_result(write - (STDIN_FILENO, &c, 1)); + safe_write(STDIN_FILENO, &c, 1); /* ...and store it. */ *bp++ = ascval; } @@ -1307,7 +1192,7 @@ static void dolog(int priority, const char *fmt, va_list ap) /* Terminate with CR-LF since the console mode is unknown. */ strcat(bp, "\r\n"); if ((fd = open("/dev/console", 1)) >= 0) { - ignore_result(write(fd, buf, strlen(buf))); + safe_write(fd, buf, strlen(buf)); close(fd); } #endif /* USE_SYSLOG */ @@ -1335,3 +1220,170 @@ static void warn(const char *fmt, ...) va_end(ap); } +static ssize_t safe_write(int fd, const char *buffer, size_t count) +{ + ssize_t offset = 0; + + while (count > 0) { + ssize_t block = write(fd, &buffer[offset], count); + if (block < 0 && errno == EINTR) + continue; + if (block <= 0) + return offset ? offset : block; + offset += block; + count -= block; + } + return offset; +} +static void output_special_char(unsigned char c, struct options *op, + struct termios *tp) +{ + struct utsname uts; + (void) uname(&uts); + 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[MAXHOSTNAMELEN+1]; +#ifdef HAVE_GETDOMAINNAME + if (getdomainname(domainname, sizeof(domainname))) +#endif + strcpy(domainname, "unknown_domain"); + domainname[sizeof(domainname)-1] = '\0'; + printf ("%s", domainname); + break; + } + case 'O': + { + char *dom = "unknown_domain"; + char host[MAXHOSTNAMELEN+1]; + struct addrinfo hints, *info = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + + if (gethostname(host, sizeof(host)) || + getaddrinfo(host, NULL, &hints, &info) || + info == NULL) + fputs(dom, stdout); + else { + char *canon; + if (info->ai_canonname && + (canon = strchr(info->ai_canonname, '.'))) + dom = canon + 1; + fputs(dom, stdout); + freeaddrinfo(info); + } + break; + } + case 'd': + case 't': + { + time_t now; + struct tm *tm; + + (void) time (&now); + tm = localtime(&now); + + if (c == 'd') /* ISO 8601 */ + (void) printf("%s %s %d %d", + nl_langinfo(ABDAY_1 + tm->tm_wday), + nl_langinfo(ABMON_1 + 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': + { + const speed_t speed = cfgetispeed(tp); + int i; + + for (i = 0; speedtab[i].speed; i++) { + if (speedtab[i].code == speed) { + 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); + break; + } +} + +static void init_special_char(char* arg, struct options *op) +{ + char ch, *p, *q; + int i; + + op->initstring = xmalloc(strlen(arg) + 1); + + /* + * Copy optarg into op->initstring decoding \ddd octal + * codes into chars. + */ + q = op->initstring; + p = arg; + while (*p) { + /* The \\ is converted to \ */ + if (*p == '\\') { + p++; + if (*p == '\\') { + ch = '\\'; + p++; + } else { + /* Handle \000 - \177. */ + ch = 0; + for (i = 1; i <= 3; i++) { + if (*p >= '0' && *p <= '7') { + ch <<= 3; + ch += *p - '0'; + p++; + } else { + break; + } + } + } + *q++ = ch; + } else + *q++ = *p++; + } + *q = '\0'; +} -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html