Add /bin/sh and /bin/login, demo users
This commit is contained in:
@@ -5,7 +5,8 @@ KERNEL_HDRS?=kernel-hdr
|
||||
CC=x86_64-elf-yggdrasil-gcc
|
||||
|
||||
DIRS=$(O) \
|
||||
$(STAGE)
|
||||
$(STAGE) \
|
||||
$(O)/sh
|
||||
HDRS=$(shell find $(S) -type f -name "*.h")
|
||||
STAGE_BIN=$(STAGE)/init \
|
||||
$(STAGE)/bin/hexd \
|
||||
@@ -14,7 +15,15 @@ STAGE_BIN=$(STAGE)/init \
|
||||
$(STAGE)/bin/date \
|
||||
$(STAGE)/bin/uname \
|
||||
$(STAGE)/bin/mount \
|
||||
$(STAGE)/bin/umount
|
||||
$(STAGE)/bin/umount \
|
||||
$(STAGE)/bin/sh \
|
||||
$(STAGE)/bin/rm \
|
||||
$(STAGE)/bin/mkdir \
|
||||
$(STAGE)/bin/login
|
||||
sh_OBJS=$(O)/sh/sh.o \
|
||||
$(O)/sh/readline.o \
|
||||
$(O)/sh/builtin.o \
|
||||
$(O)/sh/cmd.o
|
||||
|
||||
usr_CFLAGS=-msse \
|
||||
-msse2 \
|
||||
@@ -49,3 +58,9 @@ $(STAGE)/init: init.c
|
||||
|
||||
$(STAGE)/bin/%: core/bin/%.c
|
||||
$(CC) -o $@ $(usr_CFLAGS) $(usr_LDFLAGS) $<
|
||||
|
||||
$(STAGE)/bin/sh: $(sh_OBJS)
|
||||
$(CC) -o $@ $(usr_LDFLAGS) $(sh_OBJS)
|
||||
|
||||
$(O)/sh/%.o: sh/%.c $(shell find sh -name "*.h")
|
||||
$(CC) -c -o $@ $(usr_CFLAGS) $<
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
|
||||
struct spwd {
|
||||
char *sp_namp;
|
||||
char *sp_pwdp;
|
||||
};
|
||||
|
||||
static ssize_t getline(char *buf, size_t lim, char pwchr) {
|
||||
size_t c = 0;
|
||||
char chr;
|
||||
|
||||
while (1) {
|
||||
if (c == lim) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read(STDIN_FILENO, &chr, 1) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (chr) {
|
||||
case '\n':
|
||||
putchar('\n');
|
||||
buf[c] = 0;
|
||||
return c;
|
||||
case '\b':
|
||||
if (c) {
|
||||
buf[--c] = 0;
|
||||
puts2("\033[D \033[D");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (chr >= ' ' && chr < 255) {
|
||||
if (pwchr) {
|
||||
putchar(pwchr);
|
||||
} else {
|
||||
putchar(chr);
|
||||
}
|
||||
buf[c++] = chr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t buf_size) {
|
||||
int fd = open("/etc/shadow", O_RDONLY, 0);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
while (gets_safe(fd, buf, buf_size) > 0) {
|
||||
char *p0 = strchr(buf, ':');
|
||||
if (!p0) {
|
||||
break;
|
||||
}
|
||||
char *p1 = strchr(p0 + 1, ':');
|
||||
if (!p1) {
|
||||
break;
|
||||
}
|
||||
|
||||
*p0 = 0;
|
||||
*p1 = 0;
|
||||
|
||||
if (strcmp(buf, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
sp->sp_namp = buf;
|
||||
sp->sp_pwdp = p0 + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int loginuid(uid_t uid, gid_t gid, const char *sh) {
|
||||
int sh_pid = fork();
|
||||
|
||||
if (sh_pid < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sh_pid == 0) {
|
||||
if (setuid(uid) || setgid(gid)) {
|
||||
perror("login");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
const char *argp[] = { sh, NULL };
|
||||
exit(execve(sh, argp, NULL));
|
||||
} else {
|
||||
int st;
|
||||
waitpid(sh_pid, &st);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int loginas(const char *name) {
|
||||
char pwbuf[512];
|
||||
struct passwd pwd;
|
||||
struct passwd *res;
|
||||
const char *shell;
|
||||
|
||||
if (getpwnam_r(name, &pwd, pwbuf, sizeof(pwbuf), &res) != 0) {
|
||||
perror("getpwnam_r()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
shell = res->pw_shell;
|
||||
|
||||
if (access(shell, X_OK) != 0) {
|
||||
perror(shell);
|
||||
printf("Using /bin/sh instead\n");
|
||||
shell = "/bin/sh";
|
||||
}
|
||||
|
||||
return loginuid(res->pw_uid, res->pw_gid, shell);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Arguments are ignored
|
||||
if (getuid() != 0) {
|
||||
printf("login must be run as root\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int attempt = 0;
|
||||
char line_buf[64];
|
||||
char spnam_buf[128];
|
||||
struct spwd sp;
|
||||
|
||||
while (access("/etc/shadow", R_OK) != 0) {
|
||||
perror("/etc/shadow");
|
||||
// Login as passwordless root?
|
||||
if (loginuid(0, 0, "/bin/sh") != 0) {
|
||||
return -1;
|
||||
}
|
||||
// Maybe after this session /etc/shadow becomes available
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (attempt == 3) {
|
||||
puts2("\033[2J\033[1;1f");
|
||||
attempt = 0;
|
||||
}
|
||||
|
||||
printf("login: ");
|
||||
if (getline(line_buf, sizeof(line_buf), 0) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (getspnam_r(line_buf, &sp, spnam_buf, sizeof(spnam_buf)) != 0) {
|
||||
perror("getspnam_r()");
|
||||
++attempt;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("password: ");
|
||||
if (getline(line_buf, sizeof(line_buf), '*') < 0) {
|
||||
++attempt;
|
||||
continue;
|
||||
}
|
||||
|
||||
// No hashing yet, so just compare passwords
|
||||
if (!strcmp(line_buf, sp.sp_pwdp)) {
|
||||
loginas(sp.sp_namp);
|
||||
// After returning from shell, go here
|
||||
attempt = 3;
|
||||
continue;
|
||||
} else {
|
||||
++attempt;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc <= 1) {
|
||||
printf("usage: mkdir <path> ...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
res += mkdir(argv[i], 0755);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RM_RECURSIVE (1 << 0)
|
||||
|
||||
static int rm_node(const char *path, int flags) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) != 0) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((st.st_mode & S_IFMT) == S_IFDIR) {
|
||||
if (!(flags & RM_RECURSIVE)) {
|
||||
printf("%s: Is a directory\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DIR *dir = opendir(path);
|
||||
if (!dir) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
char child_path[256];
|
||||
int yes = 1;
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) {
|
||||
snprintf(child_path, sizeof(child_path), "%s/%s", path, ent->d_name);
|
||||
|
||||
if (rm_node(child_path, flags) != 0) {
|
||||
yes = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (!yes) {
|
||||
printf("%s: Is a directory\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rmdir(path) != 0) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (unlink(path) != 0) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// 1 - recurse
|
||||
int flags = 0;
|
||||
int c;
|
||||
|
||||
if (argc <= 1) {
|
||||
printf("usage: rm [-r] <path> ...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((c = getopt(argc, argv, "r")) != -1) {
|
||||
switch (c) {
|
||||
case 'r':
|
||||
flags |= RM_RECURSIVE;
|
||||
break;
|
||||
default:
|
||||
printf("usage: rm [-r] <path> ...");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = optind; i < argc; ++i) {
|
||||
rm_node(argv[i], flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
root:toor:
|
||||
alnyan:password:
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "builtin.h"
|
||||
#include "cmd.h"
|
||||
|
||||
#define DEF_BUILTIN(b_name) \
|
||||
static int __bcmd_##b_name(const struct cmd_exec *cmd)
|
||||
#define DECL_BUILTIN(b_name) \
|
||||
{ .name = #b_name, .exec = __bcmd_##b_name }
|
||||
|
||||
struct sh_builtin {
|
||||
const char *name;
|
||||
int (*exec) (const struct cmd_exec *cmd);
|
||||
};
|
||||
|
||||
static struct sh_builtin __builtins[];
|
||||
|
||||
////
|
||||
|
||||
DEF_BUILTIN(exit) {
|
||||
if (cmd->argc > 1) {
|
||||
exit(atoi(cmd->args[1]));
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
DEF_BUILTIN(cd) {
|
||||
if (cmd->argc != 2) {
|
||||
printf("usage: cd <path>\n");
|
||||
return -1;
|
||||
}
|
||||
return chdir(cmd->args[1]);
|
||||
}
|
||||
|
||||
DEF_BUILTIN(clear) {
|
||||
puts2("\033[2J\033[1;1f");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: support usernames (getpwnam_r)
|
||||
DEF_BUILTIN(setid) {
|
||||
if (cmd->argc == 2) {
|
||||
// Assume gid == uid
|
||||
if (setuid(atoi(cmd->args[1])) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (setgid(atoi(cmd->args[1])) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (cmd->argc != 3) {
|
||||
printf("usage: setid <uid> <gid>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setuid(atoi(cmd->args[1])) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (setgid(atoi(cmd->args[2])) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEF_BUILTIN(builtins) {
|
||||
for (size_t i = 0; __builtins[i].name; ++i) {
|
||||
printf("%s ", __builtins[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
static struct sh_builtin __builtins[] = {
|
||||
DECL_BUILTIN(builtins),
|
||||
DECL_BUILTIN(cd),
|
||||
DECL_BUILTIN(clear),
|
||||
DECL_BUILTIN(exit),
|
||||
DECL_BUILTIN(setid),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
int builtin_exec(const struct cmd_exec *cmd, int *cmd_res) {
|
||||
for (size_t i = 0; i < sizeof(__builtins) / sizeof(__builtins[0]); ++i) {
|
||||
if (!strcmp(__builtins[i].name, cmd->args[0])) {
|
||||
*cmd_res = __builtins[i].exec(cmd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
struct cmd_exec;
|
||||
|
||||
int builtin_exec(const struct cmd_exec *cmd, int *res);
|
||||
@@ -0,0 +1,121 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "builtin.h"
|
||||
#include "config.h"
|
||||
#include "cmd.h"
|
||||
|
||||
static int make_cmd(char *input, struct cmd_exec *ex) {
|
||||
char *p = strchr(input, ' ');
|
||||
char *e;
|
||||
|
||||
if (!p) {
|
||||
ex->args[0] = input;
|
||||
ex->args[1] = NULL;
|
||||
ex->argc = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*p++ = 0;
|
||||
ex->args[0] = input;
|
||||
ex->argc = 1;
|
||||
|
||||
while (1) {
|
||||
while (isspace(*p)) {
|
||||
++p;
|
||||
}
|
||||
if (!*p) {
|
||||
break;
|
||||
}
|
||||
|
||||
e = strchr(p, ' ');
|
||||
|
||||
if (!e) {
|
||||
ex->args[ex->argc++] = p;
|
||||
break;
|
||||
} else {
|
||||
*e++ = 0;
|
||||
ex->args[ex->argc++] = p;
|
||||
p = e;
|
||||
}
|
||||
}
|
||||
ex->args[ex->argc] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static int cmd_spawn(const char *path, const struct cmd_exec *cmd, int *cmd_res) {
|
||||
int pid;
|
||||
|
||||
if ((pid = fork()) < 0) {
|
||||
perror("fork()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
exit(execve(path, (const char *const *) cmd->args, NULL));
|
||||
} else {
|
||||
if (waitpid(pid, cmd_res) != 0) {
|
||||
perror("waitpid()");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_exec_binary(const struct cmd_exec *cmd, int *cmd_res) {
|
||||
char path_path[256];
|
||||
int res;
|
||||
|
||||
if (cmd->args[0][0] == '.' || cmd->args[0][0] == '/') {
|
||||
if ((res = access(cmd->args[0], X_OK)) != 0) {
|
||||
perror(cmd->args[0]);
|
||||
return res;
|
||||
}
|
||||
|
||||
strcpy(path_path, cmd->args[0]);
|
||||
return cmd_spawn(path_path, cmd, cmd_res);
|
||||
}
|
||||
|
||||
snprintf(path_path, sizeof(path_path), "%s/%s", PATH, cmd->args[0]);
|
||||
if ((res = access(path_path, X_OK)) == 0) {
|
||||
return cmd_spawn(path_path, cmd, cmd_res);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cmd_exec(const struct cmd_exec *cmd) {
|
||||
int res, cmd_res;
|
||||
|
||||
if ((res = builtin_exec(cmd, &cmd_res)) == 0) {
|
||||
return cmd_res;
|
||||
}
|
||||
|
||||
if ((res = cmd_exec_binary(cmd, &cmd_res)) == 0) {
|
||||
return cmd_res;
|
||||
}
|
||||
|
||||
printf("sh: command not found: %s\n", cmd->args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int eval(char *str) {
|
||||
struct cmd_exec cmd;
|
||||
|
||||
while (isspace(*str)) {
|
||||
++str;
|
||||
}
|
||||
|
||||
if (!*str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (make_cmd(str, &cmd) != 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
return cmd_exec(&cmd);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
struct cmd_exec {
|
||||
size_t argc;
|
||||
char *args[12];
|
||||
};
|
||||
|
||||
int eval(char *str);
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#define COLOR_RED "\033[31m"
|
||||
#define COLOR_GREEN "\033[32m"
|
||||
#define COLOR_YELLOW "\033[33m"
|
||||
#define COLOR_MAGENTA "\033[35m"
|
||||
#define COLOR_CYAN "\033[36m"
|
||||
#define COLOR_RESET "\033[0m"
|
||||
|
||||
// TODO: take this from env (kernel does not support env yet)
|
||||
#define PATH "/bin"
|
||||
#define PS1 COLOR_MAGENTA "%u" COLOR_RESET \
|
||||
"@" \
|
||||
COLOR_CYAN "%h" COLOR_RESET " " \
|
||||
COLOR_YELLOW "%d" COLOR_RESET \
|
||||
" %# "
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
#include <sys/select.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define KEY_UP (256)
|
||||
#define KEY_DOWN (257)
|
||||
#define KEY_RIGHT (258)
|
||||
#define KEY_LEFT (259)
|
||||
|
||||
// With support for escape sequences
|
||||
static int getch_del(void) {
|
||||
struct timeval tv = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 500000
|
||||
};
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
int res;
|
||||
|
||||
if ((res = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv)) < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &fds)) {
|
||||
res = 0;
|
||||
if (read(STDIN_FILENO, &res, 1) != 1) {
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int escape_read(void) {
|
||||
// Maybe [
|
||||
int c = getch_del();
|
||||
|
||||
if (c < 0) {
|
||||
return '\033';
|
||||
}
|
||||
|
||||
if (c != '[') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = getch_del();
|
||||
|
||||
switch (c) {
|
||||
case 'A':
|
||||
return KEY_UP;
|
||||
case 'B':
|
||||
return KEY_DOWN;
|
||||
case 'C':
|
||||
return KEY_RIGHT;
|
||||
case 'D':
|
||||
return KEY_LEFT;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int getch(void) {
|
||||
char c;
|
||||
|
||||
if (read(STDIN_FILENO, &c, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c == '\033') {
|
||||
int r = escape_read();
|
||||
|
||||
if (r > 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int readline(char *buf, size_t lim) {
|
||||
int len = 0;
|
||||
int cur = 0;
|
||||
int chr;
|
||||
|
||||
while (1) {
|
||||
if ((chr = getch()) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == lim) {
|
||||
printf("Input line is too long\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (chr) {
|
||||
case KEY_LEFT:
|
||||
if (cur) {
|
||||
puts2("\033[D");
|
||||
--cur;
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
if (cur < len) {
|
||||
puts2("\033[C");
|
||||
++cur;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (chr == '\n') {
|
||||
putchar(chr);
|
||||
buf[len] = 0;
|
||||
break;
|
||||
} else if (chr == '\b') {
|
||||
if (cur) {
|
||||
--cur;
|
||||
for (int i = cur; i < len - 1; ++i) {
|
||||
buf[i] = buf[i + 1];
|
||||
}
|
||||
puts2("\033[D\033[s");
|
||||
--len;
|
||||
for (int i = cur; i < len; ++i) {
|
||||
putchar(buf[i]);
|
||||
}
|
||||
puts2(" \033[u");
|
||||
}
|
||||
} else if (chr >= ' ' && chr < 255) {
|
||||
putchar(chr);
|
||||
puts2("\033[s");
|
||||
for (int i = cur; i < len; ++i) {
|
||||
putchar(buf[i]);
|
||||
}
|
||||
puts2("\033[u");
|
||||
for (int i = len; i > cur; --i) {
|
||||
buf[i] = buf[i - 1];
|
||||
}
|
||||
buf[cur++] = chr;
|
||||
++len;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
int readline(char *buf, size_t lim);
|
||||
@@ -0,0 +1,93 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "readline.h"
|
||||
#include "config.h"
|
||||
#include "cmd.h"
|
||||
|
||||
// Data needed for prompt
|
||||
static char p_hostname[64];
|
||||
static char p_username[64];
|
||||
static char p_cwd[256];
|
||||
static uid_t p_uid;
|
||||
//static gid_t p_gid;
|
||||
|
||||
static void update_prompt(void) {
|
||||
struct utsname _u;
|
||||
struct passwd _p;
|
||||
struct passwd *p;
|
||||
char pwbuf[512];
|
||||
|
||||
p_uid = getuid();
|
||||
|
||||
if (getcwd(p_cwd, sizeof(p_cwd)) == NULL) {
|
||||
perror("getcwd()");
|
||||
p_cwd[0] = 0;
|
||||
}
|
||||
|
||||
if (uname(&_u) != 0) {
|
||||
perror("uname()");
|
||||
p_hostname[0] = 0;
|
||||
} else {
|
||||
strcpy(p_hostname, _u.nodename);
|
||||
}
|
||||
|
||||
if (getpwuid_r(p_uid, &_p, pwbuf, sizeof(pwbuf), &p) != 0) {
|
||||
perror("getpwuid_r()");
|
||||
p_username[0] = 0;
|
||||
} else {
|
||||
strcpy(p_username, p->pw_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_prompt(void) {
|
||||
const char *p = PS1;
|
||||
|
||||
while (*p) {
|
||||
if (*p == '%') {
|
||||
switch (*++p) {
|
||||
case '#':
|
||||
putchar(p_uid == 0 ? '#' : '$');
|
||||
break;
|
||||
case 'h':
|
||||
puts2(p_hostname);
|
||||
break;
|
||||
case 'u':
|
||||
puts2(p_username);
|
||||
break;
|
||||
case 'd':
|
||||
puts2(p_cwd);
|
||||
break;
|
||||
default:
|
||||
putchar('%');
|
||||
putchar(*p);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
putchar(*p);
|
||||
}
|
||||
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char linebuf[256];
|
||||
int res;
|
||||
|
||||
while (1) {
|
||||
update_prompt();
|
||||
display_prompt();
|
||||
|
||||
if (readline(linebuf, sizeof(linebuf)) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((res = eval(linebuf)) != 0) {
|
||||
printf(COLOR_RED "Status: %d" COLOR_RESET "\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user