diff --git a/apps/login-loop.c b/apps/login-loop.c index 7f01756a..1f15be65 100644 --- a/apps/login-loop.c +++ b/apps/login-loop.c @@ -1,18 +1,199 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @brief Repeatedly invoke `login` in a loop. + * + * This is more closely related to the 'getty' command in Linux + * than our actual 'getty' command as it is also where we process + * and display /etc/issue. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2018 K. Lange - * - * login-loop - Continuously call `login` - * - * Used by the VGA terminal to provide interactive login sessions. + * Copyright (C) 2018-2021 K. Lange */ #include +#include +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include + +struct colorNames { + const char * name; + const char * output; +} ColorNames[] = { + {"black", "\033[30m"}, + {"blue", "\033[34m"}, + {"bold", "\033[1m"}, + {"brown", "\033[33m"}, + {"cyan", "\033[36"}, + {"darkgray", "\033[90m"}, + {"gray", "\033[37m"}, + {"green", "\033[32m"}, + {"lightblue", "\033[94m"}, + {"lightcyan", "\033[96m"}, + {"lightgray", "\033[97m"}, + {"lightgreen", "\033[92m"}, + {"lightmagenta", "\033[95m"}, + {"lightred", "\033[91m"}, + {"magenta", "\033[35m"}, + {"red", "\033[31m"}, + {"reset", "\033[0m"}, + {"reverse", "\033[7m"}, + {"yellow", "\033[93m"}, + {NULL, NULL}, +}; + +char * get_arg(FILE * f) { + static char buf[32]; + int n = fgetc(f); + if (n == '{') { + int count = 0; + do { + int x = fgetc(f); + if (x == '}') break; + if (x < 0) break; + buf[count++] = x; + buf[count] = '\0'; + } while (count < 31); + if (count) return buf; + } + return NULL; +} + +char * get_ipv4_address(char * arg) { + if (arg) { + char if_path[1024]; + snprintf(if_path, 300, "/dev/net/%s", arg); + int netdev = open(if_path, O_RDWR); + if (netdev >= 0) { + uint32_t ip_addr = 0; + if (!ioctl(netdev, SIOCGIFADDR, &ip_addr)) { + return inet_ntoa((struct in_addr){ntohl(ip_addr)}); + } + } + } else { + /* Read /dev/net for interfaces */ + DIR * d = opendir("/dev/net"); + if (d) { + struct dirent * ent; + while ((ent = readdir(d))) { + if (ent->d_name[0] == '.') continue; + closedir(d); + return get_ipv4_address(ent->d_name); + } + closedir(d); + } + } + + return "127.0.0.1"; +} + +void print_issue(void) { + printf("\033[H\033[2J"); + fflush(stdout); + + FILE * f = fopen("/etc/issue","r"); + if (!f) return; + + /* Parse and display /etc/issue with support + * for some escape sequences that fill in + * dynamic information... */ + + struct utsname u; + uname(&u); + + struct tm * timeinfo; + struct timeval now; + gettimeofday(&now, NULL); + timeinfo = localtime((time_t *)&now.tv_sec); + + static char buf[1024]; + + while (!feof(f)) { + int c = fgetc(f); + + if (c < 0) break; /* Probably EOF */ + + if (c == '\\') { + int next = fgetc(f); + switch (next) { + case '\n': + /* A linefeed we should quietly skip. */ + continue; + case '\\': + /* A literal backslash */ + printf("\\"); + continue; + + /* Various things from uname */ + case 'n': + printf("%s", u.nodename); + continue; + case 's': + printf("%s", u.sysname); + continue; + case 'r': + printf("%s", u.release); + continue; + case 'm': + printf("%s", u.machine); + continue; + case 'v': + printf("%s", u.version); + continue; + + /* Various other useful things */ + case '4': + printf("%s", get_ipv4_address(get_arg(f))); + continue; + case 'l': + printf("%s", ttyname(STDIN_FILENO)); + continue; + case 't': + strftime(buf,1024,"%T %Z",timeinfo); + printf("%s", buf); + continue; + case 'd': + strftime(buf,1024,"%a %b %d %Y",timeinfo); + printf("%s", buf); + continue; + + /* Formatting stuff listed in Linux's getty(8) manpage */ + case 'e': { + char * arg = get_arg(f); + if (arg) { + for (struct colorNames * cn = ColorNames; cn->name; cn++) { + if (!strcmp(arg,cn->name)) { + printf("%s", cn->output); + break; + } + } + } else { + printf("\033"); + } + continue; + } + } + } else { + printf("%c", c); + } + } + + + fclose(f); +} int main(int argc, char * argv[]) { while (1) { + print_issue(); pid_t f = fork(); if (!f) { char * args[] = { diff --git a/apps/login.c b/apps/login.c index 203aeb99..911294c6 100644 --- a/apps/login.c +++ b/apps/login.c @@ -69,10 +69,6 @@ int main(int argc, char ** argv) { } } - printf("\n"); - system("uname -a"); - printf("\n"); - signal(SIGINT, sig_pass); signal(SIGWINCH, sig_pass); signal(SIGSEGV, sig_segv); diff --git a/base/etc/issue b/base/etc/issue new file mode 100644 index 00000000..8c7bee89 --- /dev/null +++ b/base/etc/issue @@ -0,0 +1,10 @@ +\e{bold}\t\e{reset} on \e{bold}\d\e{reset} +\e{yellow}\l\e{reset} on \e{lightblue}\n\e{reset} - \e{bold}\s \r\e{reset} + + This live CD has two available user accounts: \e{bold}local\e{reset} is listed in /etc/sudoers + and \e{bold} guest\e{reset} is not. For both accounts, the password is the same as the account + name. The \e{bold}root\e{reset} account can also be accessed directly with the password \e{bold}toor\e{reset}. + You may also type \e{bold}restart\e{reset} at the login prompt to reboot. Please note that + VGA text mode and serial terminal access provides only a limited subset of the + available functionality of ToaruOS. +