You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
2.1 KiB
125 lines
2.1 KiB
#define _POSIX_C_SOURCE 200809l
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <pwd.h>
|
|
#include <termios.h>
|
|
|
|
#include "config.h"
|
|
#include "fstr.h"
|
|
#include "err.h"
|
|
|
|
#define S_ESCAPE 0x1
|
|
|
|
fstr_t PS1 = {0};
|
|
unsigned int histsize = DEF_HISTSIZE;
|
|
|
|
// Buffered user data
|
|
struct {
|
|
char *name;
|
|
char *home;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
} uinfo = {0};
|
|
|
|
struct {
|
|
// $ or #
|
|
char tag;
|
|
} shinfo;
|
|
|
|
struct {
|
|
struct termios tio;
|
|
struct termios tio_before;
|
|
} terminfo;
|
|
|
|
void sh_setup_terminal(void);
|
|
void sh_update_uinfo(void);
|
|
void sh_update_shinfo(void);
|
|
void sh_update_ps1(void);
|
|
inline void sh_print_ps1(void);
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
char i;
|
|
unsigned int state = 0;
|
|
|
|
sh_setup_terminal();
|
|
for (;;) {
|
|
sh_update_uinfo();
|
|
sh_update_shinfo();
|
|
sh_update_ps1();
|
|
sh_print_ps1();
|
|
fflush(stdout);
|
|
for (int line = 1; line;) {
|
|
|
|
read(STDIN_FILENO, &i, 1); // This blocks
|
|
fputc(i, stdout);
|
|
fflush(stdout);
|
|
|
|
switch (i) {
|
|
case '\n':
|
|
line = state & S_ESCAPE;
|
|
break;
|
|
case '\\':
|
|
state ^= ~S_ESCAPE;
|
|
break;
|
|
default:
|
|
state &= ~S_ESCAPE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
void sh_setup_terminal(void)
|
|
{
|
|
if (tcgetattr(STDOUT_FILENO, &terminfo.tio_before) == -1)
|
|
die("tcgetattr:");
|
|
terminfo.tio = terminfo.tio_before;
|
|
/* Do not echo and input is available immediately */
|
|
terminfo.tio.c_lflag &= ~ECHO;
|
|
terminfo.tio.c_lflag &= ~ICANON;
|
|
if (tcsetattr(STDOUT_FILENO, TCSANOW, &terminfo.tio) == -1)
|
|
die("tcsetattr:");
|
|
}
|
|
|
|
void sh_update_uinfo(void)
|
|
{
|
|
struct passwd *pw;
|
|
uid_t nuid;
|
|
nuid = getuid();
|
|
if (nuid == uinfo.uid && uinfo.name)
|
|
return;
|
|
uinfo.uid = nuid;
|
|
pw = getpwuid(uinfo.uid);
|
|
// User not found
|
|
if (!pw)
|
|
die("getpwuid:");
|
|
uinfo.gid = pw->pw_gid;
|
|
uinfo.name = estrdup(pw->pw_name);
|
|
uinfo.home = estrdup(pw->pw_dir);
|
|
}
|
|
|
|
void sh_update_shinfo(void)
|
|
{
|
|
shinfo.tag = uinfo.uid ? '$' : '#';
|
|
}
|
|
|
|
void sh_print_ps1(void)
|
|
{
|
|
fputs(PS1.s, stdout);
|
|
}
|
|
|
|
void sh_update_ps1(void)
|
|
{
|
|
fstr_clear(&PS1);
|
|
fstr_append_char(&PS1, shinfo.tag);
|
|
fstr_append_char(&PS1, ' ');
|
|
}
|
|
|