1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
|
/* $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 <bird-kBuild-spamx@anduin.net>
*
*
* 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 <stdio.h> /* BUFSIZ */
#include <signal.h> /* NSIG */
#ifndef _MSC_VER
# include <termios.h>
# include <sys/types.h>
# include <sys/ioctl.h>
# include <sys/resource.h>
#endif
#include <errno.h>
#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 <time.h>
#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 <sys/times.h>
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 <process.h>
# 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 <sys/wait.h>
# 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
|