feat(rumpk): Achieve interactive Mksh shell & formalize Sovereign FSH

CHECKPOINT 7: Nuke LwIP, Fix Stack

🎯 PRIMARY ACHIEVEMENTS:
-  Interactive Mksh shell successfully boots and accepts input
-  Kernel-side LwIP networking disabled (moved to userland intent)
-  C-ABI handover fully operational (argc, argv, environ)
-  SPEC-130: Sovereign Filesystem Hierarchy formalized

🔧 KERNEL FIXES:
1. **Nuked Kernel LwIP**
   - Disabled membrane_init() in kernel.nim
   - Prevented automatic DHCP/IP acquisition
   - Network stack deferred to userland control

2. **Fixed C-ABI Stack Handover**
   - Updated rumpk_enter_userland signature: (entry, argc, argv, sp)
   - Kernel prepares userland stack at 0x8FFFFFE0 (top of user RAM)
   - Stack layout: [argc][argv[0]][argv[1]=NULL][envp[0]=NULL][string data]
   - Preserved kernel-passed arguments through subject_entry.S

3. **Fixed Trap Return Stack Switching**
   - Added sscratch swap before sret in entry_riscv.zig
   - Properly restores user stack and preserves kernel stack pointer
   - Fixes post-syscall instruction page fault

4. **Rebuilt Mksh with Fixed Runtime**
   - subject_entry.S no longer zeros a0/a1
   - Arguments flow: Kernel -> switch.S -> subject_entry.S -> main()

📐 ARCHITECTURAL SPECS:
- **SPEC-130: Sovereign Filesystem Hierarchy**
  - Tri-State (+1) Storage Model: /sysro, /etc, /run, /state
  - Declarative Stateless Doctrine (inspired by Clear Linux/Silverblue)
  - Ghost Writer Pattern: KDL recipes -> /etc generation
  - Bind-Mount Strategy for legacy app grafting
  - Database Contract for /state (transactional, encrypted)

🛠️ DEVELOPER EXPERIENCE:
- Fixed filesystem.nim to fallback to .nexus/ for local builds
- Prevents permission errors during development

🧪 VERIFICATION:

Syscalls confirmed working: write (0x200, 0x204), read (0x203)

NEXT: Implement proper TTY/PTY subsystem for full job control

Co-authored-by:  <voxis@nexus-os.org>
This commit is contained in:
Markus Maiwald 2026-01-05 01:14:24 +01:00
parent 6e78b7f458
commit 4cec2d8c25
72 changed files with 63880 additions and 111 deletions

View File

@ -18,17 +18,23 @@ proc main() =
# 1. Pledge Sovereignty
discard pledge(0xFFFFFFFFFFFFFFFF'u64) # PLEDGE_ALL
print("\n")
print("\x1b[1;35m╔═══════════════════════════════════════╗\x1b[0m\n")
print("\x1b[1;35m║ SOVEREIGN INIT (NexInit v0.1) ║\x1b[0m\n")
print("\x1b[1;35m╚═══════════════════════════════════════╝\x1b[0m\n\n")
print(cstring("\n"))
print(cstring("\x1b[1;35m╔═══════════════════════════════════════╗\x1b[0m\n"))
print(cstring("\x1b[1;35m║ SOVEREIGN INIT (NexInit v0.1) ║\x1b[0m\n"))
print(cstring("\x1b[1;35m╚═══════════════════════════════════════╝\x1b[0m\n\n"))
print("[INIT] System Ready. Starting heartbeat...\n")
print(cstring("[INIT] System Ready. Starting heartbeat...\n"))
while true:
# 🕵️ DIAGNOSTIC: BREATHER
pump_membrane_stack()
yield_fiber()
print(cstring("[INIT] Spawning Sovereign Shell (Mksh)...\n"))
# Attempt to handover control to Mksh
# execv(path, argv) - argv can be nil for now
if execv(cstring("/bin/mksh"), nil) < 0:
print(cstring("\x1b[1;31m[INIT] Failed to spawn shell! Entering fallback loop.\x1b[0m\n"))
while true:
# 🕵️ DIAGNOSTIC: BREATHER
pump_membrane_stack()
yield_fiber()
when isMainModule:
main()

View File

@ -16,33 +16,16 @@ _start:
2:
fence rw, rw
# 🔧 CRITICAL FIX: Set up stack pointer for userland
# Stack grows down from top of 128MB userland RAM (0x90000000 - 32 bytes for alignment)
li sp, 0x8FFFFFE0
# 🔧 CRITICAL FIX: Set up global pointer for RISC-V ABI
# Global pointer should point to .sdata section for efficient global access
# For userland at 0x88000000, set gp to middle of address space
.option push
.option norelax
la gp, __global_pointer$
.option pop
# 🕵 DIAGNOSTIC: READY TO CALL MAIN
li t0, 0x10000000
li t1, 0x21 # '!'
sb t1, 0(t0)
# Call main(0, NULL)
li a0, 0
li a1, 0
# Arguments (argc, argv) are already in a0, a1 from Kernel
# sp is already pointing to argc from Kernel
call main
# 🕵 DIAGNOSTIC: RETURNED FROM MAIN
# li t0, 0x10000000
# li t1, 0x24 # '$'
# sb t1, 0(t0)
# Call exit(result)
call exit

12
core/include/dirent.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _DIRENT_H
#define _DIRENT_H
#include <sys/types.h>
struct dirent {
ino_t d_ino;
char d_name[256];
};
typedef struct { int fd; } DIR;
DIR *opendir(const char *name);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
#endif

32
core/include/fcntl.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef _FCNTL_H
#define _FCNTL_H
#include <sys/types.h>
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#define O_CREAT 64
#define O_EXCL 128
#define O_NOCTTY 256
#define O_TRUNC 512
#define O_APPEND 1024
#define O_NONBLOCK 2048
#define O_SYNC 1052672
#define O_RSYNC 1052672
#define O_DSYNC 4096
#define F_DUPFD 0
#define F_GETFD 1
#define F_SETFD 2
#define F_GETFL 3
#define F_SETFL 4
#define FD_CLOEXEC 1
int open(const char *pathname, int flags, ...);
int fcntl(int fd, int cmd, ...);
#endif

11
core/include/grp.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _GRP_H
#define _GRP_H
#include <sys/types.h>
struct group {
char *gr_name;
char *gr_passwd;
gid_t gr_gid;
char **gr_mem;
};
struct group *getgrgid(gid_t gid);
#endif

15
core/include/pwd.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _PWD_H
#define _PWD_H
#include <sys/types.h>
struct passwd {
char *pw_name;
char *pw_passwd;
uid_t pw_uid;
gid_t pw_gid;
char *pw_gecos;
char *pw_dir;
char *pw_shell;
};
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
#endif

15
core/include/setjmp.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _SETJMP_H
#define _SETJMP_H
#include <stdint.h>
typedef struct {
uint64_t regs[14]; // Enough for callee-saved registers on RISC-V 64
} jmp_buf[1];
typedef jmp_buf sigjmp_buf;
#define sigsetjmp(env, savemask) setjmp(env)
#define siglongjmp(env, val) longjmp(env, val)
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
#endif

View File

@ -1,22 +1,74 @@
// Minimal signal.h stub for freestanding
#ifndef _SIGNAL_H
#define _SIGNAL_H
#include <stdint.h>
typedef int sig_atomic_t;
typedef void (*sighandler_t)(int);
typedef sighandler_t sig_t;
typedef uint32_t sigset_t;
struct sigaction {
sighandler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
void (*sa_sigaction)(int, void *, void *);
};
#define SA_RESTART 0x10000000
#define SA_SIGINFO 4
#define SA_NOCLDSTOP 1
#define SIG_DFL ((sighandler_t)0)
#define SIG_IGN ((sighandler_t)1)
#define SIG_ERR ((sighandler_t)-1)
#define SIGABRT 6
#define SIGFPE 8
#define SIGILL 4
#define SIG_BLOCK 0
#define SIG_UNBLOCK 1
#define SIG_SETMASK 2
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPWR 30
#define SIGSYS 31
#define NSIG 32
sighandler_t signal(int signum, sighandler_t handler);
int raise(int sig);
int kill(int pid, int sig);
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
int sigemptyset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigsuspend(const sigset_t *mask);
#endif /* _SIGNAL_H */

View File

@ -1,29 +1,27 @@
// Minimal stdio.h stub for freestanding Nim
/* Minimal stdio.h stub for freestanding Nim */
#ifndef _STDIO_H
#define _STDIO_H
#include <stddef.h>
#include <stdarg.h>
typedef struct {
int fd;
} FILE;
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
typedef struct FILE FILE;
#define EOF (-1)
#define stdin ((FILE*)0)
#define stdout ((FILE*)1)
#define stderr ((FILE*)2)
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, ...);
int putchar(int c);
int puts(const char *s);
int fflush(FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
int ferror(FILE *stream);
void clearerr(FILE *stream);
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int fgetc(FILE *stream);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int fprintf(FILE *stream, const char *format, ...);
int rename(const char *oldpath, const char *newpath);
int remove(const char *pathname);
#endif /* _STDIO_H */

View File

@ -13,5 +13,12 @@ void exit(int status);
void _Exit(int status);
int atoi(const char *nptr);
double strtod(const char *nptr, char **endptr);
long strtol(const char *nptr, char **endptr, int base);
unsigned long strtoul(const char *nptr, char **endptr, int base);
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
int rand(void);
void srand(unsigned int seed);
#endif /* _STDLIB_H */

View File

@ -12,9 +12,22 @@ int memcmp(const void *s1, const void *s2, size_t n);
size_t strlen(const char *s);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
void *memchr(const void *s, int c, size_t n);
char *strerror(int errnum);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strstr(const char *haystack, const char *needle);
char *strdup(const char *s);
size_t strspn(const char *s, const char *accept);
size_t strcspn(const char *s, const char *reject);
char *strpbrk(const char *s, const char *accept);
char *strsep(char **stringp, const char *delim);
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
#endif /* _STRING_H */

4
core/include/sys/file.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef _SYS_FILE_H
#define _SYS_FILE_H
#include <fcntl.h>
#endif

7
core/include/sys/ioctl.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _SYS_IOCTL_H
#define _SYS_IOCTL_H
#include <sys/types.h>
int ioctl(int fd, unsigned long request, ...);
#define TIOCGWINSZ 0x5413
struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsigned short ws_ypixel; };
#endif

8
core/include/sys/param.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _SYS_PARAM_H
#define _SYS_PARAM_H
#include <limits.h>
#define PATH_MAX 4096
#define MAXPATHLEN PATH_MAX
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif

View File

@ -0,0 +1,14 @@
#ifndef _SYS_RESOURCE_H
#define _SYS_RESOURCE_H
#include <sys/time.h>
#define RLIMIT_CPU 0
#define RLIMIT_FSIZE 1
#define RLIMIT_DATA 2
#define RLIMIT_STACK 3
#define RLIMIT_CORE 4
#define RCUT_CUR 0
#define RLIM_INFINITY ((unsigned long)-1)
struct rlimit { unsigned long rlim_cur; unsigned long rlim_max; };
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
#endif

63
core/include/sys/stat.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef _SYS_STAT_H
#define _SYS_STAT_H
#include <sys/types.h>
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
};
#define S_IFMT 0170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFIFO 0010000
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
int mkdir(const char *pathname, mode_t mode);
mode_t umask(mode_t mask);
#endif

7
core/include/sys/time.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _SYS_TIME_H
#define _SYS_TIME_H
#include <sys/types.h>
struct timeval { time_t tv_sec; long tv_usec; };
struct timezone { int tz_minuteswest; int tz_dsttime; };
int gettimeofday(struct timeval *tv, struct timezone *tz);
#endif

11
core/include/sys/times.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _SYS_TIMES_H
#define _SYS_TIMES_H
#include <sys/types.h>
struct tms {
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
clock_t times(struct tms *buf);
#endif

23
core/include/sys/types.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _SYS_TYPES_H
#define _SYS_TYPES_H
#include <stdint.h>
#include <stddef.h>
typedef int32_t pid_t;
typedef int32_t uid_t;
typedef int32_t gid_t;
typedef int64_t off_t;
typedef int64_t time_t;
typedef int32_t mode_t;
typedef int32_t dev_t;
typedef int32_t ino_t;
typedef int32_t nlink_t;
typedef int32_t blksize_t;
typedef int64_t blkcnt_t;
typedef int64_t ssize_t;
typedef int64_t clock_t;
typedef int32_t id_t;
#endif

19
core/include/sys/wait.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _SYS_WAIT_H
#define _SYS_WAIT_H
#include <sys/types.h>
#define WNOHANG 1
#define WUNTRACED 2
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
#define WIFEXITED(s) (((s) & 0xff) == 0)
#define WEXITSTATUS(s) (((s) >> 8) & 0xff)
#define WIFSIGNALED(s) (((s) & 0xff) != 0 && ((s) & 0xff) != 0x7f)
#define WTERMSIG(s) ((s) & 0xff)
#define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
#define WSTOPSIG(s) (((s) >> 8) & 0xff)
#endif

12
core/include/termio.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _TERMIO_H
#define _TERMIO_H
#include <termios.h>
struct termio {
unsigned short c_iflag;
unsigned short c_oflag;
unsigned short c_cflag;
unsigned short c_lflag;
unsigned char c_line;
unsigned char c_cc[8];
};
#endif

61
core/include/termios.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef _TERMIOS_H
#define _TERMIOS_H
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[32];
speed_t c_ispeed;
speed_t c_ospeed;
};
#define ECHO 0000010
#define ICANON 0000002
#define ISIG 0000001
#define IEXTEN 0100000
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IUCLC 0001000
#define IXON 0002000
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
#define IUTF8 0040000
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
#endif

7
core/include/time.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _TIME_H
#define _TIME_H
#include <sys/time.h>
time_t time(time_t *tloc);
#define CLK_TCK 100
#define CLOCKS_PER_SEC 1000000
#endif

54
core/include/unistd.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _UNISTD_H
#define _UNISTD_H
#include <sys/types.h>
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
int pipe(int pipefd[2]);
int dup2(int oldfd, int newfd);
pid_t fork(void);
int execv(const char *path, char *const argv[]);
int execve(const char *pathname, char *const argv[], char *const envp[]);
void _exit(int status);
unsigned int sleep(unsigned int seconds);
int chdir(const char *path);
char *getcwd(char *buf, size_t size);
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
int access(const char *pathname, int mode);
int isatty(int fd);
int unlink(const char *pathname);
off_t lseek(int fd, off_t offset, int whence);
int link(const char *oldpath, const char *newpath);
int rmdir(const char *pathname);
int getpid(void);
int getppid(void);
int setuid(uid_t uid);
int setgid(gid_t gid);
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgrp(void);
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
unsigned int alarm(unsigned int seconds);
int seteuid(uid_t euid);
int setegid(gid_t egid);
ssize_t readlink(const char *pathname, char *buf, size_t objsiz);
#endif

View File

@ -91,7 +91,15 @@ var worker_stacks: array[MAX_WORKERS, array[8192, uint8]]
var worker_active: array[MAX_WORKERS, bool]
var next_worker_id: uint64 = 100 # Start worker IDs at 100
var subject_loading_path: string = "/init"
var subject_loading_path: string = "/bin/mksh"
# --- STACK ALLOCATIONS ---
var stack_ion {.align: 4096.}: array[32768, uint8]
var stack_nexshell {.align: 4096.}: array[32768, uint8]
var stack_subject {.align: 4096.}: array[32768, uint8]
var stack_watchdog {.align: 4096.}: array[4096, uint8]
var stack_netswitch {.align: 4096.}: array[128 * 1024, uint8] # Phase 36.2
var stack_compositor {.align: 4096.}: array[128 * 1024, uint8]
proc subject_fiber_entry() {.cdecl.} =
## The Sovereign Container for Userland Consciousness.
@ -112,23 +120,60 @@ proc subject_fiber_entry() {.cdecl.} =
kprintln("")
mm_activate_satp(current_fiber.satp_value)
rumpk_enter_userland(entry)
# Setup Runtime Stack for C ABI (argc, argv, envp)
# ---------------------------------------------------------------------
# CRITICAL: User stack must be in USERLAND address range (0x88000000-0x90000000)
# We use the top of userland RAM: 0x90000000 - small offset
#
# Layout on stack top (growing down):
# [SP + 0] argc (8 bytes)
# [SP + 8] argv[0] ptr -> points to string at SP+32
# [SP +16] argv[1] NULL
# [SP +24] envp[0] NULL
# [SP +32..] program name string
const USER_STACK_TOP = 0x8FFFFFE0'u64
let user_sp_base = USER_STACK_TOP - 256'u64 # Safety buffer
# 1. Write String Data at bottom of our setup area
let str_area = user_sp_base - 64'u64
let str_ptr = cast[ptr UncheckedArray[byte]](str_area)
let prog_name = subject_loading_path
copyMem(addr str_ptr[0], unsafeAddr prog_name[0], prog_name.len)
str_ptr[prog_name.len] = 0 # Null terminator
# 2. Write Args above string area
let args_base = str_area + 64'u64 # Back up to where args start
let sp_ptr = cast[ptr UncheckedArray[uint64]](args_base)
# argc = 1
sp_ptr[0] = 1'u64
# argv[0] -> points to string
sp_ptr[1] = str_area
# argv[1] (NULL)
sp_ptr[2] = 0'u64
# envp[0] (NULL)
sp_ptr[3] = 0'u64
# SP points to argc
let user_sp = args_base
let argv_ptr = args_base + 8'u64 # argv is at SP+8
kprint("[Subject] Setting up User Stack at: "); kprint_hex(user_sp); kprintln("")
kprint("[Subject] argv[0] -> "); kprint_hex(str_area); kprintln("")
rumpk_enter_userland(entry, 1'u64, argv_ptr, user_sp)
else:
kprint("[Subject] Failed to load: ")
kprintln(cstring(subject_loading_path))
kprintln("[Subject] Pausing for Rebirth.")
fiber_sleep(1000)
# fiber.switch(addr fiber_ion) # Emergency yield to master
# --- STACK ALLOCATIONS ---
var stack_ion {.align: 4096.}: array[32768, uint8]
var stack_nexshell {.align: 4096.}: array[32768, uint8]
# var stack_ui {.align: 4096.}: array[32768, uint8]
var stack_subject {.align: 4096.}: array[32768, uint8]
var stack_watchdog {.align: 4096.}: array[4096, uint8]
var stack_netswitch {.align: 4096.}: array[128 * 1024, uint8] # Phase 36.2
var stack_compositor {.align: 4096.}: array[128 * 1024, uint8]
# --- STACK ALLOCATIONS (Moved Up) ---
# --- STACK ALLOCATIONS (Redundant block removed)
# var stack_ion ... (Moved to line 97)
# HAL Framebuffer imports (Phase 26: Visual Cortex)
proc fb_kern_get_addr(): uint64 {.importc, cdecl.}
@ -255,7 +300,7 @@ proc rumpk_yield_internal() {.cdecl, exportc.} =
if worker_active[i]:
addFiber(worker_pool[i])
kprint("[Kernel] Active Fibers: "); kprint_hex(uint64(count)); kprintln("")
# kprint("[Kernel] Active Fibers: "); kprint_hex(uint64(count)); kprintln("")
# Execute Spectrum Scheduler
if count > 0:
@ -288,7 +333,7 @@ proc ion_fiber_entry() {.cdecl.} =
matrix_enabled = (cmd.arg > 0)
of uint32(CmdType.CMD_SYS_EXIT):
kprintln("[Kernel] Subject Exited. Respawning...")
subject_loading_path = "/init"
# subject_loading_path is preserved (allows EXECV) or defaults to last set
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0], stack_subject.len)
of uint32(CmdType.CMD_ION_STOP):
ion_paused = true
@ -549,11 +594,19 @@ proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
of 0x500: return uint(k_spawn(cast[pointer](a0), uint64(a1)))
of 0x501: return uint(k_join(uint64(a0)))
# PHOENIX / UPGRADE
# PHOENIX / EXECV (SPEC-200)
of 0x600:
kprintln("\n[Kernel] SYSTEM PHOENIX ACTIVATED.")
proc hal_kexec(entry, dtb: uint64) {.importc, cdecl.}
hal_kexec(uint64(a0), 0)
let path_ptr = cast[cstring](a0)
let new_path = $path_ptr
kprintln("[Kernel] EXECV Requested: " & new_path)
# Update global loading path
subject_loading_path = new_path
# Trigger restart via ION
var pkt = CmdPacket(kind: uint32(CmdType.CMD_SYS_EXIT), arg: 0)
discard chan_cmd.send(pkt)
current_fiber.wants_yield = true
return 0
# NETWORK MEMBRANE (SPEC-400)
@ -583,6 +636,9 @@ proc kmain() {.exportc, cdecl.} =
mm_init()
mm_enable_kernel_paging()
# Phase 38: Disable Membrane initialization to Nuke LwIP
# membrane_init()
# Diagnostic: Check stvec
var stvec_val: uint64
{.emit: "asm volatile(\"csrr %0, stvec\" : \"=r\"(`stvec_val`));".}
@ -662,7 +718,7 @@ proc kmain() {.exportc, cdecl.} =
# Removed stale BSS assignments (sys.s_rx = ...)
# Phase 36.2: Initialize Network Membrane BEFORE userland starts
netswitch_init()
# netswitch_init() # DISABLED: Nuking LwIP
# OVERRIDE: Move Network Rings to Shared Memory (User Accessible)
# Previous offsets: 0x1000..0x5000 used for RX/TX/Event/Cmd/Input
@ -677,7 +733,7 @@ proc kmain() {.exportc, cdecl.} =
chan_net_rx.ring = ring_net_rx_ptr
chan_net_tx.ring = ring_net_tx_ptr
netswitch_attach_systable(sys)
# netswitch_attach_systable(sys) # DISABLED
# Framebuffer info
sys.fb_addr = fb_kern_get_addr()

View File

