login: Support /etc/issue through login-loop

This commit is contained in:
K. Lange 2021-09-25 12:06:56 +09:00
parent 4bc652365f
commit 9d6ed3feb5
3 changed files with 197 additions and 10 deletions

View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <net/if.h>
#include <arpa/inet.h>
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[] = {

View File

@ -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);

10
base/etc/issue Normal file
View File

@ -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.