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:
parent
6e78b7f458
commit
4cec2d8c25
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef _SYS_FILE_H
|
||||
#define _SYS_FILE_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
""".}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 person’s 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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 person’s 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 .
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 person’s 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 variable’s
|
||||
* 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 doesn’t).
|
||||
*
|
||||
* 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 that’s 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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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… I’ve run into this one, didn’t I? “MirBSD” is pronounced “<span
|
||||
xml:lang="de-DE-1901">Mir-Be-Es-De</span>” germanically, for anglophones
|
||||
“Mir-beas’tie” is fine.</p>
|
||||
----
|
||||
ToC: sowhatismksh
|
||||
Title: I’m a $OS (<i>Android, OS/2, …</i>) user, so what’s 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. It’s
|
||||
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 shell — basically, 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&postcount=1553">not
|
||||
caused by mksh</a> but by some other code invoking mksh to do something
|
||||
on its behalf.</p>
|
||||
----
|
||||
ToC: os2
|
||||
Title: I’m 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 komh’s 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&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>There’s 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&T ksh88 is “the (original) Korn Shell”. Other implementations,
|
||||
of varying quality (MKS Toolkit’s MKS ksh being named as an example of
|
||||
the lower end, MirBSD’s 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&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&T’s was proprietary,
|
||||
closed-source code for a very long time. pdksh’s 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 OpenBSD’s 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&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, that’s 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 Debian’s</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> isn’t 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 it’s 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>It’s 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 you’re using LTO (the <tt>Build.sh</tt> option
|
||||
<tt>-c lto</tt>) try to disable it first — especially 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!
|
||||
|
||||
Don’t break Unix. Read up on the GIGO principle. Duh.
|
||||
----
|
||||
ToC: makefile
|
||||
Title: Why doesn’t 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 OpenBSD’s ports tree?
|
||||
|
||||
OpenBSD don’t like people who fork off their project at all; heck,
|
||||
they don’t 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: I’d 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 O’Reilly 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 <<i>some other shell</i>> does not work!
|
||||
|
||||
<a href="#contact">Contact</a> us on the mailing list or on IRC,
|
||||
we’ll 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 you’d 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>”: you’re 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 doesn’t 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.) It’s 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, mksh’s 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 don’t 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 jupp’s “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?
|
||||
|
||||
There’s 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 4–18 set a <tt>PS1</tt>
|
||||
(prompt) equivalent to lines 84–96 of the stock <tt>dot.mkshrc</tt>, with
|
||||
one change: line 15 (<tt>print >/dev/tty …</tt>) is new, inserted just
|
||||
before the <tt>return</tt> command of the function substitution in the
|
||||
default prompt; this is what you’ll 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; we’ll hyperlink to
|
||||
these engines when they are available.
|
||||
----
|
||||
ToC: posix-mode
|
||||
Title: How POSIX compliant is mksh? Also, UTF-8 vs. locales?
|
||||
|
||||
<p>You’ll 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. You’ll 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. mksh’s
|
||||
<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&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 mksh’s 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>&></tt>” (and “|&”) 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 |& bar |& baz &>log</tt>
|
||||
</td></tr>
|
||||
<tr><td>POSIX</td><td>
|
||||
<tt>foo 2>&1 | bar 2>&1 | baz >log 2>&1</tt>
|
||||
</td></tr>
|
||||
</table>
|
||||
----
|
||||
ToC: while-read-pipe
|
||||
Title: Something is going wrong with my while...read loop
|
||||
|
||||
<p class="boxhead">Most likely, you’ve 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 won’t terminate the function.</p>
|
||||
<p class="boxhead">Use co-processes instead:</p>
|
||||
<div class="boxtext">
|
||||
<pre>
|
||||
bar | baz |&
|
||||
while read -p foo; do ...; done
|
||||
exec 3>&p; exec 3>&-
|
||||
</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 <file</tt>);
|
||||
the same applies for NUL-terminated lines:</p>
|
||||
<div class="boxtext">
|
||||
<pre>
|
||||
find . -type f -print0 |& \
|
||||
while IFS= read -d '' -pr filename; do
|
||||
print -r -- "found <${filename#./}>"
|
||||
done
|
||||
</pre>
|
||||
</div>
|
||||
----
|
||||
ToC: command-alias
|
||||
Title: “command” doesn’t expand aliases as in ksh93
|
||||
|
||||
This is because AT&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” doesn’t work as expected!
|
||||
|
||||
<p>There’s 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 = *+ ]] && 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 doesn’t check it.</p>
|
||||
<pre>istwo() {
|
||||
for i in "$@"; do
|
||||
test x"$i" = x"2" && 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" && 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&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 && echo $x
|
||||
done | cat
|
||||
</pre>
|
||||
</div><p class="boxfoot">This is because, while the <tt>&&</tt>
|
||||
ensures that the inner command’s failure is not taken, it sets the entire
|
||||
<tt>for</tt>‥<tt>done</tt> loop’s 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> wouldn’t be amiss ☺ The <a
|
||||
href="http://www.mail-archive.com/miros-mksh@mirbsd.org/">mailing
|
||||
list</a> can also be used.
|
||||
----
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 },
|
||||
|
|
@ -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));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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); }
|
||||
Loading…
Reference in New Issue