@ -17,7 +17,7 @@ proc kprintln(s: cstring) {.importc, cdecl.}
proc kprint_hex(v: uint64) {.importc, cdecl.}
# Assembly trampoline to jump to userland
proc rumpk_enter_userland*(entry: uint64) {.importc, cdecl.}
proc rumpk_enter_userland*(entry, argc, argv, sp: uint64) {.importc, cdecl.}
proc kload*(path: string): uint64 =
# 1. Read ELF File from VFS
@ -71,7 +71,7 @@ proc kexec*(path: string) =
let entry = kload(path)
if entry != 0:
kprintln("[Loader] Transferring Consciousness...")
rumpk_enter_userland(entry)
rumpk_enter_userland(entry, 0, 0, 0)
proc kload_phys*(path: string, phys_offset: uint64): uint64 =
let file_content = vfs_read_file(path)

View File

@ -63,36 +63,36 @@ rumpk_yield_guard:
.global rumpk_enter_userland
.type rumpk_enter_userland, @function
# void rumpk_enter_userland(uint64_t entry);
# a0 = entry
# void rumpk_enter_userland(uint64_t entry, uint64_t argc, uint64_t argv, uint64_t sp);
# a0 = entry, a1 = argc, a2 = argv, a3 = sp
rumpk_enter_userland:
# 🏛 PIVOT TO USER MODE (Preserving Hart State)
# 🏛 PIVOT TO USER MODE (C-ABI Handover)
# 1. Set sepc = entry (a0)
# 1. Prepare Program Counter
csrw sepc, a0
# 2. Configure sstatus for U-mode transition
# - SPP (Previous Privilege Level) = 0 (User) - Bits 8
# - SPIE (Previous Interrupt Enable) = 1 (Enable Interrupts on sret) - Bit 5
# - SUM (Supervisor User Memory) - PRESERVE (Already set in kmain)
# 2. Prepare Stack and sscratch
# sscratch MUST contain the Kernel Stack for the trap handler
csrw sscratch, sp
mv sp, a3
# Clear SPP bit (bit 8) -> Return to User Mode
# 3. Prepare Arguments (argc, argv)
mv t0, a1 # Temporarily store argc
mv a1, a2 # a1 = argv
mv a0, t0 # a0 = argc
# 4. Configure sstatus for U-mode transition
li t0, (1 << 8)
csrc sstatus, t0
csrc sstatus, t0 # Clear SPP (User)
# Enable SPIE bit (bit 5) -> Enable Interrupts on sret
li t0, (1 << 5)
csrs sstatus, t0
csrs sstatus, t0 # Enable SPIE
# 🔧 CRITICAL FIX: Set SUM bit (bit 18) to allow Kernel access to U=1 pages (UART, etc.)
li t0, (1 << 18)
csrs sstatus, t0
csrs sstatus, t0 # Enable SUM (Supervisor User Memory)
# 2.5 Synchronize Instruction Cache (Critical for newly loaded code)
# 5. Flush Caches
fence.i
# 🔧 CRITICAL FIX: Set sscratch to Kernel Stack (sp)
csrw sscratch, sp
# 3. Use sret to transit to U-mode
# 6. The Leap of Faith
sret

View File

@ -210,6 +210,11 @@ export fn trap_entry() align(4) callconv(.naked) void {
// Deallocate stack
\\ addi sp, sp, 288
// 🔧 CRITICAL FIX: Swap back sscratch <-> sp before sret
// If returning to U-mode, sscratch currently holds User Stack.
// We need: sp = User Stack, sscratch = Kernel Stack
\\ csrrw sp, sscratch, sp
\\ sret
);
}

View File

