Compare commits
11 Commits
0f348c192b
...
2ace33176c
Author | SHA1 | Date |
---|---|---|
Jonas 'Sortie' Termansen | 2ace33176c | |
Jonas 'Sortie' Termansen | 159415c3b1 | |
Jonas 'Sortie' Termansen | c6af3bc074 | |
Jonas 'Sortie' Termansen | 3c69791078 | |
Jonas 'Sortie' Termansen | f4152b3863 | |
Jonas 'Sortie' Termansen | 6bab3819e2 | |
Juhani Krekelä | 212539c9de | |
Juhani Krekelä | cc9c031e5e | |
Jonas 'Sortie' Termansen | a8c05711aa | |
Jonas 'Sortie' Termansen | aefec2f7cd | |
Jonas 'Sortie' Termansen | 07dd21146b |
|
@ -440,7 +440,8 @@ static bool log_open(struct log* log)
|
||||||
log->fd = open(log->path, logflags, log->file_mode);
|
log->fd = open(log->path, logflags, log->file_mode);
|
||||||
if ( log->fd < 0 )
|
if ( log->fd < 0 )
|
||||||
{
|
{
|
||||||
log_error(log, "", NULL);
|
if ( errno != EROFS )
|
||||||
|
log_error(log, "", NULL);
|
||||||
// Don't block daemon startup on read-only filesystems.
|
// Don't block daemon startup on read-only filesystems.
|
||||||
return errno == EROFS;
|
return errno == EROFS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2014, 2016, 2017 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2014, 2016, 2017, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -238,6 +238,7 @@ bool BGADevice::Initialize()
|
||||||
Video::ConfigureDevice(this);
|
Video::ConfigureDevice(this);
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
|
||||||
if ( guest_additions )
|
if ( guest_additions )
|
||||||
guest_additions->ReadyVideoDevice(device_index);
|
guest_additions->ReadyVideoDevice(device_index);
|
||||||
#endif
|
#endif
|
||||||
|
@ -609,24 +610,24 @@ static void TryInitializeDevice(uint32_t devaddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool OnDevice(uint32_t devaddr, const pciid_t*, const pcitype_t*, void*,
|
||||||
|
void*)
|
||||||
|
{
|
||||||
|
TryInitializeDevice(devaddr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
pcifind_t bga_pcifind;
|
pcifind_t patterns[2];
|
||||||
memset(&bga_pcifind, 255, sizeof(bga_pcifind));
|
memset(&patterns[0], 255, sizeof(patterns[0]));
|
||||||
bga_pcifind.vendorid = 0x1234;
|
patterns[0].vendorid = 0x1234;
|
||||||
bga_pcifind.deviceid = 0x1111;
|
patterns[0].deviceid = 0x1111;
|
||||||
|
memset(&patterns[1], 255, sizeof(patterns[1]));
|
||||||
|
patterns[1].vendorid = 0x80EE;
|
||||||
|
patterns[1].deviceid = 0xBEEF;
|
||||||
|
|
||||||
uint32_t devaddr = 0;
|
PCI::Search(OnDevice, NULL, patterns, 2);
|
||||||
while ( (devaddr = PCI::SearchForDevices(bga_pcifind, devaddr)) )
|
|
||||||
TryInitializeDevice(devaddr);
|
|
||||||
|
|
||||||
memset(&bga_pcifind, 255, sizeof(bga_pcifind));
|
|
||||||
bga_pcifind.vendorid = 0x80EE;
|
|
||||||
bga_pcifind.deviceid = 0xBEEF;
|
|
||||||
|
|
||||||
devaddr = 0;
|
|
||||||
while ( (devaddr = PCI::SearchForDevices(bga_pcifind, devaddr)) )
|
|
||||||
TryInitializeDevice(devaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace BGA
|
} // namespace BGA
|
||||||
|
|
|
@ -214,13 +214,16 @@ bool login(const char* username)
|
||||||
int pipe_fds[2];
|
int pipe_fds[2];
|
||||||
if ( pipe2(pipe_fds, O_CLOEXEC) < 0 )
|
if ( pipe2(pipe_fds, O_CLOEXEC) < 0 )
|
||||||
return false;
|
return false;
|
||||||
|
char* login_shell;
|
||||||
|
if ( asprintf(&login_shell, "-%s", pwd->pw_shell) < 0 )
|
||||||
|
return close(pipe_fds[0]), close(pipe_fds[1]), false;
|
||||||
sigset_t oldset, sigttou;
|
sigset_t oldset, sigttou;
|
||||||
sigemptyset(&sigttou);
|
sigemptyset(&sigttou);
|
||||||
sigaddset(&sigttou, SIGTTOU);
|
sigaddset(&sigttou, SIGTTOU);
|
||||||
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
|
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
|
||||||
pid_t child_pid = fork();
|
pid_t child_pid = fork();
|
||||||
if ( child_pid < 0 )
|
if ( child_pid < 0 )
|
||||||
return close(pipe_fds[0]), close(pipe_fds[1]), false;
|
return free(login_shell), close(pipe_fds[0]), close(pipe_fds[1]), false;
|
||||||
if ( child_pid == 0 )
|
if ( child_pid == 0 )
|
||||||
{
|
{
|
||||||
sigdelset(&oldset, SIGINT);
|
sigdelset(&oldset, SIGINT);
|
||||||
|
@ -253,10 +256,11 @@ bool login(const char* username)
|
||||||
errno != ENOENT && errno != EACCES) ||
|
errno != ENOENT && errno != EACCES) ||
|
||||||
(execlp("/etc/session", "/etc/session", (const char*) NULL) < 0 &&
|
(execlp("/etc/session", "/etc/session", (const char*) NULL) < 0 &&
|
||||||
errno != ENOENT && errno != EACCES) ||
|
errno != ENOENT && errno != EACCES) ||
|
||||||
execlp(pwd->pw_shell, pwd->pw_shell, (const char*) NULL));
|
execlp(pwd->pw_shell, login_shell, (const char*) NULL));
|
||||||
write(pipe_fds[1], &errno, sizeof(errno));
|
write(pipe_fds[1], &errno, sizeof(errno));
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
|
free(login_shell);
|
||||||
close(pipe_fds[1]);
|
close(pipe_fds[1]);
|
||||||
int errnum;
|
int errnum;
|
||||||
if ( readall(pipe_fds[0], &errnum, sizeof(errnum)) < (ssize_t) sizeof(errnum) )
|
if ( readall(pipe_fds[0], &errnum, sizeof(errnum)) < (ssize_t) sizeof(errnum) )
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
diff -Paur --no-dereference -- dash.upstream/src/cd.c dash/src/cd.c
|
diff -Paur --no-dereference -- dash.upstream/src/cd.c dash/src/cd.c
|
||||||
--- dash.upstream/src/cd.c
|
--- dash.upstream/src/cd.c
|
||||||
+++ dash/src/cd.c
|
+++ dash/src/cd.c
|
||||||
@@ -252,7 +252,7 @@
|
@@ -268,7 +268,7 @@
|
||||||
STATIC char *
|
STATIC char *
|
||||||
getpwd()
|
getpwd()
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,24 @@ diff -Paur --no-dereference -- dash.upstream/src/exec.c dash/src/exec.c
|
||||||
+#endif
|
+#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *legal_pathopt(const char *opt, const char *term, int magic)
|
||||||
|
diff -Paur --no-dereference -- dash.upstream/src/expand.c dash/src/expand.c
|
||||||
|
--- dash.upstream/src/expand.c
|
||||||
|
+++ dash/src/expand.c
|
||||||
|
@@ -44,6 +44,13 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
+/* PATCH: Sortix does not currently have maximum filename or path length */
|
||||||
|
+#ifndef PATH_MAX
|
||||||
|
+#define PATH_MAX 4096
|
||||||
|
+#endif
|
||||||
|
+#ifndef NAME_MAX
|
||||||
|
+#define NAME_MAX 255
|
||||||
|
+#endif
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_FNMATCH
|
||||||
|
#include <fnmatch.h>
|
||||||
diff -Paur --no-dereference -- dash.upstream/src/histedit.c dash/src/histedit.c
|
diff -Paur --no-dereference -- dash.upstream/src/histedit.c dash/src/histedit.c
|
||||||
--- dash.upstream/src/histedit.c
|
--- dash.upstream/src/histedit.c
|
||||||
+++ dash/src/histedit.c
|
+++ dash/src/histedit.c
|
||||||
|
@ -53,7 +70,7 @@ diff -Paur --no-dereference -- dash.upstream/src/jobs.c dash/src/jobs.c
|
||||||
#ifdef BSD
|
#ifdef BSD
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -207,7 +206,7 @@
|
@@ -212,7 +211,7 @@
|
||||||
mflag = on = 0;
|
mflag = on = 0;
|
||||||
goto close;
|
goto close;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +79,7 @@ diff -Paur --no-dereference -- dash.upstream/src/jobs.c dash/src/jobs.c
|
||||||
break;
|
break;
|
||||||
killpg(0, SIGTTIN);
|
killpg(0, SIGTTIN);
|
||||||
} while (1);
|
} while (1);
|
||||||
@@ -457,7 +456,7 @@
|
@@ -461,7 +460,7 @@
|
||||||
|
|
||||||
if (mode & SHOW_PGID) {
|
if (mode & SHOW_PGID) {
|
||||||
/* just output process (group) id of pipeline */
|
/* just output process (group) id of pipeline */
|
||||||
|
@ -71,7 +88,7 @@ diff -Paur --no-dereference -- dash.upstream/src/jobs.c dash/src/jobs.c
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +469,7 @@
|
@@ -474,7 +473,7 @@
|
||||||
s[col - 2] = '-';
|
s[col - 2] = '-';
|
||||||
|
|
||||||
if (mode & SHOW_PID)
|
if (mode & SHOW_PID)
|
||||||
|
@ -80,7 +97,7 @@ diff -Paur --no-dereference -- dash.upstream/src/jobs.c dash/src/jobs.c
|
||||||
|
|
||||||
psend = ps + jp->nprocs;
|
psend = ps + jp->nprocs;
|
||||||
|
|
||||||
@@ -490,7 +489,7 @@
|
@@ -494,7 +493,7 @@
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* for each process */
|
/* for each process */
|
||||||
|
@ -89,43 +106,57 @@ diff -Paur --no-dereference -- dash.upstream/src/jobs.c dash/src/jobs.c
|
||||||
|
|
||||||
start:
|
start:
|
||||||
outfmt(
|
outfmt(
|
||||||
@@ -1136,7 +1135,7 @@
|
@@ -971,7 +970,7 @@
|
||||||
|
sigblockall(NULL);
|
||||||
|
vforked++;
|
||||||
|
|
||||||
|
- pid = vfork();
|
||||||
|
+ pid = fork();
|
||||||
|
|
||||||
|
if (!pid) {
|
||||||
|
forkchild(jp, n, FORK_FG);
|
||||||
|
@@ -1179,7 +1178,7 @@
|
||||||
do {
|
do {
|
||||||
gotsigchld = 0;
|
gotsigchld = 0;
|
||||||
- err = wait3(status, flags, NULL);
|
do
|
||||||
+ err = waitpid(-1, status, flags);
|
- err = wait3(status, flags, NULL);
|
||||||
if (err || !block)
|
+ err = waitpid(-1, status, flags);
|
||||||
break;
|
while (err < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (err || (err = -!block))
|
||||||
diff -Paur --no-dereference -- dash.upstream/src/Makefile.in dash/src/Makefile.in
|
diff -Paur --no-dereference -- dash.upstream/src/Makefile.in dash/src/Makefile.in
|
||||||
--- dash.upstream/src/Makefile.in
|
--- dash.upstream/src/Makefile.in
|
||||||
+++ dash/src/Makefile.in
|
+++ dash/src/Makefile.in
|
||||||
@@ -170,9 +170,9 @@
|
@@ -669,12 +669,14 @@
|
||||||
AM_CFLAGS = $(COMMON_CFLAGS)
|
-rm -f ./$(DEPDIR)/alias.Po
|
||||||
AM_CPPFLAGS = $(COMMON_CPPFLAGS)
|
-rm -f ./$(DEPDIR)/arith_yacc.Po
|
||||||
AM_CFLAGS_FOR_BUILD = -g -O2 $(COMMON_CFLAGS)
|
-rm -f ./$(DEPDIR)/arith_yylex.Po
|
||||||
-AM_CPPFLAGS_FOR_BUILD = $(COMMON_CPPFLAGS)
|
+ -rm -f ./$(DEPDIR)/builtins.Po
|
||||||
+AM_CPPFLAGS_FOR_BUILD = -DBSD=1 -DSHELL -DIFS_BROKEN
|
-rm -f ./$(DEPDIR)/cd.Po
|
||||||
COMPILE_FOR_BUILD = \
|
-rm -f ./$(DEPDIR)/error.Po
|
||||||
- $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS_FOR_BUILD) \
|
-rm -f ./$(DEPDIR)/eval.Po
|
||||||
+ unset HOST_SYSTEM_ROOT && $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS_FOR_BUILD) \
|
-rm -f ./$(DEPDIR)/exec.Po
|
||||||
$(CPPFLAGS_FOR_BUILD) \
|
-rm -f ./$(DEPDIR)/expand.Po
|
||||||
$(AM_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD)
|
-rm -f ./$(DEPDIR)/histedit.Po
|
||||||
|
+ -rm -f ./$(DEPDIR)/init.Po
|
||||||
@@ -542,7 +542,11 @@
|
-rm -f ./$(DEPDIR)/input.Po
|
||||||
|
-rm -f ./$(DEPDIR)/jobs.Po
|
||||||
info-am:
|
-rm -f ./$(DEPDIR)/mail.Po
|
||||||
|
@@ -682,11 +684,14 @@
|
||||||
-install-data-am: install-man
|
-rm -f ./$(DEPDIR)/memalloc.Po
|
||||||
+install-data-am: install-man install-proper-shells
|
-rm -f ./$(DEPDIR)/miscbltin.Po
|
||||||
+
|
-rm -f ./$(DEPDIR)/mystring.Po
|
||||||
+install-proper-shells:
|
+ -rm -f ./$(DEPDIR)/nodes.Po
|
||||||
+ mkdir -p "$(DESTDIR)$(sysconfdir)/proper-shells"
|
-rm -f ./$(DEPDIR)/options.Po
|
||||||
+ echo dash > "$(DESTDIR)$(sysconfdir)/proper-shells/dash"
|
-rm -f ./$(DEPDIR)/output.Po
|
||||||
|
-rm -f ./$(DEPDIR)/parser.Po
|
||||||
install-dvi: install-dvi-am
|
-rm -f ./$(DEPDIR)/redir.Po
|
||||||
|
-rm -f ./$(DEPDIR)/show.Po
|
||||||
|
+ -rm -f ./$(DEPDIR)/signames.Po
|
||||||
|
+ -rm -f ./$(DEPDIR)/syntax.Po
|
||||||
|
-rm -f ./$(DEPDIR)/system.Po
|
||||||
|
-rm -f ./$(DEPDIR)/trap.Po
|
||||||
|
-rm -f ./$(DEPDIR)/var.Po
|
||||||
diff -Paur --no-dereference -- dash.upstream/src/miscbltin.c dash/src/miscbltin.c
|
diff -Paur --no-dereference -- dash.upstream/src/miscbltin.c dash/src/miscbltin.c
|
||||||
--- dash.upstream/src/miscbltin.c
|
--- dash.upstream/src/miscbltin.c
|
||||||
+++ dash/src/miscbltin.c
|
+++ dash/src/miscbltin.c
|
||||||
|
@ -151,18 +182,18 @@ diff -Paur --no-dereference -- dash.upstream/src/output.c dash/src/output.c
|
||||||
diff -Paur --no-dereference -- dash.upstream/src/parser.c dash/src/parser.c
|
diff -Paur --no-dereference -- dash.upstream/src/parser.c dash/src/parser.c
|
||||||
--- dash.upstream/src/parser.c
|
--- dash.upstream/src/parser.c
|
||||||
+++ dash/src/parser.c
|
+++ dash/src/parser.c
|
||||||
@@ -32,10 +32,6 @@
|
@@ -32,10 +32,7 @@
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
-#if HAVE_ALLOCA_H
|
-#if HAVE_ALLOCA_H
|
||||||
-#include <alloca.h>
|
#include <alloca.h>
|
||||||
-#endif
|
-#endif
|
||||||
-
|
-
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
@@ -1090,10 +1086,12 @@
|
@@ -1137,10 +1134,12 @@
|
||||||
if (len) {
|
if (len) {
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
|
@ -176,7 +207,7 @@ diff -Paur --no-dereference -- dash.upstream/src/parser.c dash/src/parser.c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1300,7 +1298,7 @@
|
@@ -1373,7 +1372,7 @@
|
||||||
str = NULL;
|
str = NULL;
|
||||||
savelen = out - (char *)stackblock();
|
savelen = out - (char *)stackblock();
|
||||||
if (savelen > 0) {
|
if (savelen > 0) {
|
||||||
|
@ -185,7 +216,7 @@ diff -Paur --no-dereference -- dash.upstream/src/parser.c dash/src/parser.c
|
||||||
memcpy(str, stackblock(), savelen);
|
memcpy(str, stackblock(), savelen);
|
||||||
}
|
}
|
||||||
if (oldstyle) {
|
if (oldstyle) {
|
||||||
@@ -1400,6 +1398,7 @@
|
@@ -1463,6 +1462,7 @@
|
||||||
if (str) {
|
if (str) {
|
||||||
memcpy(out, str, savelen);
|
memcpy(out, str, savelen);
|
||||||
STADJUST(savelen, out);
|
STADJUST(savelen, out);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
NAME=dash
|
NAME=dash
|
||||||
BUILD_LIBRARIES=
|
BUILD_LIBRARIES=
|
||||||
VERSION=0.5.7
|
VERSION=0.5.11.5
|
||||||
DISTNAME=$NAME-$VERSION
|
DISTNAME=$NAME-$VERSION
|
||||||
COMPRESSION=tar.gz
|
COMPRESSION=tar.gz
|
||||||
ARCHIVE=$DISTNAME.$COMPRESSION
|
ARCHIVE=$DISTNAME.$COMPRESSION
|
||||||
SHA256SUM=ae89fa9f1145b7748cf0740e1df04cd52fdf8a285da4911dd0f04983efba4e39
|
SHA256SUM=db778110891f7937985f29bf23410fe1c5d669502760f584e54e0e7b29e123bd
|
||||||
UPSTREAM_SITE='http://gondor.apana.org.au/~herbert/dash/files'
|
UPSTREAM_SITE='http://gondor.apana.org.au/~herbert/dash/files'
|
||||||
UPSTREAM_ARCHIVE=$ARCHIVE
|
UPSTREAM_ARCHIVE=$ARCHIVE
|
||||||
|
LICENSE=BSD-3-Clause
|
||||||
BUILD_SYSTEM=configure
|
BUILD_SYSTEM=configure
|
||||||
|
MAKE_VARS='V=1'
|
||||||
|
|
|
@ -26,7 +26,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
|
unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1405,7 +1412,8 @@
|
@@ -1403,7 +1410,8 @@
|
||||||
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
||||||
memset(&iov, 0, sizeof(iov));
|
memset(&iov, 0, sizeof(iov));
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
mh.msg_controllen = sizeof(cmsgbuf.buf);
|
mh.msg_controllen = sizeof(cmsgbuf.buf);
|
||||||
cmsg = CMSG_FIRSTHDR(&mh);
|
cmsg = CMSG_FIRSTHDR(&mh);
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||||
@@ -1442,6 +1450,7 @@
|
@@ -1440,6 +1448,7 @@
|
||||||
void
|
void
|
||||||
atelnet(int nfd, unsigned char *buf, unsigned int size)
|
atelnet(int nfd, unsigned char *buf, unsigned int size)
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
unsigned char *p, *end;
|
unsigned char *p, *end;
|
||||||
unsigned char obuf[4];
|
unsigned char obuf[4];
|
||||||
|
|
||||||
@@ -1467,6 +1476,9 @@
|
@@ -1465,6 +1474,9 @@
|
||||||
if (atomicio(vwrite, nfd, obuf, 3) != 3)
|
if (atomicio(vwrite, nfd, obuf, 3) != 3)
|
||||||
warn("Write Error!");
|
warn("Write Error!");
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
+#endif
|
+#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
@@ -1581,16 +1593,20 @@
|
@@ -1578,16 +1590,20 @@
|
||||||
err(1, NULL);
|
err(1, NULL);
|
||||||
}
|
}
|
||||||
if (Tflag != -1) {
|
if (Tflag != -1) {
|
||||||
|
@ -77,7 +77,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
errno = ENOPROTOOPT;
|
errno = ENOPROTOOPT;
|
||||||
err(1, "set IPv6 traffic class not supported");
|
err(1, "set IPv6 traffic class not supported");
|
||||||
}
|
}
|
||||||
@@ -1608,13 +1624,16 @@
|
@@ -1605,13 +1621,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ttl != -1) {
|
if (ttl != -1) {
|
||||||
|
@ -96,7 +96,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minttl != -1) {
|
if (minttl != -1) {
|
||||||
@@ -1652,7 +1671,9 @@
|
@@ -1649,7 +1668,9 @@
|
||||||
{ "af41", IPTOS_DSCP_AF41 },
|
{ "af41", IPTOS_DSCP_AF41 },
|
||||||
{ "af42", IPTOS_DSCP_AF42 },
|
{ "af42", IPTOS_DSCP_AF42 },
|
||||||
{ "af43", IPTOS_DSCP_AF43 },
|
{ "af43", IPTOS_DSCP_AF43 },
|
||||||
|
@ -106,7 +106,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
|
||||||
{ "cs0", IPTOS_DSCP_CS0 },
|
{ "cs0", IPTOS_DSCP_CS0 },
|
||||||
{ "cs1", IPTOS_DSCP_CS1 },
|
{ "cs1", IPTOS_DSCP_CS1 },
|
||||||
{ "cs2", IPTOS_DSCP_CS2 },
|
{ "cs2", IPTOS_DSCP_CS2 },
|
||||||
@@ -1662,11 +1683,21 @@
|
@@ -1659,11 +1680,21 @@
|
||||||
{ "cs6", IPTOS_DSCP_CS6 },
|
{ "cs6", IPTOS_DSCP_CS6 },
|
||||||
{ "cs7", IPTOS_DSCP_CS7 },
|
{ "cs7", IPTOS_DSCP_CS7 },
|
||||||
{ "ef", IPTOS_DSCP_EF },
|
{ "ef", IPTOS_DSCP_EF },
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
NAME=libssl
|
NAME=libssl
|
||||||
BUILD_LIBRARIES=
|
BUILD_LIBRARIES=
|
||||||
VERSION=3.5.3
|
VERSION=3.6.1
|
||||||
DISTNAME=libressl-$VERSION
|
DISTNAME=libressl-$VERSION
|
||||||
COMPRESSION=tar.gz
|
COMPRESSION=tar.gz
|
||||||
ARCHIVE=$DISTNAME.$COMPRESSION
|
ARCHIVE=$DISTNAME.$COMPRESSION
|
||||||
SHA256SUM=3ab5e5eaef69ce20c6b170ee64d785b42235f48f2e62b095fca5d7b6672b8b28
|
SHA256SUM=acfac61316e93b919c28d62d53037ca734de85c46b4d703f19fd8395cf006774
|
||||||
UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL
|
UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL
|
||||||
UPSTREAM_ARCHIVE=$ARCHIVE
|
UPSTREAM_ARCHIVE=$ARCHIVE
|
||||||
LICENSE=OpenSSL
|
LICENSE=OpenSSL
|
||||||
|
|
|
@ -25,6 +25,13 @@ all: $(BINARIES)
|
||||||
install: all
|
install: all
|
||||||
mkdir -p $(DESTDIR)$(BINDIR)
|
mkdir -p $(DESTDIR)$(BINDIR)
|
||||||
install $(BINARIES) $(DESTDIR)$(BINDIR)
|
install $(BINARIES) $(DESTDIR)$(BINDIR)
|
||||||
|
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||||
|
cp sh.1 $(DESTDIR)$(MANDIR)/man1/sh.1
|
||||||
|
ln -sf sh.1 $(DESTDIR)$(MANDIR)/man1/sortix-sh.1
|
||||||
|
mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||||
|
cp profile.5 $(DESTDIR)$(MANDIR)/man5/profile.5
|
||||||
|
cp proper-sh.5 $(DESTDIR)$(MANDIR)/man5/proper-sh.5
|
||||||
|
cp shrc.5 $(DESTDIR)$(MANDIR)/man5/shrc.5
|
||||||
|
|
||||||
sortix-sh: $(SORTIX_SH_SRCS) *.h
|
sortix-sh: $(SORTIX_SH_SRCS) *.h
|
||||||
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $(SORTIX_SH_SRCS) -o $@
|
$(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $(SORTIX_SH_SRCS) -o $@
|
||||||
|
|
160
sh/editline.c
160
sh/editline.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -18,6 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -495,6 +498,161 @@ void edit_line_type_complete(struct edit_line* edit_state)
|
||||||
free(partial);
|
free(partial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t get_histsize(void)
|
||||||
|
{
|
||||||
|
const char* histfile = getenv("HISTSIZE");
|
||||||
|
if ( histfile && isdigit(*histfile) )
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
char* end;
|
||||||
|
size_t value = strtoul(histfile, &end, 10);
|
||||||
|
// Enforce a reasonable upper limit to avoid OOM on misconfigurations,
|
||||||
|
// when users try to have unlimited history size, but the below saving
|
||||||
|
// will allocate an array of this size.
|
||||||
|
if ( 1048576 <= value )
|
||||||
|
value = 1048576;
|
||||||
|
if ( !errno && !*end )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool edit_line_history_load(struct edit_line* edit_state, const char* path)
|
||||||
|
{
|
||||||
|
if ( !path )
|
||||||
|
return true;
|
||||||
|
FILE* fp = fopen(path, "r");
|
||||||
|
if ( !fp )
|
||||||
|
{
|
||||||
|
if ( errno == ENOENT )
|
||||||
|
return true;
|
||||||
|
warn("%s", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char* line = NULL;
|
||||||
|
size_t line_size;
|
||||||
|
ssize_t line_length;
|
||||||
|
while ( 0 < (line_length = getline(&line, &line_size, fp)) )
|
||||||
|
{
|
||||||
|
if ( line[line_length - 1] == '\n' )
|
||||||
|
line[--line_length] = '\0';
|
||||||
|
edit_line_append_history(edit_state, line);
|
||||||
|
}
|
||||||
|
edit_state->history_begun = edit_state->history_used;
|
||||||
|
if ( ferror(fp) )
|
||||||
|
warn("read: %s", path);
|
||||||
|
free(line);
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool edit_line_history_save(struct edit_line* edit_state, const char* path)
|
||||||
|
{
|
||||||
|
size_t histsize = get_histsize();
|
||||||
|
if ( !path || !histsize )
|
||||||
|
return true;
|
||||||
|
// Avoid replacing the null device if used to disable the history.
|
||||||
|
if ( !strcmp(path, "/dev/null") )
|
||||||
|
return true;
|
||||||
|
// TODO: File locking is a better alternative to replacing the actual file.
|
||||||
|
// A temporary file rename is used to atomically replace the contents
|
||||||
|
// but may lose the race with other processes.
|
||||||
|
char* tmp;
|
||||||
|
if ( asprintf(&tmp, "%s.XXXXXXXXX", path) < 0 )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int fd = mkstemp(tmp);
|
||||||
|
if ( fd < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == EROFS )
|
||||||
|
return true;
|
||||||
|
warn("%s", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FILE* fpout = fdopen(fd, "w");
|
||||||
|
if ( !fpout )
|
||||||
|
{
|
||||||
|
warn("%s", path);
|
||||||
|
close(fd);
|
||||||
|
unlink(tmp);
|
||||||
|
free(tmp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Merge with any updated history.
|
||||||
|
bool success = true;
|
||||||
|
char** history = calloc(sizeof(char*), histsize);
|
||||||
|
if ( !history )
|
||||||
|
warn("malloc"), success = false;
|
||||||
|
size_t first = 0;
|
||||||
|
size_t used = 0;
|
||||||
|
FILE* fpin;
|
||||||
|
if ( success && (fpin = fopen(path, "r")) )
|
||||||
|
{
|
||||||
|
char* line = NULL;
|
||||||
|
size_t line_size;
|
||||||
|
ssize_t line_length;
|
||||||
|
while ( 0 < (line_length = getline(&line, &line_size, fpin)) )
|
||||||
|
{
|
||||||
|
if ( line[line_length - 1] == '\n' )
|
||||||
|
line[--line_length] = '\0';
|
||||||
|
size_t n = (first + used) % histsize;
|
||||||
|
if ( history[n] )
|
||||||
|
free(history[n]);
|
||||||
|
history[n] = line;
|
||||||
|
if ( used == histsize )
|
||||||
|
first = (first + 1) % histsize;
|
||||||
|
else
|
||||||
|
used++;
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
if ( ferror(fpin) )
|
||||||
|
warn("read: %s", path), success = false;
|
||||||
|
fclose(fpin);
|
||||||
|
}
|
||||||
|
else if ( errno != ENOENT )
|
||||||
|
warn("%s", path);
|
||||||
|
for ( size_t i = edit_state->history_begun;
|
||||||
|
success && i < edit_state->history_used;
|
||||||
|
i++ )
|
||||||
|
{
|
||||||
|
char* line = strdup(edit_state->history[i]);
|
||||||
|
if ( !line )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_t n = (first + used) % histsize;
|
||||||
|
if ( history[n] )
|
||||||
|
free(history[n]);
|
||||||
|
history[n] = line;
|
||||||
|
if ( used == histsize )
|
||||||
|
first = (first + 1) % histsize;
|
||||||
|
else
|
||||||
|
used++;
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
for ( size_t i = 0; i < used; i++ )
|
||||||
|
{
|
||||||
|
size_t n = (first + i) % histsize;
|
||||||
|
char* line = history[n];
|
||||||
|
if ( success && fprintf(fpout, "%s\n", line) < 0 )
|
||||||
|
warn("%s", tmp), success = false;
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
int ret = fclose(fpout);
|
||||||
|
if ( success && ret == EOF )
|
||||||
|
warn("%s", path), success = false;
|
||||||
|
if ( success && rename(tmp, path) < 0 )
|
||||||
|
warn("rename: %s -> %s", tmp, path), success = false;
|
||||||
|
if ( !success )
|
||||||
|
unlink(tmp);
|
||||||
|
free(tmp);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
#define SORTIX_LFLAGS (ISORTIX_KBKEY | ISORTIX_CHARS_DISABLE | ISORTIX_32BIT | \
|
#define SORTIX_LFLAGS (ISORTIX_KBKEY | ISORTIX_CHARS_DISABLE | ISORTIX_32BIT | \
|
||||||
ISORTIX_NONBLOCK | ISORTIX_TERMMODE)
|
ISORTIX_NONBLOCK | ISORTIX_TERMMODE)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -38,6 +38,7 @@ struct edit_line
|
||||||
size_t history_used;
|
size_t history_used;
|
||||||
size_t history_length;
|
size_t history_length;
|
||||||
size_t history_target;
|
size_t history_target;
|
||||||
|
size_t history_begun;
|
||||||
void* check_input_incomplete_context;
|
void* check_input_incomplete_context;
|
||||||
bool (*check_input_incomplete)(void*, const char*);
|
bool (*check_input_incomplete)(void*, const char*);
|
||||||
void* trap_eof_opportunity_context;
|
void* trap_eof_opportunity_context;
|
||||||
|
@ -81,6 +82,8 @@ void edit_line_type_clear(struct edit_line* edit_state);
|
||||||
void edit_line_type_delete_word_before(struct edit_line* edit_state);
|
void edit_line_type_delete_word_before(struct edit_line* edit_state);
|
||||||
int edit_line_completion_sort(const void* a_ptr, const void* b_ptr);
|
int edit_line_completion_sort(const void* a_ptr, const void* b_ptr);
|
||||||
void edit_line_type_complete(struct edit_line* edit_state);
|
void edit_line_type_complete(struct edit_line* edit_state);
|
||||||
|
bool edit_line_history_load(struct edit_line* edit_state, const char* path);
|
||||||
|
bool edit_line_history_save(struct edit_line* edit_state, const char* path);
|
||||||
void edit_line(struct edit_line* edit_state);
|
void edit_line(struct edit_line* edit_state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
.Dd November 9, 2022
|
||||||
|
.Dt PROFILE 5
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm profile
|
||||||
|
.Nd login shell startup
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm ~/.profile
|
||||||
|
.Nm /etc/profile
|
||||||
|
.Nm /etc/default/profile
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
Interactive login shell sessions in
|
||||||
|
.Xr sh 1
|
||||||
|
execute the commands in the
|
||||||
|
.Nm
|
||||||
|
script upon startup, searching for the user's script at
|
||||||
|
.Pa ~/.profile ,
|
||||||
|
any system administrator provided script at
|
||||||
|
.Pa /etc/profile ,
|
||||||
|
or any operating system provided script at
|
||||||
|
.Pa /etc/default/profile ,
|
||||||
|
whichever exists first.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Xr shrc 5
|
||||||
|
script is run instead in interactive non-login shell sessions.
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "/etc/default/profile" -compact
|
||||||
|
.It Pa ~/.profile
|
||||||
|
The user's
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
.It Pa /etc/profile
|
||||||
|
The system administor provided
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
.It Pa /etc/default/profile
|
||||||
|
The operating system provided
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To portably run the
|
||||||
|
.Xr shrc 5
|
||||||
|
script upon startup of non-login interactive shells in all shells:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
export ENV="$HOME/.shrc"
|
||||||
|
.Ed
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dash 1 ,
|
||||||
|
.Xr sh 1 ,
|
||||||
|
.Xr shrc 5
|
||||||
|
.Sh BUGS
|
||||||
|
.Xr sh 1
|
||||||
|
is currently primitive and cannot execute most scripts.
|
||||||
|
Beware of sharing the
|
||||||
|
.Nm
|
||||||
|
script between it and other shells such as
|
||||||
|
.Xr dash 1 .
|
|
@ -0,0 +1,49 @@
|
||||||
|
.Dd November 16, 2022
|
||||||
|
.Dt PROPER-SH 5
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm proper-sh
|
||||||
|
.Nd name of a better non-interactive shell
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /etc/proper-sh
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Xr sh 1
|
||||||
|
program is a thin wrapper that invokes
|
||||||
|
.Xr sortix-sh 1
|
||||||
|
on interactive use, but this shell is primitive and cannot execute most scripts,
|
||||||
|
so non-interactive uses of
|
||||||
|
.Xr sh 1
|
||||||
|
instead searches for the name of a better shell to execute in this order:
|
||||||
|
.Pp
|
||||||
|
.Bl -bullet -compact
|
||||||
|
.It
|
||||||
|
The shell named in the
|
||||||
|
.Ev SORTIX_SH_BACKEND
|
||||||
|
environment variable.
|
||||||
|
.It
|
||||||
|
The shell named in the
|
||||||
|
.Pa /etc/proper-sh
|
||||||
|
file.
|
||||||
|
.It
|
||||||
|
.Xr dash 1 ,
|
||||||
|
if installed.
|
||||||
|
.It
|
||||||
|
.Sy sortix-sh ,
|
||||||
|
if no better shell was found.
|
||||||
|
.El
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Bl -tag -width "SORTIX_SH_BACKEND"
|
||||||
|
.It Ev SORTIX_SH_BACKEND
|
||||||
|
The name of a better non-interactive shell, taking precedence if set over the
|
||||||
|
.Pa /etc/proper-sh
|
||||||
|
file.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "/etc/proper-sh" -compact
|
||||||
|
.It Pa /etc/proper-sh
|
||||||
|
File containing the name of a better non-interactive shell.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dash 1 ,
|
||||||
|
.Xr sh 1
|
157
sh/proper-sh.c
157
sh/proper-sh.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2014, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -17,114 +17,85 @@
|
||||||
* Forward execution to the best shell.
|
* Forward execution to the best shell.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
const char* getenv_safe(const char* name, const char* def)
|
static bool is_supported(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
const char* ret = getenv(name);
|
int i;
|
||||||
return ret ? ret : def;
|
for ( i = 1; i < argc; i++ )
|
||||||
}
|
|
||||||
|
|
||||||
bool is_existing_shell(const char* candidate)
|
|
||||||
{
|
|
||||||
pid_t child_pid = fork();
|
|
||||||
if ( child_pid < 0 )
|
|
||||||
return false;
|
|
||||||
if ( !child_pid )
|
|
||||||
{
|
{
|
||||||
close(0);
|
const char* arg = argv[i];
|
||||||
close(1);
|
if ( (arg[0] != '-' && arg[0] != '+') || !arg[1] )
|
||||||
close(2);
|
break; // Intentionally not continue and note '+' support.
|
||||||
open("/dev/null", O_RDONLY);
|
if ( !strcmp(arg, "--") )
|
||||||
open("/dev/null", O_WRONLY);
|
|
||||||
open("/dev/null", O_WRONLY);
|
|
||||||
execlp("which", "which", "--", candidate, (const char*) NULL);
|
|
||||||
exit(127);
|
|
||||||
}
|
|
||||||
int status;
|
|
||||||
waitpid(child_pid, &status, 0);
|
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* search_for_proper_shell(void)
|
|
||||||
{
|
|
||||||
if ( getenv("SORTIX_SH_BACKEND") )
|
|
||||||
{
|
|
||||||
if ( !getenv("SORTIX_SH_BACKEND")[0] )
|
|
||||||
return NULL;
|
|
||||||
if ( is_existing_shell(getenv("SORTIX_SH_BACKEND")) )
|
|
||||||
return strdup(getenv("SORTIX_SH_BACKEND"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* backends_dir_path =
|
|
||||||
getenv_safe("SORTIX_SH_BACKENDS_DIR", "/etc/proper-shells");
|
|
||||||
|
|
||||||
struct dirent** shell_entries;
|
|
||||||
int num_shell_entries = scandir(backends_dir_path, &shell_entries, NULL, alphasort);
|
|
||||||
if ( 0 <= num_shell_entries )
|
|
||||||
{
|
|
||||||
char* result = NULL;
|
|
||||||
for ( int i = 0; i < num_shell_entries; i++ )
|
|
||||||
{
|
|
||||||
struct dirent* entry = shell_entries[i];
|
|
||||||
const char* name = entry->d_name;
|
|
||||||
if ( !strcmp(name, ".") || !strcmp(name, "..") )
|
|
||||||
continue;
|
|
||||||
size_t path_length = strlen(backends_dir_path) + 1 + strlen(name);
|
|
||||||
char* path = (char*) malloc(path_length + 1);
|
|
||||||
if ( !path )
|
|
||||||
continue;
|
|
||||||
stpcpy(stpcpy(stpcpy(path, backends_dir_path), "/"), name);
|
|
||||||
FILE* fp = fopen(path, "r");
|
|
||||||
free(path);
|
|
||||||
if ( !fp )
|
|
||||||
continue;
|
|
||||||
size_t result_size = 0;
|
|
||||||
ssize_t result_length = getline(&result, &result_size, fp);
|
|
||||||
fclose(fp);
|
|
||||||
if ( result_length < 0 )
|
|
||||||
{
|
|
||||||
free(result);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( result[result_length-1] == '\n' )
|
|
||||||
result[--result_length] = '\0';
|
|
||||||
if ( !is_existing_shell(result) )
|
|
||||||
{
|
|
||||||
free(result);
|
|
||||||
result = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
if ( arg[0] == '+' || arg[1] != '-' )
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
while ( (c = *++arg) ) switch ( c )
|
||||||
|
{
|
||||||
|
case 'e': break;
|
||||||
|
case 'i': break;
|
||||||
|
case 'l': break;
|
||||||
|
case 's': break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for ( int i = 0; i < num_shell_entries; i++ )
|
else if ( !strcmp(arg, "--help") )
|
||||||
free(shell_entries[i]);
|
;
|
||||||
free(shell_entries);
|
else if ( !strcmp(arg, "--version") )
|
||||||
if ( result )
|
;
|
||||||
return result;
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return i == argc;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if ( argc == 1 && isatty(0) && isatty(1) )
|
if ( !isatty(0) || !isatty(1) || !is_supported(argc, argv) )
|
||||||
execvp("sortix-sh", argv);
|
{
|
||||||
|
const char* env = getenv("SORTIX_SH_BACKEND");
|
||||||
|
if ( env && env[0] )
|
||||||
|
{
|
||||||
|
execvp(env, argv);
|
||||||
|
if ( errno != ENOENT )
|
||||||
|
err(127, "%s", env);
|
||||||
|
}
|
||||||
|
|
||||||
char* proper_shell = search_for_proper_shell();
|
FILE* fp = fopen("/etc/proper-sh", "r");
|
||||||
if ( proper_shell )
|
if ( !fp && errno != ENOENT )
|
||||||
execvp(proper_shell, argv);
|
err(127, "/etc/proper-sh");
|
||||||
free(proper_shell);
|
if ( fp )
|
||||||
|
{
|
||||||
|
char* proper_sh = NULL;
|
||||||
|
size_t proper_sh_size = 0;
|
||||||
|
ssize_t proper_sh_length = getline(&proper_sh, &proper_sh_size, fp);
|
||||||
|
if ( proper_sh_length < 0 )
|
||||||
|
err(127, "/etc/proper-sh");
|
||||||
|
if ( proper_sh_length && proper_sh[proper_sh_length - 1] == '\n' )
|
||||||
|
proper_sh[--proper_sh_length] = '\0';
|
||||||
|
if ( proper_sh[0] )
|
||||||
|
{
|
||||||
|
execvp(proper_sh, argv);
|
||||||
|
if ( errno != ENOENT )
|
||||||
|
err(127, "%s", proper_sh);
|
||||||
|
}
|
||||||
|
free(proper_sh);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
execvp("dash", argv);
|
||||||
|
if ( errno != ENOENT )
|
||||||
|
err(127, "dash");
|
||||||
|
}
|
||||||
|
|
||||||
execvp("sortix-sh", argv);
|
execvp("sortix-sh", argv);
|
||||||
return 127;
|
err(127, "sortix-sh");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
.Dd November 9, 2022
|
||||||
|
.Dt SH 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm sh
|
||||||
|
.Nd shell command interpreter
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm sh
|
||||||
|
.Op Fl ceils
|
||||||
|
.Op Ar script Oo argument ... Oc
|
||||||
|
.Nm sortix-sh
|
||||||
|
.Op Fl ceils
|
||||||
|
.Op Ar script Oo argument ... Oc
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is the command line interpreter for the shell language.
|
||||||
|
It reads and executes commands from the standard input or the
|
||||||
|
.Ar script
|
||||||
|
file if specified.
|
||||||
|
.Nm
|
||||||
|
is interactive if the standard input is a terminal and no
|
||||||
|
.Ar script
|
||||||
|
file was specified.
|
||||||
|
.Pp
|
||||||
|
The standard shell
|
||||||
|
.Nm sortix-sh
|
||||||
|
is currently primitive and cannot execute most scripts.
|
||||||
|
.Nm sh
|
||||||
|
is currently a thin wrapper that detects non-interactive use and invokes a
|
||||||
|
better shell instead, named in the
|
||||||
|
.Ev SORTIX_SH_BACKEND
|
||||||
|
environment variable if set, or named in
|
||||||
|
.Xr proper-sh 5
|
||||||
|
if it exists, and otherwise
|
||||||
|
.Xr dash 1
|
||||||
|
is invoked.
|
||||||
|
.Pp
|
||||||
|
The options can be unset by prefixing them with a plus
|
||||||
|
.Sq +
|
||||||
|
instead of a dash
|
||||||
|
.Sq - .
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width "12345678"
|
||||||
|
.It Fl c
|
||||||
|
The
|
||||||
|
.Ar script
|
||||||
|
argument contains the script's text instead of a path to the script file.
|
||||||
|
.It Fl e
|
||||||
|
Exit if any command exit non-zero.
|
||||||
|
.It Fl i
|
||||||
|
Interactively read and execute commands.
|
||||||
|
.It Fl l
|
||||||
|
The shell is a login shell.
|
||||||
|
Interactive shells run the
|
||||||
|
.Xr profile 5
|
||||||
|
script on startup instead of the
|
||||||
|
.Xr shrc
|
||||||
|
script.
|
||||||
|
This option is set if the shell is invoked by a name starting with a dash
|
||||||
|
.Sq - .
|
||||||
|
.It Fl s
|
||||||
|
Read commands from the standard input (the default).
|
||||||
|
This option can be combined with the
|
||||||
|
.Fl c
|
||||||
|
option to execute the script text in the
|
||||||
|
.Ar script
|
||||||
|
argument before reading normally from the standard input
|
||||||
|
.El
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Nm
|
||||||
|
uses environment these variables:
|
||||||
|
.Bl -tag -width "HISTFILE"
|
||||||
|
.It Ev ENV
|
||||||
|
File to execute on non-login interactive startup instead of
|
||||||
|
.Pa ~/.shrc
|
||||||
|
per
|
||||||
|
.Xr shrc 5 .
|
||||||
|
This variable is subject to path expansion.
|
||||||
|
.It Ev HISTFILE
|
||||||
|
Save the shell history in this file.
|
||||||
|
The default is
|
||||||
|
.Pa ~/.sh_history .
|
||||||
|
.It Ev HISTSIZE
|
||||||
|
Maximum number of commands in the saved shell history.
|
||||||
|
The default is 500.
|
||||||
|
.It Ev HOME
|
||||||
|
The user's home directory
|
||||||
|
.Sq ( ~ ) .
|
||||||
|
.It Ev PATH
|
||||||
|
The colon-separated list of directory paths to search for programs.
|
||||||
|
.It Ev PS1
|
||||||
|
Interactive shell prompt when expecting a new command.
|
||||||
|
.It Ev PS2
|
||||||
|
Interactive shell prompt when the current command continues onto another line.
|
||||||
|
.It Ev PWD
|
||||||
|
Set to the current working directory.
|
||||||
|
.It Ev SHELL
|
||||||
|
Set to
|
||||||
|
.Nm .
|
||||||
|
.It Ev SHLVL
|
||||||
|
Depth of recursive shell sessions.
|
||||||
|
The outermost interactive shell (depth 1) will currently refuse to exit on an
|
||||||
|
end-of-file condition (^D) when on the
|
||||||
|
.Pa /dev/tty1
|
||||||
|
terminal to avoid accidentally powering off the machine.
|
||||||
|
.It Ev SORTIX_SH_BACKEND
|
||||||
|
Name of a better shell to use for non-interactive use per
|
||||||
|
.Xr proper-sh 5 .
|
||||||
|
This variable takes precedence over
|
||||||
|
.Pa /etc/proper-sh .
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "/etc/proper-sh" -compact
|
||||||
|
.It Pa ~/.profile , /etc/profile , /etc/default/profile
|
||||||
|
.Xr profile 5
|
||||||
|
script whose commands are run on non-login interactive shell startup.
|
||||||
|
.It Pa /etc/proper-sh
|
||||||
|
Name of a better shell to use for non-interactive use per
|
||||||
|
.Xr proper-sh 5 .
|
||||||
|
The
|
||||||
|
.Ev SORTIX_SH_BACKEND
|
||||||
|
environment variable takes precedence over this file if set.
|
||||||
|
.Xr dash 1
|
||||||
|
is used by default if it is installed.
|
||||||
|
.It Pa ~/.sh_history
|
||||||
|
The saved shell history.
|
||||||
|
This location is controlled by the
|
||||||
|
.Ev HISTFILE
|
||||||
|
environment variable.
|
||||||
|
.It Pa ~/.shrc , /etc/shrc , /etc/default/shrc
|
||||||
|
.Xr shrc 5
|
||||||
|
script whose commands are run on login interactive shell startup.
|
||||||
|
The
|
||||||
|
.Ev ENV
|
||||||
|
environment variable overrides the search for the script if set.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Nm
|
||||||
|
exits with the same exit status as the last run command, or 0 if no command has
|
||||||
|
been run.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dash 1 ,
|
||||||
|
.Xr profile 5 ,
|
||||||
|
.Xr proper-sh 5 ,
|
||||||
|
.Xr session 5 ,
|
||||||
|
.Xr shrc 5 ,
|
||||||
|
.Xr login 8
|
366
sh/sh.c
366
sh/sh.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <error.h>
|
#include <error.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
@ -51,17 +53,19 @@
|
||||||
#include "showline.h"
|
#include "showline.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
const char* builtin_commands[] =
|
static const char* builtin_commands[] =
|
||||||
{
|
{
|
||||||
"cd",
|
"cd",
|
||||||
"exit",
|
"exit",
|
||||||
"unset",
|
"unset",
|
||||||
"clearenv",
|
"clearenv",
|
||||||
|
"history",
|
||||||
(const char*) NULL,
|
(const char*) NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int status = 0;
|
static bool foreground_shell;
|
||||||
bool foreground_shell;
|
static int status = 0;
|
||||||
|
static struct edit_line edit_state;
|
||||||
|
|
||||||
static bool is_proper_absolute_path(const char* path)
|
static bool is_proper_absolute_path(const char* path)
|
||||||
{
|
{
|
||||||
|
@ -1295,7 +1299,7 @@ struct execute_result execute(char** tokens,
|
||||||
// foreground process group, but bar dies prior to foo's tcsetpgrp
|
// foreground process group, but bar dies prior to foo's tcsetpgrp
|
||||||
// call, because then the shell would run tcsetpgrp to take back
|
// call, because then the shell would run tcsetpgrp to take back
|
||||||
// control, and only then would foo do its tcsetpgrp call.
|
// control, and only then would foo do its tcsetpgrp call.
|
||||||
while ( foreground_shell && pgid == -1 && tcgetpgrp(0) != childpid )
|
while ( interactive && pgid == -1 && tcgetpgrp(0) != childpid )
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
|
||||||
struct execute_result result;
|
struct execute_result result;
|
||||||
|
@ -1306,7 +1310,7 @@ struct execute_result execute(char** tokens,
|
||||||
}
|
}
|
||||||
|
|
||||||
setpgid(0, pgid != -1 ? pgid : 0);
|
setpgid(0, pgid != -1 ? pgid : 0);
|
||||||
if ( foreground_shell && pgid == -1 )
|
if ( interactive && pgid == -1 )
|
||||||
{
|
{
|
||||||
sigset_t oldset, sigttou;
|
sigset_t oldset, sigttou;
|
||||||
sigemptyset(&sigttou);
|
sigemptyset(&sigttou);
|
||||||
|
@ -1339,6 +1343,19 @@ struct execute_result execute(char** tokens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( strcmp(argv[0], "history") == 0 )
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < edit_state.history_used; i++ )
|
||||||
|
{
|
||||||
|
const char* line = edit_state.history[i];
|
||||||
|
if ( fprintf(stdout, "%5zu %s\n", i + 1, line) < 0 )
|
||||||
|
err(1, "stdout");
|
||||||
|
}
|
||||||
|
if ( fflush(stdout) == EOF )
|
||||||
|
err(1, "stdout");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
execvp(argv[0], argv);
|
execvp(argv[0], argv);
|
||||||
|
|
||||||
if ( interactive && errno == ENOENT )
|
if ( interactive && errno == ENOENT )
|
||||||
|
@ -1491,12 +1508,15 @@ readcmd:
|
||||||
// as that may have side effects if a process checks for this
|
// as that may have side effects if a process checks for this
|
||||||
// behavior and then unexpectedly the shell takes back support
|
// behavior and then unexpectedly the shell takes back support
|
||||||
// without the usual ^Z mechanism.
|
// without the usual ^Z mechanism.
|
||||||
sigset_t oldset, sigttou;
|
if ( interactive )
|
||||||
sigemptyset(&sigttou);
|
{
|
||||||
sigaddset(&sigttou, SIGTTOU);
|
sigset_t oldset, sigttou;
|
||||||
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
|
sigemptyset(&sigttou);
|
||||||
tcsetpgrp(0, getpgid(0));
|
sigaddset(&sigttou, SIGTTOU);
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
|
||||||
|
tcsetpgrp(0, getpgid(0));
|
||||||
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
}
|
||||||
pgid = -1;
|
pgid = -1;
|
||||||
status = 0;
|
status = 0;
|
||||||
goto readcmd;
|
goto readcmd;
|
||||||
|
@ -1520,12 +1540,15 @@ readcmd:
|
||||||
status = 1;
|
status = 1;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
sigset_t oldset, sigttou;
|
if ( interactive )
|
||||||
sigemptyset(&sigttou);
|
{
|
||||||
sigaddset(&sigttou, SIGTTOU);
|
sigset_t oldset, sigttou;
|
||||||
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
|
sigemptyset(&sigttou);
|
||||||
tcsetpgrp(0, getpgid(0));
|
sigaddset(&sigttou, SIGTTOU);
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
|
||||||
|
tcsetpgrp(0, getpgid(0));
|
||||||
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
}
|
||||||
if ( WIFSIGNALED(exitstatus) && WTERMSIG(exitstatus) == SIGINT )
|
if ( WIFSIGNALED(exitstatus) && WTERMSIG(exitstatus) == SIGINT )
|
||||||
printf("^C\n");
|
printf("^C\n");
|
||||||
else if ( WIFSIGNALED(exitstatus) && WTERMSIG(exitstatus) != SIGPIPE )
|
else if ( WIFSIGNALED(exitstatus) && WTERMSIG(exitstatus) != SIGPIPE )
|
||||||
|
@ -1834,6 +1857,152 @@ size_t do_complete(char*** completions_ptr,
|
||||||
return *completions_ptr = completions, completions_count;
|
return *completions_ptr = completions, completions_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void eval_ps_append_c(struct stringbuf* buf, char c)
|
||||||
|
{
|
||||||
|
if ( c == '\\' || c == '\'' || c == '"' || c == '$' || c == '`' )
|
||||||
|
stringbuf_append_c(buf, '\\');
|
||||||
|
stringbuf_append_c(buf, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eval_ps_append(struct stringbuf* buf, const char* str)
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; str[i]; i++ )
|
||||||
|
eval_ps_append_c(buf, str[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* eval_ps(const char* ps)
|
||||||
|
{
|
||||||
|
struct stringbuf buf;
|
||||||
|
stringbuf_begin(&buf);
|
||||||
|
bool escaped = false;
|
||||||
|
while ( *ps )
|
||||||
|
{
|
||||||
|
char c = *ps++;
|
||||||
|
if ( !escaped && c == '\\' )
|
||||||
|
{
|
||||||
|
escaped = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if ( escaped && '0' <= c && c <= '7' )
|
||||||
|
{
|
||||||
|
unsigned char byte = c - '0';
|
||||||
|
if ( '0' <= *ps && *ps <= '7' )
|
||||||
|
{
|
||||||
|
byte = byte * 8 + *ps++ - '0';
|
||||||
|
if ( byte <= 037 && '0' <= *ps && *ps <= '7' )
|
||||||
|
byte = byte * 8 + *ps++ - '0';
|
||||||
|
}
|
||||||
|
eval_ps_append_c(&buf, byte);
|
||||||
|
}
|
||||||
|
else if ( escaped && c == 'a' )
|
||||||
|
eval_ps_append_c(&buf, '\a');
|
||||||
|
else if ( escaped && c == 'e' )
|
||||||
|
eval_ps_append_c(&buf, '\e');
|
||||||
|
else if ( escaped && (c == 'h' || c == 'H') )
|
||||||
|
{
|
||||||
|
char hostname[HOST_NAME_MAX + 1] = "?";
|
||||||
|
gethostname(hostname, sizeof(hostname));
|
||||||
|
if ( c == 'h' )
|
||||||
|
hostname[strcspn(hostname, ".")] = '\0';
|
||||||
|
eval_ps_append(&buf, hostname);
|
||||||
|
}
|
||||||
|
else if ( escaped && c == 'l' )
|
||||||
|
{
|
||||||
|
char* tty = ttyname(0);
|
||||||
|
if ( tty )
|
||||||
|
eval_ps_append(&buf, basename(tty));
|
||||||
|
else
|
||||||
|
eval_ps_append_c(&buf, '?');
|
||||||
|
}
|
||||||
|
else if ( escaped && c == 'n' )
|
||||||
|
eval_ps_append_c(&buf, '\n');
|
||||||
|
else if ( escaped && c == 'r' )
|
||||||
|
eval_ps_append_c(&buf, '\r');
|
||||||
|
else if ( escaped && c == 's' )
|
||||||
|
{
|
||||||
|
const char* argv0 = getenv("0");
|
||||||
|
if ( !argv0 )
|
||||||
|
argv0 = program_invocation_short_name;
|
||||||
|
char* base = strdup(argv0);
|
||||||
|
if ( !base )
|
||||||
|
eval_ps_append_c(&buf, '?');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eval_ps_append(&buf, basename(base));
|
||||||
|
free(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( escaped && (c == 't' || c == 'T' || c == '@' || c == 'A') )
|
||||||
|
{
|
||||||
|
const char* format = "";
|
||||||
|
switch ( c )
|
||||||
|
{
|
||||||
|
case 't': format = "%H:%M:%S"; break;
|
||||||
|
case 'T': format = "%I:%M:%S"; break;
|
||||||
|
case '@': format = "%I:%M %p"; break;
|
||||||
|
case 'A': format = "%H:%M"; break;
|
||||||
|
}
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm tm;
|
||||||
|
localtime_r(&now, &tm);
|
||||||
|
char buffer[16] = "";
|
||||||
|
strftime(buffer, sizeof(buffer), format, &tm);
|
||||||
|
eval_ps_append(&buf, buffer);
|
||||||
|
}
|
||||||
|
else if ( escaped && c == 'u' )
|
||||||
|
{
|
||||||
|
char* user = getlogin();
|
||||||
|
eval_ps_append(&buf, user ? user : "?");
|
||||||
|
}
|
||||||
|
else if ( escaped && (c == 'w' || c == 'W') )
|
||||||
|
{
|
||||||
|
char* dir = get_current_dir_name();
|
||||||
|
const char* home = getenv("HOME");
|
||||||
|
if ( !dir )
|
||||||
|
eval_ps_append_c(&buf, '?');
|
||||||
|
else if ( c == 'w' )
|
||||||
|
{
|
||||||
|
size_t home_len = home ? strlen(home) : 0;
|
||||||
|
if ( home_len && !strncmp(dir, home, home_len) )
|
||||||
|
{
|
||||||
|
eval_ps_append_c(&buf, '~');
|
||||||
|
eval_ps_append(&buf, dir + home_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
eval_ps_append(&buf, dir);
|
||||||
|
}
|
||||||
|
else if ( home && !strcmp(dir, home) )
|
||||||
|
eval_ps_append_c(&buf, '~');
|
||||||
|
else
|
||||||
|
eval_ps_append(&buf, basename(dir));
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
else if ( escaped && c == '$' )
|
||||||
|
eval_ps_append_c(&buf, getuid() == 0 ? '#' : '$');
|
||||||
|
else if ( escaped && (c == '[' || c == ']') )
|
||||||
|
{
|
||||||
|
// TODO: Ignoring this sequence when predicting cursor position.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( escaped || c == '\'' || c == '"' )
|
||||||
|
stringbuf_append_c(&buf, '\\');
|
||||||
|
stringbuf_append_c(&buf, c);
|
||||||
|
}
|
||||||
|
escaped = false;
|
||||||
|
}
|
||||||
|
char* string = stringbuf_finish(&buf);
|
||||||
|
if ( !string )
|
||||||
|
return NULL;
|
||||||
|
char* expanded = token_expand_variables(string);
|
||||||
|
free(string);
|
||||||
|
if ( !expanded )
|
||||||
|
return NULL;
|
||||||
|
char* finalized = token_finalize(expanded);
|
||||||
|
free(expanded);
|
||||||
|
return finalized;
|
||||||
|
}
|
||||||
|
|
||||||
struct sh_read_command
|
struct sh_read_command
|
||||||
{
|
{
|
||||||
char* command;
|
char* command;
|
||||||
|
@ -1846,7 +2015,6 @@ void read_command_interactive(struct sh_read_command* sh_read_command)
|
||||||
{
|
{
|
||||||
update_env();
|
update_env();
|
||||||
|
|
||||||
static struct edit_line edit_state; // static to preserve command history.
|
|
||||||
edit_state.in_fd = 0;
|
edit_state.in_fd = 0;
|
||||||
edit_state.out_fd = 1;
|
edit_state.out_fd = 1;
|
||||||
edit_state.check_input_incomplete_context = NULL;
|
edit_state.check_input_incomplete_context = NULL;
|
||||||
|
@ -1856,45 +2024,15 @@ void read_command_interactive(struct sh_read_command* sh_read_command)
|
||||||
edit_state.complete_context = NULL;
|
edit_state.complete_context = NULL;
|
||||||
edit_state.complete = do_complete;
|
edit_state.complete = do_complete;
|
||||||
|
|
||||||
char* current_dir = get_current_dir_name();
|
const char* def_ps1 = "\\033[;1;32m\\u@\\H \\033[1;34m\\w \\$\\033[m ";
|
||||||
|
const char* def_ps2 = "> ";
|
||||||
const char* print_username = getlogin();
|
edit_state.ps1 = eval_ps(getenv_safe_def("PS1", def_ps1));
|
||||||
if ( !print_username )
|
edit_state.ps2 = eval_ps(getenv_safe_def("PS2", def_ps2));
|
||||||
print_username = getuid() == 0 ? "root" : "?";
|
|
||||||
char hostname[HOST_NAME_MAX + 1];
|
|
||||||
if ( gethostname(hostname, sizeof(hostname)) < 0 )
|
|
||||||
strlcpy(hostname, "(none)", sizeof(hostname));
|
|
||||||
const char* print_hostname = hostname;
|
|
||||||
const char* print_dir = current_dir ? current_dir : "?";
|
|
||||||
const char* home_dir = getenv_safe("HOME");
|
|
||||||
|
|
||||||
const char* print_dir_1 = print_dir;
|
|
||||||
const char* print_dir_2 = "";
|
|
||||||
char prompt_char = getuid() == 0 ? '#' : '$';
|
|
||||||
|
|
||||||
size_t home_dir_len = strlen(home_dir);
|
|
||||||
if ( home_dir_len && strncmp(print_dir, home_dir, home_dir_len) == 0 )
|
|
||||||
{
|
|
||||||
print_dir_1 = "~";
|
|
||||||
print_dir_2 = print_dir + home_dir_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ps1;
|
|
||||||
asprintf(&ps1, "\e[;1;32m%s@%s \e[1;34m%s%s %c\e[m ",
|
|
||||||
print_username,
|
|
||||||
print_hostname,
|
|
||||||
print_dir_1,
|
|
||||||
print_dir_2,
|
|
||||||
prompt_char);
|
|
||||||
|
|
||||||
free(current_dir);
|
|
||||||
|
|
||||||
edit_state.ps1 = ps1;
|
|
||||||
edit_state.ps2 = "> ";
|
|
||||||
|
|
||||||
edit_line(&edit_state);
|
edit_line(&edit_state);
|
||||||
|
|
||||||
free(ps1);
|
free((char*) edit_state.ps1);
|
||||||
|
free((char*) edit_state.ps2);
|
||||||
|
|
||||||
if ( edit_state.abort_editing )
|
if ( edit_state.abort_editing )
|
||||||
{
|
{
|
||||||
|
@ -2004,12 +2142,12 @@ void read_command_non_interactive(struct sh_read_command* sh_read_command,
|
||||||
sh_read_command->command = command;
|
sh_read_command->command = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run(FILE* fp,
|
static int run(FILE* fp,
|
||||||
const char* fp_name,
|
const char* fp_name,
|
||||||
bool interactive,
|
bool interactive,
|
||||||
bool exit_on_error,
|
bool exit_on_error,
|
||||||
bool* script_exited,
|
bool* script_exited,
|
||||||
int status)
|
int status)
|
||||||
{
|
{
|
||||||
// TODO: The interactive read code should cope when the input is not a
|
// TODO: The interactive read code should cope when the input is not a
|
||||||
// terminal; it should print the prompt and then read normally without
|
// terminal; it should print the prompt and then read normally without
|
||||||
|
@ -2058,6 +2196,83 @@ int run(FILE* fp,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char* find_rc(bool login)
|
||||||
|
{
|
||||||
|
const char* env = getenv("ENV");
|
||||||
|
if ( !login && env )
|
||||||
|
{
|
||||||
|
// TODO: Path expansion.
|
||||||
|
char* result = strdup(env);
|
||||||
|
if ( !result )
|
||||||
|
err(1, "malloc");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const char* home = getenv("HOME");
|
||||||
|
const char* rcname = login ? "profile" : "shrc";
|
||||||
|
const char* dirs[] = { home, "/etc", "/etc/default" };
|
||||||
|
bool found = false;
|
||||||
|
for ( size_t i = 0; !found && i < sizeof(dirs) / sizeof(dirs[0]); i++ )
|
||||||
|
{
|
||||||
|
char* rc;
|
||||||
|
if ( asprintf(&rc, "%s%s%s", dirs[i], i ? "/" : "/.", rcname) < 0 )
|
||||||
|
err(1, "malloc");
|
||||||
|
if ( (found = !access(rc, F_OK)) )
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int top(FILE* fp,
|
||||||
|
const char* fp_name,
|
||||||
|
bool interactive,
|
||||||
|
bool exit_on_error,
|
||||||
|
bool login,
|
||||||
|
bool* script_exited,
|
||||||
|
int status)
|
||||||
|
{
|
||||||
|
if ( interactive )
|
||||||
|
{
|
||||||
|
const char* home = getenv("HOME");
|
||||||
|
const char* histfile = getenv("HISTFILE");
|
||||||
|
if ( !histfile && home )
|
||||||
|
{
|
||||||
|
char* path;
|
||||||
|
if ( asprintf(&path, "%s/.sh_history", home) < 0 ||
|
||||||
|
setenv("HISTFILE", path, 1) < 0 )
|
||||||
|
err(1, "malloc");
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* rc = find_rc(login);
|
||||||
|
if ( rc )
|
||||||
|
{
|
||||||
|
FILE* rcfp = fopen(rc, "r");
|
||||||
|
if ( !rcfp )
|
||||||
|
warn("%s", rc);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = run(rcfp, rc, false, exit_on_error, script_exited,
|
||||||
|
status);
|
||||||
|
fclose(rcfp);
|
||||||
|
}
|
||||||
|
free(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( *script_exited || (status != 0 && exit_on_error) )
|
||||||
|
return status;
|
||||||
|
|
||||||
|
edit_line_history_load(&edit_state, getenv("HISTFILE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
status = run(fp, fp_name, interactive, exit_on_error, script_exited,
|
||||||
|
status);
|
||||||
|
|
||||||
|
if ( interactive )
|
||||||
|
edit_line_history_save(&edit_state, getenv("HISTFILE"));
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static void compact_arguments(int* argc, char*** argv)
|
static void compact_arguments(int* argc, char*** argv)
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < *argc; i++ )
|
for ( int i = 0; i < *argc; i++ )
|
||||||
|
@ -2133,8 +2348,10 @@ int main(int argc, char* argv[])
|
||||||
bool flag_c_first_operand_is_command = false;
|
bool flag_c_first_operand_is_command = false;
|
||||||
bool flag_e_exit_on_error = false;
|
bool flag_e_exit_on_error = false;
|
||||||
bool flag_i_interactive = false;
|
bool flag_i_interactive = false;
|
||||||
|
bool flag_l_login = argv[0][0] == '-';
|
||||||
bool flag_s_stdin = false;
|
bool flag_s_stdin = false;
|
||||||
|
|
||||||
|
// The well implemented options are recognized in proper-sh.c.
|
||||||
const char* argv0 = argv[0];
|
const char* argv0 = argv[0];
|
||||||
for ( int i = 1; i < argc; i++ )
|
for ( int i = 1; i < argc; i++ )
|
||||||
{
|
{
|
||||||
|
@ -2149,7 +2366,11 @@ int main(int argc, char* argv[])
|
||||||
char c;
|
char c;
|
||||||
while ( (c = *++arg) ) switch ( c )
|
while ( (c = *++arg) ) switch ( c )
|
||||||
{
|
{
|
||||||
|
case 'c': flag_c_first_operand_is_command = false; break;
|
||||||
case 'e': flag_e_exit_on_error = false; break;
|
case 'e': flag_e_exit_on_error = false; break;
|
||||||
|
case 'i': flag_i_interactive = false; break;
|
||||||
|
case 'l': flag_l_login = false; break;
|
||||||
|
case 's': flag_s_stdin = false; break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
||||||
help(stderr, argv0);
|
help(stderr, argv0);
|
||||||
|
@ -2164,6 +2385,7 @@ int main(int argc, char* argv[])
|
||||||
case 'c': flag_c_first_operand_is_command = true; break;
|
case 'c': flag_c_first_operand_is_command = true; break;
|
||||||
case 'e': flag_e_exit_on_error = true; break;
|
case 'e': flag_e_exit_on_error = true; break;
|
||||||
case 'i': flag_i_interactive = true; break;
|
case 'i': flag_i_interactive = true; break;
|
||||||
|
case 'l': flag_l_login = true; break;
|
||||||
case 's': flag_s_stdin = true; break;
|
case 's': flag_s_stdin = true; break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
||||||
|
@ -2205,7 +2427,7 @@ int main(int argc, char* argv[])
|
||||||
char ppidstr[3 * sizeof(pid_t)];
|
char ppidstr[3 * sizeof(pid_t)];
|
||||||
snprintf(pidstr, sizeof(pidstr), "%ji", (intmax_t) getpid());
|
snprintf(pidstr, sizeof(pidstr), "%ji", (intmax_t) getpid());
|
||||||
snprintf(ppidstr, sizeof(ppidstr), "%ji", (intmax_t) getppid());
|
snprintf(ppidstr, sizeof(ppidstr), "%ji", (intmax_t) getppid());
|
||||||
setenv("SHELL", argv[0], 1);
|
setenv("SHELL", argv[0] + (argv[0][0] == '-'), 1);
|
||||||
setenv("$", pidstr, 1);
|
setenv("$", pidstr, 1);
|
||||||
setenv("PPID", ppidstr, 1);
|
setenv("PPID", ppidstr, 1);
|
||||||
setenv("?", "0", 1);
|
setenv("?", "0", 1);
|
||||||
|
@ -2234,8 +2456,8 @@ int main(int argc, char* argv[])
|
||||||
if ( !fp )
|
if ( !fp )
|
||||||
error(2, errno, "fmemopen");
|
error(2, errno, "fmemopen");
|
||||||
|
|
||||||
status = run(fp, "<command-line>", false, flag_e_exit_on_error,
|
status = top(fp, "<command-line>", false, flag_e_exit_on_error,
|
||||||
&script_exited, status);
|
flag_l_login, &script_exited, status);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
@ -2245,8 +2467,8 @@ int main(int argc, char* argv[])
|
||||||
if ( flag_s_stdin )
|
if ( flag_s_stdin )
|
||||||
{
|
{
|
||||||
bool is_interactive = flag_i_interactive || isatty(fileno(stdin));
|
bool is_interactive = flag_i_interactive || isatty(fileno(stdin));
|
||||||
status = run(stdin, "<stdin>", is_interactive, flag_e_exit_on_error,
|
status = top(stdin, "<stdin>", is_interactive, flag_e_exit_on_error,
|
||||||
&script_exited, status);
|
flag_l_login, &script_exited, status);
|
||||||
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
@ -2261,8 +2483,8 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_interactive = flag_i_interactive || isatty(fileno(stdin));
|
bool is_interactive = flag_i_interactive || isatty(fileno(stdin));
|
||||||
status = run(stdin, "<stdin>", is_interactive, flag_e_exit_on_error,
|
status = top(stdin, "<stdin>", is_interactive, flag_e_exit_on_error,
|
||||||
&script_exited, status);
|
flag_l_login, &script_exited, status);
|
||||||
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
@ -2279,8 +2501,8 @@ int main(int argc, char* argv[])
|
||||||
FILE* fp = fopen(path, "r");
|
FILE* fp = fopen(path, "r");
|
||||||
if ( !fp )
|
if ( !fp )
|
||||||
error(127, errno, "%s", path);
|
error(127, errno, "%s", path);
|
||||||
status = run(fp, path, false, flag_e_exit_on_error, &script_exited,
|
status = top(fp, path, false, flag_e_exit_on_error, flag_l_login,
|
||||||
status);
|
&script_exited, status);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
||||||
exit(status);
|
exit(status);
|
||||||
|
@ -2288,8 +2510,8 @@ int main(int argc, char* argv[])
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool is_interactive = flag_i_interactive || isatty(fileno(stdin));
|
bool is_interactive = flag_i_interactive || isatty(fileno(stdin));
|
||||||
status = run(stdin, "<stdin>", is_interactive, flag_e_exit_on_error,
|
status = top(stdin, "<stdin>", is_interactive, flag_e_exit_on_error,
|
||||||
&script_exited, status);
|
flag_l_login, &script_exited, status);
|
||||||
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
if ( script_exited || (status != 0 && flag_e_exit_on_error) )
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
.Dd November 9, 2022
|
||||||
|
.Dt SHRC 5
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm shrc
|
||||||
|
.Nd login shell startup
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm $ENV
|
||||||
|
.Nm ~/.shrc
|
||||||
|
.Nm /etc/shrc
|
||||||
|
.Nm /etc/default/shrc
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
Interactive non-login shell sessions in
|
||||||
|
.Xr sh 1
|
||||||
|
execute the commands in the
|
||||||
|
.Nm
|
||||||
|
script upon startup, using the
|
||||||
|
.Pa ENV
|
||||||
|
environment variable with path expansion if set, and otherwise searching for the
|
||||||
|
user's script at
|
||||||
|
.Pa ~/.shrc ,
|
||||||
|
any system administrator provided script at
|
||||||
|
.Pa /etc/shrc ,
|
||||||
|
or any operating system provided script at
|
||||||
|
.Pa /etc/default/shrc ,
|
||||||
|
whichever exists first.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Xr profile 5
|
||||||
|
script is run instead in interactive login shell sessions.
|
||||||
|
.Sh ENVIRONMENT
|
||||||
|
.Bl -tag -width "ENV"
|
||||||
|
.It Ev ENV
|
||||||
|
File to execute on non-login interactive startup instead of searching the
|
||||||
|
standard paths for the
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
This variable is subject to path expansion.
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width "/etc/default/shrc" -compact
|
||||||
|
.It Pa ~/.shrc
|
||||||
|
The user's
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
.It Pa /etc/shrc
|
||||||
|
The system administor provided
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
.It Pa /etc/default/shrc
|
||||||
|
The operating system provided
|
||||||
|
.Nm
|
||||||
|
script.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dash 1 ,
|
||||||
|
.Xr sh 1 ,
|
||||||
|
.Xr shrc 5
|
||||||
|
.Sh CAVEATS
|
||||||
|
.Xr dash
|
||||||
|
does not use the
|
||||||
|
.Nm
|
||||||
|
script, but instead only uses the
|
||||||
|
.Ev ENV
|
||||||
|
environment variable.
|
||||||
|
To invoke the
|
||||||
|
.Nm
|
||||||
|
script portably across all standard shells upon startup of non-interactive login
|
||||||
|
sells, set the
|
||||||
|
.Ev ENV
|
||||||
|
variable to the user's
|
||||||
|
.Nm
|
||||||
|
script per the example in
|
||||||
|
.Xr profile 5 .
|
||||||
|
.Sh BUGS
|
||||||
|
.Xr sh 1
|
||||||
|
is currently primitive and cannot execute most scripts.
|
||||||
|
Beware of sharing the
|
||||||
|
.Nm
|
||||||
|
script between it and other shells such as
|
||||||
|
.Xr dash 1 .
|
|
@ -6,4 +6,4 @@ need tty
|
||||||
|
|
||||||
cd "$HOME"
|
cd "$HOME"
|
||||||
exit-code-meaning poweroff-reboot
|
exit-code-meaning poweroff-reboot
|
||||||
exec "$SHELL"
|
exec "$SHELL" -l
|
||||||
|
|
Loading…
Reference in New Issue