/* vi: set sw=4 ts=4: */
/*
* ash shell port for busybox
*
* Copyright (c) 1989, 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
* was re-ported from NetBSD and debianized.
*
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Modified by Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
*
*
* Original BSD copyright notice is retained at the end of this file.
*/
/*
* The follow should be set to reflect the type of system you have:
* JOBS -> 1 if you have Berkeley job control, 0 otherwise.
* define SYSV if you are running under System V.
* define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
* define DEBUG=2 to compile in and turn on debugging.
*
* When debugging is on, debugging info will be written to ./trace and
* a quit signal will generate a core dump.
*/
#define IFS_BROKEN
#define PROFILE 0
#ifdef DEBUG
#define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h>
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#include <setjmp.h>
#include <signal.h>
#include <stdint.h>
#include <sysexits.h>
#include <fnmatch.h>
#include <glob.h>
#include "busybox.h"
#include "pwd_.h"
#ifdef CONFIG_ASH_JOB_CONTROL
#define JOBS 1
#else
#undef JOBS
#endif
#if JOBS
#include <termios.h>
#endif
#include "cmdedit.h"
#ifdef __GLIBC__
/* glibc sucks */
static int *dash_errno;
#undef errno
#define errno (*dash_errno)
#endif
#if defined(__uClinux__)
#error "Do not even bother, ash will not run on uClinux"
#endif
#ifdef DEBUG
#define _DIAGASSERT(assert_expr) assert(assert_expr)
#else
#define _DIAGASSERT(assert_expr)
#endif
#ifdef CONFIG_ASH_ALIAS
/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
#define ALIASINUSE 1
#define ALIASDEAD 2
struct alias {
struct alias *next;
char *name;
char *val;
int flag;
};
static struct alias *lookupalias(const char *, int);
static int aliascmd(int, char **);
static int unaliascmd(int, char **);
static void rmaliases(void);
static int unalias(const char *);
static void printalias(const struct alias *);
#endif
/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
static void setpwd(const char *, int);
/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
/*
* Types of operations (passed to the errmsg routine).
*/
static const char not_found_msg[] = "%s: not found";
#define E_OPEN "No such file" /* opening a file */
#define E_CREAT "Directory nonexistent" /* creating a file */
#define E_EXEC not_found_msg+4 /* executing a program */
/*
* We enclose jmp_buf in a structure so that we can declare pointers to
* jump locations. The global variable handler contains the location to
* jump to when an exception occurs, and the global variable exception
* contains a code identifying the exeception. To implement nested
* exception handlers, the user should save the value of handler on entry
* to an inner scope, set handler to point to a jmploc structure for the
* inner scope, and restore handler on exit from the scope.
*/
struct jmploc {
jmp_buf loc;
};
static struct jmploc *handler;
static int exception;
static volatile int suppressint;
static volatile sig_atomic_t intpending;
static int exerrno; /* Last exec error, error for EXEXEC */
/* exceptions */
#define EXINT 0 /* SIGINT received */
#define EXERROR 1 /* a generic error */
#define EXSHELLPROC 2 /* execute a shell procedure */
#define EXEXEC 3 /* command execution failed */
#define EXEXIT 4 /* exit the shell */
#define EXSIG 5 /* trapped signal in wait(1) */
/* do we generate EXSIG events */
static int exsig;
/* last pending signal */
static volatile sig_atomic_t pendingsigs;
/*
* These macros allow the user to suspend the handling of interrupt signals
* over a period of time. This is similar to SIGHOLD to or sigblock, but
* much more efficient and portable. (But hacking the kernel is so much
* more fun than worrying about efficiency and portability. :-))
*/
#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
#define INTOFF \
({ \
suppressint++; \
barrier(); \
0; \
})
#define SAVEINT(v) ((v) = suppressint)
#define RESTOREINT(v) \
({ \
barrier(); \
if ((suppressint = (v)) == 0 && intpending) onint(); \
0; \
})
#define EXSIGON() \
({ \
exsig++; \
barrier(); \
if (pendingsigs) \
exraise(EXSIG); \
0; \
})
/* EXSIG is turned off by evalbltin(). */
static void exraise(int) __attribute__((__noreturn__));
static void onint(void) __attribute__((__noreturn__));
static void error(const char *, ...) __attribute__((__noreturn__));
static void exerror(int, const char *, ...) __attribute__((__noreturn__));
static void sh_warnx(const char *, ...);
#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
static void
inton(void) {
if (--suppressint == 0 && intpending) {
onint();
}
}
#define INTON inton()
static void forceinton(void)
{
suppressint = 0;
if (intpending)
onint();
}
#define FORCEINTON forceinton()
#else
#define INTON \
({ \
barrier(); \
if (--suppressint == 0 && intpending) onint(); \
0; \
})
#define FORCEINTON \
({ \
barrier(); \
suppressint = 0; \
if (intpending) onint(); \
0; \
})
#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
/*
* BSD setjmp saves the signal mask, which violates ANSI C and takes time,
* so we use _setjmp instead.
*/
#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
#define setjmp(jmploc) _setjmp(jmploc)
#define longjmp(jmploc, val) _longjmp(jmploc, val)
#endif
/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
struct strlist {
struct strlist *next;
char *text;
};
struct arglist {
struct strlist *list;
struct strlist **lastp;
};
/*
* expandarg() flags
*/
#define EXP_FULL 0x1 /* perform word splitting & file globbing */
#define EXP_TILDE 0x2 /* do normal tilde expansion */
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
#define EXP_WORD 0x80 /* expand word in parameter expansion */
#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
union node;
static void expandarg(union node *, struct arglist *, int);
#define rmescapes(p) _rmescapes((p), 0)
static char *_rmescapes(char *, int);
static int casematch(union node *, char *);
#ifdef CONFIG_ASH_MATH_SUPPORT
static void expari(int);
#endif
/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
static char *commandname; /* currently executing command */
static struct strlist *cmdenviron; /* environment for builtin command */
static int exitstatus; /* exit status of last command */
static int back_exitstatus; /* exit status of backquoted command */
struct backcmd { /* result of evalbackcmd */
int fd; /* file descriptor to read from */
char *buf; /* buffer */
int nleft; /* number of chars in buffer */
struct job *jp; /* job structure for command */
};
/*
* This file was generated by the mknodes program.
*/
#define NCMD 0
#define NPIPE 1
#define NREDIR 2
#define NBACKGND 3
#define NSUBSHELL 4
#define NAND 5
#define NOR 6
#define NSEMI 7
#define NIF 8
#define NWHILE 9
#define NUNTIL 10
#define NFOR 11
#define NCASE 12
#define NCLIST 13
#define NDEFUN 14
#define NARG 15
#define NTO 16
#define NCLOBBER 17
#define NFROM 18
#define NFROMTO 19
#define NAPPEND 20
#define NTOFD 21
#define