/* $Id: shinstance.h 3480 2020-09-21 11:20:56Z bird $ */ /** @file * The shell instance and it's methods. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef ___shinstance_h #define ___shinstance_h #include /* BUFSIZ */ #include /* NSIG */ #ifndef _MSC_VER # include # include # include # include #endif #include #ifdef _MSC_VER # define EWOULDBLOCK 140 #endif #include "shtypes.h" #include "shthread.h" #include "shfile.h" #include "shheap.h" #include "shell.h" #include "output.h" #include "options.h" #include "expand.h" #include "exec.h" #include "var.h" #include "show.h" #ifdef _MSC_VER # define strcasecmp stricmp # define strncasecmp strnicmp #endif #ifndef SH_FORKED_MODE extern shmtx g_sh_exec_inherit_mtx; #endif #ifndef SH_FORKED_MODE /** * Subshell status. */ typedef struct shsubshellstatus { unsigned volatile refs; /**< Reference counter. */ int volatile status; /**< The exit code. */ KBOOL volatile done; /**< Set if done (valid exit code). */ void *towaiton; /**< Event semaphore / whatever to wait on. */ # if K_OS == K_OS_WINDOWS uintptr_t volatile hThread; /**< The thread handle (child closes this). */ # endif struct shsubshellstatus *next; /**< Next free one on the free chain. */ } shsubshellstatus; #else struct shsubshellstatus; #endif /** * A child process. */ typedef struct shchild { shpid pid; /**< The pid. */ #if K_OS == K_OS_WINDOWS void *hChild; /**< The handle to wait on. */ #endif #ifndef SH_FORKED_MODE shsubshellstatus *subshellstatus; /**< Pointer to the subshell status structure. NULL if child process. */ #endif } shchild; /* memalloc.c */ #define MINSIZE 504 /* minimum size of a block */ struct stack_block { struct stack_block *prev; char space[MINSIZE]; }; #ifdef KASH_SEPARATE_PARSER_ALLOCATOR /** Parser stack allocator block. * These are reference counted so they can be shared between the parent and * child shells. They are also using as an alternative to copying function * definitions, here the final goal is to automatically emit separate * pstack_blocks for function while parsing to make it more flexible. */ typedef struct pstack_block { /** Pointer to the next unallocated byte (= stacknxt). */ char *nextbyte; /** Number of bytes available in the current stack block (= stacknleft). */ size_t avail; /* Number of chars left for string data (PSTPUTC, PSTUPUTC, et al) (= sstrnleft). */ size_t strleft; /** Top of the allocation stack (nextbyte points within this). */ struct stack_block *top; /** Size of the top stack element (user space only). */ size_t topsize; /** @name statistics * @{ */ size_t allocations; size_t bytesalloced; size_t nodesalloced; size_t entriesalloced; size_t strbytesalloced; size_t blocks; size_t fragmentation; /** @} */ /** Reference counter. */ unsigned volatile refs; /** Whether to make it current when is restored to the top of the stack. */ KBOOL done; /** The first stack block. */ struct stack_block first; } pstack_block; #endif /* input.c */ struct strpush { struct strpush *prev; /* preceding string on stack */ char *prevstring; int prevnleft; int prevlleft; struct alias *ap; /* if push was associated with an alias */ }; /* * The parsefile structure pointed to by the global variable parsefile * contains information about the current file being read. */ struct parsefile { struct parsefile *prev; /* preceding file on stack */ int linno; /* current line */ int fd; /* file descriptor (or -1 if string) */ int nleft; /* number of chars left in this line */ int lleft; /* number of chars left in this buffer */ char *nextc; /* next char in buffer */ char *buf; /* input buffer */ struct strpush *strpush; /* for pushing strings at this level */ struct strpush basestrpush; /* so pushing one is fast */ }; /* exec.c */ #define CMDTABLESIZE 31 /* should be prime */ #define ARB 1 /* actual size determined at run time */ struct tblentry { struct tblentry *next; /* next entry in hash chain */ union param param; /* definition of builtin function */ short cmdtype; /* index identifying command */ char rehash; /* if set, cd done since entry created */ char cmdname[ARB]; /* name of command */ }; /* expand.c */ /* * Structure specifying which parts of the string should be searched * for IFS characters. */ struct ifsregion { struct ifsregion *next; /* next region in list */ int begoff; /* offset of start of region */ int endoff; /* offset of end of region */ int inquotes; /* search for nul bytes only */ }; /* redir.c */ struct redirtab { struct redirtab *next; short renamed[10]; }; /** * This is a replacement for temporary node field nfile.expfname. * Uses stack allocator, created by expredir(), duplicated by * subshellinitredir() and popped (but not freed) by expredircleanup(). */ typedef struct redirexpfnames { struct redirexpfnames *prev; /**< Previous record. */ unsigned depth; /**< Nesting depth. */ unsigned count; /**< Number of expanded filenames in the array. */ char *names[1]; /**< Variable size. */ } redirexpfnames; /** * A shell instance. * * This is the core structure of the shell, it contains all * the data associated with a shell process except that it's * running in a thread and not a separate process. */ struct shinstance { struct shinstance *next; /**< The next shell instance. */ struct shinstance *prev; /**< The previous shell instance. */ struct shinstance *parent; /**< The parent shell instance. */ shpid pid; /**< The (fake) process id of this shell instance. */ shtid tid; /**< The thread identifier of the thread for this shell. */ shpid pgid; /**< Process group ID. */ shfdtab fdtab; /**< The file descriptor table. */ shsigaction_t sigactions[NSIG]; /**< The signal actions registered with this shell instance. */ shsigset_t sigmask; /**< Our signal mask. */ char **shenviron; /**< The environment vector. */ int linked; /**< Set if we're still linked. */ unsigned num_children; /**< Number of children in the array. */ shchild *children; /**< The child array. */ #ifndef SH_FORKED_MODE int (*thread)(struct shinstance *, void *); /**< The thread procedure. */ void *threadarg; /**< The thread argument. */ struct jmploc *exitjmp; /**< Long jump target in sh_thread_wrapper for use by sh__exit. */ shsubshellstatus *subshellstatus; /**< Pointer to the subshell status structure (NULL if root). */ #endif /* alias.c */ #define ATABSIZE 39 struct alias *atab[ATABSIZE]; unsigned aliases; /**< Number of active aliases. */ /* cd.c */ char *curdir; /**< current working directory */ char *prevdir; /**< previous working directory */ char *cdcomppath; /**< (stalloc) */ int getpwd_first; /**< static in getpwd. (initialized to 1!) */ /* error.h */ struct jmploc *handler; int exception; int exerrno/* = 0 */; /**< Last exec error */ int volatile suppressint; int volatile intpending; /* error.c */ char errmsg_buf[16]; /**< static in errmsg. (bss) */ /* eval.h */ char *commandname; /**< currently executing command */ int exitstatus; /**< exit status of last command */ int back_exitstatus;/**< exit status of backquoted command */ struct strlist *cmdenviron; /**< environment for builtin command (varlist from evalcommand()) */ int funcnest; /**< depth of function calls */ int evalskip; /**< set if we are skipping commands */ int skipcount; /**< number of levels to skip */ int loopnest; /**< current loop nesting level */ int commandnamemalloc; /**< Set if commandname is malloc'ed (only subshells). */ /* expand.c */ char *expdest; /**< output of current string (stack) */ struct nodelist *argbackq; /**< list of back quote expressions */ struct ifsregion ifsfirst; /**< first struct in list of ifs regions */ struct ifsregion *ifslastp; /**< last struct in list */ struct arglist exparg; /**< holds expanded arg list (stack) */ char *expdir; /**< Used by expandmeta. */ /* exec.h */ const char *pathopt; /**< set by padvance */ /* exec.c */ struct tblentry *cmdtable[CMDTABLESIZE]; int builtinloc/* = -1*/; /**< index in path of %builtin, or -1 */ /* input.h */ int plinno/* = 1 */;/**< input line number */ int parsenleft; /**< number of characters left in input buffer */ char *parsenextc; /**< next character in input buffer */ int init_editline/* = 0 */; /**< 0 == not setup, 1 == OK, -1 == failed */ /* input.c */ int parselleft; /**< copy of parsefile->lleft */ struct parsefile basepf; /**< top level input file */ char basebuf[BUFSIZ];/**< buffer for top level input file */ struct parsefile *parsefile/* = &basepf*/; /**< current input file */ #ifndef SMALL EditLine *el; /**< cookie for editline package */ #endif /* jobs.h */ shpid backgndpid/* = -1 */; /**< pid of last background process */ int job_warning; /**< user was warned about stopped jobs */ /* jobs.c */ struct job *jobtab; /**< array of jobs */ int njobs; /**< size of array */ int jobs_invalid; /**< set in child */ shpid initialpgrp; /**< pgrp of shell on invocation */ int curjob/* = -1*/;/**< current job */ int ttyfd/* = -1*/; int jobctl; /**< job control enabled / disabled */ char *cmdnextc; int cmdnleft; /* mail.c */ #define MAXMBOXES 10 int nmboxes; /**< number of mailboxes */ time_t mailtime[MAXMBOXES]; /**< times of mailboxes */ /* main.h */ shpid rootpid; /**< pid of main shell. */ int rootshell; /**< true if we aren't a child of the main shell. */ struct shinstance *psh_rootshell; /**< The root shell pointer. (!rootshell) */ /* memalloc.h */ char *stacknxt/* = stackbase.space*/; int stacknleft/* = MINSIZE*/; int sstrnleft; int herefd/* = -1 */; /* memalloc.c */ struct stack_block stackbase; struct stack_block *stackp/* = &stackbase*/; struct stackmark *markp; #ifdef KASH_SEPARATE_PARSER_ALLOCATOR pstack_block *curpstack; /**< The pstack entry we're currently allocating from (NULL when not in parse.c). */ pstack_block **pstack; /**< Stack of parsed stuff. */ unsigned pstacksize; /**< Number of entries in pstack. */ unsigned pstackalloced; /**< The allocated size of pstack. */ pstack_block *freepstack; /**< One cached pstack entry (lots of parsecmd calls). */ #endif /* myhistedit.h */ int displayhist; #ifndef SMALL History *hist; EditLine *el; #endif /* output.h */ struct output output; struct output errout; struct output memout; struct output *out1; struct output *out2; /* output.c */ #define OUTBUFSIZ BUFSIZ #define MEM_OUT -3 /**< output to dynamically allocated memory */ /* options.h */ struct optent optlist[NOPTS]; char *minusc; /**< argument to -c option */ char *arg0; /**< $0 */ struct shparam shellparam; /**< $@ */ char **argptr; /**< argument list for builtin commands */ char *optionarg; /**< set by nextopt */ char *optptr; /**< used by nextopt */ char **orgargv; /**< The original argument vector (for cleanup). */ int arg0malloc; /**< Indicates whether arg0 was allocated or is part of orgargv. */ /* parse.h */ int tokpushback; int whichprompt; /**< 1 == PS1, 2 == PS2 */ /* parser.c */ int noalias/* = 0*/;/**< when set, don't handle aliases */ struct heredoc *heredoclist; /**< list of here documents to read */ int parsebackquote; /**< nonzero if we are inside backquotes */ int doprompt; /**< if set, prompt the user */ int needprompt; /**< true if interactive and at start of line */ int lasttoken; /**< last token read */ char *wordtext; /**< text of last word returned by readtoken */ int checkkwd; /**< 1 == check for kwds, 2 == also eat newlines */ struct nodelist *backquotelist; union node *redirnode; struct heredoc *heredoc; int quoteflag; /**< set if (part of) last token was quoted */ int startlinno; /**< line # where last token started */ /* redir.c */ struct redirtab *redirlist; int fd0_redirected/* = 0*/; redirexpfnames *expfnames; /**< Expanded filenames for current redirection setup. */ /* show.c */ char tracebuf[1024]; size_t tracepos; int tracefd; /* trap.h */ int pendingsigs; /**< indicates some signal received */ /* trap.c */ char gotsig[NSIG]; /**< indicates specified signal received */ char *trap[NSIG+1]; /**< trap handler commands */ char sigmode[NSIG]; /**< current value of signal */ /* var.h */ struct localvar *localvars; struct var vatty; struct var vifs; struct var vmail; struct var vmpath; struct var vpath; #ifdef _MSC_VER struct var vpath2; #endif struct var vps1; struct var vps2; struct var vps4; #ifndef SMALL struct var vterm; struct var vhistsize; #endif struct var voptind; #ifdef PC_OS2_LIBPATHS struct var libpath_vars[4]; #endif #ifdef SMALL # define VTABSIZE 39 #else # define VTABSIZE 517 #endif struct var *vartab[VTABSIZE]; /* builtins.h */ /* bltin/test.c */ char **t_wp; struct t_op const *t_wp_op; }; extern void sh_init_globals(void); extern shinstance *sh_create_root_shell(char **, char **); extern shinstance *sh_create_child_shell(shinstance *); /* environment & pwd.h */ char *sh_getenv(shinstance *, const char *); char **sh_environ(shinstance *); const char *sh_gethomedir(shinstance *, const char *); /* signals */ #define SH_SIG_UNK ((shsig_t)(intptr_t)-199) #define SH_SIG_DFL ((shsig_t)(intptr_t)SIG_DFL) #define SH_SIG_IGN ((shsig_t)(intptr_t)SIG_IGN) #define SH_SIG_ERR ((shsig_t)(intptr_t)SIG_ERR) #ifdef _MSC_VER # define SA_RESTART 0x02 # define SIG_BLOCK 1 # define SIG_UNBLOCK 2 # define SIG_SETMASK 3 # define SIGHUP 1 /* _SIGHUP_IGNORE */ /*# define SIGINT 2 */ # define SIGQUIT 3 /* _SIGQUIT_IGNORE */ /*# define SIGILL 4 */ /*# define SIGFPE 8 */ /*# define SIGSEGV 11 */ # define SIGPIPE 13 /* _SIGPIPE_IGNORE */ /*# define SIGTERM 15 */ # define SIGTTIN 16 /* _SIGIOINT_IGNORE */ # define SIGTSTP 17 /* _SIGSTOP_IGNORE */ # define SIGTTOU 18 # define SIGCONT 20 /*# define SIGBREAK 21 */ /*# define SIGABRT 22 */ const char *strsignal(int iSig); #endif /* _MSC_VER */ #ifndef HAVE_SYS_SIGNAME extern const char * const sys_signame[NSIG]; #endif int sh_sigaction(shinstance *, int, const struct shsigaction *, struct shsigaction *); shsig_t sh_signal(shinstance *, int, shsig_t); int sh_siginterrupt(shinstance *, int, int); void sh_sigemptyset(shsigset_t *); void sh_sigfillset(shsigset_t *); void sh_sigaddset(shsigset_t *, int); void sh_sigdelset(shsigset_t *, int); int sh_sigismember(shsigset_t const *, int); int sh_sigprocmask(shinstance *, int, shsigset_t const *, shsigset_t *); SH_NORETURN_1 void sh_abort(shinstance *) SH_NORETURN_2; void sh_raise_sigint(shinstance *); int sh_kill(shinstance *, shpid, int); int sh_killpg(shinstance *, shpid, int); /* times */ #include #ifdef _MSC_VER typedef struct shtms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; } shtms; #else # include typedef struct tms shtms; #endif clock_t sh_times(shinstance *, shtms *); int sh_sysconf_clk_tck(void); /* wait / process */ int sh_add_child(shinstance *psh, shpid pid, void *hChild, struct shsubshellstatus *sts); #ifdef _MSC_VER # include # define WNOHANG 1 /* Don't hang in wait. */ # define WUNTRACED 2 /* Tell about stopped, untraced children. */ # define WCONTINUED 4 /* Report a job control continued process. */ # define _W_INT(w) (*(int *)&(w)) /* Convert union wait to int. */ # define WCOREFLAG 0200 # define _WSTATUS(x) (_W_INT(x) & 0177) # define _WSTOPPED 0177 /* _WSTATUS if process is stopped */ # define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED) # define WSTOPSIG(x) (_W_INT(x) >> 8) # define WIFSIGNALED(x) (_WSTATUS(x) != 0 && !WIFSTOPPED(x) && !WIFCONTINUED(x)) /* bird: made GLIBC tests happy. */ # define WTERMSIG(x) (_WSTATUS(x)) # define WIFEXITED(x) (_WSTATUS(x) == 0) # define WEXITSTATUS(x) (_W_INT(x) >> 8) # define WIFCONTINUED(x) (x == 0x13) /* 0x13 == SIGCONT */ # define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) # define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) # define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED) #else # include # ifdef __HAIKU__ # define WCOREDUMP(x) WIFCORED(x) # endif #endif #ifdef SH_FORKED_MODE shpid sh_fork(shinstance *); #else shpid sh_thread_start(shinstance *pshparent, shinstance *pshchild, int (*thread)(shinstance *, void *), void *arg); #endif shpid sh_waitpid(shinstance *, shpid, int *, int); SH_NORETURN_1 void sh__exit(shinstance *, int) SH_NORETURN_2; int sh_execve(shinstance *, const char *, const char * const*, const char * const *); uid_t sh_getuid(shinstance *); uid_t sh_geteuid(shinstance *); gid_t sh_getgid(shinstance *); gid_t sh_getegid(shinstance *); shpid sh_getpid(shinstance *); shpid sh_getpgrp(shinstance *); shpid sh_getpgid(shinstance *, shpid); int sh_setpgid(shinstance *, shpid, shpid); /* tc* */ shpid sh_tcgetpgrp(shinstance *, int); int sh_tcsetpgrp(shinstance *, int, shpid); /* sys/resource.h */ #ifdef _MSC_VER typedef int64_t shrlim_t; typedef struct shrlimit { shrlim_t rlim_cur; shrlim_t rlim_max; } shrlimit; # define RLIMIT_CPU 0 # define RLIMIT_FSIZE 1 # define RLIMIT_DATA 2 # define RLIMIT_STACK 3 # define RLIMIT_CORE 4 # define RLIMIT_RSS 5 # define RLIMIT_MEMLOCK 6 # define RLIMIT_NPROC 7 # define RLIMIT_NOFILE 8 # define RLIMIT_SBSIZE 9 # define RLIMIT_VMEM 10 # define RLIM_NLIMITS 11 # define RLIM_INFINITY (0x7fffffffffffffffLL) #else typedef rlim_t shrlim_t; typedef struct rlimit shrlimit; #endif int sh_getrlimit(shinstance *, int, shrlimit *); int sh_setrlimit(shinstance *, int, const shrlimit *); /* string.h */ const char *sh_strerror(shinstance *, int); #ifdef DEBUG # define TRACE2(param) trace param # define TRACE2V(param) tracev param #else # define TRACE2(param) do { } while (0) # define TRACE2V(param) do { } while (0) #endif #endif