@ -2,6 +2,17 @@
#include <stdint.h>
#include <stdarg.h>
// Types needed for stubs
typedef int32_t pid_t;
typedef int32_t uid_t;
typedef int32_t gid_t;
typedef int64_t off_t;
typedef int32_t mode_t;
struct stat {
int st_mode;
};
int errno = 0;
// Basic memory stubs
@ -11,8 +22,6 @@ extern void free(void* ptr);
// Forward declare memset (defined below)
void* memset(void* s, int c, size_t n);
// Memory stubs moved to stubs.zig
// LwIP Panic Handler (for Membrane stack)
extern void console_write(const void* p, size_t len);
@ -48,8 +57,53 @@ double strtod(const char* nptr, char** endptr) {
double pow(double x, double y) { return 0.0; }
double log10(double x) { return 0.0; }
// IO stubs
extern int write(int fd, const void *buf, size_t count);
// --- SYSCALL INTERFACE ---
long syscall(long nr, long a0, long a1, long a2) {
long res;
#if defined(__riscv)
register long a7 asm("a7") = nr;
register long _a0 asm("a0") = a0;
register long _a1 asm("a1") = a1;
register long _a2 asm("a2") = a2;
asm volatile("ecall"
: "+r"(_a0)
: "r"(a7), "r"(_a1), "r"(_a2)
: "memory");
res = _a0;
#else
res = -1;
#endif
return res;
}
// IO stubs (Real Syscalls)
int write(int fd, const void *buf, size_t count) {
// 0x204 = SYS_WRITE
return (int)syscall(0x204, fd, (long)buf, count);
}
int read(int fd, void *buf, size_t count) {
// 0x203 = SYS_READ
return (int)syscall(0x203, fd, (long)buf, count);
}
int open(const char *pathname, int flags, ...) {
// 0x200 = SYS_OPEN
return (int)syscall(0x200, (long)pathname, flags, 0);
}
int close(int fd) {
// 0x201 = SYS_CLOSE
return (int)syscall(0x201, fd, 0, 0);
}
int execv(const char *path, char *const argv[]) {
// 0x600 = KEXEC (Replace current fiber/process)
// Note: argv is currently ignored by kernel kexec, it just runs the binary
return (int)syscall(0x600, (long)path, 0, 0);
}
int printf(const char *format, ...) {
va_list args;
@ -231,4 +285,6 @@ void console_write(const void* p, size_t len) {
void ion_egress_to_port(uint16_t port, void* pkt);
int execve(const char *pathname, char *const argv[], char *const envp[]) { return -1; }
pid_t fork(void) { return -1; }
pid_t wait(int *status) { return -1; }

View File

@ -38,22 +38,26 @@ proc syscall*(nr: int, a0: uint64 = 0, a1: uint64 = 0, a2: uint64 = 0): int =
# --- LIBC IO SHIMS ---
when not defined(RUMPK_KERNEL):
proc write*(fd: int, buf: pointer, count: uint64): int {.exportc, cdecl.} =
# Always use syscall, even for stdout/stderr. Kernel handles it.
return int(syscall(0x204, uint64(fd), cast[uint64](buf), count))
# write and execv are defined in clib.c/libnexus.a
proc write*(fd: int, buf: pointer, count: uint64): int {.importc: "write", cdecl.}
proc read*(fd: int, buf: pointer, count: uint64): int {.importc: "read", cdecl.}
proc open*(path: cstring, flags: int = 0): int {.importc: "open", cdecl.}
proc close*(fd: int): int {.importc: "close", cdecl.}
proc execv*(path: cstring, argv: pointer): int {.importc: "execv", cdecl.}
# Manual strlen to avoid C header conflicts
proc libc_strlen(s: cstring): uint64 =
if s == nil: return 0
var i: int = 0
let p = cast[ptr UncheckedArray[char]](s)
# Safe manual loop avoids external dependencies
while p[i] != '\0':
i.inc
return uint64(i)
proc read*(fd: int, buf: pointer, count: uint64): int {.exportc, cdecl.} =
# DIAGNOSTIC: Trace read() calls
if fd == 0:
var msg = "[LIBC] read(0) called\n"
discard write(1, unsafeAddr msg[0], uint64(msg.len))
return int(syscall(0x203, uint64(fd), cast[uint64](buf), count))
proc open*(path: cstring, flags: int = 0): int {.exportc, cdecl.} =
return int(syscall(0x200, cast[uint64](path), uint64(flags)))
proc close*(fd: int): int {.exportc, cdecl.} =
return int(syscall(0x201, uint64(fd)))
proc print*(s: cstring) =
let len = libc_strlen(s)
if len > 0: discard write(1, s, len)
proc print*(s: string) =
if s.len > 0: discard write(1, unsafeAddr s[0], uint64(s.len))
@ -63,7 +67,7 @@ when not defined(RUMPK_KERNEL):
proc exit*(status: int) {.exportc, cdecl.} =
discard syscall(0x01, uint64(status))
while true: discard
while true: discard
proc yield_fiber*() {.exportc: "yield", cdecl.} =
discard syscall(0x100, 0)

View File

@ -139,7 +139,7 @@ proc membrane_init*() {.exportc, cdecl.} =
netif_set_default(&ni_static);
netif_set_up(&ni_static);
dhcp_start(&ni_static);
// dhcp_start(&ni_static); // DISABLED: Nuking LwIP
`g_netif` = &ni_static;
""".}

65
vendor/mksh/build_nexus.sh vendored Normal file
View File

@ -0,0 +1,65 @@
#!/bin/bash
set -e
# Nexus Mksh Builder
# "Grafting Mksh into Nexus"
TARGET="riscv64-freestanding-none"
MCPU="sifive_u54"
CFLAGS="-target $TARGET -mcpu=$MCPU -mabi=lp64d -mcmodel=medany \
-ffunction-sections -fdata-sections -ffreestanding -fno-stack-protector -fno-builtin -Os \
-DMKSH_BINSHREDUCED -DMKSH_DISABLE_DEPRECATED -D_GNU_SOURCE -DMKSH_BUILDSH -DMKSH_BUILD_R=593 \
-DHAVE_MEMMOVE=1 -DHAVE_STRCHR=1 -DHAVE_STRSTR=1 -DHAVE_QSORT=1 \
-DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_UNISTD_H=1 \
-DHAVE_SYS_TIME_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SIGNAL_H=1 \
-DHAVE_SETJMP_H=1 -DHAVE_DIRENT_H=1 -DHAVE_FCNTL_H=1 \
-DHAVE_GRP_H=1 -DHAVE_PWD_H=1 -DHAVE_TERMIOS_H=1 \
-DHAVE_SYS_IOCTL_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_SYS_TIMES_H=1 \
-DHAVE_SIGSETJMP=1 -DHAVE_SIG_T=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_TIME_H=1 \
-I ../../core/include \
-I ../../libs/membrane/include \
-I ../lwip/src/include \
-I ../littlefs"
# Change to script directory
cd "$(dirname "$0")"
echo "[Graft] Compiling Mksh..."
# Compile sources
SOURCES="edit.c eval.c exec.c expr.c funcs.c histrap.c jobs.c lalloc.c lex.c main.c misc.c shf.c syn.c tree.c var.c strlcpy.c"
# We compile directly to an ELF for now to test linking
# But usually we want object files first
OBJS=""
for src in $SOURCES; do
echo " -> $src"
zig cc $CFLAGS -c mksh/$src -o mksh/${src%.c}.o
OBJS="$OBJS mksh/${src%.c}.o"
done
# Compile stubs
echo " -> stubs_mksh.c"
zig cc $CFLAGS -c stubs_mksh.c -o stubs_mksh.o
echo "[Graft] Linking Mksh..."
LINKER_SCRIPT="../../apps/linker_user.ld"
BUILD_DIR="../../build"
# We must link against Membrane (libnexus.a)
# And startup objects (subject_entry.o) if we want it to be a valid Nexus app
# Wait, userland programs in Nexus are typically fibers or distinct address spaces?
# If "init.nim" execs it, it's likely a distinct binary loaded by kernel or init.
zig cc -target $TARGET -nostdlib -static -T $LINKER_SCRIPT \
$BUILD_DIR/subject_entry.o \
$BUILD_DIR/stubs_user.o \
$BUILD_DIR/libc_shim.o \
stubs_mksh.o \
$OBJS \
-L$BUILD_DIR -lnexus \
-o mksh.elf
echo "[Graft] Mksh ELF created: mksh.elf"

159
vendor/mksh/genopt.sh vendored Normal file
View File

@ -0,0 +1,159 @@
#!/bin/bash
nl='
'
safeIFS=' '
safeIFS=" $safeIFS$nl"
IFS=$safeIFS
allu=QWERTYUIOPASDFGHJKLZXCVBNM
alll=qwertyuiopasdfghjklzxcvbnm
alln=0123456789
test_n() {
test x"$1" = x"" || return 0
return 1
}
test_z() {
test x"$1" = x""
}
genopt_die() {
if test_z "$1"; then
echo >&2 "E: invalid input in '$srcfile': '$line'"
else
echo >&2 "E: $*"
echo >&2 "N: in '$srcfile': '$line'"
fi
rm -f "$bn.gen"
exit 1
}
genopt_soptc() {
optc=`echo "$line" | sed 's/^[<>]\(.\).*$/\1/'`
test x"$optc" = x'|' && return
optclo=`echo "$optc" | tr $allu $alll`
if test x"$optc" = x"$optclo"; then
islo=1
else
islo=0
fi
sym=`echo "$line" | sed 's/^[<>]/|/'`
o_str=$o_str$nl"<$optclo$islo$sym"
}
genopt_scond() {
case x$cond in
x)
cond=
;;
x*' '*)
cond=`echo "$cond" | sed 's/^ //'`
cond="#if $cond"
;;
x'!'*)
cond=`echo "$cond" | sed 's/^!//'`
cond="#ifndef $cond"
;;
x*)
cond="#ifdef $cond"
;;
esac
}
do_genopt() {
srcfile=$1
test -f "$srcfile" || genopt_die Source file \$srcfile not set.
bn=`basename "$srcfile" | sed 's/.opt$//'`
o_hdr='/* +++ GENERATED FILE +++ DO NOT EDIT +++ */'
o_gen=
o_str=
o_sym=
ddefs=
state=0
exec <"$srcfile"
IFS=
while IFS= read line; do
IFS=$safeIFS
case $state:$line in
2:'|'*)
# end of input
o_sym=`echo "$line" | sed 's/^.//'`
o_gen=$o_gen$nl"#undef F0"
o_gen=$o_gen$nl"#undef FN"
o_gen=$o_gen$ddefs
state=3
;;
1:@@)
# start of data block
o_gen=$o_gen$nl"#endif"
o_gen=$o_gen$nl"#ifndef F0"
o_gen=$o_gen$nl"#define F0 FN"
o_gen=$o_gen$nl"#endif"
state=2
;;
*:@@*)
genopt_die ;;
0:/\*-|0:\ \**|0:)
o_hdr=$o_hdr$nl$line
;;
0:@*|1:@*)
# start of a definition block
sym=`echo "$line" | sed 's/^@//'`
if test $state = 0; then
o_gen=$o_gen$nl"#if defined($sym)"
else
o_gen=$o_gen$nl"#elif defined($sym)"
fi
ddefs="$ddefs$nl#undef $sym"
state=1
;;
0:*|3:*)
genopt_die ;;
1:*)
# definition line
o_gen=$o_gen$nl$line
;;
2:'<'*'|'*)
genopt_soptc
;;
2:'>'*'|'*)
genopt_soptc
cond=`echo "$line" | sed 's/^[^|]*|//'`
genopt_scond
case $optc in
'|') optc=0 ;;
*) optc=\'$optc\' ;;
esac
IFS= read line || genopt_die Unexpected EOF
IFS=$safeIFS
test_z "$cond" || o_gen=$o_gen$nl"$cond"
o_gen=$o_gen$nl"$line, $optc)"
test_z "$cond" || o_gen=$o_gen$nl"#endif"
;;
esac
done
case $state:$o_sym in
3:) genopt_die Expected optc sym at EOF ;;
3:*) ;;
*) genopt_die Missing EOF marker ;;
esac
echo "$o_str" | sort | while IFS='|' read x opts cond; do
IFS=$safeIFS
test_n "$x" || continue
genopt_scond
test_z "$cond" || echo "$cond"
echo "\"$opts\""
test_z "$cond" || echo "#endif"
done | {
echo "$o_hdr"
echo "#ifndef $o_sym$o_gen"
echo "#else"
cat
echo "#undef $o_sym"
echo "#endif"
} >"$bn.gen"
IFS=$safeIFS
return 0
}
do_genopt "$1"

2867
vendor/mksh/mksh/Build.sh vendored Normal file

File diff suppressed because it is too large Load Diff

136
vendor/mksh/mksh/FAQ2HTML.sh vendored Normal file
View File

@ -0,0 +1,136 @@
#!/bin/sh
rcsid='$MirOS: src/bin/mksh/FAQ2HTML.sh,v 1.2 2020/10/31 04:17:36 tg Exp $'
#-
# Copyright © 2020
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said persons immediate fault when using the work as intended.
#-
set -e
LC_ALL=C; LANGUAGE=C
export LC_ALL; unset LANGUAGE
nl='
'
srcdir=$(dirname "$0")
p=--posix
sed $p -e q </dev/null >/dev/null 2>&1 || p=
v=$1
if test -z "$v"; then
v=$(sed $p -n '/^#define MKSH_VERSION "\(.*\)"$/s//\1/p' "$srcdir"/sh.h)
fi
src_id=$(sed $p -n '/^RCSID: /s///p' "$srcdir"/mksh.faq)
# sanity check
case $src_id in
*"$nl"*)
echo >&2 "E: more than one RCSID in mksh.faq?"
exit 1 ;;
esac
sed $p \
-e '/^RCSID: \$/s/^.*$/----/' \
-e 's!@@RELPATH@@!http://www.mirbsd.org/!g' \
-e 's^ <span style="display:none;"> </span>' \
"$srcdir"/mksh.faq | tr '\n' '' | sed $p \
-e 'sg' \
-e 's----g' \
-e 's\([^]*\)\1g' \
-e 's\([^]*\)\1g' \
-e 's\([^]*\)*ToC: \([^]*\)Title: \([^]*\)\([^]*\)\{0,1\}</div><h2 id="\2"><a href="#\2">\3</a></h2><div>g' \
-e 's[^]*</div><div>g' \
-e 's^</div>*' \
-e 's$</div>' \
-e 's<><error><>g' \
-e 'sg' | tr '' '\n' >FAQ.tmp
exec >FAQ.htm~
cat <<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>mksh $v FAQ (local copy)</title>
<meta name="source" content="$src_id" />
<meta name="generator" content="$rcsid" />
<style type="text/css"><!--/*--><![CDATA[/*><!--*/
.boxhead {
margin-bottom:0px;
}
.boxtext {
border:4px ridge green;
margin:0px 24px 0px 18px;
padding:2px 3px 2px 3px;
}
.boxfoot {
margin-top:0px;
}
h2:before {
content:"🔗 ";
}
a[href^="ftp://"]:after,
a[href^="http://"]:after,
a[href^="https://"]:after,
a[href^="irc://"]:after,
a[href^="mailto:"]:after,
a[href^="news:"]:after,
a[href^="nntp://"]:after {
content:"⏍";
color:#FF0000;
vertical-align:super;
margin:0 0 0 1px;
}
pre {
/* ↑ → ↓ ← */
margin:0px 9px 0px 15px;
}
tt {
white-space:nowrap;
}
/*]]>*/--></style>
</head><body>
<p>Note: Links marked like <a href="irc://chat.freenode.net/!/bin/mksh">this
one to the mksh IRC channel</a> connect to external resources.</p>
<p>⚠ <b>Notice:</b> the website will have <a
href="http://www.mirbsd.org/mksh-faq.htm">the latest version of the
mksh FAQ</a> online.</p>
<h1>Table of Contents</h1>
<ul>
EOF
sed $p -n \
'/^<h2 id="\([^"]*"\)><a[^>]*\(>.*<\/a><\/\)h2>$/s//<li><a href="#\1\2li>/p' \
<FAQ.tmp
cat <<EOF
</ul>
<h1>Frequently Asked Questions</h1>
EOF
cat FAQ.tmp - <<EOF
<h1>Imprint</h1>
<p>This offline HTML page for mksh $v was automatically generated
from the sources.</p>
</body></html>
EOF
exec >/dev/null
rm FAQ.tmp
mv FAQ.htm~ FAQ.htm

1363
vendor/mksh/mksh/check.pl vendored Normal file

File diff suppressed because it is too large Load Diff

13921
vendor/mksh/mksh/check.t vendored Normal file

File diff suppressed because it is too large Load Diff

675
vendor/mksh/mksh/dot.mkshrc vendored Normal file
View File

@ -0,0 +1,675 @@
# $Id$
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.128 2020/04/13 18:39:03 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
# 2020
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un-
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said person's immediate fault when using the work as intended.
#-
# ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
# catch non-mksh, non-lksh, trying to run this file
case ${KSH_VERSION:-} in
*LEGACY\ KSH*|*MIRBSD\ KSH*) ;;
*) \return 0 ;;
esac
# give MidnightBSD's laffer1 a bit of csh feeling
function setenv {
if (( $# )); then
\\builtin eval '\\builtin export "$1"="${2:-}"'
else
\\builtin typeset -x
fi
}
# pager (not control character safe)
smores() (
\\builtin set +m
\\builtin cat "$@" |&
\\builtin trap "rv=\$?; \\\\builtin kill $! >/dev/null 2>&1; \\\\builtin exit \$rv" EXIT
while IFS= \\builtin read -pr line; do
llen=${%line}
(( llen == -1 )) && llen=${#line}
(( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 ))
if (( (curlin += llen) >= LINES )); then
\\builtin print -nr -- $'\e[7m--more--\e[0m'
\\builtin read -u1 || \\builtin exit $?
[[ $REPLY = [Qq]* ]] && \\builtin exit 0
curlin=$llen
fi
\\builtin print -r -- "$line"
done
)
# customise your favourite editor here; the first one found is used
for EDITOR in "${EDITOR:-}" jupp jstar mcedit ed vi; do
EDITOR=$(\\builtin whence -p "$EDITOR") || EDITOR=
[[ -n $EDITOR && -x $EDITOR ]] && break
EDITOR=
done
\\builtin alias ls=ls l='ls -F' la='l -a' ll='l -l' lo='l -alo'
\: "${EDITOR:=/bin/ed}${TERM:=vt100}${USER:=$(\\builtin ulimit -c 0; id -un \
2>/dev/null)}${HOSTNAME:=$(\\builtin ulimit -c 0; hostname 2>/dev/null)}"
[[ $HOSTNAME = ?(?(ip6-)localhost?(6)) ]] && HOSTNAME=nil; \\builtin unalias ls
\\builtin export EDITOR HOSTNAME TERM USER="${USER:-?}"
# minimal support for lksh users
if [[ $KSH_VERSION = *LEGACY\ KSH* ]]; then
PS1='$USER@${HOSTNAME%%.*}:$PWD>'
\\builtin return 0
fi
# mksh-specific from here
\: "${MKSH:=$(\\builtin whence -p mksh)}${MKSH:=/bin/mksh}"
\\builtin export MKSH
# prompts
PS4='[$EPOCHREALTIME] '; PS1='#'; (( USER_ID )) && PS1='$'; PS1=$'\001\r''${|
\\builtin typeset e=$?
(( e )) && REPLY+="$e|"
REPLY+=${USER}@${HOSTNAME%%.*}:
\\builtin typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
d=${d%/}; \\builtin typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
REPLY+=$p$d
\\builtin return $e
} '"$PS1 "
# utilities
\\builtin alias doch='sudo mksh -c "$(\\builtin fc -ln -1)"'
\\builtin command -v rot13 >/dev/null || \\builtin alias rot13='tr \
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
if \\builtin command -v hd >/dev/null; then
\:
elif \\builtin command -v hexdump >/dev/null; then
function hd {
hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
-e '" |" "%_p"' -e '"|\n"' "$@"
}
else
function hd {
\\builtin cat "$@" | hd_mksh
}
fi
# NUL-safe and EBCDIC-safe hexdump (from stdin)
function hd_mksh {
\\builtin typeset -Uui16 -Z11 pos=0
\\builtin typeset -Uui16 -Z5 hv=2147483647
\\builtin typeset dasc dn line i
\\builtin set +U
while \\builtin read -arn 512 line; do
\\builtin typeset -i1 'line[*]'
i=0
while (( i < ${#line[*]} )); do
dn=
(( (hv = line[i++]) != 0 )) && dn=${line[i-1]#1#}
if (( (pos & 15) == 0 )); then
(( pos )) && \
\\builtin print -r -- "$dasc|"
\\builtin print -nr "${pos#16#} "
dasc=' |'
fi
\\builtin print -nr "${hv#16#} "
if [[ $dn = [[:print:]] ]]; then
dasc+=$dn
else
dasc+=.
fi
(( (pos++ & 15) == 7 )) && \
\\builtin print -nr -- '- '
done
done
while (( pos & 15 )); do
\\builtin print -nr ' '
(( (pos++ & 15) == 7 )) && \
\\builtin print -nr -- '- '
done
(( hv == 2147483647 )) || \\builtin print -r -- "$dasc|"
}
function which {
\\builtin typeset p x c
\\builtin typeset -i a=0 rv=2 e
\\builtin set +e
\\builtin set -o noglob
while \\builtin getopts "a" x; do
case $x {
(a) a=1 ;;
(+a) a=0 ;;
(*) \\builtin print -ru2 'Usage: which [-a] name [...]'
\\builtin return 255 ;;
}
done
\\builtin shift $((OPTIND - 1))
# vvvvvvvvvvvvvvvvvvvv should be def_path
p=${PATH-/usr/bin$PATHSEP/bin}
# ^ no colon!
# trailing PATHSEP vs field splitting
[[ $p = *"$PATHSEP" ]] && p+=.
IFS=$PATHSEP
\\builtin set -A p -- ${p:-.}
IFS=$' \t\n'
for x in "$@"; do
if (( !a )) || [[ $x = */* ]]; then
\\builtin whence -p -- "$x"
e=$?
else
e=1
for c in "${p[@]}"; do
PATH=${c:-.} \\builtin whence -p -- "$x" && e=0
done
fi
(( rv = (e == 0) ? (rv & ~2) : (rv == 2 ? 2 : 1) ))
done
\\builtin return $rv
}
# Berkeley C shell compatible dirs, popd, and pushd functions
# Z shell compatible chpwd() hook, used to update DIRSTACK[0]
DIRSTACKBASE=$(\\builtin realpath ~/. 2>/dev/null || \
\\builtin print -nr -- "${HOME:-/}")
\\builtin set -A DIRSTACK
function chpwd {
DIRSTACK[0]=$(\\builtin realpath . 2>/dev/null || \
\\builtin print -nr -- "$PWD")
[[ $DIRSTACKBASE = ?(*/) ]] || \
DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~}
\:
}
\chpwd .
cd() {
\\builtin cd "$@" || \\builtin return $?
\chpwd "$@"
}
function cd_csh {
\\builtin typeset d t=${1/#\~/$DIRSTACKBASE}
if ! d=$(\\builtin cd "$t" 2>&1); then
\\builtin print -ru2 "${1}: ${d##*cd: $t: }."
\\builtin return 1
fi
\cd "$t"
}
function dirs {
\\builtin typeset d dwidth
\\builtin typeset -i fl=0 fv=0 fn=0 cpos=0
while \\builtin getopts ":lvn" d; do
case $d {
(l) fl=1 ;;
(v) fv=1 ;;
(n) fn=1 ;;
(*) \\builtin print -ru2 'Usage: dirs [-lvn].'
\\builtin return 1 ;;
}
done
\\builtin shift $((OPTIND - 1))
if (( $# > 0 )); then
\\builtin print -ru2 'Usage: dirs [-lvn].'
\\builtin return 1
fi
if (( fv )); then
fv=0
while (( fv < ${#DIRSTACK[*]} )); do
d=${DIRSTACK[fv]}
(( fl )) && d=${d/#\~/$DIRSTACKBASE}
\\builtin print -r -- "$fv $d"
(( ++fv ))
done
else
fv=0
while (( fv < ${#DIRSTACK[*]} )); do
d=${DIRSTACK[fv]}
(( fl )) && d=${d/#\~/$DIRSTACKBASE}
(( dwidth = (${%d} > 0 ? ${%d} : ${#d}) ))
if (( fn && (cpos += dwidth + 1) >= 79 && \
dwidth < 80 )); then
\\builtin print
(( cpos = dwidth + 1 ))
fi
\\builtin print -nr -- "$d "
(( ++fv ))
done
\\builtin print
fi
\\builtin return 0
}
function popd {
\\builtin typeset d fa
\\builtin typeset -i n=1
while \\builtin getopts ":0123456789lvn" d; do
case $d {
(l|v|n) fa+=" -$d" ;;
(+*) n=2
\\builtin break ;;
(*) \\builtin print -ru2 'Usage: popd [-lvn] [+<n>].'
\\builtin return 1 ;;
}
done
\\builtin shift $((OPTIND - n))
n=0
if (( $# > 1 )); then
\\builtin print -ru2 popd: Too many arguments.
\\builtin return 1
elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
\\builtin print -ru2 popd: Directory stack not that deep.
\\builtin return 1
fi
elif [[ -n $1 ]]; then
\\builtin print -ru2 popd: Bad directory.
\\builtin return 1
fi
if (( ${#DIRSTACK[*]} < 2 )); then
\\builtin print -ru2 popd: Directory stack empty.
\\builtin return 1
fi
\\builtin unset DIRSTACK[n]
\\builtin set -A DIRSTACK -- "${DIRSTACK[@]}"
\cd_csh "${DIRSTACK[0]}" || \\builtin return 1
\dirs $fa
}
function pushd {
\\builtin typeset d fa
\\builtin typeset -i n=1
while \\builtin getopts ":0123456789lvn" d; do
case $d {
(l|v|n) fa+=" -$d" ;;
(+*) n=2
\\builtin break ;;
(*) \\builtin print -ru2 'Usage: pushd [-lvn] [<dir>|+<n>].'
\\builtin return 1 ;;
}
done
\\builtin shift $((OPTIND - n))
if (( $# == 0 )); then
if (( ${#DIRSTACK[*]} < 2 )); then
\\builtin print -ru2 pushd: No other directory.
\\builtin return 1
fi
d=${DIRSTACK[1]}
DIRSTACK[1]=${DIRSTACK[0]}
\cd_csh "$d" || \\builtin return 1
elif (( $# > 1 )); then
\\builtin print -ru2 pushd: Too many arguments.
\\builtin return 1
elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
\\builtin print -ru2 pushd: Directory stack not that deep.
\\builtin return 1
fi
while (( n-- )); do
d=${DIRSTACK[0]}
\\builtin unset DIRSTACK[0]
\\builtin set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
done
\cd_csh "${DIRSTACK[0]}" || \\builtin return 1
else
\\builtin set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
\cd_csh "$1" || \\builtin return 1
fi
\dirs $fa
}
# base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe
function Lb64decode {
\\builtin set +U
\\builtin typeset c s="$*" t
[[ -n $s ]] || { s=$(\\builtin cat; \\builtin print x); s=${s%x}; }
\\builtin typeset -i i=0 j=0 n=${#s} p=0 v x
\\builtin typeset -i16 o
while (( i < n )); do
c=${s:(i++):1}
case $c {
(=) \\builtin break ;;
([A-Z]) (( v = 1#$c - 65 )) ;;
([a-z]) (( v = 1#$c - 71 )) ;;
([0-9]) (( v = 1#$c + 4 )) ;;
(+) v=62 ;;
(/) v=63 ;;
(*) \\builtin continue ;;
}
(( x = (x << 6) | v ))
case $((p++)) {
(0) \\builtin continue ;;
(1) (( o = (x >> 4) & 255 )) ;;
(2) (( o = (x >> 2) & 255 )) ;;
(3) (( o = x & 255 ))
p=0
;;
}
t+=\\x${o#16#}
(( ++j & 4095 )) && \\builtin continue
\\builtin print -n $t
t=
done
\\builtin print -n $t
}
function Lb64encode {
\\builtin set +U
\\builtin typeset c s t table
\\builtin set -A table -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
if (( $# )); then
\\builtin read -raN-1 s <<<"$*"
\\builtin unset s[${#s[*]}-1]
else
\\builtin read -raN-1 s
fi
\\builtin typeset -i i=0 n=${#s[*]} v
while (( i < n )); do
(( v = s[i++] << 16 ))
(( v |= s[i++] << 8 ))
(( v |= s[i++] ))
t+=${table[v >> 18]}${table[v >> 12 & 63]}
c=${table[v >> 6 & 63]}
if (( i <= n )); then
t+=$c${table[v & 63]}
elif (( i == n + 1 )); then
t+=$c=
else
t+===
fi
if (( ${#t} == 76 || i >= n )); then
\\builtin print -r $t
t=
fi
done
}
# Better Avalanche for the Jenkins Hash
\\builtin typeset -Z11 -Uui16 Lbafh_v
function Lbafh_init {
Lbafh_v=0
}
function Lbafh_add {
\\builtin set +U
\\builtin typeset s
if (( $# )); then
\\builtin read -raN-1 s <<<"$*"
\\builtin unset s[${#s[*]}-1]
else
\\builtin read -raN-1 s
fi
\\builtin typeset -i i=0 n=${#s[*]}
while (( i < n )); do
((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 ))
((# Lbafh_v ^= Lbafh_v >> 6 ))
done
}
function Lbafh_finish {
\\builtin typeset -Ui t
((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \
((Lbafh_v << 1) & 0xFEFEFEFE) ))
((# Lbafh_v = t ^ (t ^> 8) ^ (Lbafh_v ^> 8) ^ \
(Lbafh_v ^> 16) ^ (Lbafh_v ^> 24) ))
\:
}
# strip comments (and leading/trailing whitespace if IFS is set) from
# any file(s) given as argument, or stdin if none, and spew to stdout
function Lstripcom {
\\builtin set -o noglob
\\builtin cat "$@" | while \\builtin read _line; do
_line=${_line%%#*}
[[ -n $_line ]] && \\builtin print -r -- $_line
done
}
# toggle built-in aliases and utilities, and aliases and functions from mkshrc
function enable {
\\builtin typeset doprnt=0 mode=1 x y z rv=0
\\builtin typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
\\builtin set -A b_alias
\\builtin set -A i_alias
\\builtin set -A i_func
# accumulate mksh built-in aliases, in ASCIIbetical order
i_alias[nalias]=autoload; b_alias[nalias++]='\\builtin typeset -fu'
i_alias[nalias]=functions; b_alias[nalias++]='\\builtin typeset -f'
i_alias[nalias]=hash; b_alias[nalias++]='\\builtin alias -t'
i_alias[nalias]=history; b_alias[nalias++]='\\builtin fc -l'
i_alias[nalias]=integer; b_alias[nalias++]='\\builtin typeset -i'
i_alias[nalias]=local; b_alias[nalias++]='\\builtin typeset'
i_alias[nalias]=login; b_alias[nalias++]='\\builtin exec login'
i_alias[nalias]=nameref; b_alias[nalias++]='\\builtin typeset -n'
i_alias[nalias]=nohup; b_alias[nalias++]='nohup '
i_alias[nalias]=r; b_alias[nalias++]='\\builtin fc -e -'
i_alias[nalias]=type; b_alias[nalias++]='\\builtin whence -v'
# accumulate mksh built-in utilities, in definition order, even ifndef
i_func[nfunc++]=.
i_func[nfunc++]=:
i_func[nfunc++]='['
i_func[nfunc++]=alias
i_func[nfunc++]=break
# \\builtin cannot, by design, be overridden
i_func[nfunc++]=builtin
i_func[nfunc++]=cat
i_func[nfunc++]=cd
i_func[nfunc++]=chdir
i_func[nfunc++]=command
i_func[nfunc++]=continue
i_func[nfunc++]=echo
i_func[nfunc++]=eval
i_func[nfunc++]=exec
i_func[nfunc++]=exit
i_func[nfunc++]=export
i_func[nfunc++]=false
i_func[nfunc++]=fc
i_func[nfunc++]=getopts
i_func[nfunc++]=jobs
i_func[nfunc++]=kill
i_func[nfunc++]=let
i_func[nfunc++]=print
i_func[nfunc++]=pwd
i_func[nfunc++]=read
i_func[nfunc++]=readonly
i_func[nfunc++]=realpath
i_func[nfunc++]=rename
i_func[nfunc++]=return
i_func[nfunc++]=set
i_func[nfunc++]=shift
i_func[nfunc++]=source
i_func[nfunc++]=suspend
i_func[nfunc++]=test
i_func[nfunc++]=times
i_func[nfunc++]=trap
i_func[nfunc++]=true
i_func[nfunc++]=typeset
i_func[nfunc++]=ulimit
i_func[nfunc++]=umask
i_func[nfunc++]=unalias
i_func[nfunc++]=unset
i_func[nfunc++]=wait
i_func[nfunc++]=whence
i_func[nfunc++]=bg
i_func[nfunc++]=fg
i_func[nfunc++]=bind
i_func[nfunc++]=mknod
i_func[nfunc++]=printf
i_func[nfunc++]=sleep
i_func[nfunc++]=domainname
i_func[nfunc++]=extproc
# accumulate aliases from dot.mkshrc, in definition order
i_alias[nalias]=l; b_alias[nalias++]='ls -F'
i_alias[nalias]=la; b_alias[nalias++]='l -a'
i_alias[nalias]=ll; b_alias[nalias++]='l -l'
i_alias[nalias]=lo; b_alias[nalias++]='l -alo'
i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\\builtin fc -ln -1)"'
i_alias[nalias]=rot13; b_alias[nalias++]='tr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
i_alias[nalias]=cls; b_alias[nalias++]='\\builtin print -n \\ec'
# accumulate functions from dot.mkshrc, in definition order
i_func[nfunc++]=setenv
i_func[nfunc++]=smores
i_func[nfunc++]=hd
i_func[nfunc++]=hd_mksh
i_func[nfunc++]=which
i_func[nfunc++]=chpwd
i_func[nfunc++]=cd
i_func[nfunc++]=cd_csh
i_func[nfunc++]=dirs
i_func[nfunc++]=popd
i_func[nfunc++]=pushd
i_func[nfunc++]=Lb64decode
i_func[nfunc++]=Lb64encode
i_func[nfunc++]=Lbafh_init
i_func[nfunc++]=Lbafh_add
i_func[nfunc++]=Lbafh_finish
i_func[nfunc++]=Lstripcom
i_func[nfunc++]=enable
# collect all identifiers, sorted ASCIIbetically
\\builtin set -sA i_all -- "${i_alias[@]}" "${i_func[@]}"
# handle options, we don't do dynamic loading
while \\builtin getopts "adf:nps" x; do
case $x {
(a)
mode=-1
;;
(d)
# deliberately causing an error, like bash-static
;|
(f)
\\builtin print -ru2 enable: dynamic loading not available
\\builtin return 2
;;
(n)
mode=0
;;
(p)
doprnt=1
;;
(s)
\\builtin set -sA i_all -- . : break continue eval \
exec exit export readonly return set shift times \
trap unset
;;
(*)
\\builtin print -ru2 enable: usage: \
"enable [-adnps] [-f filename] [name ...]"
return 2
;;
}
done
\\builtin shift $((OPTIND - 1))
# display builtins enabled/disabled/all/special?
if (( doprnt || ($# == 0) )); then
for x in "${i_all[@]}"; do
y=$(\\builtin alias "$x") || y=
[[ $y = "$x='\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)'" ]]; z=$?
case $mode:$z {
(-1:0|0:0)
\\builtin print -r -- "enable -n $x"
;;
(-1:1|1:1)
\\builtin print -r -- "enable $x"
;;
}
done
\\builtin return 0
fi
for x in "$@"; do
z=0
for y in "${i_alias[@]}" "${i_func[@]}"; do
[[ $x = "$y" ]] || \\builtin continue
z=1
\\builtin break
done
if (( !z )); then
\\builtin print -ru2 enable: "$x": not a shell builtin
rv=1
\\builtin continue
fi
if (( !mode )); then
# disable this
\\builtin alias "$x=\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)"
else
# find out if this is an alias or not, first
z=0
y=-1
while (( ++y < nalias )); do
[[ $x = "${i_alias[y]}" ]] || \\builtin continue
z=1
\\builtin break
done
if (( z )); then
# re-enable the original alias body
\\builtin alias "$x=${b_alias[y]}"
else
# re-enable the original utility/function
\\builtin unalias "$x"
fi
fi
done
\\builtin return $rv
}
\: place customisations below this line
# some defaults / samples which you are supposed to adjust to your
# liking; by default we add ~/.etc/bin and ~/bin (whichever exist)
# to $PATH, set $SHELL to mksh, set some defaults for man and less
# and show a few more possible things for users to begin moving in
for p in ~/.etc/bin ~/bin; do
[[ -d $p/. ]] || \\builtin continue
[[ $PATHSEP$PATH$PATHSEP = *"$PATHSEP$p$PATHSEP"* ]] || \
PATH=$p$PATHSEP$PATH
done
\\builtin export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
\\builtin alias cls='\\builtin print -n \\ec'
#\\builtin unset LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
# LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
# LC_TELEPHONE LC_TIME LANGUAGE LANG LC_ALL
#p=en_GB.UTF-8
#\\builtin export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
#\\builtin export LANG=C.UTF-8 LC_CTYPE=C.UTF-8
#\\builtin export LC_ALL=C.UTF-8
#\\builtin set -U
#[[ ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} = *[Uu][Tt][Ff]?(-)8* ]] || \\builtin set +U
\\builtin unset p
\: place customisations above this line

5716
vendor/mksh/mksh/edit.c vendored Normal file

File diff suppressed because it is too large Load Diff

116
vendor/mksh/mksh/emacsfn.h vendored Normal file
View File

@ -0,0 +1,116 @@
/*-
* Copyright (c) 2009, 2010, 2015, 2016, 2020
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#if defined(EMACSFN_DEFNS)
__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.11 2020/04/13 20:46:39 tg Exp $");
#define FN(cname,sname,flags) static int x_##cname(int);
#elif defined(EMACSFN_ENUMS)
#define FN(cname,sname,flags) XFUNC_##cname,
#define F0(cname,sname,flags) XFUNC_##cname = 0,
#elif defined(EMACSFN_ITEMS)
#define FN(cname,sname,flags) { x_##cname, sname, flags },
#endif
#ifndef F0
#define F0 FN
#endif
F0(abort, "abort", 0)
FN(beg_hist, "beginning-of-history", 0)
FN(cls, "clear-screen", 0)
FN(comment, "comment", 0)
FN(comp_comm, "complete-command", 0)
FN(comp_file, "complete-file", 0)
FN(comp_list, "complete-list", 0)
FN(complete, "complete", 0)
FN(del_back, "delete-char-backward", XF_ARG)
FN(del_bword, "delete-word-backward", XF_ARG)
FN(del_char, "delete-char-forward", XF_ARG)
FN(del_fword, "delete-word-forward", XF_ARG)
FN(del_line, "kill-line", 0)
FN(draw_line, "redraw", 0)
#ifndef MKSH_SMALL
FN(edit_line, "edit-line", XF_ARG)
#endif
FN(end_hist, "end-of-history", 0)
FN(end_of_text, "eot", 0)
FN(enumerate, "list", 0)
FN(eot_del, "eot-or-delete", XF_ARG)
FN(error, "error", 0)
#ifndef MKSH_SMALL
FN(eval_region, "evaluate-region", 0)
#endif
FN(expand, "expand-file", 0)
#ifndef MKSH_SMALL
FN(fold_capitalise, "capitalize-word", XF_ARG)
FN(fold_lower, "downcase-word", XF_ARG)
FN(fold_upper, "upcase-word", XF_ARG)
#endif
FN(goto_hist, "goto-history", XF_ARG)
#ifndef MKSH_SMALL
FN(ins_string, "macro-string", XF_NOBIND)
#endif
FN(insert, "auto-insert", XF_ARG)
FN(kill, "kill-to-eol", XF_ARG)
FN(kill_region, "kill-region", 0)
FN(list_comm, "list-command", 0)
FN(list_file, "list-file", 0)
FN(literal, "quote", 0)
FN(meta1, "prefix-1", XF_PREFIX)
FN(meta2, "prefix-2", XF_PREFIX)
FN(meta3, "prefix-3", XF_PREFIX)
FN(meta_yank, "yank-pop", 0)
FN(mv_back, "backward-char", XF_ARG)
FN(mv_beg, "beginning-of-line", 0)
FN(mv_bword, "backward-word", XF_ARG)
FN(mv_end, "end-of-line", 0)
FN(mv_forw, "forward-char", XF_ARG)
FN(mv_fword, "forward-word", XF_ARG)
FN(newline, "newline", 0)
FN(next_com, "down-history", XF_ARG)
FN(nl_next_com, "newline-and-next", 0)
FN(noop, "no-op", 0)
FN(prev_com, "up-history", XF_ARG)
FN(prev_histword, "prev-hist-word", XF_ARG)
#ifndef MKSH_SMALL
FN(quote_region, "quote-region", 0)
#endif
FN(search_char_back, "search-character-backward", XF_ARG)
FN(search_char_forw, "search-character-forward", XF_ARG)
FN(search_hist, "search-history", 0)
#ifndef MKSH_SMALL
FN(search_hist_dn, "search-history-down", 0)
FN(search_hist_up, "search-history-up", 0)
#endif
FN(set_arg, "set-arg", XF_NOBIND)
FN(set_mark, "set-mark-command", 0)
FN(transpose, "transpose-chars", 0)
FN(version, "version", 0)
#ifndef MKSH_SMALL
FN(vt_hack, "vt100-hack", XF_ARG)
#endif
FN(xchg_point_mark, "exchange-point-and-mark", 0)
FN(yank, "yank", 0)
#undef FN
#undef F0
#undef EMACSFN_DEFNS
#undef EMACSFN_ENUMS
#undef EMACSFN_ITEMS

2111
vendor/mksh/mksh/eval.c vendored Normal file

File diff suppressed because it is too large Load Diff

1870
vendor/mksh/mksh/exec.c vendored Normal file

File diff suppressed because it is too large Load Diff

1235
vendor/mksh/mksh/expr.c vendored Normal file

File diff suppressed because it is too large Load Diff

123
vendor/mksh/mksh/exprtok.h vendored Normal file
View File

@ -0,0 +1,123 @@
/*-
* Copyright (c) 2016, 2020
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#if defined(EXPRTOK_DEFNS)
__RCSID("$MirOS: src/bin/mksh/exprtok.h,v 1.4 2020/04/07 11:56:46 tg Exp $");
/* see range comment below */
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
#define FN(name,len,prec,enum) /* nothing */
#define F1(enum) /* nothing */
#elif defined(EXPRTOK_ENUM)
#define F0(name,len,prec,enum) enum = 0,
#define FN(name,len,prec,enum) enum,
#define F1(enum) enum,
#define F2(enum) enum,
#define F9(enum) enum
#elif defined(EXPRTOK_NAME)
#define FN(name,len,prec,enum) name,
#define F1(enum) ""
#elif defined(EXPRTOK_LEN)
#define FN(name,len,prec,enum) len,
#define F1(enum) 0
#elif defined(EXPRTOK_PREC)
#define FN(name,len,prec,enum) prec,
#define F1(enum) P_PRIMARY
#endif
#ifndef F0
#define F0 FN
#endif
#ifndef F2
#define F2(enum) /* nothing */
#define F9(enum) /* nothing */
#endif
/* tokens must be ordered so the longest are first (e.g. += before +) */
/* some (long) unary operators */
F0("++", 2, P_PRIMARY, O_PLUSPLUS) /* before + */
FN("--", 2, P_PRIMARY, O_MINUSMINUS) /* before - */
/* binary operators */
FN("==", 2, P_EQUALITY, O_EQ) /* before = */
FN("!=", 2, P_EQUALITY, O_NE) /* before ! */
/* assignments are assumed to be in range O_ASN .. O_BORASN */
FN("=", 1, P_ASSIGN, O_ASN)
FN("*=", 2, P_ASSIGN, O_TIMESASN)
FN("/=", 2, P_ASSIGN, O_DIVASN)
FN("%=", 2, P_ASSIGN, O_MODASN)
FN("+=", 2, P_ASSIGN, O_PLUSASN)
FN("-=", 2, P_ASSIGN, O_MINUSASN)
#ifndef MKSH_LEGACY_MODE
FN("^<=", 3, P_ASSIGN, O_ROLASN) /* before ^< */
FN("^>=", 3, P_ASSIGN, O_RORASN) /* before ^> */
#endif
FN("<<=", 3, P_ASSIGN, O_LSHIFTASN)
FN(">>=", 3, P_ASSIGN, O_RSHIFTASN)
FN("&=", 2, P_ASSIGN, O_BANDASN)
FN("^=", 2, P_ASSIGN, O_BXORASN)
FN("|=", 2, P_ASSIGN, O_BORASN)
/* binary non-assignment operators */
#ifndef MKSH_LEGACY_MODE
FN("^<", 2, P_SHIFT, O_ROL) /* before ^ */
FN("^>", 2, P_SHIFT, O_ROR) /* before ^ */
#endif
FN("<<", 2, P_SHIFT, O_LSHIFT)
FN(">>", 2, P_SHIFT, O_RSHIFT)
FN("<=", 2, P_RELATION, O_LE)
FN(">=", 2, P_RELATION, O_GE)
FN("<", 1, P_RELATION, O_LT)
FN(">", 1, P_RELATION, O_GT)
FN("&&", 2, P_LAND, O_LAND)
FN("||", 2, P_LOR, O_LOR)
FN("*", 1, P_MULT, O_TIMES)
FN("/", 1, P_MULT, O_DIV)
FN("%", 1, P_MULT, O_MOD)
FN("+", 1, P_ADD, O_PLUS)
FN("-", 1, P_ADD, O_MINUS)
FN("&", 1, P_BAND, O_BAND)
FN("^", 1, P_BXOR, O_BXOR)
FN("|", 1, P_BOR, O_BOR)
FN("?", 1, P_TERN, O_TERN)
FN(",", 1, P_COMMA, O_COMMA)
/* things after this aren't used as binary operators */
/* unary that are not also binaries */
FN("~", 1, P_PRIMARY, O_BNOT)
FN("!", 1, P_PRIMARY, O_LNOT)
/* misc */
FN("(", 1, P_PRIMARY, OPEN_PAREN)
FN(")", 1, P_PRIMARY, CLOSE_PAREN)
FN(":", 1, P_PRIMARY, CTERN)
/* things that don't appear in the opinfo[] table */
F1(VAR) /*XXX should be F2 */
F2(LIT)
F2(END)
F9(BAD)
#undef FN
#undef F0
#undef F1
#undef F2
#undef F9
#undef EXPRTOK_DEFNS
#undef EXPRTOK_ENUM
#undef EXPRTOK_NAME
#undef EXPRTOK_LEN
#undef EXPRTOK_PREC

3459
vendor/mksh/mksh/funcs.c vendored Normal file

File diff suppressed because it is too large Load Diff

1631
vendor/mksh/mksh/histrap.c vendored Normal file

File diff suppressed because it is too large Load Diff

36
vendor/mksh/mksh/jehanne.c vendored Normal file
View File

@ -0,0 +1,36 @@
/*-
* Copyright (c) 2017
* Giacomo Tesio <giacomo@tesio.it>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*-
* Initialisation code for the Jehanne operating system (a Plan 9 de-
* rivative, using GCC)
*/
static const char __rcsid[] __attribute__((__used__)) =
"$MirOS: src/bin/mksh/jehanne.c,v 1.1 2017/12/22 16:30:00 tg Exp $";
#include <u.h>
#include <lib9.h>
#include <posix.h>
void
__application_newlib_init(int argc, char *argv[])
{
rfork(RFFDG | RFREND | RFNOTEG);
libposix_emulate_SIGCHLD();
}

1962
vendor/mksh/mksh/jobs.c vendored Normal file

File diff suppressed because it is too large Load Diff

193
vendor/mksh/mksh/lalloc.c vendored Normal file
View File

@ -0,0 +1,193 @@
/*-
* Copyright (c) 2009, 2010, 2011, 2013, 2014, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#include "sh.h"
#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
#include <err.h>
#endif
__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.26 2016/02/26 21:53:36 tg Exp $");
/* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
#if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
#define remalloc(p,n) ((p) == NULL ? malloc_osi(n) : realloc_osi((p), (n)))
#else
#define remalloc(p,n) realloc_osi((p), (n))
#endif
static struct lalloc_common *findptr(struct lalloc_common **, char *, Area *);
#ifndef MKSH_ALLOC_CATCH_UNDERRUNS
#define ALLOC_ISUNALIGNED(p) (((size_t)(p)) % sizeof(struct lalloc_common))
#else
#define ALLOC_ISUNALIGNED(p) (((size_t)(p)) & 4095)
#undef remalloc
#undef free_osimalloc
static void
free_osimalloc(void *ptr)
{
struct lalloc_item *lp = ptr;
if (munmap(lp, lp->len))
err(1, "free_osimalloc");
}
static void *
remalloc(void *ptr, size_t size)
{
struct lalloc_item *lp, *lold = ptr;
size = (size + 4095) & ~(size_t)4095;
if (lold && lold->len >= size)
return (ptr);
if ((lp = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, (off_t)0)) == MAP_FAILED)
err(1, "remalloc: mmap(%zu)", size);
if (ALLOC_ISUNALIGNED(lp))
errx(1, "remalloc: unaligned(%p)", lp);
if (mprotect(((char *)lp) + 4096, 4096, PROT_NONE))
err(1, "remalloc: mprotect");
lp->len = size;
if (lold) {
memcpy(((char *)lp) + 8192, ((char *)lold) + 8192,
lold->len - 8192);
if (munmap(lold, lold->len))
err(1, "remalloc: munmap");
}
return (lp);
}
#endif
void
ainit(Area *ap)
{
#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
if (sysconf(_SC_PAGESIZE) != 4096) {
fprintf(stderr, "mksh: fatal: pagesize %lu not 4096!\n",
sysconf(_SC_PAGESIZE));
fflush(stderr);
abort();
}
#endif
/* area pointer and items share struct lalloc_common */
ap->next = NULL;
}
static struct lalloc_common *
findptr(struct lalloc_common **lpp, char *ptr, Area *ap)
{
void *lp;
#ifndef MKSH_SMALL
if (ALLOC_ISUNALIGNED(ptr))
goto fail;
#endif
/* get address of ALLOC_ITEM from user item */
/*
* note: the alignment of "ptr" to ALLOC_ITEM is checked
* above; the "void *" gets us rid of a gcc 2.95 warning
*/
*lpp = (lp = ptr - sizeof(ALLOC_ITEM));
/* search for allocation item in group list */
while (ap->next != lp)
if ((ap = ap->next) == NULL) {
#ifndef MKSH_SMALL
fail:
#endif
#ifdef DEBUG
internal_warningf("rogue pointer %zX in ap %zX",
(size_t)ptr, (size_t)ap);
/* try to get a coredump */
abort();
#else
internal_errorf("rogue pointer %zX", (size_t)ptr);
#endif
}
return (ap);
}
void *
aresize2(void *ptr, size_t fac1, size_t fac2, Area *ap)
{
if (notoktomul(fac1, fac2))
internal_errorf(Tintovfl, fac1, '*', fac2);
return (aresize(ptr, fac1 * fac2, ap));
}
void *
aresize(void *ptr, size_t numb, Area *ap)
{
struct lalloc_common *lp = NULL;
/* resizing (true) or newly allocating? */
if (ptr != NULL) {
struct lalloc_common *pp;
pp = findptr(&lp, ptr, ap);
pp->next = lp->next;
}
if (notoktoadd(numb, sizeof(ALLOC_ITEM)) ||
(lp = remalloc(lp, numb + sizeof(ALLOC_ITEM))) == NULL
#ifndef MKSH_SMALL
|| ALLOC_ISUNALIGNED(lp)
#endif
)
internal_errorf(Toomem, numb);
/* area pointer and items share struct lalloc_common */
lp->next = ap->next;
ap->next = lp;
/* return user item address */
return ((char *)lp + sizeof(ALLOC_ITEM));
}
void
afree(void *ptr, Area *ap)
{
if (ptr != NULL) {
struct lalloc_common *lp, *pp;
pp = findptr(&lp, ptr, ap);
/* unhook */
pp->next = lp->next;
/* now free ALLOC_ITEM */
free_osimalloc(lp);
}
}
void
afreeall(Area *ap)
{
struct lalloc_common *lp;
/* traverse group (linked list) */
while ((lp = ap->next) != NULL) {
/* make next ALLOC_ITEM head of list */
ap->next = lp->next;
/* free old head */
free_osimalloc(lp);
}
}

1820
vendor/mksh/mksh/lex.c vendored Normal file

File diff suppressed because it is too large Load Diff

361
vendor/mksh/mksh/lksh.1 vendored Normal file
View File

@ -0,0 +1,361 @@
.\" $MirOS: src/bin/mksh/lksh.1,v 1.26 2020/09/04 22:37:01 tg Exp $
.\"-
.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, 2018
.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
.\" are retained or reproduced in an accompanying document, permission
.\" is granted to deal in this work without restriction, including un
.\" limited rights to use, publicly perform, distribute, sell, modify,
.\" merge, give away, or sublicence.
.\"
.\" This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
.\" the utmost extent permitted by applicable law, neither express nor
.\" implied; without malicious intent or gross negligence. In no event
.\" may a licensor, author or contributor be held liable for indirect,
.\" direct, other damage, loss, or other issues arising in any way out
.\" of dealing in the work, even if advised of the possibility of such
.\" damage or existence of a defect, except proven that it results out
.\" of said persons immediate fault when using the work as intended.
.\"-
.\" Try to make GNU groff and AT&T nroff more compatible
.\" * ` generates in gnroff, so use \`
.\" * ' generates in gnroff, \' generates ´, so use \*(aq
.\" * - generates in gnroff, \- generates , so .tr it to -
.\" thus use - for hyphens and \- for minus signs and option dashes
.\" * ~ is size-reduced and placed atop in groff, so use \*(TI
.\" * ^ is size-reduced and placed atop in groff, so use \*(ha
.\" * \(en does not work in nroff, so use \*(en for a solo en dash
.\" * and \*(EM for a correctly spaced em dash
.\" * <>| are problematic, so redefine and use \*(Lt\*(Gt\*(Ba
.\" Also make sure to use \& *before* a punctuation char that is to not
.\" be interpreted as punctuation, and especially with two-letter words
.\" but also (after) a period that does not end a sentence (“e.g.\&”).
.\" The section after the "doc" macropackage has been loaded contains
.\" additional code to convene between the UCB mdoc macropackage (and
.\" its variant as BSD mdoc in groff) and the GNU mdoc macropackage.
.\"
.ie \n(.g \{\
. if \*[.T]ascii .tr \-\N'45'
. if \*[.T]latin1 .tr \-\N'45'
. if \*[.T]utf8 .tr \-\N'45'
. ds <= \[<=]
. ds >= \[>=]
. ds Rq \[rq]
. ds Lq \[lq]
. ds sL \(aq
. ds sR \(aq
. if \*[.T]utf8 .ds sL `
. if \*[.T]ps .ds sL `
. if \*[.T]utf8 .ds sR '
. if \*[.T]ps .ds sR '
. ds aq \(aq
. ds TI \(ti
. ds ha \(ha
. ds en \(en
.\}
.el \{\
. ds aq '
. ds TI ~
. ds ha ^
. ds en \(em
.\}
.ie n \{\
. ds EM \ \*(en\ \&
.\}
.el \{\
. ds EM \f(TR\^\(em\^\fP
.\}
.\"
.\" Implement .Dd with the Mdocdate RCS keyword
.\"
.rn Dd xD
.de Dd
.ie \\$1$Mdocdate: \{\
. xD \\$2 \\$3, \\$4
.\}
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
..
.\"
.\" .Dd must come before definition of .Mx, because when called
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
.Dd $Mdocdate: September 4 2020 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
.ie \n(.g \{\
. if \*[.T]utf8 .tr \[la]\*(Lt
. if \*[.T]utf8 .tr \[ra]\*(Gt
. ie d volume-ds-1 .ds tT gnu
. el .ie d doc-volume-ds-1 .ds tT gnp
. el .ds tT bsd
.\}
.el .ds tT ucb
.\"
.\" Implement .Mx (MirBSD)
.\"
.ie "\*(tT"gnu" \{\
. eo
. de Mx
. nr curr-font \n[.f]
. nr curr-size \n[.ps]
. ds str-Mx \f[\n[curr-font]]\s[\n[curr-size]u]
. ds str-Mx1 \*[Tn-font-size]\%MirBSD\*[str-Mx]
. if !\n[arg-limit] \
. if \n[.$] \{\
. ds macro-name Mx
. parse-args \$@
. \}
. if (\n[arg-limit] > \n[arg-ptr]) \{\
. nr arg-ptr +1
. ie (\n[type\n[arg-ptr]] == 2) \
. as str-Mx1 \~\*[arg\n[arg-ptr]]
. el \
. nr arg-ptr -1
. \}
. ds arg\n[arg-ptr] "\*[str-Mx1]
. nr type\n[arg-ptr] 2
. ds space\n[arg-ptr] "\*[space]
. nr num-args (\n[arg-limit] - \n[arg-ptr])
. nr arg-limit \n[arg-ptr]
. if \n[num-args] \
. parse-space-vector
. print-recursive
..
. ec
. ds sP \s0
. ds tN \*[Tn-font-size]
.\}
.el .ie "\*(tT"gnp" \{\
. eo
. de Mx
. nr doc-curr-font \n[.f]
. nr doc-curr-size \n[.ps]
. ds doc-str-Mx \f[\n[doc-curr-font]]\s[\n[doc-curr-size]u]
. ds doc-str-Mx1 \*[doc-Tn-font-size]\%MirBSD\*[doc-str-Mx]
. if !\n[doc-arg-limit] \
. if \n[.$] \{\
. ds doc-macro-name Mx
. doc-parse-args \$@
. \}
. if (\n[doc-arg-limit] > \n[doc-arg-ptr]) \{\
. nr doc-arg-ptr +1
. ie (\n[doc-type\n[doc-arg-ptr]] == 2) \
. as doc-str-Mx1 \~\*[doc-arg\n[doc-arg-ptr]]
. el \
. nr doc-arg-ptr -1
. \}
. ds doc-arg\n[doc-arg-ptr] "\*[doc-str-Mx1]
. nr doc-type\n[doc-arg-ptr] 2
. ds doc-space\n[doc-arg-ptr] "\*[doc-space]
. nr doc-num-args (\n[doc-arg-limit] - \n[doc-arg-ptr])
. nr doc-arg-limit \n[doc-arg-ptr]
. if \n[doc-num-args] \
. doc-parse-space-vector
. doc-print-recursive
..
. ec
. ds sP \s0
. ds tN \*[doc-Tn-font-size]
.\}
.el \{\
. de Mx
. nr cF \\n(.f
. nr cZ \\n(.s
. ds aa \&\f\\n(cF\s\\n(cZ
. if \\n(aC==0 \{\
. ie \\n(.$==0 \&MirBSD\\*(aa
. el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
. \}
. if \\n(aC>\\n(aP \{\
. nr aP \\n(aP+1
. ie \\n(C\\n(aP==2 \{\
. as b1 \&MirBSD\ #\&\\*(A\\n(aP\\*(aa
. ie \\n(aC>\\n(aP \{\
. nr aP \\n(aP+1
. nR
. \}
. el .aZ
. \}
. el \{\
. as b1 \&MirBSD\\*(aa
. nR
. \}
. \}
..
.\}
.\"-
.Dt LKSH 1
.Os MirBSD
.Sh NAME
.Nm lksh
.Nd Legacy Korn shell built on mksh
.Sh SYNOPSIS
.Nm
.Bk -words
.Op Fl +abCefhiklmnprUuvXx
.Op Fl +o Ar opt
.Oo
.Fl c Ar string \*(Ba
.Fl s \*(Ba
.Ar file
.Op Ar args ...
.Oc
.Ek
.Sh DESCRIPTION
.Nm
is a command interpreter intended exclusively for running legacy
shell scripts.
It is built on
.Nm mksh ;
refer to its manual page for details on the scripting language.
It is recommended to port scripts to
.Nm mksh
instead of relying on legacy or objectionable POSIX-mandated behaviour,
since the MirBSD Korn Shell scripting language is much more consistent.
.Pp
Do not use
.Nm
as an interactive or login shell; use
.Nm mksh
instead.
.Pp
Note that it's strongly recommended to invoke
.Nm
with
.Fl o Ic posix
to fully enjoy better compatibility to the
.Tn POSIX
standard (which is probably why you use
.Nm
over
.Nm mksh
in the first place);
.Fl o Ic sh
(possibly additionally to the above) may be needed for some legacy scripts.
.Sh LEGACY MODE
.Nm
currently has the following differences from
.Nm mksh :
.Bl -bullet
.It
The
.Ev KSH_VERSION
string identifies
.Nm
as
.Dq Li LEGACY KSH
instead of
.Dq Li MIRBSD KSH .
Note that the rest of the version string is identical between
the two shell flavours, and the behaviour and differences can
change between versions; see the accompanying manual page
.Xr mksh 1
for the versions this document applies to.
.It
.Nm
uses
.Tn POSIX
arithmetic, which has quite a few implications:
The data type for arithmetic operations is the host
.Tn ISO
C
.Vt long
data type.
Signed integer wraparound is Undefined Behaviour; this means that...
.Bd -literal -offset indent
$ echo $((2147483647 + 1))
.Ed
.Pp
\&... is permitted to, e.g. delete all files on your system
(the figure differs for non-32-bit systems, the rule doesn't).
The sign of the result of a modulo operation with at least one
negative operand is unspecified.
Shift operations on negative numbers are unspecified.
Division of the largest negative number by \-1 is Undefined Behaviour.
The compiler is permitted to delete all data and crash the system
if Undefined Behaviour occurs (see above for an example).
.It
The rotation arithmetic operators are not available.
.It
The shift arithmetic operators take all bits of the second operand into
account; if they exceed permitted precision, the result is unspecified.
.It
Unless
.Ic set -o posix
is active,
.Nm
always uses traditional mode for constructs like:
.Bd -literal -offset indent
$ set -- $(getopt ab:c "$@")
$ echo $?
.Ed
.Pp
POSIX mandates this to show 0, but traditional mode
passes through the errorlevel from the
.Xr getopt 1
command.
.It
Functions defined with the
.Ic function
reserved word share the shell options
.Pq Ic set -o
instead of locally scoping them.
.El
.Sh SEE ALSO
.Xr mksh 1
.Pp
.Pa http://www.mirbsd.org/mksh.htm
.Pp
.Pa http://www.mirbsd.org/ksh\-chan.htm
.Sh CAVEATS
To use
.Nm
as
.Pa /bin/sh ,
compilation to enable
.Ic set -o posix
by default if called as
.Nm sh
.Pq adding Dv \-DMKSH_BINSHPOSIX to Dv CPPFLAGS
is highly recommended for better standards compliance.
.Pp
For better compatibility with legacy scripts, such as many
.Tn Debian
maintainer scripts, Upstart and SYSV init scripts, and other
unfixed scripts, also adding the
.Dv \-DMKSH_BINSHREDUCED
compile-time option to enable
.Em both
.Ic set -o posix -o sh
when the shell is run as
.Nm sh ,
as well as integrating the optional disrecommended
.Xr printf 1
builtin, might be necessary.
.Pp
.Nm
tries to make a cross between a legacy bourne/posix compatibl-ish
shell and a legacy pdksh-alike but
.Dq legacy
is not exactly specified.
.Pp
Talk to the
.Mx
development team and users using the mailing list at
.Aq Mt miros\-mksh@mirbsd.org
(please note the EU-DSGVO/GDPR notice on
.Pa http://www.mirbsd.org/rss.htm#lists
and in the SMTP banner!) or the
.Li \&#\&!/bin/mksh
.Pq or Li \&#ksh
IRC channel at
.Pa irc.freenode.net
.Pq Port 6697 SSL, 6667 unencrypted
if you need any further quirks or assistance,
and consider migrating your legacy scripts to work with
.Nm mksh
instead of requiring
.Nm .

2151
vendor/mksh/mksh/main.c vendored Normal file

File diff suppressed because it is too large Load Diff

226
vendor/mksh/mksh/mirhash.h vendored Normal file
View File

@ -0,0 +1,226 @@
/*-
* Copyright © 2011, 2014, 2015
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided AS IS and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said persons immediate fault when using the work as intended.
*-
* This file provides BAFH (Better Avalanche for the Jenkins Hash) as
* inline macro bodies that operate on register uint32_t variables,
* with variants that use their local intermediate registers.
*
* Usage note for BAFH with entropy distribution: input up to 4 bytes
* is best combined into a 32-bit unsigned integer, which is then run
* through BAFHFinish_reg for mixing and then used as context instead
* of 0. Longer input should be handled the same: take the first four
* bytes as IV after mixing then add subsequent bytes the same way.
* This needs counting input bytes and is endian-dependent, thus not,
* for speed reasons, specified for the regular stable hash, but very
* much recommended if the actual output value may differ across runs
* (so is using a random value instead of 0 for the IV).
*-
* Little quote gem:
* We are looking into it. Changing the core
* hash function in PHP isn't a trivial change
* and will take us some time.
* -- Rasmus Lerdorf
*/
#ifndef SYSKERN_MIRHASH_H
#define SYSKERN_MIRHASH_H 1
#define SYSKERN_MIRHASH_BAFH
#include <sys/types.h>
__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.6 2015/11/29 17:05:02 tg Exp $");
/*-
* BAFH itself is defined by the following primitives:
*
* BAFHInit(ctx) initialises the hash context, which consists of a
* sole 32-bit unsigned integer (ideally in a register), to 0.
* It is possible to use any initial value out of [0; 2³²[ which
* is, in fact, recommended if using BAFH for entropy distribution
* but for a regular stable hash, the IV 0 is needed.
*
* BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity
* into the hash context. The algorithm used is Jenkins one-at-a-
* time, except that an additional constant 1 is added so that, if
* the context is (still) zero, adding a NUL byte is not ignored.
*
* BAFHror(eax,cl) evaluates to the unsigned 32-bit integer eax,
* rotated right by cl [0; 31] (no casting, be careful!) where
* eax must be uint32_t and cl an in-range integer.
*
* BAFHFinish(ctx) avalanches the context around so every sub-byte
* depends on all input octets; afterwards, the context variables
* value is the hash output. BAFH does not use any padding, nor is
* the input length added; this is due to the common use case (for
* quick entropy distribution and use with a hashtable).
* Warning: BAFHFinish uses the MixColumn algorithm of AES which
* is reversible (to avoid introducing funnels and reducing entro
* py), so blinding may need to be employed for some uses, e.g. in
* mksh, after a fork.
*
* The BAFHUpdateOctet and BAFHFinish are available in two flavours:
* suffixed with _reg (assumes the context is in a register) or _mem
* (which doesnt).
*
* The following high-level macros (with _reg and _mem variants) are
* available:
*
* BAFHUpdateMem(ctx,buf,len) adds a memory block to a context.
* BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf).
* BAFHHostMem(ctx,buf,len) calculates the hash of the memory buf
* fer using the first 4 octets (mixed) for IV, as outlined above;
* the result is endian-dependent; ctx assumed to be a register.
* BAFHHostStr(ctx,buf) does the same for C strings.
*
* All macros may use ctx multiple times in their expansion, but all
* other arguments are always evaluated at most once except BAFHror.
*
* To stay portable, never use the BAFHHost*() macros (these are for
* host-local entropy shuffling), and encode numbers using ULEB128.
*/
#define BAFHInit(h) do { \
(h) = 0; \
} while (/* CONSTCOND */ 0)
#define BAFHUpdateOctet_reg(h,b) do { \
(h) += (uint8_t)(b); \
++(h); \
(h) += (h) << 10; \
(h) ^= (h) >> 6; \
} while (/* CONSTCOND */ 0)
#define BAFHUpdateOctet_mem(m,b) do { \
register uint32_t BAFH_h = (m); \
\
BAFHUpdateOctet_reg(BAFH_h, (b)); \
(m) = BAFH_h; \
} while (/* CONSTCOND */ 0)
#define BAFHror(eax,cl) (((eax) >> (cl)) | ((eax) << (32 - (cl))))
#define BAFHFinish_reg(h) do { \
register uint32_t BAFHFinish_v; \
\
BAFHFinish_v = ((h) >> 7) & 0x01010101U; \
BAFHFinish_v += BAFHFinish_v << 1; \
BAFHFinish_v += BAFHFinish_v << 3; \
BAFHFinish_v ^= ((h) << 1) & 0xFEFEFEFEU; \
\
BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \
BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \
BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \
(h) = BAFHror((h), 8) ^ BAFHFinish_v; \
} while (/* CONSTCOND */ 0)
#define BAFHFinish_mem(m) do { \
register uint32_t BAFHFinish_v, BAFH_h = (m); \
\
BAFHFinish_v = (BAFH_h >> 7) & 0x01010101U; \
BAFHFinish_v += BAFHFinish_v << 1; \
BAFHFinish_v += BAFHFinish_v << 3; \
BAFHFinish_v ^= (BAFH_h << 1) & 0xFEFEFEFEU; \
\
BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \
BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \
BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \
(m) = BAFHror(BAFH_h, 8) ^ BAFHFinish_v; \
} while (/* CONSTCOND */ 0)
#define BAFHUpdateMem_reg(h,p,z) do { \
register const uint8_t *BAFHUpdate_p; \
register size_t BAFHUpdate_z = (z); \
\
BAFHUpdate_p = (const void *)(p); \
while (BAFHUpdate_z--) \
BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \
} while (/* CONSTCOND */ 0)
/* meh should have named them _r/m but thats not valid C */
#define BAFHUpdateMem_mem(m,p,z) do { \
register uint32_t BAFH_h = (m); \
\
BAFHUpdateMem_reg(BAFH_h, (p), (z)); \
(m) = BAFH_h; \
} while (/* CONSTCOND */ 0)
#define BAFHUpdateStr_reg(h,s) do { \
register const uint8_t *BAFHUpdate_s; \
register uint8_t BAFHUpdate_c; \
\
BAFHUpdate_s = (const void *)(s); \
while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \
BAFHUpdateOctet_reg((h), BAFHUpdate_c); \
} while (/* CONSTCOND */ 0)
#define BAFHUpdateStr_mem(m,s) do { \
register uint32_t BAFH_h = (m); \
\
BAFHUpdateStr_reg(BAFH_h, (s)); \
(m) = BAFH_h; \
} while (/* CONSTCOND */ 0)
#define BAFHHostMem(h,p,z) do { \
register const uint8_t *BAFHUpdate_p; \
register size_t BAFHUpdate_z = (z); \
size_t BAFHHost_z; \
union { \
uint8_t as_u8[4]; \
uint32_t as_u32; \
} BAFHHost_v; \
\
BAFHUpdate_p = (const void *)(p); \
BAFHHost_v.as_u32 = 0; \
BAFHHost_z = BAFHUpdate_z < 4 ? BAFHUpdate_z : 4; \
memcpy(BAFHHost_v.as_u8, BAFHUpdate_p, BAFHHost_z); \
BAFHUpdate_p += BAFHHost_z; \
BAFHUpdate_z -= BAFHHost_z; \
(h) = BAFHHost_v.as_u32; \
BAFHFinish_reg(h); \
while (BAFHUpdate_z--) \
BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \
BAFHFinish_reg(h); \
} while (/* CONSTCOND */ 0)
#define BAFHHostStr(h,s) do { \
register const uint8_t *BAFHUpdate_s; \
register uint8_t BAFHUpdate_c; \
union { \
uint8_t as_u8[4]; \
uint32_t as_u32; \
} BAFHHost_v; \
\
BAFHUpdate_s = (const void *)(s); \
BAFHHost_v.as_u32 = 0; \
if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0) \
++BAFHUpdate_s; \
if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0) \
++BAFHUpdate_s; \
if ((BAFHHost_v.as_u8[2] = *BAFHUpdate_s) != 0) \
++BAFHUpdate_s; \
if ((BAFHHost_v.as_u8[3] = *BAFHUpdate_s) != 0) \
++BAFHUpdate_s; \
(h) = BAFHHost_v.as_u32; \
BAFHFinish_reg(h); \
while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \
BAFHUpdateOctet_reg((h), BAFHUpdate_c); \
BAFHFinish_reg(h); \
} while (/* CONSTCOND */ 0)
#endif

2639
vendor/mksh/mksh/misc.c vendored Normal file

File diff suppressed because it is too large Load Diff

7119
vendor/mksh/mksh/mksh.1 vendored Normal file

File diff suppressed because it is too large Load Diff

652
vendor/mksh/mksh/mksh.faq vendored Normal file
View File

@ -0,0 +1,652 @@
RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.10 2020/10/01 22:59:12 tg Exp $
ToC: spelling
Title: How do you spell <tt>mksh</tt>? How do you pronounce it?
<p>This <a href="@@RELPATH@@mksh.htm">shell</a> is spelt either
“<tt>mksh</tt>” (with, even at the beginning of a sentence, <a
href="https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Capital_letters#Items_that_require_initial_lower_case">an
initial lowercase letter</a>; this is important) or “MirBSD Korn Shell”,
possibly with “the”.</p>
<p>I usually pronounce it as “<span xml:lang="de-DE-1901">em-ka-es-ha</span>”,
that is, the letters individually in my native German, or say “MirBSD Korn
Shell”, although it is manageable, mostly for Slavic speakers, to actually
say “mksh” as if it were a word ☺</p>
<p>Oh… Ive run into this one, didnt I? “MirBSD” is pronounced “<span
xml:lang="de-DE-1901">Mir-Be-Es-De</span>” germanically, for anglophones
“Mir-beastie” is fine.</p>
----
ToC: sowhatismksh
Title: Im a $OS (<i>Android, OS/2, …</i>) user, so whats mksh?
<p>mksh is a so-called (Unix) “shell” or “command interpreter”, similar to
<tt>COMMAND.COM</tt>, <tt>CMD.EXE</tt> or PowerShell on other operating
systems you might know. Basically, it runs in a terminal (“console” or
“DOS box”) window, taking user input and running that as commands. Its
also used to write so-called (shell) “script”s, short programs made by
putting several of those commands into a “batch file”.</p>
<p>On Android, mksh is used as the system shellbasically, the one
running commands at system startup, in the background, and on user
behalf (but never of its own). Any privilege pop-ups you might <a
href="https://forum.xda-developers.com/showthread.php?t=1963976">be
encountering</a> are therefore <a
href="https://forum.xda-developers.com/showpost.php?p=33550523&amp;postcount=1553">not
caused by mksh</a> but by some other code invoking mksh to do something
on its behalf.</p>
----
ToC: os2
Title: Im an OS/2 user, what else do I need to know?
<p>Unlike the native command prompt, the current working directory is,
for security reasons common on Unix systems which the shell is designed
for, not in the search path at all; if you really need this, run the
command <tt>PATH=.$PATHSEP$PATH</tt> or add that to a suitable
initialisation file (<tt>~/.mkshrc</tt>).</p>
<p>There are two different newline modes for mksh-os2: standard (Unix)
mode, in which only LF (0A hex) is supported as line separator, and
“textmode”, which also accepts ASCII newlines (CR+LF), like most other
tools on OS/2, but creating an incompatibility with standard mksh. If
you compiled mksh from source, you will get the standard Unix mode unless
<tt>-T</tt> is added during compilation; however, you will most likely
have gotten this shell through komhs port on Hobbes, or from his OS/2
Factory on eComStation Korea, which uses “textmode”, though. Most OS/2
users will want to use “textmode” unless they need absolute compatibility
with Unix mksh and other Unix shells and tools.</p>
----
ToC: kornshell
Title: How does this relate to ksh or the Korn Shell?
<p>The Korn Shell (AT&amp;T ksh) was authored by David Korn; two major
flavours exist (ksh88 and ksh93), the latter having been maintained
until 2012 (last formal release) and 2014 (last beta snapshot, buggy).
A ksh86 did exist.</p>
<p>Theres now <tt>ksh2020</tt>, a project having restarted development
around November 2017 forking the last <tt>ksh93 v-</tt> (beta) snapshot
and continuing to develop it, presented at FOSDEM.</p>
<p>AT&amp;T ksh88 is “the (original) Korn Shell”. Other implementations,
of varying quality (MKS Toolkits MKS ksh being named as an example of
the lower end, MirBSDs mksh at the upper end). They are all <em>not</em>
“Korn Shell” or “ksh”. However, mksh got blessed by David Korn, as long
as it cannot be confused with the original Korn Shell.</p>
<p>The POSIX shell standard, while lacking most Korn Shell features, was
largely based on AT&amp;T ksh88, with some from the Bourne shell.</p>
<p>mksh is the currently active development of what started as the Public
Domain Bourne Shell in the mid-1980s with ksh88-compatibl-ish extensions
having been added later, making the Public Domain Korn Shell (pdksh),
which, while never officially blessed, was the only way for most to get
a Korn Shell-like command interpreter for AT&amp;Ts was proprietary,
closed-source code for a very long time. pdkshs development ended in
1999, with some projects like Debian and NetBSD® creating small bug fixes
(which often introduced new bugs) as part of maintenance. Around 2003,
OpenBSD started cleaning up their shipped version of pdksh, removing old
and compatibility code and modernising it. In 2002, development of what
is now mksh started as the system shell of MirBSD, which took over almost
all of OpenBSDs cleanup, adding compatibility to other operating systems
back on top of it, and after 2004, independent, massive development of
bugfixes including a complete reorganisation of the way the parser works,
and of new features both independent and compatible with other shells
(ksh93, GNU bash, zsh, BSD csh) started and was followed by working with
the group behind POSIX to fix issues both in the standard and in mksh.
mksh became the system shell in several other operating systems and Linux
distributions and Android and thus is likely the Korn shell, if not Unix
shell, flavour with the largest user base. It has replaced pdksh in all
contemporary systems except QNX, NetBSD® and OpenBSD (who continue to
maintain their variant on “low flame”).</p>
<p>dtksh is the “Desktop Korn Shell”, a build of AT&amp;T ksh93 with some
additional built-in utilities for graphics programming (windows, menu
bars, dialogue boxes, etc.) utilising Motif bindings.</p>
<p>MKS ksh is a proprietary reimplemention aiming for, but not quite
getting close to, ksh88 compatibility.</p>
<p>SKsh is an AmigaOS-specific Korn Shell-lookalike by Steve Koren.</p>
<p>The <a href="@@RELPATH@@ksh-chan.htm">Homepage of the <tt>#ksh</tt>
channel on Freenode IRC</a> contains more information about the Korn
Shell in general and its flavours.</p>
----
ToC: packaging
Title: How should I package mksh? (common cases)
<p>Export a few environment variables, namely <tt>CC</tt> (the C compiler),
<tt>CPPFLAGS</tt> (all C præprocessor definitions), <tt>CFLAGS</tt> (only
compiler flags, <em>no</em> <tt>-Dfoo</tt> or anything!), <tt>LDFLAGS</tt>
(for anything to pass to the C compiler while linking) and <tt>LIBS</tt>
(appended to the linking command line after everything else. You might
wish to <tt>export LDSTATIC=-static</tt> for a static build as well.</p>
<p>When cross-compiling, <tt>CC</tt> is the <em>cross</em> compiler (mksh
currently does not require a compiler targetting the build system), but
you <em>must</em> also export <tt>TARGET_OS</tt> to whatever system you
are compiling for, e.g. “Linux”. For most operating systems, thats just
the uname(1) output. Some very rare systems also need <tt>TARGET_OSREV</tt>;
consult the source code of <tt>Build.sh</tt> for details.</p>
<p>Create two subdirectories, say <tt>build-mksh</tt> and <tt>build-lksh</tt>.
In each of them, start a compilation by issuing <tt>sh ../Build.sh -r</tt>
followed by running the testsuite<a href="#packaging-fn1">¹</a> via
<tt>./test.sh</tt>. For lksh(1) add <tt>-DMKSH_BINSHPOSIX</tt> to
<tt>CPPFLAGS</tt> and use <tt>sh ../Build.sh -r -L</tt> to compile.</p>
<p>See <a href="#testsuite-fails">below</a> if the testsuite fails.</p>
<p>Install <tt>build-mksh/mksh</tt> as <tt>/bin/mksh</tt> (or similar),
<tt>build-lksh/lksh</tt> as <tt>/bin/lksh</tt> with a symlink(7) to it
from <tt>/bin/sh</tt> (if desred), and <tt>mksh.1</tt> and <tt>lksh.1</tt>
as manpages (mdoc macropackage required). Install <tt>dot.mkshrc</tt>
either as <tt>/etc/skel/.mkshrc</tt> (meaning your users will have to
manually resynchronise their home directories copies after every package
upgrade) or as <tt>/etc/mkshrc</tt>, in which case you install a <a
href="https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=alioth/mksh.git;a=blob;f=debian/.mkshrc;hb=HEAD">redirection
script like Debians</a> into <tt>/etc/skel/.mkshrc</tt>. You may need a <a
href="@@RELPATH@@TaC-mksh.txt">summary of the licence information</a>.</p>
<p>At runtime, the presence of <tt>/bin/ed</tt> as default history editor
is recommended, as well as a manpage formatter; you can also install
preformatted manpages from <tt>build-*ksh/*ksh.cat1</tt> if nroff(1) (or
<tt>$NROFF</tt>) is available at build time by removing the <tt>-r</tt>
flag from either <tt>Build.sh</tt> invocation.</p>
<p>Some shell features require the ability to create temporary files and
FIFOS (cf. mkfifo(2))/pipes at runtime. Set <tt>TMPDIR</tt> to a suitable
location if <tt>/tmp</tt> isnt it; if this is known ahead of time, you
can add <tt>-DMKSH_DEFAULT_TMPDIR=\"/path/to/tmp\"</tt> to CPPFLAGS. We
currently are unable to determine one on Android because its bionic libc
does not expose any method suitable to do so in the generic case.</p>
<p id="packaging-fn1">① To run the testsuite, ed(1) must be available as
<tt>/bin/ed</tt>, and perl(1) is needed. When cross-compiling, the version
of the first <tt>ed</tt> binary on the <tt>PATH</tt> <em>must</em> be the
same as that in the target system on which the tests are to be run, in
order to be able to detect which flavour of ed to adjust the tests for.
Busybox ed is broken beyond repair, and all three ed-related tests will
always fail with it.</p>
----
ToC: mkshrc
Title: How does mksh load configuration files?
<p>The shell loads first <tt>/etc/profile</tt> then <tt>~/.profile</tt>
if called as login shell or with the <tt>-l</tt> flag, then loads the file
<tt>$ENV</tt> points to (defaulting to <tt>~/.mkshrc</tt>) for interactive
shells (that includes login shells).</p>
<p>Distributors should take care to either install the <tt>dot.mkshrc</tt>
example provided into <tt>/etc/skel/.mkshrc</tt> (so that its available
for newly created user accounts) and ensure it can propagate to existing
accounts or, if upgrading these is difficult, install the shipped file
as, for example, <tt>/etc/mkshrc</tt> and install a skeleton file, such
as the one in Debian, that sources the file in <tt>/etc</tt>.</p>
<p>Its vital that users can change the configuration, so do not force a
root-provided config file onto them; the shipped file, after all, is just
an example.</p>
<p>If you need central user and configuration management and cannot use
something that installs skeleton files upon home directory creation
(like pam_mkhomedir), you can <tt>export ENV</tt> in <tt>/etc/profile</tt>
to a file (say <tt>/etc/shellrc</tt>) that sources the per-shell file.
Users can, this way, still override it by setting a different <tt>$ENV</tt>
in their <tt>~/.profile</tt>.</p>
----
ToC: testsuite-fails
Title: The testsuite fails!
<p>The mksh testsuite has uncovered numerous bugs in operating systems
(kernels, libraries), compilers and toolchains. It is likely that you
just ran into one. If youre using LTO (the <tt>Build.sh</tt> option
<tt>-c lto</tt>) try to disable it firstespecially GCC is a repeat
offender breaking LTO and its antecessor <tt>-fwhole-program --combine</tt>
and tends to do wrong code generation quite a bit. Otherwise, try
lowering the optimisation levels, bisecting, etc.</p>
----
ToC: selinux-androidiocy
Title: I forbid stat(2) in my SELinux policy, and some things do not work!
Dont break Unix. Read up on the GIGO principle. Duh.
----
ToC: makefile
Title: Why doesnt this use a Makefile to build?
<p>Not all supported target operating environments have a make utility
available, and shell was required for “mirtoconf” (like autoconf)
already anyway, so it was chosen to run the make part as well.</p>
<p>You can, however, add the <tt>-M</tt> flag to your <tt>Build.sh</tt>
invocations to let it produce a <tt>Makefrag.inc</tt> file <em>tailored
for this specific build</em> which you can then include in a Makefile,
such as with the BSD make(1) “.include” command or <a
href="https://www.gnu.org/software/make/manual/make.html#Include">GNU
make</a> equivalent. It even contains, for the user to start out with,
a commented-out example of how to do that in the most basic manner.</p>
----
ToC: oldbsd
Title: Why do other BSDs and QNX still use pdksh instead of mksh?
<p>Some systems are resistant to change, mostly due to bikeshedding
(some people would, for example, rather see all shells banned to
ports/pkgsrc®) and hysterial raisins (historical reasons ☻). Most
BSDs have mksh packages available, and it works on all of them and
QNX just fine.</p>
<p>In fact, on all of these systems, you can replace their 1999-era
<tt>/bin/ksh</tt> (which is a pdksh) with mksh. On at least NetBSD®
1.6 and up (not 1.5) and OpenBSD, even <tt>/bin/sh</tt> is fair game.</p>
<p>MidnightBSD notably has adopted mksh as system shell (thanks laffer1).</p>
----
ToC: openbsd
Title: Why is there no mksh in OpenBSDs ports tree?
OpenBSD dont like people who fork off their project at all; heck,
they dont even like the people they themselves forked off (NetBSD®).
Several people tried over the years to get one committed, but nobody
dared so as to not lose their commit bit. If you try, succeed, and
survive Theo, however, kudos to you! See also <a href="#oldbsd">the
“other BSDs” FAQ entry</a>.
----
ToC: book
Title: Id like an introduction.
Unfortunately, nobody has written a book about mksh yet, although
other shells have received (sometimes decent) attention from authors
and publishers. This FAQ lists a subset of things packagers and
generic people ask, and the mksh(1) manpage is more of a reference,
so you are probably best off starting with a shell-agnostic, POSIX
or ksh88 reference such as the first edition (the second one deals
with ksh93 which differs far more from mksh than ksh88, as ancient
as it is, does) of the OReilly book (⚠ disclaimer: only an example,
not a recommendation) and going forward by reading scripts (the
“shellsnippets” repository referenced in the <tt>#ksh</tt> channel
homepage (see the top of this document) has many examples) and
trying to understand them and the mksh specifics from the manpage.
----
ToC: ps1conv
Title: My prompt from &lt;<i>some other shell</i>&gt; does not work!
<a href="#contact">Contact</a> us on the mailing list or on IRC,
well convert it for you. Also have a look at the PS1 section in
the mksh(1) manpage (search for “otherwise unused char”, e.g. with
<tt>/</tt> in less(1), to spot it quickly).
----
ToC: ps1weird
Title: My prompt is weird!
<p>There are several reasons why your <tt>PS1</tt> might be not
what youd expect:</p><ul>
<li><tt>$PS1</tt> is <tt>export</tt>ed. <strong>Do not export PS1!</strong>
(This was agreed upon as suggestion in a discussion between bash, zsh and
Korn shell developers.) The feature set of different shells vastly differs
and each shell should use its default PS1 or from its startup files.</li>
<li><tt>$ENV</tt> <a href="#env">is set and/or <tt>export</tt>ed</a>.</li>
<li>Your prompt is just “<tt># </tt>”: youre entering a root shell, and
<tt>$PS1</tt> does not contain the # character, in which case the shell
forces this prompt, making extra privileges obvious.</li>
<li>Your prompt is just “<tt>$ </tt>”: perhaps your system administrator
did not install the shipped <tt>dot.mkshrc</tt> file, or you did not copy
<tt>/etc/skel/.mkshrc</tt> into your home directory (perhaps it was created
before <tt>mksh</tt> was installed?). Without another idea for a fix, get <a
href="http://www.mirbsd.org/cvs.cgi/~checkout~/src/bin/mksh/dot.mkshrc?rev=HEAD;content-type=text%2Fplain">this
file</a> and store it as <tt>~/.mkshrc</tt> then run <tt>mksh</tt>; this
will at the very least install our sample (“user@host:path $ ”) prompt.</li>
<li>Your prompt contains things like “\u” or “\w”: it is for another shell
and <a href="#ps1conv">needs converting</a>.</li>
<li>Your prompt contains colours, and when the command line is long the
cursor position or screen contents, especially using the history, is off:
terminal escapes must be escaped from the shell; check the PS1 section in
the manpage: search for “otherwise unused char” (see above).</li>
<li>If the prompt doesnt leave enough space on the right, the shell inserts
a line break after it when rendering.</li>
</ul>
----
ToC: env
Title: On startup files and <tt>$ENV</tt> across and detecting various shells
Interactive shells look at <tt>~/.mkshrc</tt> (or <tt>/system/etc/mkshrc</tt>
on Android and <tt>/etc/mkshrc</tt> on FreeWRT and OpenWrt) by default. This
location can, however, be overridden by setting the <tt>ENV</tt> environment
variable. (FreeBSD is rumoured to set it in their system profile.) Its better
to not set <tt>$ENV</tt> if possible and let every shell user their native
startup files; otherwise, you must ensure that it runs under all shells. Check
<tt>$BASH_VERSION</tt> (GNU bash), <tt>$KSH_VERSION</tt> (contains “LEGACY KSH”
or “MIRBSD KSH” for mksh, “PD KSH” for ancient mirbsdksh/oksh/pdksh, “Version”
for ksh93); <tt>$NETBSD_SHELL</tt> (NetBSD ash); <tt>POSH_VERSION</tt> (posh, a
pdksh derivative); <tt>$SH_VERSION</tt> (“PD KSH” as sh), <tt>$YASH_VERSION</tt>
(yash), <tt>$ZSH_VERSION</tt> (or if <tt>$VERSION</tt> begins with “zsh”); a <a
href="@@RELPATH@@ksh-chan.htm#which-shell">list of more approaches</a> exists.
----
ToC: ctrl-x-e
Title: Multiline command editing
<p>mksh is very independent of the terminal and external libraries and
databases, such as termcap, and therefore is conservative in which ANSI
control codes are sent to the terminal.</p>
<p>For this reason, mkshs input line editing uses a “windowed one-line”
concept: the line the cursor is on is a “window” into the whole input,
horizontally scrolled. Some other shells (that are much larger and have
more dependencies on external tooling) use a “multi-line” editing mode,
and users occasionally wish for this. It is on the long-term TODO, but
(due to the aforementioned implications) this is not trivial.</p>
<p>One way to achieve multi-line editing is to <em>dis</em>able input
line editing: <tt>set +o emacs +o vi</tt><br />This will, however, lose
you all editing features: tab completion, cursor keys, history, etc.</p>
<p>Another way, if you dont need it all the time, is to use a function
that spawns your editor on the input line: press <tt>^Xe</tt> in the
default emacs mode or <tt>Esc + v</tt> in vi mode. Once you exit the
editor, whatever was written there is run; this includes the original
command line if you quit without saving, so request the editor to exit
nōn-zero (e.g. using jupps “abendjoe” command) to prevent execution.
This is <em>really</em> useful to write ad-hōc scripts as well.</p>
----
ToC: ctrl-l-cls
Title: ^L (Ctrl-L) does not clear the screen
Use ^[^L (Escape+Ctrl-L) or rebind it:<br />
<tt>bind '^L=clear-screen'</tt>
----
ToC: ctrl-u-pico
Title: ^U (Ctrl-U) clears the entire line
If it should only delete the line up to the cursor, use:<br />
<tt>bind -m ^U='^[0^K'</tt>
----
ToC: cur-up-zsh
Title: Cursor Up behaves differently from zsh
Some shells make Cursor Up search in the history only for commands
starting with what was already entered. mksh separates the shortcuts:
Cursor Up goes up one command and PgUp searches the history as described
above. You can, of course, rebind:<br />
<tt>bind '^XA=search-history-up'</tt>
----
ToC: current
Title: Can mksh set the title of the window according to the command running?
Theres no such thing as “the command currently running”; consider
pipelines and delays (<tt>cmd1 | (cmd2; sleep 3; cmd3) | cmd4</tt>).
There is, however, a way to make the shell display the command <em>line</em>
during the time it is executed; for testing, you will need to download <a
href="https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=shellsnippets/shellsnippets.git;a=blob;f=mksh/terminal-title;hb=HEAD">this
script</a> and <tt>source</tt> it. For merging into your <tt>~/.mkshrc</tt>
you should first understand how it works: lines 418 set a <tt>PS1</tt>
(prompt) equivalent to lines 8496 of the stock <tt>dot.mkshrc</tt>, with
one change: line 15 (<tt>print &gt;/dev/tty …</tt>) is new, inserted just
before the <tt>return</tt> command of the function substitution in the
default prompt; this is what youll need to merge into your own, custom,
prompt (if you have one; otherwise pull this adaption to the default
one). Line 19 is the only other thing in this script rebinding the Ctrl-M
key (which is normally produced by the Enter/Return key) to code that…
does <em>something crazy</em>. This trick however <em>does funny things with
multiline commands</em>, so if you type something out in multiple lines,
for example <strong>here documents</strong> or <strong>loops</strong> press
<strong>Ctrl-J instead of Enter/Return</strong> after <em>each</em> line
including the first (at PS1) and final (at PS2) one.
----
ToC: other-tty
Title: How do I start mksh on a specific terminal?
<p>Normally: <tt>mksh -T<i>/dev/tty2</i></tt></p>
<p>However, if you want for it to return (e.g. for an embedded system rescue
shell), use this on your real console device instead:
<tt>mksh -T!<i>/dev/ttyACM0</i></tt></p>
<p>mksh can also daemonise (send to the background):
<tt>mksh -T- -c 'exec cdio lock'</tt></p>
----
ToC: completion
Title: What about programmable tab completion?
The shell itself provides static deterministic tab completion.
However, you can use hooks like reprogramming the Tab key to a
command line editor macro, and using the <tt>evaluate-region</tt>
editor command (modulo a bugfix) together with <tt>quote-region</tt> and shell functions to
implement a programmable completion engine. Multiple people have
been considering doing so in our IRC channel; well hyperlink to
these engines when they are available.
----
ToC: posix-mode
Title: How POSIX compliant is mksh? Also, UTF-8 vs. locales?
<p>Youll need to use the <tt>lksh</tt> binary, unless your C <tt>long</tt>
type is 32 bits wide, for POSIX-compliant arithmetic in the shell. This is
because <tt>mksh</tt> provides consistent, wraparound-defined, 32-bit
arithmetics on all platforms normally. Youll also need to enable POSIX mode
(<tt>set -o posix</tt>) explicitly, which also disables brace expansion upon
being enabled (use <tt>set -o braceexpand</tt> to reenable if needed).</p>
<p>For the purpose of POSIX, mksh supports only the <tt>C</tt> locale. mkshs
<tt>utf8-mode</tt> (which only supports the BMP (Basic Multilingual Plane) of
UCS and maps raw octets into the U+EF80‥U+EFFF wide character range; see
<tt>Arithmetic expressions</tt> in mksh(1) for details) <em>must</em> stay
disabled in POSIX mode (it is disabled upon enabling POSIX mode in R56+).</p>
<p class="boxhead">The following POSIX sh-compatible code toggles the
<tt>utf8-mode</tt> option dependent on the current POSIX locale, for mksh
to allow using the UTF-8 mode, within the constraints outlined above, in
code portable across various shell implementations:</p>
<div class="boxtext">
<pre>
case ${KSH_VERSION:-} in
*MIRBSD KSH*|*LEGACY KSH*)
case ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} in
*[Uu][Tt][Ff]8*|*[Uu][Tt][Ff]-8*) set -U ;;
*) set +U ;;
esac ;;
esac
</pre>
</div><p class="boxfoot">In near future, (UTF-8) locale tracking will
be implemented, though.</p>
<p>The shell is pretty close to POSIX, when run as <tt>lksh -o posix</tt>
under the "C" locale it is intended to match. It does not do everything
like other POSIX-compatible or compliant shells, though.</p>
----
ToC: function-local-scopes
Title: What differences in function-local scopes are there?
<p><tt>mksh</tt> has a different scope model from AT&amp;T <tt>ksh</tt>,
which leads to subtle differences in semantics for identical builtins.
This can cause issues with a <tt>nameref</tt> to suddenly point to a
local variable by accident. (Other common shells share mkshs scoping
model.)</p>
<p class="boxhead">GNU <tt>bash</tt> allows unsetting local variables; in
<tt>mksh</tt>, doing so in a function allows back access to the global
variable (actually the one in the next scope up) with the same name. The
following code, when run before function definitions, changes the behaviour
of <tt>unset</tt> to behave like other shells (the alias can be removed
after the definitions):</p>
<div class="boxtext">
<pre>
case ${KSH_VERSION:-} in
*MIRBSD KSH*|*LEGACY KSH*)
function unset_compat {
\\builtin typeset unset_compat_x
for unset_compat_x in "$@"; do
eval "\\\\builtin unset $unset_compat_x[*]"
done
}
\\builtin alias unset=unset_compat
;;
esac
</pre>
</div><p class="boxfoot">When a local variable is created (e.g. using
<tt>local</tt>, <tt>typeset</tt>, <tt>integer</tt> or
<tt>\\builtin typeset</tt>) it does not, like in other shells, inherit
the value from the global (next scope up) variable with the same name;
it is rather created without any value (unset but defined).</p>
----
ToC: regex-comparison
Title: I get an error in this regex comparison
<p>Use extglobs instead of regexes:<br />
<tt>[[ foo =~ (foo|bar).*baz ]]</tt><br />
 becomes…<br />
<tt>[[ foo = *@(foo|bar)*baz* ]]</tt></p>
----
ToC: trim-vector
Title: ${@?}: bad substitution
<p>In mksh, you cannot assign to or trim a vector (yet). For most
cases it is possible to write the affected code in a way avoiding
this extension; for example, trimming <tt>${@#foo}</tt> could be
applied to <tt>$1</tt> only and <tt>${@?}</tt> can be replaced
with a test whether <tt>$# -eq 0</tt>.</p>
----
ToC: extensions-to-avoid
Title: Are there any extensions to avoid?
<p>GNU <tt>bash</tt> supports “<tt>&amp;&gt;</tt>” (and “|&amp;”) to redirect
both stdout and stderr in one go, but this breaks POSIX and Korn Shell syntax;
use POSIX redirections instead:</p>
<table border="1" cellpadding="3">
<tr><td>GNU bash</td><td>
<tt>foo |&amp; bar |&amp; baz &amp;&gt;log</tt>
</td></tr>
<tr><td>POSIX</td><td>
<tt>foo 2&gt;&amp;1 | bar 2&gt;&amp;1 | baz &gt;log 2&gt;&amp;1</tt>
</td></tr>
</table>
----
ToC: while-read-pipe
Title: Something is going wrong with my while...read loop
<p class="boxhead">Most likely, youve encountered the problem in which
the shell runs all parts of a pipeline as subshell. The inner loop will
be executed in a subshell and variable changes cannot be propagated if
run in a pipeline:</p>
<div class="boxtext">
<pre>
bar | baz | while read foo; do ...; done
</pre>
</div><p class="boxfoot">Note that <tt>exit</tt> in the inner loop will
also only exit the subshell and not the original shell. Likewise, if the
code is inside a function, <tt>return</tt> in the inner loop will only
exit the subshell and wont terminate the function.</p>
<p class="boxhead">Use co-processes instead:</p>
<div class="boxtext">
<pre>
bar | baz |&amp;
while read -p foo; do ...; done
exec 3&gt;&amp;p; exec 3&gt;&amp;-
</pre>
</div><p class="boxfoot">If <tt>read</tt> is run in a way such as
<tt>while read foo; do ...; done</tt> then leading whitespace will be
removed (IFS) and backslashes processed. You might want to use
<tt>while IFS= read -r foo; do ...; done</tt> for pristine I/O.</p>
<p class="boxhead">Similarly, when using the <tt>-a</tt> option, use of the
<tt>-r</tt> option might be prudent (<tt>read -raN-1 arr &lt;file</tt>);
the same applies for NUL-terminated lines:</p>
<div class="boxtext">
<pre>
find . -type f -print0 |&amp; \
while IFS= read -d '' -pr filename; do
print -r -- "found &lt;${filename#./}&gt;"
done
</pre>
</div>
----
ToC: command-alias
Title: “command” doesnt expand aliases as in ksh93
This is because AT&amp;T ksh93 ships a predefined alias enabling this:<br />
<tt>alias command='command '</tt><br />
put this into your <tt>~/.mkshrc</tt>
(note the space before the closing single quote)
----
ToC: builtin-rename
Title: “rename” doesnt work as expected!
<p>Theres a <tt>rename</tt> built-in utility in mksh, which is a very
thin wrapper around the rename(2) syscall. It receives two pathnames,
source and destination where the first is then atomically renamed to
the latter. It does not move, i.e. fails for different filesystems.</p>
<p>The GNU package <tt>util-linux</tt> has a different <tt>rename</tt>
command. If you wish to invoke an external utility (in favour over a
builtin), you can use <tt>dot.mkshrc</tt>s function <tt>enable</tt>
or put the following into your <tt>~/.mkshrc</tt>:</p>
<pre>alias rename="$(whence -p rename)"</pre>
----
ToC: builtin-sleep
Title: “sleep” does not accept m for minutes!
<p>mksh contains a <tt>sleep</tt> built-in utility, in order to be
able to offer sub-second sleep to shell scripts for most platforms.
(It does not exist if the platform lacks select(2)which should
be rare.)</p>
<p>GNU coreutils contains a sleep implementation accepting suffixed
numbers. If you wish to invoke an external utility (in favour over a
builtin), you can use <tt>dot.mkshrc</tt>s function <tt>enable</tt>
or put something along the following lines into <tt>~/.mkshrc</tt>:</p>
<pre>alias sleep="$(whence -p sleep)"</pre>
<pre>timer() { sleep $(($1*60${2:++$2})); } # timer mins [secs]</pre>
<pre>timer() {
local arg=${1/m/'*60+'}
[[ $arg = *+ ]] &amp;&amp; arg+=0
sleep $(($arg)
}</pre>
----
ToC: string-concat
Title: “+=” behaves differently from other shells
<p>In POSIX shell, “=” in code like <tt>var=content</tt> is a string
assignment, always. You can use <tt>var=$((content))</tt> for an
arithmetic assignment that mostly uses C language rules.</p>
<p>It stands to consider that the common shell extension “+=” as in
<tt>var+=content</tt> would always do string concatenation; it does
in mksh, but not in some other shells, in which, when <tt>var</tt> has
been declared integer, addition is done instead.</p>
<p>You can make the code portable by using “((…))” (a.k.a. <tt>let</tt>)
instead: <tt>(( var += content ))</tt> does arithmetic addition in
all shells involved.</p>
----
ToC: set-e
Title: I use “set -e” and my code unexpectedly errors out
<p>I personally recommend people to not use “<tt>set -e</tt>”, as it
makes error handling more difficult. However, some insist. There have
been bugfixes (relative to e.g. oksh/loksh and posh) in this aspect,
and the user has to make sure <tt>$?</tt> is always 0 ASAP even after
a command that doesnt check it.</p>
<pre>istwo() {
for i in "$@"; do
test x"$i" = x"2" &amp;&amp; echo two
done
}
set -e
istwo 1
echo END</pre>
<p>This can be fixed by either adding an explicit “<tt>:</tt>” (or
“<tt>true</tt>”) after the comparison, or even…</p>
<pre>test x"$i" = x"2" &amp;&amp; echo two || :</pre>
<p>… or right after the <tt>done</tt> inside the function, but…</p>
<pre>test x"$i" != x"2" || echo two</pre>
<p>… negating the condition and using “<tt>||</tt>” is preferable.</p>
<p>Remember that Korn shell-style functions (with <tt>function</tt>
keyword and <strong>without</strong> parenthesēs) in AT&amp;T ksh93
and mksh R51 and up have their own shell option scope, but while…</p>
<pre>function istwo {
set +e
}</pre>
<p>… might help in error handling, the return status of a function is
still the last errorlevel inside, so an explicit true (“<tt>:</tt>”)
or, more explicitly, “<tt>return 0</tt>” at its end is still needed
if the <em>caller</em> runs under <tt>set -e</tt>.</p>
----
ToC: set-eo-pipefail
Title: I use “set -eo pipefail” and my code unexpectedly errors out
<p class="boxhead">Related to the above FAQ entry, using
<tt>set -o pipefail</tt> makes the following construct error out:</p>
<div class="boxtext">
<pre>
set -e
for x in 1 2; do
false &amp;&amp; echo $x
done | cat
</pre>
</div><p class="boxfoot">This is because, while the <tt>&amp;&amp;</tt>
ensures that the inner commands failure is not taken, it sets the entire
<tt>for</tt>‥<tt>done</tt> loops errorlevel, which is passed on by
<tt>-o pipefail</tt>.</p>
<p>Invert the inner command:<br />
<tt>true || echo $x</tt></p>
----
ToC: faq
Title: My question is not answered here!
Do read the mksh(1) manual page. You might also wish to read the <a
href="@@RELPATH@@ksh-chan.htm">homepage of the <tt>#ksh</tt> IRC channel
on Freenode</a> which lists several resources for Korn or POSIX-compatible
shells in general. Or, <a href="#contact">contact</a> us (developer and
users), for example via IRC.
----
ToC: contact
Title: How do I contact you (to say thanks)?
You can say hi in the <tt>#!/bin/mksh</tt> channel on Freenode <a
href="@@RELPATH@@irc.htm">IRC</a>, although a <a
href="@@RELPATH@@danke.htm">donation</a> wouldnt be amiss ☺ The <a
href="http://www.mail-archive.com/miros-mksh@mirbsd.org/">mailing
list</a> can also be used.
----

BIN
vendor/mksh/mksh/mksh.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

612
vendor/mksh/mksh/os2.c vendored Normal file
View File

@ -0,0 +1,612 @@
/*-
* Copyright (c) 2015, 2017, 2020
* KO Myung-Hun <komh@chollian.net>
* Copyright (c) 2017, 2020
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#define INCL_KBD
#define INCL_DOS
#include <os2.h>
#include "sh.h"
#include <klibc/startup.h>
#include <errno.h>
#include <io.h>
#include <unistd.h>
#include <process.h>
__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.11 2020/10/01 21:13:45 tg Exp $");
struct a_s_arg {
union {
int (*i)(const char *, int);
int (*p)(const char *, void *);
} fn;
union {
int i;
void *p;
} arg;
bool isint;
};
static void remove_trailing_dots(char *, size_t);
static int access_stat_ex(const char *, struct a_s_arg *);
static int test_exec_exist(const char *, void *);
static void response(int *, const char ***);
static char *make_response_file(char * const *);
static void add_temp(const char *);
static void cleanup_temps(void);
static void cleanup(void);
#define RPUT(x) do { \
if (new_argc >= new_alloc) { \
new_alloc += 20; \
if (!(new_argv = realloc(new_argv, \
new_alloc * sizeof(char *)))) \
goto exit_out_of_memory; \
} \
new_argv[new_argc++] = (x); \
} while (/* CONSTCOND */ 0)
#define KLIBC_ARG_RESPONSE_EXCLUDE \
(__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL)
static void
response(int *argcp, const char ***argvp)
{
int i, old_argc, new_argc, new_alloc = 0;
const char **old_argv, **new_argv;
char *line, *l, *p;
FILE *f;
old_argc = *argcp;
old_argv = *argvp;
for (i = 1; i < old_argc; ++i)
if (old_argv[i] &&
!(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) &&
old_argv[i][0] == '@')
break;
if (i >= old_argc)
/* do nothing */
return;
new_argv = NULL;
new_argc = 0;
for (i = 0; i < old_argc; ++i) {
if (i == 0 || !old_argv[i] ||
(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) ||
old_argv[i][0] != '@' ||
!(f = fopen(old_argv[i] + 1, "rt")))
RPUT(old_argv[i]);
else {
long filesize;
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
line = malloc(filesize + /* type */ 1 + /* NUL */ 1);
if (!line) {
exit_out_of_memory:
fputs("Out of memory while reading response file\n", stderr);
exit(255);
}
line[0] = __KLIBC_ARG_NONZERO | __KLIBC_ARG_RESPONSE;
l = line + 1;
while (fgets(l, (filesize + 1) - (l - (line + 1)), f)) {
p = strchr(l, '\n');
if (p) {
/*
* if a line ends with a backslash,
* concatenate with the next line
*/
if (p > l && p[-1] == '\\') {
char *p1;
int count = 0;
for (p1 = p - 1; p1 >= l &&
*p1 == '\\'; p1--)
count++;
if (count & 1) {
l = p + 1;
continue;
}
}
*p = 0;
}
p = strdup(line);
if (!p)
goto exit_out_of_memory;
RPUT(p + 1);
l = line + 1;
}
free(line);
if (ferror(f)) {
fputs("Cannot read response file\n", stderr);
exit(255);
}
fclose(f);
}
}
RPUT(NULL);
--new_argc;
*argcp = new_argc;
*argvp = new_argv;
}
static void
init_extlibpath(void)
{
const char *vars[] = {
"BEGINLIBPATH",
"ENDLIBPATH",
"LIBPATHSTRICT",
NULL
};
char val[512];
int flag;
for (flag = 0; vars[flag]; flag++) {
DosQueryExtLIBPATH(val, flag + 1);
if (val[0])
setenv(vars[flag], val, 1);
}
}
void
os2_init(int *argcp, const char ***argvp)
{
KBDINFO ki;
response(argcp, argvp);
init_extlibpath();
if (!isatty(STDIN_FILENO))
setmode(STDIN_FILENO, O_BINARY);
if (!isatty(STDOUT_FILENO))
setmode(STDOUT_FILENO, O_BINARY);
if (!isatty(STDERR_FILENO))
setmode(STDERR_FILENO, O_BINARY);
/* ensure ECHO mode is ON so that read command echoes. */
memset(&ki, 0, sizeof(ki));
ki.cb = sizeof(ki);
ki.fsMask |= KEYBOARD_ECHO_ON;
KbdSetStatus(&ki, 0);
atexit(cleanup);
}
void
setextlibpath(const char *name, const char *val)
{
int flag;
char *p, *cp;
if (!strcmp(name, "BEGINLIBPATH"))
flag = BEGIN_LIBPATH;
else if (!strcmp(name, "ENDLIBPATH"))
flag = END_LIBPATH;
else if (!strcmp(name, "LIBPATHSTRICT"))
flag = LIBPATHSTRICT;
else
return;
/* convert slashes to backslashes */
strdupx(cp, val, ATEMP);
for (p = cp; *p; p++) {
if (*p == '/')
*p = '\\';
}
DosSetExtLIBPATH(cp, flag);
afree(cp, ATEMP);
}
/* remove trailing dots */
static void
remove_trailing_dots(char *name, size_t namelen)
{
char *p = name + namelen;
while (--p > name && *p == '.')
/* nothing */;
if (*p != '.' && *p != '/' && *p != '\\' && *p != ':')
p[1] = '\0';
}
/* alias of stat() */
extern int _std_stat(const char *, struct stat *);
/* replacement for stat() of kLIBC which fails if there are trailing dots */
int
stat(const char *name, struct stat *buffer)
{
size_t namelen = strlen(name) + 1;
char nodots[namelen];
memcpy(nodots, name, namelen);
remove_trailing_dots(nodots, namelen);
return (_std_stat(nodots, buffer));
}
/* alias of access() */
extern int _std_access(const char *, int);
/* replacement for access() of kLIBC which fails if there are trailing dots */
int
access(const char *name, int mode)
{
size_t namelen = strlen(name) + 1;
char nodots[namelen];
/*
* On OS/2 kLIBC, X_OK is set only for executable files.
* This prevents scripts from being executed.
*/
if (mode & X_OK)
mode = (mode & ~X_OK) | R_OK;
memcpy(nodots, name, namelen);
remove_trailing_dots(nodots, namelen);
return (_std_access(nodots, mode));
}
#define MAX_X_SUFFIX_LEN 4
static const char *x_suffix_list[] =
{ "", ".ksh", ".exe", ".sh", ".cmd", ".com", ".bat", NULL };
/* call fn() by appending executable extensions */
static int
access_stat_ex(const char *name, struct a_s_arg *action)
{
char *x_name;
const char **x_suffix;
int rc = -1;
size_t x_namelen = strlen(name) + MAX_X_SUFFIX_LEN + 1;
/* otherwise, try to append executable suffixes */
x_name = alloc(x_namelen, ATEMP);
for (x_suffix = x_suffix_list; rc && *x_suffix; x_suffix++) {
strlcpy(x_name, name, x_namelen);
strlcat(x_name, *x_suffix, x_namelen);
rc = action->isint ? action->fn.i(x_name, action->arg.i) :
action->fn.p(x_name, action->arg.p);
}
afree(x_name, ATEMP);
return (rc);
}
/* access()/search_access() version */
int
access_ex(int (*fn)(const char *, int), const char *name, int mode)
{
struct a_s_arg arg;
arg.fn.i = fn;
arg.arg.i = mode;
arg.isint = true;
return (access_stat_ex(name, &arg));
}
/* stat()/lstat() version */
int
stat_ex(int (*fn)(const char *, struct stat *),
const char *name, struct stat *buffer)
{
struct a_s_arg arg;
arg.fn.p = fn;
arg.arg.p = buffer;
arg.isint = false;
return (access_stat_ex(name, &arg));
}
static int
test_exec_exist(const char *name, void *arg)
{
struct stat sb;
char *real_name;
if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode))
return (-1);
/*XXX memory leak */
strdupx(real_name, name, ATEMP);
*((char **)arg) = real_name;
return (0);
}
const char *
real_exec_name(const char *name)
{
struct a_s_arg arg;
char *real_name;
arg.fn.p = &test_exec_exist;
arg.arg.p = (void *)(&real_name);
arg.isint = false;
return (access_stat_ex(name, &arg) ? name : real_name);
}
/* make a response file to pass a very long command line */
static char *
make_response_file(char * const *argv)
{
char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
char *rsp_name = &rsp_name_arg[1];
int i;
int fd;
char *result;
if ((fd = mkstemp(rsp_name)) == -1)
return (NULL);
/* write all the arguments except a 0th program name */
for (i = 1; argv[i]; i++) {
write(fd, argv[i], strlen(argv[i]));
write(fd, "\n", 1);
}
close(fd);
add_temp(rsp_name);
strdupx(result, rsp_name_arg, ATEMP);
return (result);
}
/* alias of execve() */
extern int _std_execve(const char *, char * const *, char * const *);
/* replacement for execve() of kLIBC */
int
execve(const char *name, char * const *argv, char * const *envp)
{
const char *exec_name;
FILE *fp;
char sign[2];
int pid;
int status;
int fd;
int rc;
int saved_mode;
int saved_errno;
/*
* #! /bin/sh : append .exe
* extproc sh : search sh.exe in PATH
*/
exec_name = search_path(name, path, X_OK, NULL);
if (!exec_name) {
errno = ENOENT;
return (-1);
}
/*-
* kLIBC execve() has problems when executing scripts.
* 1. it fails to execute a script if a directory whose name
* is same as an interpreter exists in a current directory.
* 2. it fails to execute a script not starting with sharpbang.
* 3. it fails to execute a batch file if COMSPEC is set to a shell
* incompatible with cmd.exe, such as /bin/sh.
* And ksh process scripts more well, so let ksh process scripts.
*/
errno = 0;
if (!(fp = fopen(exec_name, "rb")))
errno = ENOEXEC;
if (!errno && fread(sign, 1, sizeof(sign), fp) != sizeof(sign))
errno = ENOEXEC;
if (fp && fclose(fp))
errno = ENOEXEC;
if (!errno &&
!((sign[0] == 'M' && sign[1] == 'Z') ||
(sign[0] == 'N' && sign[1] == 'E') ||
(sign[0] == 'L' && sign[1] == 'X')))
errno = ENOEXEC;
if (errno == ENOEXEC)
return (-1);
/*
* Normal OS/2 programs expect that standard IOs, especially stdin,
* are opened in text mode at the startup. By the way, on OS/2 kLIBC
* child processes inherit a translation mode of a parent process.
* As a result, if stdin is set to binary mode in a parent process,
* stdin of child processes is opened in binary mode as well at the
* startup. In this case, some programs such as sed suffer from CR.
*/
saved_mode = setmode(STDIN_FILENO, O_TEXT);
pid = spawnve(P_NOWAIT, exec_name, argv, envp);
saved_errno = errno;
/* arguments too long? */
if (pid == -1 && saved_errno == EINVAL) {
/* retry with a response file */
char *rsp_name_arg = make_response_file(argv);
if (rsp_name_arg) {
char *rsp_argv[3] = { argv[0], rsp_name_arg, NULL };
pid = spawnve(P_NOWAIT, exec_name, rsp_argv, envp);
saved_errno = errno;
afree(rsp_name_arg, ATEMP);
}
}
/* restore translation mode of stdin */
setmode(STDIN_FILENO, saved_mode);
if (pid == -1) {
cleanup_temps();
errno = saved_errno;
return (-1);
}
/* close all opened handles */
for (fd = 0; fd < NUFILE; fd++) {
if (fcntl(fd, F_GETFD) == -1)
continue;
close(fd);
}
while ((rc = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
/* nothing */;
cleanup_temps();
/* Is this possible? And is this right? */
if (rc == -1)
return (-1);
if (WIFSIGNALED(status))
_exit(ksh_sigmask(WTERMSIG(status)));
_exit(WEXITSTATUS(status));
}
static struct temp *templist = NULL;
static void
add_temp(const char *name)
{
struct temp *tp;
tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM);
memcpy(tp->tffn, name, strlen(name) + 1);
tp->next = templist;
templist = tp;
}
/* alias of unlink() */
extern int _std_unlink(const char *);
/*
* Replacement for unlink() of kLIBC not supporting to remove files used by
* another processes.
*/
int
unlink(const char *name)
{
int rc;
rc = _std_unlink(name);
if (rc == -1 && errno != ENOENT)
add_temp(name);
return (rc);
}
static void
cleanup_temps(void)
{
struct temp *tp;
struct temp **tpnext;
for (tpnext = &templist, tp = templist; tp; tp = *tpnext) {
if (_std_unlink(tp->tffn) == 0 || errno == ENOENT) {
*tpnext = tp->next;
afree(tp, APERM);
} else {
tpnext = &tp->next;
}
}
}
static void
cleanup(void)
{
cleanup_temps();
}
int
getdrvwd(char **cpp, unsigned int drvltr)
{
PBYTE cp;
ULONG sz;
APIRET rc;
ULONG drvno;
if (DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH,
&sz, sizeof(sz)) != 0) {
errno = EDOOFUS;
return (-1);
}
/* allocate 'X:/' plus sz plus NUL */
checkoktoadd((size_t)sz, (size_t)4);
cp = aresize(*cpp, (size_t)sz + (size_t)4, ATEMP);
cp[0] = ksh_toupper(drvltr);
cp[1] = ':';
cp[2] = '/';
drvno = ksh_numuc(cp[0]) + 1;
/* NUL is part of space within buffer passed */
++sz;
if ((rc = DosQueryCurrentDir(drvno, cp + 3, &sz)) == 0) {
/* success! */
*cpp = cp;
return (0);
}
afree(cp, ATEMP);
*cpp = NULL;
switch (rc) {
case 15: /* invalid drive */
errno = ENOTBLK;
break;
case 26: /* not dos disk */
errno = ENODEV;
break;
case 108: /* drive locked */
errno = EDEADLK;
break;
case 111: /* buffer overflow */
errno = ENAMETOOLONG;
break;
default:
errno = EINVAL;
}
return (-1);
}

113
vendor/mksh/mksh/rlimits.opt vendored Normal file
View File

@ -0,0 +1,113 @@
/*-
* Copyright (c) 2013, 2015, 2019
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*-
* Keep {r,u}limits.opt in sync with each other!
*/
@RLIMITS_DEFNS
__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.5 2020/07/24 20:11:18 tg Exp $");
@RLIMITS_ITEMS
#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid),
@@
/* generic options for the ulimit builtin */
<a|
<H|
<S|
/* do not use options -H, -S or -a or change the order */
>t|RLIMIT_CPU
FN("time(cpu-seconds)", RLIMIT_CPU, 1
>f|RLIMIT_FSIZE
FN("file(blocks)", RLIMIT_FSIZE, 512
>c|RLIMIT_CORE
FN("coredump(blocks)", RLIMIT_CORE, 512
>d|RLIMIT_DATA
FN("data(KiB)", RLIMIT_DATA, 1024
>s|RLIMIT_STACK
FN("stack(KiB)", RLIMIT_STACK, 1024
>l|RLIMIT_MEMLOCK
FN("lockedmem(KiB)", RLIMIT_MEMLOCK, 1024
>n|RLIMIT_NOFILE
FN("nofiles(descriptors)", RLIMIT_NOFILE, 1
>p|RLIMIT_NPROC
FN("processes", RLIMIT_NPROC, 1
>w|RLIMIT_SWAP
FN("swap(KiB)", RLIMIT_SWAP, 1024
>T|RLIMIT_TIME
FN("humantime(seconds)", RLIMIT_TIME, 1
>V|RLIMIT_NOVMON
FN("vnodemonitors", RLIMIT_NOVMON, 1
>i|RLIMIT_SIGPENDING
FN("sigpending", RLIMIT_SIGPENDING, 1
>q|RLIMIT_MSGQUEUE
FN("msgqueue(bytes)", RLIMIT_MSGQUEUE, 1
>M|RLIMIT_AIO_MEM
FN("AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024
>O|RLIMIT_AIO_OPS
FN("AIOoperations", RLIMIT_AIO_OPS, 1
>C|RLIMIT_TCACHE
FN("cachedthreads", RLIMIT_TCACHE, 1
>B|RLIMIT_SBSIZE
FN("sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024
>P|RLIMIT_PTHREAD
FN("threadsperprocess", RLIMIT_PTHREAD, 1
>r|RLIMIT_THREADS
FN("threadsperprocess", RLIMIT_THREADS, 1
>e|RLIMIT_NICE
FN("maxnice", RLIMIT_NICE, 1
>r|RLIMIT_RTPRIO
FN("maxrtprio", RLIMIT_RTPRIO, 1
>m|ULIMIT_M_IS_RSS
FN("resident-set(KiB)", RLIMIT_RSS, 1024
>m|ULIMIT_M_IS_VMEM
FN("memory(KiB)", RLIMIT_VMEM, 1024
>v|ULIMIT_V_IS_VMEM
FN("virtual-memory(KiB)", RLIMIT_VMEM, 1024
>v|ULIMIT_V_IS_AS
FN("address-space(KiB)", RLIMIT_AS, 1024
>x|RLIMIT_LOCKS
FN("filelocks", RLIMIT_LOCKS, 1
|RLIMITS_OPTCS

2903
vendor/mksh/mksh/sh.h vendored Normal file

File diff suppressed because it is too large Load Diff

155
vendor/mksh/mksh/sh_flags.gen vendored Normal file
View File

@ -0,0 +1,155 @@
/* +++ GENERATED FILE +++ DO NOT EDIT +++ */
/*-
* Copyright (c) 2013, 2014, 2015, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#ifndef SHFLAGS_OPTCS
#if defined(SHFLAGS_DEFNS)
__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.9 2020/05/16 22:38:25 tg Exp $");
#elif defined(SHFLAGS_ENUMS)
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
#elif defined(SHFLAGS_ITEMS)
#define FN(sname,cname,flags,ochar) ((const char *)(&shoptione_ ## cname)) + 2,
#endif
#ifndef F0
#define F0 FN
#endif
F0("allexport", FEXPORT, OF_ANY, 'a')
#if HAVE_NICE
FN("bgnice", FBGNICE, OF_ANY, 0)
#endif
FN("braceexpand", FBRACEEXPAND, OF_ANY, 0)
#ifndef MKSH_NO_CMDLINE_EDITING
FN("emacs", FEMACS, OF_ANY, 0)
#endif
FN("errexit", FERREXIT, OF_ANY, 'e')
#ifndef MKSH_NO_CMDLINE_EDITING
FN("gmacs", FGMACS, OF_ANY, 0)
#endif
FN("ignoreeof", FIGNOREEOF, OF_ANY, 0)
FN("inherit-xtrace", FXTRACEREC, OF_ANY, 0)
#ifndef SHFLAGS_NOT_CMD
FN("interactive", FTALKING, OF_CMDLINE, 'i')
#endif
FN("keyword", FKEYWORD, OF_ANY, 'k')
#ifndef SHFLAGS_NOT_CMD
FN("login", FLOGIN, OF_CMDLINE, 'l')
#endif
FN("markdirs", FMARKDIRS, OF_ANY, 'X')
#ifndef MKSH_UNEMPLOYED
FN("monitor", FMONITOR, OF_ANY, 'm')
#endif
FN("noclobber", FNOCLOBBER, OF_ANY, 'C')
FN("noexec", FNOEXEC, OF_ANY, 'n')
FN("noglob", FNOGLOB, OF_ANY, 'f')
FN("nohup", FNOHUP, OF_ANY, 0)
FN("nolog", FNOLOG, OF_ANY, 0)
#ifndef MKSH_UNEMPLOYED
FN("notify", FNOTIFY, OF_ANY, 'b')
#endif
FN("nounset", FNOUNSET, OF_ANY, 'u')
FN("physical", FPHYSICAL, OF_ANY, 0)
FN("pipefail", FPIPEFAIL, OF_ANY, 0)
FN("posix", FPOSIX, OF_ANY, 0)
FN("privileged", FPRIVILEGED, OF_ANY, 'p')
#ifndef SHFLAGS_NOT_CMD
FN("restricted", FRESTRICTED, OF_CMDLINE, 'r')
#endif
FN("sh", FSH, OF_ANY, 0)
#ifndef SHFLAGS_NOT_CMD
FN("stdin", FSTDIN, OF_CMDLINE, 's')
#endif
FN("trackall", FTRACKALL, OF_ANY, 'h')
FN("utf8-mode", FUNNYCODE, OF_ANY, 'U')
FN("verbose", FVERBOSE, OF_ANY, 'v')
#ifndef MKSH_NO_CMDLINE_EDITING
FN("vi", FVI, OF_ANY, 0)
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY, 0)
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY, 0)
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
FN("viraw", FVIRAW, OF_ANY, 0)
#endif
FN("xtrace", FXTRACE, OF_ANY, 'x')
#ifndef SHFLAGS_NOT_CMD
FN("", FCOMMAND, OF_CMDLINE, 'c')
#endif
FN("", FTALKING_I, OF_INTERNAL, 0)
#undef F0
#undef FN
#undef SHFLAGS_DEFNS
#undef SHFLAGS_ENUMS
#undef SHFLAGS_ITEMS
#else
#ifndef SHFLAGS_NOT_SET
"A:"
#endif
"a"
#ifndef MKSH_UNEMPLOYED
"b"
#endif
"C"
#ifndef SHFLAGS_NOT_CMD
"c"
#endif
"e"
"f"
"h"
#ifndef SHFLAGS_NOT_CMD
"i"
#endif
"k"
#ifndef SHFLAGS_NOT_CMD
"l"
#endif
#ifndef MKSH_UNEMPLOYED
"m"
#endif
"n"
#ifndef SHFLAGS_NOT_CMD
"o:"
#endif
#ifndef SHFLAGS_NOT_SET
"o;"
#endif
"p"
#ifndef SHFLAGS_NOT_CMD
"r"
#endif
#ifndef SHFLAGS_NOT_CMD
"s"
#endif
#ifndef SHFLAGS_NOT_SET
"s"
#endif
#ifndef SHFLAGS_NOT_CMD
"T:"
#endif
"U"
"u"
"v"
"X"
"x"
#undef SHFLAGS_OPTCS
#endif

194
vendor/mksh/mksh/sh_flags.opt vendored Normal file
View File

@ -0,0 +1,194 @@
/*-
* Copyright (c) 2013, 2014, 2015, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
@SHFLAGS_DEFNS
__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.9 2020/05/16 22:38:25 tg Exp $");
@SHFLAGS_ENUMS
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
@SHFLAGS_ITEMS
#define FN(sname,cname,flags,ochar) ((const char *)(&shoptione_ ## cname)) + 2,
@@
/* special cases */
<o:|!SHFLAGS_NOT_CMD
<T:|!SHFLAGS_NOT_CMD
<A:|!SHFLAGS_NOT_SET
<o;|!SHFLAGS_NOT_SET
<s|!SHFLAGS_NOT_SET
/*
* options are sorted by their longnames
*/
/* -a all new parameters are created with the export attribute */
>a|
F0("allexport", FEXPORT, OF_ANY
/* ./. bgnice */
>| HAVE_NICE
FN("bgnice", FBGNICE, OF_ANY
/* ./. enable {} globbing (non-standard) */
>|
FN("braceexpand", FBRACEEXPAND, OF_ANY
/* ./. Emacs command line editing mode */
>|!MKSH_NO_CMDLINE_EDITING
FN("emacs", FEMACS, OF_ANY
/* -e quit on error */
>e|
FN("errexit", FERREXIT, OF_ANY
/* ./. Emacs command line editing mode, gmacs variant */
>|!MKSH_NO_CMDLINE_EDITING
FN("gmacs", FGMACS, OF_ANY
/* ./. reading EOF does not exit */
>|
FN("ignoreeof", FIGNOREEOF, OF_ANY
/* ./. inherit -x flag */
>|
FN("inherit-xtrace", FXTRACEREC, OF_ANY
/* -i interactive shell */
>i|!SHFLAGS_NOT_CMD
FN("interactive", FTALKING, OF_CMDLINE
/* -k name=value are recognised anywhere */
>k|
FN("keyword", FKEYWORD, OF_ANY
/* -l login shell */
>l|!SHFLAGS_NOT_CMD
FN("login", FLOGIN, OF_CMDLINE
/* -X mark dirs with / in file name completion */
>X|
FN("markdirs", FMARKDIRS, OF_ANY
/* -m job control monitoring */
>m|!MKSH_UNEMPLOYED
FN("monitor", FMONITOR, OF_ANY
/* -C don't overwrite existing files */
>C|
FN("noclobber", FNOCLOBBER, OF_ANY
/* -n don't execute any commands */
>n|
FN("noexec", FNOEXEC, OF_ANY
/* -f don't do file globbing */
>f|
FN("noglob", FNOGLOB, OF_ANY
/* ./. don't kill running jobs when login shell exits */
>|
FN("nohup", FNOHUP, OF_ANY
/* ./. don't save functions in history (no effect) */
>|
FN("nolog", FNOLOG, OF_ANY
/* -b asynchronous job completion notification */
>b|!MKSH_UNEMPLOYED
FN("notify", FNOTIFY, OF_ANY
/* -u using an unset variable is an error */
>u|
FN("nounset", FNOUNSET, OF_ANY
/* ./. don't do logical cds/pwds (non-standard) */
>|
FN("physical", FPHYSICAL, OF_ANY
/* ./. errorlevel of a pipeline is the rightmost nonzero value */
>|
FN("pipefail", FPIPEFAIL, OF_ANY
/* ./. adhere more closely to POSIX even when undesirable */
>|
FN("posix", FPOSIX, OF_ANY
/* -p privileged shell (suid) */
>p|
FN("privileged", FPRIVILEGED, OF_ANY
/* -r restricted shell */
>r|!SHFLAGS_NOT_CMD
FN("restricted", FRESTRICTED, OF_CMDLINE
/* ./. kludge mode for better compat with traditional sh (OS-specific) */
>|
FN("sh", FSH, OF_ANY
/* -s (invocation) parse stdin (pseudo non-standard) */
>s|!SHFLAGS_NOT_CMD
FN("stdin", FSTDIN, OF_CMDLINE
/* -h create tracked aliases for all commands */
>h|
FN("trackall", FTRACKALL, OF_ANY
/* -U enable UTF-8 processing (non-standard) */
>U|
FN("utf8-mode", FUNNYCODE, OF_ANY
/* -v echo input */
>v|
FN("verbose", FVERBOSE, OF_ANY
/* ./. Vi command line editing mode */
>|!MKSH_NO_CMDLINE_EDITING
FN("vi", FVI, OF_ANY
/* ./. enable ESC as file name completion character (non-standard) */
>|!MKSH_NO_CMDLINE_EDITING
FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY
/* ./. enable Tab as file name completion character (non-standard) */
>|!MKSH_NO_CMDLINE_EDITING
FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY
/* ./. always read in raw mode (no effect) */
>|!MKSH_NO_CMDLINE_EDITING
FN("viraw", FVIRAW, OF_ANY
/* -x execution trace (display commands as they are run) */
>x|
FN("xtrace", FXTRACE, OF_ANY
/* -c (invocation) execute specified command */
>c|!SHFLAGS_NOT_CMD
FN("", FCOMMAND, OF_CMDLINE
/*
* anonymous flags: used internally by shell only (not visible to user)
*/
/* ./. (internal) initial shell was interactive */
>|
FN("", FTALKING_I, OF_INTERNAL
|SHFLAGS_OPTCS

1322
vendor/mksh/mksh/shf.c vendored Normal file

File diff suppressed because it is too large Load Diff

31
vendor/mksh/mksh/signames.inc vendored Normal file
View File

@ -0,0 +1,31 @@
{ "HUP", 1 },
{ "INT", 2 },
{ "QUIT", 3 },
{ "ILL", 4 },
{ "TRAP", 5 },
{ "ABRT", 6 },
{ "BUS", 7 },
{ "FPE", 8 },
{ "KILL", 9 },
{ "USR1", 10 },
{ "SEGV", 11 },
{ "USR2", 12 },
{ "PIPE", 13 },
{ "ALRM", 14 },
{ "TERM", 15 },
{ "STKFLT", 16 },
{ "CHLD", 17 },
{ "CONT", 18 },
{ "STOP", 19 },
{ "TSTP", 20 },
{ "TTIN", 21 },
{ "TTOU", 22 },
{ "URG", 23 },
{ "XCPU", 24 },
{ "XFSZ", 25 },
{ "VTALRM", 26 },
{ "PROF", 27 },
{ "WINCH", 28 },
{ "IO", 29 },
{ "PWR", 30 },
{ "SYS", 31 },

53
vendor/mksh/mksh/strlcpy.c vendored Normal file
View File

@ -0,0 +1,53 @@
/*-
* Copyright (c) 2006, 2008, 2009, 2013
* mirabilos <m@mirbsd.org>
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.10 2015/11/29 17:05:02 tg Exp $");
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
#undef strlcpy
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
const char *s = src;
if (siz == 0)
goto traverse_src;
/* copy as many chars as will fit */
while (--siz && (*dst++ = *s++))
;
/* not enough room in dst */
if (siz == 0) {
/* safe to NUL-terminate dst since we copied <= siz-1 chars */
*dst = '\0';
traverse_src:
/* traverse rest of src */
while (*s++)
;
}
/* count does not include NUL */
return ((size_t)(s - src - 1));
}

1184
vendor/mksh/mksh/syn.c vendored Normal file

File diff suppressed because it is too large Load Diff

1182
vendor/mksh/mksh/tree.c vendored Normal file

File diff suppressed because it is too large Load Diff

360
vendor/mksh/mksh/ulimit.c vendored Normal file
View File

@ -0,0 +1,360 @@
/* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
* 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
* 2019, 2020
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/ulimit.c,v 1.3 2020/07/24 21:08:26 tg Exp $");
#define SOFT 0x1
#define HARD 0x2
#if HAVE_RLIMIT
#if !HAVE_RLIM_T
typedef unsigned long rlim_t;
#endif
/* Magic to divine the 'm' and 'v' limits */
#ifdef RLIMIT_AS
#if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \
!defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS)
#define ULIMIT_V_IS_AS
#elif defined(RLIMIT_VMEM)
#if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS)
#define ULIMIT_V_IS_AS
#else
#define ULIMIT_V_IS_VMEM
#endif
#endif
#endif
#ifdef RLIMIT_RSS
#ifdef ULIMIT_V_IS_VMEM
#define ULIMIT_M_IS_RSS
#elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS)
#define ULIMIT_M_IS_VMEM
#else
#define ULIMIT_M_IS_RSS
#endif
#if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && \
!defined(__APPLE__) && (RLIMIT_RSS == RLIMIT_AS)
/* On Mac OSX keep -m as -v alias for pkgsrc and other software expecting it */
#undef ULIMIT_M_IS_RSS
#endif
#endif
#if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM)
#define ULIMIT_V_IS_VMEM
#endif
#if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \
(!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)))
#define ULIMIT_M_IS_VMEM
#endif
#if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \
(RLIMIT_VMEM == RLIMIT_AS)
#undef ULIMIT_M_IS_VMEM
#endif
#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
# error nonsensical m ulimit
#endif
#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
# error nonsensical v ulimit
#endif
#define LIMITS_GEN "rlimits.gen"
#else /* !HAVE_RLIMIT */
#undef RLIMIT_CORE /* just in case */
#if defined(UL_GETFSIZE)
#define KSH_UL_GFIL UL_GETFSIZE
#elif defined(UL_GFILLIM)
#define KSH_UL_GFIL UL_GFILLIM
#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
#define KSH_UL_GFIL 1
#endif
#if defined(UL_SETFSIZE)
#define KSH_UL_SFIL UL_SETFSIZE
#elif defined(UL_SFILLIM)
#define KSH_UL_SFIL UL_SFILLIM
#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
#define KSH_UL_SFIL 2
#endif
#if defined(KSH_UL_SFIL)
#define KSH_UL_WFIL true
#else
#define KSH_UL_WFIL false
#define KSH_UL_SFIL 0
#endif
#if defined(UL_GETMAXBRK)
#define KSH_UL_GBRK UL_GETMAXBRK
#elif defined(UL_GMEMLIM)
#define KSH_UL_GBRK UL_GMEMLIM
#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
#define KSH_UL_GBRK 3
#endif
#if defined(UL_GDESLIM)
#define KSH_UL_GDES UL_GDESLIM
#elif defined(__GLIBC__) || defined(KSH_ULIMIT2_TEST)
#define KSH_UL_GDES 4
#endif
extern char etext;
extern long ulimit(int, long);
#define LIMITS_GEN "ulimits.gen"
#endif /* !HAVE_RLIMIT */
struct limits {
/* limit resource / read command */
int resource;
#if HAVE_RLIMIT
/* multiply by to get rlim_{cur,max} values */
unsigned int factor;
#else
/* write command */
int wesource;
/* writable? */
bool writable;
#endif
/* getopts char */
char optchar;
/* limit name */
char name[1];
};
#define RLIMITS_DEFNS
#if HAVE_RLIMIT
#define FN(lname,lid,lfac,lopt) \
static const struct { \
int resource; \
unsigned int factor; \
char optchar; \
char name[sizeof(lname)]; \
} rlimits_ ## lid = { \
lid, lfac, lopt, lname \
};
#else
#define FN(lname,lg,ls,lw,lopt) \
static const struct { \
int rcmd; \
int wcmd; \
bool writable; \
char optchar; \
char name[sizeof(lname)]; \
} rlimits_ ## lg = { \
lg, ls, lw, lopt, lname \
};
#endif
#include LIMITS_GEN
static void print_ulimit(const struct limits *, int);
static int set_ulimit(const struct limits *, const char *, int);
static const struct limits * const rlimits[] = {
#define RLIMITS_ITEMS
#include LIMITS_GEN
};
static const char rlimits_opts[] =
#define RLIMITS_OPTCS
#include LIMITS_GEN
#ifndef RLIMIT_CORE
"c"
#endif
;
int
c_ulimit(const char **wp)
{
size_t i = 0;
int how = SOFT | HARD, optc;
char what = 'f';
bool all = false;
while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
switch (optc) {
case ORD('H'):
how = HARD;
break;
case ORD('S'):
how = SOFT;
break;
case ORD('a'):
all = true;
break;
case ORD('?'):
bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
return (1);
default:
what = optc;
}
while (i < NELEM(rlimits)) {
if (rlimits[i]->optchar == what)
goto found;
++i;
}
#ifndef RLIMIT_CORE
if (what == ORD('c'))
/* silently accept */
return 0;
#endif
internal_warningf("ulimit: %c", what);
return (1);
found:
if (wp[builtin_opt.optind]) {
if (all || wp[builtin_opt.optind + 1]) {
bi_errorf(Ttoo_many_args);
return (1);
}
return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
}
if (!all)
print_ulimit(rlimits[i], how);
else for (i = 0; i < NELEM(rlimits); ++i) {
shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name);
print_ulimit(rlimits[i], how);
}
return (0);
}
#if HAVE_RLIMIT
#define RL_T rlim_t
#define RL_U (rlim_t)RLIM_INFINITY
#else
#define RL_T long
#define RL_U LONG_MAX
#endif
static int
set_ulimit(const struct limits *l, const char *v, int how MKSH_A_UNUSED)
{
RL_T val = (RL_T)0;
#if HAVE_RLIMIT
struct rlimit limit;
#endif
if (strcmp(v, "unlimited") == 0)
val = RL_U;
else {
mksh_uari_t rval;
if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false))
return (1);
/*
* Avoid problems caused by typos that evaluate misses due
* to evaluating unset parameters to 0...
* If this causes problems, will have to add parameter to
* evaluate() to control if unset params are 0 or an error.
*/
if (!rval && !ctype(v[0], C_DIGIT)) {
bi_errorf("invalid %s limit: %s", l->name, v);
return (1);
}
#if HAVE_RLIMIT
val = (rlim_t)((rlim_t)rval * l->factor);
#else
val = (RL_T)rval;
#endif
}
#if HAVE_RLIMIT
if (getrlimit(l->resource, &limit) < 0) {
#ifndef MKSH_SMALL
bi_errorf("limit %s could not be read, contact the mksh developers: %s",
l->name, cstrerror(errno));
#endif
/* some can't be read */
limit.rlim_cur = RLIM_INFINITY;
limit.rlim_max = RLIM_INFINITY;
}
if (how & SOFT)
limit.rlim_cur = val;
if (how & HARD)
limit.rlim_max = val;
if (!setrlimit(l->resource, &limit))
return (0);
#else
if (l->writable == false) {
/* check.t:ulimit-2 fails if we return 1 and/or do:
bi_errorf(Tf_ro, l->name);
*/
return (0);
}
if (ulimit(l->wesource, val) != -1L)
return (0);
#endif
if (errno == EPERM)
bi_errorf("%s exceeds allowable %s limit", v, l->name);
else
bi_errorf("bad %s limit: %s", l->name, cstrerror(errno));
return (1);
}
static void
print_ulimit(const struct limits *l, int how MKSH_A_UNUSED)
{
RL_T val = (RL_T)0;
#if HAVE_RLIMIT
struct rlimit limit;
if (getrlimit(l->resource, &limit))
#else
if ((val = ulimit(l->resource, 0)) < 0)
#endif
{
shf_puts("unknown\n", shl_stdout);
return;
}
#if HAVE_RLIMIT
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
#endif
if (val == RL_U)
shf_puts("unlimited\n", shl_stdout);
else {
#if HAVE_RLIMIT
val /= l->factor;
#elif defined(KSH_UL_GBRK)
if (l->resource == KSH_UL_GBRK)
val = (RL_T)(((size_t)val - (size_t)&etext) /
(size_t)1024);
#endif
shprintf("%lu\n", (unsigned long)val);
}
}

46
vendor/mksh/mksh/ulimits.opt vendored Normal file
View File

@ -0,0 +1,46 @@
/*-
* Copyright (c) 2013, 2015, 2020
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*-
* Keep {r,u}limits.opt in sync with each other!
*/
@RLIMITS_DEFNS
__RCSID("$MirOS: src/bin/mksh/ulimits.opt,v 1.2 2020/07/24 20:50:11 tg Exp $");
@RLIMITS_ITEMS
#define FN(lname,lg,ls,lw,lopt) (const struct limits *)(&rlimits_ ## lg),
@@
/* generic options for the ulimit builtin */
<a|
<H|
<S|
/* do not use options -H, -S or -a or change the order */
>f|KSH_UL_GFIL
FN("file(blocks)", KSH_UL_GFIL, KSH_UL_SFIL, KSH_UL_WFIL
>d|KSH_UL_GBRK
FN("data(KiB)", KSH_UL_GBRK, 0, false
>n|KSH_UL_GDES
FN("nofiles(descriptors)", KSH_UL_GDES, 0, false
|RLIMITS_OPTCS

2244
vendor/mksh/mksh/var.c vendored Normal file

File diff suppressed because it is too large Load Diff

80
vendor/mksh/mksh/var_spec.h vendored Normal file
View File

@ -0,0 +1,80 @@
/*-
* Copyright (c) 2009, 2011, 2012, 2016, 2018
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#if defined(VARSPEC_DEFNS)
__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.11 2018/01/13 21:38:10 tg Exp $");
#define FN(name) /* nothing */
#elif defined(VARSPEC_ENUMS)
#define FN(name) V_##name,
#define F0(name) V_##name = 0,
#elif defined(VARSPEC_ITEMS)
#define F0(name) /* nothing */
#define FN(name) #name,
#endif
#ifndef F0
#define F0 FN
#endif
/* NOTE: F0 are skipped for the ITEMS array, only FN generate names */
/* 0 is always V_NONE */
F0(NONE)
/* 1 and up are special variables */
FN(BASHPID)
#ifdef __OS2__
FN(BEGINLIBPATH)
#endif
FN(COLUMNS)
#ifdef __OS2__
FN(ENDLIBPATH)
#endif
FN(EPOCHREALTIME)
#if HAVE_PERSISTENT_HISTORY
FN(HISTFILE)
#endif
FN(HISTSIZE)
FN(IFS)
#ifdef MKSH_EARLY_LOCALE_TRACKING
FN(LANG)
FN(LC_ALL)
FN(LC_CTYPE)
#endif
#ifdef __OS2__
FN(LIBPATHSTRICT)
#endif
FN(LINENO)
FN(LINES)
FN(OPTIND)
FN(PATH)
FN(RANDOM)
FN(SECONDS)
#ifndef MKSH_NO_CMDLINE_EDITING
FN(TERM)
#endif
FN(TMOUT)
FN(TMPDIR)
#undef FN
#undef F0
#undef VARSPEC_DEFNS
#undef VARSPEC_ENUMS
#undef VARSPEC_ITEMS

129
vendor/mksh/stubs_mksh.c vendored Normal file
View File

@ -0,0 +1,129 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <setjmp.h>
#include <termios.h>
// Globals
char **environ = NULL;
extern void console_write(const void* p, size_t len);
// Stubs
int fstat(int fd, struct stat *buf) { return 0; }
int lstat(const char *path, struct stat *buf) { return 0; }
int stat(const char *path, struct stat *buf) { return 0; }
int sigemptyset(sigset_t *set) { return 0; }
int sigaddset(sigset_t *set, int signum) { return 0; }
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { return 0; }
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { return 0; }
int sigsuspend(const sigset_t *mask) { return -1; }
int kill(pid_t pid, int sig) { return 0; }
unsigned int alarm(unsigned int seconds) { return 0; }
off_t lseek(int fd, off_t offset, int whence) { return 0; }
// ssize_t read(int fd, void *buf, size_t count) { return 0; } // In libc.nim
// ssize_t write(int fd, const void *buf, size_t count) { return 0; } // In clib.c
// int open(const char *pathname, int flags, ...) { return -1; } // In libc.nim
// int close(int fd) { return 0; } // In libc.nim
int pipe(int pipefd[2]) { return -1; }
int dup2(int oldfd, int newfd) { return newfd; }
int fcntl(int fd, int cmd, ...) { return 0; }
int ioctl(int fd, unsigned long request, ...) { return 0; }
// int execve(const char *pathname, char *const argv[], char *const envp[]) { return -1; } // In clib.c
// pid_t fork(void) { return -1; } // In clib.c
pid_t waitpid(pid_t pid, int *status, int options) { return -1; }
pid_t getpid(void) { return 1; }
pid_t getppid(void) { return 0; }
uid_t getuid(void) { return 0; }
uid_t geteuid(void) { return 0; }
gid_t getgid(void) { return 0; }
gid_t getegid(void) { return 0; }
pid_t getpgrp(void) { return 1; }
int setuid(uid_t uid) { return 0; }
int setgid(gid_t gid) { return 0; }
int seteuid(uid_t uid) { return 0; }
int setegid(gid_t gid) { return 0; }
int setpgid(pid_t pid, pid_t pgid) { return 0; }
int tcgetattr(int fd, struct termios *termios_p) { return 0; }
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p) { return 0; }
pid_t tcgetpgrp(int fd) { return 1; }
int tcsetpgrp(int fd, pid_t pgrp) { return 0; }
int isatty(int fd) { return 1; }
int access(const char *pathname, int mode) { return -1; }
int unlink(const char *pathname) { return -1; }
int rename(const char *oldpath, const char *newpath) { return -1; }
int rmdir(const char *pathname) { return -1; }
int chdir(const char *path) { return 0; }
char *getcwd(char *buf, size_t size) {
if (size > 1) { buf[0]='/'; buf[1]='\0'; return buf; }
return NULL;
}
int mkdir(const char *pathname, mode_t mode) { return -1; }
time_t time(time_t *tloc) { return 0; }
clock_t times(struct tms *buf) { return 0; }
unsigned int sleep(unsigned int seconds) { return 0; }
DIR *opendir(const char *name) { return NULL; }
struct dirent *readdir(DIR *dirp) { return NULL; }
int closedir(DIR *dirp) { return 0; }
ssize_t readlink(const char *pathname, char *buf, size_t objsiz) { return -1; }
struct passwd *getpwnam(const char *name) { return NULL; }
// qsort
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
if (nmemb < 2 || size == 0) return;
char *b = (char *)base;
char *tmp = malloc(size);
for (size_t i = 0; i < nmemb - 1; i++) {
for (size_t j = 0; j < nmemb - i - 1; j++) {
if (compar(b + j * size, b + (j + 1) * size) > 0) {
// swap
memcpy(tmp, b + j * size, size);
memcpy(b + j * size, b + (j + 1) * size, size);
memcpy(b + (j + 1) * size, tmp, size);
}
}
}
free(tmp);
}
// strstr
char *strstr(const char *haystack, const char *needle) {
if (!*needle) return (char *)haystack;
for (char *p = (char *)haystack; *p; p++) {
if (*p == *needle) {
char *h = p, *n = (char *)needle;
while (*h && *n && *h == *n) { h++; n++; }
if (!*n) return p;
}
}
return NULL;
}
mode_t umask(mode_t mask) { return 0; }
int c_ulimit(const char **wp) { return 0; }
void longjmp(jmp_buf env, int val) { while(1); }
int setjmp(jmp_buf env) { return 0; }
void exit(int status) { while(1); }