diff options
181 files changed, 6267 insertions, 26544 deletions
diff --git a/adb/adb_client.c b/adb/adb_client.c index 8340738..f7823a8 100644 --- a/adb/adb_client.c +++ b/adb/adb_client.c @@ -278,7 +278,9 @@ int adb_connect(const char *service) return 0; fd = _adb_connect(service); - if(fd == -2) { + if(fd == -1) { + fprintf(stderr,"error: %s\n", __adb_error); + } else if(fd == -2) { fprintf(stderr,"** daemon still not running\n"); } D("adb_connect: return fd %d\n", fd); diff --git a/adb/commandline.c b/adb/commandline.c index 27a1754..c9bb437 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -767,7 +767,7 @@ static int restore(int argc, char** argv) { fd = adb_connect("restore:"); if (fd < 0) { - fprintf(stderr, "adb: unable to connect for backup\n"); + fprintf(stderr, "adb: unable to connect for restore\n"); adb_close(tarFd); return -1; } diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index 354d0fb..9fec081 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -642,8 +642,8 @@ static int local_build_list(copyinfo **filelist, ci = mkcopyinfo(lpath, rpath, name, 0); if(lstat(ci->src, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno)); + free(ci); closedir(d); - return -1; } if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c index d3e841b..f24f14c 100644 --- a/adb/file_sync_service.c +++ b/adb/file_sync_service.c @@ -110,6 +110,7 @@ static int do_list(int s, const char *path) if(writex(s, &msg.dent, sizeof(msg.dent)) || writex(s, de->d_name, len)) { + closedir(d); return -1; } } diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c index 20c08d2..fa7fd98 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.c @@ -55,13 +55,13 @@ struct fbinfo { void framebuffer_service(int fd, void *cookie) { struct fbinfo fbinfo; - unsigned int i; + unsigned int i, bsize; char buf[640]; int fd_screencap; int w, h, f; int fds[2]; - if (pipe(fds) < 0) goto done; + if (pipe(fds) < 0) goto pipefail; pid_t pid = fork(); if (pid < 0) goto done; @@ -164,17 +164,19 @@ void framebuffer_service(int fd, void *cookie) if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done; /* write data */ - for(i = 0; i < fbinfo.size; i += sizeof(buf)) { - if(readx(fd_screencap, buf, sizeof(buf))) goto done; - if(writex(fd, buf, sizeof(buf))) goto done; + for(i = 0; i < fbinfo.size; i += bsize) { + bsize = sizeof(buf); + if (i + bsize > fbinfo.size) + bsize = fbinfo.size - i; + if(readx(fd_screencap, buf, bsize)) goto done; + if(writex(fd, buf, bsize)) goto done; } - if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done; - if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done; done: TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); close(fds[0]); close(fds[1]); +pipefail: close(fd); } diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index 68bb232..19b3022 100644 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -155,7 +155,10 @@ #define VENDOR_ID_QISDA 0x1D45 // ECS's USB Vendor ID #define VENDOR_ID_ECS 0x03fc - +// MSI's USB Vendor ID +#define VENDOR_ID_MSI 0x0DB0 +// Wacom's USB Vendor ID +#define VENDOR_ID_WACOM 0x0531 /** built-in vendor list */ int builtInVendorIds[] = { @@ -219,6 +222,8 @@ int builtInVendorIds[] = { VENDOR_ID_NOOK, VENDOR_ID_QISDA, VENDOR_ID_ECS, + VENDOR_ID_MSI, + VENDOR_ID_WACOM, }; #define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0])) diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c index 3569e27..7d3740c 100644 --- a/cpio/mkbootfs.c +++ b/cpio/mkbootfs.c @@ -220,6 +220,8 @@ static void _archive_dir(char *in, char *out, int ilen, int olen) free(names[i]); } free(names); + + closedir(d); } static void _archive(char *in, char *out, int ilen, int olen) diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index 8621e9c..2fe7c7a 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -24,11 +24,11 @@ LOCAL_CFLAGS += -DWITH_VFP_D32 endif # ARCH_ARM_HAVE_VFP_D32 LOCAL_SHARED_LIBRARIES := \ + libbacktrace \ + libc \ libcutils \ liblog \ - libc \ - libcorkscrew \ - libselinux + libselinux \ include $(BUILD_EXECUTABLE) diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c index 67e3028..6bcd07e 100644 --- a/debuggerd/arm/machine.c +++ b/debuggerd/arm/machine.c @@ -42,7 +42,7 @@ #endif #endif -static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { +static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */ uintptr_t p, end; @@ -102,7 +102,7 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { p += 4; } *asc_out = '\0'; - _LOG(log, scopeFlags, " %s %s\n", code_buffer, ascii_buffer); + _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer); } } @@ -110,16 +110,13 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { * If configured to do so, dump memory around *all* registers * for the crashing thread. */ -void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid, bool at_fault) { +void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { struct pt_regs regs; if(ptrace(PTRACE_GETREGS, tid, 0, ®s)) { return; } - int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; - - if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) { + if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; for (int reg = 0; reg < 14; reg++) { @@ -134,39 +131,36 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), continue; } - _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); - dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE); + _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); } } /* explicitly allow upload of code dump logging */ - _LOG(log, scopeFlags, "\ncode around pc:\n"); - dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags); + _LOG(log, scope_flags, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scope_flags); if (regs.ARM_pc != regs.ARM_lr) { - _LOG(log, scopeFlags, "\ncode around lr:\n"); - dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scopeFlags); + _LOG(log, scope_flags, "\ncode around lr:\n"); + dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scope_flags); } } -void dump_registers(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid, bool at_fault) +void dump_registers(log_t* log, pid_t tid, int scope_flags) { struct pt_regs r; - int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; - if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, scopeFlags, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n", (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3); - _LOG(log, scopeFlags, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n", (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7); - _LOG(log, scopeFlags, " r8 %08x r9 %08x sl %08x fp %08x\n", + _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n", (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp); - _LOG(log, scopeFlags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr, (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr); @@ -175,14 +169,14 @@ void dump_registers(const ptrace_context_t* context __attribute((unused)), int i; if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) { - _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); return; } for (i = 0; i < NUM_VFP_REGS; i += 2) { - _LOG(log, scopeFlags, " d%-2d %016llx d%-2d %016llx\n", + _LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n", i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]); } - _LOG(log, scopeFlags, " scr %08lx\n", vfp_regs.fpscr); + _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr); #endif } diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c index f42f24c..aa7a3c2 100644 --- a/debuggerd/backtrace.c +++ b/debuggerd/backtrace.c @@ -27,13 +27,11 @@ #include <sys/types.h> #include <sys/ptrace.h> -#include <corkscrew/backtrace.h> +#include <backtrace/backtrace.h> -#include "tombstone.h" +#include "backtrace.h" #include "utility.h" -#define STACK_DEPTH 32 - static void dump_process_header(log_t* log, pid_t pid) { char path[PATH_MAX]; char procnamebuf[1024]; @@ -62,7 +60,7 @@ static void dump_process_footer(log_t* log, pid_t pid) { _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid); } -static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached, +static void dump_thread(log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) { char path[PATH_MAX]; char threadnamebuf[1024]; @@ -91,20 +89,12 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a wait_for_stop(tid, total_sleep_time_usec); - backtrace_frame_t backtrace[STACK_DEPTH]; - ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH); - if (frames <= 0) { - _LOG(log, SCOPE_AT_FAULT, "Could not obtain stack trace for thread.\n"); + backtrace_context_t context; + if (!backtrace_create_context(&context, tid, -1, 0)) { + _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n"); } else { - backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; - get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); - for (size_t i = 0; i < (size_t)frames; i++) { - char line[MAX_BACKTRACE_LINE_LENGTH]; - format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], - line, MAX_BACKTRACE_LINE_LENGTH); - _LOG(log, SCOPE_AT_FAULT, " %s\n", line); - } - free_backtrace_symbols(backtrace_symbols, frames); + dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, " "); + backtrace_destroy_context(&context); } if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { @@ -120,9 +110,8 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, log.amfd = amfd; log.quiet = true; - ptrace_context_t* context = load_ptrace_context(tid); dump_process_header(&log, pid); - dump_thread(&log, tid, context, true, detach_failed, total_sleep_time_usec); + dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec); char task_path[64]; snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); @@ -140,11 +129,19 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, continue; } - dump_thread(&log, new_tid, context, false, detach_failed, total_sleep_time_usec); + dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec); } closedir(d); } dump_process_footer(&log, pid); - free_ptrace_context(context); +} + +void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, + int scope_flags, const char* prefix) { + char buf[512]; + for (size_t i = 0; i < context->backtrace->num_frames; i++) { + backtrace_format_frame_data(context, i, buf, sizeof(buf)); + _LOG(log, scope_flags, "%s%s\n", prefix, buf); + } } diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h index c5c786a..54a60b2 100644 --- a/debuggerd/backtrace.h +++ b/debuggerd/backtrace.h @@ -21,11 +21,17 @@ #include <stdbool.h> #include <sys/types.h> -#include <corkscrew/ptrace.h> +#include <backtrace/backtrace.h> + +#include "utility.h" /* Dumps a backtrace using a format similar to what Dalvik uses so that the result * can be intermixed in a bug report. */ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); +/* Dumps the backtrace in the backtrace data structure to the log. */ +void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, + int scope_flags, const char* prefix); + #endif // _DEBUGGERD_BACKTRACE_H diff --git a/debuggerd/machine.h b/debuggerd/machine.h index 1619dd3..2f1e201 100644 --- a/debuggerd/machine.h +++ b/debuggerd/machine.h @@ -17,15 +17,11 @@ #ifndef _DEBUGGERD_MACHINE_H #define _DEBUGGERD_MACHINE_H -#include <stddef.h> -#include <stdbool.h> #include <sys/types.h> -#include <corkscrew/ptrace.h> - #include "utility.h" -void dump_memory_and_code(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault); -void dump_registers(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault); +void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags); +void dump_registers(log_t* log, pid_t tid, int scope_flags); #endif // _DEBUGGERD_MACHINE_H diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c index 65fdf02..489f3c5 100644 --- a/debuggerd/mips/machine.c +++ b/debuggerd/mips/machine.c @@ -26,7 +26,7 @@ #include <corkscrew/ptrace.h> -#include <linux/user.h> +#include <sys/user.h> #include "../utility.h" #include "../machine.h" @@ -36,7 +36,7 @@ #define R(x) ((unsigned int)(x)) -static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { +static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */ uintptr_t p, end; @@ -92,7 +92,7 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { p += 4; } *asc_out = '\0'; - _LOG(log, scopeFlags, " %s %s\n", code_buffer, ascii_buffer); + _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer); } } @@ -100,15 +100,13 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { * If configured to do so, dump memory around *all* registers * for the crashing thread. */ -void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid, bool at_fault) { +void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { pt_regs_mips_t r; if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { return; } - int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; - if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) { + if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; for (int reg = 0; reg < 32; reg++) { @@ -130,50 +128,47 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), continue; } - _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); - dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE); + _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); } } unsigned int pc = R(r.cp0_epc); unsigned int ra = R(r.regs[31]); - _LOG(log, scopeFlags, "\ncode around pc:\n"); - dump_memory(log, tid, (uintptr_t)pc, scopeFlags); + _LOG(log, scope_flags, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)pc, scope_flags); if (pc != ra) { - _LOG(log, scopeFlags, "\ncode around ra:\n"); - dump_memory(log, tid, (uintptr_t)ra, scopeFlags); + _LOG(log, scope_flags, "\ncode around ra:\n"); + dump_memory(log, tid, (uintptr_t)ra, scope_flags); } } -void dump_registers(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid, bool at_fault) +void dump_registers(log_t* log, pid_t tid, int scope_flags) { pt_regs_mips_t r; - int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; - if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, scopeFlags, " zr %08x at %08x v0 %08x v1 %08x\n", + _LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n", R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3])); - _LOG(log, scopeFlags, " a0 %08x a1 %08x a2 %08x a3 %08x\n", + _LOG(log, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n", R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7])); - _LOG(log, scopeFlags, " t0 %08x t1 %08x t2 %08x t3 %08x\n", + _LOG(log, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n", R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11])); - _LOG(log, scopeFlags, " t4 %08x t5 %08x t6 %08x t7 %08x\n", + _LOG(log, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n", R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15])); - _LOG(log, scopeFlags, " s0 %08x s1 %08x s2 %08x s3 %08x\n", + _LOG(log, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n", R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19])); - _LOG(log, scopeFlags, " s4 %08x s5 %08x s6 %08x s7 %08x\n", + _LOG(log, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n", R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23])); - _LOG(log, scopeFlags, " t8 %08x t9 %08x k0 %08x k1 %08x\n", + _LOG(log, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n", R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27])); - _LOG(log, scopeFlags, " gp %08x sp %08x s8 %08x ra %08x\n", + _LOG(log, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n", R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31])); - _LOG(log, scopeFlags, " hi %08x lo %08x bva %08x epc %08x\n", + _LOG(log, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n", R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc)); } diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c index 7009a8e..aa63547 100644 --- a/debuggerd/tombstone.c +++ b/debuggerd/tombstone.c @@ -32,8 +32,7 @@ #include <log/logger.h> #include <cutils/properties.h> -#include <corkscrew/demangle.h> -#include <corkscrew/backtrace.h> +#include <backtrace/backtrace.h> #include <sys/socket.h> #include <linux/un.h> @@ -42,9 +41,8 @@ #include "machine.h" #include "tombstone.h" -#include "utility.h" +#include "backtrace.h" -#define STACK_DEPTH 32 #define STACK_WORDS 16 #define MAX_TOMBSTONES 10 @@ -193,7 +191,7 @@ static void dump_fault_addr(log_t* log, pid_t tid, int sig) } } -static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) { +static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) { char path[64]; char threadnamebuf[1024]; char* threadname = NULL; @@ -211,7 +209,7 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) { } } - if (at_fault) { + if (IS_AT_FAULT(scope_flags)) { char procnamebuf[1024]; char* procname = NULL; @@ -230,64 +228,46 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) { } } -static void dump_backtrace(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid __attribute((unused)), bool at_fault, - const backtrace_frame_t* backtrace, size_t frames) { - int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; - _LOG(log, scopeFlags, "\nbacktrace:\n"); - - backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; - get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); - for (size_t i = 0; i < frames; i++) { - char line[MAX_BACKTRACE_LINE_LENGTH]; - format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], - line, MAX_BACKTRACE_LINE_LENGTH); - _LOG(log, scopeFlags, " %s\n", line); - } - free_backtrace_symbols(backtrace_symbols, frames); -} - -static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid, - int scopeFlags, uintptr_t* sp, size_t words, int label) { +static void dump_stack_segment(const backtrace_context_t* context, log_t* log, + int scope_flags, uintptr_t *sp, size_t words, int label) { for (size_t i = 0; i < words; i++) { uint32_t stack_content; - if (!try_get_word_ptrace(tid, *sp, &stack_content)) { + if (!backtrace_read_word(context, *sp, &stack_content)) { break; } - const map_info_t* mi; - const symbol_t* symbol; - find_symbol_ptrace(context, stack_content, &mi, &symbol); - - if (symbol) { - char* demangled_name = demangle_symbol_name(symbol->name); - const char* symbol_name = demangled_name ? demangled_name : symbol->name; - uint32_t offset = stack_content - (mi->start + symbol->start); + const char* map_name = backtrace_get_map_name(context, stack_content, NULL); + if (!map_name) { + map_name = ""; + } + uintptr_t offset = 0; + char* func_name = backtrace_get_func_name(context, stack_content, &offset); + if (func_name) { if (!i && label >= 0) { if (offset) { - _LOG(log, scopeFlags, " #%02d %08x %08x %s (%s+%u)\n", - label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset); + _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n", + label, *sp, stack_content, map_name, func_name, offset); } else { - _LOG(log, scopeFlags, " #%02d %08x %08x %s (%s)\n", - label, *sp, stack_content, mi ? mi->name : "", symbol_name); + _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n", + label, *sp, stack_content, map_name, func_name); } } else { if (offset) { - _LOG(log, scopeFlags, " %08x %08x %s (%s+%u)\n", - *sp, stack_content, mi ? mi->name : "", symbol_name, offset); + _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n", + *sp, stack_content, map_name, func_name, offset); } else { - _LOG(log, scopeFlags, " %08x %08x %s (%s)\n", - *sp, stack_content, mi ? mi->name : "", symbol_name); + _LOG(log, scope_flags, " %08x %08x %s (%s)\n", + *sp, stack_content, map_name, func_name); } } - free(demangled_name); + free(func_name); } else { if (!i && label >= 0) { - _LOG(log, scopeFlags, " #%02d %08x %08x %s\n", - label, *sp, stack_content, mi ? mi->name : ""); + _LOG(log, scope_flags, " #%02d %08x %08x %s\n", + label, *sp, stack_content, map_name); } else { - _LOG(log, scopeFlags, " %08x %08x %s\n", - *sp, stack_content, mi ? mi->name : ""); + _LOG(log, scope_flags, " %08x %08x %s\n", + *sp, stack_content, map_name); } } @@ -295,45 +275,43 @@ static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_ } } -static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault, - const backtrace_frame_t* backtrace, size_t frames) { - bool have_first = false; - size_t first, last; - for (size_t i = 0; i < frames; i++) { - if (backtrace[i].stack_top) { - if (!have_first) { - have_first = true; - first = i; +static void dump_stack(const backtrace_context_t* context, log_t* log, int scope_flags) { + const backtrace_t* backtrace = context->backtrace; + size_t first = 0, last; + for (size_t i = 0; i < backtrace->num_frames; i++) { + if (backtrace->frames[i].sp) { + if (!first) { + first = i+1; } last = i; } } - if (!have_first) { + if (!first) { return; } + first--; - int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0); - _LOG(log, scopeFlags, "\nstack:\n"); + scope_flags |= SCOPE_SENSITIVE; // Dump a few words before the first frame. - uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t); - dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, -1); + uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t); + dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, -1); // Dump a few words from all successive frames. // Only log the first 3 frames, put the rest in the tombstone. for (size_t i = first; i <= last; i++) { - const backtrace_frame_t* frame = &backtrace[i]; - if (sp != frame->stack_top) { - _LOG(log, scopeFlags, " ........ ........\n"); - sp = frame->stack_top; + const backtrace_frame_data_t* frame = &backtrace->frames[i]; + if (sp != frame->sp) { + _LOG(log, scope_flags, " ........ ........\n"); + sp = frame->sp; } if (i - first == 3) { - scopeFlags &= (~SCOPE_AT_FAULT); + scope_flags &= (~SCOPE_AT_FAULT); } if (i == last) { - dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, i); - if (sp < frame->stack_top + frame->stack_size) { - _LOG(log, scopeFlags, " ........ ........\n"); + dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, i); + if (sp < frame->sp + frame->stack_size) { + _LOG(log, scope_flags, " ........ ........\n"); } } else { size_t words = frame->stack_size / sizeof(uint32_t); @@ -342,39 +320,40 @@ static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, b } else if (words > STACK_WORDS) { words = STACK_WORDS; } - dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i); + dump_stack_segment(context, log, scope_flags, &sp, words, i); } } } -static void dump_backtrace_and_stack(const ptrace_context_t* context, log_t* log, pid_t tid, - bool at_fault) { - backtrace_frame_t backtrace[STACK_DEPTH]; - ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH); - if (frames > 0) { - dump_backtrace(context, log, tid, at_fault, backtrace, frames); - dump_stack(context, log, tid, at_fault, backtrace, frames); +static void dump_backtrace_and_stack(const backtrace_context_t* context, + log_t* log, int scope_flags) { + if (context->backtrace->num_frames) { + _LOG(log, scope_flags, "\nbacktrace:\n"); + dump_backtrace_to_log(context, log, scope_flags, " "); + + _LOG(log, scope_flags, "\nstack:\n"); + dump_stack(context, log, scope_flags); } } -static void dump_map(log_t* log, map_info_t* m, const char* what, int scopeFlags) { +static void dump_map(log_t* log, const backtrace_map_info_t* m, const char* what, int scope_flags) { if (m != NULL) { - _LOG(log, scopeFlags, " %08x-%08x %c%c%c %s\n", m->start, m->end, + _LOG(log, scope_flags, " %08x-%08x %c%c%c %s\n", m->start, m->end, m->is_readable ? 'r' : '-', m->is_writable ? 'w' : '-', m->is_executable ? 'x' : '-', m->name); } else { - _LOG(log, scopeFlags, " (no %s)\n", what); + _LOG(log, scope_flags, " (no %s)\n", what); } } -static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault) { - int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0); +static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* log, pid_t tid, int scope_flags) { + scope_flags |= SCOPE_SENSITIVE; siginfo_t si; memset(&si, 0, sizeof(si)); if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { - _LOG(log, scopeFlags, "cannot get siginfo for %d: %s\n", + _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno)); return; } @@ -388,15 +367,15 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t return; } - _LOG(log, scopeFlags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr); + _LOG(log, scope_flags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr); /* * Search for a match, or for a hole where the match would be. The list * is backward from the file content, so it starts at high addresses. */ - map_info_t* map = context->map_info_list; - map_info_t *next = NULL; - map_info_t *prev = NULL; + const backtrace_map_info_t* map = map_info_list; + const backtrace_map_info_t* next = NULL; + const backtrace_map_info_t* prev = NULL; while (map != NULL) { if (addr >= map->start && addr < map->end) { next = map->next; @@ -416,31 +395,32 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t * Show "next" then "match" then "prev" so that the addresses appear in * ascending order (like /proc/pid/maps). */ - dump_map(log, next, "map below", scopeFlags); - dump_map(log, map, "map for address", scopeFlags); - dump_map(log, prev, "map above", scopeFlags); + dump_map(log, next, "map below", scope_flags); + dump_map(log, map, "map for address", scope_flags); + dump_map(log, prev, "map above", scope_flags); } -static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault, - int* total_sleep_time_usec) { - wait_for_stop(tid, total_sleep_time_usec); +static void dump_thread(const backtrace_context_t* context, log_t* log, + int scope_flags, int* total_sleep_time_usec) { + const backtrace_t* backtrace = context->backtrace; + wait_for_stop(backtrace->tid, total_sleep_time_usec); - dump_registers(context, log, tid, at_fault); - dump_backtrace_and_stack(context, log, tid, at_fault); - if (at_fault) { - dump_memory_and_code(context, log, tid, at_fault); - dump_nearby_maps(context, log, tid, at_fault); + dump_registers(log, backtrace->tid, scope_flags); + dump_backtrace_and_stack(context, log, scope_flags); + if (IS_AT_FAULT(scope_flags)) { + dump_memory_and_code(log, backtrace->tid, scope_flags); + dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags); } } /* Return true if some thread is not detached cleanly */ -static bool dump_sibling_thread_report(const ptrace_context_t* context, +static bool dump_sibling_thread_report( log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec) { char task_path[64]; snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); DIR* d = opendir(task_path); - /* Bail early if cannot open the task directory */ + /* Bail early if the task directory cannot be opened */ if (d == NULL) { XLOG("Cannot open /proc/%d/task\n", pid); return false; @@ -467,8 +447,12 @@ static bool dump_sibling_thread_report(const ptrace_context_t* context, } _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); - dump_thread_info(log, pid, new_tid, false); - dump_thread(context, log, new_tid, false, total_sleep_time_usec); + dump_thread_info(log, pid, new_tid, 0); + backtrace_context_t new_context; + if (backtrace_create_context(&new_context, pid, new_tid, 0)) { + dump_thread(&new_context, log, 0, total_sleep_time_usec); + backtrace_destroy_context(&new_context); + } if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) { LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno)); @@ -624,7 +608,7 @@ static void dump_logs(log_t* log, pid_t pid, bool tailOnly) dump_log_file(log, pid, "/dev/log/main", tailOnly); } -static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) { +static void dump_abort_message(const backtrace_context_t* context, log_t* log, uintptr_t address) { if (address == 0) { return; } @@ -636,7 +620,7 @@ static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) { char* p = &msg[0]; while (p < &msg[sizeof(msg)]) { uint32_t data; - if (!try_get_word_ptrace(tid, address, &data)) { + if (!backtrace_read_word(context, address, &data)) { break; } address += sizeof(uint32_t); @@ -686,14 +670,17 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); dump_build_info(log); dump_revision_info(log); - dump_thread_info(log, pid, tid, true); + dump_thread_info(log, pid, tid, SCOPE_AT_FAULT); if (signal) { dump_fault_addr(log, tid, signal); } - dump_abort_message(log, tid, abort_msg_address); - ptrace_context_t* context = load_ptrace_context(tid); - dump_thread(context, log, tid, true, total_sleep_time_usec); + backtrace_context_t context; + if (backtrace_create_context(&context, pid, tid, 0)) { + dump_abort_message(&context, log, abort_msg_address); + dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec); + backtrace_destroy_context(&context); + } if (want_logs) { dump_logs(log, pid, true); @@ -701,11 +688,9 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a bool detach_failed = false; if (dump_sibling_threads) { - detach_failed = dump_sibling_thread_report(context, log, pid, tid, total_sleep_time_usec); + detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec); } - free_ptrace_context(context); - if (want_logs) { dump_logs(log, pid, false); } diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c index af79092..db44b11 100644 --- a/debuggerd/x86/machine.c +++ b/debuggerd/x86/machine.c @@ -1,5 +1,4 @@ -/* system/debuggerd/debuggerd.c -** +/* ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,35 +23,24 @@ #include <sys/types.h> #include <sys/ptrace.h> -#include <corkscrew/ptrace.h> - -#include <linux/user.h> - #include "../utility.h" #include "../machine.h" -void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid, bool at_fault) { +void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { } -void dump_registers(const ptrace_context_t* context __attribute((unused)), - log_t* log, pid_t tid, bool at_fault) { - struct pt_regs_x86 r; - int scopeFlags = (at_fault ? SCOPE_AT_FAULT : 0); - - if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); +void dump_registers(log_t* log, pid_t tid, int scope_flags) { + struct pt_regs r; + if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) { + _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); return; } - //if there is no stack, no print just like arm - if(!r.ebp) - return; - _LOG(log, scopeFlags, " eax %08x ebx %08x ecx %08x edx %08x\n", + _LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n", r.eax, r.ebx, r.ecx, r.edx); - _LOG(log, scopeFlags, " esi %08x edi %08x\n", + _LOG(log, scope_flags, " esi %08lx edi %08lx\n", r.esi, r.edi); - _LOG(log, scopeFlags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n", + _LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n", r.xcs, r.xds, r.xes, r.xfs, r.xss); - _LOG(log, scopeFlags, " eip %08x ebp %08x esp %08x flags %08x\n", + _LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n", r.eip, r.ebp, r.esp, r.eflags); } diff --git a/fastboot/Android.mk b/fastboot/Android.mk index 1189e1f..b9b3c92 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -18,9 +18,10 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ $(LOCAL_PATH)/../../extras/ext4_utils -LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c +LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c LOCAL_MODULE := fastboot LOCAL_MODULE_TAGS := debug +LOCAL_CFLAGS += -std=gnu99 ifeq ($(HOST_OS),linux) LOCAL_SRC_FILES += usb_linux.c util_linux.c @@ -69,7 +70,7 @@ $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) -LOCAL_SRC_FILES := usbtest.c usb_linux.c +LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c LOCAL_MODULE := usbtest include $(BUILD_HOST_EXECUTABLE) endif diff --git a/fastboot/engine.c b/fastboot/engine.c index b07e742..972c4ed 100644 --- a/fastboot/engine.c +++ b/fastboot/engine.c @@ -36,7 +36,6 @@ #include <stdbool.h> #include <string.h> #include <sys/stat.h> -#include <sys/time.h> #include <sys/types.h> #include <unistd.h> @@ -48,34 +47,13 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -double now() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; -} - -char *mkmsg(const char *fmt, ...) -{ - char buf[256]; - char *s; - va_list ap; - - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - va_end(ap); - - s = strdup(buf); - if (s == 0) die("out of memory"); - return s; -} - #define OP_DOWNLOAD 1 #define OP_COMMAND 2 #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_FORMAT 5 #define OP_DOWNLOAD_SPARSE 6 +#define OP_WAIT_FOR_DISCONNECT 7 typedef struct Action Action; @@ -573,6 +551,11 @@ void fb_queue_notice(const char *notice) a->data = (void*) notice; } +void fb_queue_wait_for_disconnect(void) +{ + queue_action(OP_WAIT_FOR_DISCONNECT, ""); +} + int fb_execute_queue(usb_handle *usb) { Action *a; @@ -614,6 +597,8 @@ int fb_execute_queue(usb_handle *usb) status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; + } else if (a->op == OP_WAIT_FOR_DISCONNECT) { + usb_wait_for_disconnect(usb); } else { die("bogus action"); } diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index f186c93..73a6e56 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -30,7 +30,6 @@ #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <string.h> @@ -106,17 +105,6 @@ static struct { {"system.img", "system.sig", "system", false}, }; -void die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr,"error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr,"\n"); - va_end(ap); - exit(1); -} - void get_my_path(char *path); char *find_item(const char *item, const char *product) @@ -503,7 +491,13 @@ static int setup_requirement_line(char *name) for(n = 0; n < count; n++) { out[n] = strdup(strip(val[n])); - if (out[n] == 0) return -1; + if (out[n] == 0) { + for(size_t i = 0; i < n; ++i) { + free((char*) out[i]); + } + free(out); + return -1; + } } fb_queue_require(prod, name, invert, n, out); @@ -1102,6 +1096,7 @@ int main(int argc, char **argv) fb_queue_reboot(); } else if (wants_reboot_bootloader) { fb_queue_command("reboot-bootloader", "rebooting into bootloader"); + fb_queue_wait_for_disconnect(); } if (fb_queue_is_empty()) diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index c1b2964..976c397 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -58,10 +58,13 @@ void fb_queue_reboot(void); void fb_queue_command(const char *cmd, const char *msg); void fb_queue_download(const char *name, void *data, unsigned size); void fb_queue_notice(const char *notice); +void fb_queue_wait_for_disconnect(void); int fb_execute_queue(usb_handle *usb); int fb_queue_is_empty(void); /* util stuff */ +double now(); +char *mkmsg(const char *fmt, ...); void die(const char *fmt, ...); /* Current product */ diff --git a/fastboot/usb.h b/fastboot/usb.h index d504ee2..17cf0a9 100644 --- a/fastboot/usb.h +++ b/fastboot/usb.h @@ -62,6 +62,6 @@ usb_handle *usb_open(ifc_match_func callback); int usb_close(usb_handle *h); int usb_read(usb_handle *h, void *_data, int len); int usb_write(usb_handle *h, const void *_data, int len); - +int usb_wait_for_disconnect(usb_handle *h); #endif diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index b7a9ca3..f2ce226 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -50,10 +50,17 @@ #endif #include <asm/byteorder.h> +#include "fastboot.h" #include "usb.h" #define MAX_RETRIES 5 +/* Timeout in seconds for usb_wait_for_disconnect. + * It doesn't usually take long for a device to disconnect (almost always + * under 2 seconds) but we'll time out after 3 seconds just in case. + */ +#define WAIT_FOR_DISCONNECT_TIMEOUT 3 + #ifdef TRACE_USB #define DBG1(x...) fprintf(stderr, x) #define DBG(x...) fprintf(stderr, x) @@ -75,10 +82,18 @@ struct usb_handle unsigned char ep_out; }; +/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices. + * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'. + * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1'). + * The name must also start with a digit, to disallow '.' and '..' + */ static inline int badname(const char *name) { - while(*name) { - if(!isdigit(*name++)) return 1; + if (!isdigit(*name)) + return 1; + while(*++name) { + if(!isdigit(*name) && *name != '.' && *name != '-') + return 1; } return 0; } @@ -95,7 +110,8 @@ static int check(void *_desc, int len, unsigned type, int size) return 0; } -static int filter_usb_device(int fd, char *ptr, int len, int writable, +static int filter_usb_device(char* sysfs_name, + char *ptr, int len, int writable, ifc_match_func callback, int *ept_in_id, int *ept_out_id, int *ifc_id) { @@ -131,69 +147,35 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable, info.dev_protocol = dev->bDeviceProtocol; info.writable = writable; - // read device serial number (if there is one) - info.serial_number[0] = 0; - if (dev->iSerialNumber) { - struct usbdevfs_ctrltransfer ctrl; - // Keep it short enough because some bootloaders are borked if the URB len is > 255 - // 128 is too big by 1. - __u16 buffer[127]; - - memset(buffer, 0, sizeof(buffer)); - - ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; - ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; - ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber; - //language ID (en-us) for serial number string - ctrl.wIndex = 0x0409; - ctrl.wLength = sizeof(buffer); - ctrl.data = buffer; - ctrl.timeout = 50; - - result = ioctl(fd, USBDEVFS_CONTROL, &ctrl); - if (result > 0) { - int i; - // skip first word, and copy the rest to the serial string, changing shorts to bytes. - result /= 2; - for (i = 1; i < result; i++) - info.serial_number[i - 1] = buffer[i]; - info.serial_number[i - 1] = 0; - } - } + snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name); - /* We need to get a path that represents a particular port on a particular - * hub. We are passed an fd that was obtained by opening an entry under - * /dev/bus/usb. Unfortunately, the names of those entries change each - * time devices are plugged and unplugged. So how to get a repeatable - * path? udevadm provided the inspiration. We can get the major and - * minor of the device file, read the symlink that can be found here: - * /sys/dev/char/<major>:<minor> - * and then use the last element of that path. As a concrete example, I - * have an Android device at /dev/bus/usb/001/027 so working with bash: - * $ ls -l /dev/bus/usb/001/027 - * crw-rw-r-- 1 root plugdev 189, 26 Apr 9 11:03 /dev/bus/usb/001/027 - * $ ls -l /sys/dev/char/189:26 - * lrwxrwxrwx 1 root root 0 Apr 9 11:03 /sys/dev/char/189:26 -> - * ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3 - * So our device_path would be 1-4.2.3 which says my device is connected - * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per - * http://www.linux-usb.org/FAQ.html). + /* Read device serial number (if there is one). + * We read the serial number from sysfs, since it's faster and more + * reliable than issuing a control pipe read, and also won't + * cause problems for devices which don't like getting descriptor + * requests while they're in the middle of flashing. */ - info.device_path[0] = '\0'; - result = fstat(fd, &st); - if (!result && S_ISCHR(st.st_mode)) { - char cdev[128]; - char link[256]; - char *slash; - ssize_t link_len; - snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d", - major(st.st_rdev), minor(st.st_rdev)); - link_len = readlink(cdev, link, sizeof(link) - 1); - if (link_len > 0) { - link[link_len] = '\0'; - slash = strrchr(link, '/'); - if (slash) - snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1); + info.serial_number[0] = '\0'; + if (dev->iSerialNumber) { + char path[80]; + int fd; + + snprintf(path, sizeof(path), + "/sys/bus/usb/devices/%s/serial", sysfs_name); + path[sizeof(path) - 1] = '\0'; + + fd = open(path, O_RDONLY); + if (fd >= 0) { + int chars_read = read(fd, info.serial_number, + sizeof(info.serial_number) - 1); + close(fd); + + if (chars_read <= 0) + info.serial_number[0] = '\0'; + else if (info.serial_number[chars_read - 1] == '\n') { + // strip trailing newline + info.serial_number[chars_read - 1] = '\0'; + } } } @@ -241,14 +223,73 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable, return -1; } +static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node, + char* buf, int bufsize) +{ + char path[80]; + int fd, n; + + snprintf(path, sizeof(path), + "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node); + path[sizeof(path) - 1] = '\0'; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + n = read(fd, buf, bufsize - 1); + close(fd); + + if (n < 0) + return -1; + + buf[n] = '\0'; + + return n; +} + +static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node) +{ + char buf[16]; + int value; + + if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0) + return -1; + + if (sscanf(buf, "%d", &value) != 1) + return -1; + + return value; +} + +/* Given the name of a USB device in sysfs, get the name for the same + * device in devfs. Returns 0 for success, -1 for failure. + */ +static int convert_to_devfs_name(const char* sysfs_name, + char* devname, int devname_size) +{ + int busnum, devnum; + + busnum = read_sysfs_number(sysfs_name, "busnum"); + if (busnum < 0) + return -1; + + devnum = read_sysfs_number(sysfs_name, "devnum"); + if (devnum < 0) + return -1; + + snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum); + return 0; +} + static usb_handle *find_usb_device(const char *base, ifc_match_func callback) { usb_handle *usb = 0; - char busname[64], devname[64]; + char devname[64]; char desc[1024]; int n, in, out, ifc; - DIR *busdir, *devdir; + DIR *busdir; struct dirent *de; int fd; int writable; @@ -259,15 +300,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback) while((de = readdir(busdir)) && (usb == 0)) { if(badname(de->d_name)) continue; - sprintf(busname, "%s/%s", base, de->d_name); - devdir = opendir(busname); - if(devdir == 0) continue; - -// DBG("[ scanning %s ]\n", busname); - while((de = readdir(devdir)) && (usb == 0)) { - - if(badname(de->d_name)) continue; - sprintf(devname, "%s/%s", busname, de->d_name); + if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) { // DBG("[ scanning %s ]\n", devname); writable = 1; @@ -282,7 +315,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback) n = read(fd, desc, sizeof(desc)); - if(filter_usb_device(fd, desc, n, writable, callback, + if(filter_usb_device(de->d_name, desc, n, writable, callback, &in, &out, &ifc) == 0) { usb = calloc(1, sizeof(usb_handle)); strcpy(usb->fname, devname); @@ -301,7 +334,6 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback) close(fd); } } - closedir(devdir); } closedir(busdir); @@ -315,26 +347,11 @@ int usb_write(usb_handle *h, const void *_data, int len) struct usbdevfs_bulktransfer bulk; int n; - if(h->ep_out == 0) { + if(h->ep_out == 0 || h->desc == -1) { return -1; } - if(len == 0) { - bulk.ep = h->ep_out; - bulk.len = 0; - bulk.data = data; - bulk.timeout = 0; - - n = ioctl(h->desc, USBDEVFS_BULK, &bulk); - if(n != 0) { - fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); - return -1; - } - return 0; - } - - while(len > 0) { + do { int xfer; xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; @@ -353,7 +370,7 @@ int usb_write(usb_handle *h, const void *_data, int len) count += xfer; len -= xfer; data += xfer; - } + } while(len > 0); return count; } @@ -365,7 +382,7 @@ int usb_read(usb_handle *h, void *_data, int len) struct usbdevfs_bulktransfer bulk; int n, retry; - if(h->ep_in == 0) { + if(h->ep_in == 0 || h->desc == -1) { return -1; } @@ -431,5 +448,20 @@ int usb_close(usb_handle *h) usb_handle *usb_open(ifc_match_func callback) { - return find_usb_device("/dev/bus/usb", callback); + return find_usb_device("/sys/bus/usb/devices", callback); +} + +/* Wait for the system to notice the device is gone, so that a subsequent + * fastboot command won't try to access the device before it's rebooted. + * Returns 0 for success, -1 for timeout. + */ +int usb_wait_for_disconnect(usb_handle *usb) +{ + double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT; + while (now() < deadline) { + if (access(usb->fname, F_OK)) + return 0; + usleep(50000); + } + return -1; } diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c index 1548ba8..0f55e0d 100644 --- a/fastboot/usb_osx.c +++ b/fastboot/usb_osx.c @@ -467,6 +467,11 @@ int usb_close(usb_handle *h) { return 0; } +int usb_wait_for_disconnect(usb_handle *usb) { + /* TODO: Punt for now */ + return 0; +} + int usb_read(usb_handle *h, void *data, int len) { IOReturn result; UInt32 numBytes = len; diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c index 7aa36b2..07f7be2 100644 --- a/fastboot/usb_windows.c +++ b/fastboot/usb_windows.c @@ -269,6 +269,11 @@ int usb_close(usb_handle* handle) { return 0; } +int usb_wait_for_disconnect(usb_handle *usb) { + /* TODO: Punt for now */ + return 0; +} + int recognized_device(usb_handle* handle, ifc_match_func callback) { struct usb_ifc_info info; USB_DEVICE_DESCRIPTOR device_desc; diff --git a/fastboot/util.c b/fastboot/util.c new file mode 100644 index 0000000..f2bbd34 --- /dev/null +++ b/fastboot/util.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/time.h> + +#include "fastboot.h" + +double now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; +} + +char *mkmsg(const char *fmt, ...) +{ + char buf[256]; + char *s; + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + s = strdup(buf); + if (s == 0) die("out of memory"); + return s; +} + +void die(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr,"error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr,"\n"); + va_end(ap); + exit(1); +} diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index f432f6a..13b71ee 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -238,74 +238,16 @@ out: return f; } -/* Read a line of text till the next newline character. - * If no newline is found before the buffer is full, continue reading till a new line is seen, - * then return an empty buffer. This effectively ignores lines that are too long. - * On EOF, return null. - */ -static char *fs_getline(char *buf, int size, FILE *file) -{ - int cnt = 0; - int eof = 0; - int eol = 0; - int c; - - if (size < 1) { - return NULL; - } - - while (cnt < (size - 1)) { - c = getc(file); - if (c == EOF) { - eof = 1; - break; - } - - *(buf + cnt) = c; - cnt++; - - if (c == '\n') { - eol = 1; - break; - } - } - - /* Null terminate what we've read */ - *(buf + cnt) = '\0'; - - if (eof) { - if (cnt) { - return buf; - } else { - return NULL; - } - } else if (eol) { - return buf; - } else { - /* The line is too long. Read till a newline or EOF. - * If EOF, return null, if newline, return an empty buffer. - */ - while(1) { - c = getc(file); - if (c == EOF) { - return NULL; - } else if (c == '\n') { - *buf = '\0'; - return buf; - } - } - } -} - struct fstab *fs_mgr_read_fstab(const char *fstab_path) { FILE *fstab_file; int cnt, entries; - int len; - char line[256]; + ssize_t len; + size_t alloc_len = 0; + char *line = NULL; const char *delim = " \t"; char *save_ptr, *p; - struct fstab *fstab; + struct fstab *fstab = NULL; struct fstab_rec *recs; struct fs_mgr_flag_values flag_vals; #define FS_OPTIONS_LEN 1024 @@ -318,9 +260,8 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) } entries = 0; - while (fs_getline(line, sizeof(line), fstab_file)) { + while ((len = getline(&line, &alloc_len, fstab_file)) != -1) { /* if the last character is a newline, shorten the string by 1 byte */ - len = strlen(line); if (line[len - 1] == '\n') { line[len - 1] = '\0'; } @@ -337,7 +278,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) if (!entries) { ERROR("No entries found in fstab\n"); - return 0; + goto err; } /* Allocate and init the fstab structure */ @@ -349,9 +290,8 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) fseek(fstab_file, 0, SEEK_SET); cnt = 0; - while (fs_getline(line, sizeof(line), fstab_file)) { + while ((len = getline(&line, &alloc_len, fstab_file)) != -1) { /* if the last character is a newline, shorten the string by 1 byte */ - len = strlen(line); if (line[len - 1] == '\n') { line[len - 1] = '\0'; } @@ -376,25 +316,25 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) if (!(p = strtok_r(line, delim, &save_ptr))) { ERROR("Error parsing mount source\n"); - return 0; + goto err; } fstab->recs[cnt].blk_device = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_point\n"); - return 0; + goto err; } fstab->recs[cnt].mount_point = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_type\n"); - return 0; + goto err; } fstab->recs[cnt].fs_type = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_flags\n"); - return 0; + goto err; } tmp_fs_options[0] = '\0'; fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL, @@ -409,7 +349,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_mgr_options\n"); - return 0; + goto err; } fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0); @@ -422,8 +362,15 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) cnt++; } fclose(fstab_file); - + free(line); return fstab; + +err: + fclose(fstab_file); + free(line); + if (fstab) + fs_mgr_free_fstab(fstab); + return NULL; } void fs_mgr_free_fstab(struct fstab *fstab) @@ -442,7 +389,6 @@ void fs_mgr_free_fstab(struct fstab *fstab) free(fstab->recs[i].fs_options); free(fstab->recs[i].key_loc); free(fstab->recs[i].label); - i++; } /* Free the fstab_recs array created by calloc(3) */ diff --git a/gpttool/gpttool.c b/gpttool/gpttool.c index 05d5177..d3f08fe 100644 --- a/gpttool/gpttool.c +++ b/gpttool/gpttool.c @@ -161,7 +161,7 @@ void show(struct ptable *ptbl) { struct efi_entry *entry = ptbl->entry; unsigned n, m; - char name[EFI_NAMELEN]; + char name[EFI_NAMELEN + 1]; fprintf(stderr,"ptn start block end block name\n"); fprintf(stderr,"---- ------------- ------------- --------------------\n"); diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h new file mode 100644 index 0000000..b15678c --- /dev/null +++ b/include/backtrace/Backtrace.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BACKTRACE_BACKTRACE_H +#define _BACKTRACE_BACKTRACE_H + +#include <backtrace/backtrace.h> + +#include <string> + +class BacktraceImpl; + +class Backtrace { +public: + // Create the correct Backtrace object based on what is to be unwound. + // If pid < 0 or equals the current pid, then the Backtrace object + // corresponds to the current process. + // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace + // object corresponds to a thread in the current process. + // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a + // different process. + // Tracing a thread in a different process is not supported. + static Backtrace* Create(pid_t pid, pid_t tid); + + virtual ~Backtrace(); + + // Get the current stack trace and store in the backtrace_ structure. + virtual bool Unwind(size_t num_ignore_frames); + + // Get the function name and offset into the function given the pc. + // If the string is empty, then no valid function name was found. + virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset); + + // Get the name of the map associated with the given pc. If NULL is returned, + // then map_start is not set. Otherwise, map_start is the beginning of this + // map. + virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start); + + // Finds the memory map associated with the given ptr. + virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr); + + // Read the data at a specific address. + virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0; + + // Create a string representing the formatted line of backtrace information + // for a single frame. + virtual std::string FormatFrameData(size_t frame_num); + + pid_t Pid() { return backtrace_.pid; } + pid_t Tid() { return backtrace_.tid; } + size_t NumFrames() { return backtrace_.num_frames; } + + const backtrace_t* GetBacktrace() { return &backtrace_; } + + const backtrace_frame_data_t* GetFrame(size_t frame_num) { + return &backtrace_.frames[frame_num]; + } + +protected: + Backtrace(BacktraceImpl* impl); + + virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value); + + BacktraceImpl* impl_; + + backtrace_map_info_t* map_info_; + + backtrace_t backtrace_; + + friend class BacktraceImpl; +}; + +#endif // _BACKTRACE_BACKTRACE_H diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h new file mode 100644 index 0000000..8a45690 --- /dev/null +++ b/include/backtrace/backtrace.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BACKTRACE_H +#define _BACKTRACE_H + +#include <stdint.h> +#include <stdbool.h> +#include <sys/types.h> + +__BEGIN_DECLS + +// When the pid to be traced is set to this value, then trace the current +// process. If the tid value is not BACKTRACE_NO_TID, then the specified +// thread from the current process will be traced. +#define BACKTRACE_CURRENT_PROCESS -1 +// When the tid to be traced is set to this value, then trace the specified +// pid. +#define BACKTRACE_NO_TID -1 + +#define MAX_BACKTRACE_FRAMES 64 + +typedef struct backtrace_map_info { + struct backtrace_map_info* next; + uintptr_t start; + uintptr_t end; + bool is_readable; + bool is_writable; + bool is_executable; + char name[]; +} backtrace_map_info_t; + +typedef struct { + uintptr_t pc; /* The absolute pc. */ + uintptr_t sp; /* The top of the stack. */ + size_t stack_size; /* The size of the stack, zero indicate an unknown stack size. */ + const char* map_name; /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */ + uintptr_t map_offset; /* pc relative to the start of the map, only valid if map_name is not NULL. */ + char* func_name; /* The function name associated with this pc, NULL if not found. */ + uintptr_t func_offset; /* pc relative to the start of the function, only valid if func_name is not NULL. */ +} backtrace_frame_data_t; + +typedef struct { + backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES]; + size_t num_frames; + + pid_t pid; + pid_t tid; + backtrace_map_info_t* map_info_list; +} backtrace_t; + +typedef struct { + void* data; + const backtrace_t* backtrace; +} backtrace_context_t; + +/* Create a context for the backtrace data and gather the backtrace. + * If pid < 0, then gather the backtrace for the current process. + */ +bool backtrace_create_context( + backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames); + +/* Gather the backtrace data for a pthread instead of a process. */ +bool backtrace_create_thread_context( + backtrace_context_t* context, pid_t tid, size_t num_ignore_frames); + +/* Free any memory allocated during the context create. */ +void backtrace_destroy_context(backtrace_context_t* context); + +/* Read data at a specific address for a process. */ +bool backtrace_read_word( + const backtrace_context_t* context, uintptr_t ptr, uint32_t* value); + +/* Get information about the map name associated with a pc. If NULL is + * returned, then map_start is not set. + */ +const char* backtrace_get_map_name( + const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start); + +/* Get the function name and offset given the pc. If NULL is returned, + * then func_offset is not set. The returned string is allocated using + * malloc and must be freed by the caller. + */ +char* backtrace_get_func_name( + const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset); + +/* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory + * map for the current process. + */ +backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid); + +/* Frees memory associated with the map list. */ +void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list); + +/* Finds the memory map that contains the specified pc. */ +const backtrace_map_info_t* backtrace_find_map_info( + const backtrace_map_info_t* map_info_list, uintptr_t pc); + +/* Create a formatted line of backtrace information for a single frame. */ +void backtrace_format_frame_data( + const backtrace_context_t* context, size_t frame_num, char* buf, + size_t buf_size); + +/* Get the backtrace data structure associated with the context. */ +const backtrace_t* backtrace_get_data(backtrace_context_t* context); + +__END_DECLS + +#endif /* _BACKTRACE_H */ diff --git a/include/cutils/list.h b/include/cutils/list.h index 3881fc9..72395f4 100644 --- a/include/cutils/list.h +++ b/include/cutils/list.h @@ -44,6 +44,11 @@ struct listnode #define list_for_each_reverse(node, list) \ for (node = (list)->prev; node != (list); node = node->prev) +#define list_for_each_safe(node, next, list) \ + for (node = (list)->next, next = node->next; \ + node != (list); \ + node = next, next = node->next) + void list_init(struct listnode *list); void list_add_tail(struct listnode *list, struct listnode *item); void list_remove(struct listnode *item); diff --git a/include/ion/ion.h b/include/ion/ion.h index 018c0a1..fbd34e2 100644 --- a/include/ion/ion.h +++ b/include/ion/ion.h @@ -25,6 +25,8 @@ __BEGIN_DECLS +struct ion_handle; + int ion_open(); int ion_close(int fd); int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, diff --git a/include/mincrypt/dsa_sig.h b/include/mincrypt/dsa_sig.h new file mode 100644 index 0000000..b0d91cd --- /dev/null +++ b/include/mincrypt/dsa_sig.h @@ -0,0 +1,43 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ + +#include "mincrypt/p256.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns 0 if input sig is not a valid ASN.1 sequence +int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int); + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */ diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h index 96806f7..c813b44 100644 --- a/include/mincrypt/hash-internal.h +++ b/include/mincrypt/hash-internal.h @@ -1,8 +1,31 @@ -// Copyright 2007 Google Inc. All Rights Reserved. -// Author: mschilder@google.com (Marius Schilder) - -#ifndef SECURITY_UTIL_LITE_HASH_INTERNAL_H__ -#define SECURITY_UTIL_LITE_HASH_INTERNAL_H__ +/* + * Copyright 2007 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ #include <stdint.h> @@ -37,4 +60,4 @@ typedef struct HASH_CTX { } #endif // __cplusplus -#endif // SECURITY_UTIL_LITE_HASH_INTERNAL_H__ +#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ diff --git a/include/mincrypt/p256.h b/include/mincrypt/p256.h new file mode 100644 index 0000000..465a1b9 --- /dev/null +++ b/include/mincrypt/p256.h @@ -0,0 +1,162 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ + +// Collection of routines manipulating 256 bit unsigned integers. +// Just enough to implement ecdsa-p256 and related algorithms. + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define P256_BITSPERDIGIT 32 +#define P256_NDIGITS 8 +#define P256_NBYTES 32 + +typedef int p256_err; +typedef uint32_t p256_digit; +typedef int32_t p256_sdigit; +typedef uint64_t p256_ddigit; +typedef int64_t p256_sddigit; + +// Defining p256_int as struct to leverage struct assigment. +typedef struct { + p256_digit a[P256_NDIGITS]; +} p256_int; + +extern const p256_int SECP256r1_n; // Curve order +extern const p256_int SECP256r1_p; // Curve prime +extern const p256_int SECP256r1_b; // Curve param + +// Initialize a p256_int to zero. +void p256_init(p256_int* a); + +// Clear a p256_int to zero. +void p256_clear(p256_int* a); + +// Return bit. Index 0 is least significant. +int p256_get_bit(const p256_int* a, int index); + +// b := a % MOD +void p256_mod( + const p256_int* MOD, + const p256_int* a, + p256_int* b); + +// c := a * (top_b | b) % MOD +void p256_modmul( + const p256_int* MOD, + const p256_int* a, + const p256_digit top_b, + const p256_int* b, + p256_int* c); + +// b := 1 / a % MOD +// MOD best be SECP256r1_n +void p256_modinv( + const p256_int* MOD, + const p256_int* a, + p256_int* b); + +// b := 1 / a % MOD +// MOD best be SECP256r1_n +// Faster than p256_modinv() +void p256_modinv_vartime( + const p256_int* MOD, + const p256_int* a, + p256_int* b); + +// b := a << (n % P256_BITSPERDIGIT) +// Returns the bits shifted out of most significant digit. +p256_digit p256_shl(const p256_int* a, int n, p256_int* b); + +// b := a >> (n % P256_BITSPERDIGIT) +void p256_shr(const p256_int* a, int n, p256_int* b); + +int p256_is_zero(const p256_int* a); +int p256_is_odd(const p256_int* a); +int p256_is_even(const p256_int* a); + +// Returns -1, 0 or 1. +int p256_cmp(const p256_int* a, const p256_int *b); + +// c: = a - b +// Returns -1 on borrow. +int p256_sub(const p256_int* a, const p256_int* b, p256_int* c); + +// c := a + b +// Returns 1 on carry. +int p256_add(const p256_int* a, const p256_int* b, p256_int* c); + +// c := a + (single digit)b +// Returns carry 1 on carry. +int p256_add_d(const p256_int* a, p256_digit b, p256_int* c); + +// ec routines. + +// {out_x,out_y} := nG +void p256_base_point_mul(const p256_int *n, + p256_int *out_x, + p256_int *out_y); + +// {out_x,out_y} := n{in_x,in_y} +void p256_point_mul(const p256_int *n, + const p256_int *in_x, + const p256_int *in_y, + p256_int *out_x, + p256_int *out_y); + +// {out_x,out_y} := n1G + n2{in_x,in_y} +void p256_points_mul_vartime( + const p256_int *n1, const p256_int *n2, + const p256_int *in_x, const p256_int *in_y, + p256_int *out_x, p256_int *out_y); + +// Return whether point {x,y} is on curve. +int p256_is_valid_point(const p256_int* x, const p256_int* y); + +// Outputs big-endian binary form. No leading zero skips. +void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]); + +// Reads from big-endian binary form, +// thus pre-pad with leading zeros if short. +void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst); + +#define P256_DIGITS(x) ((x)->a) +#define P256_DIGIT(x,y) ((x)->a[y]) + +#define P256_ZERO {{0}} +#define P256_ONE {{1}} + +#ifdef __cplusplus +} +#endif + +#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ diff --git a/include/mincrypt/p256_ecdsa.h b/include/mincrypt/p256_ecdsa.h new file mode 100644 index 0000000..da339fa --- /dev/null +++ b/include/mincrypt/p256_ecdsa.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ + +// Using current directory as relative include path here since +// this code typically gets lifted into a variety of build systems +// and directory structures. +#include "p256.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns 0 if {r,s} is not a signature on message for +// public key {key_x,key_y}. +// +// Note: message is a p256_int. +// Convert from a binary string using p256_from_bin(). +int p256_ecdsa_verify(const p256_int* key_x, + const p256_int* key_y, + const p256_int* message, + const p256_int* r, const p256_int* s); + +#ifdef __cplusplus +} +#endif + +#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h index cc0e800..3d0556b 100644 --- a/include/mincrypt/rsa.h +++ b/include/mincrypt/rsa.h @@ -25,8 +25,8 @@ ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _EMBEDDED_RSA_H_ -#define _EMBEDDED_RSA_H_ +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ #include <inttypes.h> @@ -55,4 +55,4 @@ int RSA_verify(const RSAPublicKey *key, } #endif -#endif +#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h index 120ddcb..ef60aab 100644 --- a/include/mincrypt/sha.h +++ b/include/mincrypt/sha.h @@ -1,8 +1,30 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// Author: mschilder@google.com (Marius Schilder) - -#ifndef SECURITY_UTIL_LITE_SHA1_H__ -#define SECURITY_UTIL_LITE_SHA1_H__ +/* + * Copyright 2005 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ #include <stdint.h> #include "hash-internal.h" @@ -27,4 +49,4 @@ const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest); } #endif // __cplusplus -#endif // SECURITY_UTIL_LITE_SHA1_H__ +#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h index 0f3efb7..3a87c31 100644 --- a/include/mincrypt/sha256.h +++ b/include/mincrypt/sha256.h @@ -1,8 +1,31 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// Author: mschilder@google.com (Marius Schilder) - -#ifndef SECURITY_UTIL_LITE_SHA256_H__ -#define SECURITY_UTIL_LITE_SHA256_H__ +/* + * Copyright 2011 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ +#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ #include <stdint.h> #include "hash-internal.h" @@ -26,4 +49,4 @@ const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest); } #endif // __cplusplus -#endif // SECURITY_UTIL_LITE_SHA256_H__ +#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h index f3501cf..c0a9418 100644 --- a/include/sysutils/NetlinkEvent.h +++ b/include/sysutils/NetlinkEvent.h @@ -36,6 +36,7 @@ public: const static int NlActionLinkUp; const static int NlActionAddressUpdated; const static int NlActionAddressRemoved; + const static int NlActionRdnss; NetlinkEvent(); virtual ~NetlinkEvent(); @@ -49,9 +50,10 @@ public: void dump(); protected: - bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize); bool parseBinaryNetlinkMessage(char *buffer, int size); bool parseAsciiNetlinkMessage(char *buffer, int size); + bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize); + bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize); }; #endif diff --git a/init/Android.mk b/init/Android.mk index abfc68a..1f43ba6 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -10,7 +10,6 @@ LOCAL_SRC_FILES:= \ property_service.c \ util.c \ parser.c \ - logo.c \ keychords.c \ signal_handler.c \ init_parser.c \ diff --git a/init/builtins.c b/init/builtins.c index e8c8f91..e2932d5 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -797,12 +797,24 @@ int do_chmod(int nargs, char **args) { int do_restorecon(int nargs, char **args) { int i; + int ret = 0; for (i = 1; i < nargs; i++) { if (restorecon(args[i]) < 0) - return -errno; + ret = -errno; } - return 0; + return ret; +} + +int do_restorecon_recursive(int nargs, char **args) { + int i; + int ret = 0; + + for (i = 1; i < nargs; i++) { + if (restorecon_recursive(args[i]) < 0) + ret = -errno; + } + return ret; } int do_setsebool(int nargs, char **args) { diff --git a/init/devices.c b/init/devices.c index 1893642..af88c5f 100644 --- a/init/devices.c +++ b/init/devices.c @@ -33,6 +33,7 @@ #include <selinux/selinux.h> #include <selinux/label.h> #include <selinux/android.h> +#include <selinux/avc.h> #include <private/android_filesystem_config.h> #include <sys/time.h> @@ -830,6 +831,15 @@ void handle_device_fd() struct uevent uevent; parse_event(msg, &uevent); + if (sehandle && selinux_status_updated() > 0) { + struct selabel_handle *sehandle2; + sehandle2 = selinux_android_file_context_handle(); + if (sehandle2) { + selabel_close(sehandle); + sehandle = sehandle2; + } + } + handle_device_event(&uevent); handle_firmware_event(&uevent); } @@ -896,6 +906,7 @@ void device_init(void) sehandle = NULL; if (is_selinux_enabled() > 0) { sehandle = selinux_android_file_context_handle(); + selinux_status_open(true); } /* is 256K enough? udev uses 16MB! */ diff --git a/init/init.c b/init/init.c index 94a2011..864fc6c 100644 --- a/init/init.c +++ b/init/init.c @@ -250,14 +250,12 @@ void service_start(struct service *svc, const char *dynamic_args) for (ei = svc->envvars; ei; ei = ei->next) add_environment(ei->name, ei->value); - setsockcreatecon(scon); - for (si = svc->sockets; si; si = si->next) { int socket_type = ( !strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET)); int s = create_socket(si->name, socket_type, - si->perm, si->uid, si->gid); + si->perm, si->uid, si->gid, si->socketcon ?: scon); if (s >= 0) { publish_socket(si->name, s); } @@ -265,7 +263,6 @@ void service_start(struct service *svc, const char *dynamic_args) freecon(scon); scon = NULL; - setsockcreatecon(NULL); if (svc->ioprio_class != IoSchedClass_NONE) { if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) { @@ -657,29 +654,28 @@ static int console_init_action(int nargs, char **args) have_console = 1; close(fd); - if( load_565rle_image(INIT_IMAGE_FILE) ) { - fd = open("/dev/tty0", O_WRONLY); - if (fd >= 0) { - const char *msg; - msg = "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" // console is 40 cols x 30 lines - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - " A N D R O I D "; - write(fd, msg, strlen(msg)); - close(fd); - } + fd = open("/dev/tty0", O_WRONLY); + if (fd >= 0) { + const char *msg; + msg = "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" // console is 40 cols x 30 lines + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + " A N D R O I D "; + write(fd, msg, strlen(msg)); + close(fd); } + return 0; } diff --git a/init/init.h b/init/init.h index aa6a4ab..736b75b 100644 --- a/init/init.h +++ b/init/init.h @@ -55,6 +55,7 @@ struct socketinfo { uid_t uid; gid_t gid; int perm; + const char *socketcon; }; struct svcenvinfo { @@ -132,10 +133,6 @@ void service_restart(struct service *svc); void service_start(struct service *svc, const char *dynamic_args); void property_changed(const char *name, const char *value); -#define INIT_IMAGE_FILE "/initlogo.rle" - -int load_565rle_image( char *file_name ); - extern struct selabel_handle *sehandle; extern struct selabel_handle *sehandle_prop; extern int selinux_reload_policy(void); diff --git a/init/init_parser.c b/init/init_parser.c index 776c699..3f0838f 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -135,6 +135,7 @@ int lookup_keyword(const char *s) case 'r': if (!strcmp(s, "estart")) return K_restart; if (!strcmp(s, "estorecon")) return K_restorecon; + if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive; if (!strcmp(s, "mdir")) return K_rmdir; if (!strcmp(s, "m")) return K_rm; break; @@ -552,12 +553,14 @@ void queue_all_property_triggers() if (length > PROP_NAME_MAX) { ERROR("property name too long in trigger %s", act->name); } else { + int ret; memcpy(prop_name, name, length); prop_name[length] = 0; /* does the property exist, and match the trigger value? */ - property_get(prop_name, value); - if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) { + ret = property_get(prop_name, value); + if (ret > 0 && (!strcmp(equals + 1, value) || + !strcmp(equals + 1, "*"))) { action_add_queue_tail(act); } } @@ -771,7 +774,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args svc->envvars = ei; break; } - case K_socket: {/* name type perm [ uid gid ] */ + case K_socket: {/* name type perm [ uid gid context ] */ struct socketinfo *si; if (nargs < 4) { parse_error(state, "socket option requires name, type, perm arguments\n"); @@ -794,6 +797,8 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args si->uid = decode_uid(args[4]); if (nargs > 5) si->gid = decode_uid(args[5]); + if (nargs > 6) + si->socketcon = args[6]; si->next = svc->sockets; svc->sockets = si; break; diff --git a/init/keywords.h b/init/keywords.h index 5a44df3..97fe50c 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -17,6 +17,7 @@ int do_mount(int nargs, char **args); int do_powerctl(int nargs, char **args); int do_restart(int nargs, char **args); int do_restorecon(int nargs, char **args); +int do_restorecon_recursive(int nargs, char **args); int do_rm(int nargs, char **args); int do_rmdir(int nargs, char **args); int do_setcon(int nargs, char **args); @@ -71,6 +72,7 @@ enum { KEYWORD(powerctl, COMMAND, 1, do_powerctl) KEYWORD(restart, COMMAND, 1, do_restart) KEYWORD(restorecon, COMMAND, 1, do_restorecon) + KEYWORD(restorecon_recursive, COMMAND, 1, do_restorecon_recursive) KEYWORD(rm, COMMAND, 1, do_rm) KEYWORD(rmdir, COMMAND, 1, do_rmdir) KEYWORD(seclabel, OPTION, 0, 0) diff --git a/init/logo.c b/init/logo.c deleted file mode 100644 index 614224c..0000000 --- a/init/logo.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <linux/fb.h> -#include <linux/kd.h> - -#include "log.h" - -#ifdef ANDROID -#include <cutils/memory.h> -#else -void android_memset16(void *_ptr, unsigned short val, unsigned count) -{ - unsigned short *ptr = _ptr; - count >>= 1; - while(count--) - *ptr++ = val; -} -#endif - -struct FB { - unsigned short *bits; - unsigned size; - int fd; - struct fb_fix_screeninfo fi; - struct fb_var_screeninfo vi; -}; - -#define fb_width(fb) ((fb)->vi.xres) -#define fb_height(fb) ((fb)->vi.yres) -#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2) - -static int fb_open(struct FB *fb) -{ - fb->fd = open("/dev/graphics/fb0", O_RDWR); - if (fb->fd < 0) - return -1; - - if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) - goto fail; - if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) - goto fail; - - fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, - MAP_SHARED, fb->fd, 0); - if (fb->bits == MAP_FAILED) - goto fail; - - return 0; - -fail: - close(fb->fd); - return -1; -} - -static void fb_close(struct FB *fb) -{ - munmap(fb->bits, fb_size(fb)); - close(fb->fd); -} - -/* there's got to be a more portable way to do this ... */ -static void fb_update(struct FB *fb) -{ - fb->vi.yoffset = 1; - ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); - fb->vi.yoffset = 0; - ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); -} - -static int vt_set_mode(int graphics) -{ - int fd, r; - fd = open("/dev/tty0", O_RDWR | O_SYNC); - if (fd < 0) - return -1; - r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT)); - close(fd); - return r; -} - -/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ - -int load_565rle_image(char *fn) -{ - struct FB fb; - struct stat s; - unsigned short *data, *bits, *ptr; - unsigned count, max; - int fd; - - if (vt_set_mode(1)) - return -1; - - fd = open(fn, O_RDONLY); - if (fd < 0) { - ERROR("cannot open '%s'\n", fn); - goto fail_restore_text; - } - - if (fstat(fd, &s) < 0) { - goto fail_close_file; - } - - data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) - goto fail_close_file; - - if (fb_open(&fb)) - goto fail_unmap_data; - - max = fb_width(&fb) * fb_height(&fb); - ptr = data; - count = s.st_size; - bits = fb.bits; - while (count > 3) { - unsigned n = ptr[0]; - if (n > max) - break; - android_memset16(bits, ptr[1], n << 1); - bits += n; - max -= n; - ptr += 2; - count -= 4; - } - - munmap(data, s.st_size); - fb_update(&fb); - fb_close(&fb); - close(fd); - unlink(fn); - return 0; - -fail_unmap_data: - munmap(data, s.st_size); -fail_close_file: - close(fd); -fail_restore_text: - vt_set_mode(0); - return -1; -} - diff --git a/init/property_service.c b/init/property_service.c index 9ac2781..c370769 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -81,6 +81,7 @@ struct { { "sys.powerctl", AID_SHELL, 0 }, { "service.", AID_SYSTEM, 0 }, { "wlan.", AID_SYSTEM, 0 }, + { "gps.", AID_GPS, 0 }, { "bluetooth.", AID_BLUETOOTH, 0 }, { "dhcp.", AID_SYSTEM, 0 }, { "dhcp.", AID_DHCP, 0 }, @@ -92,6 +93,7 @@ struct { { "persist.sys.", AID_SYSTEM, 0 }, { "persist.service.", AID_SYSTEM, 0 }, { "persist.security.", AID_SYSTEM, 0 }, + { "persist.gps.", AID_GPS, 0 }, { "persist.service.bdroid.", AID_BLUETOOTH, 0 }, { "selinux." , AID_SYSTEM, 0 }, { NULL, 0, 0 } @@ -437,10 +439,13 @@ void get_property_workspace(int *fd, int *sz) *sz = pa_workspace.size; } -static void load_properties(char *data) +static void load_properties(char *data, char *prefix) { char *key, *value, *eol, *sol, *tmp; + size_t plen; + if (prefix) + plen = strlen(prefix); sol = data; while((eol = strchr(sol, '\n'))) { key = sol; @@ -456,6 +461,9 @@ static void load_properties(char *data) tmp = value - 2; while((tmp > key) && isspace(*tmp)) *tmp-- = 0; + if (prefix && strncmp(key, prefix, plen)) + continue; + while(isspace(*value)) value++; tmp = eol - 2; while((tmp > value) && isspace(*tmp)) *tmp-- = 0; @@ -464,7 +472,7 @@ static void load_properties(char *data) } } -static void load_properties_from_file(const char *fn) +static void load_properties_from_file(const char *fn, char *prefix) { char *data; unsigned sz; @@ -472,7 +480,7 @@ static void load_properties_from_file(const char *fn) data = read_file(fn, &sz); if(data != 0) { - load_properties(data); + load_properties(data, prefix); free(data); } } @@ -545,7 +553,7 @@ void property_init(void) void property_load_boot_defaults(void) { - load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT); + load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL); } int properties_inited(void) @@ -560,7 +568,7 @@ static void load_override_properties() { ret = property_get("ro.debuggable", debuggable); if (ret && (strcmp(debuggable, "1") == 0)) { - load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE); + load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL); } #endif /* ALLOW_LOCAL_PROP_OVERRIDE */ } @@ -582,13 +590,14 @@ void start_property_service(void) { int fd; - load_properties_from_file(PROP_PATH_SYSTEM_BUILD); - load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT); + load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); + load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); + load_properties_from_file(PROP_PATH_FACTORY, "ro."); load_override_properties(); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); - fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0); + fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); if(fd < 0) return; fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFL, O_NONBLOCK); diff --git a/init/readme.txt b/init/readme.txt index 7a5997d..42a09cb 100644 --- a/init/readme.txt +++ b/init/readme.txt @@ -70,10 +70,13 @@ disabled setenv <name> <value> Set the environment variable <name> to <value> in the launched process. -socket <name> <type> <perm> [ <user> [ <group> ] ] +socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ] Create a unix domain socket named /dev/socket/<name> and pass its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket". User and group default to 0. + Context is the SELinux security context for the socket. + It defaults to the service security context, as specified by seclabel or + computed based on the service executable file security context. user <username> Change to username before exec'ing this service. @@ -189,12 +192,18 @@ mount <type> <device> <dir> [ <mountoption> ]* device by name. <mountoption>s include "ro", "rw", "remount", "noatime", ... -restorecon <path> +restorecon <path> [ <path> ]* Restore the file named by <path> to the security context specified in the file_contexts configuration. Not required for directories created by the init.rc as these are automatically labeled correctly by init. +restorecon_recursive <path> [ <path> ]* + Recursively restore the directory tree named by <path> to the + security contexts specified in the file_contexts configuration. + Do NOT use this with paths leading to shell-writable or app-writable + directories, e.g. /data/local/tmp, /data/data or any prefix thereof. + setcon <securitycontext> Set the current process security context to the specified string. This is typically only used from early-init to set the init context diff --git a/init/util.c b/init/util.c index 1908b3a..9aaa77d 100644 --- a/init/util.c +++ b/init/util.c @@ -84,11 +84,15 @@ unsigned int decode_uid(const char *s) * daemon. We communicate the file descriptor's value via the environment * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo"). */ -int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) +int create_socket(const char *name, int type, mode_t perm, uid_t uid, + gid_t gid, const char *socketcon) { struct sockaddr_un addr; int fd, ret; - char *secon; + char *filecon; + + if (socketcon) + setsockcreatecon(socketcon); fd = socket(PF_UNIX, type, 0); if (fd < 0) { @@ -96,6 +100,9 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) return -1; } + if (socketcon) + setsockcreatecon(NULL); + memset(&addr, 0 , sizeof(addr)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", @@ -107,11 +114,11 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) goto out_close; } - secon = NULL; + filecon = NULL; if (sehandle) { - ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK); + ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK); if (ret == 0) - setfscreatecon(secon); + setfscreatecon(filecon); } ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr)); @@ -121,7 +128,7 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid) } setfscreatecon(NULL); - freecon(secon); + freecon(filecon); chown(addr.sun_path, uid, gid); chmod(addr.sun_path, perm); @@ -398,7 +405,9 @@ void open_devnull_stdio(void) void get_hardware_name(char *hardware, unsigned int *revision) { - char data[1024]; + const char *cpuinfo = "/proc/cpuinfo"; + char *data = NULL; + size_t len = 0, limit = 1024; int fd, n; char *x, *hw, *rev; @@ -406,14 +415,32 @@ void get_hardware_name(char *hardware, unsigned int *revision) if (hardware[0]) return; - fd = open("/proc/cpuinfo", O_RDONLY); + fd = open(cpuinfo, O_RDONLY); if (fd < 0) return; - n = read(fd, data, 1023); - close(fd); - if (n < 0) return; + for (;;) { + x = realloc(data, limit); + if (!x) { + ERROR("Failed to allocate memory to read %s\n", cpuinfo); + goto done; + } + data = x; + + n = read(fd, data + len, limit - len); + if (n < 0) { + ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno); + goto done; + } + len += n; - data[n] = 0; + if (len < limit) + break; + + /* We filled the buffer, so increase size and loop to read more */ + limit *= 2; + } + + data[len] = 0; hw = strstr(data, "\nHardware"); rev = strstr(data, "\nRevision"); @@ -438,18 +465,22 @@ void get_hardware_name(char *hardware, unsigned int *revision) *revision = strtoul(x + 2, 0, 16); } } + +done: + close(fd); + free(data); } void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu)) { - char cmdline[1024]; + char cmdline[2048]; char *ptr; int fd; fd = open("/proc/cmdline", O_RDONLY); if (fd >= 0) { - int n = read(fd, cmdline, 1023); + int n = read(fd, cmdline, sizeof(cmdline) - 1); if (n < 0) n = 0; /* get rid of trailing newline, it happens */ diff --git a/init/util.h b/init/util.h index 6bca4e6..04b8129 100644 --- a/init/util.h +++ b/init/util.h @@ -26,7 +26,7 @@ static const char *coldboot_done = "/dev/.coldboot_done"; int mtd_name_to_number(const char *name); int create_socket(const char *name, int type, mode_t perm, - uid_t uid, gid_t gid); + uid_t uid, gid_t gid, const char *socketcon); void *read_file(const char *fn, unsigned *_sz); time_t gettime(void); unsigned int decode_uid(const char *s); diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk new file mode 100644 index 0000000..eb55b47 --- /dev/null +++ b/libbacktrace/Android.mk @@ -0,0 +1,263 @@ +LOCAL_PATH:= $(call my-dir) + +common_src := \ + Backtrace.cpp \ + BacktraceThread.cpp \ + map_info.c \ + thread_utils.c \ + +common_cflags := \ + -Wall \ + -Wno-unused-parameter \ + -Werror \ + +common_conlyflags := \ + -std=gnu99 \ + +common_cppflags := \ + -std=gnu++11 \ + +common_shared_libs := \ + libcutils \ + libgccdemangle \ + liblog \ + +# To enable using libunwind on each arch, add it to the list below. +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm)) + +#---------------------------------------------------------------------------- +# The native libbacktrace library with libunwind. +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + $(common_src) \ + UnwindCurrent.cpp \ + UnwindPtrace.cpp \ + +LOCAL_CFLAGS := \ + $(common_cflags) \ + +LOCAL_CONLYFLAGS += \ + $(common_conlyflags) \ + +LOCAL_CPPFLAGS += \ + $(common_cppflags) \ + +LOCAL_MODULE := libbacktrace +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES := \ + $(common_c_includes) \ + external/libunwind/include \ + +LOCAL_SHARED_LIBRARIES := \ + $(common_shared_libs) \ + libunwind \ + libunwind-ptrace \ + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include external/stlport/libstlport.mk + +include $(BUILD_SHARED_LIBRARY) + +else + +#---------------------------------------------------------------------------- +# The native libbacktrace library with libcorkscrew. +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + $(common_src) \ + Corkscrew.cpp \ + +LOCAL_CFLAGS := \ + $(common_cflags) \ + +LOCAL_CONLYFLAGS += \ + $(common_conlyflags) \ + +LOCAL_CPPFLAGS += \ + $(common_cppflags) \ + +LOCAL_MODULE := libbacktrace +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES := \ + $(common_c_includes) \ + system/core/libcorkscrew \ + +LOCAL_SHARED_LIBRARIES := \ + $(common_shared_libs) \ + libcorkscrew \ + libdl \ + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include external/stlport/libstlport.mk + +include $(BUILD_SHARED_LIBRARY) + +endif + +#---------------------------------------------------------------------------- +# libbacktrace test library, all optimizations turned off +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_MODULE := libbacktrace_test +LOCAL_MODULE_FLAGS := debug + +LOCAL_SRC_FILES := \ + backtrace_testlib.c + +LOCAL_CFLAGS += \ + -std=gnu99 \ + -O0 \ + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include $(BUILD_SHARED_LIBRARY) + +#---------------------------------------------------------------------------- +# libbacktrace test executable +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_MODULE := backtrace_test +LOCAL_MODULE_FLAGS := debug + +LOCAL_SRC_FILES := \ + backtrace_test.cpp \ + thread_utils.c \ + +LOCAL_CFLAGS += \ + $(common_cflags) \ + -fno-builtin \ + -fstack-protector-all \ + -O0 \ + -g \ + -DGTEST_OS_LINUX_ANDROID \ + -DGTEST_HAS_STD_STRING \ + +LOCAL_CONLYFLAGS += \ + $(common_conlyflags) \ + +LOCAL_CPPFLAGS += \ + $(common_cppflags) \ + +LOCAL_SHARED_LIBRARIES += \ + libcutils \ + libbacktrace_test \ + libbacktrace \ + +LOCAL_LDLIBS := \ + -lpthread \ + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include $(BUILD_NATIVE_TEST) + +#---------------------------------------------------------------------------- +# Only linux-x86 host versions of libbacktrace supported. +#---------------------------------------------------------------------------- +ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86) + +#---------------------------------------------------------------------------- +# The host libbacktrace library using libcorkscrew +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_SRC_FILES += \ + $(common_src) \ + Corkscrew.cpp \ + +LOCAL_CFLAGS += \ + $(common_cflags) \ + +LOCAL_CONLYFLAGS += \ + $(common_conlyflags) \ + +LOCAL_CPPFLAGS += \ + $(common_cppflags) \ + +LOCAL_C_INCLUDES := \ + $(common_c_includes) \ + system/core/libcorkscrew \ + +LOCAL_SHARED_LIBRARIES := \ + libgccdemangle \ + liblog \ + libcorkscrew \ + +LOCAL_LDLIBS += \ + -ldl \ + -lrt \ + +LOCAL_MODULE := libbacktrace +LOCAL_MODULE_TAGS := optional + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include $(BUILD_HOST_SHARED_LIBRARY) + +#---------------------------------------------------------------------------- +# libbacktrace host test library, all optimizations turned off +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_MODULE := libbacktrace_test +LOCAL_MODULE_FLAGS := debug + +LOCAL_SRC_FILES := \ + backtrace_testlib.c + +LOCAL_CFLAGS += \ + -std=gnu99 \ + -O0 \ + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include $(BUILD_HOST_SHARED_LIBRARY) + +#---------------------------------------------------------------------------- +# libbacktrace host test executable +#---------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_MODULE := backtrace_test +LOCAL_MODULE_FLAGS := debug + +LOCAL_SRC_FILES := \ + backtrace_test.cpp \ + thread_utils.c \ + +LOCAL_CFLAGS += \ + $(common_cflags) \ + -fno-builtin \ + -fstack-protector-all \ + -O0 \ + -g \ + -DGTEST_HAS_STD_STRING \ + +LOCAL_SHARED_LIBRARIES := \ + libbacktrace_test \ + libbacktrace \ + +LOCAL_LDLIBS := \ + -lpthread \ + +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(LOCAL_PATH)/Android.mk + +include $(BUILD_HOST_NATIVE_TEST) + +endif # HOST_OS-HOST_ARCH == linux-x86 diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp new file mode 100644 index 0000000..b22d301 --- /dev/null +++ b/libbacktrace/Backtrace.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <unistd.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include <string> + +#include <backtrace/Backtrace.h> +#include <cutils/log.h> + +#include "Backtrace.h" +#include "thread_utils.h" + +//------------------------------------------------------------------------- +// BacktraceImpl functions. +//------------------------------------------------------------------------- +backtrace_t* BacktraceImpl::GetBacktraceData() { + return &backtrace_obj_->backtrace_; +} + +//------------------------------------------------------------------------- +// Backtrace functions. +//------------------------------------------------------------------------- +Backtrace::Backtrace(BacktraceImpl* impl) : impl_(impl), map_info_(NULL) { + impl_->SetParent(this); + backtrace_.num_frames = 0; + backtrace_.pid = -1; + backtrace_.tid = -1; +} + +Backtrace::~Backtrace() { + for (size_t i = 0; i < NumFrames(); i++) { + if (backtrace_.frames[i].func_name) { + free(backtrace_.frames[i].func_name); + backtrace_.frames[i].func_name = NULL; + } + } + + if (map_info_) { + backtrace_destroy_map_info_list(map_info_); + map_info_ = NULL; + } + + if (impl_) { + delete impl_; + impl_ = NULL; + } +} + +bool Backtrace::Unwind(size_t num_ignore_frames) { + return impl_->Unwind(num_ignore_frames); +} + +extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len, + int* status); + +std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) { + std::string func_name = impl_->GetFunctionNameRaw(pc, offset); + if (!func_name.empty()) { +#if defined(__APPLE__) + // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7. + if (symbol_name[0] != '_') { + return func_name; + } +#endif + char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0); + if (name) { + func_name = name; + free(name); + } + } + return func_name; +} + +bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) { + if (ptr & 3) { + BACK_LOGW("invalid pointer %p", (void*)ptr); + *out_value = (uint32_t)-1; + return false; + } + return true; +} + +const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) { + const backtrace_map_info_t* map_info = FindMapInfo(pc); + if (map_info) { + if (map_start) { + *map_start = map_info->start; + } + return map_info->name; + } + return NULL; +} + +const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) { + return backtrace_find_map_info(map_info_, ptr); +} + +std::string Backtrace::FormatFrameData(size_t frame_num) { + backtrace_frame_data_t* frame = &backtrace_.frames[frame_num]; + const char* map_name; + if (frame->map_name) { + map_name = frame->map_name; + } else { + map_name = "<unknown>"; + } + uintptr_t relative_pc; + if (frame->map_offset) { + relative_pc = frame->map_offset; + } else { + relative_pc = frame->pc; + } + + char buf[512]; + if (frame->func_name && frame->func_offset) { + snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")", + frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name, + frame->func_name, frame->func_offset); + } else if (frame->func_name) { + snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame_num, + (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name); + } else { + snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame_num, + (int)sizeof(uintptr_t)*2, relative_pc, map_name); + } + + return buf; +} + +//------------------------------------------------------------------------- +// BacktraceCurrent functions. +//------------------------------------------------------------------------- +BacktraceCurrent::BacktraceCurrent(BacktraceImpl* impl) : Backtrace(impl) { + map_info_ = backtrace_create_map_info_list(-1); + + backtrace_.pid = getpid(); +} + +BacktraceCurrent::~BacktraceCurrent() { +} + +bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) { + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + + const backtrace_map_info_t* map_info = FindMapInfo(ptr); + if (map_info && map_info->is_readable) { + *out_value = *reinterpret_cast<uint32_t*>(ptr); + return true; + } else { + BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr)); + *out_value = static_cast<uint32_t>(-1); + return false; + } +} + +//------------------------------------------------------------------------- +// BacktracePtrace functions. +//------------------------------------------------------------------------- +BacktracePtrace::BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid) + : Backtrace(impl) { + map_info_ = backtrace_create_map_info_list(tid); + + backtrace_.pid = pid; + backtrace_.tid = tid; +} + +BacktracePtrace::~BacktracePtrace() { +} + +bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) { + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + +#if defined(__APPLE__) + BACK_LOGW("MacOS does not support reading from another pid."); + return false; +#else + // ptrace() returns -1 and sets errno when the operation fails. + // To disambiguate -1 from a valid result, we clear errno beforehand. + errno = 0; + *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL); + if (*out_value == static_cast<uint32_t>(-1) && errno) { + BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s", + reinterpret_cast<void*>(ptr), Tid(), strerror(errno)); + return false; + } + return true; +#endif +} + +Backtrace* Backtrace::Create(pid_t pid, pid_t tid) { + if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) { + if (tid == BACKTRACE_NO_TID || tid == gettid()) { + return CreateCurrentObj(); + } else { + return CreateThreadObj(tid); + } + } else if (tid == BACKTRACE_NO_TID) { + return CreatePtraceObj(pid, pid); + } else { + return CreatePtraceObj(pid, tid); + } +} + +//------------------------------------------------------------------------- +// Common interface functions. +//------------------------------------------------------------------------- +bool backtrace_create_context( + backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) { + Backtrace* backtrace = Backtrace::Create(pid, tid); + if (!backtrace) { + return false; + } + if (!backtrace->Unwind(num_ignore_frames)) { + delete backtrace; + return false; + } + + context->data = backtrace; + context->backtrace = backtrace->GetBacktrace(); + return true; +} + +void backtrace_destroy_context(backtrace_context_t* context) { + if (context->data) { + Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); + delete backtrace; + context->data = NULL; + } + context->backtrace = NULL; +} + +const backtrace_t* backtrace_get_data(backtrace_context_t* context) { + if (context && context->data) { + Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); + return backtrace->GetBacktrace(); + } + return NULL; +} + +bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) { + if (context->data) { + Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); + return backtrace->ReadWord(ptr, value); + } + return true; +} + +const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) { + if (context->data) { + Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); + return backtrace->GetMapName(pc, map_start); + } + return NULL; +} + +char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) { + if (context->data) { + Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); + std::string func_name = backtrace->GetFunctionName(pc, func_offset); + if (!func_name.empty()) { + return strdup(func_name.c_str()); + } + } + return NULL; +} + +void backtrace_format_frame_data( + const backtrace_context_t* context, size_t frame_num, char* buf, + size_t buf_size) { + if (buf_size == 0 || buf == NULL) { + BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size); + } else if (context->data) { + Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); + std::string line = backtrace->FormatFrameData(frame_num); + if (line.size() > buf_size) { + memcpy(buf, line.c_str(), buf_size-1); + buf[buf_size] = '\0'; + } else { + memcpy(buf, line.c_str(), line.size()+1); + } + } +} diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h new file mode 100644 index 0000000..00f0a10 --- /dev/null +++ b/libbacktrace/Backtrace.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_BACKTRACE_H +#define _LIBBACKTRACE_BACKTRACE_H + +#include <backtrace/Backtrace.h> + +#include <sys/types.h> + +// Macro to log the function name along with the warning message. +#define BACK_LOGW(format, ...) \ + ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__) + +class BacktraceImpl { +public: + virtual ~BacktraceImpl() { } + + virtual bool Unwind(size_t num_ignore_frames) = 0; + + // The name returned is not demangled, Backtrace::GetFunctionName() + // takes care of demangling the name. + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0; + + void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; } + +protected: + backtrace_t* GetBacktraceData(); + + Backtrace* backtrace_obj_; +}; + +class BacktraceCurrent : public Backtrace { +public: + BacktraceCurrent(BacktraceImpl* impl); + virtual ~BacktraceCurrent(); + + bool ReadWord(uintptr_t ptr, uint32_t* out_value); +}; + +class BacktracePtrace : public Backtrace { +public: + BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid); + virtual ~BacktracePtrace(); + + bool ReadWord(uintptr_t ptr, uint32_t* out_value); +}; + +Backtrace* CreateCurrentObj(); +Backtrace* CreatePtraceObj(pid_t pid, pid_t tid); +Backtrace* CreateThreadObj(pid_t tid); + +#endif // _LIBBACKTRACE_BACKTRACE_H diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp new file mode 100644 index 0000000..8e664c4 --- /dev/null +++ b/libbacktrace/BacktraceThread.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <inttypes.h> +#include <pthread.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> + +#include <cutils/atomic.h> +#include <cutils/log.h> + +#include "BacktraceThread.h" +#include "thread_utils.h" + +//------------------------------------------------------------------------- +// ThreadEntry implementation. +//------------------------------------------------------------------------- +static ThreadEntry* g_list = NULL; +static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; + +ThreadEntry::ThreadEntry( + BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) + : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL), + state(STATE_WAITING), num_ignore_frames(num_ignore_frames) { +} + +ThreadEntry::~ThreadEntry() { + pthread_mutex_lock(&g_entry_mutex); + if (g_list == this) { + g_list = next; + } else { + if (next) { + next->prev = prev; + } + prev->next = next; + } + pthread_mutex_unlock(&g_entry_mutex); + + next = NULL; + prev = NULL; +} + +ThreadEntry* ThreadEntry::AddThreadToUnwind( + BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) { + ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames); + + pthread_mutex_lock(&g_entry_mutex); + ThreadEntry* cur_entry = g_list; + while (cur_entry != NULL) { + if (cur_entry->Match(pid, tid)) { + // There is already an entry for this pid/tid, this is bad. + BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid); + + pthread_mutex_unlock(&g_entry_mutex); + return NULL; + } + cur_entry = cur_entry->next; + } + + // Add the entry to the list. + entry->next = g_list; + if (g_list) { + g_list->prev = entry; + } + g_list = entry; + pthread_mutex_unlock(&g_entry_mutex); + + return entry; +} + +//------------------------------------------------------------------------- +// BacktraceThread functions. +//------------------------------------------------------------------------- +static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, + void* sigcontext) { + if (pthread_mutex_lock(&g_entry_mutex) == 0) { + pid_t pid = getpid(); + pid_t tid = gettid(); + ThreadEntry* cur_entry = g_list; + while (cur_entry) { + if (cur_entry->Match(pid, tid)) { + break; + } + cur_entry = cur_entry->next; + } + pthread_mutex_unlock(&g_entry_mutex); + if (!cur_entry) { + BACK_LOGW("Unable to find pid %d tid %d information", pid, tid); + return; + } + + if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) { + cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext, + cur_entry->num_ignore_frames); + } + android_atomic_release_store(STATE_DONE, &cur_entry->state); + } +} + +BacktraceThread::BacktraceThread( + BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid) + : BacktraceCurrent(impl), thread_intf_(thread_intf) { + backtrace_.tid = tid; +} + +BacktraceThread::~BacktraceThread() { +} + +void BacktraceThread::FinishUnwind() { + for (size_t i = 0; i < NumFrames(); i++) { + backtrace_frame_data_t* frame = &backtrace_.frames[i]; + + frame->map_offset = 0; + uintptr_t map_start; + frame->map_name = GetMapName(frame->pc, &map_start); + if (frame->map_name) { + frame->map_offset = frame->pc - map_start; + } + + frame->func_offset = 0; + std::string func_name = GetFunctionName(frame->pc, &frame->func_offset); + if (!func_name.empty()) { + frame->func_name = strdup(func_name.c_str()); + } + } +} + +bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { + entry->state = STATE_WAITING; + + if (tgkill(Pid(), Tid(), SIGURG) != 0) { + BACK_LOGW("tgkill failed %s", strerror(errno)); + return false; + } + + // Allow up to ten seconds for the dump to start. + int wait_millis = 10000; + int32_t state; + while (true) { + state = android_atomic_acquire_load(&entry->state); + if (state != STATE_WAITING) { + break; + } + if (wait_millis--) { + usleep(1000); + } else { + break; + } + } + + bool cancelled = false; + if (state == STATE_WAITING) { + if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) { + BACK_LOGW("Cancelled dump of thread %d", entry->tid); + state = STATE_CANCEL; + cancelled = true; + } else { + state = android_atomic_acquire_load(&entry->state); + } + } + + // Wait for at most ten seconds for the cancel or dump to finish. + wait_millis = 10000; + while (android_atomic_acquire_load(&entry->state) != STATE_DONE) { + if (wait_millis--) { + usleep(1000); + } else { + BACK_LOGW("Didn't finish thread unwind in 60 seconds."); + break; + } + } + return !cancelled; +} + +bool BacktraceThread::Unwind(size_t num_ignore_frames) { + if (!thread_intf_->Init()) { + return false; + } + + ThreadEntry* entry = ThreadEntry::AddThreadToUnwind( + thread_intf_, Pid(), Tid(), num_ignore_frames); + if (!entry) { + return false; + } + + // Prevent multiple threads trying to set the trigger action on different + // threads at the same time. + bool retval = false; + if (pthread_mutex_lock(&g_sigaction_mutex) == 0) { + struct sigaction act, oldact; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = SignalHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + sigemptyset(&act.sa_mask); + if (sigaction(SIGURG, &act, &oldact) == 0) { + retval = TriggerUnwindOnThread(entry); + sigaction(SIGURG, &oldact, NULL); + } else { + BACK_LOGW("sigaction failed %s", strerror(errno)); + } + pthread_mutex_unlock(&g_sigaction_mutex); + } else { + BACK_LOGW("unable to acquire sigaction mutex."); + } + + if (retval) { + FinishUnwind(); + } + delete entry; + + return retval; +} diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h new file mode 100644 index 0000000..8ed1122 --- /dev/null +++ b/libbacktrace/BacktraceThread.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H +#define _LIBBACKTRACE_BACKTRACE_THREAD_H + +#include <inttypes.h> +#include <pthread.h> +#include <sys/types.h> + +#include "Backtrace.h" + +typedef enum { + STATE_WAITING = 0, + STATE_DUMPING, + STATE_DONE, + STATE_CANCEL, +} state_e; + +class BacktraceThreadInterface; + +struct ThreadEntry { + ThreadEntry( + BacktraceThreadInterface* impl, pid_t pid, pid_t tid, + size_t num_ignore_frames); + ~ThreadEntry(); + + bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); } + + static ThreadEntry* AddThreadToUnwind( + BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid, + size_t num_ignored_frames); + + BacktraceThreadInterface* thread_intf; + pid_t pid; + pid_t tid; + ThreadEntry* next; + ThreadEntry* prev; + int32_t state; + int num_ignore_frames; +}; + +// Interface class that does not contain any local storage, only defines +// virtual functions to be defined by subclasses. +class BacktraceThreadInterface { +public: + virtual ~BacktraceThreadInterface() { } + + virtual bool Init() = 0; + + virtual void ThreadUnwind( + siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0; +}; + +class BacktraceThread : public BacktraceCurrent { +public: + // impl and thread_intf should point to the same object, this allows + // the compiler to catch if an implementation does not properly + // subclass both. + BacktraceThread( + BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid); + virtual ~BacktraceThread(); + + virtual bool Unwind(size_t num_ignore_frames); + + virtual void ThreadUnwind( + siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) { + thread_intf_->ThreadUnwind(siginfo, sigcontext, num_ignore_frames); + } + +private: + virtual bool TriggerUnwindOnThread(ThreadEntry* entry); + + virtual void FinishUnwind(); + + BacktraceThreadInterface* thread_intf_; +}; + +#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp new file mode 100644 index 0000000..2be5930 --- /dev/null +++ b/libbacktrace/Corkscrew.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "libbacktrace" + +#include <backtrace/backtrace.h> + +#include <string.h> + +#include <backtrace-arch.h> +#include <cutils/log.h> +#include <corkscrew/backtrace.h> + +#ifndef __USE_GNU +#define __USE_GNU +#endif +#include <dlfcn.h> + +#include "Corkscrew.h" + +//------------------------------------------------------------------------- +// CorkscrewCommon functions. +//------------------------------------------------------------------------- +bool CorkscrewCommon::GenerateFrameData( + backtrace_frame_t* cork_frames, ssize_t num_frames) { + if (num_frames < 0) { + BACK_LOGW("libcorkscrew unwind failed."); + return false; + } + + backtrace_t* data = GetBacktraceData(); + data->num_frames = num_frames; + for (size_t i = 0; i < data->num_frames; i++) { + backtrace_frame_data_t* frame = &data->frames[i]; + frame->pc = cork_frames[i].absolute_pc; + frame->sp = cork_frames[i].stack_top; + frame->stack_size = cork_frames[i].stack_size; + frame->map_name = NULL; + frame->map_offset = 0; + frame->func_name = NULL; + frame->func_offset = 0; + + uintptr_t map_start; + frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); + if (frame->map_name) { + frame->map_offset = frame->pc - map_start; + } + + std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); + if (!func_name.empty()) { + frame->func_name = strdup(func_name.c_str()); + } + } + return true; +} + +//------------------------------------------------------------------------- +// CorkscrewCurrent functions. +//------------------------------------------------------------------------- +CorkscrewCurrent::CorkscrewCurrent() { +} + +CorkscrewCurrent::~CorkscrewCurrent() { +} + +bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) { + backtrace_frame_t frames[MAX_BACKTRACE_FRAMES]; + ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES); + + return GenerateFrameData(frames, num_frames); +} + +std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { + *offset = 0; + + Dl_info info; + const backtrace_map_info_t* map_info = backtrace_obj_->FindMapInfo(pc); + if (map_info) { + if (dladdr((const void*)pc, &info)) { + if (info.dli_sname) { + *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase; + return info.dli_sname; + } + } else { + // dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file... + symbol_table_t* symbol_table = load_symbol_table(map_info->name); + if (symbol_table) { + // First check if we can find the symbol using a relative pc. + std::string name; + const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map_info->start); + if (elf_symbol) { + name = elf_symbol->name; + *offset = pc - map_info->start - elf_symbol->start; + } else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) { + // Found the symbol using the absolute pc. + name = elf_symbol->name; + *offset = pc - elf_symbol->start; + } + free_symbol_table(symbol_table); + return name; + } + } + } + return ""; +} + +//------------------------------------------------------------------------- +// CorkscrewThread functions. +//------------------------------------------------------------------------- +CorkscrewThread::CorkscrewThread() { +} + +CorkscrewThread::~CorkscrewThread() { + if (corkscrew_map_info_) { + free_map_info_list(corkscrew_map_info_); + corkscrew_map_info_ = NULL; + } +} + +bool CorkscrewThread::Init() { + corkscrew_map_info_ = load_map_info_list(backtrace_obj_->Pid()); + return corkscrew_map_info_ != NULL; +} + +void CorkscrewThread::ThreadUnwind( + siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) { + backtrace_frame_t frames[MAX_BACKTRACE_FRAMES]; + ssize_t num_frames = unwind_backtrace_signal_arch( + siginfo, sigcontext, corkscrew_map_info_, frames, num_ignore_frames, + MAX_BACKTRACE_FRAMES); + if (num_frames > 0) { + backtrace_t* data = GetBacktraceData(); + data->num_frames = num_frames; + for (size_t i = 0; i < data->num_frames; i++) { + backtrace_frame_data_t* frame = &data->frames[i]; + frame->pc = frames[i].absolute_pc; + frame->sp = frames[i].stack_top; + frame->stack_size = frames[i].stack_size; + + frame->map_offset = 0; + frame->map_name = NULL; + frame->map_offset = 0; + + frame->func_offset = 0; + frame->func_name = NULL; + } + } +} + +//------------------------------------------------------------------------- +// CorkscrewPtrace functions. +//------------------------------------------------------------------------- +CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) { +} + +CorkscrewPtrace::~CorkscrewPtrace() { + if (ptrace_context_) { + free_ptrace_context(ptrace_context_); + ptrace_context_ = NULL; + } +} + +bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) { + ptrace_context_ = load_ptrace_context(backtrace_obj_->Tid()); + + backtrace_frame_t frames[MAX_BACKTRACE_FRAMES]; + ssize_t num_frames = unwind_backtrace_ptrace( + backtrace_obj_->Tid(), ptrace_context_, frames, num_ignore_frames, + MAX_BACKTRACE_FRAMES); + + return GenerateFrameData(frames, num_frames); +} + +std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { + // Get information about a different process. + const map_info_t* map_info; + const symbol_t* symbol; + find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol); + char* symbol_name = NULL; + if (symbol) { + if (map_info) { + *offset = pc - map_info->start - symbol->start; + } + symbol_name = symbol->name; + return symbol_name; + } + + return ""; +} + +//------------------------------------------------------------------------- +// C++ object creation functions. +//------------------------------------------------------------------------- +Backtrace* CreateCurrentObj() { + return new BacktraceCurrent(new CorkscrewCurrent()); +} + +Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) { + return new BacktracePtrace(new CorkscrewPtrace(), pid, tid); +} + +Backtrace* CreateThreadObj(pid_t tid) { + CorkscrewThread* thread_obj = new CorkscrewThread(); + return new BacktraceThread(thread_obj, thread_obj, tid); +} diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h new file mode 100644 index 0000000..7cb125c --- /dev/null +++ b/libbacktrace/Corkscrew.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_CORKSCREW_H +#define _LIBBACKTRACE_CORKSCREW_H + +#include <inttypes.h> + +#include <string> + +#include <backtrace/backtrace.h> +#include <backtrace/Backtrace.h> + +#include <corkscrew/backtrace.h> + +#include "Backtrace.h" +#include "BacktraceThread.h" + +class CorkscrewCommon : public BacktraceImpl { +public: + bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames); +}; + +class CorkscrewCurrent : public CorkscrewCommon { +public: + CorkscrewCurrent(); + virtual ~CorkscrewCurrent(); + + virtual bool Unwind(size_t num_ignore_threads); + + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); +}; + +class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface { +public: + CorkscrewThread(); + virtual ~CorkscrewThread(); + + virtual bool Init(); + + virtual void ThreadUnwind( + siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames); + +private: + map_info_t* corkscrew_map_info_; +}; + +class CorkscrewPtrace : public CorkscrewCommon { +public: + CorkscrewPtrace(); + virtual ~CorkscrewPtrace(); + + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + + virtual bool Unwind(size_t num_ignore_threads); + +private: + ptrace_context_t* ptrace_context_; +}; + +#endif // _LIBBACKTRACE_CORKSCREW_H diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp new file mode 100644 index 0000000..d4ba68f --- /dev/null +++ b/libbacktrace/UnwindCurrent.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "libbacktrace" + +#include <sys/types.h> + +#include <cutils/log.h> + +#include <backtrace/backtrace.h> + +#define UNW_LOCAL_ONLY +#include <libunwind.h> + +#include "UnwindCurrent.h" + +// Define the ucontext_t structures needed for each supported arch. +#if defined(__arm__) + // The current version of the <signal.h> doesn't define ucontext_t. + #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined. + + // Machine context at the time a signal was raised. + typedef struct ucontext { + uint32_t uc_flags; + struct ucontext* uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + uint32_t uc_sigmask; + } ucontext_t; +#elif defined(__mips__) + typedef struct ucontext { + uint32_t sp; + uint32_t ra; + uint32_t pc; + } ucontext_t; +#elif defined(__i386__) + #include <asm/sigcontext.h> + #include <asm/ucontext.h> + typedef struct ucontext ucontext_t; +#else + #error Unsupported architecture. +#endif + +//------------------------------------------------------------------------- +// UnwindCurrent functions. +//------------------------------------------------------------------------- +UnwindCurrent::UnwindCurrent() { +} + +UnwindCurrent::~UnwindCurrent() { +} + +bool UnwindCurrent::Unwind(size_t num_ignore_frames) { + int ret = unw_getcontext(&context_); + if (ret < 0) { + BACK_LOGW("unw_getcontext failed %d", ret); + return false; + } + return UnwindFromContext(num_ignore_frames, true); +} + +std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { + *offset = 0; + char buf[512]; + unw_word_t value; + if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf), + &value, &context_) >= 0 && buf[0] != '\0') { + *offset = static_cast<uintptr_t>(value); + return buf; + } + return ""; +} + +bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { + backtrace_t* backtrace = GetBacktraceData(); + backtrace->num_frames = 0; + + // The cursor structure is pretty large, do not put it on the stack. + unw_cursor_t* cursor = new unw_cursor_t; + int ret = unw_init_local(cursor, &context_); + if (ret < 0) { + BACK_LOGW("unw_init_local failed %d", ret); + return false; + } + + do { + unw_word_t pc; + ret = unw_get_reg(cursor, UNW_REG_IP, &pc); + if (ret < 0) { + BACK_LOGW("Failed to read IP %d", ret); + break; + } + unw_word_t sp; + ret = unw_get_reg(cursor, UNW_REG_SP, &sp); + if (ret < 0) { + BACK_LOGW("Failed to read SP %d", ret); + break; + } + + if (num_ignore_frames == 0) { + size_t num_frames = backtrace->num_frames; + backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; + frame->pc = static_cast<uintptr_t>(pc); + frame->sp = static_cast<uintptr_t>(sp); + frame->stack_size = 0; + frame->map_name = NULL; + frame->map_offset = 0; + frame->func_name = NULL; + frame->func_offset = 0; + + if (num_frames > 0) { + // Set the stack size for the previous frame. + backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; + prev->stack_size = frame->sp - prev->sp; + } + + if (resolve) { + std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); + if (!func_name.empty()) { + frame->func_name = strdup(func_name.c_str()); + } + + uintptr_t map_start; + frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); + if (frame->map_name) { + frame->map_offset = frame->pc - map_start; + } + } + + backtrace->num_frames++; + } else { + num_ignore_frames--; + } + ret = unw_step (cursor); + } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); + + delete cursor; + return true; +} + +void UnwindCurrent::ExtractContext(void* sigcontext) { + unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_); + const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext); + +#if defined(__arm__) + context->regs[0] = uc->uc_mcontext.arm_r0; + context->regs[1] = uc->uc_mcontext.arm_r1; + context->regs[2] = uc->uc_mcontext.arm_r2; + context->regs[3] = uc->uc_mcontext.arm_r3; + context->regs[4] = uc->uc_mcontext.arm_r4; + context->regs[5] = uc->uc_mcontext.arm_r5; + context->regs[6] = uc->uc_mcontext.arm_r6; + context->regs[7] = uc->uc_mcontext.arm_r7; + context->regs[8] = uc->uc_mcontext.arm_r8; + context->regs[9] = uc->uc_mcontext.arm_r9; + context->regs[10] = uc->uc_mcontext.arm_r10; + context->regs[11] = uc->uc_mcontext.arm_fp; + context->regs[12] = uc->uc_mcontext.arm_ip; + context->regs[13] = uc->uc_mcontext.arm_sp; + context->regs[14] = uc->uc_mcontext.arm_lr; + context->regs[15] = uc->uc_mcontext.arm_pc; +#elif defined(__mips__) + context->uc_mcontext.sp = uc->sp; + context->uc_mcontext.pc = uc->pc; + context->uc_mcontext.ra = uc->ra; +#elif defined(__i386__) + context->uc_mcontext.gregs[REG_EBP] = uc->uc_mcontext.gregs[REG_EBP]; + context->uc_mcontext.gregs[REG_ESP] = uc->uc_mcontext.gregs[REG_ESP]; + context->uc_mcontext.gregs[REG_EIP] = uc->uc_mcontext.gregs[REG_EIP]; +#endif +} + +//------------------------------------------------------------------------- +// UnwindThread functions. +//------------------------------------------------------------------------- +UnwindThread::UnwindThread() { +} + +UnwindThread::~UnwindThread() { +} + +bool UnwindThread::Init() { + return true; +} + +void UnwindThread::ThreadUnwind( + siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) { + ExtractContext(sigcontext); + UnwindFromContext(num_ignore_frames, false); +} + +//------------------------------------------------------------------------- +// C++ object creation function. +//------------------------------------------------------------------------- +Backtrace* CreateCurrentObj() { + return new BacktraceCurrent(new UnwindCurrent()); +} + +Backtrace* CreateThreadObj(pid_t tid) { + UnwindThread* thread_obj = new UnwindThread(); + return new BacktraceThread(thread_obj, thread_obj, tid); +} diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h new file mode 100644 index 0000000..7dc977d --- /dev/null +++ b/libbacktrace/UnwindCurrent.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_UNWIND_CURRENT_H +#define _LIBBACKTRACE_UNWIND_CURRENT_H + +#include <string> + +#include "Backtrace.h" +#include "BacktraceThread.h" + +#define UNW_LOCAL_ONLY +#include <libunwind.h> + +class UnwindCurrent : public BacktraceImpl { +public: + UnwindCurrent(); + virtual ~UnwindCurrent(); + + virtual bool Unwind(size_t num_ignore_frames); + + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + + bool UnwindFromContext(size_t num_ignore_frames, bool resolve); + + void ExtractContext(void* sigcontext); + +protected: + unw_context_t context_; +}; + +class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface { +public: + UnwindThread(); + virtual ~UnwindThread(); + + virtual bool Init(); + + virtual void ThreadUnwind( + siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames); +}; + +#endif // _LIBBACKTRACE_UNWIND_CURRENT_H diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp new file mode 100644 index 0000000..a734a24 --- /dev/null +++ b/libbacktrace/UnwindPtrace.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "libbacktrace" + +#include <backtrace/backtrace.h> + +#include <sys/types.h> +#include <string.h> + +#include <cutils/log.h> + +#include <libunwind.h> +#include <libunwind-ptrace.h> + +#include "UnwindPtrace.h" + +UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) { +} + +UnwindPtrace::~UnwindPtrace() { + if (upt_info_) { + _UPT_destroy(upt_info_); + upt_info_ = NULL; + } + if (addr_space_) { + unw_destroy_addr_space(addr_space_); + addr_space_ = NULL; + } +} + +bool UnwindPtrace::Unwind(size_t num_ignore_frames) { + addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); + if (!addr_space_) { + BACK_LOGW("unw_create_addr_space failed."); + return false; + } + + upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid())); + if (!upt_info_) { + BACK_LOGW("Failed to create upt info."); + return false; + } + + backtrace_t* backtrace = GetBacktraceData(); + backtrace->num_frames = 0; + + unw_cursor_t cursor; + int ret = unw_init_remote(&cursor, addr_space_, upt_info_); + if (ret < 0) { + BACK_LOGW("unw_init_remote failed %d", ret); + return false; + } + + do { + unw_word_t pc; + ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); + if (ret < 0) { + BACK_LOGW("Failed to read IP %d", ret); + break; + } + unw_word_t sp; + ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); + if (ret < 0) { + BACK_LOGW("Failed to read SP %d", ret); + break; + } + + if (num_ignore_frames == 0) { + size_t num_frames = backtrace->num_frames; + backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; + frame->pc = static_cast<uintptr_t>(pc); + frame->sp = static_cast<uintptr_t>(sp); + frame->stack_size = 0; + frame->map_name = NULL; + frame->map_offset = 0; + frame->func_name = NULL; + frame->func_offset = 0; + + if (num_frames > 0) { + backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; + prev->stack_size = frame->sp - prev->sp; + } + + std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); + if (!func_name.empty()) { + frame->func_name = strdup(func_name.c_str()); + } + + uintptr_t map_start; + frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); + if (frame->map_name) { + frame->map_offset = frame->pc - map_start; + } + + backtrace->num_frames++; + } else { + num_ignore_frames--; + } + ret = unw_step (&cursor); + } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); + + return true; +} + +std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { + *offset = 0; + char buf[512]; + unw_word_t value; + if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value, + upt_info_) >= 0 && buf[0] != '\0') { + *offset = static_cast<uintptr_t>(value); + return buf; + } + return ""; +} + +//------------------------------------------------------------------------- +// C++ object creation function. +//------------------------------------------------------------------------- +Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) { + return new BacktracePtrace(new UnwindPtrace(), pid, tid); +} diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h new file mode 100644 index 0000000..781405b --- /dev/null +++ b/libbacktrace/UnwindPtrace.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_UNWIND_PTRACE_H +#define _LIBBACKTRACE_UNWIND_PTRACE_H + +#include <string> + +#include "Backtrace.h" + +#include <libunwind.h> + +class UnwindPtrace : public BacktraceImpl { +public: + UnwindPtrace(); + virtual ~UnwindPtrace(); + + virtual bool Unwind(size_t num_ignore_frames); + + virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + +private: + unw_addr_space_t addr_space_; + struct UPT_info* upt_info_; +}; + +#endif // _LIBBACKTRACE_UNWIND_PTRACE_H diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp new file mode 100644 index 0000000..2603e1f --- /dev/null +++ b/libbacktrace/backtrace_test.cpp @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dirent.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#include <backtrace/backtrace.h> + +#include <cutils/atomic.h> +#include <gtest/gtest.h> + +#include <vector> + +#include "thread_utils.h" + +// Number of microseconds per milliseconds. +#define US_PER_MSEC 1000 + +// Number of nanoseconds in a second. +#define NS_PER_SEC 1000000000ULL + +// Number of simultaneous dumping operations to perform. +#define NUM_THREADS 20 + +// Number of simultaneous threads running in our forked process. +#define NUM_PTRACE_THREADS 5 + +typedef struct { + pid_t tid; + int32_t state; + pthread_t threadId; +} thread_t; + +typedef struct { + thread_t thread; + backtrace_context_t context; + int32_t* now; + int32_t done; +} dump_thread_t; + +extern "C" { +// Prototypes for functions in the test library. +int test_level_one(int, int, int, int, void (*)(void*), void*); + +int test_recursive_call(int, void (*)(void*), void*); +} + +uint64_t NanoTime() { + struct timespec t = { 0, 0 }; + clock_gettime(CLOCK_MONOTONIC, &t); + return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec); +} + +void DumpFrames(const backtrace_context_t* context) { + if (context->backtrace->num_frames == 0) { + printf(" No frames to dump\n"); + } else { + char line[512]; + for (size_t i = 0; i < context->backtrace->num_frames; i++) { + backtrace_format_frame_data(context, i, line, sizeof(line)); + printf(" %s\n", line); + } + } +} + +void WaitForStop(pid_t pid) { + uint64_t start = NanoTime(); + + siginfo_t si; + while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) { + if ((NanoTime() - start) > NS_PER_SEC) { + printf("The process did not get to a stopping point in 1 second.\n"); + break; + } + usleep(US_PER_MSEC); + } +} + +bool ReadyLevelBacktrace(const backtrace_t* backtrace) { + // See if test_level_four is in the backtrace. + bool found = false; + for (size_t i = 0; i < backtrace->num_frames; i++) { + if (backtrace->frames[i].func_name != NULL && + strcmp(backtrace->frames[i].func_name, "test_level_four") == 0) { + found = true; + break; + } + } + + return found; +} + +void VerifyLevelDump(const backtrace_t* backtrace) { + ASSERT_GT(backtrace->num_frames, static_cast<size_t>(0)); + ASSERT_LT(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES)); + + // Look through the frames starting at the highest to find the + // frame we want. + size_t frame_num = 0; + for (size_t i = backtrace->num_frames-1; i > 2; i--) { + if (backtrace->frames[i].func_name != NULL && + strcmp(backtrace->frames[i].func_name, "test_level_one") == 0) { + frame_num = i; + break; + } + } + ASSERT_GT(frame_num, static_cast<size_t>(0)); + + ASSERT_TRUE(NULL != backtrace->frames[frame_num].func_name); + ASSERT_STREQ(backtrace->frames[frame_num].func_name, "test_level_one"); + ASSERT_TRUE(NULL != backtrace->frames[frame_num-1].func_name); + ASSERT_STREQ(backtrace->frames[frame_num-1].func_name, "test_level_two"); + ASSERT_TRUE(NULL != backtrace->frames[frame_num-2].func_name); + ASSERT_STREQ(backtrace->frames[frame_num-2].func_name, "test_level_three"); + ASSERT_TRUE(NULL != backtrace->frames[frame_num-3].func_name); + ASSERT_STREQ(backtrace->frames[frame_num-3].func_name, "test_level_four"); +} + +void VerifyLevelBacktrace(void*) { + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0)); + + VerifyLevelDump(context.backtrace); + + backtrace_destroy_context(&context); +} + +bool ReadyMaxBacktrace(const backtrace_t* backtrace) { + return (backtrace->num_frames == MAX_BACKTRACE_FRAMES); +} + +void VerifyMaxDump(const backtrace_t* backtrace) { + ASSERT_EQ(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES)); + // Verify that the last frame is our recursive call. + ASSERT_TRUE(NULL != backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name); + ASSERT_STREQ(backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name, + "test_recursive_call"); +} + +void VerifyMaxBacktrace(void*) { + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0)); + + VerifyMaxDump(context.backtrace); + + backtrace_destroy_context(&context); +} + +void ThreadSetState(void* data) { + thread_t* thread = reinterpret_cast<thread_t*>(data); + android_atomic_acquire_store(1, &thread->state); + volatile int i = 0; + while (thread->state) { + i++; + } +} + +void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(const backtrace_t*)) { + backtrace_context_t context; + + backtrace_create_context(&context, getpid(), tid, 0); + + VerifyFunc(context.backtrace); + + backtrace_destroy_context(&context); +} + +bool WaitForNonZero(int32_t* value, uint64_t seconds) { + uint64_t start = NanoTime(); + do { + if (android_atomic_acquire_load(value)) { + return true; + } + } while ((NanoTime() - start) < seconds * NS_PER_SEC); + return false; +} + +TEST(libbacktrace, local_trace) { + ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0); +} + +void VerifyIgnoreFrames( + const backtrace_t* bt_all, const backtrace_t* bt_ign1, + const backtrace_t* bt_ign2, const char* cur_proc) { + EXPECT_EQ(bt_all->num_frames, bt_ign1->num_frames + 1); + EXPECT_EQ(bt_all->num_frames, bt_ign2->num_frames + 2); + + // Check all of the frames are the same > the current frame. + bool check = (cur_proc == NULL); + for (size_t i = 0; i < bt_ign2->num_frames; i++) { + if (check) { + EXPECT_EQ(bt_ign2->frames[i].pc, bt_ign1->frames[i+1].pc); + EXPECT_EQ(bt_ign2->frames[i].sp, bt_ign1->frames[i+1].sp); + EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_ign1->frames[i+1].stack_size); + + EXPECT_EQ(bt_ign2->frames[i].pc, bt_all->frames[i+2].pc); + EXPECT_EQ(bt_ign2->frames[i].sp, bt_all->frames[i+2].sp); + EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_all->frames[i+2].stack_size); + } + if (!check && bt_ign2->frames[i].func_name && + strcmp(bt_ign2->frames[i].func_name, cur_proc) == 0) { + check = true; + } + } +} + +void VerifyLevelIgnoreFrames(void*) { + backtrace_context_t all; + ASSERT_TRUE(backtrace_create_context(&all, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0)); + ASSERT_TRUE(all.backtrace != NULL); + + backtrace_context_t ign1; + ASSERT_TRUE(backtrace_create_context(&ign1, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 1)); + ASSERT_TRUE(ign1.backtrace != NULL); + + backtrace_context_t ign2; + ASSERT_TRUE(backtrace_create_context(&ign2, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 2)); + ASSERT_TRUE(ign2.backtrace != NULL); + + VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace, + "VerifyLevelIgnoreFrames"); + + backtrace_destroy_context(&all); + backtrace_destroy_context(&ign1); + backtrace_destroy_context(&ign2); +} + +TEST(libbacktrace, local_trace_ignore_frames) { + ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0); +} + +TEST(libbacktrace, local_max_trace) { + ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0); +} + +void VerifyProcTest(pid_t pid, pid_t tid, + bool (*ReadyFunc)(const backtrace_t*), + void (*VerifyFunc)(const backtrace_t*)) { + pid_t ptrace_tid; + if (tid < 0) { + ptrace_tid = pid; + } else { + ptrace_tid = tid; + } + uint64_t start = NanoTime(); + bool verified = false; + do { + usleep(US_PER_MSEC); + if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) { + // Wait for the process to get to a stopping point. + WaitForStop(ptrace_tid); + + backtrace_context_t context; + ASSERT_TRUE(backtrace_create_context(&context, pid, tid, 0)); + if (ReadyFunc(context.backtrace)) { + VerifyFunc(context.backtrace); + verified = true; + } + backtrace_destroy_context(&context); + ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0); + } + // If 5 seconds have passed, then we are done. + } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC); + ASSERT_TRUE(verified); +} + +TEST(libbacktrace, ptrace_trace) { + pid_t pid; + if ((pid = fork()) == 0) { + ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + exit(1); + } + VerifyProcTest(pid, BACKTRACE_NO_TID, ReadyLevelBacktrace, VerifyLevelDump); + + kill(pid, SIGKILL); + int status; + ASSERT_EQ(waitpid(pid, &status, 0), pid); +} + +TEST(libbacktrace, ptrace_max_trace) { + pid_t pid; + if ((pid = fork()) == 0) { + ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0); + exit(1); + } + VerifyProcTest(pid, BACKTRACE_NO_TID, ReadyMaxBacktrace, VerifyMaxDump); + + kill(pid, SIGKILL); + int status; + ASSERT_EQ(waitpid(pid, &status, 0), pid); +} + +void VerifyProcessIgnoreFrames(const backtrace_t* bt_all) { + pid_t pid = bt_all->pid; + + backtrace_context_t ign1; + ASSERT_TRUE(backtrace_create_context(&ign1, pid, BACKTRACE_NO_TID, 1)); + ASSERT_TRUE(ign1.backtrace != NULL); + + backtrace_context_t ign2; + ASSERT_TRUE(backtrace_create_context(&ign2, pid, BACKTRACE_NO_TID, 2)); + ASSERT_TRUE(ign2.backtrace != NULL); + + VerifyIgnoreFrames(bt_all, ign1.backtrace, ign2.backtrace, NULL); + + backtrace_destroy_context(&ign1); + backtrace_destroy_context(&ign2); +} + +TEST(libbacktrace, ptrace_ignore_frames) { + pid_t pid; + if ((pid = fork()) == 0) { + ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + exit(1); + } + VerifyProcTest(pid, BACKTRACE_NO_TID, ReadyLevelBacktrace, VerifyProcessIgnoreFrames); + + kill(pid, SIGKILL); + int status; + ASSERT_EQ(waitpid(pid, &status, 0), pid); +} + +// Create a process with multiple threads and dump all of the threads. +void* PtraceThreadLevelRun(void*) { + EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + return NULL; +} + +void GetThreads(pid_t pid, std::vector<pid_t>* threads) { + // Get the list of tasks. + char task_path[128]; + snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); + + DIR* tasks_dir = opendir(task_path); + ASSERT_TRUE(tasks_dir != NULL); + struct dirent* entry; + while ((entry = readdir(tasks_dir)) != NULL) { + char* end; + pid_t tid = strtoul(entry->d_name, &end, 10); + if (*end == '\0') { + threads->push_back(tid); + } + } + closedir(tasks_dir); +} + +TEST(libbacktrace, ptrace_threads) { + pid_t pid; + if ((pid = fork()) == 0) { + for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthread_t thread; + ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0); + } + ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0); + exit(1); + } + + // Check to see that all of the threads are running before unwinding. + std::vector<pid_t> threads; + uint64_t start = NanoTime(); + do { + usleep(US_PER_MSEC); + threads.clear(); + GetThreads(pid, &threads); + } while ((threads.size() != NUM_PTRACE_THREADS + 1) && + ((NanoTime() - start) <= 5 * NS_PER_SEC)); + ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1)); + + ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0); + WaitForStop(pid); + for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) { + // Skip the current forked process, we only care about the threads. + if (pid == *it) { + continue; + } + VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump); + } + ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); + + kill(pid, SIGKILL); + int status; + ASSERT_EQ(waitpid(pid, &status, 0), pid); +} + +void VerifyLevelThread(void*) { + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0)); + + VerifyLevelDump(context.backtrace); + + backtrace_destroy_context(&context); +} + +TEST(libbacktrace, thread_current_level) { + ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0); +} + +void VerifyMaxThread(void*) { + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0)); + + VerifyMaxDump(context.backtrace); + + backtrace_destroy_context(&context); +} + +TEST(libbacktrace, thread_current_max) { + ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0); +} + +void* ThreadLevelRun(void* data) { + thread_t* thread = reinterpret_cast<thread_t*>(data); + + thread->tid = gettid(); + EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0); + return NULL; +} + +TEST(libbacktrace, thread_level_trace) { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + thread_t thread_data = { 0, 0, 0 }; + pthread_t thread; + ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0); + + // Wait up to 2 seconds for the tid to be set. + ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); + + // Save the current signal action and make sure it is restored afterwards. + struct sigaction cur_action; + ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0); + + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid,0)); + + VerifyLevelDump(context.backtrace); + + backtrace_destroy_context(&context); + + // Tell the thread to exit its infinite loop. + android_atomic_acquire_store(0, &thread_data.state); + + // Verify that the old action was restored. + struct sigaction new_action; + ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0); + EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction); + EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags); +} + +TEST(libbacktrace, thread_ignore_frames) { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + thread_t thread_data = { 0, 0, 0 }; + pthread_t thread; + ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0); + + // Wait up to 2 seconds for the tid to be set. + ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); + + backtrace_context_t all; + ASSERT_TRUE(backtrace_create_context(&all, getpid(), thread_data.tid, 0)); + + backtrace_context_t ign1; + ASSERT_TRUE(backtrace_create_context(&ign1, getpid(), thread_data.tid, 1)); + + backtrace_context_t ign2; + ASSERT_TRUE(backtrace_create_context(&ign2, getpid(), thread_data.tid, 2)); + + VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace, NULL); + + backtrace_destroy_context(&all); + backtrace_destroy_context(&ign1); + backtrace_destroy_context(&ign2); + + // Tell the thread to exit its infinite loop. + android_atomic_acquire_store(0, &thread_data.state); +} + +void* ThreadMaxRun(void* data) { + thread_t* thread = reinterpret_cast<thread_t*>(data); + + thread->tid = gettid(); + EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0); + return NULL; +} + +TEST(libbacktrace, thread_max_trace) { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + thread_t thread_data = { 0, 0, 0 }; + pthread_t thread; + ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0); + + // Wait for the tid to be set. + ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); + + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid, 0)); + + VerifyMaxDump(context.backtrace); + + backtrace_destroy_context(&context); + + // Tell the thread to exit its infinite loop. + android_atomic_acquire_store(0, &thread_data.state); +} + +void* ThreadDump(void* data) { + dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data); + while (true) { + if (android_atomic_acquire_load(dump->now)) { + break; + } + } + + dump->context.data = NULL; + dump->context.backtrace = NULL; + + // The status of the actual unwind will be checked elsewhere. + backtrace_create_context(&dump->context, getpid(), dump->thread.tid, 0); + + android_atomic_acquire_store(1, &dump->done); + + return NULL; +} + +TEST(libbacktrace, thread_multiple_dump) { + // Dump NUM_THREADS simultaneously. + std::vector<thread_t> runners(NUM_THREADS); + std::vector<dump_thread_t> dumpers(NUM_THREADS); + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + for (size_t i = 0; i < NUM_THREADS; i++) { + // Launch the runners, they will spin in hard loops doing nothing. + runners[i].tid = 0; + runners[i].state = 0; + ASSERT_TRUE(pthread_create(&runners[i].threadId, &attr, ThreadMaxRun, &runners[i]) == 0); + } + + // Wait for tids to be set. + for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) { + ASSERT_TRUE(WaitForNonZero(&it->state, 10)); + } + + // Start all of the dumpers at once, they will spin until they are signalled + // to begin their dump run. + int32_t dump_now = 0; + for (size_t i = 0; i < NUM_THREADS; i++) { + dumpers[i].thread.tid = runners[i].tid; + dumpers[i].thread.state = 0; + dumpers[i].done = 0; + dumpers[i].now = &dump_now; + + ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0); + } + + // Start all of the dumpers going at once. + android_atomic_acquire_store(1, &dump_now); + + for (size_t i = 0; i < NUM_THREADS; i++) { + ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10)); + + // Tell the runner thread to exit its infinite loop. + android_atomic_acquire_store(0, &runners[i].state); + + ASSERT_TRUE(dumpers[i].context.backtrace != NULL); + VerifyMaxDump(dumpers[i].context.backtrace); + backtrace_destroy_context(&dumpers[i].context); + } +} + +TEST(libbacktrace, format_test) { + backtrace_context_t context; + + ASSERT_TRUE(backtrace_create_context(&context, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0)); + ASSERT_TRUE(context.backtrace != NULL); + + backtrace_frame_data_t* frame = const_cast<backtrace_frame_data_t*>(&context.backtrace->frames[1]); + backtrace_frame_data_t save_frame = *frame; + + memset(frame, 0, sizeof(backtrace_frame_data_t)); + char buf[512]; + backtrace_format_frame_data(&context, 1, buf, sizeof(buf)); +#if defined(__LP64__) + EXPECT_STREQ(buf, "#01 pc 0000000000000000 <unknown>"); +#else + EXPECT_STREQ(buf, "#01 pc 00000000 <unknown>"); +#endif + + frame->pc = 0x12345678; + frame->map_name = "MapFake"; + backtrace_format_frame_data(&context, 1, buf, sizeof(buf)); +#if defined(__LP64__) + EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake"); +#else + EXPECT_STREQ(buf, "#01 pc 12345678 MapFake"); +#endif + + frame->func_name = const_cast<char*>("ProcFake"); + backtrace_format_frame_data(&context, 1, buf, sizeof(buf)); +#if defined(__LP64__) + EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake (ProcFake)"); +#else + EXPECT_STREQ(buf, "#01 pc 12345678 MapFake (ProcFake)"); +#endif + + frame->func_offset = 645; + backtrace_format_frame_data(&context, 1, buf, sizeof(buf)); +#if defined(__LP64__) + EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake (ProcFake+645)"); +#else + EXPECT_STREQ(buf, "#01 pc 12345678 MapFake (ProcFake+645)"); +#endif + + *frame = save_frame; + + backtrace_destroy_context(&context); +} diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c new file mode 100644 index 0000000..d4d15db --- /dev/null +++ b/libbacktrace/backtrace_testlib.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> + +int test_level_four(int one, int two, int three, int four, + void (*callback_func)(void*), void* data) { + if (callback_func != NULL) { + callback_func(data); + } else { + while (1) { + } + } + return one + two + three + four; +} + +int test_level_three(int one, int two, int three, int four, + void (*callback_func)(void*), void* data) { + return test_level_four(one+3, two+6, three+9, four+12, callback_func, data) + 3; +} + +int test_level_two(int one, int two, int three, int four, + void (*callback_func)(void*), void* data) { + return test_level_three(one+2, two+4, three+6, four+8, callback_func, data) + 2; +} + +int test_level_one(int one, int two, int three, int four, + void (*callback_func)(void*), void* data) { + return test_level_two(one+1, two+2, three+3, four+4, callback_func, data) + 1; +} + +int test_recursive_call(int level, void (*callback_func)(void*), void* data) { + if (level > 0) { + return test_recursive_call(level - 1, callback_func, data) + level; + } else if (callback_func != NULL) { + callback_func(data); + } else { + while (1) { + } + } + return 0; +} diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c new file mode 100644 index 0000000..9cc6e01 --- /dev/null +++ b/libbacktrace/map_info.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <pthread.h> +#include <unistd.h> +#include <cutils/log.h> +#include <sys/time.h> + +#include <backtrace/backtrace.h> + +#if defined(__APPLE__) + +// Mac OS vmmap(1) output: +// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 +static backtrace_map_info_t* parse_vmmap_line(const char* line) { + unsigned long int start; + unsigned long int end; + char permissions[4]; + int name_pos; + if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n", + &start, &end, permissions, &name_pos) != 3) { + return NULL; + } + + const char* name = line + name_pos; + size_t name_len = strlen(name); + + backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len); + if (mi != NULL) { + mi->start = start; + mi->end = end; + mi->is_readable = permissions[0] == 'r'; + mi->is_writable = permissions[1] == 'w'; + mi->is_executable = permissions[2] == 'x'; + memcpy(mi->name, name, name_len); + mi->name[name_len - 1] = '\0'; + ALOGV("Parsed map: start=0x%08x, end=0x%08x, " + "is_readable=%d, is_writable=%d is_executable=%d, name=%s", + mi->start, mi->end, + mi->is_readable, mi->is_writable, mi->is_executable, mi->name); + } + return mi; +} + +backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) { + char cmd[1024]; + if (pid < 0) { + pid = getpid(); + } + snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid); + FILE* fp = popen(cmd, "r"); + if (fp == NULL) { + return NULL; + } + + char line[1024]; + backtrace_map_info_t* milist = NULL; + while (fgets(line, sizeof(line), fp) != NULL) { + backtrace_map_info_t* mi = parse_vmmap_line(line); + if (mi != NULL) { + mi->next = milist; + milist = mi; + } + } + pclose(fp); + return milist; +} + +#else + +// Linux /proc/<pid>/maps lines: +// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 +static backtrace_map_info_t* parse_maps_line(const char* line) +{ + unsigned long int start; + unsigned long int end; + char permissions[5]; + int name_pos; + if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end, + permissions, &name_pos) != 3) { + return NULL; + } + + while (isspace(line[name_pos])) { + name_pos += 1; + } + const char* name = line + name_pos; + size_t name_len = strlen(name); + if (name_len && name[name_len - 1] == '\n') { + name_len -= 1; + } + + backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1); + if (mi) { + mi->start = start; + mi->end = end; + mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r'; + mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w'; + mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x'; + memcpy(mi->name, name, name_len); + mi->name[name_len] = '\0'; + ALOGV("Parsed map: start=0x%08x, end=0x%08x, " + "is_readable=%d, is_writable=%d, is_executable=%d, name=%s", + mi->start, mi->end, + mi->is_readable, mi->is_writable, mi->is_executable, mi->name); + } + return mi; +} + +backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) { + char path[PATH_MAX]; + char line[1024]; + FILE* fp; + backtrace_map_info_t* milist = NULL; + + if (tid < 0) { + tid = getpid(); + } + snprintf(path, PATH_MAX, "/proc/%d/maps", tid); + fp = fopen(path, "r"); + if (fp) { + while(fgets(line, sizeof(line), fp)) { + backtrace_map_info_t* mi = parse_maps_line(line); + if (mi) { + mi->next = milist; + milist = mi; + } + } + fclose(fp); + } + return milist; +} + +#endif + +void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) { + while (milist) { + backtrace_map_info_t* next = milist->next; + free(milist); + milist = next; + } +} + +const backtrace_map_info_t* backtrace_find_map_info( + const backtrace_map_info_t* milist, uintptr_t addr) { + const backtrace_map_info_t* mi = milist; + while (mi && !(addr >= mi->start && addr < mi->end)) { + mi = mi->next; + } + return mi; +} diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c new file mode 100644 index 0000000..6f4cd3c --- /dev/null +++ b/libbacktrace/thread_utils.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "thread_utils.h" + +#if defined(__APPLE__) + +#include <sys/syscall.h> + +// Mac OS >= 10.6 has a system call equivalent to Linux's gettid(). +pid_t gettid() { + return syscall(SYS_thread_selfid); +} + +#elif !defined(__BIONIC__) + +// glibc doesn't implement or export either gettid or tgkill. +#include <unistd.h> +#include <sys/syscall.h> + +pid_t gettid() { + return syscall(__NR_gettid); +} + +int tgkill(int tgid, int tid, int sig) { + return syscall(__NR_tgkill, tgid, tid, sig); +} + +#endif diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h new file mode 100644 index 0000000..ae4c929 --- /dev/null +++ b/libbacktrace/thread_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBBACKTRACE_THREAD_UTILS_H +#define _LIBBACKTRACE_THREAD_UTILS_H + +#include <unistd.h> + +__BEGIN_DECLS + +int tgkill(int tgid, int tid, int sig); + +pid_t gettid(); + +__END_DECLS + +#endif /* _LIBBACKTRACE_THREAD_UTILS_H */ diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk index d62c2d5..e275317 100644 --- a/libcorkscrew/Android.mk +++ b/libcorkscrew/Android.mk @@ -51,7 +51,7 @@ endif LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle -LOCAL_CFLAGS += -std=gnu99 -Werror +LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter LOCAL_MODULE := libcorkscrew LOCAL_MODULE_TAGS := optional @@ -81,7 +81,7 @@ ifeq ($(HOST_OS),linux) LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux? LOCAL_LDLIBS += -lrt endif -LOCAL_CFLAGS += -std=gnu99 -Werror +LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter LOCAL_MODULE := libcorkscrew LOCAL_MODULE_TAGS := optional include $(BUILD_HOST_SHARED_LIBRARY) diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c index e133ab6..ef22821 100755 --- a/libcorkscrew/arch-x86/backtrace-x86.c +++ b/libcorkscrew/arch-x86/backtrace-x86.c @@ -380,7 +380,7 @@ static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie case DW_CFA_offset_extended: // probably we don't have it on x86. if (!try_get_uleb128(memory, ptr, ®, cursor)) return false; if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false; - if (reg > DWARF_REGISTERS) { + if (reg >= DWARF_REGISTERS) { ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS); return false; } @@ -390,39 +390,39 @@ static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie break; case DW_CFA_restore_extended: // probably we don't have it on x86. if (!try_get_uleb128(memory, ptr, ®, cursor)) return false; - dstate->regs[reg].rule = stack->regs[reg].rule; - dstate->regs[reg].value = stack->regs[reg].value; - if (reg > DWARF_REGISTERS) { + if (reg >= DWARF_REGISTERS) { ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS); return false; } + dstate->regs[reg].rule = stack->regs[reg].rule; + dstate->regs[reg].value = stack->regs[reg].value; ALOGV("DW_CFA_restore: r%d = %c(%d)", reg, dstate->regs[reg].rule, dstate->regs[reg].value); break; case DW_CFA_undefined: // probably we don't have it on x86. if (!try_get_uleb128(memory, ptr, ®, cursor)) return false; - dstate->regs[reg].rule = 'u'; - dstate->regs[reg].value = 0; - if (reg > DWARF_REGISTERS) { + if (reg >= DWARF_REGISTERS) { ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS); return false; } + dstate->regs[reg].rule = 'u'; + dstate->regs[reg].value = 0; ALOGV("DW_CFA_undefined: r%d", reg); break; case DW_CFA_same_value: // probably we don't have it on x86. if (!try_get_uleb128(memory, ptr, ®, cursor)) return false; - dstate->regs[reg].rule = 's'; - dstate->regs[reg].value = 0; - if (reg > DWARF_REGISTERS) { + if (reg >= DWARF_REGISTERS) { ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS); return false; } + dstate->regs[reg].rule = 's'; + dstate->regs[reg].value = 0; ALOGV("DW_CFA_same_value: r%d", reg); break; case DW_CFA_register: // probably we don't have it on x86. if (!try_get_uleb128(memory, ptr, ®, cursor)) return false; /* that's new register actually, not offset */ if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false; - if (reg > DWARF_REGISTERS || offset > DWARF_REGISTERS) { + if (reg >= DWARF_REGISTERS || offset >= DWARF_REGISTERS) { ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS); return false; } @@ -520,7 +520,7 @@ static bool get_old_register_value(const memory_t* memory, uint32_t cfa, /* Updaing state based on dwarf state. */ static bool update_state(const memory_t* memory, unwind_state_t* state, - dwarf_state_t* dstate, cie_info_t* cie_info) { + dwarf_state_t* dstate) { unwind_state_t newstate; /* We can restore more registers here if we need them. Meanwile doing minimal work here. */ /* Getting CFA. */ @@ -550,7 +550,6 @@ static bool update_state(const memory_t* memory, unwind_state_t* state, /* Execute CIE and FDE instructions for FDE found with find_fde. */ static bool execute_fde(const memory_t* memory, - const map_info_t* map_info_list, uintptr_t fde, unwind_state_t* state) { uint32_t fde_length = 0; @@ -753,7 +752,7 @@ static bool execute_fde(const memory_t* memory, ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc); } - return update_state(memory, state, dstate, cie_info); + return update_state(memory, state, dstate); } static ssize_t unwind_backtrace_common(const memory_t* memory, @@ -805,7 +804,7 @@ static ssize_t unwind_backtrace_common(const memory_t* memory, uint32_t stack_top = state->reg[DWARF_ESP]; - if (!execute_fde(memory, map_info_list, fde, state)) break; + if (!execute_fde(memory, fde, state)) break; if (frame) { frame->stack_top = stack_top; diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 0fd5a57..f8dda36 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -96,11 +96,6 @@ include $(BUILD_HOST_STATIC_LIBRARY) # Shared and static library for target # ======================================================== -# This is needed in LOCAL_C_INCLUDES to access the C library's private -# header named <bionic_time.h> -# -libcutils_c_includes := bionic/libc/private - include $(CLEAR_VARS) LOCAL_MODULE := libcutils LOCAL_SRC_FILES := $(commonSources) \ @@ -115,18 +110,18 @@ LOCAL_SRC_FILES := $(commonSources) \ uevent.c ifeq ($(TARGET_ARCH),arm) -LOCAL_SRC_FILES += arch-arm/memset32.S + LOCAL_SRC_FILES += arch-arm/memset32.S else # !arm -ifeq ($(TARGET_ARCH_VARIANT),x86-atom) -LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c -else # !x86-atom -ifeq ($(TARGET_ARCH),mips) -LOCAL_SRC_FILES += arch-mips/android_memset.c -else # !mips -LOCAL_SRC_FILES += memory.c -endif # !mips -endif # !x86-atom + ifeq ($(TARGET_ARCH),x86) + LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32 + LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c + else # !x86 + ifeq ($(TARGET_ARCH),mips) + LOCAL_SRC_FILES += arch-mips/android_memset.c + else # !mips + LOCAL_SRC_FILES += memory.c + endif # !mips + endif # !x86 endif # !arm LOCAL_C_INCLUDES := $(libcutils_c_includes) $(KERNEL_HEADERS) diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c index 16f82bb..aef3054 100644 --- a/libcutils/android_reboot.c +++ b/libcutils/android_reboot.c @@ -16,6 +16,7 @@ #include <unistd.h> #include <sys/reboot.h> +#include <sys/syscall.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -118,7 +119,7 @@ int android_reboot(int cmd, int flags, char *arg) break; case ANDROID_RB_RESTART2: - ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg); break; diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S index b1f09cb..f8b79bd 100644 --- a/libcutils/arch-x86/android_memset16.S +++ b/libcutils/arch-x86/android_memset16.S @@ -17,16 +17,9 @@ * Contributed by: Intel Corporation */ -#if defined(USE_SSE2) - # include "cache_wrapper.S" # undef __i686 # define USE_AS_ANDROID # define sse2_memset16_atom android_memset16 # include "sse2-memset16-atom.S" -#else - -# include "memset16.S" - -#endif diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S index 1fb2ffe..6249fce 100644 --- a/libcutils/arch-x86/android_memset32.S +++ b/libcutils/arch-x86/android_memset32.S @@ -17,17 +17,9 @@ * Contributed by: Intel Corporation */ -#if defined(USE_SSE2) - # include "cache_wrapper.S" # undef __i686 # define USE_AS_ANDROID # define sse2_memset32_atom android_memset32 # include "sse2-memset32-atom.S" -#else - -# include "memset32.S" - -#endif - diff --git a/libcutils/arch-x86/sse2-memset16-atom.S b/libcutils/arch-x86/sse2-memset16-atom.S index cafec82..c2a762b 100644..100755 --- a/libcutils/arch-x86/sse2-memset16-atom.S +++ b/libcutils/arch-x86/sse2-memset16-atom.S @@ -86,7 +86,7 @@ name: \ # define SETRTNVAL movl DEST(%esp), %eax #endif -#ifdef SHARED +#if (defined SHARED || defined __PIC__) # define ENTRANCE PUSH (%ebx); # define RETURN_END POP (%ebx); ret # define RETURN RETURN_END; CFI_PUSH (%ebx) @@ -344,7 +344,7 @@ L(128bytesormore): PUSH (%ebx) mov $SHARED_CACHE_SIZE, %ebx #else -# ifdef SHARED +# if (defined SHARED || defined __PIC__) call __i686.get_pc_thunk.bx add $_GLOBAL_OFFSET_TABLE_, %ebx mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx @@ -362,7 +362,7 @@ L(128bytesormore): # define RESTORE_EBX_STATE CFI_PUSH (%ebx) cmp $DATA_CACHE_SIZE, %ecx #else -# ifdef SHARED +# if (defined SHARED || defined __PIC__) # define RESTORE_EBX_STATE call __i686.get_pc_thunk.bx add $_GLOBAL_OFFSET_TABLE_, %ebx @@ -471,7 +471,7 @@ L(128bytesormore_nt): jae L(128bytesormore_nt) sfence L(shared_cache_loop_end): -#if defined DATA_CACHE_SIZE || !defined SHARED +#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__) POP (%ebx) #endif add %ecx, %edx diff --git a/libcutils/arch-x86/sse2-memset32-atom.S b/libcutils/arch-x86/sse2-memset32-atom.S index 4a52484..05eb64f 100644..100755 --- a/libcutils/arch-x86/sse2-memset32-atom.S +++ b/libcutils/arch-x86/sse2-memset32-atom.S @@ -86,7 +86,7 @@ name: \ # define SETRTNVAL #endif -#ifdef SHARED +#if (defined SHARED || defined __PIC__) # define ENTRANCE PUSH (%ebx); # define RETURN_END POP (%ebx); ret # define RETURN RETURN_END; CFI_PUSH (%ebx) @@ -259,7 +259,7 @@ L(128bytesormore): PUSH (%ebx) mov $SHARED_CACHE_SIZE, %ebx #else -# ifdef SHARED +# if (defined SHARED || defined __PIC__) call __i686.get_pc_thunk.bx add $_GLOBAL_OFFSET_TABLE_, %ebx mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx @@ -276,7 +276,7 @@ L(128bytesormore): # define RESTORE_EBX_STATE CFI_PUSH (%ebx) cmp $DATA_CACHE_SIZE, %ecx #else -# ifdef SHARED +# if (defined SHARED || defined __PIC__) # define RESTORE_EBX_STATE call __i686.get_pc_thunk.bx add $_GLOBAL_OFFSET_TABLE_, %ebx @@ -386,7 +386,7 @@ L(128bytesormore_nt): jae L(128bytesormore_nt) sfence L(shared_cache_loop_end): -#if defined DATA_CACHE_SIZE || !defined SHARED +#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__) POP (%ebx) #endif add %ecx, %edx diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c index 8b71f87..3089a94 100644 --- a/libcutils/ashmem-dev.c +++ b/libcutils/ashmem-dev.c @@ -48,7 +48,7 @@ int ashmem_create_region(const char *name, size_t size) return fd; if (name) { - char buf[ASHMEM_NAME_LEN]; + char buf[ASHMEM_NAME_LEN] = {0}; strlcpy(buf, name, sizeof(buf)); ret = ioctl(fd, ASHMEM_SET_NAME, buf); diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c index be14af6..098b5db 100644 --- a/libcutils/dir_hash.c +++ b/libcutils/dir_hash.c @@ -159,6 +159,7 @@ static int recurse(HashAlgorithm algorithm, const char *directory_path, free(name); free(node); + closedir(d); return -1; } diff --git a/libion/ion_test.c b/libion/ion_test.c index 0caaa2a..d2c37ca 100644 --- a/libion/ion_test.c +++ b/libion/ion_test.c @@ -13,7 +13,6 @@ #include <ion/ion.h> #include <linux/ion.h> -#include <linux/omap_ion.h> size_t len = 1024*1024, align = 0; int prot = PROT_READ | PROT_WRITE; diff --git a/liblinenoise/Android.mk b/liblinenoise/Android.mk deleted file mode 100644 index b32a5f1..0000000 --- a/liblinenoise/Android.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# Static library -# ======================================================== - -include $(CLEAR_VARS) -LOCAL_MODULE:= liblinenoise -LOCAL_SRC_FILES := linenoise.c - - -include $(BUILD_STATIC_LIBRARY) diff --git a/liblinenoise/MODULE_LICENSE_BSD_LIKE b/liblinenoise/MODULE_LICENSE_BSD_LIKE deleted file mode 100644 index e69de29..0000000 --- a/liblinenoise/MODULE_LICENSE_BSD_LIKE +++ /dev/null diff --git a/liblinenoise/NOTICE b/liblinenoise/NOTICE deleted file mode 100644 index f61419e..0000000 --- a/liblinenoise/NOTICE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com> -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of Redis nor the names of its contributors may be used - to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/liblinenoise/linenoise.c b/liblinenoise/linenoise.c deleted file mode 100644 index 4f6775c..0000000 --- a/liblinenoise/linenoise.c +++ /dev/null @@ -1,449 +0,0 @@ -/* linenoise.c -- guerrilla line editing library against the idea that a - * line editing lib needs to be 20,000 lines of C code. - * - * You can find the latest source code at: - * - * http://github.com/antirez/linenoise - * - * Does a number of crazy assumptions that happen to be true in 99.9999% of - * the 2010 UNIX computers around. - * - * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * References: - * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html - * - * Todo list: - * - Switch to gets() if $TERM is something we can't support. - * - Filter bogus Ctrl+<char> combinations. - * - Win32 support - * - * Bloat: - * - Completion? - * - History search like Ctrl+r in readline? - * - * List of escape sequences used by this program, we do everything just - * with three sequences. In order to be so cheap we may have some - * flickering effect with some slow terminal, but the lesser sequences - * the more compatible. - * - * CHA (Cursor Horizontal Absolute) - * Sequence: ESC [ n G - * Effect: moves cursor to column n - * - * EL (Erase Line) - * Sequence: ESC [ n K - * Effect: if n is 0 or missing, clear from cursor to end of line - * Effect: if n is 1, clear from beginning of line to cursor - * Effect: if n is 2, clear entire line - * - * CUF (CUrsor Forward) - * Sequence: ESC [ n C - * Effect: moves cursor forward of n chars - * - */ - -#include <termios.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <unistd.h> - -#define LINENOISE_MAX_LINE 4096 -static char *unsupported_term[] = {"dumb","cons25",NULL}; - -static struct termios orig_termios; /* in order to restore at exit */ -static int rawmode = 0; /* for atexit() function to check if restore is needed*/ -static int atexit_registered = 0; /* register atexit just 1 time */ -static int history_max_len = 100; -static int history_len = 0; -char **history = NULL; - -static void linenoiseAtExit(void); -int linenoiseHistoryAdd(const char *line); - -static int isUnsupportedTerm(void) { - char *term = getenv("TERM"); - int j; - - if (term == NULL) return 0; - for (j = 0; unsupported_term[j]; j++) - if (!strcasecmp(term,unsupported_term[j])) return 1; - return 0; -} - -static void freeHistory(void) { - if (history) { - int j; - - for (j = 0; j < history_len; j++) - free(history[j]); - free(history); - } -} - -static int enableRawMode(int fd) { - struct termios raw; - - if (!isatty(STDIN_FILENO)) goto fatal; - if (!atexit_registered) { - atexit(linenoiseAtExit); - atexit_registered = 1; - } - if (tcgetattr(fd,&orig_termios) == -1) goto fatal; - - raw = orig_termios; /* modify the original mode */ - /* input modes: no break, no CR to NL, no parity check, no strip char, - * no start/stop output control. */ - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - /* output modes - disable post processing */ - raw.c_oflag &= ~(OPOST); - /* control modes - set 8 bit chars */ - raw.c_cflag |= (CS8); - /* local modes - choing off, canonical off, no extended functions, - * no signal chars (^Z,^C) */ - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - /* control chars - set return condition: min number of bytes and timer. - * We want read to return every single byte, without timeout. */ - raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ - - /* put terminal in raw mode */ - if (tcsetattr(fd,TCSADRAIN,&raw) < 0) goto fatal; - rawmode = 1; - return 0; - -fatal: - errno = ENOTTY; - return -1; -} - -static void disableRawMode(int fd) { - /* Don't even check the return value as it's too late. */ - if (rawmode && tcsetattr(fd,TCSADRAIN,&orig_termios) != -1) - rawmode = 0; -} - -/* At exit we'll try to fix the terminal to the initial conditions. */ -static void linenoiseAtExit(void) { - disableRawMode(STDIN_FILENO); - freeHistory(); -} - -static int getColumns(void) { - struct winsize ws; - - if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 4096; - if (ws.ws_col == 0) { - return 4096; - } - return ws.ws_col; -} - -static int effectiveLen(const char* prompt) { - int col = 0; - char c; - // TODO: Handle escape sequences. - while ( (c = *prompt++) != 0 ) { - if (c == '\n') { - col = 0; - } else { - col++; - } - } - return col; -} - -static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) { - char seq[64]; - size_t plen = effectiveLen(prompt); - - while((plen+pos) >= cols) { - buf++; - len--; - pos--; - } - while (plen+len > cols) { - len--; - } - - /* Cursor to left edge */ - snprintf(seq,64,"\x1b[0G"); - if (write(fd,seq,strlen(seq)) == -1) return; - /* Write the prompt and the current buffer content */ - if (write(fd,prompt,strlen(prompt)) == -1) return; - if (write(fd,buf,len) == -1) return; - /* Erase to right */ - snprintf(seq,64,"\x1b[0K"); - if (write(fd,seq,strlen(seq)) == -1) return; - /* Move cursor to original position. */ - snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen)); - if (write(fd,seq,strlen(seq)) == -1) return; -} - -static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) { - size_t plen = strlen(prompt); - size_t pos = 0; - size_t len = 0; - size_t cols = getColumns(); - int history_index = 0; - - buf[0] = '\0'; - buflen--; /* Make sure there is always space for the nulterm */ - - /* The latest history entry is always our current buffer, that - * initially is just an empty string. */ - linenoiseHistoryAdd(""); - - if (write(fd,prompt,plen) == -1) return -1; - while(1) { - char c; - int nread; - char seq[2]; - - nread = read(fd,&c,1); - if (nread <= 0) return len; - switch(c) { - case 10: /* line feed. */ - case 13: /* enter */ - history_len--; - return len; - case 4: /* ctrl-d */ - history_len--; - return (len == 0) ? -1 : (int)len; - case 3: /* ctrl-c */ - errno = EAGAIN; - return -1; - case 127: /* backspace */ - case 8: /* ctrl-h */ - if (pos > 0 && len > 0) { - memmove(buf+pos-1,buf+pos,len-pos); - pos--; - len--; - buf[len] = '\0'; - refreshLine(fd,prompt,buf,len,pos,cols); - } - break; - case 20: /* ctrl-t */ - if (pos > 0 && pos < len) { - int aux = buf[pos-1]; - buf[pos-1] = buf[pos]; - buf[pos] = aux; - if (pos != len-1) pos++; - refreshLine(fd,prompt,buf,len,pos,cols); - } - break; - case 2: /* ctrl-b */ - goto left_arrow; - case 6: /* ctrl-f */ - goto right_arrow; - case 16: /* ctrl-p */ - seq[1] = 65; - goto up_down_arrow; - case 14: /* ctrl-n */ - seq[1] = 66; - goto up_down_arrow; - break; - case 27: /* escape sequence */ - if (read(fd,seq,2) == -1) break; - if (seq[0] == 91 && seq[1] == 68) { -left_arrow: - /* left arrow */ - if (pos > 0) { - pos--; - refreshLine(fd,prompt,buf,len,pos,cols); - } - } else if (seq[0] == 91 && seq[1] == 67) { -right_arrow: - /* right arrow */ - if (pos != len) { - pos++; - refreshLine(fd,prompt,buf,len,pos,cols); - } - } else if (seq[0] == 91 && (seq[1] == 65 || seq[1] == 66)) { -up_down_arrow: - /* up and down arrow: history */ - if (history_len > 1) { - /* Update the current history entry before to - * overwrite it with tne next one. */ - free(history[history_len-1-history_index]); - history[history_len-1-history_index] = strdup(buf); - /* Show the new entry */ - history_index += (seq[1] == 65) ? 1 : -1; - if (history_index < 0) { - history_index = 0; - break; - } else if (history_index >= history_len) { - history_index = history_len-1; - break; - } - strncpy(buf,history[history_len-1-history_index],buflen); - buf[buflen] = '\0'; - len = pos = strlen(buf); - refreshLine(fd,prompt,buf,len,pos,cols); - } - } - break; - default: - if (len < buflen) { - if (len == pos) { - buf[pos] = c; - pos++; - len++; - buf[len] = '\0'; - if (plen+len < cols) { - /* Avoid a full update of the line in the - * trivial case. */ - if (write(fd,&c,1) == -1) return -1; - } else { - refreshLine(fd,prompt,buf,len,pos,cols); - } - } else { - memmove(buf+pos+1,buf+pos,len-pos); - buf[pos] = c; - len++; - pos++; - buf[len] = '\0'; - refreshLine(fd,prompt,buf,len,pos,cols); - } - } - break; - case 21: /* Ctrl+u, delete the whole line. */ - buf[0] = '\0'; - pos = len = 0; - refreshLine(fd,prompt,buf,len,pos,cols); - break; - case 11: /* Ctrl+k, delete from current to end of line. */ - buf[pos] = '\0'; - len = pos; - refreshLine(fd,prompt,buf,len,pos,cols); - break; - case 1: /* Ctrl+a, go to the start of the line */ - pos = 0; - refreshLine(fd,prompt,buf,len,pos,cols); - break; - case 5: /* ctrl+e, go to the end of the line */ - pos = len; - refreshLine(fd,prompt,buf,len,pos,cols); - break; - } - } - return len; -} - -static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { - int fd = STDIN_FILENO; - int count; - - if (buflen == 0) { - errno = EINVAL; - return -1; - } - if (!isatty(STDIN_FILENO)) { - if (fgets(buf, buflen, stdin) == NULL) return -1; - count = strlen(buf); - if (count && buf[count-1] == '\n') { - count--; - buf[count] = '\0'; - } - } else { - if (enableRawMode(fd) == -1) return -1; - count = linenoisePrompt(fd, buf, buflen, prompt); - disableRawMode(fd); - } - return count; -} - -char *linenoise(const char *prompt) { - char buf[LINENOISE_MAX_LINE]; - int count; - - if (isUnsupportedTerm()) { - size_t len; - - printf("%s",prompt); - fflush(stdout); - if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; - len = strlen(buf); - while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) { - len--; - buf[len] = '\0'; - } - return strdup(buf); - } else { - count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); - if (count == -1) return NULL; - return strdup(buf); - } -} - -/* Using a circular buffer is smarter, but a bit more complex to handle. */ -int linenoiseHistoryAdd(const char *line) { - char *linecopy; - - if (history_max_len == 0) return 0; - if (history == 0) { - history = malloc(sizeof(char*)*history_max_len); - if (history == NULL) return 0; - memset(history,0,(sizeof(char*)*history_max_len)); - } - linecopy = strdup(line); - if (!linecopy) return 0; - if (history_len == history_max_len) { - memmove(history,history+1,sizeof(char*)*(history_max_len-1)); - history_len--; - } - history[history_len] = linecopy; - history_len++; - return 1; -} - -int linenoiseHistorySetMaxLen(int len) { - char **new; - - if (len < 1) return 0; - if (history) { - int tocopy = history_len; - - new = malloc(sizeof(char*)*len); - if (new == NULL) return 0; - if (len < tocopy) tocopy = len; - memcpy(new,history+(history_max_len-tocopy), sizeof(char*)*tocopy); - free(history); - history = new; - } - history_max_len = len; - if (history_len > history_max_len) - history_len = history_max_len; - return 1; -} diff --git a/liblinenoise/linenoise.h b/liblinenoise/linenoise.h deleted file mode 100644 index 57bf9d1..0000000 --- a/liblinenoise/linenoise.h +++ /dev/null @@ -1,41 +0,0 @@ -/* linenoise.h -- guerrilla line editing library against the idea that a - * line editing lib needs to be 20,000 lines of C code. - * - * See linenoise.c for more information. - * - * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __LINENOISE_H -#define __LINENOISE_H - -char *linenoise(const char *prompt); -int linenoiseHistoryAdd(const char *line); -int linenoiseHistorySetMaxLen(int len); - -#endif /* __LINENOISE_H */ diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk index 090d0e5..7906986 100644 --- a/libmincrypt/Android.mk +++ b/libmincrypt/Android.mk @@ -1,18 +1,18 @@ # Copyright 2008 The Android Open Source Project # LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) +include $(CLEAR_VARS) LOCAL_MODULE := libmincrypt -LOCAL_SRC_FILES := rsa.c sha.c sha256.c +LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c +LOCAL_CFLAGS := -Wall -Werror include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) - LOCAL_MODULE := libmincrypt -LOCAL_SRC_FILES := rsa.c sha.c sha256.c +LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c +LOCAL_CFLAGS := -Wall -Werror include $(BUILD_HOST_STATIC_LIBRARY) - include $(LOCAL_PATH)/tools/Android.mk \ $(LOCAL_PATH)/test/Android.mk diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c new file mode 100644 index 0000000..8df6cf7 --- /dev/null +++ b/libmincrypt/dsa_sig.c @@ -0,0 +1,125 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +#include "mincrypt/p256.h" + +/** + * Trims off the leading zero bytes and copy it to a buffer aligning it to the end. + */ +static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src, + int src_len) { + int dst_offset; + while (*src == '\0' && src_len > 0) { + src++; + src_len--; + } + if (src_len > P256_NBYTES || src_len < 1) { + return 0; + } + dst_offset = P256_NBYTES - src_len; + memset(dst, 0, dst_offset); + memcpy(dst + dst_offset, src, src_len); + return 1; +} + +/** + * Unpacks the ASN.1 DSA signature sequence. + */ +int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) { + /* + * Structure is: + * 0x30 0xNN SEQUENCE + s_length + * 0x02 0xNN INTEGER + r_length + * 0xAA 0xBB .. r_length bytes of "r" (offset 4) + * 0x02 0xNN INTEGER + s_length + * 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len) + */ + int seq_len; + unsigned char r_bytes[P256_NBYTES]; + unsigned char s_bytes[P256_NBYTES]; + int r_len; + int s_len; + + memset(r_bytes, 0, sizeof(r_bytes)); + memset(s_bytes, 0, sizeof(s_bytes)); + + /* + * Must have at least: + * 2 bytes sequence header and length + * 2 bytes R integer header and length + * 1 byte of R + * 2 bytes S integer header and length + * 1 byte of S + * + * 8 bytes total + */ + if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) { + return 0; + } + + seq_len = sig[1]; + if ((seq_len <= 0) || (seq_len + 2 != sig_len)) { + return 0; + } + + r_len = sig[3]; + /* + * Must have at least: + * 2 bytes for R header and length + * 2 bytes S integer header and length + * 1 byte of S + */ + if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) { + return 0; + } + s_len = sig[5 + r_len]; + + /** + * Must have: + * 2 bytes for R header and length + * r_len bytes for R + * 2 bytes S integer header and length + */ + if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) { + return 0; + } + + /* + * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have + * a correctly-sized buffer and that the resulting integer isn't too large. + */ + if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len) + || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) { + return 0; + } + + p256_from_bin(r_bytes, r_int); + p256_from_bin(s_bytes, s_int); + + return 1; +} diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c new file mode 100644 index 0000000..1608d37 --- /dev/null +++ b/libmincrypt/p256.c @@ -0,0 +1,375 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This is an implementation of the P256 elliptic curve group. It's written to +// be portable 32-bit, although it's still constant-time. +// +// WARNING: Implementing these functions in a constant-time manner is far from +// obvious. Be careful when touching this code. +// +// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. + +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +#include "mincrypt/p256.h" + +const p256_int SECP256r1_n = // curve order + {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}}; + +const p256_int SECP256r1_p = // curve field size + {{-1, -1, -1, 0, 0, 0, 1, -1 }}; + +const p256_int SECP256r1_b = // curve b + {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, + 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}}; + +static const p256_int p256_one = P256_ONE; + +void p256_init(p256_int* a) { + memset(a, 0, sizeof(*a)); +} + +void p256_clear(p256_int* a) { p256_init(a); } + +int p256_get_bit(const p256_int* scalar, int bit) { + return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT) + >> (bit & (P256_BITSPERDIGIT - 1))) & 1; +} + +int p256_is_zero(const p256_int* a) { + int i, result = 0; + for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i); + return !result; +} + +// top, c[] += a[] * b +// Returns new top +static p256_digit mulAdd(const p256_int* a, + p256_digit b, + p256_digit top, + p256_digit* c) { + int i; + p256_ddigit carry = 0; + + for (i = 0; i < P256_NDIGITS; ++i) { + carry += *c; + carry += (p256_ddigit)P256_DIGIT(a, i) * b; + *c++ = (p256_digit)carry; + carry >>= P256_BITSPERDIGIT; + } + return top + (p256_digit)carry; +} + +// top, c[] -= top_a, a[] +static p256_digit subTop(p256_digit top_a, + const p256_digit* a, + p256_digit top_c, + p256_digit* c) { + int i; + p256_sddigit borrow = 0; + + for (i = 0; i < P256_NDIGITS; ++i) { + borrow += *c; + borrow -= *a++; + *c++ = (p256_digit)borrow; + borrow >>= P256_BITSPERDIGIT; + } + borrow += top_c; + borrow -= top_a; + top_c = (p256_digit)borrow; + assert((borrow >> P256_BITSPERDIGIT) == 0); + return top_c; +} + +// top, c[] -= MOD[] & mask (0 or -1) +// returns new top. +static p256_digit subM(const p256_int* MOD, + p256_digit top, + p256_digit* c, + p256_digit mask) { + int i; + p256_sddigit borrow = 0; + for (i = 0; i < P256_NDIGITS; ++i) { + borrow += *c; + borrow -= P256_DIGIT(MOD, i) & mask; + *c++ = (p256_digit)borrow; + borrow >>= P256_BITSPERDIGIT; + } + return top + (p256_digit)borrow; +} + +// top, c[] += MOD[] & mask (0 or -1) +// returns new top. +static p256_digit addM(const p256_int* MOD, + p256_digit top, + p256_digit* c, + p256_digit mask) { + int i; + p256_ddigit carry = 0; + for (i = 0; i < P256_NDIGITS; ++i) { + carry += *c; + carry += P256_DIGIT(MOD, i) & mask; + *c++ = (p256_digit)carry; + carry >>= P256_BITSPERDIGIT; + } + return top + (p256_digit)carry; +} + +// c = a * b mod MOD. c can be a and/or b. +void p256_modmul(const p256_int* MOD, + const p256_int* a, + const p256_digit top_b, + const p256_int* b, + p256_int* c) { + p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 }; + p256_digit top = 0; + int i; + + // Multiply/add into tmp. + for (i = 0; i < P256_NDIGITS; ++i) { + if (i) tmp[i + P256_NDIGITS - 1] = top; + top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i); + } + + // Multiply/add top digit + tmp[i + P256_NDIGITS - 1] = top; + top = mulAdd(a, top_b, 0, tmp + i); + + // Reduce tmp, digit by digit. + for (; i >= 0; --i) { + p256_digit reducer[P256_NDIGITS] = { 0 }; + p256_digit top_reducer; + + // top can be any value at this point. + // Guestimate reducer as top * MOD, since msw of MOD is -1. + top_reducer = mulAdd(MOD, top, 0, reducer); + + // Subtract reducer from top | tmp. + top = subTop(top_reducer, reducer, top, tmp + i); + + // top is now either 0 or 1. Make it 0, fixed-timing. + assert(top <= 1); + + top = subM(MOD, top, tmp + i, ~(top - 1)); + + assert(top == 0); + + // We have now reduced the top digit off tmp. Fetch new top digit. + top = tmp[i + P256_NDIGITS - 1]; + } + + // tmp might still be larger than MOD, yet same bit length. + // Make sure it is less, fixed-timing. + addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1)); + + memcpy(c, tmp, P256_NBYTES); +} +int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; } +int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); } + +p256_digit p256_shl(const p256_int* a, int n, p256_int* b) { + int i; + p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1); + + n %= P256_BITSPERDIGIT; + for (i = P256_NDIGITS - 1; i > 0; --i) { + p256_digit accu = (P256_DIGIT(a, i) << n); + accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n)); + P256_DIGIT(b, i) = accu; + } + P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n); + + top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT); + + return top; +} + +void p256_shr(const p256_int* a, int n, p256_int* b) { + int i; + + n %= P256_BITSPERDIGIT; + for (i = 0; i < P256_NDIGITS - 1; ++i) { + p256_digit accu = (P256_DIGIT(a, i) >> n); + accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n)); + P256_DIGIT(b, i) = accu; + } + P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n); +} + +static void p256_shr1(const p256_int* a, int highbit, p256_int* b) { + int i; + + for (i = 0; i < P256_NDIGITS - 1; ++i) { + p256_digit accu = (P256_DIGIT(a, i) >> 1); + accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1)); + P256_DIGIT(b, i) = accu; + } + P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) | + (highbit << (P256_BITSPERDIGIT - 1)); +} + +// Return -1, 0, 1 for a < b, a == b or a > b respectively. +int p256_cmp(const p256_int* a, const p256_int* b) { + int i; + p256_sddigit borrow = 0; + p256_digit notzero = 0; + + for (i = 0; i < P256_NDIGITS; ++i) { + borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i); + // Track whether any result digit is ever not zero. + // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1. + notzero |= !!((p256_digit)borrow); + borrow >>= P256_BITSPERDIGIT; + } + return (int)borrow | notzero; +} + +// c = a - b. Returns borrow: 0 or -1. +int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) { + int i; + p256_sddigit borrow = 0; + + for (i = 0; i < P256_NDIGITS; ++i) { + borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i); + if (c) P256_DIGIT(c, i) = (p256_digit)borrow; + borrow >>= P256_BITSPERDIGIT; + } + return (int)borrow; +} + +// c = a + b. Returns carry: 0 or 1. +int p256_add(const p256_int* a, const p256_int* b, p256_int* c) { + int i; + p256_ddigit carry = 0; + + for (i = 0; i < P256_NDIGITS; ++i) { + carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i); + if (c) P256_DIGIT(c, i) = (p256_digit)carry; + carry >>= P256_BITSPERDIGIT; + } + return (int)carry; +} + +// b = a + d. Returns carry, 0 or 1. +int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) { + int i; + p256_ddigit carry = d; + + for (i = 0; i < P256_NDIGITS; ++i) { + carry += (p256_ddigit)P256_DIGIT(a, i); + if (b) P256_DIGIT(b, i) = (p256_digit)carry; + carry >>= P256_BITSPERDIGIT; + } + return (int)carry; +} + +// b = 1/a mod MOD, binary euclid. +void p256_modinv_vartime(const p256_int* MOD, + const p256_int* a, + p256_int* b) { + p256_int R = P256_ZERO; + p256_int S = P256_ONE; + p256_int U = *MOD; + p256_int V = *a; + + for (;;) { + if (p256_is_even(&U)) { + p256_shr1(&U, 0, &U); + if (p256_is_even(&R)) { + p256_shr1(&R, 0, &R); + } else { + // R = (R+MOD)/2 + p256_shr1(&R, p256_add(&R, MOD, &R), &R); + } + } else if (p256_is_even(&V)) { + p256_shr1(&V, 0, &V); + if (p256_is_even(&S)) { + p256_shr1(&S, 0, &S); + } else { + // S = (S+MOD)/2 + p256_shr1(&S, p256_add(&S, MOD, &S) , &S); + } + } else { // U,V both odd. + if (!p256_sub(&V, &U, NULL)) { + p256_sub(&V, &U, &V); + if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S); + if (p256_is_zero(&V)) break; // done. + } else { + p256_sub(&U, &V, &U); + if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R); + } + } + } + + p256_mod(MOD, &R, b); +} + +void p256_mod(const p256_int* MOD, + const p256_int* in, + p256_int* out) { + if (out != in) *out = *in; + addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1)); +} + +// Verify y^2 == x^3 - 3x + b mod p +// and 0 < x < p and 0 < y < p +int p256_is_valid_point(const p256_int* x, const p256_int* y) { + p256_int y2, x3; + + if (p256_cmp(&SECP256r1_p, x) <= 0 || + p256_cmp(&SECP256r1_p, y) <= 0 || + p256_is_zero(x) || + p256_is_zero(y)) return 0; + + p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2 + + p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2 + p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3 + if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x + if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x + if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x + if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b + p256_sub(&x3, &SECP256r1_p, &x3); + + return p256_cmp(&y2, &x3) == 0; +} + +void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) { + int i; + const uint8_t* p = &src[0]; + + for (i = P256_NDIGITS - 1; i >= 0; --i) { + P256_DIGIT(dst, i) = + (p[0] << 24) | + (p[1] << 16) | + (p[2] << 8) | + p[3]; + p += 4; + } +} diff --git a/libmincrypt/p256_ec.c b/libmincrypt/p256_ec.c new file mode 100644 index 0000000..90262cc --- /dev/null +++ b/libmincrypt/p256_ec.c @@ -0,0 +1,1279 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This is an implementation of the P256 elliptic curve group. It's written to +// be portable 32-bit, although it's still constant-time. +// +// WARNING: Implementing these functions in a constant-time manner is far from +// obvious. Be careful when touching this code. +// +// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. + +#include <stdint.h> +#include <stdio.h> + +#include <string.h> +#include <stdlib.h> + +#include "mincrypt/p256.h" + +typedef uint8_t u8; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; + +/* Our field elements are represented as nine 32-bit limbs. + * + * The value of an felem (field element) is: + * x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228) + * + * That is, each limb is alternately 29 or 28-bits wide in little-endian + * order. + * + * This means that an felem hits 2**257, rather than 2**256 as we would like. A + * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems + * when multiplying as terms end up one bit short of a limb which would require + * much bit-shifting to correct. + * + * Finally, the values stored in an felem are in Montgomery form. So the value + * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257. + */ +typedef u32 limb; +#define NLIMBS 9 +typedef limb felem[NLIMBS]; + +static const limb kBottom28Bits = 0xfffffff; +static const limb kBottom29Bits = 0x1fffffff; + +/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and + * 28-bit words. */ +static const felem kOne = { + 2, 0, 0, 0xffff800, + 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff, + 0 +}; +static const felem kZero = {0}; +static const felem kP = { + 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff, + 0, 0, 0x200000, 0xf000000, + 0xfffffff +}; +static const felem k2P = { + 0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff, + 0, 0, 0x400000, 0xe000000, + 0x1fffffff +}; +/* kPrecomputed contains precomputed values to aid the calculation of scalar + * multiples of the base point, G. It's actually two, equal length, tables + * concatenated. + * + * The first table contains (x,y) felem pairs for 16 multiples of the base + * point, G. + * + * Index | Index (binary) | Value + * 0 | 0000 | 0G (all zeros, omitted) + * 1 | 0001 | G + * 2 | 0010 | 2**64G + * 3 | 0011 | 2**64G + G + * 4 | 0100 | 2**128G + * 5 | 0101 | 2**128G + G + * 6 | 0110 | 2**128G + 2**64G + * 7 | 0111 | 2**128G + 2**64G + G + * 8 | 1000 | 2**192G + * 9 | 1001 | 2**192G + G + * 10 | 1010 | 2**192G + 2**64G + * 11 | 1011 | 2**192G + 2**64G + G + * 12 | 1100 | 2**192G + 2**128G + * 13 | 1101 | 2**192G + 2**128G + G + * 14 | 1110 | 2**192G + 2**128G + 2**64G + * 15 | 1111 | 2**192G + 2**128G + 2**64G + G + * + * The second table follows the same style, but the terms are 2**32G, + * 2**96G, 2**160G, 2**224G. + * + * This is ~2KB of data. */ +static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = { + 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee, + 0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3, + 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c, + 0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22, + 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050, + 0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b, + 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa, + 0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2, + 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609, + 0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581, + 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca, + 0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33, + 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6, + 0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd, + 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0, + 0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881, + 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a, + 0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26, + 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b, + 0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023, + 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133, + 0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa, + 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29, + 0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc, + 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8, + 0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59, + 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39, + 0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689, + 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa, + 0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3, + 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1, + 0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f, + 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72, + 0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d, + 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b, + 0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a, + 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a, + 0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f, + 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb, + 0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc, + 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9, + 0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce, + 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2, + 0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca, + 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229, + 0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57, + 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c, + 0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa, + 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651, + 0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec, + 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7, + 0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c, + 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927, + 0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298, + 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8, + 0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2, + 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d, + 0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4, + 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8, + 0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78, +}; + + +/* Field element operations: */ + +/* NON_ZERO_TO_ALL_ONES returns: + * 0xffffffff for 0 < x <= 2**31 + * 0 for x == 0 or x > 2**31. + * + * x must be a u32 or an equivalent type such as limb. */ +#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1) + +/* felem_reduce_carry adds a multiple of p in order to cancel |carry|, + * which is a term at 2**257. + * + * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28. + * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */ +static void felem_reduce_carry(felem inout, limb carry) { + const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry); + + inout[0] += carry << 1; + inout[3] += 0x10000000 & carry_mask; + /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the + * previous line therefore this doesn't underflow. */ + inout[3] -= carry << 11; + inout[4] += (0x20000000 - 1) & carry_mask; + inout[5] += (0x10000000 - 1) & carry_mask; + inout[6] += (0x20000000 - 1) & carry_mask; + inout[6] -= carry << 22; + /* This may underflow if carry is non-zero but, if so, we'll fix it in the + * next line. */ + inout[7] -= 1 & carry_mask; + inout[7] += carry << 25; +} + +/* felem_sum sets out = in+in2. + * + * On entry, in[i]+in2[i] must not overflow a 32-bit word. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */ +static void felem_sum(felem out, const felem in, const felem in2) { + limb carry = 0; + unsigned i; + + for (i = 0;; i++) { + out[i] = in[i] + in2[i]; + out[i] += carry; + carry = out[i] >> 29; + out[i] &= kBottom29Bits; + + i++; + if (i == NLIMBS) + break; + + out[i] = in[i] + in2[i]; + out[i] += carry; + carry = out[i] >> 28; + out[i] &= kBottom28Bits; + } + + felem_reduce_carry(out, carry); +} + +#define two31m3 (((limb)1) << 31) - (((limb)1) << 3) +#define two30m2 (((limb)1) << 30) - (((limb)1) << 2) +#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2) +#define two31m2 (((limb)1) << 31) - (((limb)1) << 2) +#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2) +#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2) + +/* zero31 is 0 mod p. */ +static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 }; + +/* felem_diff sets out = in-in2. + * + * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and + * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ +static void felem_diff(felem out, const felem in, const felem in2) { + limb carry = 0; + unsigned i; + + for (i = 0;; i++) { + out[i] = in[i] - in2[i]; + out[i] += zero31[i]; + out[i] += carry; + carry = out[i] >> 29; + out[i] &= kBottom29Bits; + + i++; + if (i == NLIMBS) + break; + + out[i] = in[i] - in2[i]; + out[i] += zero31[i]; + out[i] += carry; + carry = out[i] >> 28; + out[i] &= kBottom28Bits; + } + + felem_reduce_carry(out, carry); +} + +/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words + * with the same 29,28,... bit positions as an felem. + * + * The values in felems are in Montgomery form: x*R mod p where R = 2**257. + * Since we just multiplied two Montgomery values together, the result is + * x*y*R*R mod p. We wish to divide by R in order for the result also to be + * in Montgomery form. + * + * On entry: tmp[i] < 2**64 + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */ +static void felem_reduce_degree(felem out, u64 tmp[17]) { + /* The following table may be helpful when reading this code: + * + * Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10... + * Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29 + * Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285 + * (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */ + limb tmp2[18], carry, x, xMask; + unsigned i; + + /* tmp contains 64-bit words with the same 29,28,29-bit positions as an + * felem. So the top of an element of tmp might overlap with another + * element two positions down. The following loop eliminates this + * overlap. */ + tmp2[0] = (limb)(tmp[0] & kBottom29Bits); + + /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try + * and hint to the compiler that it can do a single-word shift by selecting + * the right register rather than doing a double-word shift and truncating + * afterwards. */ + tmp2[1] = ((limb) tmp[0]) >> 29; + tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits; + tmp2[1] += ((limb) tmp[1]) & kBottom28Bits; + carry = tmp2[1] >> 28; + tmp2[1] &= kBottom28Bits; + + for (i = 2; i < 17; i++) { + tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25; + tmp2[i] += ((limb)(tmp[i - 1])) >> 28; + tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits; + tmp2[i] += ((limb) tmp[i]) & kBottom29Bits; + tmp2[i] += carry; + carry = tmp2[i] >> 29; + tmp2[i] &= kBottom29Bits; + + i++; + if (i == 17) + break; + tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25; + tmp2[i] += ((limb)(tmp[i - 1])) >> 29; + tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits; + tmp2[i] += ((limb) tmp[i]) & kBottom28Bits; + tmp2[i] += carry; + carry = tmp2[i] >> 28; + tmp2[i] &= kBottom28Bits; + } + + tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25; + tmp2[17] += ((limb)(tmp[16])) >> 29; + tmp2[17] += (((limb)(tmp[16] >> 32)) << 3); + tmp2[17] += carry; + + /* Montgomery elimination of terms. + * + * Since R is 2**257, we can divide by R with a bitwise shift if we can + * ensure that the right-most 257 bits are all zero. We can make that true by + * adding multiplies of p without affecting the value. + * + * So we eliminate limbs from right to left. Since the bottom 29 bits of p + * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0. + * We can do that for 8 further limbs and then right shift to eliminate the + * extra factor of R. */ + for (i = 0;; i += 2) { + tmp2[i + 1] += tmp2[i] >> 29; + x = tmp2[i] & kBottom29Bits; + xMask = NON_ZERO_TO_ALL_ONES(x); + tmp2[i] = 0; + + /* The bounds calculations for this loop are tricky. Each iteration of + * the loop eliminates two words by adding values to words to their + * right. + * + * The following table contains the amounts added to each word (as an + * offset from the value of i at the top of the loop). The amounts are + * accounted for from the first and second half of the loop separately + * and are written as, for example, 28 to mean a value <2**28. + * + * Word: 3 4 5 6 7 8 9 10 + * Added in top half: 28 11 29 21 29 28 + * 28 29 + * 29 + * Added in bottom half: 29 10 28 21 28 28 + * 29 + * + * The value that is currently offset 7 will be offset 5 for the next + * iteration and then offset 3 for the iteration after that. Therefore + * the total value added will be the values added at 7, 5 and 3. + * + * The following table accumulates these values. The sums at the bottom + * are written as, for example, 29+28, to mean a value < 2**29+2**28. + * + * Word: 3 4 5 6 7 8 9 10 11 12 13 + * 28 11 10 29 21 29 28 28 28 28 28 + * 29 28 11 28 29 28 29 28 29 28 + * 29 28 21 21 29 21 29 21 + * 10 29 28 21 28 21 28 + * 28 29 28 29 28 29 28 + * 11 10 29 10 29 10 + * 29 28 11 28 11 + * 29 29 + * -------------------------------------------- + * 30+ 31+ 30+ 31+ 30+ + * 28+ 29+ 28+ 29+ 21+ + * 21+ 28+ 21+ 28+ 10 + * 10 21+ 10 21+ + * 11 11 + * + * So the greatest amount is added to tmp2[10] and tmp2[12]. If + * tmp2[10/12] has an initial value of <2**29, then the maximum value + * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32, + * as required. */ + tmp2[i + 3] += (x << 10) & kBottom28Bits; + tmp2[i + 4] += (x >> 18); + + tmp2[i + 6] += (x << 21) & kBottom29Bits; + tmp2[i + 7] += x >> 8; + + /* At position 200, which is the starting bit position for word 7, we + * have a factor of 0xf000000 = 2**28 - 2**24. */ + tmp2[i + 7] += 0x10000000 & xMask; + /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */ + tmp2[i + 8] += (x - 1) & xMask; + tmp2[i + 7] -= (x << 24) & kBottom28Bits; + tmp2[i + 8] -= x >> 4; + + tmp2[i + 8] += 0x20000000 & xMask; + tmp2[i + 8] -= x; + tmp2[i + 8] += (x << 28) & kBottom29Bits; + tmp2[i + 9] += ((x >> 1) - 1) & xMask; + + if (i+1 == NLIMBS) + break; + tmp2[i + 2] += tmp2[i + 1] >> 28; + x = tmp2[i + 1] & kBottom28Bits; + xMask = NON_ZERO_TO_ALL_ONES(x); + tmp2[i + 1] = 0; + + tmp2[i + 4] += (x << 11) & kBottom29Bits; + tmp2[i + 5] += (x >> 18); + + tmp2[i + 7] += (x << 21) & kBottom28Bits; + tmp2[i + 8] += x >> 7; + + /* At position 199, which is the starting bit of the 8th word when + * dealing with a context starting on an odd word, we have a factor of + * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th + * word from i+1 is i+8. */ + tmp2[i + 8] += 0x20000000 & xMask; + tmp2[i + 9] += (x - 1) & xMask; + tmp2[i + 8] -= (x << 25) & kBottom29Bits; + tmp2[i + 9] -= x >> 4; + + tmp2[i + 9] += 0x10000000 & xMask; + tmp2[i + 9] -= x; + tmp2[i + 10] += (x - 1) & xMask; + } + + /* We merge the right shift with a carry chain. The words above 2**257 have + * widths of 28,29,... which we need to correct when copying them down. */ + carry = 0; + for (i = 0; i < 8; i++) { + /* The maximum value of tmp2[i + 9] occurs on the first iteration and + * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is + * therefore safe. */ + out[i] = tmp2[i + 9]; + out[i] += carry; + out[i] += (tmp2[i + 10] << 28) & kBottom29Bits; + carry = out[i] >> 29; + out[i] &= kBottom29Bits; + + i++; + out[i] = tmp2[i + 9] >> 1; + out[i] += carry; + carry = out[i] >> 28; + out[i] &= kBottom28Bits; + } + + out[8] = tmp2[17]; + out[8] += carry; + carry = out[8] >> 29; + out[8] &= kBottom29Bits; + + felem_reduce_carry(out, carry); +} + +/* felem_square sets out=in*in. + * + * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ +static void felem_square(felem out, const felem in) { + u64 tmp[17]; + + tmp[0] = ((u64) in[0]) * in[0]; + tmp[1] = ((u64) in[0]) * (in[1] << 1); + tmp[2] = ((u64) in[0]) * (in[2] << 1) + + ((u64) in[1]) * (in[1] << 1); + tmp[3] = ((u64) in[0]) * (in[3] << 1) + + ((u64) in[1]) * (in[2] << 1); + tmp[4] = ((u64) in[0]) * (in[4] << 1) + + ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2]; + tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) * + (in[4] << 1) + ((u64) in[2]) * (in[3] << 1); + tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) * + (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) + + ((u64) in[3]) * (in[3] << 1); + tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) * + (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) + + ((u64) in[3]) * (in[4] << 1); + /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60, + * which is < 2**64 as required. */ + tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) * + (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) + + ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4]; + tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) * + (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) + + ((u64) in[4]) * (in[5] << 1); + tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) * + (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) + + ((u64) in[5]) * (in[5] << 1); + tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) * + (in[7] << 1) + ((u64) in[5]) * (in[6] << 1); + tmp[12] = ((u64) in[4]) * (in[8] << 1) + + ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6]; + tmp[13] = ((u64) in[5]) * (in[8] << 1) + + ((u64) in[6]) * (in[7] << 1); + tmp[14] = ((u64) in[6]) * (in[8] << 1) + + ((u64) in[7]) * (in[7] << 1); + tmp[15] = ((u64) in[7]) * (in[8] << 1); + tmp[16] = ((u64) in[8]) * in[8]; + + felem_reduce_degree(out, tmp); +} + +/* felem_mul sets out=in*in2. + * + * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and + * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ +static void felem_mul(felem out, const felem in, const felem in2) { + u64 tmp[17]; + + tmp[0] = ((u64) in[0]) * in2[0]; + tmp[1] = ((u64) in[0]) * (in2[1] << 0) + + ((u64) in[1]) * (in2[0] << 0); + tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) * + (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0); + tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) * + (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) + + ((u64) in[3]) * (in2[0] << 0); + tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) * + (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) + + ((u64) in[3]) * (in2[1] << 1) + + ((u64) in[4]) * (in2[0] << 0); + tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) * + (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) + + ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) * + (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0); + tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) * + (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) + + ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) * + (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) + + ((u64) in[6]) * (in2[0] << 0); + tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) * + (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) + + ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) * + (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) + + ((u64) in[6]) * (in2[1] << 0) + + ((u64) in[7]) * (in2[0] << 0); + /* tmp[8] has the greatest value but doesn't overflow. See logic in + * felem_square. */ + tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) * + (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) + + ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) * + (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) + + ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) * + (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0); + tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) * + (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) + + ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) * + (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) + + ((u64) in[7]) * (in2[2] << 0) + + ((u64) in[8]) * (in2[1] << 0); + tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) * + (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) + + ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) * + (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) + + ((u64) in[8]) * (in2[2] << 0); + tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) * + (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) + + ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) * + (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0); + tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) * + (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) + + ((u64) in[7]) * (in2[5] << 1) + + ((u64) in[8]) * (in2[4] << 0); + tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) * + (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) + + ((u64) in[8]) * (in2[5] << 0); + tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) * + (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0); + tmp[15] = ((u64) in[7]) * (in2[8] << 0) + + ((u64) in[8]) * (in2[7] << 0); + tmp[16] = ((u64) in[8]) * (in2[8] << 0); + + felem_reduce_degree(out, tmp); +} + +static void felem_assign(felem out, const felem in) { + memcpy(out, in, sizeof(felem)); +} + +/* felem_inv calculates |out| = |in|^{-1} + * + * Based on Fermat's Little Theorem: + * a^p = a (mod p) + * a^{p-1} = 1 (mod p) + * a^{p-2} = a^{-1} (mod p) + */ +static void felem_inv(felem out, const felem in) { + felem ftmp, ftmp2; + /* each e_I will hold |in|^{2^I - 1} */ + felem e2, e4, e8, e16, e32, e64; + unsigned i; + + felem_square(ftmp, in); /* 2^1 */ + felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */ + felem_assign(e2, ftmp); + felem_square(ftmp, ftmp); /* 2^3 - 2^1 */ + felem_square(ftmp, ftmp); /* 2^4 - 2^2 */ + felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */ + felem_assign(e4, ftmp); + felem_square(ftmp, ftmp); /* 2^5 - 2^1 */ + felem_square(ftmp, ftmp); /* 2^6 - 2^2 */ + felem_square(ftmp, ftmp); /* 2^7 - 2^3 */ + felem_square(ftmp, ftmp); /* 2^8 - 2^4 */ + felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */ + felem_assign(e8, ftmp); + for (i = 0; i < 8; i++) { + felem_square(ftmp, ftmp); + } /* 2^16 - 2^8 */ + felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */ + felem_assign(e16, ftmp); + for (i = 0; i < 16; i++) { + felem_square(ftmp, ftmp); + } /* 2^32 - 2^16 */ + felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */ + felem_assign(e32, ftmp); + for (i = 0; i < 32; i++) { + felem_square(ftmp, ftmp); + } /* 2^64 - 2^32 */ + felem_assign(e64, ftmp); + felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */ + for (i = 0; i < 192; i++) { + felem_square(ftmp, ftmp); + } /* 2^256 - 2^224 + 2^192 */ + + felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */ + for (i = 0; i < 16; i++) { + felem_square(ftmp2, ftmp2); + } /* 2^80 - 2^16 */ + felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */ + for (i = 0; i < 8; i++) { + felem_square(ftmp2, ftmp2); + } /* 2^88 - 2^8 */ + felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */ + for (i = 0; i < 4; i++) { + felem_square(ftmp2, ftmp2); + } /* 2^92 - 2^4 */ + felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */ + felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */ + felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */ + felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */ + felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */ + felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */ + felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */ + + felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */ +} + +/* felem_scalar_3 sets out=3*out. + * + * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ +static void felem_scalar_3(felem out) { + limb carry = 0; + unsigned i; + + for (i = 0;; i++) { + out[i] *= 3; + out[i] += carry; + carry = out[i] >> 29; + out[i] &= kBottom29Bits; + + i++; + if (i == NLIMBS) + break; + + out[i] *= 3; + out[i] += carry; + carry = out[i] >> 28; + out[i] &= kBottom28Bits; + } + + felem_reduce_carry(out, carry); +} + +/* felem_scalar_4 sets out=4*out. + * + * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ +static void felem_scalar_4(felem out) { + limb carry = 0, next_carry; + unsigned i; + + for (i = 0;; i++) { + next_carry = out[i] >> 27; + out[i] <<= 2; + out[i] &= kBottom29Bits; + out[i] += carry; + carry = next_carry + (out[i] >> 29); + out[i] &= kBottom29Bits; + + i++; + if (i == NLIMBS) + break; + + next_carry = out[i] >> 26; + out[i] <<= 2; + out[i] &= kBottom28Bits; + out[i] += carry; + carry = next_carry + (out[i] >> 28); + out[i] &= kBottom28Bits; + } + + felem_reduce_carry(out, carry); +} + +/* felem_scalar_8 sets out=8*out. + * + * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. + * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ +static void felem_scalar_8(felem out) { + limb carry = 0, next_carry; + unsigned i; + + for (i = 0;; i++) { + next_carry = out[i] >> 26; + out[i] <<= 3; + out[i] &= kBottom29Bits; + out[i] += carry; + carry = next_carry + (out[i] >> 29); + out[i] &= kBottom29Bits; + + i++; + if (i == NLIMBS) + break; + + next_carry = out[i] >> 25; + out[i] <<= 3; + out[i] &= kBottom28Bits; + out[i] += carry; + carry = next_carry + (out[i] >> 28); + out[i] &= kBottom28Bits; + } + + felem_reduce_carry(out, carry); +} + +/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of + * time depending on the value of |in|. */ +static char felem_is_zero_vartime(const felem in) { + limb carry; + int i; + limb tmp[NLIMBS]; + + felem_assign(tmp, in); + + /* First, reduce tmp to a minimal form. */ + do { + carry = 0; + for (i = 0;; i++) { + tmp[i] += carry; + carry = tmp[i] >> 29; + tmp[i] &= kBottom29Bits; + + i++; + if (i == NLIMBS) + break; + + tmp[i] += carry; + carry = tmp[i] >> 28; + tmp[i] &= kBottom28Bits; + } + + felem_reduce_carry(tmp, carry); + } while (carry); + + /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */ + return memcmp(tmp, kZero, sizeof(tmp)) == 0 || + memcmp(tmp, kP, sizeof(tmp)) == 0 || + memcmp(tmp, k2P, sizeof(tmp)) == 0; +} + + +/* Group operations: + * + * Elements of the elliptic curve group are represented in Jacobian + * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in + * Jacobian form. */ + +/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}. + * + * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */ +static void point_double(felem x_out, felem y_out, felem z_out, const felem x, + const felem y, const felem z) { + felem delta, gamma, alpha, beta, tmp, tmp2; + + felem_square(delta, z); + felem_square(gamma, y); + felem_mul(beta, x, gamma); + + felem_sum(tmp, x, delta); + felem_diff(tmp2, x, delta); + felem_mul(alpha, tmp, tmp2); + felem_scalar_3(alpha); + + felem_sum(tmp, y, z); + felem_square(tmp, tmp); + felem_diff(tmp, tmp, gamma); + felem_diff(z_out, tmp, delta); + + felem_scalar_4(beta); + felem_square(x_out, alpha); + felem_diff(x_out, x_out, beta); + felem_diff(x_out, x_out, beta); + + felem_diff(tmp, beta, x_out); + felem_mul(tmp, alpha, tmp); + felem_square(tmp2, gamma); + felem_scalar_8(tmp2); + felem_diff(y_out, tmp, tmp2); +} + +/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}. + * (i.e. the second point is affine.) + * + * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + * + * Note that this function does not handle P+P, infinity+P nor P+infinity + * correctly. */ +static void point_add_mixed(felem x_out, felem y_out, felem z_out, + const felem x1, const felem y1, const felem z1, + const felem x2, const felem y2) { + felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp; + + felem_square(z1z1, z1); + felem_sum(tmp, z1, z1); + + felem_mul(u2, x2, z1z1); + felem_mul(z1z1z1, z1, z1z1); + felem_mul(s2, y2, z1z1z1); + felem_diff(h, u2, x1); + felem_sum(i, h, h); + felem_square(i, i); + felem_mul(j, h, i); + felem_diff(r, s2, y1); + felem_sum(r, r, r); + felem_mul(v, x1, i); + + felem_mul(z_out, tmp, h); + felem_square(rr, r); + felem_diff(x_out, rr, j); + felem_diff(x_out, x_out, v); + felem_diff(x_out, x_out, v); + + felem_diff(tmp, v, x_out); + felem_mul(y_out, tmp, r); + felem_mul(tmp, y1, j); + felem_diff(y_out, y_out, tmp); + felem_diff(y_out, y_out, tmp); +} + +/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}. + * + * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + * + * Note that this function does not handle P+P, infinity+P nor P+infinity + * correctly. */ +static void point_add(felem x_out, felem y_out, felem z_out, const felem x1, + const felem y1, const felem z1, const felem x2, + const felem y2, const felem z2) { + felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp; + + felem_square(z1z1, z1); + felem_square(z2z2, z2); + felem_mul(u1, x1, z2z2); + + felem_sum(tmp, z1, z2); + felem_square(tmp, tmp); + felem_diff(tmp, tmp, z1z1); + felem_diff(tmp, tmp, z2z2); + + felem_mul(z2z2z2, z2, z2z2); + felem_mul(s1, y1, z2z2z2); + + felem_mul(u2, x2, z1z1); + felem_mul(z1z1z1, z1, z1z1); + felem_mul(s2, y2, z1z1z1); + felem_diff(h, u2, u1); + felem_sum(i, h, h); + felem_square(i, i); + felem_mul(j, h, i); + felem_diff(r, s2, s1); + felem_sum(r, r, r); + felem_mul(v, u1, i); + + felem_mul(z_out, tmp, h); + felem_square(rr, r); + felem_diff(x_out, rr, j); + felem_diff(x_out, x_out, v); + felem_diff(x_out, x_out, v); + + felem_diff(tmp, v, x_out); + felem_mul(y_out, tmp, r); + felem_mul(tmp, s1, j); + felem_diff(y_out, y_out, tmp); + felem_diff(y_out, y_out, tmp); +} + +/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} + + * {x2,y2,z2}. + * + * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + * + * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */ +static void point_add_or_double_vartime( + felem x_out, felem y_out, felem z_out, const felem x1, const felem y1, + const felem z1, const felem x2, const felem y2, const felem z2) { + felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp; + char x_equal, y_equal; + + felem_square(z1z1, z1); + felem_square(z2z2, z2); + felem_mul(u1, x1, z2z2); + + felem_sum(tmp, z1, z2); + felem_square(tmp, tmp); + felem_diff(tmp, tmp, z1z1); + felem_diff(tmp, tmp, z2z2); + + felem_mul(z2z2z2, z2, z2z2); + felem_mul(s1, y1, z2z2z2); + + felem_mul(u2, x2, z1z1); + felem_mul(z1z1z1, z1, z1z1); + felem_mul(s2, y2, z1z1z1); + felem_diff(h, u2, u1); + x_equal = felem_is_zero_vartime(h); + felem_sum(i, h, h); + felem_square(i, i); + felem_mul(j, h, i); + felem_diff(r, s2, s1); + y_equal = felem_is_zero_vartime(r); + if (x_equal && y_equal) { + point_double(x_out, y_out, z_out, x1, y1, z1); + return; + } + felem_sum(r, r, r); + felem_mul(v, u1, i); + + felem_mul(z_out, tmp, h); + felem_square(rr, r); + felem_diff(x_out, rr, j); + felem_diff(x_out, x_out, v); + felem_diff(x_out, x_out, v); + + felem_diff(tmp, v, x_out); + felem_mul(y_out, tmp, r); + felem_mul(tmp, s1, j); + felem_diff(y_out, y_out, tmp); + felem_diff(y_out, y_out, tmp); +} + +/* copy_conditional sets out=in if mask = 0xffffffff in constant time. + * + * On entry: mask is either 0 or 0xffffffff. */ +static void copy_conditional(felem out, const felem in, limb mask) { + int i; + + for (i = 0; i < NLIMBS; i++) { + const limb tmp = mask & (in[i] ^ out[i]); + out[i] ^= tmp; + } +} + +/* select_affine_point sets {out_x,out_y} to the index'th entry of table. + * On entry: index < 16, table[0] must be zero. */ +static void select_affine_point(felem out_x, felem out_y, const limb* table, + limb index) { + limb i, j; + + memset(out_x, 0, sizeof(felem)); + memset(out_y, 0, sizeof(felem)); + + for (i = 1; i < 16; i++) { + limb mask = i ^ index; + mask |= mask >> 2; + mask |= mask >> 1; + mask &= 1; + mask--; + for (j = 0; j < NLIMBS; j++, table++) { + out_x[j] |= *table & mask; + } + for (j = 0; j < NLIMBS; j++, table++) { + out_y[j] |= *table & mask; + } + } +} + +/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of + * table. On entry: index < 16, table[0] must be zero. */ +static void select_jacobian_point(felem out_x, felem out_y, felem out_z, + const limb* table, limb index) { + limb i, j; + + memset(out_x, 0, sizeof(felem)); + memset(out_y, 0, sizeof(felem)); + memset(out_z, 0, sizeof(felem)); + + /* The implicit value at index 0 is all zero. We don't need to perform that + * iteration of the loop because we already set out_* to zero. */ + table += 3 * NLIMBS; + + // Hit all entries to obscure cache profiling. + for (i = 1; i < 16; i++) { + limb mask = i ^ index; + mask |= mask >> 2; + mask |= mask >> 1; + mask &= 1; + mask--; + for (j = 0; j < NLIMBS; j++, table++) { + out_x[j] |= *table & mask; + } + for (j = 0; j < NLIMBS; j++, table++) { + out_y[j] |= *table & mask; + } + for (j = 0; j < NLIMBS; j++, table++) { + out_z[j] |= *table & mask; + } + } +} + +/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian + * number. Note that the value of scalar must be less than the order of the + * group. */ +static void scalar_base_mult(felem nx, felem ny, felem nz, + const p256_int* scalar) { + int i, j; + limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask; + u32 table_offset; + + felem px, py; + felem tx, ty, tz; + + memset(nx, 0, sizeof(felem)); + memset(ny, 0, sizeof(felem)); + memset(nz, 0, sizeof(felem)); + + /* The loop adds bits at positions 0, 64, 128 and 192, followed by + * positions 32,96,160 and 224 and does this 32 times. */ + for (i = 0; i < 32; i++) { + if (i) { + point_double(nx, ny, nz, nx, ny, nz); + } + table_offset = 0; + for (j = 0; j <= 32; j += 32) { + char bit0 = p256_get_bit(scalar, 31 - i + j); + char bit1 = p256_get_bit(scalar, 95 - i + j); + char bit2 = p256_get_bit(scalar, 159 - i + j); + char bit3 = p256_get_bit(scalar, 223 - i + j); + limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3); + + select_affine_point(px, py, kPrecomputed + table_offset, index); + table_offset += 30 * NLIMBS; + + /* Since scalar is less than the order of the group, we know that + * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle + * below. */ + point_add_mixed(tx, ty, tz, nx, ny, nz, px, py); + /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero + * (a.k.a. the point at infinity). We handle that situation by + * copying the point from the table. */ + copy_conditional(nx, px, n_is_infinity_mask); + copy_conditional(ny, py, n_is_infinity_mask); + copy_conditional(nz, kOne, n_is_infinity_mask); + + /* Equally, the result is also wrong if the point from the table is + * zero, which happens when the index is zero. We handle that by + * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */ + p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index); + mask = p_is_noninfinite_mask & ~n_is_infinity_mask; + copy_conditional(nx, tx, mask); + copy_conditional(ny, ty, mask); + copy_conditional(nz, tz, mask); + /* If p was not zero, then n is now non-zero. */ + n_is_infinity_mask &= ~p_is_noninfinite_mask; + } + } +} + +/* point_to_affine converts a Jacobian point to an affine point. If the input + * is the point at infinity then it returns (0, 0) in constant time. */ +static void point_to_affine(felem x_out, felem y_out, const felem nx, + const felem ny, const felem nz) { + felem z_inv, z_inv_sq; + felem_inv(z_inv, nz); + felem_square(z_inv_sq, z_inv); + felem_mul(x_out, nx, z_inv_sq); + felem_mul(z_inv, z_inv, z_inv_sq); + felem_mul(y_out, ny, z_inv); +} + +/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */ +static void scalar_mult(felem nx, felem ny, felem nz, const felem x, + const felem y, const p256_int* scalar) { + int i; + felem px, py, pz, tx, ty, tz; + felem precomp[16][3]; + limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask; + + /* We precompute 0,1,2,... times {x,y}. */ + memset(precomp, 0, sizeof(felem) * 3); + memcpy(&precomp[1][0], x, sizeof(felem)); + memcpy(&precomp[1][1], y, sizeof(felem)); + memcpy(&precomp[1][2], kOne, sizeof(felem)); + + for (i = 2; i < 16; i += 2) { + point_double(precomp[i][0], precomp[i][1], precomp[i][2], + precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]); + + point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2], + precomp[i][0], precomp[i][1], precomp[i][2], x, y); + } + + memset(nx, 0, sizeof(felem)); + memset(ny, 0, sizeof(felem)); + memset(nz, 0, sizeof(felem)); + n_is_infinity_mask = -1; + + /* We add in a window of four bits each iteration and do this 64 times. */ + for (i = 0; i < 256; i += 4) { + if (i) { + point_double(nx, ny, nz, nx, ny, nz); + point_double(nx, ny, nz, nx, ny, nz); + point_double(nx, ny, nz, nx, ny, nz); + point_double(nx, ny, nz, nx, ny, nz); + } + + index = (p256_get_bit(scalar, 255 - i - 0) << 3) | + (p256_get_bit(scalar, 255 - i - 1) << 2) | + (p256_get_bit(scalar, 255 - i - 2) << 1) | + p256_get_bit(scalar, 255 - i - 3); + + /* See the comments in scalar_base_mult about handling infinities. */ + select_jacobian_point(px, py, pz, precomp[0][0], index); + point_add(tx, ty, tz, nx, ny, nz, px, py, pz); + copy_conditional(nx, px, n_is_infinity_mask); + copy_conditional(ny, py, n_is_infinity_mask); + copy_conditional(nz, pz, n_is_infinity_mask); + + p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index); + mask = p_is_noninfinite_mask & ~n_is_infinity_mask; + + copy_conditional(nx, tx, mask); + copy_conditional(ny, ty, mask); + copy_conditional(nz, tz, mask); + n_is_infinity_mask &= ~p_is_noninfinite_mask; + } +} + +#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p + +#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff} // 1 / 2^257 mod p256.p + +static const p256_int kR = { kRDigits }; +static const p256_int kRInv = { kRInvDigits }; + +/* to_montgomery sets out = R*in. */ +static void to_montgomery(felem out, const p256_int* in) { + p256_int in_shifted; + int i; + + p256_init(&in_shifted); + p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted); + + for (i = 0; i < NLIMBS; i++) { + if ((i & 1) == 0) { + out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits; + p256_shr(&in_shifted, 29, &in_shifted); + } else { + out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits; + p256_shr(&in_shifted, 28, &in_shifted); + } + } + + p256_clear(&in_shifted); +} + +/* from_montgomery sets out=in/R. */ +static void from_montgomery(p256_int* out, const felem in) { + p256_int result, tmp; + int i, top; + + p256_init(&result); + p256_init(&tmp); + + p256_add_d(&tmp, in[NLIMBS - 1], &result); + for (i = NLIMBS - 2; i >= 0; i--) { + if ((i & 1) == 0) { + top = p256_shl(&result, 29, &tmp); + } else { + top = p256_shl(&result, 28, &tmp); + } + top |= p256_add_d(&tmp, in[i], &result); + } + + p256_modmul(&SECP256r1_p, &kRInv, top, &result, out); + + p256_clear(&result); + p256_clear(&tmp); +} + +/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the + * order of the group. */ +void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) { + felem x, y, z; + + scalar_base_mult(x, y, z, n); + + { + felem x_affine, y_affine; + + point_to_affine(x_affine, y_affine, x, y, z); + from_montgomery(out_x, x_affine); + from_montgomery(out_y, y_affine); + } +} + +/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where + * n1 and n2 are < the order of the group. + * + * As indicated by the name, this function operates in variable time. This + * is safe because it's used for signature validation which doesn't deal + * with secrets. */ +void p256_points_mul_vartime( + const p256_int* n1, const p256_int* n2, const p256_int* in_x, + const p256_int* in_y, p256_int* out_x, p256_int* out_y) { + felem x1, y1, z1, x2, y2, z2, px, py; + + /* If both scalars are zero, then the result is the point at infinity. */ + if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) { + p256_clear(out_x); + p256_clear(out_y); + return; + } + + to_montgomery(px, in_x); + to_montgomery(py, in_y); + scalar_base_mult(x1, y1, z1, n1); + scalar_mult(x2, y2, z2, px, py, n2); + + if (p256_is_zero(n2) != 0) { + /* If n2 == 0, then {x2,y2,z2} is zero and the result is just + * {x1,y1,z1}. */ + } else if (p256_is_zero(n1) != 0) { + /* If n1 == 0, then {x1,y1,z1} is zero and the result is just + * {x2,y2,z2}. */ + memcpy(x1, x2, sizeof(x2)); + memcpy(y1, y2, sizeof(y2)); + memcpy(z1, z2, sizeof(z2)); + } else { + /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */ + point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2); + } + + point_to_affine(px, py, x1, y1, z1); + from_montgomery(out_x, px); + from_montgomery(out_y, py); +} diff --git a/libmincrypt/p256_ecdsa.c b/libmincrypt/p256_ecdsa.c new file mode 100644 index 0000000..f2264b0 --- /dev/null +++ b/libmincrypt/p256_ecdsa.c @@ -0,0 +1,56 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +#include "mincrypt/p256_ecdsa.h" +#include "mincrypt/p256.h" + +int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y, + const p256_int* message, + const p256_int* r, const p256_int* s) { + p256_int u, v; + + // Check public key. + if (!p256_is_valid_point(key_x, key_y)) return 0; + + // Check r and s are != 0 % n. + p256_mod(&SECP256r1_n, r, &u); + p256_mod(&SECP256r1_n, s, &v); + if (p256_is_zero(&u) || p256_is_zero(&v)) return 0; + + p256_modinv_vartime(&SECP256r1_n, s, &v); + p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n + p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n + + p256_points_mul_vartime(&u, &v, + key_x, key_y, + &u, &v); + + p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n + return p256_cmp(r, &u) == 0; +} + diff --git a/libmincrypt/test/Android.mk b/libmincrypt/test/Android.mk index a28ccd8..73ff7d0 100644 --- a/libmincrypt/test/Android.mk +++ b/libmincrypt/test/Android.mk @@ -1,10 +1,15 @@ # Copyright 2013 The Android Open Source Project LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) +include $(CLEAR_VARS) LOCAL_MODULE := rsa_test LOCAL_SRC_FILES := rsa_test.c LOCAL_STATIC_LIBRARIES := libmincrypt -include $(BUILD_HOST_EXECUTABLE) +include $(BUILD_HOST_NATIVE_TEST) +include $(CLEAR_VARS) +LOCAL_MODULE := ecdsa_test +LOCAL_SRC_FILES := ecdsa_test.c +LOCAL_STATIC_LIBRARIES := libmincrypt +include $(BUILD_HOST_NATIVE_TEST) diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c new file mode 100644 index 0000000..b5a7b3a --- /dev/null +++ b/libmincrypt/test/ecdsa_test.c @@ -0,0 +1,278 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "mincrypt/p256.h" +#include "mincrypt/p256_ecdsa.h" +#include "mincrypt/sha256.h" + +/** + * Messages signed using: + * +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDw6UiziVMbjlfSpOAIpA2tcL+v1OlznZLnpadO8BGi1oAoGCCqGSM49 +AwEHoUQDQgAEZw7VAOjAXYRFuhZWYBgjahdOvkwcAnjGkxQWytZW+iS1hI3ZGE24 +6XmNka9IGxAgj2n/ip+MuZJMFoJ9DRea3g== +-----END EC PRIVATE KEY----- + */ + +p256_int key_x = { + .a = {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu, + 0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u} +}; +p256_int key_y = { + .a = {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au, + 0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u} +}; + +char* message_1 = + "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59" + "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3" + "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e" + "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe" + "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02" + "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3" + "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d" + "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08" + "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9" + "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6" + "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e" + "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de" + "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5" + "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d" + "d5 9d 73 be 12"; + +char* signature_1 = + "30 44 02 20 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7" + "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66" + "7c 98 25 d9 02 20 54 f3 7f 5a e9 36 9c a2 f0 51" + "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7" + "ea 57 7e 88 46 12"; + +// Same as signature 1, but with leading zeroes. +char* message_2 = + "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59" + "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3" + "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e" + "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe" + "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02" + "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3" + "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d" + "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08" + "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9" + "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6" + "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e" + "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de" + "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5" + "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d" + "d5 9d 73 be 12"; + +char* signature_2 = + "30 46 02 21 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7" + "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66" + "7c 98 25 d9 02 21 00 54 f3 7f 5a e9 36 9c a2 f0 51" + "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7" + "ea 57 7e 88 46 12"; + +// Excessive zeroes on the signature +char* message_3 = + "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59" + "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3" + "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e" + "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe" + "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02" + "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3" + "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d" + "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08" + "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9" + "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6" + "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e" + "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de" + "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5" + "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d" + "d5 9d 73 be 12"; + +char* signature_3 = + "30 4c 02 24 00 00 00 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7" + "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66" + "7c 98 25 d9 02 24 00 00 00 00 54 f3 7f 5a e9 36 9c a2 f0 51" + "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7" + "ea 57 7e 88 46 12"; + + +char* good_dsa_signature_1 = + "30 0D 02 01 01 02 08 00 A5 55 5A 01 FF A5 01"; +p256_int good_dsa_signature_1_r = { + .a = {0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U, + 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U} +}; +p256_int good_dsa_signature_1_s = { + .a = {0x01FFA501U, 0x00A5555AU, 0x00000000U, 0x00000000U, + 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U} +}; + + +char* bad_dsa_signature_1 = + "a0 06 02 01 01 02 01 01"; + +char* bad_dsa_signature_2 = + "30 07 02 01 01 02 01 01"; + +char* bad_dsa_signature_3 = + "30 06 82 01 01 02 01 01"; + +char* bad_dsa_signature_4 = + "30 06 02 00 01 02 01 01"; + +char* bad_dsa_signature_5 = + "30 06 02 01 01 82 01 01"; + +char* bad_dsa_signature_6 = + "30 05 02 01 01 02 00"; + +char* bad_dsa_signature_7 = + "30 06 02 01 01 02 00 01"; + +unsigned char* parsehex(char* str, int* len) { + // result can't be longer than input + unsigned char* result = malloc(strlen(str)); + + unsigned char* p = result; + *len = 0; + + while (*str) { + int b; + + while (isspace(*str)) str++; + + switch (*str) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + b = (*str - '0') << 4; break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + b = (*str - 'a' + 10) << 4; break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + b = (*str - 'A' + 10) << 4; break; + case '\0': + return result; + default: + return NULL; + } + str++; + + while (isspace(*str)) str++; + + switch (*str) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + b |= *str - '0'; break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + b |= *str - 'a' + 10; break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + b |= *str - 'A' + 10; break; + default: + return NULL; + } + str++; + + *p++ = b; + ++*len; + } + + return result; +} + +int main(int arg, char** argv) { + + unsigned char hash_buf[SHA256_DIGEST_SIZE]; + + unsigned char* message; + int mlen; + unsigned char* signature; + int slen; + + p256_int hash; + p256_int r; + p256_int s; + + int success = 1; + +#define CHECK_DSA_SIG(sig, good) do {\ + message = parsehex(sig, &mlen); \ + int result = dsa_sig_unpack(message, mlen, &r, &s); \ + printf(#sig ": %s\n", result ? "good" : "bad"); \ + success = success && !(good ^ result); \ + free(message); \ + } while(0) +#define CHECK_GOOD_DSA_SIG(n) do {\ + CHECK_DSA_SIG(good_dsa_signature_##n, 1); \ + int result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_r), P256_DIGITS(&r), \ + P256_NBYTES); \ + success = success && result; \ + printf(" R value %s\n", result ? "good" : "bad"); \ + result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_s), P256_DIGITS(&s), \ + P256_NBYTES); \ + success = success && result; \ + printf(" S value %s\n", result ? "good" : "bad"); \ + } while (0) +#define CHECK_BAD_DSA_SIG(n) \ + CHECK_DSA_SIG(bad_dsa_signature_##n, 0) + + CHECK_GOOD_DSA_SIG(1); + + CHECK_BAD_DSA_SIG(1); + CHECK_BAD_DSA_SIG(2); + CHECK_BAD_DSA_SIG(3); + CHECK_BAD_DSA_SIG(4); + CHECK_BAD_DSA_SIG(5); + CHECK_BAD_DSA_SIG(6); + CHECK_BAD_DSA_SIG(7); + + +#define TEST_MESSAGE(n) do {\ + message = parsehex(message_##n, &mlen); \ + SHA256_hash(message, mlen, hash_buf); \ + p256_from_bin(hash_buf, &hash); \ + signature = parsehex(signature_##n, &slen); \ + int result = dsa_sig_unpack(signature, slen, &r, &s); \ + if (result) { result = p256_ecdsa_verify(&key_x, &key_y, &hash, &r, &s); } \ + printf("message %d: %s\n", n, result ? "verified" : "not verified"); \ + success = success && result; \ + free(signature); \ + } while(0) + + TEST_MESSAGE(1); + TEST_MESSAGE(2); + TEST_MESSAGE(3); + + printf("\n%s\n\n", success ? "PASS" : "FAIL"); + + return !success; +} diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk index b61234a..3154914 100644 --- a/libmincrypt/tools/Android.mk +++ b/libmincrypt/tools/Android.mk @@ -13,9 +13,10 @@ # limitations under the License. LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) +include $(CLEAR_VARS) LOCAL_MODULE := dumpkey LOCAL_SRC_FILES := DumpPublicKey.java LOCAL_JAR_MANIFEST := DumpPublicKey.mf +LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java index 7189116..3eb1398 100644 --- a/libmincrypt/tools/DumpPublicKey.java +++ b/libmincrypt/tools/DumpPublicKey.java @@ -16,6 +16,8 @@ package com.android.dumpkey; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + import java.io.FileInputStream; import java.math.BigInteger; import java.security.cert.CertificateFactory; @@ -23,7 +25,10 @@ import java.security.cert.X509Certificate; import java.security.KeyStore; import java.security.Key; import java.security.PublicKey; +import java.security.Security; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; +import java.security.spec.ECPoint; /** * Command line tool to extract RSA public keys from X.509 certificates @@ -39,9 +44,8 @@ class DumpPublicKey { * 3: 2048-bit RSA key with e=3 and SHA-256 hash * 4: 2048-bit RSA key with e=65537 and SHA-256 hash * @throws Exception if the key has the wrong size or public exponent - */ - static int check(RSAPublicKey key, boolean useSHA256) throws Exception { + static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception { BigInteger pubexp = key.getPublicExponent(); BigInteger modulus = key.getModulus(); int version; @@ -64,12 +68,42 @@ class DumpPublicKey { } /** + * @param key to perform sanity checks on + * @return version number of key. Supported versions are: + * 5: 256-bit EC key with curve NIST P-256 + * @throws Exception if the key has the wrong size or public exponent + */ + static int checkEC(ECPublicKey key) throws Exception { + if (key.getParams().getCurve().getField().getFieldSize() != 256) { + throw new Exception("Curve must be NIST P-256"); + } + + return 5; + } + + /** + * Perform sanity check on public key. + */ + static int check(PublicKey key, boolean useSHA256) throws Exception { + if (key instanceof RSAPublicKey) { + return checkRSA((RSAPublicKey) key, useSHA256); + } else if (key instanceof ECPublicKey) { + if (!useSHA256) { + throw new Exception("Must use SHA-256 with EC keys!"); + } + return checkEC((ECPublicKey) key); + } else { + throw new Exception("Unsupported key class: " + key.getClass().getName()); + } + } + + /** * @param key to output * @return a String representing this public key. If the key is a * version 1 key, the string will be a C initializer; this is * not true for newer key versions. */ - static String print(RSAPublicKey key, boolean useSHA256) throws Exception { + static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception { int version = check(key, useSHA256); BigInteger N = key.getModulus(); @@ -128,11 +162,78 @@ class DumpPublicKey { return result.toString(); } + /** + * @param key to output + * @return a String representing this public key. If the key is a + * version 1 key, the string will be a C initializer; this is + * not true for newer key versions. + */ + static String printEC(ECPublicKey key) throws Exception { + int version = checkEC(key); + + StringBuilder result = new StringBuilder(); + + result.append("v"); + result.append(Integer.toString(version)); + result.append(" "); + + BigInteger X = key.getW().getAffineX(); + BigInteger Y = key.getW().getAffineY(); + int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate + + result.append("{"); + result.append(nbytes); + + BigInteger B = BigInteger.valueOf(0x100L); // 2^8 + + // Write out Y coordinate as array of characters. + result.append(",{"); + for (int i = 0; i < nbytes; ++i) { + long n = X.mod(B).longValue(); + result.append(n); + + if (i != nbytes - 1) { + result.append(","); + } + + X = X.divide(B); + } + result.append("}"); + + // Write out Y coordinate as array of characters. + result.append(",{"); + for (int i = 0; i < nbytes; ++i) { + long n = Y.mod(B).longValue(); + result.append(n); + + if (i != nbytes - 1) { + result.append(","); + } + + Y = Y.divide(B); + } + result.append("}"); + + result.append("}"); + return result.toString(); + } + + static String print(PublicKey key, boolean useSHA256) throws Exception { + if (key instanceof RSAPublicKey) { + return printRSA((RSAPublicKey) key, useSHA256); + } else if (key instanceof ECPublicKey) { + return printEC((ECPublicKey) key); + } else { + throw new Exception("Unsupported key class: " + key.getClass().getName()); + } + } + public static void main(String[] args) { if (args.length < 1) { System.err.println("Usage: DumpPublicKey certfile ... > source.c"); System.exit(1); } + Security.addProvider(new BouncyCastleProvider()); try { for (int i = 0; i < args.length; i++) { FileInputStream input = new FileInputStream(args[i]); @@ -147,7 +248,7 @@ class DumpPublicKey { // anyway. Continue to do so for backwards // compatibility. useSHA256 = false; - } else if ("SHA256withRSA".equals(sigAlg)) { + } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) { useSHA256 = true; } else { System.err.println(args[i] + ": unsupported signature algorithm \"" + @@ -155,7 +256,7 @@ class DumpPublicKey { System.exit(1); } - RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey()); + PublicKey key = cert.getPublicKey(); check(key, useSHA256); System.out.print(print(key, useSHA256)); System.out.println(i < args.length - 1 ? "," : ""); diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index eb33d06..4d004f6 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -50,6 +50,11 @@ #define ALOGW printf #endif +#ifdef HAVE_ANDROID_OS +/* SIOCKILLADDR is an Android extension. */ +#define SIOCKILLADDR 0x8939 +#endif + static int ifc_ctl_sock = -1; static int ifc_ctl_sock6 = -1; void printerr(char *fmt, ...); diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c index dfb217b..3e72b57 100644 --- a/libsparse/backed_block.c +++ b/libsparse/backed_block.c @@ -370,7 +370,7 @@ int backed_block_split(struct backed_block_list *bbl, struct backed_block *bb, } new_bb = malloc(sizeof(struct backed_block)); - if (bb == NULL) { + if (new_bb == NULL) { return -ENOMEM; } diff --git a/libsparse/output_file.c b/libsparse/output_file.c index 5014e4a..a28b0a5 100644 --- a/libsparse/output_file.c +++ b/libsparse/output_file.c @@ -46,15 +46,6 @@ #define off64_t off_t #endif -#ifdef __BIONIC__ -extern void* __mmap2(void *, size_t, int, int, int, off_t); -static inline void *mmap64(void *addr, size_t length, int prot, int flags, - int fd, off64_t offset) -{ - return __mmap2(addr, length, prot, flags, fd, offset >> 12); -} -#endif - #define min(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) @@ -731,10 +722,12 @@ int write_fd_chunk(struct output_file *out, unsigned int len, } pos = lseek64(fd, offset, SEEK_SET); if (pos < 0) { + free(data); return -errno; } ret = read_all(fd, data, len); if (ret < 0) { + free(data); return ret; } ptr = data; diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index aae2ae7..9f2606c 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -24,6 +24,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> +#include <netinet/icmp6.h> #include <arpa/inet.h> #include <net/if.h> @@ -44,6 +45,7 @@ const int NetlinkEvent::NlActionLinkUp = 4; const int NetlinkEvent::NlActionLinkDown = 5; const int NetlinkEvent::NlActionAddressUpdated = 6; const int NetlinkEvent::NlActionAddressRemoved = 7; +const int NetlinkEvent::NlActionRdnss = 8; NetlinkEvent::NetlinkEvent() { mAction = NlActionUnknown; @@ -76,7 +78,7 @@ void NetlinkEvent::dump() { } /* - * Decode a RTM_NEWADDR or RTM_DELADDR message. + * Parse a RTM_NEWADDR or RTM_DELADDR message. */ bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize) { @@ -172,13 +174,111 @@ bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, } /* - * Parse an binary message from a NETLINK_ROUTE netlink socket. + * Parse a RTM_NEWNDUSEROPT message. + */ +bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) { + // Check the length is valid. + if (msg->nduseropt_opts_len > len) { + SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n", + msg->nduseropt_opts_len, len); + return false; + } + len = msg->nduseropt_opts_len; + + // Check address family and packet type. + if (msg->nduseropt_family != AF_INET6) { + SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n", + msg->nduseropt_family); + return false; + } + + if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT || + msg->nduseropt_icmp_code != 0) { + SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n", + msg->nduseropt_icmp_type, msg->nduseropt_icmp_code); + return false; + } + + // Find the interface name. + char ifname[IFNAMSIZ + 1]; + if (!if_indextoname(msg->nduseropt_ifindex, ifname)) { + SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n", + msg->nduseropt_ifindex); + return false; + } + + // The kernel sends a separate netlink message for each ND option in the RA. + // So only parse the first ND option in the message. + struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1); + + // The length is in multiples of 8 octets. + uint16_t optlen = opthdr->nd_opt_len; + if (optlen * 8 > len) { + SLOGE("Invalid option length %d > %d for ND option %d\n", + optlen * 8, len, opthdr->nd_opt_type); + return false; + } + + if (opthdr->nd_opt_type == ND_OPT_RDNSS) { + // DNS Servers (RFC 6106). + // Each address takes up 2*8 octets, and the header takes up 8 octets. + // So for a valid option with one or more addresses, optlen must be + // odd and greater than 1. + if ((optlen < 3) || !(optlen & 0x1)) { + SLOGE("Invalid optlen %d for RDNSS option\n", optlen); + return false; + } + int numaddrs = (optlen - 1) / 2; + + // Find the lifetime. + struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr; + uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime); + + // Construct "SERVERS=<comma-separated string of DNS addresses>". + // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the + // the last address are followed by ','; the last is followed by '\0'. + static const char kServerTag[] = "SERVERS="; + static const int kTagLength = sizeof(kServerTag) - 1; + int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1); + char *buf = (char *) malloc(bufsize); + if (!buf) { + SLOGE("RDNSS option: out of memory\n"); + return false; + } + strcpy(buf, kServerTag); + int pos = kTagLength; + + struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1); + for (int i = 0; i < numaddrs; i++) { + if (i > 0) { + buf[pos++] = ','; + } + inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos); + pos += strlen(buf + pos); + } + buf[pos] = '\0'; + + mAction = NlActionRdnss; + mSubsystem = strdup("net"); + asprintf(&mParams[0], "INTERFACE=%s", ifname); + asprintf(&mParams[1], "LIFETIME=%u", lifetime); + mParams[2] = buf; + } else { + SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type); + return false; + } + + return true; +} + +/* + * Parse a binary message from a NETLINK_ROUTE netlink socket. */ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { const struct nlmsghdr *nh; for (nh = (struct nlmsghdr *) buffer; - NLMSG_OK(nh, size) && (nh->nlmsg_type != NLMSG_DONE); + NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); nh = NLMSG_NEXT(nh, size)) { if (nh->nlmsg_type == RTM_NEWLINK) { @@ -245,8 +345,25 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) { continue; } + + } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) { + int len = nh->nlmsg_len - sizeof(*nh); + struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh); + + if (sizeof(*ndmsg) > (size_t) len) { + SLOGE("Got a short RTM_NEWNDUSEROPT message\n"); + continue; + } + + size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg)); + if (!parseNdUserOptMessage(ndmsg, optsize)) { + continue; + } + + } else { - SLOGD("Unexpected netlink message. type=0x%x\n", nh->nlmsg_type); + SLOGD("Unexpected netlink message. type=0x%x\n", + nh->nlmsg_type); } } diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp index 5a79647..30ca663 100644 --- a/libutils/VectorImpl.cpp +++ b/libutils/VectorImpl.cpp @@ -384,7 +384,11 @@ void* VectorImpl::_grow(size_t where, size_t amount) { const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage); SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); + if (sb) { + mStorage = sb->data(); + } else { + return NULL; + } } else { SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); if (sb) { @@ -399,6 +403,8 @@ void* VectorImpl::_grow(size_t where, size_t amount) } release_storage(); mStorage = const_cast<void*>(array); + } else { + return NULL; } } } else { @@ -436,7 +442,11 @@ void VectorImpl::_shrink(size_t where, size_t amount) { const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage); SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); + if (sb) { + mStorage = sb->data(); + } else { + return; + } } else { SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); if (sb) { @@ -451,6 +461,8 @@ void VectorImpl::_shrink(size_t where, size_t amount) } release_storage(); mStorage = const_cast<void*>(array); + } else{ + return; } } } else { diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h index 242ab35..9171d85 100644 --- a/mkbootimg/bootimg.h +++ b/mkbootimg/bootimg.h @@ -24,6 +24,7 @@ typedef struct boot_img_hdr boot_img_hdr; #define BOOT_MAGIC_SIZE 8 #define BOOT_NAME_SIZE 16 #define BOOT_ARGS_SIZE 512 +#define BOOT_EXTRA_ARGS_SIZE 1024 struct boot_img_hdr { @@ -43,10 +44,14 @@ struct boot_img_hdr unsigned unused[2]; /* future expansion: should be 0 */ unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ - + unsigned char cmdline[BOOT_ARGS_SIZE]; unsigned id[8]; /* timestamp / checksum / sha1 / etc */ + + /* Supplemental command line data; kept here to maintain + * binary compatibility with older versions of mkbootimg */ + unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE]; }; /* diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c index 34a879b..d598f03 100644 --- a/mkbootimg/mkbootimg.c +++ b/mkbootimg/mkbootimg.c @@ -114,6 +114,7 @@ int main(int argc, char **argv) unsigned ramdisk_offset = 0x01000000; unsigned second_offset = 0x00f00000; unsigned tags_offset = 0x00000100; + size_t cmdlen; argc--; argv++; @@ -192,11 +193,19 @@ int main(int argc, char **argv) memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); - if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) { + cmdlen = strlen(cmdline); + if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) { fprintf(stderr,"error: kernel commandline too large\n"); return 1; } - strcpy((char*)hdr.cmdline, cmdline); + /* Even if we need to use the supplemental field, ensure we + * are still NULL-terminated */ + strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1); + hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0'; + if (cmdlen >= (BOOT_ARGS_SIZE - 1)) { + cmdline += (BOOT_ARGS_SIZE - 1); + strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE); + } kernel_data = load_file(kernel_fn, &hdr.kernel_size); if(kernel_data == 0) { diff --git a/rootdir/init.rc b/rootdir/init.rc index 21ebccb..3976032 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -17,6 +17,9 @@ on early-init # This should occur before anything else (e.g. ueventd) is started. setcon u:r:init:s0 + # Set the security context of /adb_keys if present. + restorecon /adb_keys + start ueventd # create mountpoints @@ -221,6 +224,10 @@ on post-fs-data mkdir /data/local 0751 root root mkdir /data/misc/media 0700 media media + # Set security context of any pre-existing /data/misc/adb/adb_keys file. + restorecon /data/misc/adb + restorecon /data/misc/adb/adb_keys + # For security reasons, /data/local/tmp should always be empty. # Do not place files or directories in /data/local/tmp mkdir /data/local/tmp 0771 shell shell @@ -258,6 +265,9 @@ on post-fs-data # Separate location for storing security policy files on data mkdir /data/security 0711 system system + # Reload policy from /data/security if present. + setprop selinux.reload_policy 1 + # If there is no fs-post-data action in the init.<device>.rc file, you # must uncomment this line, otherwise encrypted filesystems # won't work. @@ -352,22 +362,22 @@ on boot chown root radio /proc/cmdline # Set these so we can remotely update SELinux policy - chown system system /sys/fs/selinux/load chown system system /sys/fs/selinux/enforce # Define TCP buffer sizes for various networks # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax, - setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208 - setprop net.tcp.buffersize.wifi 524288,1048576,2097152,262144,524288,1048576 - setprop net.tcp.buffersize.lte 524288,1048576,2097152,262144,524288,1048576 - setprop net.tcp.buffersize.umts 4094,87380,110208,4096,16384,110208 - setprop net.tcp.buffersize.hspa 4094,87380,262144,4096,16384,262144 - setprop net.tcp.buffersize.hsupa 4094,87380,262144,4096,16384,262144 - setprop net.tcp.buffersize.hsdpa 4094,87380,262144,4096,16384,262144 - setprop net.tcp.buffersize.hspap 4094,87380,1220608,4096,16384,1220608 - setprop net.tcp.buffersize.edge 4093,26280,35040,4096,16384,35040 - setprop net.tcp.buffersize.gprs 4092,8760,11680,4096,8760,11680 - setprop net.tcp.buffersize.evdo 4094,87380,262144,4096,16384,262144 + setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208 + setprop net.tcp.buffersize.wifi 524288,1048576,2097152,262144,524288,1048576 + setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152 + setprop net.tcp.buffersize.lte 524288,1048576,2097152,262144,524288,1048576 + setprop net.tcp.buffersize.umts 4094,87380,110208,4096,16384,110208 + setprop net.tcp.buffersize.hspa 4094,87380,262144,4096,16384,262144 + setprop net.tcp.buffersize.hsupa 4094,87380,262144,4096,16384,262144 + setprop net.tcp.buffersize.hsdpa 4094,87380,262144,4096,16384,262144 + setprop net.tcp.buffersize.hspap 4094,87380,1220608,4096,16384,1220608 + setprop net.tcp.buffersize.edge 4093,26280,35040,4096,16384,35040 + setprop net.tcp.buffersize.gprs 4092,8760,11680,4096,8760,11680 + setprop net.tcp.buffersize.evdo 4094,87380,262144,4096,16384,262144 class_start core class_start main @@ -422,10 +432,6 @@ service healthd-charger /sbin/healthd -n critical seclabel u:r:healthd:s0 -on property:selinux.reload_policy=1 - restart ueventd - restart installd - service console /system/bin/sh class core console diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index 2cf0265..a60cfc5 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -5,6 +5,8 @@ /dev/tty 0666 root root /dev/random 0666 root root /dev/urandom 0666 root root +# Make HW RNG readable by group system to let EntropyMixer read it. +/dev/hw_random 0440 root system /dev/ashmem 0666 root root /dev/binder 0666 root root diff --git a/sh/Android.mk b/sh/Android.mk deleted file mode 100644 index dcd13d8..0000000 --- a/sh/Android.mk +++ /dev/null @@ -1,70 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - alias.c \ - arith.c \ - arith_lex.c \ - builtins.c \ - cd.c \ - error.c \ - eval.c \ - exec.c \ - expand.c \ - input.c \ - jobs.c \ - main.c \ - memalloc.c \ - miscbltin.c \ - mystring.c \ - nodes.c \ - options.c \ - parser.c \ - redir.c \ - show.c \ - syntax.c \ - trap.c \ - output.c \ - var.c \ - bltin/echo.c \ - init.c - -LOCAL_MODULE:= ash -LOCAL_MODULE_TAGS:= shell_ash - -LOCAL_CFLAGS += -DSHELL -DWITH_LINENOISE - -LOCAL_STATIC_LIBRARIES := liblinenoise - -LOCAL_C_INCLUDES += system/core/liblinenoise - -make_ash_files: PRIVATE_SRC_FILES := $(SRC_FILES) -make_ash_files: PRIVATE_CFLAGS := $(LOCAL_CFLAGS) -make_ash_files: - p4 edit arith.c arith_lex.c arith.h builtins.h builtins.c - p4 edit init.c nodes.c nodes.h token.h - sh ./mktokens - bison -o arith.c arith.y - flex -o arith_lex.c arith_lex.l - perl -ne 'print if ( /^\#\s*define\s+ARITH/ );' < arith.c > arith.h - sh ./mkbuiltins shell.h builtins.def . -Wall -O2 - sh ./mknodes.sh nodetypes nodes.c.pat . - sh ./mkinit.sh $(PRIVATE_SRC_FILES) - -include $(BUILD_EXECUTABLE) - - -# create /system/bin/sh symlink to $(TARGET_SHELL) -# not the optimal place for this, but a fitting one - -OUTSYSTEMBINSH := $(TARGET_OUT)/bin/sh -LOCAL_MODULE := systembinsh -$(OUTSYSTEMBINSH): | $(TARGET_SHELL) -$(OUTSYSTEMBINSH): LOCAL_MODULE := $(LOCAL_MODULE) -$(OUTSYSTEMBINSH): - @echo "Symlink: $@ -> $(TARGET_SHELL)" - @rm -rf $@ - $(hide) ln -sf $(TARGET_SHELL) $@ - -ALL_DEFAULT_INSTALLED_MODULES += $(OUTSYSTEMBINSH) -ALL_MODULES.$(LOCAL_MODULE).INSTALLED += $(OUTSYSTEMBINSH) diff --git a/sh/MODULE_LICENSE_BSD b/sh/MODULE_LICENSE_BSD deleted file mode 100644 index e69de29..0000000 --- a/sh/MODULE_LICENSE_BSD +++ /dev/null diff --git a/sh/NOTICE b/sh/NOTICE deleted file mode 100644 index 49a66d2..0000000 --- a/sh/NOTICE +++ /dev/null @@ -1,31 +0,0 @@ -Copyright (c) 1991, 1993 - The Regents of the University of California. All rights reserved. - -This code is derived from software contributed to Berkeley by -Kenneth Almquist. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - - diff --git a/sh/TOUR b/sh/TOUR deleted file mode 100644 index f5c00c4..0000000 --- a/sh/TOUR +++ /dev/null @@ -1,357 +0,0 @@ -# $NetBSD: TOUR,v 1.8 1996/10/16 14:24:56 christos Exp $ -# @(#)TOUR 8.1 (Berkeley) 5/31/93 - -NOTE -- This is the original TOUR paper distributed with ash and -does not represent the current state of the shell. It is provided anyway -since it provides helpful information for how the shell is structured, -but be warned that things have changed -- the current shell is -still under development. - -================================================================ - - A Tour through Ash - - Copyright 1989 by Kenneth Almquist. - - -DIRECTORIES: The subdirectory bltin contains commands which can -be compiled stand-alone. The rest of the source is in the main -ash directory. - -SOURCE CODE GENERATORS: Files whose names begin with "mk" are -programs that generate source code. A complete list of these -programs is: - - program intput files generates - ------- ------------ --------- - mkbuiltins builtins builtins.h builtins.c - mkinit *.c init.c - mknodes nodetypes nodes.h nodes.c - mksignames - signames.h signames.c - mksyntax - syntax.h syntax.c - mktokens - token.h - bltin/mkexpr unary_op binary_op operators.h operators.c - -There are undoubtedly too many of these. Mkinit searches all the -C source files for entries looking like: - - INIT { - x = 1; /* executed during initialization */ - } - - RESET { - x = 2; /* executed when the shell does a longjmp - back to the main command loop */ - } - - SHELLPROC { - x = 3; /* executed when the shell runs a shell procedure */ - } - -It pulls this code out into routines which are when particular -events occur. The intent is to improve modularity by isolating -the information about which modules need to be explicitly -initialized/reset within the modules themselves. - -Mkinit recognizes several constructs for placing declarations in -the init.c file. - INCLUDE "file.h" -includes a file. The storage class MKINIT makes a declaration -available in the init.c file, for example: - MKINIT int funcnest; /* depth of function calls */ -MKINIT alone on a line introduces a structure or union declara- -tion: - MKINIT - struct redirtab { - short renamed[10]; - }; -Preprocessor #define statements are copied to init.c without any -special action to request this. - -INDENTATION: The ash source is indented in multiples of six -spaces. The only study that I have heard of on the subject con- -cluded that the optimal amount to indent is in the range of four -to six spaces. I use six spaces since it is not too big a jump -from the widely used eight spaces. If you really hate six space -indentation, use the adjind (source included) program to change -it to something else. - -EXCEPTIONS: Code for dealing with exceptions appears in -exceptions.c. The C language doesn't include exception handling, -so I implement it using setjmp and longjmp. The global variable -exception contains the type of exception. EXERROR is raised by -calling error. EXINT is an interrupt. EXSHELLPROC is an excep- -tion which is raised when a shell procedure is invoked. The pur- -pose of EXSHELLPROC is to perform the cleanup actions associated -with other exceptions. After these cleanup actions, the shell -can interpret a shell procedure itself without exec'ing a new -copy of the shell. - -INTERRUPTS: In an interactive shell, an interrupt will cause an -EXINT exception to return to the main command loop. (Exception: -EXINT is not raised if the user traps interrupts using the trap -command.) The INTOFF and INTON macros (defined in exception.h) -provide uninterruptable critical sections. Between the execution -of INTOFF and the execution of INTON, interrupt signals will be -held for later delivery. INTOFF and INTON can be nested. - -MEMALLOC.C: Memalloc.c defines versions of malloc and realloc -which call error when there is no memory left. It also defines a -stack oriented memory allocation scheme. Allocating off a stack -is probably more efficient than allocation using malloc, but the -big advantage is that when an exception occurs all we have to do -to free up the memory in use at the time of the exception is to -restore the stack pointer. The stack is implemented using a -linked list of blocks. - -STPUTC: If the stack were contiguous, it would be easy to store -strings on the stack without knowing in advance how long the -string was going to be: - p = stackptr; - *p++ = c; /* repeated as many times as needed */ - stackptr = p; -The folloing three macros (defined in memalloc.h) perform these -operations, but grow the stack if you run off the end: - STARTSTACKSTR(p); - STPUTC(c, p); /* repeated as many times as needed */ - grabstackstr(p); - -We now start a top-down look at the code: - -MAIN.C: The main routine performs some initialization, executes -the user's profile if necessary, and calls cmdloop. Cmdloop is -repeatedly parses and executes commands. - -OPTIONS.C: This file contains the option processing code. It is -called from main to parse the shell arguments when the shell is -invoked, and it also contains the set builtin. The -i and -j op- -tions (the latter turns on job control) require changes in signal -handling. The routines setjobctl (in jobs.c) and setinteractive -(in trap.c) are called to handle changes to these options. - -PARSING: The parser code is all in parser.c. A recursive des- -cent parser is used. Syntax tables (generated by mksyntax) are -used to classify characters during lexical analysis. There are -three tables: one for normal use, one for use when inside single -quotes, and one for use when inside double quotes. The tables -are machine dependent because they are indexed by character vari- -ables and the range of a char varies from machine to machine. - -PARSE OUTPUT: The output of the parser consists of a tree of -nodes. The various types of nodes are defined in the file node- -types. - -Nodes of type NARG are used to represent both words and the con- -tents of here documents. An early version of ash kept the con- -tents of here documents in temporary files, but keeping here do- -cuments in memory typically results in significantly better per- -formance. It would have been nice to make it an option to use -temporary files for here documents, for the benefit of small -machines, but the code to keep track of when to delete the tem- -porary files was complex and I never fixed all the bugs in it. -(AT&T has been maintaining the Bourne shell for more than ten -years, and to the best of my knowledge they still haven't gotten -it to handle temporary files correctly in obscure cases.) - -The text field of a NARG structure points to the text of the -word. The text consists of ordinary characters and a number of -special codes defined in parser.h. The special codes are: - - CTLVAR Variable substitution - CTLENDVAR End of variable substitution - CTLBACKQ Command substitution - CTLBACKQ|CTLQUOTE Command substitution inside double quotes - CTLESC Escape next character - -A variable substitution contains the following elements: - - CTLVAR type name '=' [ alternative-text CTLENDVAR ] - -The type field is a single character specifying the type of sub- -stitution. The possible types are: - - VSNORMAL $var - VSMINUS ${var-text} - VSMINUS|VSNUL ${var:-text} - VSPLUS ${var+text} - VSPLUS|VSNUL ${var:+text} - VSQUESTION ${var?text} - VSQUESTION|VSNUL ${var:?text} - VSASSIGN ${var=text} - VSASSIGN|VSNUL ${var=text} - -In addition, the type field will have the VSQUOTE flag set if the -variable is enclosed in double quotes. The name of the variable -comes next, terminated by an equals sign. If the type is not -VSNORMAL, then the text field in the substitution follows, ter- -minated by a CTLENDVAR byte. - -Commands in back quotes are parsed and stored in a linked list. -The locations of these commands in the string are indicated by -CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether -the back quotes were enclosed in double quotes. - -The character CTLESC escapes the next character, so that in case -any of the CTL characters mentioned above appear in the input, -they can be passed through transparently. CTLESC is also used to -escape '*', '?', '[', and '!' characters which were quoted by the -user and thus should not be used for file name generation. - -CTLESC characters have proved to be particularly tricky to get -right. In the case of here documents which are not subject to -variable and command substitution, the parser doesn't insert any -CTLESC characters to begin with (so the contents of the text -field can be written without any processing). Other here docu- -ments, and words which are not subject to splitting and file name -generation, have the CTLESC characters removed during the vari- -able and command substitution phase. Words which are subject -splitting and file name generation have the CTLESC characters re- -moved as part of the file name phase. - -EXECUTION: Command execution is handled by the following files: - eval.c The top level routines. - redir.c Code to handle redirection of input and output. - jobs.c Code to handle forking, waiting, and job control. - exec.c Code to to path searches and the actual exec sys call. - expand.c Code to evaluate arguments. - var.c Maintains the variable symbol table. Called from expand.c. - -EVAL.C: Evaltree recursively executes a parse tree. The exit -status is returned in the global variable exitstatus. The alter- -native entry evalbackcmd is called to evaluate commands in back -quotes. It saves the result in memory if the command is a buil- -tin; otherwise it forks off a child to execute the command and -connects the standard output of the child to a pipe. - -JOBS.C: To create a process, you call makejob to return a job -structure, and then call forkshell (passing the job structure as -an argument) to create the process. Waitforjob waits for a job -to complete. These routines take care of process groups if job -control is defined. - -REDIR.C: Ash allows file descriptors to be redirected and then -restored without forking off a child process. This is accom- -plished by duplicating the original file descriptors. The redir- -tab structure records where the file descriptors have be dupli- -cated to. - -EXEC.C: The routine find_command locates a command, and enters -the command in the hash table if it is not already there. The -third argument specifies whether it is to print an error message -if the command is not found. (When a pipeline is set up, -find_command is called for all the commands in the pipeline be- -fore any forking is done, so to get the commands into the hash -table of the parent process. But to make command hashing as -transparent as possible, we silently ignore errors at that point -and only print error messages if the command cannot be found -later.) - -The routine shellexec is the interface to the exec system call. - -EXPAND.C: Arguments are processed in three passes. The first -(performed by the routine argstr) performs variable and command -substitution. The second (ifsbreakup) performs word splitting -and the third (expandmeta) performs file name generation. If the -"/u" directory is simulated, then when "/u/username" is replaced -by the user's home directory, the flag "didudir" is set. This -tells the cd command that it should print out the directory name, -just as it would if the "/u" directory were implemented using -symbolic links. - -VAR.C: Variables are stored in a hash table. Probably we should -switch to extensible hashing. The variable name is stored in the -same string as the value (using the format "name=value") so that -no string copying is needed to create the environment of a com- -mand. Variables which the shell references internally are preal- -located so that the shell can reference the values of these vari- -ables without doing a lookup. - -When a program is run, the code in eval.c sticks any environment -variables which precede the command (as in "PATH=xxx command") in -the variable table as the simplest way to strip duplicates, and -then calls "environment" to get the value of the environment. -There are two consequences of this. First, if an assignment to -PATH precedes the command, the value of PATH before the assign- -ment must be remembered and passed to shellexec. Second, if the -program turns out to be a shell procedure, the strings from the -environment variables which preceded the command must be pulled -out of the table and replaced with strings obtained from malloc, -since the former will automatically be freed when the stack (see -the entry on memalloc.c) is emptied. - -BUILTIN COMMANDS: The procedures for handling these are scat- -tered throughout the code, depending on which location appears -most appropriate. They can be recognized because their names al- -ways end in "cmd". The mapping from names to procedures is -specified in the file builtins, which is processed by the mkbuil- -tins command. - -A builtin command is invoked with argc and argv set up like a -normal program. A builtin command is allowed to overwrite its -arguments. Builtin routines can call nextopt to do option pars- -ing. This is kind of like getopt, but you don't pass argc and -argv to it. Builtin routines can also call error. This routine -normally terminates the shell (or returns to the main command -loop if the shell is interactive), but when called from a builtin -command it causes the builtin command to terminate with an exit -status of 2. - -The directory bltins contains commands which can be compiled in- -dependently but can also be built into the shell for efficiency -reasons. The makefile in this directory compiles these programs -in the normal fashion (so that they can be run regardless of -whether the invoker is ash), but also creates a library named -bltinlib.a which can be linked with ash. The header file bltin.h -takes care of most of the differences between the ash and the -stand-alone environment. The user should call the main routine -"main", and #define main to be the name of the routine to use -when the program is linked into ash. This #define should appear -before bltin.h is included; bltin.h will #undef main if the pro- -gram is to be compiled stand-alone. - -CD.C: This file defines the cd and pwd builtins. The pwd com- -mand runs /bin/pwd the first time it is invoked (unless the user -has already done a cd to an absolute pathname), but then -remembers the current directory and updates it when the cd com- -mand is run, so subsequent pwd commands run very fast. The main -complication in the cd command is in the docd command, which -resolves symbolic links into actual names and informs the user -where the user ended up if he crossed a symbolic link. - -SIGNALS: Trap.c implements the trap command. The routine set- -signal figures out what action should be taken when a signal is -received and invokes the signal system call to set the signal ac- -tion appropriately. When a signal that a user has set a trap for -is caught, the routine "onsig" sets a flag. The routine dotrap -is called at appropriate points to actually handle the signal. -When an interrupt is caught and no trap has been set for that -signal, the routine "onint" in error.c is called. - -OUTPUT: Ash uses it's own output routines. There are three out- -put structures allocated. "Output" represents the standard out- -put, "errout" the standard error, and "memout" contains output -which is to be stored in memory. This last is used when a buil- -tin command appears in backquotes, to allow its output to be col- -lected without doing any I/O through the UNIX operating system. -The variables out1 and out2 normally point to output and errout, -respectively, but they are set to point to memout when appropri- -ate inside backquotes. - -INPUT: The basic input routine is pgetc, which reads from the -current input file. There is a stack of input files; the current -input file is the top file on this stack. The code allows the -input to come from a string rather than a file. (This is for the --c option and the "." and eval builtin commands.) The global -variable plinno is saved and restored when files are pushed and -popped from the stack. The parser routines store the number of -the current line in this variable. - -DEBUGGING: If DEBUG is defined in shell.h, then the shell will -write debugging information to the file $HOME/trace. Most of -this is done using the TRACE macro, which takes a set of printf -arguments inside two sets of parenthesis. Example: -"TRACE(("n=%d0, n))". The double parenthesis are necessary be- -cause the preprocessor can't handle functions with a variable -number of arguments. Defining DEBUG also causes the shell to -generate a core dump if it is sent a quit signal. The tracing -code is in show.c. diff --git a/sh/ThirdPartyProject.prop b/sh/ThirdPartyProject.prop deleted file mode 100644 index eb9167e..0000000 --- a/sh/ThirdPartyProject.prop +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2010 Google Inc. All Rights Reserved. -#Fri Jul 16 10:03:08 PDT 2010 -currentVersion=Unknown -version=1.17 -isNative=true -name=ash -keywords=ash -onDevice=true -homepage=http\://www.in-ulm.de/~mascheck/various/ash/ diff --git a/sh/alias.c b/sh/alias.c deleted file mode 100644 index 59a3dc1..0000000 --- a/sh/alias.c +++ /dev/null @@ -1,273 +0,0 @@ -/* $NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> -#include "shell.h" -#include "input.h" -#include "output.h" -#include "error.h" -#include "memalloc.h" -#include "mystring.h" -#include "alias.h" -#include "options.h" /* XXX for argptr (should remove?) */ -#include "var.h" - -#define ATABSIZE 39 - -struct alias *atab[ATABSIZE]; - -STATIC void setalias(char *, char *); -STATIC int unalias(char *); -STATIC struct alias **hashalias(char *); - -STATIC -void -setalias(char *name, char *val) -{ - struct alias *ap, **app; - - app = hashalias(name); - for (ap = *app; ap; ap = ap->next) { - if (equal(name, ap->name)) { - INTOFF; - ckfree(ap->val); - ap->val = savestr(val); - INTON; - return; - } - } - /* not found */ - INTOFF; - ap = ckmalloc(sizeof (struct alias)); - ap->name = savestr(name); - /* - * XXX - HACK: in order that the parser will not finish reading the - * alias value off the input before processing the next alias, we - * dummy up an extra space at the end of the alias. This is a crock - * and should be re-thought. The idea (if you feel inclined to help) - * is to avoid alias recursions. The mechanism used is: when - * expanding an alias, the value of the alias is pushed back on the - * input as a string and a pointer to the alias is stored with the - * string. The alias is marked as being in use. When the input - * routine finishes reading the string, it markes the alias not - * in use. The problem is synchronization with the parser. Since - * it reads ahead, the alias is marked not in use before the - * resulting token(s) is next checked for further alias sub. The - * H A C K is that we add a little fluff after the alias value - * so that the string will not be exhausted. This is a good - * idea ------- ***NOT*** - */ -#ifdef notyet - ap->val = savestr(val); -#else /* hack */ - { - int len = strlen(val); - ap->val = ckmalloc(len + 2); - memcpy(ap->val, val, len); - ap->val[len] = ' '; /* fluff */ - ap->val[len+1] = '\0'; - } -#endif - ap->next = *app; - *app = ap; - INTON; -} - -STATIC int -unalias(char *name) -{ - struct alias *ap, **app; - - app = hashalias(name); - - for (ap = *app; ap; app = &(ap->next), ap = ap->next) { - if (equal(name, ap->name)) { - /* - * if the alias is currently in use (i.e. its - * buffer is being used by the input routine) we - * just null out the name instead of freeing it. - * We could clear it out later, but this situation - * is so rare that it hardly seems worth it. - */ - if (ap->flag & ALIASINUSE) - *ap->name = '\0'; - else { - INTOFF; - *app = ap->next; - ckfree(ap->name); - ckfree(ap->val); - ckfree(ap); - INTON; - } - return (0); - } - } - - return (1); -} - -#ifdef mkinit -MKINIT void rmaliases(void); - -SHELLPROC { - rmaliases(); -} -#endif - -void -rmaliases(void) -{ - struct alias *ap, *tmp; - int i; - - INTOFF; - for (i = 0; i < ATABSIZE; i++) { - ap = atab[i]; - atab[i] = NULL; - while (ap) { - ckfree(ap->name); - ckfree(ap->val); - tmp = ap; - ap = ap->next; - ckfree(tmp); - } - } - INTON; -} - -struct alias * -lookupalias(char *name, int check) -{ - struct alias *ap = *hashalias(name); - - for (; ap; ap = ap->next) { - if (equal(name, ap->name)) { - if (check && (ap->flag & ALIASINUSE)) - return (NULL); - return (ap); - } - } - - return (NULL); -} - -char * -get_alias_text(char *name) -{ - struct alias *ap; - - ap = lookupalias(name, 0); - if (ap == NULL) - return NULL; - return ap->val; -} - -/* - * TODO - sort output - */ -int -aliascmd(int argc, char **argv) -{ - char *n, *v; - int ret = 0; - struct alias *ap; - - if (argc == 1) { - int i; - - for (i = 0; i < ATABSIZE; i++) - for (ap = atab[i]; ap; ap = ap->next) { - if (*ap->name != '\0') { - out1fmt("alias %s=", ap->name); - print_quoted(ap->val); - out1c('\n'); - } - } - return (0); - } - while ((n = *++argv) != NULL) { - if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ - if ((ap = lookupalias(n, 0)) == NULL) { - outfmt(out2, "alias: %s not found\n", n); - ret = 1; - } else { - out1fmt("alias %s=", n); - print_quoted(ap->val); - out1c('\n'); - } - } else { - *v++ = '\0'; - setalias(n, v); - } - } - - return (ret); -} - -int -unaliascmd(int argc, char **argv) -{ - int i; - - while ((i = nextopt("a")) != '\0') { - if (i == 'a') { - rmaliases(); - return (0); - } - } - for (i = 0; *argptr; argptr++) - i = unalias(*argptr); - - return (i); -} - -STATIC struct alias ** -hashalias(char *p) -{ - unsigned int hashval; - - hashval = *p << 4; - while (*p) - hashval+= *p++; - return &atab[hashval % ATABSIZE]; -} diff --git a/sh/alias.h b/sh/alias.h deleted file mode 100644 index 7ce25f4..0000000 --- a/sh/alias.h +++ /dev/null @@ -1,50 +0,0 @@ -/* $NetBSD: alias.h,v 1.6 2003/08/07 09:05:29 agc Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)alias.h 8.2 (Berkeley) 5/4/95 - */ - -#define ALIASINUSE 1 - -struct alias { - struct alias *next; - char *name; - char *val; - int flag; -}; - -struct alias *lookupalias(char *, int); -char *get_alias_text(char *); -int aliascmd(int, char **); -int unaliascmd(int, char **); -void rmaliases(void); diff --git a/sh/arith.c b/sh/arith.c deleted file mode 100644 index f8f92a9..0000000 --- a/sh/arith.c +++ /dev/null @@ -1,1587 +0,0 @@ -/* A Bison parser, made by GNU Bison 1.875d. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - - 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, 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. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Written by Richard Stallman by simplifying the original so called - ``semantic'' parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - ARITH_NUM = 258, - ARITH_LPAREN = 259, - ARITH_RPAREN = 260, - ARITH_OR = 261, - ARITH_AND = 262, - ARITH_BOR = 263, - ARITH_BXOR = 264, - ARITH_BAND = 265, - ARITH_NE = 266, - ARITH_EQ = 267, - ARITH_LE = 268, - ARITH_GE = 269, - ARITH_GT = 270, - ARITH_LT = 271, - ARITH_RSHIFT = 272, - ARITH_LSHIFT = 273, - ARITH_SUB = 274, - ARITH_ADD = 275, - ARITH_REM = 276, - ARITH_DIV = 277, - ARITH_MUL = 278, - ARITH_BNOT = 279, - ARITH_NOT = 280, - ARITH_UNARYPLUS = 281, - ARITH_UNARYMINUS = 282 - }; -#endif -#define ARITH_NUM 258 -#define ARITH_LPAREN 259 -#define ARITH_RPAREN 260 -#define ARITH_OR 261 -#define ARITH_AND 262 -#define ARITH_BOR 263 -#define ARITH_BXOR 264 -#define ARITH_BAND 265 -#define ARITH_NE 266 -#define ARITH_EQ 267 -#define ARITH_LE 268 -#define ARITH_GE 269 -#define ARITH_GT 270 -#define ARITH_LT 271 -#define ARITH_RSHIFT 272 -#define ARITH_LSHIFT 273 -#define ARITH_SUB 274 -#define ARITH_ADD 275 -#define ARITH_REM 276 -#define ARITH_DIV 277 -#define ARITH_MUL 278 -#define ARITH_BNOT 279 -#define ARITH_NOT 280 -#define ARITH_UNARYPLUS 281 -#define ARITH_UNARYMINUS 282 - - - - -/* Copy the first part of user declarations. */ -#line 1 "arith.y" - -/* $NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> -#include "expand.h" -#include "shell.h" -#include "error.h" -#include "output.h" -#include "memalloc.h" - -const char *arith_buf, *arith_startbuf; - -void yyerror(const char *); -#ifdef TESTARITH -int main(int , char *[]); -int error(char *); -#endif - - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -typedef int YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 214 of yacc.c. */ -#line 202 "arith.c" - -#if ! defined (yyoverflow) || YYERROR_VERBOSE - -# ifndef YYFREE -# define YYFREE free -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# endif - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# endif -# else -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# endif -#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short int yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined (__GNUC__) && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined (__STDC__) || defined (__cplusplus) - typedef signed char yysigned_char; -#else - typedef short int yysigned_char; -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 14 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 170 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 28 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 3 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 26 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 52 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 282 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const unsigned char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 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 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const unsigned char yyprhs[] = -{ - 0, 0, 3, 5, 9, 13, 17, 21, 25, 29, - 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, - 73, 77, 81, 84, 87, 90, 93 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yysigned_char yyrhs[] = -{ - 29, 0, -1, 30, -1, 4, 30, 5, -1, 30, - 6, 30, -1, 30, 7, 30, -1, 30, 8, 30, - -1, 30, 9, 30, -1, 30, 10, 30, -1, 30, - 12, 30, -1, 30, 15, 30, -1, 30, 14, 30, - -1, 30, 16, 30, -1, 30, 13, 30, -1, 30, - 11, 30, -1, 30, 18, 30, -1, 30, 17, 30, - -1, 30, 20, 30, -1, 30, 19, 30, -1, 30, - 23, 30, -1, 30, 22, 30, -1, 30, 21, 30, - -1, 25, 30, -1, 24, 30, -1, 19, 30, -1, - 20, 30, -1, 3, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const unsigned char yyrline[] = -{ - 0, 76, 76, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 104, 109, 110, 111, 112, 113 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE -/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "ARITH_NUM", "ARITH_LPAREN", - "ARITH_RPAREN", "ARITH_OR", "ARITH_AND", "ARITH_BOR", "ARITH_BXOR", - "ARITH_BAND", "ARITH_NE", "ARITH_EQ", "ARITH_LE", "ARITH_GE", "ARITH_GT", - "ARITH_LT", "ARITH_RSHIFT", "ARITH_LSHIFT", "ARITH_SUB", "ARITH_ADD", - "ARITH_REM", "ARITH_DIV", "ARITH_MUL", "ARITH_BNOT", "ARITH_NOT", - "ARITH_UNARYPLUS", "ARITH_UNARYMINUS", "$accept", "exp", "expr", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const unsigned short int yytoknum[] = -{ - 0, 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 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const unsigned char yyr1[] = -{ - 0, 28, 29, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const unsigned char yyr2[] = -{ - 0, 2, 1, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 1 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const unsigned char yydefact[] = -{ - 0, 26, 0, 0, 0, 0, 0, 0, 2, 0, - 24, 25, 23, 22, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 4, 5, 6, 7, 8, 14, - 9, 13, 11, 10, 12, 16, 15, 18, 17, 21, - 20, 19 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yysigned_char yydefgoto[] = -{ - -1, 7, 8 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -13 -static const short int yypact[] = -{ - 28, -13, 28, 28, 28, 28, 28, 12, 67, 49, - -13, -13, -13, -13, -13, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, -13, 84, 100, 115, 23, 128, 139, - 139, -12, -12, -12, -12, 144, 144, 147, 147, -13, - -13, -13 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yysigned_char yypgoto[] = -{ - -13, -13, -2 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 -static const unsigned char yytable[] = -{ - 9, 10, 11, 12, 13, 26, 27, 28, 29, 30, - 31, 32, 14, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 1, 2, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 3, 4, 0, - 0, 0, 5, 6, 33, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 28, 29, 30, 31, 32, 30, 31, - 32 -}; - -static const yysigned_char yycheck[] = -{ - 2, 3, 4, 5, 6, 17, 18, 19, 20, 21, - 22, 23, 0, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 3, 4, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 19, 20, -1, - -1, -1, 24, 25, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 19, 20, 21, 22, 23, 21, 22, - 23 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const unsigned char yystos[] = -{ - 0, 3, 4, 19, 20, 24, 25, 29, 30, 30, - 30, 30, 30, 30, 0, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 5, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30 -}; - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up");\ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - ((Current).first_line = (Rhs)[1].first_line, \ - (Current).first_column = (Rhs)[1].first_column, \ - (Current).last_line = (Rhs)[N].last_line, \ - (Current).last_column = (Rhs)[N].last_column) -#endif - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -# define YYDSYMPRINT(Args) \ -do { \ - if (yydebug) \ - yysymprint Args; \ -} while (0) - -# define YYDSYMPRINTF(Title, Token, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yysymprint (stderr, \ - Token, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_stack_print (short int *bottom, short int *top) -#else -static void -yy_stack_print (bottom, top) - short int *bottom; - short int *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (/* Nothing. */; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_reduce_print (int yyrule) -#else -static void -yy_reduce_print (yyrule) - int yyrule; -#endif -{ - int yyi; - unsigned int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", - yyrule - 1, yylno); - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) - YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); - YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YYDSYMPRINT(Args) -# define YYDSYMPRINTF(Title, Token, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -#endif /* !YYERROR_VERBOSE */ - - - -#if YYDEBUG -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) -#else -static void -yysymprint (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - if (yytype < YYNTOKENS) - { - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); -# ifdef YYPRINT - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - } - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - switch (yytype) - { - default: - break; - } - YYFPRINTF (yyoutput, ")"); -} - -#endif /* ! YYDEBUG */ -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yydestruct (int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yytype, yyvaluep) - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM); -# else -int yyparse (); -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM) -# else -int yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short int yyssa[YYINITDEPTH]; - short int *yyss = yyssa; - register short int *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - - - -#define YYPOPSTACK (yyvsp--, yyssp--) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short int *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyoverflowlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - short int *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; - - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 76 "arith.y" - { - return (yyvsp[0]); - ;} - break; - - case 3: -#line 82 "arith.y" - { yyval = yyvsp[-1]; ;} - break; - - case 4: -#line 83 "arith.y" - { yyval = yyvsp[-2] ? yyvsp[-2] : yyvsp[0] ? yyvsp[0] : 0; ;} - break; - - case 5: -#line 84 "arith.y" - { yyval = yyvsp[-2] ? ( yyvsp[0] ? yyvsp[0] : 0 ) : 0; ;} - break; - - case 6: -#line 85 "arith.y" - { yyval = yyvsp[-2] | yyvsp[0]; ;} - break; - - case 7: -#line 86 "arith.y" - { yyval = yyvsp[-2] ^ yyvsp[0]; ;} - break; - - case 8: -#line 87 "arith.y" - { yyval = yyvsp[-2] & yyvsp[0]; ;} - break; - - case 9: -#line 88 "arith.y" - { yyval = yyvsp[-2] == yyvsp[0]; ;} - break; - - case 10: -#line 89 "arith.y" - { yyval = yyvsp[-2] > yyvsp[0]; ;} - break; - - case 11: -#line 90 "arith.y" - { yyval = yyvsp[-2] >= yyvsp[0]; ;} - break; - - case 12: -#line 91 "arith.y" - { yyval = yyvsp[-2] < yyvsp[0]; ;} - break; - - case 13: -#line 92 "arith.y" - { yyval = yyvsp[-2] <= yyvsp[0]; ;} - break; - - case 14: -#line 93 "arith.y" - { yyval = yyvsp[-2] != yyvsp[0]; ;} - break; - - case 15: -#line 94 "arith.y" - { yyval = yyvsp[-2] << yyvsp[0]; ;} - break; - - case 16: -#line 95 "arith.y" - { yyval = yyvsp[-2] >> yyvsp[0]; ;} - break; - - case 17: -#line 96 "arith.y" - { yyval = yyvsp[-2] + yyvsp[0]; ;} - break; - - case 18: -#line 97 "arith.y" - { yyval = yyvsp[-2] - yyvsp[0]; ;} - break; - - case 19: -#line 98 "arith.y" - { yyval = yyvsp[-2] * yyvsp[0]; ;} - break; - - case 20: -#line 99 "arith.y" - { - if (yyvsp[0] == 0) - yyerror("division by zero"); - yyval = yyvsp[-2] / yyvsp[0]; - ;} - break; - - case 21: -#line 104 "arith.y" - { - if (yyvsp[0] == 0) - yyerror("division by zero"); - yyval = yyvsp[-2] % yyvsp[0]; - ;} - break; - - case 22: -#line 109 "arith.y" - { yyval = !(yyvsp[0]); ;} - break; - - case 23: -#line 110 "arith.y" - { yyval = ~(yyvsp[0]); ;} - break; - - case 24: -#line 111 "arith.y" - { yyval = -(yyvsp[0]); ;} - break; - - case 25: -#line 112 "arith.y" - { yyval = yyvsp[0]; ;} - break; - - - } - -/* Line 1010 of yacc.c. */ -#line 1276 "arith.c" - - yyvsp -= yylen; - yyssp -= yylen; - - - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (YYPACT_NINF < yyn && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - int yytype = YYTRANSLATE (yychar); - const char* yyprefix; - char *yymsg; - int yyx; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 0; - - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); - yycount += 1; - if (yycount == 5) - { - yysize = 0; - break; - } - } - yysize += (sizeof ("syntax error, unexpected ") - + yystrlen (yytname[yytype])); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); - yyp = yystpcpy (yyp, yytname[yytype]); - - if (yycount < 5) - { - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yyp = yystpcpy (yyp, yyprefix); - yyp = yystpcpy (yyp, yytname[yyx]); - yyprefix = " or "; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("syntax error; also virtual memory exhausted"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror ("syntax error"); - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* If at end of input, pop the error token, - then the rest of the stack, then return failure. */ - if (yychar == YYEOF) - for (;;) - { - YYPOPSTACK; - if (yyssp == yyss) - YYABORT; - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[*yyssp], yyvsp); - } - } - else - { - YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); - yydestruct (yytoken, &yylval); - yychar = YYEMPTY; - - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - -#ifdef __GNUC__ - /* Pacify GCC when the user code never invokes YYERROR and the label - yyerrorlab therefore never appears in user code. */ - if (0) - goto yyerrorlab; -#endif - - yyvsp -= yylen; - yyssp -= yylen; - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[yystate], yyvsp); - YYPOPSTACK; - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; - - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*----------------------------------------------. -| yyoverflowlab -- parser overflow comes here. | -`----------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} - - -#line 115 "arith.y" - -int -arith(s) - const char *s; -{ - long result; - - arith_buf = arith_startbuf = s; - - INTOFF; - result = yyparse(); - arith_lex_reset(); /* reprime lex */ - INTON; - - return (result); -} - - -/* - * The exp(1) builtin. - */ -int -expcmd(argc, argv) - int argc; - char **argv; -{ - const char *p; - char *concat; - char **ap; - long i; - - if (argc > 1) { - p = argv[1]; - if (argc > 2) { - /* - * concatenate arguments - */ - STARTSTACKSTR(concat); - ap = argv + 2; - for (;;) { - while (*p) - STPUTC(*p++, concat); - if ((p = *ap++) == NULL) - break; - STPUTC(' ', concat); - } - STPUTC('\0', concat); - p = grabstackstr(concat); - } - } else - p = ""; - - i = arith(p); - - out1fmt("%ld\n", i); - return (! i); -} - -/*************************/ -#ifdef TEST_ARITH -#include <stdio.h> -main(argc, argv) - char *argv[]; -{ - printf("%d\n", exp(argv[1])); -} -error(s) - char *s; -{ - fprintf(stderr, "exp: %s\n", s); - exit(1); -} -#endif - -void -yyerror(s) - const char *s; -{ - -// yyerrok; - yyclearin; - arith_lex_reset(); /* reprime lex */ - error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); - /* NOTREACHED */ -} - - diff --git a/sh/arith.h b/sh/arith.h deleted file mode 100644 index f70c093..0000000 --- a/sh/arith.h +++ /dev/null @@ -1,25 +0,0 @@ -#define ARITH_NUM 258 -#define ARITH_LPAREN 259 -#define ARITH_RPAREN 260 -#define ARITH_OR 261 -#define ARITH_AND 262 -#define ARITH_BOR 263 -#define ARITH_BXOR 264 -#define ARITH_BAND 265 -#define ARITH_NE 266 -#define ARITH_EQ 267 -#define ARITH_LE 268 -#define ARITH_GE 269 -#define ARITH_GT 270 -#define ARITH_LT 271 -#define ARITH_RSHIFT 272 -#define ARITH_LSHIFT 273 -#define ARITH_SUB 274 -#define ARITH_ADD 275 -#define ARITH_REM 276 -#define ARITH_DIV 277 -#define ARITH_MUL 278 -#define ARITH_BNOT 279 -#define ARITH_NOT 280 -#define ARITH_UNARYPLUS 281 -#define ARITH_UNARYMINUS 282 diff --git a/sh/arith.y b/sh/arith.y deleted file mode 100644 index d51ed38..0000000 --- a/sh/arith.y +++ /dev/null @@ -1,199 +0,0 @@ -%{ -/* $NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> -#include "expand.h" -#include "shell.h" -#include "error.h" -#include "output.h" -#include "memalloc.h" - -const char *arith_buf, *arith_startbuf; - -void yyerror(const char *); -#ifdef TESTARITH -int main(int , char *[]); -int error(char *); -#endif - -%} -%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN - -%left ARITH_OR -%left ARITH_AND -%left ARITH_BOR -%left ARITH_BXOR -%left ARITH_BAND -%left ARITH_EQ ARITH_NE -%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE -%left ARITH_LSHIFT ARITH_RSHIFT -%left ARITH_ADD ARITH_SUB -%left ARITH_MUL ARITH_DIV ARITH_REM -%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT -%% - -exp: expr { - return ($1); - } - ; - - -expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; } - | expr ARITH_OR expr { $$ = $1 ? $1 : $3 ? $3 : 0; } - | expr ARITH_AND expr { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } - | expr ARITH_BOR expr { $$ = $1 | $3; } - | expr ARITH_BXOR expr { $$ = $1 ^ $3; } - | expr ARITH_BAND expr { $$ = $1 & $3; } - | expr ARITH_EQ expr { $$ = $1 == $3; } - | expr ARITH_GT expr { $$ = $1 > $3; } - | expr ARITH_GE expr { $$ = $1 >= $3; } - | expr ARITH_LT expr { $$ = $1 < $3; } - | expr ARITH_LE expr { $$ = $1 <= $3; } - | expr ARITH_NE expr { $$ = $1 != $3; } - | expr ARITH_LSHIFT expr { $$ = $1 << $3; } - | expr ARITH_RSHIFT expr { $$ = $1 >> $3; } - | expr ARITH_ADD expr { $$ = $1 + $3; } - | expr ARITH_SUB expr { $$ = $1 - $3; } - | expr ARITH_MUL expr { $$ = $1 * $3; } - | expr ARITH_DIV expr { - if ($3 == 0) - yyerror("division by zero"); - $$ = $1 / $3; - } - | expr ARITH_REM expr { - if ($3 == 0) - yyerror("division by zero"); - $$ = $1 % $3; - } - | ARITH_NOT expr { $$ = !($2); } - | ARITH_BNOT expr { $$ = ~($2); } - | ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); } - | ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; } - | ARITH_NUM - ; -%% -int -arith(s) - const char *s; -{ - long result; - - arith_buf = arith_startbuf = s; - - INTOFF; - result = yyparse(); - arith_lex_reset(); /* reprime lex */ - INTON; - - return (result); -} - - -/* - * The exp(1) builtin. - */ -int -expcmd(argc, argv) - int argc; - char **argv; -{ - const char *p; - char *concat; - char **ap; - long i; - - if (argc > 1) { - p = argv[1]; - if (argc > 2) { - /* - * concatenate arguments - */ - STARTSTACKSTR(concat); - ap = argv + 2; - for (;;) { - while (*p) - STPUTC(*p++, concat); - if ((p = *ap++) == NULL) - break; - STPUTC(' ', concat); - } - STPUTC('\0', concat); - p = grabstackstr(concat); - } - } else - p = ""; - - i = arith(p); - - out1fmt("%ld\n", i); - return (! i); -} - -/*************************/ -#ifdef TEST_ARITH -#include <stdio.h> -main(argc, argv) - char *argv[]; -{ - printf("%d\n", exp(argv[1])); -} -error(s) - char *s; -{ - fprintf(stderr, "exp: %s\n", s); - exit(1); -} -#endif - -void -yyerror(s) - const char *s; -{ - -// yyerrok; - yyclearin; - arith_lex_reset(); /* reprime lex */ - error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); - /* NOTREACHED */ -} diff --git a/sh/arith_lex.c b/sh/arith_lex.c deleted file mode 100644 index 9a132dd..0000000 --- a/sh/arith_lex.c +++ /dev/null @@ -1,1890 +0,0 @@ -#line 2 "arith_lex.c" - -#line 4 "arith_lex.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 31 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ - -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L -#include <inttypes.h> -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#if __STDC__ - -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN (yy_start) = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START (((yy_start) - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart(yyin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#endif - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -extern int yyleng; - -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = (yy_hold_char); \ - YY_RESTORE_YY_MORE_OFFSET \ - (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, (yytext_ptr) ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef unsigned int yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* Stack of input buffers. */ -static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ -static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ - ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ - : NULL) - -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; -static int yy_n_chars; /* number of characters read into yy_ch_buf */ -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart (FILE *input_file ); -void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); -YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); -void yy_delete_buffer (YY_BUFFER_STATE b ); -void yy_flush_buffer (YY_BUFFER_STATE b ); -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); -void yypop_buffer_state (void ); - -static void yyensure_buffer_stack (void ); -static void yy_load_buffer_state (void ); -static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); - -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) - -YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); -YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); - -void *yyalloc (yy_size_t ); -void *yyrealloc (void *,yy_size_t ); -void yyfree (void * ); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - yyensure_buffer_stack (); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - yyensure_buffer_stack (); \ - YY_CURRENT_BUFFER_LVALUE = \ - yy_create_buffer(yyin,YY_BUF_SIZE ); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define yywrap(n) 1 -#define YY_SKIP_YYWRAP - -typedef unsigned char YY_CHAR; - -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; - -typedef int yy_state_type; - -extern int yylineno; - -int yylineno = 1; - -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state (void ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); -static int yy_get_next_buffer (void ); -static void yy_fatal_error (yyconst char msg[] ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - (yytext_ptr) = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ - (yy_hold_char) = *yy_cp; \ - *yy_cp = '\0'; \ - (yy_c_buf_p) = yy_cp; - -#define YY_NUM_RULES 29 -#define YY_END_OF_BUFFER 30 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static yyconst flex_int16_t yy_accept[39] = - { 0, - 0, 0, 30, 28, 1, 1, 27, 23, 12, 6, - 7, 21, 24, 25, 22, 3, 4, 17, 28, 15, - 5, 11, 10, 26, 14, 9, 3, 0, 4, 19, - 18, 13, 16, 20, 5, 8, 2, 0 - } ; - -static yyconst flex_int32_t yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 4, 1, 1, 1, 5, 6, 1, 7, - 8, 9, 10, 1, 11, 1, 12, 13, 14, 14, - 14, 14, 14, 14, 14, 15, 15, 1, 1, 16, - 17, 18, 1, 1, 19, 19, 19, 19, 19, 19, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 1, 1, 1, 21, 20, 1, 19, 19, 19, 19, - - 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 22, - 20, 20, 1, 23, 1, 24, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst flex_int32_t yy_meta[25] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 2, 1, 1, 1, 2, 3, - 1, 3, 1, 1 - } ; - -static yyconst flex_int16_t yy_base[41] = - { 0, - 0, 0, 47, 48, 48, 48, 29, 48, 39, 48, - 48, 48, 48, 48, 48, 12, 14, 14, 27, 15, - 0, 48, 20, 48, 48, 48, 22, 0, 24, 48, - 48, 48, 48, 48, 0, 48, 0, 48, 38, 40 - } ; - -static yyconst flex_int16_t yy_def[41] = - { 0, - 38, 1, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 39, 38, 38, 38, 38, 38, 38, 40, 38, 38, - 38, 38, 38, 38, 39, 38, 40, 0, 38, 38 - } ; - -static yyconst flex_int16_t yy_nxt[73] = - { 0, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 17, 18, 19, 20, 21, 21, - 22, 21, 23, 24, 27, 27, 29, 29, 29, 30, - 31, 33, 34, 28, 27, 27, 29, 29, 29, 35, - 35, 37, 36, 32, 26, 25, 38, 3, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38 - } ; - -static yyconst flex_int16_t yy_chk[73] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 16, 16, 17, 17, 17, 18, - 18, 20, 20, 16, 27, 27, 29, 29, 29, 39, - 39, 40, 23, 19, 9, 7, 3, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -extern int yy_flex_debug; -int yy_flex_debug = 0; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "arith_lex.l" -#line 2 "arith_lex.l" -/* $NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $"); -#endif -#endif /* not lint */ - -#include <unistd.h> -#include "arith.h" -#include "error.h" -#include "expand.h" -#include "var.h" - -extern int yylval; -extern char *arith_buf, *arith_startbuf; -#undef YY_INPUT -#define YY_INPUT(buf,result,max) \ - result = (*buf = *arith_buf++) ? 1 : YY_NULL; -#define YY_NO_UNPUT -#line 526 "arith_lex.c" - -#define INITIAL 0 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include <unistd.h> -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap (void ); -#else -extern int yywrap (void ); -#endif -#endif - - static void yyunput (int c,char *buf_ptr ); - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ); -#endif - -#ifndef YY_NO_INPUT - -#ifdef __cplusplus -static int yyinput (void ); -#else -static int input (void ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - size_t n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int yylex (void); - -#define YY_DECL int yylex (void) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - -#line 60 "arith_lex.l" - -#line 679 "arith_lex.c" - - if ( (yy_init) ) - { - (yy_init) = 0; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! (yy_start) ) - (yy_start) = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - yyensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ); - } - - yy_load_buffer_state( ); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = (yy_c_buf_p); - - /* Support of yytext. */ - *yy_cp = (yy_hold_char); - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = (yy_start); -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 39 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 48 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = (yy_hold_char); - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); - goto yy_find_action; - -case 1: -/* rule 1 can match eol */ -YY_RULE_SETUP -#line 61 "arith_lex.l" -{ ; } - YY_BREAK -case 2: -YY_RULE_SETUP -#line 62 "arith_lex.l" -{ yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } - YY_BREAK -case 3: -YY_RULE_SETUP -#line 63 "arith_lex.l" -{ yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } - YY_BREAK -case 4: -YY_RULE_SETUP -#line 64 "arith_lex.l" -{ yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } - YY_BREAK -case 5: -YY_RULE_SETUP -#line 65 "arith_lex.l" -{ char *v = lookupvar(yytext); - if (v) { - yylval = strtol(v, &v, 0); - if (*v == 0) - return ARITH_NUM; - } - error("arith: syntax error: \"%s\"", arith_startbuf); - } - YY_BREAK -case 6: -YY_RULE_SETUP -#line 73 "arith_lex.l" -{ return(ARITH_LPAREN); } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 74 "arith_lex.l" -{ return(ARITH_RPAREN); } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 75 "arith_lex.l" -{ return(ARITH_OR); } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 76 "arith_lex.l" -{ return(ARITH_AND); } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 77 "arith_lex.l" -{ return(ARITH_BOR); } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 78 "arith_lex.l" -{ return(ARITH_BXOR); } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 79 "arith_lex.l" -{ return(ARITH_BAND); } - YY_BREAK -case 13: -YY_RULE_SETUP -#line 80 "arith_lex.l" -{ return(ARITH_EQ); } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 81 "arith_lex.l" -{ return(ARITH_NE); } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 82 "arith_lex.l" -{ return(ARITH_GT); } - YY_BREAK -case 16: -YY_RULE_SETUP -#line 83 "arith_lex.l" -{ return(ARITH_GE); } - YY_BREAK -case 17: -YY_RULE_SETUP -#line 84 "arith_lex.l" -{ return(ARITH_LT); } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 85 "arith_lex.l" -{ return(ARITH_LE); } - YY_BREAK -case 19: -YY_RULE_SETUP -#line 86 "arith_lex.l" -{ return(ARITH_LSHIFT); } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 87 "arith_lex.l" -{ return(ARITH_RSHIFT); } - YY_BREAK -case 21: -YY_RULE_SETUP -#line 88 "arith_lex.l" -{ return(ARITH_MUL); } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 89 "arith_lex.l" -{ return(ARITH_DIV); } - YY_BREAK -case 23: -YY_RULE_SETUP -#line 90 "arith_lex.l" -{ return(ARITH_REM); } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 91 "arith_lex.l" -{ return(ARITH_ADD); } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 92 "arith_lex.l" -{ return(ARITH_SUB); } - YY_BREAK -case 26: -YY_RULE_SETUP -#line 93 "arith_lex.l" -{ return(ARITH_BNOT); } - YY_BREAK -case 27: -YY_RULE_SETUP -#line 94 "arith_lex.l" -{ return(ARITH_NOT); } - YY_BREAK -case 28: -YY_RULE_SETUP -#line 95 "arith_lex.l" -{ error("arith: syntax error: \"%s\"", arith_startbuf); } - YY_BREAK -case 29: -YY_RULE_SETUP -#line 96 "arith_lex.l" -ECHO; - YY_BREAK -#line 915 "arith_lex.c" -case YY_STATE_EOF(INITIAL): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = (yy_hold_char); - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++(yy_c_buf_p); - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = (yy_c_buf_p); - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( ) ) - { - case EOB_ACT_END_OF_FILE: - { - (yy_did_buffer_switch_on_eof) = 0; - - if ( yywrap( ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! (yy_did_buffer_switch_on_eof) ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = - (yytext_ptr) + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( ); - - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - (yy_c_buf_p) = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; - - yy_current_state = yy_get_previous_state( ); - - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ -} /* end of yylex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (void) -{ - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); - register int number_to_move, i; - int ret_val; - - if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; - - else - { - size_t num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; - - int yy_c_buf_p_offset = - (int) ((yy_c_buf_p) - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - (yy_n_chars), num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - if ( (yy_n_chars) == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart(yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - (yy_n_chars) += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; - - (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (void) -{ - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = (yy_start); - - for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 39 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) -{ - register int yy_is_jam; - register char *yy_cp = (yy_c_buf_p); - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - (yy_last_accepting_state) = yy_current_state; - (yy_last_accepting_cpos) = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 39 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 38); - - return yy_is_jam ? 0 : yy_current_state; -} - - static void yyunput (int c, register char * yy_bp ) -{ - register char *yy_cp; - - yy_cp = (yy_c_buf_p); - - /* undo effects of setting up yytext */ - *yy_cp = (yy_hold_char); - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = (yy_n_chars) + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - - while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - (yytext_ptr) = yy_bp; - (yy_hold_char) = *yy_cp; - (yy_c_buf_p) = yy_cp; -} - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (void) -#else - static int input (void) -#endif - -{ - int c; - - *(yy_c_buf_p) = (yy_hold_char); - - if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) - /* This was really a NUL. */ - *(yy_c_buf_p) = '\0'; - - else - { /* need more input */ - int offset = (yy_c_buf_p) - (yytext_ptr); - ++(yy_c_buf_p); - - switch ( yy_get_next_buffer( ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart(yyin ); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap( ) ) - return EOF; - - if ( ! (yy_did_buffer_switch_on_eof) ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = (yytext_ptr) + offset; - break; - } - } - } - - c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ - *(yy_c_buf_p) = '\0'; /* preserve yytext */ - (yy_hold_char) = *++(yy_c_buf_p); - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * - * @note This function does not reset the start condition to @c INITIAL . - */ - void yyrestart (FILE * input_file ) -{ - - if ( ! YY_CURRENT_BUFFER ){ - yyensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - yy_create_buffer(yyin,YY_BUF_SIZE ); - } - - yy_init_buffer(YY_CURRENT_BUFFER,input_file ); - yy_load_buffer_state( ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * - */ - void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) -{ - - /* TODO. We should be able to replace this entire function body - * with - * yypop_buffer_state(); - * yypush_buffer_state(new_buffer); - */ - yyensure_buffer_stack (); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - yy_load_buffer_state( ); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - (yy_did_buffer_switch_on_eof) = 1; -} - -static void yy_load_buffer_state (void) -{ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - (yy_hold_char) = *(yy_c_buf_p); -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * - * @return the allocated buffer state. - */ - YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer(b,file ); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with yy_create_buffer() - * - */ - void yy_delete_buffer (YY_BUFFER_STATE b ) -{ - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yyfree((void *) b->yy_ch_buf ); - - yyfree((void *) b ); -} - -#ifndef __cplusplus -extern int isatty (int ); -#endif /* __cplusplus */ - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a yyrestart() or at EOF. - */ - static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) - -{ - int oerrno = errno; - - yy_flush_buffer(b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then yy_init_buffer was _probably_ - * called from yyrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * - */ - void yy_flush_buffer (YY_BUFFER_STATE b ) -{ - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - yy_load_buffer_state( ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * - */ -void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) -{ - if (new_buffer == NULL) - return; - - yyensure_buffer_stack(); - - /* This block is copied from yy_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - (yy_buffer_stack_top)++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from yy_switch_to_buffer. */ - yy_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * - */ -void yypop_buffer_state (void) -{ - if (!YY_CURRENT_BUFFER) - return; - - yy_delete_buffer(YY_CURRENT_BUFFER ); - YY_CURRENT_BUFFER_LVALUE = NULL; - if ((yy_buffer_stack_top) > 0) - --(yy_buffer_stack_top); - - if (YY_CURRENT_BUFFER) { - yy_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void yyensure_buffer_stack (void) -{ - int num_to_alloc; - - if (!(yy_buffer_stack)) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; - (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - ); - - memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - (yy_buffer_stack_max) = num_to_alloc; - (yy_buffer_stack_top) = 0; - return; - } - - if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = (yy_buffer_stack_max) + grow_size; - (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc - ((yy_buffer_stack), - num_to_alloc * sizeof(struct yy_buffer_state*) - ); - - /* zero only the new slots.*/ - memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); - (yy_buffer_stack_max) = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer(b ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to yylex() will - * scan from a @e copy of @a str. - * @param str a NUL-terminated string to scan - * - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * yy_scan_bytes() instead. - */ -YY_BUFFER_STATE yy_scan_string (yyconst char * yy_str ) -{ - - return yy_scan_bytes(yy_str,strlen(yy_str) ); -} - -/** Setup the input buffer state to scan the given bytes. The next call to yylex() will - * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. - * - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * bytes, int len ) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yyalloc(n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer(buf,n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yy_fatal_error (yyconst char* msg ) -{ - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = (yy_hold_char); \ - (yy_c_buf_p) = yytext + yyless_macro_arg; \ - (yy_hold_char) = *(yy_c_buf_p); \ - *(yy_c_buf_p) = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the current line number. - * - */ -int yyget_lineno (void) -{ - - return yylineno; -} - -/** Get the input stream. - * - */ -FILE *yyget_in (void) -{ - return yyin; -} - -/** Get the output stream. - * - */ -FILE *yyget_out (void) -{ - return yyout; -} - -/** Get the length of the current token. - * - */ -int yyget_leng (void) -{ - return yyleng; -} - -/** Get the current token. - * - */ - -char *yyget_text (void) -{ - return yytext; -} - -/** Set the current line number. - * @param line_number - * - */ -void yyset_lineno (int line_number ) -{ - - yylineno = line_number; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param in_str A readable stream. - * - * @see yy_switch_to_buffer - */ -void yyset_in (FILE * in_str ) -{ - yyin = in_str ; -} - -void yyset_out (FILE * out_str ) -{ - yyout = out_str ; -} - -int yyget_debug (void) -{ - return yy_flex_debug; -} - -void yyset_debug (int bdebug ) -{ - yy_flex_debug = bdebug ; -} - -/* yylex_destroy is for both reentrant and non-reentrant scanners. */ -int yylex_destroy (void) -{ - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - yy_delete_buffer(YY_CURRENT_BUFFER ); - YY_CURRENT_BUFFER_LVALUE = NULL; - yypop_buffer_state(); - } - - /* Destroy the stack itself. */ - yyfree((yy_buffer_stack) ); - (yy_buffer_stack) = NULL; - - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) -{ - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s ) -{ - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -void *yyalloc (yy_size_t size ) -{ - return (void *) malloc( size ); -} - -void *yyrealloc (void * ptr, yy_size_t size ) -{ - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); -} - -void yyfree (void * ptr ) -{ - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef yytext_ptr -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif -#line 96 "arith_lex.l" - - - -void -arith_lex_reset() { -#ifdef YY_NEW_FILE - YY_NEW_FILE; -#endif -} - diff --git a/sh/arith_lex.l b/sh/arith_lex.l deleted file mode 100644 index 79116fc..0000000 --- a/sh/arith_lex.l +++ /dev/null @@ -1,103 +0,0 @@ -%{ -/* $NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: arith_lex.l,v 1.12.6.1 2005/04/07 11:38:58 tron Exp $"); -#endif -#endif /* not lint */ - -#include <unistd.h> -#include "arith.h" -#include "error.h" -#include "expand.h" -#include "var.h" - -extern int yylval; -extern char *arith_buf, *arith_startbuf; -#undef YY_INPUT -#define YY_INPUT(buf,result,max) \ - result = (*buf = *arith_buf++) ? 1 : YY_NULL; -#define YY_NO_UNPUT -%} -%option noyywrap - -%% -[ \t\n] { ; } -0x[0-9a-fA-F]+ { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } -0[0-7]* { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } -[1-9][0-9]* { yylval = strtol(yytext, 0, 0); return(ARITH_NUM); } -[A-Za-z_][A-Za-z_0-9]* { char *v = lookupvar(yytext); - if (v) { - yylval = strtol(v, &v, 0); - if (*v == 0) - return ARITH_NUM; - } - error("arith: syntax error: \"%s\"", arith_startbuf); - } -"(" { return(ARITH_LPAREN); } -")" { return(ARITH_RPAREN); } -"||" { return(ARITH_OR); } -"&&" { return(ARITH_AND); } -"|" { return(ARITH_BOR); } -"^" { return(ARITH_BXOR); } -"&" { return(ARITH_BAND); } -"==" { return(ARITH_EQ); } -"!=" { return(ARITH_NE); } -">" { return(ARITH_GT); } -">=" { return(ARITH_GE); } -"<" { return(ARITH_LT); } -"<=" { return(ARITH_LE); } -"<<" { return(ARITH_LSHIFT); } -">>" { return(ARITH_RSHIFT); } -"*" { return(ARITH_MUL); } -"/" { return(ARITH_DIV); } -"%" { return(ARITH_REM); } -"+" { return(ARITH_ADD); } -"-" { return(ARITH_SUB); } -"~" { return(ARITH_BNOT); } -"!" { return(ARITH_NOT); } -. { error("arith: syntax error: \"%s\"", arith_startbuf); } -%% - -void -arith_lex_reset() { -#ifdef YY_NEW_FILE - YY_NEW_FILE; -#endif -} diff --git a/sh/bltin/bltin.h b/sh/bltin/bltin.h deleted file mode 100644 index b8f9d75..0000000 --- a/sh/bltin/bltin.h +++ /dev/null @@ -1,94 +0,0 @@ -/* $NetBSD: bltin.h,v 1.11 2003/08/07 09:05:40 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)bltin.h 8.1 (Berkeley) 5/31/93 - */ - -/* - * This file is included by programs which are optionally built into the - * shell. If SHELL is defined, we try to map the standard UNIX library - * routines to ash routines using defines. - */ - -#include "../shell.h" -#include "../mystring.h" -#ifdef SHELL -#include "../output.h" -#include "../error.h" -#undef stdout -#undef stderr -#undef putc -#undef putchar -#undef fileno -#define stdout out1 -#define stderr out2 -#define printf out1fmt -#define putc(c, file) outc(c, file) -#define putchar(c) out1c(c) -#define FILE struct output -#define fprintf outfmt -#define fputs outstr -#define fflush flushout -#define fileno(f) ((f)->fd) -#define INITARGS(argv) -#define err sh_err -#define verr sh_verr -#define errx sh_errx -#define verrx sh_verrx -#define warn sh_warn -#define vwarn sh_vwarn -#define warnx sh_warnx -#define vwarnx sh_vwarnx -#define exit sh_exit -#define setprogname(s) -#define getprogname() commandname -#define setlocate(l,s) 0 - -#define getenv(p) bltinlookup((p),0) - -#else -#undef NULL -#include <stdio.h> -#undef main -#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else -#endif - -pointer stalloc(int); -void error(const char *, ...); -void sh_warnx(const char *, ...); -void sh_exit(int) __attribute__((__noreturn__)); - -int echocmd(int, char **); - - -extern const char *commandname; diff --git a/sh/bltin/echo.1 b/sh/bltin/echo.1 deleted file mode 100644 index 7e71fa3..0000000 --- a/sh/bltin/echo.1 +++ /dev/null @@ -1,109 +0,0 @@ -.\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:40 agc Exp $ -.\" -.\" Copyright (c) 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" This code is derived from software contributed to Berkeley by -.\" Kenneth Almquist. -.\" Copyright 1989 by Kenneth Almquist -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)echo.1 8.1 (Berkeley) 5/31/93 -.\" -.Dd May 31, 1993 -.Dt ECHO 1 -.Os -.Sh NAME -.Nm echo -.Nd produce message in a shell script -.Sh SYNOPSIS -.Nm -.Op Fl n | Fl e -.Ar args ... -.Sh DESCRIPTION -.Nm -prints its arguments on the standard output, separated by spaces. -Unless the -.Fl n -option is present, a newline is output following the arguments. -The -.Fl e -option causes -.Nm -to treat the escape sequences specially, as described in the following -paragraph. -The -.Fl e -option is the default, and is provided solely for compatibility with -other systems. -Only one of the options -.Fl n -and -.Fl e -may be given. -.Pp -If any of the following sequences of characters is encountered during -output, the sequence is not output. Instead, the specified action is -performed: -.Bl -tag -width indent -.It Li \eb -A backspace character is output. -.It Li \ec -Subsequent output is suppressed. This is normally used at the end of the -last argument to suppress the trailing newline that -.Nm -would otherwise output. -.It Li \ef -Output a form feed. -.It Li \en -Output a newline character. -.It Li \er -Output a carriage return. -.It Li \et -Output a (horizontal) tab character. -.It Li \ev -Output a vertical tab. -.It Li \e0 Ns Ar digits -Output the character whose value is given by zero to three digits. -If there are zero digits, a nul character is output. -.It Li \e\e -Output a backslash. -.El -.Sh HINTS -Remember that backslash is special to the shell and needs to be escaped. -To output a message to standard error, say -.Pp -.D1 echo message \*[Gt]\*[Am]2 -.Sh BUGS -The octal character escape mechanism -.Pq Li \e0 Ns Ar digits -differs from the -C language mechanism. -.Pp -There is no way to force -.Nm -to treat its arguments literally, rather than interpreting them as -options and escape sequences. diff --git a/sh/bltin/echo.c b/sh/bltin/echo.c deleted file mode 100644 index bed7535..0000000 --- a/sh/bltin/echo.c +++ /dev/null @@ -1,116 +0,0 @@ -/* $NetBSD: echo.c,v 1.12 2005/02/06 04:43:43 perry Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)echo.c 8.1 (Berkeley) 5/31/93 - */ - -/* - * Echo command. - * - * echo is steeped in tradition - several of them! - * netbsd has supported 'echo [-n | -e] args' in spite of -e not being - * documented anywhere. - * Posix requires that -n be supported, output from strings containing - * \ is implementation defined - * The Single Unix Spec requires that \ escapes be treated as if -e - * were set, but that -n not be treated as an option. - * (ksh supports 'echo [-eEn] args', but not -- so that it is actually - * impossible to actually output '-n') - * - * It is suggested that 'printf "%b" "string"' be used to get \ sequences - * expanded. printf is now a builtin of netbsd's sh and csh. - */ - -//#define main echocmd - -#include "bltin.h" - -int -echocmd(int argc, char **argv) -{ - char **ap; - char *p; - char c; - int count; - int nflag = 0; - int eflag = 0; - - ap = argv; - if (argc) - ap++; - - if ((p = *ap) != NULL) { - if (equal(p, "-n")) { - nflag = 1; - ap++; - } else if (equal(p, "-e")) { - eflag = 1; - ap++; - } - } - - while ((p = *ap++) != NULL) { - while ((c = *p++) != '\0') { - if (c == '\\' && eflag) { - switch (*p++) { - case 'a': c = '\a'; break; /* bell */ - case 'b': c = '\b'; break; - case 'c': return 0; /* exit */ - case 'e': c = 033; break; /* escape */ - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case '\\': break; /* c = '\\' */ - case '0': - c = 0; - count = 3; - while (--count >= 0 && (unsigned)(*p - '0') < 8) - c = (c << 3) + (*p++ - '0'); - break; - default: - /* Output the '/' and char following */ - p--; - break; - } - } - putchar(c); - } - if (*ap) - putchar(' '); - } - if (! nflag) - putchar('\n'); - return 0; -} diff --git a/sh/builtins.c b/sh/builtins.c deleted file mode 100644 index 344dbd6..0000000 --- a/sh/builtins.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file was generated by the mkbuiltins program. - */ - -#include "shell.h" -#include "builtins.h" - -const struct builtincmd builtincmd[] = { - - { "command", bltincmd }, - { "bg", bgcmd }, - { "cd", cdcmd }, - { "chdir", cdcmd }, - { "echo", echocmd }, - { "exp", expcmd }, - { "let", expcmd }, - { "false", falsecmd }, -#if WITH_HISTORY - { "fc", histcmd }, - { "inputrc", inputrc }, -#endif - { "fg", fgcmd }, - { "getopts", getoptscmd }, - { "hash", hashcmd }, - { "jobid", jobidcmd }, - { "jobs", jobscmd }, - { "local", localcmd }, -#ifndef SMALL -#endif - { "pwd", pwdcmd }, - { "read", readcmd }, - { "setvar", setvarcmd }, - { "true", truecmd }, - { "type", typecmd }, - { "umask", umaskcmd }, - { "unalias", unaliascmd }, - { "wait", waitcmd }, - { "alias", aliascmd }, - { "ulimit", ulimitcmd }, - { "wordexp", wordexpcmd }, - { 0, 0 }, -}; - -const struct builtincmd splbltincmd[] = { - { "break", breakcmd }, - { "continue", breakcmd }, - { ".", dotcmd }, - { "eval", evalcmd }, - { "exec", execcmd }, - { "exit", exitcmd }, - { "export", exportcmd }, - { "readonly", exportcmd }, - { "return", returncmd }, - { "set", setcmd }, - { "shift", shiftcmd }, - { "times", timescmd }, - { "trap", trapcmd }, - { ":", truecmd }, - { "unset", unsetcmd }, - { 0, 0 }, -}; diff --git a/sh/builtins.def b/sh/builtins.def deleted file mode 100644 index 18e56c6..0000000 --- a/sh/builtins.def +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/sh - -# $NetBSD: builtins.def,v 1.21 2004/07/13 15:05:59 seb Exp $ -# -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)builtins.def 8.4 (Berkeley) 5/4/95 - -# -# This file lists all the builtin commands. The first column is the name -# of a C routine. -# The -j flag specifies that this command is to be excluded from systems -# without job control. -# The -h flag specifies that this command is to be excluded from systems -# based on the SMALL compile-time symbol. -# The -s flag specifies that this is a posix 'special builtin' command. -# The -u flag specifies that this is a posix 'standard utility'. -# The rest of the line specifies the command name or names used to run -# the command. - -bltincmd -u command -bgcmd -j -u bg -breakcmd -s break -s continue -cdcmd -u cd chdir -dotcmd -s . -echocmd echo -evalcmd -s eval -execcmd -s exec -exitcmd -s exit -expcmd exp let -exportcmd -s export -s readonly -falsecmd -u false -#if WITH_HISTORY -histcmd -h -u fc -inputrc inputrc -#endif -fgcmd -j -u fg -getoptscmd -u getopts -hashcmd hash -jobidcmd jobid -jobscmd -u jobs -localcmd local -#ifndef SMALL -##printfcmd printf -#endif -pwdcmd -u pwd -readcmd -u read -returncmd -s return -setcmd -s set -setvarcmd setvar -shiftcmd -s shift -timescmd -s times -trapcmd -s trap -truecmd -s : -u true -typecmd type -umaskcmd -u umask -unaliascmd -u unalias -unsetcmd -s unset -waitcmd -u wait -aliascmd -u alias -ulimitcmd ulimit -##testcmd test [ -##killcmd -u kill # mandated by posix for 'kill %job' -wordexpcmd wordexp -#newgrp -u newgrp # optional command in posix - -#exprcmd expr diff --git a/sh/builtins.h b/sh/builtins.h deleted file mode 100644 index 1f9e45a..0000000 --- a/sh/builtins.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file was generated by the mkbuiltins program. - */ - -#include <sys/cdefs.h> - -struct builtincmd { - const char *name; - int (*builtin)(int, char **); -}; - -extern const struct builtincmd builtincmd[]; -extern const struct builtincmd splbltincmd[]; - - -int bltincmd(int, char **); -int bgcmd(int, char **); -int breakcmd(int, char **); -int cdcmd(int, char **); -int dotcmd(int, char **); -int echocmd(int, char **); -int evalcmd(int, char **); -int execcmd(int, char **); -int exitcmd(int, char **); -int expcmd(int, char **); -int exportcmd(int, char **); -int falsecmd(int, char **); -#if WITH_HISTORY -int histcmd(int, char **); -int inputrc(int, char **); -#endif -int fgcmd(int, char **); -int getoptscmd(int, char **); -int hashcmd(int, char **); -int jobidcmd(int, char **); -int jobscmd(int, char **); -int localcmd(int, char **); -#ifndef SMALL -#endif -int pwdcmd(int, char **); -int readcmd(int, char **); -int returncmd(int, char **); -int setcmd(int, char **); -int setvarcmd(int, char **); -int shiftcmd(int, char **); -int timescmd(int, char **); -int trapcmd(int, char **); -int truecmd(int, char **); -int typecmd(int, char **); -int umaskcmd(int, char **); -int unaliascmd(int, char **); -int unsetcmd(int, char **); -int waitcmd(int, char **); -int aliascmd(int, char **); -int ulimitcmd(int, char **); -int wordexpcmd(int, char **); diff --git a/sh/cd.c b/sh/cd.c deleted file mode 100644 index 4ab599b..0000000 --- a/sh/cd.c +++ /dev/null @@ -1,446 +0,0 @@ -/* $NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $"); -#endif -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -/* - * The cd and pwd commands. - */ - -#include "shell.h" -#include "var.h" -#include "nodes.h" /* for jobs.h */ -#include "jobs.h" -#include "options.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" -#include "exec.h" -#include "redir.h" -#include "mystring.h" -#include "show.h" -#include "cd.h" - -STATIC int docd(char *, int); -STATIC char *getcomponent(void); -STATIC void updatepwd(char *); -STATIC void find_curdir(int noerror); - -char *curdir = NULL; /* current working directory */ -char *prevdir; /* previous working directory */ -STATIC char *cdcomppath; - -int -cdcmd(int argc, char **argv) -{ - const char *dest; - const char *path; - char *p, *d; - struct stat statb; - int print = cdprint; /* set -cdprint to enable */ - - nextopt(nullstr); - - /* - * Try (quite hard) to have 'curdir' defined, nothing has set - * it on entry to the shell, but we want 'cd fred; cd -' to work. - */ - getpwd(1); - dest = *argptr; - if (dest == NULL) { - dest = bltinlookup("HOME", 1); - if (dest == NULL) - error("HOME not set"); - } else { - if (argptr[1]) { - /* Do 'ksh' style substitution */ - if (!curdir) - error("PWD not set"); - p = strstr(curdir, dest); - if (!p) - error("bad substitution"); - d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1); - memcpy(d, curdir, p - curdir); - strcpy(d + (p - curdir), argptr[1]); - strcat(d, p + strlen(dest)); - dest = d; - print = 1; - } - } - - if (dest[0] == '-' && dest[1] == '\0') { - dest = prevdir ? prevdir : curdir; - print = 1; - } - if (*dest == '\0') - dest = "."; - if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL) - path = nullstr; - while ((p = padvance(&path, dest)) != NULL) { - if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { - if (!print) { - /* - * XXX - rethink - */ - if (p[0] == '.' && p[1] == '/' && p[2] != '\0') - p += 2; - print = strcmp(p, dest); - } - if (docd(p, print) >= 0) - return 0; - - } - } - error("can't cd to %s", dest); - /* NOTREACHED */ -} - - -/* - * Actually do the chdir. In an interactive shell, print the - * directory name if "print" is nonzero. - */ - -STATIC int -docd(char *dest, int print) -{ - char *p; - char *q; - char *component; - struct stat statb; - int first; - int badstat; - - TRACE(("docd(\"%s\", %d) called\n", dest, print)); - - /* - * Check each component of the path. If we find a symlink or - * something we can't stat, clear curdir to force a getcwd() - * next time we get the value of the current directory. - */ - badstat = 0; - cdcomppath = stalloc(strlen(dest) + 1); - scopy(dest, cdcomppath); - STARTSTACKSTR(p); - if (*dest == '/') { - STPUTC('/', p); - cdcomppath++; - } - first = 1; - while ((q = getcomponent()) != NULL) { - if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) - continue; - if (! first) - STPUTC('/', p); - first = 0; - component = q; - while (*q) - STPUTC(*q++, p); - if (equal(component, "..")) - continue; - STACKSTRNUL(p); - if ((lstat(stackblock(), &statb) < 0) - || (S_ISLNK(statb.st_mode))) { - /* print = 1; */ - badstat = 1; - break; - } - } - - INTOFF; - if (chdir(dest) < 0) { - INTON; - return -1; - } - updatepwd(badstat ? NULL : dest); - INTON; - if (print && iflag && curdir) - out1fmt("%s\n", curdir); - return 0; -} - - -/* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. - */ - -STATIC char * -getcomponent() -{ - char *p; - char *start; - - if ((p = cdcomppath) == NULL) - return NULL; - start = cdcomppath; - while (*p != '/' && *p != '\0') - p++; - if (*p == '\0') { - cdcomppath = NULL; - } else { - *p++ = '\0'; - cdcomppath = p; - } - return start; -} - - - -/* - * Update curdir (the name of the current directory) in response to a - * cd command. We also call hashcd to let the routines in exec.c know - * that the current directory has changed. - */ - -STATIC void -updatepwd(char *dir) -{ - char *new; - char *p; - - hashcd(); /* update command hash table */ - - /* - * If our argument is NULL, we don't know the current directory - * any more because we traversed a symbolic link or something - * we couldn't stat(). - */ - if (dir == NULL || curdir == NULL) { - if (prevdir) - ckfree(prevdir); - INTOFF; - prevdir = curdir; - curdir = NULL; - getpwd(1); - INTON; - if (curdir) - setvar("PWD", curdir, VEXPORT); - else - unsetvar("PWD", 0); - return; - } - cdcomppath = stalloc(strlen(dir) + 1); - scopy(dir, cdcomppath); - STARTSTACKSTR(new); - if (*dir != '/') { - p = curdir; - while (*p) - STPUTC(*p++, new); - if (p[-1] == '/') - STUNPUTC(new); - } - while ((p = getcomponent()) != NULL) { - if (equal(p, "..")) { - while (new > stackblock() && (STUNPUTC(new), *new) != '/'); - } else if (*p != '\0' && ! equal(p, ".")) { - STPUTC('/', new); - while (*p) - STPUTC(*p++, new); - } - } - if (new == stackblock()) - STPUTC('/', new); - STACKSTRNUL(new); - INTOFF; - if (prevdir) - ckfree(prevdir); - prevdir = curdir; - curdir = savestr(stackblock()); - setvar("PWD", curdir, VEXPORT); - INTON; -} - -/* - * Posix says the default should be 'pwd -L' (as below), however - * the 'cd' command (above) does something much nearer to the - * posix 'cd -P' (not the posix default of 'cd -L'). - * If 'cd' is changed to support -P/L then the default here - * needs to be revisited if the historic behaviour is to be kept. - */ - -int -pwdcmd(int argc, char **argv) -{ - int i; - char opt = 'L'; - - while ((i = nextopt("LP")) != '\0') - opt = i; - if (*argptr) - error("unexpected argument"); - - if (opt == 'L') - getpwd(0); - else - find_curdir(0); - - setvar("PWD", curdir, VEXPORT); - out1str(curdir); - out1c('\n'); - return 0; -} - - - - -#define MAXPWD 256 - -/* - * Find out what the current directory is. If we already know the current - * directory, this routine returns immediately. - */ -void -getpwd(int noerror) -{ - char *pwd; - struct stat stdot, stpwd; - static int first = 1; - - if (curdir) - return; - - if (first) { - first = 0; - pwd = getenv("PWD"); - if (pwd && *pwd == '/' && stat(".", &stdot) != -1 && - stat(pwd, &stpwd) != -1 && - stdot.st_dev == stpwd.st_dev && - stdot.st_ino == stpwd.st_ino) { - curdir = savestr(pwd); - return; - } - } - - find_curdir(noerror); - - return; -} - -STATIC void -find_curdir(int noerror) -{ - int i; - char *pwd; - - /* - * Things are a bit complicated here; we could have just used - * getcwd, but traditionally getcwd is implemented using popen - * to /bin/pwd. This creates a problem for us, since we cannot - * keep track of the job if it is being ran behind our backs. - * So we re-implement getcwd(), and we suppress interrupts - * throughout the process. This is not completely safe, since - * the user can still break out of it by killing the pwd program. - * We still try to use getcwd for systems that we know have a - * c implementation of getcwd, that does not open a pipe to - * /bin/pwd. - */ -#if defined(__NetBSD__) || defined(__SVR4) || defined(__linux__) - for (i = MAXPWD;; i *= 2) { - pwd = stalloc(i); - if (getcwd(pwd, i) != NULL) { - curdir = savestr(pwd); - return; - } - stunalloc(pwd); - if (errno == ERANGE) - continue; - if (!noerror) - error("getcwd() failed: %s", strerror(errno)); - return; - } -#else - { - char *p; - int status; - struct job *jp; - int pip[2]; - - pwd = stalloc(MAXPWD); - INTOFF; - if (pipe(pip) < 0) - error("Pipe call failed"); - jp = makejob((union node *)NULL, 1); - if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) { - (void) close(pip[0]); - if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); - close(pip[1]); - } - (void) execl("/bin/pwd", "pwd", (char *)0); - sh_warn("Cannot exec /bin/pwd"); - exit(1); - } - (void) close(pip[1]); - pip[1] = -1; - p = pwd; - while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0 - || (i == -1 && errno == EINTR)) { - if (i > 0) - p += i; - } - (void) close(pip[0]); - pip[0] = -1; - status = waitforjob(jp); - if (status != 0) - error((char *)0); - if (i < 0 || p == pwd || p[-1] != '\n') { - if (noerror) { - INTON; - return; - } - error("pwd command failed"); - } - p[-1] = '\0'; - INTON; - curdir = savestr(pwd); - return; - } -#endif -} diff --git a/sh/cd.h b/sh/cd.h deleted file mode 100644 index a4dcc01..0000000 --- a/sh/cd.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $NetBSD: cd.h,v 1.4 2003/08/07 09:05:30 agc Exp $ */ - -/*- - * Copyright (c) 1995 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -void getpwd(int); -int cdcmd(int, char **); -int pwdcmd(int, char **); diff --git a/sh/error.c b/sh/error.c deleted file mode 100644 index 8cbed19..0000000 --- a/sh/error.c +++ /dev/null @@ -1,366 +0,0 @@ -/* $NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $"); -#endif -#endif /* not lint */ - -/* - * Errors and exceptions. - */ - -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> - -#include "shell.h" -#include "main.h" -#include "options.h" -#include "output.h" -#include "error.h" -#include "show.h" - -#define signal bsd_signal -/* - * Code to handle exceptions in C. - */ - -struct jmploc *handler; -int exception; -volatile int suppressint; -volatile int intpending; -char *commandname; - - -static void exverror(int, const char *, va_list) - __attribute__((__noreturn__)); - -/* - * Called to raise an exception. Since C doesn't include exceptions, we - * just do a longjmp to the exception handler. The type of exception is - * stored in the global variable "exception". - */ - -void -exraise(int e) -{ - if (handler == NULL) - abort(); - exception = e; - longjmp(handler->loc, 1); -} - - -/* - * Called from trap.c when a SIGINT is received. (If the user specifies - * that SIGINT is to be trapped or ignored using the trap builtin, then - * this routine is not called.) Suppressint is nonzero when interrupts - * are held using the INTOFF macro. The call to _exit is necessary because - * there is a short period after a fork before the signal handlers are - * set to the appropriate value for the child. (The test for iflag is - * just defensive programming.) - */ - -void -onint(void) -{ - sigset_t nsigset; - - if (suppressint) { - intpending = 1; - return; - } - intpending = 0; - sigemptyset(&nsigset); - sigprocmask(SIG_SETMASK, &nsigset, NULL); - if (rootshell && iflag) - exraise(EXINT); - else { - signal(SIGINT, SIG_DFL); - raise(SIGINT); - } - /* NOTREACHED */ -} - -static void -exvwarning(int sv_errno, const char *msg, va_list ap) -{ - /* Partially emulate line buffered output so that: - * printf '%d\n' 1 a 2 - * and - * printf '%d %d %d\n' 1 a 2 - * both generate sensible text when stdout and stderr are merged. - */ - if (output.nextc != output.buf && output.nextc[-1] == '\n') - flushout(&output); - if (commandname) - outfmt(&errout, "%s: ", commandname); - if (msg != NULL) { - doformat(&errout, msg, ap); - if (sv_errno >= 0) - outfmt(&errout, ": "); - } - if (sv_errno >= 0) - outfmt(&errout, "%s", strerror(sv_errno)); - out2c('\n'); - flushout(&errout); -} - -/* - * Exverror is called to raise the error exception. If the second argument - * is not NULL then error prints an error message using printf style - * formatting. It then raises the error exception. - */ -static void -exverror(int cond, const char *msg, va_list ap) -{ - CLEAR_PENDING_INT; - INTOFF; - -#ifdef DEBUG - if (msg) { - TRACE(("exverror(%d, \"", cond)); - TRACEV((msg, ap)); - TRACE(("\") pid=%d\n", getpid())); - } else - TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); -#endif - if (msg) - exvwarning(-1, msg, ap); - - flushall(); - exraise(cond); - /* NOTREACHED */ -} - - -void -error(const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - exverror(EXERROR, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - -void -exerror(int cond, const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - exverror(cond, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - -/* - * error/warning routines for external builtins - */ - -void -sh_exit(int rval) -{ - exerrno = rval & 255; - exraise(EXEXEC); -} - -void -sh_err(int status, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - exvwarning(errno, fmt, ap); - va_end(ap); - sh_exit(status); -} - -void -sh_verr(int status, const char *fmt, va_list ap) -{ - exvwarning(errno, fmt, ap); - sh_exit(status); -} - -void -sh_errx(int status, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - exvwarning(-1, fmt, ap); - va_end(ap); - sh_exit(status); -} - -void -sh_verrx(int status, const char *fmt, va_list ap) -{ - exvwarning(-1, fmt, ap); - sh_exit(status); -} - -void -sh_warn(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - exvwarning(errno, fmt, ap); - va_end(ap); -} - -void -sh_vwarn(const char *fmt, va_list ap) -{ - exvwarning(errno, fmt, ap); -} - -void -sh_warnx(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - exvwarning(-1, fmt, ap); - va_end(ap); -} - -void -sh_vwarnx(const char *fmt, va_list ap) -{ - exvwarning(-1, fmt, ap); -} - - -/* - * Table of error messages. - */ - -struct errname { - short errcode; /* error number */ - short action; /* operation which encountered the error */ - const char *msg; /* text describing the error */ -}; - - -#define ALL (E_OPEN|E_CREAT|E_EXEC) - -STATIC const struct errname errormsg[] = { - { EINTR, ALL, "interrupted" }, - { EACCES, ALL, "permission denied" }, - { EIO, ALL, "I/O error" }, - { EEXIST, ALL, "file exists" }, - { ENOENT, E_OPEN, "no such file" }, - { ENOENT, E_CREAT,"directory nonexistent" }, - { ENOENT, E_EXEC, "not found" }, - { ENOTDIR, E_OPEN, "no such file" }, - { ENOTDIR, E_CREAT,"directory nonexistent" }, - { ENOTDIR, E_EXEC, "not found" }, - { EISDIR, ALL, "is a directory" }, -#ifdef EMFILE - { EMFILE, ALL, "too many open files" }, -#endif - { ENFILE, ALL, "file table overflow" }, - { ENOSPC, ALL, "file system full" }, -#ifdef EDQUOT - { EDQUOT, ALL, "disk quota exceeded" }, -#endif -#ifdef ENOSR - { ENOSR, ALL, "no streams resources" }, -#endif - { ENXIO, ALL, "no such device or address" }, - { EROFS, ALL, "read-only file system" }, - { ETXTBSY, ALL, "text busy" }, -#ifdef EAGAIN - { EAGAIN, E_EXEC, "not enough memory" }, -#endif - { ENOMEM, ALL, "not enough memory" }, -#ifdef ENOLINK - { ENOLINK, ALL, "remote access failed" }, -#endif -#ifdef EMULTIHOP - { EMULTIHOP, ALL, "remote access failed" }, -#endif -#ifdef ECOMM - { ECOMM, ALL, "remote access failed" }, -#endif -#ifdef ESTALE - { ESTALE, ALL, "remote access failed" }, -#endif -#ifdef ETIMEDOUT - { ETIMEDOUT, ALL, "remote access failed" }, -#endif -#ifdef ELOOP - { ELOOP, ALL, "symbolic link loop" }, -#endif - { E2BIG, E_EXEC, "argument list too long" }, -#ifdef ELIBACC - { ELIBACC, E_EXEC, "shared library missing" }, -#endif - { 0, 0, NULL }, -}; - - -/* - * Return a string describing an error. The returned string may be a - * pointer to a static buffer that will be overwritten on the next call. - * Action describes the operation that got the error. - */ - -const char * -errmsg(int e, int action) -{ - struct errname const *ep; - static char buf[12]; - - for (ep = errormsg ; ep->errcode ; ep++) { - if (ep->errcode == e && (ep->action & action) != 0) - return ep->msg; - } - fmtstr(buf, sizeof buf, "error %d", e); - return buf; -} diff --git a/sh/error.h b/sh/error.h deleted file mode 100644 index 8e70ca4..0000000 --- a/sh/error.h +++ /dev/null @@ -1,117 +0,0 @@ -/* $NetBSD: error.h,v 1.16 2003/08/07 09:05:30 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)error.h 8.2 (Berkeley) 5/4/95 - */ - -#include <stdarg.h> - -/* - * Types of operations (passed to the errmsg routine). - */ - -#define E_OPEN 01 /* opening a file */ -#define E_CREAT 02 /* creating a file */ -#define E_EXEC 04 /* 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. - */ - -#include <setjmp.h> - -struct jmploc { - jmp_buf loc; -}; - -extern struct jmploc *handler; -extern int exception; -extern int exerrno; /* 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 */ - - -/* - * 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. :-)) - */ - -extern volatile int suppressint; -extern volatile int intpending; - -#define INTOFF suppressint++ -#define INTON { if (--suppressint == 0 && intpending) onint(); } -#define FORCEINTON {suppressint = 0; if (intpending) onint();} -#define CLEAR_PENDING_INT intpending = 0 -#define int_pending() intpending - -void exraise(int) __attribute__((__noreturn__)); -void onint(void); -void error(const char *, ...) __attribute__((__noreturn__)); -void exerror(int, const char *, ...) __attribute__((__noreturn__)); -const char *errmsg(int, int); - -void sh_err(int, const char *, ...) __attribute__((__noreturn__)); -void sh_verr(int, const char *, va_list) __attribute__((__noreturn__)); -void sh_errx(int, const char *, ...) __attribute__((__noreturn__)); -void sh_verrx(int, const char *, va_list) __attribute__((__noreturn__)); -void sh_warn(const char *, ...); -void sh_vwarn(const char *, va_list); -void sh_warnx(const char *, ...); -void sh_vwarnx(const char *, va_list); - -void sh_exit(int) __attribute__((__noreturn__)); - - -/* - * BSD setjmp saves the signal mask, which violates ANSI C and takes time, - * so we use _setjmp instead. - */ - -#if defined(BSD) && !defined(__SVR4) && !defined(__linux__) -#define setjmp(jmploc) _setjmp(jmploc) -#define longjmp(jmploc, val) _longjmp(jmploc, val) -#endif diff --git a/sh/eval.c b/sh/eval.c deleted file mode 100644 index 4eb7ded..0000000 --- a/sh/eval.c +++ /dev/null @@ -1,1257 +0,0 @@ -/* $NetBSD: eval.c,v 1.81.2.1 2005/06/13 22:03:51 tron Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; -#else -__RCSID("$NetBSD: eval.c,v 1.81.2.1 2005/06/13 22:03:51 tron Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> -#include <signal.h> -#include <stdio.h> -#include <unistd.h> -#ifdef __linux__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#include <sys/times.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/wait.h> - -/* - * Evaluate a command. - */ - -#include "shell.h" -#include "nodes.h" -#include "syntax.h" -#include "expand.h" -#include "parser.h" -#include "jobs.h" -#include "eval.h" -#include "builtins.h" -#include "options.h" -#include "exec.h" -#include "redir.h" -#include "input.h" -#include "output.h" -#include "trap.h" -#include "var.h" -#include "memalloc.h" -#include "error.h" -#include "show.h" -#include "mystring.h" -#include "main.h" -#ifndef SMALL -#include "myhistedit.h" -#endif - - -/* flags in argument to evaltree */ -#define EV_EXIT 01 /* exit after evaluating tree */ -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#define EV_BACKCMD 04 /* command executing within back quotes */ - -int evalskip; /* set if we are skipping commands */ -STATIC int skipcount; /* number of levels to skip */ -MKINIT int loopnest; /* current loop nesting level */ -int funcnest; /* depth of function calls */ - - -char *commandname; -struct strlist *cmdenviron; -int exitstatus; /* exit status of last command */ -int back_exitstatus; /* exit status of backquoted command */ - - -STATIC void evalloop(union node *, int); -STATIC void evalfor(union node *, int); -STATIC void evalcase(union node *, int); -STATIC void evalsubshell(union node *, int); -STATIC void expredir(union node *); -STATIC void evalpipe(union node *); -STATIC void evalcommand(union node *, int, struct backcmd *); -STATIC void prehash(union node *); - - -/* - * Called to reset things after an exception. - */ - -#ifdef mkinit -INCLUDE "eval.h" - -RESET { - evalskip = 0; - loopnest = 0; - funcnest = 0; -} - -SHELLPROC { - exitstatus = 0; -} -#endif - -static int -sh_pipe(int fds[2]) -{ - int nfd; - - if (pipe(fds)) - return -1; - - if (fds[0] < 3) { - nfd = fcntl(fds[0], F_DUPFD, 3); - if (nfd != -1) { - close(fds[0]); - fds[0] = nfd; - } - } - - if (fds[1] < 3) { - nfd = fcntl(fds[1], F_DUPFD, 3); - if (nfd != -1) { - close(fds[1]); - fds[1] = nfd; - } - } - return 0; -} - - -/* - * The eval commmand. - */ - -int -evalcmd(int argc, char **argv) -{ - char *p; - char *concat; - char **ap; - - if (argc > 1) { - p = argv[1]; - if (argc > 2) { - STARTSTACKSTR(concat); - ap = argv + 2; - for (;;) { - while (*p) - STPUTC(*p++, concat); - if ((p = *ap++) == NULL) - break; - STPUTC(' ', concat); - } - STPUTC('\0', concat); - p = grabstackstr(concat); - } - evalstring(p, EV_TESTED); - } - return exitstatus; -} - - -/* - * Execute a command or commands contained in a string. - */ - -void -evalstring(char *s, int flag) -{ - union node *n; - struct stackmark smark; - - setstackmark(&smark); - setinputstring(s, 1); - - while ((n = parsecmd(0)) != NEOF) { - evaltree(n, flag); - popstackmark(&smark); - } - popfile(); - popstackmark(&smark); -} - - - -/* - * Evaluate a parse tree. The value is left in the global variable - * exitstatus. - */ - -void -evaltree(union node *n, int flags) -{ - if (n == NULL) { - TRACE(("evaltree(NULL) called\n")); - exitstatus = 0; - goto out; - } -#ifdef WITH_HISTORY - displayhist = 1; /* show history substitutions done with fc */ -#endif - TRACE(("pid %d, evaltree(%p: %d, %d) called\n", - getpid(), n, n->type, flags)); - switch (n->type) { - case NSEMI: - evaltree(n->nbinary.ch1, flags & EV_TESTED); - if (evalskip) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NAND: - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus != 0) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NOR: - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus == 0) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NREDIR: - expredir(n->nredir.redirect); - redirect(n->nredir.redirect, REDIR_PUSH); - evaltree(n->nredir.n, flags); - popredir(); - break; - case NSUBSHELL: - evalsubshell(n, flags); - break; - case NBACKGND: - evalsubshell(n, flags); - break; - case NIF: { - evaltree(n->nif.test, EV_TESTED); - if (evalskip) - goto out; - if (exitstatus == 0) - evaltree(n->nif.ifpart, flags); - else if (n->nif.elsepart) - evaltree(n->nif.elsepart, flags); - else - exitstatus = 0; - break; - } - case NWHILE: - case NUNTIL: - evalloop(n, flags); - break; - case NFOR: - evalfor(n, flags); - break; - case NCASE: - evalcase(n, flags); - break; - case NDEFUN: - defun(n->narg.text, n->narg.next); - exitstatus = 0; - break; - case NNOT: - evaltree(n->nnot.com, EV_TESTED); - exitstatus = !exitstatus; - break; - case NPIPE: - evalpipe(n); - break; - case NCMD: - evalcommand(n, flags, (struct backcmd *)NULL); - break; - default: - out1fmt("Node type = %d\n", n->type); - flushout(&output); - break; - } -out: - if (pendingsigs) - dotrap(); - if ((flags & EV_EXIT) != 0) - exitshell(exitstatus); -} - - -STATIC void -evalloop(union node *n, int flags) -{ - int status; - - loopnest++; - status = 0; - for (;;) { - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip) { -skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { - evalskip = 0; - continue; - } - if (evalskip == SKIPBREAK && --skipcount <= 0) - evalskip = 0; - break; - } - if (n->type == NWHILE) { - if (exitstatus != 0) - break; - } else { - if (exitstatus == 0) - break; - } - evaltree(n->nbinary.ch2, flags & EV_TESTED); - status = exitstatus; - if (evalskip) - goto skipping; - } - loopnest--; - exitstatus = status; -} - - - -STATIC void -evalfor(union node *n, int flags) -{ - struct arglist arglist; - union node *argp; - struct strlist *sp; - struct stackmark smark; - int status = 0; - - setstackmark(&smark); - arglist.lastp = &arglist.list; - for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - if (evalskip) - goto out; - } - *arglist.lastp = NULL; - - loopnest++; - for (sp = arglist.list ; sp ; sp = sp->next) { - setvar(n->nfor.var, sp->text, 0); - evaltree(n->nfor.body, flags & EV_TESTED); - status = exitstatus; - if (evalskip) { - if (evalskip == SKIPCONT && --skipcount <= 0) { - evalskip = 0; - continue; - } - if (evalskip == SKIPBREAK && --skipcount <= 0) - evalskip = 0; - break; - } - } - loopnest--; - exitstatus = status; -out: - popstackmark(&smark); -} - - - -STATIC void -evalcase(union node *n, int flags) -{ - union node *cp; - union node *patp; - struct arglist arglist; - struct stackmark smark; - int status = 0; - - setstackmark(&smark); - arglist.lastp = &arglist.list; - expandarg(n->ncase.expr, &arglist, EXP_TILDE); - for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { - for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { - if (casematch(patp, arglist.list->text)) { - if (evalskip == 0) { - evaltree(cp->nclist.body, flags); - status = exitstatus; - } - goto out; - } - } - } -out: - exitstatus = status; - popstackmark(&smark); -} - - - -/* - * Kick off a subshell to evaluate a tree. - */ - -STATIC void -evalsubshell(union node *n, int flags) -{ - struct job *jp; - int backgnd = (n->type == NBACKGND); - - expredir(n->nredir.redirect); - INTOFF; - jp = makejob(n, 1); - if (forkshell(jp, n, backgnd) == 0) { - INTON; - if (backgnd) - flags &=~ EV_TESTED; - redirect(n->nredir.redirect, 0); - /* never returns */ - evaltree(n->nredir.n, flags | EV_EXIT); - } - if (! backgnd) - exitstatus = waitforjob(jp); - INTON; -} - - - -/* - * Compute the names of the files in a redirection list. - */ - -STATIC void -expredir(union node *n) -{ - union node *redir; - - for (redir = n ; redir ; redir = redir->nfile.next) { - struct arglist fn; - fn.lastp = &fn.list; - switch (redir->type) { - case NFROMTO: - case NFROM: - case NTO: - case NCLOBBER: - case NAPPEND: - expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); - redir->nfile.expfname = fn.list->text; - break; - case NFROMFD: - case NTOFD: - if (redir->ndup.vname) { - expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); - fixredir(redir, fn.list->text, 1); - } - break; - } - } -} - - - -/* - * Evaluate a pipeline. All the processes in the pipeline are children - * of the process creating the pipeline. (This differs from some versions - * of the shell, which make the last process in a pipeline the parent - * of all the rest.) - */ - -STATIC void -evalpipe(union node *n) -{ - struct job *jp; - struct nodelist *lp; - int pipelen; - int prevfd; - int pip[2]; - - TRACE(("evalpipe(0x%lx) called\n", (long)n)); - pipelen = 0; - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) - pipelen++; - INTOFF; - jp = makejob(n, pipelen); - prevfd = -1; - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - prehash(lp->n); - pip[1] = -1; - if (lp->next) { - if (sh_pipe(pip) < 0) { - close(prevfd); - error("Pipe call failed"); - } - } - if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { - INTON; - if (prevfd > 0) { - close(0); - copyfd(prevfd, 0); - close(prevfd); - } - if (pip[1] >= 0) { - close(pip[0]); - if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); - close(pip[1]); - } - } - evaltree(lp->n, EV_EXIT); - } - if (prevfd >= 0) - close(prevfd); - prevfd = pip[0]; - close(pip[1]); - } - if (n->npipe.backgnd == 0) { - exitstatus = waitforjob(jp); - TRACE(("evalpipe: job done exit status %d\n", exitstatus)); - } - INTON; -} - - - -/* - * Execute a command inside back quotes. If it's a builtin command, we - * want to save its output in a block obtained from malloc. Otherwise - * we fork off a subprocess and get the output of the command via a pipe. - * Should be called with interrupts off. - */ - -void -evalbackcmd(union node *n, struct backcmd *result) -{ - int pip[2]; - struct job *jp; - struct stackmark smark; /* unnecessary */ - - setstackmark(&smark); - result->fd = -1; - result->buf = NULL; - result->nleft = 0; - result->jp = NULL; - if (n == NULL) { - goto out; - } -#ifdef notyet - /* - * For now we disable executing builtins in the same - * context as the shell, because we are not keeping - * enough state to recover from changes that are - * supposed only to affect subshells. eg. echo "`cd /`" - */ - if (n->type == NCMD) { - exitstatus = oexitstatus; - evalcommand(n, EV_BACKCMD, result); - } else -#endif - { - INTOFF; - if (sh_pipe(pip) < 0) - error("Pipe call failed"); - jp = makejob(n, 1); - if (forkshell(jp, n, FORK_NOJOB) == 0) { - FORCEINTON; - close(pip[0]); - if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); - close(pip[1]); - } - eflag = 0; - evaltree(n, EV_EXIT); - /* NOTREACHED */ - } - close(pip[1]); - result->fd = pip[0]; - result->jp = jp; - INTON; - } -out: - popstackmark(&smark); - TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", - result->fd, result->buf, result->nleft, result->jp)); -} - -static const char * -syspath(void) -{ - static char *sys_path = NULL; -#ifndef __linux__ - static int mib[] = {CTL_USER, USER_CS_PATH}; -#endif - static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin"; - - if (sys_path == NULL) { -#ifndef __linux__ - size_t len; - if (sysctl(mib, 2, 0, &len, 0, 0) != -1 && - (sys_path = ckmalloc(len + 5)) != NULL && - sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) { - memcpy(sys_path, "PATH=", 5); - } else -#endif - { - ckfree(sys_path); - /* something to keep things happy */ - sys_path = def_path; - } - } - return sys_path; -} - -static int -parse_command_args(int argc, char **argv, int *use_syspath) -{ - int sv_argc = argc; - char *cp, c; - - *use_syspath = 0; - - for (;;) { - argv++; - if (--argc == 0) - break; - cp = *argv; - if (*cp++ != '-') - break; - if (*cp == '-' && cp[1] == 0) { - argv++; - argc--; - break; - } - while ((c = *cp++)) { - switch (c) { - case 'p': - *use_syspath = 1; - break; - default: - /* run 'typecmd' for other options */ - return 0; - } - } - } - return sv_argc - argc; -} - -int vforked = 0; - -/* - * Execute a simple command. - */ - -STATIC void -evalcommand(union node *cmd, int flags, struct backcmd *backcmd) -{ - struct stackmark smark; - union node *argp; - struct arglist arglist; - struct arglist varlist; - char **argv; - int argc; - char **envp; - int varflag; - struct strlist *sp; - int mode; - int pip[2]; - struct cmdentry cmdentry; - struct job *jp; - struct jmploc jmploc; - struct jmploc *volatile savehandler = 0; - char *volatile savecmdname; - volatile struct shparam saveparam; - struct localvar *volatile savelocalvars; - volatile int e; - char *lastarg; - const char *path = pathval(); - volatile int temp_path = 0; -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &argv; - (void) &argc; - (void) &lastarg; - (void) &flags; -#endif - - vforked = 0; - /* First expand the arguments. */ - TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); - setstackmark(&smark); - back_exitstatus = 0; - - arglist.lastp = &arglist.list; - varflag = 1; - /* Expand arguments, ignoring the initial 'name=value' ones */ - for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { - char *p = argp->narg.text; - if (varflag && is_name(*p)) { - do { - p++; - } while (is_in_name(*p)); - if (*p == '=') - continue; - } - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - varflag = 0; - } - *arglist.lastp = NULL; - - expredir(cmd->ncmd.redirect); - - /* Now do the initial 'name=value' ones we skipped above */ - varlist.lastp = &varlist.list; - for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { - char *p = argp->narg.text; - if (!is_name(*p)) - break; - do - p++; - while (is_in_name(*p)); - if (*p != '=') - break; - expandarg(argp, &varlist, EXP_VARTILDE); - } - *varlist.lastp = NULL; - - argc = 0; - for (sp = arglist.list ; sp ; sp = sp->next) - argc++; - argv = stalloc(sizeof (char *) * (argc + 1)); - - for (sp = arglist.list ; sp ; sp = sp->next) { - TRACE(("evalcommand arg: %s\n", sp->text)); - *argv++ = sp->text; - } - *argv = NULL; - lastarg = NULL; - if (iflag && funcnest == 0 && argc > 0) - lastarg = argv[-1]; - argv -= argc; - - /* Print the command if xflag is set. */ - if (xflag) { - char sep = 0; - out2str(ps4val()); - for (sp = varlist.list ; sp ; sp = sp->next) { - if (sep != 0) - outc(sep, &errout); - out2str(sp->text); - sep = ' '; - } - for (sp = arglist.list ; sp ; sp = sp->next) { - if (sep != 0) - outc(sep, &errout); - out2str(sp->text); - sep = ' '; - } - outc('\n', &errout); - flushout(&errout); - } - - /* Now locate the command. */ - if (argc == 0) { - cmdentry.cmdtype = CMDSPLBLTIN; - cmdentry.u.bltin = bltincmd; - } else { - static const char PATH[] = "PATH="; - int cmd_flags = DO_ERR; - - /* - * Modify the command lookup path, if a PATH= assignment - * is present - */ - for (sp = varlist.list; sp; sp = sp->next) - if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) - path = sp->text + sizeof(PATH) - 1; - - do { - int argsused, use_syspath; - find_command(argv[0], &cmdentry, cmd_flags, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { - exitstatus = 127; - flushout(&errout); - goto out; - } - - /* implement the 'command' builtin here */ - if (cmdentry.cmdtype != CMDBUILTIN || - cmdentry.u.bltin != bltincmd) - break; - cmd_flags |= DO_NOFUNC; - argsused = parse_command_args(argc, argv, &use_syspath); - if (argsused == 0) { - /* use 'type' builting to display info */ - cmdentry.u.bltin = typecmd; - break; - } - argc -= argsused; - argv += argsused; - if (use_syspath) - path = syspath() + 5; - } while (argc != 0); - if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) - /* posix mandates that 'command <splbltin>' act as if - <splbltin> was a normal builtin */ - cmdentry.cmdtype = CMDBUILTIN; - } - - /* Fork off a child process if necessary. */ - if (cmd->ncmd.backgnd - || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) - || ((flags & EV_BACKCMD) != 0 - && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) - || cmdentry.u.bltin == dotcmd - || cmdentry.u.bltin == evalcmd))) { - INTOFF; - jp = makejob(cmd, 1); - mode = cmd->ncmd.backgnd; - if (flags & EV_BACKCMD) { - mode = FORK_NOJOB; - if (sh_pipe(pip) < 0) - error("Pipe call failed"); - } -#ifdef DO_SHAREDVFORK - /* It is essential that if DO_SHAREDVFORK is defined that the - * child's address space is actually shared with the parent as - * we rely on this. - */ - if (cmdentry.cmdtype == CMDNORMAL) { - pid_t pid; - - savelocalvars = localvars; - localvars = NULL; - vforked = 1; - switch (pid = vfork()) { - case -1: - TRACE(("Vfork failed, errno=%d\n", errno)); - INTON; - error("Cannot vfork"); - break; - case 0: - /* Make sure that exceptions only unwind to - * after the vfork(2) - */ - if (setjmp(jmploc.loc)) { - if (exception == EXSHELLPROC) { - /* We can't progress with the vfork, - * so, set vforked = 2 so the parent - * knows, and _exit(); - */ - vforked = 2; - _exit(0); - } else { - _exit(exerrno); - } - } - savehandler = handler; - handler = &jmploc; - listmklocal(varlist.list, VEXPORT | VNOFUNC); - forkchild(jp, cmd, mode, vforked); - break; - default: - handler = savehandler; /* restore from vfork(2) */ - poplocalvars(); - localvars = savelocalvars; - if (vforked == 2) { - vforked = 0; - - (void)waitpid(pid, NULL, 0); - /* We need to progress in a normal fork fashion */ - goto normal_fork; - } - vforked = 0; - forkparent(jp, cmd, mode, pid); - goto parent; - } - } else { -normal_fork: -#endif - if (forkshell(jp, cmd, mode) != 0) - goto parent; /* at end of routine */ - FORCEINTON; -#ifdef DO_SHAREDVFORK - } -#endif - if (flags & EV_BACKCMD) { - if (!vforked) { - FORCEINTON; - } - close(pip[0]); - if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); - close(pip[1]); - } - } - flags |= EV_EXIT; - } - - /* This is the child process if a fork occurred. */ - /* Execute the command. */ - switch (cmdentry.cmdtype) { - case CMDFUNCTION: -#ifdef DEBUG - trputs("Shell function: "); trargs(argv); -#endif - redirect(cmd->ncmd.redirect, REDIR_PUSH); - saveparam = shellparam; - shellparam.malloc = 0; - shellparam.reset = 1; - shellparam.nparam = argc - 1; - shellparam.p = argv + 1; - shellparam.optnext = NULL; - INTOFF; - savelocalvars = localvars; - localvars = NULL; - INTON; - if (setjmp(jmploc.loc)) { - if (exception == EXSHELLPROC) { - freeparam((volatile struct shparam *) - &saveparam); - } else { - freeparam(&shellparam); - shellparam = saveparam; - } - poplocalvars(); - localvars = savelocalvars; - handler = savehandler; - longjmp(handler->loc, 1); - } - savehandler = handler; - handler = &jmploc; - listmklocal(varlist.list, 0); - /* stop shell blowing its stack */ - if (++funcnest > 1000) - error("too many nested function calls"); - evaltree(cmdentry.u.func, flags & EV_TESTED); - funcnest--; - INTOFF; - poplocalvars(); - localvars = savelocalvars; - freeparam(&shellparam); - shellparam = saveparam; - handler = savehandler; - popredir(); - INTON; - if (evalskip == SKIPFUNC) { - evalskip = 0; - skipcount = 0; - } - if (flags & EV_EXIT) - exitshell(exitstatus); - break; - - case CMDBUILTIN: - case CMDSPLBLTIN: -#ifdef DEBUG - trputs("builtin command: "); trargs(argv); -#endif - mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; - if (flags == EV_BACKCMD) { - memout.nleft = 0; - memout.nextc = memout.buf; - memout.bufsize = 64; - mode |= REDIR_BACKQ; - } - e = -1; - savehandler = handler; - savecmdname = commandname; - handler = &jmploc; - if (!setjmp(jmploc.loc)) { - /* We need to ensure the command hash table isn't - * corruped by temporary PATH assignments. - * However we must ensure the 'local' command works! - */ - if (path != pathval() && (cmdentry.u.bltin == hashcmd || - cmdentry.u.bltin == typecmd)) { - savelocalvars = localvars; - localvars = 0; - mklocal(path - 5 /* PATH= */, 0); - temp_path = 1; - } else - temp_path = 0; - redirect(cmd->ncmd.redirect, mode); - - /* exec is a special builtin, but needs this list... */ - cmdenviron = varlist.list; - /* we must check 'readonly' flag for all builtins */ - listsetvar(varlist.list, - cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); - commandname = argv[0]; - /* initialize nextopt */ - argptr = argv + 1; - optptr = NULL; - /* and getopt */ -#ifndef __linux__ - optreset = 1; -#endif - optind = 1; - exitstatus = cmdentry.u.bltin(argc, argv); - } else { - e = exception; - exitstatus = e == EXINT ? SIGINT + 128 : - e == EXEXEC ? exerrno : 2; - } - handler = savehandler; - flushall(); - out1 = &output; - out2 = &errout; - freestdout(); - if (temp_path) { - poplocalvars(); - localvars = savelocalvars; - } - cmdenviron = NULL; - if (e != EXSHELLPROC) { - commandname = savecmdname; - if (flags & EV_EXIT) - exitshell(exitstatus); - } - if (e != -1) { - if ((e != EXERROR && e != EXEXEC) - || cmdentry.cmdtype == CMDSPLBLTIN) - exraise(e); - FORCEINTON; - } - if (cmdentry.u.bltin != execcmd) - popredir(); - if (flags == EV_BACKCMD) { - backcmd->buf = memout.buf; - backcmd->nleft = memout.nextc - memout.buf; - memout.buf = NULL; - } - break; - - default: -#ifdef DEBUG - trputs("normal command: "); trargs(argv); -#endif - clearredir(vforked); - redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0); - if (!vforked) - for (sp = varlist.list ; sp ; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - envp = environment(); - shellexec(argv, envp, path, cmdentry.u.index, vforked); - break; - } - goto out; - -parent: /* parent process gets here (if we forked) */ - if (mode == FORK_FG) { /* argument to fork */ - exitstatus = waitforjob(jp); - } else if (mode == FORK_NOJOB) { - backcmd->fd = pip[0]; - close(pip[1]); - backcmd->jp = jp; - } - FORCEINTON; - -out: - if (lastarg) - /* dsl: I think this is intended to be used to support - * '_' in 'vi' command mode during line editing... - * However I implemented that within libedit itself. - */ - setvar("_", lastarg, 0); - popstackmark(&smark); - - if (eflag && exitstatus && !(flags & EV_TESTED)) - exitshell(exitstatus); -} - - -/* - * Search for a command. This is called before we fork so that the - * location of the command will be available in the parent as well as - * the child. The check for "goodname" is an overly conservative - * check that the name will not be subject to expansion. - */ - -STATIC void -prehash(union node *n) -{ - struct cmdentry entry; - - if (n->type == NCMD && n->ncmd.args) - if (goodname(n->ncmd.args->narg.text)) - find_command(n->ncmd.args->narg.text, &entry, 0, - pathval()); -} - - - -/* - * Builtin commands. Builtin commands whose functions are closely - * tied to evaluation are implemented here. - */ - -/* - * No command given. - */ - -int -bltincmd(int argc, char **argv) -{ - /* - * Preserve exitstatus of a previous possible redirection - * as POSIX mandates - */ - return back_exitstatus; -} - - -/* - * Handle break and continue commands. Break, continue, and return are - * all handled by setting the evalskip flag. The evaluation routines - * above all check this flag, and if it is set they start skipping - * commands rather than executing them. The variable skipcount is - * the number of loops to break/continue, or the number of function - * levels to return. (The latter is always 1.) It should probably - * be an error to break out of more loops than exist, but it isn't - * in the standard shell so we don't make it one here. - */ - -int -breakcmd(int argc, char **argv) -{ - int n = argc > 1 ? number(argv[1]) : 1; - - if (n > loopnest) - n = loopnest; - if (n > 0) { - evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; - skipcount = n; - } - return 0; -} - - -/* - * The return command. - */ - -int -returncmd(int argc, char **argv) -{ - int ret = argc > 1 ? number(argv[1]) : exitstatus; - - if (funcnest) { - evalskip = SKIPFUNC; - skipcount = 1; - return ret; - } - else { - /* Do what ksh does; skip the rest of the file */ - evalskip = SKIPFILE; - skipcount = 1; - return ret; - } -} - - -int -falsecmd(int argc, char **argv) -{ - return 1; -} - - -int -truecmd(int argc, char **argv) -{ - return 0; -} - - -int -execcmd(int argc, char **argv) -{ - if (argc > 1) { - struct strlist *sp; - - iflag = 0; /* exit on error */ - mflag = 0; - optschanged(); - for (sp = cmdenviron; sp; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - shellexec(argv + 1, environment(), pathval(), 0, 0); - } - return 0; -} - -static int -conv_time(clock_t ticks, char *seconds, size_t l) -{ - static clock_t tpm = 0; - clock_t mins; - int i; - - mins = ticks / tpm; - snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm ); - - if (seconds[0] == '6' && seconds[1] == '0') { - /* 59.99995 got rounded up... */ - mins++; - strlcpy(seconds, "0.0", l); - return mins; - } - - /* suppress trailing zeros */ - i = strlen(seconds) - 1; - for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--) - seconds[i] = 0; - return mins; -} - -int -timescmd(int argc, char **argv) -{ - struct tms tms; - int u, s, cu, cs; - char us[8], ss[8], cus[8], css[8]; - - nextopt(""); - - times(&tms); - - u = conv_time(tms.tms_utime, us, sizeof(us)); - s = conv_time(tms.tms_stime, ss, sizeof(ss)); - cu = conv_time(tms.tms_cutime, cus, sizeof(cus)); - cs = conv_time(tms.tms_cstime, css, sizeof(css)); - - outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n", - u, us, s, ss, cu, cus, cs, css); - - return 0; -} diff --git a/sh/eval.h b/sh/eval.h deleted file mode 100644 index 155bc44..0000000 --- a/sh/eval.h +++ /dev/null @@ -1,64 +0,0 @@ -/* $NetBSD: eval.h,v 1.14 2003/08/07 09:05:31 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)eval.h 8.2 (Berkeley) 5/4/95 - */ - -extern char *commandname; /* currently executing command */ -extern int exitstatus; /* exit status of last command */ -extern int back_exitstatus; /* exit status of backquoted command */ -extern struct strlist *cmdenviron; /* environment for builtin 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 */ -}; - -void evalstring(char *, int); -union node; /* BLETCH for ansi C */ -void evaltree(union node *, int); -void evalbackcmd(union node *, struct backcmd *); - -/* in_function returns nonzero if we are currently evaluating a function */ -#define in_function() funcnest -extern int funcnest; -extern int evalskip; - -/* reasons for skipping commands (see comment on breakcmd routine) */ -#define SKIPBREAK 1 -#define SKIPCONT 2 -#define SKIPFUNC 3 -#define SKIPFILE 4 diff --git a/sh/exec.c b/sh/exec.c deleted file mode 100644 index fe3613f..0000000 --- a/sh/exec.c +++ /dev/null @@ -1,1063 +0,0 @@ -/* $NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95"; -#else -__RCSID("$NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc Exp $"); -#endif -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> - -/* - * When commands are first encountered, they are entered in a hash table. - * This ensures that a full path search will not have to be done for them - * on each invocation. - * - * We should investigate converting to a linear search, even though that - * would make the command name "hash" a misnomer. - */ - -#include "shell.h" -#include "main.h" -#include "nodes.h" -#include "parser.h" -#include "redir.h" -#include "eval.h" -#include "exec.h" -#include "builtins.h" -#include "var.h" -#include "options.h" -#include "input.h" -#include "output.h" -#include "syntax.h" -#include "memalloc.h" -#include "error.h" -#include "init.h" -#include "mystring.h" -#include "show.h" -#include "jobs.h" -#include "alias.h" - - -#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 */ -}; - - -STATIC struct tblentry *cmdtable[CMDTABLESIZE]; -STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */ -int exerrno = 0; /* Last exec error */ - - -STATIC void tryexec(char *, char **, char **, int); -STATIC void execinterp(char **, char **); -STATIC void printentry(struct tblentry *, int); -STATIC void clearcmdentry(int); -STATIC struct tblentry *cmdlookup(const char *, int); -STATIC void delete_cmd_entry(void); - - -extern char *const parsekwd[]; - -/* - * Exec a program. Never returns. If you change this routine, you may - * have to change the find_command routine as well. - */ - -void -shellexec(char **argv, char **envp, const char *path, int idx, int vforked) -{ - char *cmdname; - int e; - - if (strchr(argv[0], '/') != NULL) { - tryexec(argv[0], argv, envp, vforked); - e = errno; - } else { - e = ENOENT; - while ((cmdname = padvance(&path, argv[0])) != NULL) { - if (--idx < 0 && pathopt == NULL) { - tryexec(cmdname, argv, envp, vforked); - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - } - stunalloc(cmdname); - } - } - - /* Map to POSIX errors */ - switch (e) { - case EACCES: - exerrno = 126; - break; - case ENOENT: - exerrno = 127; - break; - default: - exerrno = 2; - break; - } - TRACE(("shellexec failed for %s, errno %d, vforked %d, suppressint %d\n", - argv[0], e, vforked, suppressint )); - exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); - /* NOTREACHED */ -} - - -STATIC void -tryexec(char *cmd, char **argv, char **envp, int vforked) -{ - int e; -#ifndef BSD - char *p; -#endif - -#ifdef SYSV - do { - execve(cmd, argv, envp); - } while (errno == EINTR); -#else - execve(cmd, argv, envp); -#endif - e = errno; - if (e == ENOEXEC) { - if (vforked) { - /* We are currently vfork(2)ed, so raise an - * exception, and evalcommand will try again - * with a normal fork(2). - */ - exraise(EXSHELLPROC); - } - initshellproc(); - setinputfile(cmd, 0); - commandname = arg0 = savestr(argv[0]); -#if !defined(BSD) && !defined(__linux__) - pgetc(); pungetc(); /* fill up input buffer */ - p = parsenextc; - if (parsenleft > 2 && p[0] == '#' && p[1] == '!') { - argv[0] = cmd; - execinterp(argv, envp); - } -#endif - setparam(argv + 1); - exraise(EXSHELLPROC); - } - errno = e; -} - - -#if !defined(BSD) && !defined(__linux__) -/* - * Execute an interpreter introduced by "#!", for systems where this - * feature has not been built into the kernel. If the interpreter is - * the shell, return (effectively ignoring the "#!"). If the execution - * of the interpreter fails, exit. - * - * This code peeks inside the input buffer in order to avoid actually - * reading any input. It would benefit from a rewrite. - */ - -#define NEWARGS 5 - -STATIC void -execinterp(char **argv, char **envp) -{ - int n; - char *inp; - char *outp; - char c; - char *p; - char **ap; - char *newargs[NEWARGS]; - int i; - char **ap2; - char **new; - - n = parsenleft - 2; - inp = parsenextc + 2; - ap = newargs; - for (;;) { - while (--n >= 0 && (*inp == ' ' || *inp == '\t')) - inp++; - if (n < 0) - goto bad; - if ((c = *inp++) == '\n') - break; - if (ap == &newargs[NEWARGS]) -bad: error("Bad #! line"); - STARTSTACKSTR(outp); - do { - STPUTC(c, outp); - } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n'); - STPUTC('\0', outp); - n++, inp--; - *ap++ = grabstackstr(outp); - } - if (ap == newargs + 1) { /* if no args, maybe no exec is needed */ - p = newargs[0]; - for (;;) { - if (equal(p, "sh") || equal(p, "ash")) { - return; - } - while (*p != '/') { - if (*p == '\0') - goto break2; - p++; - } - p++; - } -break2:; - } - i = (char *)ap - (char *)newargs; /* size in bytes */ - if (i == 0) - error("Bad #! line"); - for (ap2 = argv ; *ap2++ != NULL ; ); - new = ckmalloc(i + ((char *)ap2 - (char *)argv)); - ap = newargs, ap2 = new; - while ((i -= sizeof (char **)) >= 0) - *ap2++ = *ap++; - ap = argv; - while (*ap2++ = *ap++); - shellexec(new, envp, pathval(), 0); - /* NOTREACHED */ -} -#endif - - - -/* - * Do a path search. The variable path (passed by reference) should be - * set to the start of the path before the first call; padvance will update - * this value as it proceeds. Successive calls to padvance will return - * the possible path expansions in sequence. If an option (indicated by - * a percent sign) appears in the path entry then the global variable - * pathopt will be set to point to it; otherwise pathopt will be set to - * NULL. - */ - -const char *pathopt; - -char * -padvance(const char **path, const char *name) -{ - const char *p; - char *q; - const char *start; - int len; - - if (*path == NULL) - return NULL; - start = *path; - for (p = start ; *p && *p != ':' && *p != '%' ; p++); - len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ - while (stackblocksize() < len) - growstackblock(); - q = stackblock(); - if (p != start) { - memcpy(q, start, p - start); - q += p - start; - *q++ = '/'; - } - strcpy(q, name); - pathopt = NULL; - if (*p == '%') { - pathopt = ++p; - while (*p && *p != ':') p++; - } - if (*p == ':') - *path = p + 1; - else - *path = NULL; - return stalloc(len); -} - - - -/*** Command hashing code ***/ - - -int -hashcmd(int argc, char **argv) -{ - struct tblentry **pp; - struct tblentry *cmdp; - int c; - int verbose; - struct cmdentry entry; - char *name; - - verbose = 0; - while ((c = nextopt("rv")) != '\0') { - if (c == 'r') { - clearcmdentry(0); - } else if (c == 'v') { - verbose++; - } - } - if (*argptr == NULL) { - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (verbose || cmdp->cmdtype == CMDNORMAL) - printentry(cmdp, verbose); - } - } - return 0; - } - while ((name = *argptr) != NULL) { - if ((cmdp = cmdlookup(name, 0)) != NULL - && (cmdp->cmdtype == CMDNORMAL - || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) - delete_cmd_entry(); - find_command(name, &entry, DO_ERR, pathval()); - if (verbose) { - if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ - cmdp = cmdlookup(name, 0); - printentry(cmdp, verbose); - } - flushall(); - } - argptr++; - } - return 0; -} - - -STATIC void -printentry(struct tblentry *cmdp, int verbose) -{ - int idx; - const char *path; - char *name; - - switch (cmdp->cmdtype) { - case CMDNORMAL: - idx = cmdp->param.index; - path = pathval(); - do { - name = padvance(&path, cmdp->cmdname); - stunalloc(name); - } while (--idx >= 0); - out1str(name); - break; - case CMDSPLBLTIN: - out1fmt("special builtin %s", cmdp->cmdname); - break; - case CMDBUILTIN: - out1fmt("builtin %s", cmdp->cmdname); - break; - case CMDFUNCTION: - out1fmt("function %s", cmdp->cmdname); - if (verbose) { - struct procstat ps; - INTOFF; - commandtext(&ps, cmdp->param.func); - INTON; - out1str("() { "); - out1str(ps.cmd); - out1str("; }"); - } - break; - default: - error("internal error: %s cmdtype %d", cmdp->cmdname, cmdp->cmdtype); - } - if (cmdp->rehash) - out1c('*'); - out1c('\n'); -} - - - -/* - * Resolve a command name. If you change this routine, you may have to - * change the shellexec routine as well. - */ - -void -find_command(char *name, struct cmdentry *entry, int act, const char *path) -{ - struct tblentry *cmdp, loc_cmd; - int idx; - int prev; - char *fullname; - struct stat statb; - int e; - int (*bltin)(int,char **); - - /* If name contains a slash, don't use PATH or hash table */ - if (strchr(name, '/') != NULL) { - if (act & DO_ABS) { - while (stat(name, &statb) < 0) { -#ifdef SYSV - if (errno == EINTR) - continue; -#endif - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - entry->cmdtype = CMDUNKNOWN; - entry->u.index = -1; - return; - } - entry->cmdtype = CMDNORMAL; - entry->u.index = -1; - return; - } - entry->cmdtype = CMDNORMAL; - entry->u.index = 0; - return; - } - - if (path != pathval()) - act |= DO_ALTPATH; - - if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL) - act |= DO_ALTBLTIN; - - /* If name is in the table, check answer will be ok */ - if ((cmdp = cmdlookup(name, 0)) != NULL) { - do { - switch (cmdp->cmdtype) { - case CMDNORMAL: - if (act & DO_ALTPATH) { - cmdp = NULL; - continue; - } - break; - case CMDFUNCTION: - if (act & DO_NOFUNC) { - cmdp = NULL; - continue; - } - break; - case CMDBUILTIN: - if ((act & DO_ALTBLTIN) || builtinloc >= 0) { - cmdp = NULL; - continue; - } - break; - } - /* if not invalidated by cd, we're done */ - if (cmdp->rehash == 0) - goto success; - } while (0); - } - - /* If %builtin not in path, check for builtin next */ - if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc < 0) && - (bltin = find_builtin(name)) != 0) - goto builtin_success; - - /* We have to search path. */ - prev = -1; /* where to start */ - if (cmdp) { /* doing a rehash */ - if (cmdp->cmdtype == CMDBUILTIN) - prev = builtinloc; - else - prev = cmdp->param.index; - } - - e = ENOENT; - idx = -1; -loop: - while ((fullname = padvance(&path, name)) != NULL) { - stunalloc(fullname); - idx++; - if (pathopt) { - if (prefix("builtin", pathopt)) { - if ((bltin = find_builtin(name)) == 0) - goto loop; - goto builtin_success; - } else if (prefix("func", pathopt)) { - /* handled below */ - } else { - /* ignore unimplemented options */ - goto loop; - } - } - /* if rehash, don't redo absolute path names */ - if (fullname[0] == '/' && idx <= prev) { - if (idx < prev) - goto loop; - TRACE(("searchexec \"%s\": no change\n", name)); - goto success; - } - while (stat(fullname, &statb) < 0) { -#ifdef SYSV - if (errno == EINTR) - continue; -#endif - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - goto loop; - } - e = EACCES; /* if we fail, this will be the error */ - if (!S_ISREG(statb.st_mode)) - goto loop; - if (pathopt) { /* this is a %func directory */ - if (act & DO_NOFUNC) - goto loop; - stalloc(strlen(fullname) + 1); - readcmdfile(fullname); - if ((cmdp = cmdlookup(name, 0)) == NULL || - cmdp->cmdtype != CMDFUNCTION) - error("%s not defined in %s", name, fullname); - stunalloc(fullname); - goto success; - } -#ifdef notdef - /* XXX this code stops root executing stuff, and is buggy - if you need a group from the group list. */ - if (statb.st_uid == geteuid()) { - if ((statb.st_mode & 0100) == 0) - goto loop; - } else if (statb.st_gid == getegid()) { - if ((statb.st_mode & 010) == 0) - goto loop; - } else { - if ((statb.st_mode & 01) == 0) - goto loop; - } -#endif - TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); - INTOFF; - if (act & DO_ALTPATH) { - stalloc(strlen(fullname) + 1); - cmdp = &loc_cmd; - } else - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDNORMAL; - cmdp->param.index = idx; - INTON; - goto success; - } - - /* We failed. If there was an entry for this command, delete it */ - if (cmdp) - delete_cmd_entry(); - if (act & DO_ERR) - outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC)); - entry->cmdtype = CMDUNKNOWN; - return; - -builtin_success: - INTOFF; - if (act & DO_ALTPATH) - cmdp = &loc_cmd; - else - cmdp = cmdlookup(name, 1); - if (cmdp->cmdtype == CMDFUNCTION) - /* DO_NOFUNC must have been set */ - cmdp = &loc_cmd; - cmdp->cmdtype = CMDBUILTIN; - cmdp->param.bltin = bltin; - INTON; -success: - cmdp->rehash = 0; - entry->cmdtype = cmdp->cmdtype; - entry->u = cmdp->param; -} - - - -/* - * Search the table of builtin commands. - */ - -int -(*find_builtin(name))(int, char **) - char *name; -{ - const struct builtincmd *bp; - - for (bp = builtincmd ; bp->name ; bp++) { - if (*bp->name == *name && equal(bp->name, name)) - return bp->builtin; - } - return 0; -} - -int -(*find_splbltin(name))(int, char **) - char *name; -{ - const struct builtincmd *bp; - - for (bp = splbltincmd ; bp->name ; bp++) { - if (*bp->name == *name && equal(bp->name, name)) - return bp->builtin; - } - return 0; -} - -/* - * At shell startup put special builtins into hash table. - * ensures they are executed first (see posix). - * We stop functions being added with the same name - * (as they are impossible to call) - */ - -void -hash_special_builtins(void) -{ - const struct builtincmd *bp; - struct tblentry *cmdp; - - for (bp = splbltincmd ; bp->name ; bp++) { - cmdp = cmdlookup(bp->name, 1); - cmdp->cmdtype = CMDSPLBLTIN; - cmdp->param.bltin = bp->builtin; - } -} - - - -/* - * Called when a cd is done. Marks all commands so the next time they - * are executed they will be rehashed. - */ - -void -hashcd(void) -{ - struct tblentry **pp; - struct tblentry *cmdp; - - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype == CMDNORMAL - || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) - cmdp->rehash = 1; - } - } -} - - - -/* - * Fix command hash table when PATH changed. - * Called before PATH is changed. The argument is the new value of PATH; - * pathval() still returns the old value at this point. - * Called with interrupts off. - */ - -void -changepath(const char *newval) -{ - const char *old, *new; - int idx; - int firstchange; - int bltin; - - old = pathval(); - new = newval; - firstchange = 9999; /* assume no change */ - idx = 0; - bltin = -1; - for (;;) { - if (*old != *new) { - firstchange = idx; - if ((*old == '\0' && *new == ':') - || (*old == ':' && *new == '\0')) - firstchange++; - old = new; /* ignore subsequent differences */ - } - if (*new == '\0') - break; - if (*new == '%' && bltin < 0 && prefix("builtin", new + 1)) - bltin = idx; - if (*new == ':') { - idx++; - } - new++, old++; - } - if (builtinloc < 0 && bltin >= 0) - builtinloc = bltin; /* zap builtins */ - if (builtinloc >= 0 && bltin < 0) - firstchange = 0; - clearcmdentry(firstchange); - builtinloc = bltin; -} - - -/* - * Clear out command entries. The argument specifies the first entry in - * PATH which has changed. - */ - -STATIC void -clearcmdentry(int firstchange) -{ - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if ((cmdp->cmdtype == CMDNORMAL && - cmdp->param.index >= firstchange) - || (cmdp->cmdtype == CMDBUILTIN && - builtinloc >= firstchange)) { - *pp = cmdp->next; - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - -/* - * Delete all functions. - */ - -#ifdef mkinit -MKINIT void deletefuncs(void); -MKINIT void hash_special_builtins(void); - -INIT { - hash_special_builtins(); -} - -SHELLPROC { - deletefuncs(); -} -#endif - -void -deletefuncs(void) -{ - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if (cmdp->cmdtype == CMDFUNCTION) { - *pp = cmdp->next; - freefunc(cmdp->param.func); - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - - -/* - * Locate a command in the command hash table. If "add" is nonzero, - * add the command to the table if it is not already present. The - * variable "lastcmdentry" is set to point to the address of the link - * pointing to the entry, so that delete_cmd_entry can delete the - * entry. - */ - -struct tblentry **lastcmdentry; - - -STATIC struct tblentry * -cmdlookup(const char *name, int add) -{ - int hashval; - const char *p; - struct tblentry *cmdp; - struct tblentry **pp; - - p = name; - hashval = *p << 4; - while (*p) - hashval += *p++; - hashval &= 0x7FFF; - pp = &cmdtable[hashval % CMDTABLESIZE]; - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (equal(cmdp->cmdname, name)) - break; - pp = &cmdp->next; - } - if (add && cmdp == NULL) { - INTOFF; - cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB - + strlen(name) + 1); - cmdp->next = NULL; - cmdp->cmdtype = CMDUNKNOWN; - cmdp->rehash = 0; - strcpy(cmdp->cmdname, name); - INTON; - } - lastcmdentry = pp; - return cmdp; -} - -/* - * Delete the command entry returned on the last lookup. - */ - -STATIC void -delete_cmd_entry(void) -{ - struct tblentry *cmdp; - - INTOFF; - cmdp = *lastcmdentry; - *lastcmdentry = cmdp->next; - ckfree(cmdp); - INTON; -} - - - -#ifdef notdef -void -getcmdentry(char *name, struct cmdentry *entry) -{ - struct tblentry *cmdp = cmdlookup(name, 0); - - if (cmdp) { - entry->u = cmdp->param; - entry->cmdtype = cmdp->cmdtype; - } else { - entry->cmdtype = CMDUNKNOWN; - entry->u.index = 0; - } -} -#endif - - -/* - * Add a new command entry, replacing any existing command entry for - * the same name - except special builtins. - */ - -STATIC void -addcmdentry(char *name, struct cmdentry *entry) -{ - struct tblentry *cmdp; - - INTOFF; - cmdp = cmdlookup(name, 1); - if (cmdp->cmdtype != CMDSPLBLTIN) { - if (cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - } - cmdp->cmdtype = entry->cmdtype; - cmdp->param = entry->u; - } - INTON; -} - - -/* - * Define a shell function. - */ - -void -defun(char *name, union node *func) -{ - struct cmdentry entry; - - INTOFF; - entry.cmdtype = CMDFUNCTION; - entry.u.func = copyfunc(func); - addcmdentry(name, &entry); - INTON; -} - - -/* - * Delete a function if it exists. - */ - -int -unsetfunc(char *name) -{ - struct tblentry *cmdp; - - if ((cmdp = cmdlookup(name, 0)) != NULL && - cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - delete_cmd_entry(); - return (0); - } - return (1); -} - -/* - * Locate and print what a word is... - * also used for 'command -[v|V]' - */ - -int -typecmd(int argc, char **argv) -{ - struct cmdentry entry; - struct tblentry *cmdp; - char * const *pp; - struct alias *ap; - int err = 0; - char *arg; - int c; - int V_flag = 0; - int v_flag = 0; - int p_flag = 0; - - while ((c = nextopt("vVp")) != 0) { - switch (c) { - case 'v': v_flag = 1; break; - case 'V': V_flag = 1; break; - case 'p': p_flag = 1; break; - } - } - - if (p_flag && (v_flag || V_flag)) - error("cannot specify -p with -v or -V"); - - while ((arg = *argptr++)) { - if (!v_flag) - out1str(arg); - /* First look at the keywords */ - for (pp = parsekwd; *pp; pp++) - if (**pp == *arg && equal(*pp, arg)) - break; - - if (*pp) { - if (v_flag) - err = 1; - else - out1str(" is a shell keyword\n"); - continue; - } - - /* Then look at the aliases */ - if ((ap = lookupalias(arg, 1)) != NULL) { - if (!v_flag) - out1fmt(" is an alias for \n"); - out1fmt("%s\n", ap->val); - continue; - } - - /* Then check if it is a tracked alias */ - if ((cmdp = cmdlookup(arg, 0)) != NULL) { - entry.cmdtype = cmdp->cmdtype; - entry.u = cmdp->param; - } else { - /* Finally use brute force */ - find_command(arg, &entry, DO_ABS, pathval()); - } - - switch (entry.cmdtype) { - case CMDNORMAL: { - if (strchr(arg, '/') == NULL) { - const char *path = pathval(); - char *name; - int j = entry.u.index; - do { - name = padvance(&path, arg); - stunalloc(name); - } while (--j >= 0); - if (!v_flag) - out1fmt(" is%s ", - cmdp ? " a tracked alias for" : ""); - out1fmt("%s\n", name); - } else { - if (access(arg, X_OK) == 0) { - if (!v_flag) - out1fmt(" is "); - out1fmt("%s\n", arg); - } else { - if (!v_flag) - out1fmt(": %s\n", - strerror(errno)); - else - err = 126; - } - } - break; - } - case CMDFUNCTION: - if (!v_flag) - out1str(" is a shell function\n"); - else - out1fmt("%s\n", arg); - break; - - case CMDBUILTIN: - if (!v_flag) - out1str(" is a shell builtin\n"); - else - out1fmt("%s\n", arg); - break; - - case CMDSPLBLTIN: - if (!v_flag) - out1str(" is a special shell builtin\n"); - else - out1fmt("%s\n", arg); - break; - - default: - if (!v_flag) - out1str(": not found\n"); - err = 127; - break; - } - } - return err; -} diff --git a/sh/exec.h b/sh/exec.h deleted file mode 100644 index 26fd09c..0000000 --- a/sh/exec.h +++ /dev/null @@ -1,79 +0,0 @@ -/* $NetBSD: exec.h,v 1.21 2003/08/07 09:05:31 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)exec.h 8.3 (Berkeley) 6/8/95 - */ - -/* values of cmdtype */ -#define CMDUNKNOWN -1 /* no entry in table for command */ -#define CMDNORMAL 0 /* command is an executable program */ -#define CMDFUNCTION 1 /* command is a shell function */ -#define CMDBUILTIN 2 /* command is a shell builtin */ -#define CMDSPLBLTIN 3 /* command is a special shell builtin */ - - -struct cmdentry { - int cmdtype; - union param { - int index; - int (*bltin)(int, char**); - union node *func; - } u; -}; - - -/* action to find_command() */ -#define DO_ERR 0x01 /* prints errors */ -#define DO_ABS 0x02 /* checks absolute paths */ -#define DO_NOFUNC 0x04 /* don't return shell functions, for command */ -#define DO_ALTPATH 0x08 /* using alternate path */ -#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ - -extern const char *pathopt; /* set by padvance */ - -void shellexec(char **, char **, const char *, int, int) - __attribute__((__noreturn__)); -char *padvance(const char **, const char *); -int hashcmd(int, char **); -void find_command(char *, struct cmdentry *, int, const char *); -int (*find_builtin(char *))(int, char **); -int (*find_splbltin(char *))(int, char **); -void hashcd(void); -void changepath(const char *); -void deletefuncs(void); -void getcmdentry(char *, struct cmdentry *); -void addcmdentry(char *, struct cmdentry *); -void defun(char *, union node *); -int unsetfunc(char *); -int typecmd(int, char **); -void hash_special_builtins(void); diff --git a/sh/expand.c b/sh/expand.c deleted file mode 100644 index d3462fc..0000000 --- a/sh/expand.c +++ /dev/null @@ -1,1559 +0,0 @@ -/* $NetBSD: expand.c,v 1.68.2.2 2005/04/07 11:37:39 tron Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; -#else -__RCSID("$NetBSD: expand.c,v 1.68.2.2 2005/04/07 11:37:39 tron Exp $"); -#endif -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <errno.h> -#include <dirent.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> - -/* - * Routines to expand arguments to commands. We have to deal with - * backquotes, shell variables, and file metacharacters. - */ - -#include "shell.h" -#include "main.h" -#include "nodes.h" -#include "eval.h" -#include "expand.h" -#include "syntax.h" -#include "parser.h" -#include "jobs.h" -#include "options.h" -#include "var.h" -#include "input.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" -#include "mystring.h" -#include "show.h" - -/* - * 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 */ -}; - - -char *expdest; /* output of current string */ -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 */ - -STATIC void argstr(char *, int); -STATIC char *exptilde(char *, int); -STATIC void expbackq(union node *, int, int); -STATIC int subevalvar(char *, char *, int, int, int, int); -STATIC char *evalvar(char *, int); -STATIC int varisset(char *, int); -STATIC void varvalue(char *, int, int, int); -STATIC void recordregion(int, int, int); -STATIC void removerecordregions(int); -STATIC void ifsbreakup(char *, struct arglist *); -STATIC void ifsfree(void); -STATIC void expandmeta(struct strlist *, int); -STATIC void expmeta(char *, char *); -STATIC void addfname(char *); -STATIC struct strlist *expsort(struct strlist *); -STATIC struct strlist *msort(struct strlist *, int); -STATIC int pmatch(char *, char *, int); -STATIC char *cvtnum(int, char *); - -/* - * Expand shell variables and backquotes inside a here document. - */ - -void -expandhere(union node *arg, int fd) -{ - herefd = fd; - expandarg(arg, (struct arglist *)NULL, 0); - xwrite(fd, stackblock(), expdest - stackblock()); -} - - -/* - * Perform variable substitution and command substitution on an argument, - * placing the resulting list of arguments in arglist. If EXP_FULL is true, - * perform splitting and file name expansion. When arglist is NULL, perform - * here document expansion. - */ - -void -expandarg(union node *arg, struct arglist *arglist, int flag) -{ - struct strlist *sp; - char *p; - - argbackq = arg->narg.backquote; - STARTSTACKSTR(expdest); - ifsfirst.next = NULL; - ifslastp = NULL; - argstr(arg->narg.text, flag); - if (arglist == NULL) { - return; /* here document expanded */ - } - STPUTC('\0', expdest); - p = grabstackstr(expdest); - exparg.lastp = &exparg.list; - /* - * TODO - EXP_REDIR - */ - if (flag & EXP_FULL) { - ifsbreakup(p, &exparg); - *exparg.lastp = NULL; - exparg.lastp = &exparg.list; - expandmeta(exparg.list, flag); - } else { - if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ - rmescapes(p); - sp = (struct strlist *)stalloc(sizeof (struct strlist)); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; - } - ifsfree(); - *exparg.lastp = NULL; - if (exparg.list) { - *arglist->lastp = exparg.list; - arglist->lastp = exparg.lastp; - } -} - - - -/* - * Perform variable and command substitution. - * If EXP_FULL is set, output CTLESC characters to allow for further processing. - * Otherwise treat $@ like $* since no splitting will be performed. - */ - -STATIC void -argstr(char *p, int flag) -{ - char c; - int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ - int firsteq = 1; - const char *ifs = 0; - int ifs_split = EXP_IFS_SPLIT; - - if (flag & EXP_IFS_SPLIT) - ifs = ifsset() ? ifsval() : " \t\n"; - - if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) - p = exptilde(p, flag); - for (;;) { - switch (c = *p++) { - case '\0': - case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */ - return; - case CTLQUOTEMARK: - /* "$@" syntax adherence hack */ - if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') - break; - if ((flag & EXP_FULL) != 0) - STPUTC(c, expdest); - ifs_split = 0; - break; - case CTLQUOTEEND: - ifs_split = EXP_IFS_SPLIT; - break; - case CTLESC: - if (quotes) - STPUTC(c, expdest); - c = *p++; - STPUTC(c, expdest); - break; - case CTLVAR: - p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split)); - break; - case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c & CTLQUOTE, flag); - argbackq = argbackq->next; - break; - case CTLENDARI: - expari(flag); - break; - case ':': - case '=': - /* - * sort of a hack - expand tildes in variable - * assignments (after the first '=' and after ':'s). - */ - STPUTC(c, expdest); - if (flag & EXP_VARTILDE && *p == '~') { - if (c == '=') { - if (firsteq) - firsteq = 0; - else - break; - } - p = exptilde(p, flag); - } - break; - default: - STPUTC(c, expdest); - if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) { - /* We need to get the output split here... */ - recordregion(expdest - stackblock() - 1, - expdest - stackblock(), 0); - } - break; - } - } -} - -STATIC char * -exptilde(char *p, int flag) -{ - char c, *startp = p; - const char *home; - int quotes = flag & (EXP_FULL | EXP_CASE); - - while ((c = *p) != '\0') { - switch(c) { - case CTLESC: - return (startp); - case CTLQUOTEMARK: - return (startp); - case ':': - if (flag & EXP_VARTILDE) - goto done; - break; - case '/': - goto done; - } - p++; - } -done: - *p = '\0'; - if (*(startp+1) == '\0') { - if ((home = lookupvar("HOME")) == NULL) - goto lose; - } else - goto lose; - if (*home == '\0') - goto lose; - *p = c; - while ((c = *home++) != '\0') { - if (quotes && SQSYNTAX[(int)c] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(c, expdest); - } - return (p); -lose: - *p = c; - return (startp); -} - - -STATIC void -removerecordregions(int endoff) -{ - if (ifslastp == NULL) - return; - - if (ifsfirst.endoff > endoff) { - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - if (ifsfirst.begoff > endoff) - ifslastp = NULL; - else { - ifslastp = &ifsfirst; - ifsfirst.endoff = endoff; - } - return; - } - - ifslastp = &ifsfirst; - while (ifslastp->next && ifslastp->next->begoff < endoff) - ifslastp=ifslastp->next; - while (ifslastp->next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifslastp->next->next; - ckfree(ifslastp->next); - ifslastp->next = ifsp; - INTON; - } - if (ifslastp->endoff > endoff) - ifslastp->endoff = endoff; -} - - -/* - * Expand arithmetic expression. Backup to start of expression, - * evaluate, place result in (backed up) result, adjust string position. - */ -void -expari(int flag) -{ - char *p, *start; - int result; - int begoff; - int quotes = flag & (EXP_FULL | EXP_CASE); - int quoted; - - /* ifsfree(); */ - - /* - * This routine is slightly over-complicated for - * efficiency. First we make sure there is - * enough space for the result, which may be bigger - * than the expression if we add exponentation. Next we - * scan backwards looking for the start of arithmetic. If the - * next previous character is a CTLESC character, then we - * have to rescan starting from the beginning since CTLESC - * characters have to be processed left to right. - */ -#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10 -#error "integers with more than 10 digits are not supported" -#endif - CHECKSTRSPACE(12 - 2, expdest); - USTPUTC('\0', expdest); - start = stackblock(); - p = expdest - 1; - while (*p != CTLARI && p >= start) - --p; - if (*p != CTLARI) - error("missing CTLARI (shouldn't happen)"); - if (p > start && *(p-1) == CTLESC) - for (p = start; *p != CTLARI; p++) - if (*p == CTLESC) - p++; - - if (p[1] == '"') - quoted=1; - else - quoted=0; - begoff = p - start; - removerecordregions(begoff); - if (quotes) - rmescapes(p+2); - result = arith(p+2); - fmtstr(p, 12, "%d", result); - - while (*p++) - ; - - if (quoted == 0) - recordregion(begoff, p - 1 - start, 0); - result = expdest - p + 1; - STADJUST(-result, expdest); -} - - -/* - * Expand stuff in backwards quotes. - */ - -STATIC void -expbackq(union node *cmd, int quoted, int flag) -{ - struct backcmd in; - int i; - char buf[128]; - char *p; - char *dest = expdest; - struct ifsregion saveifs, *savelastp; - struct nodelist *saveargbackq; - char lastc; - int startloc = dest - stackblock(); - char const *syntax = quoted? DQSYNTAX : BASESYNTAX; - int saveherefd; - int quotes = flag & (EXP_FULL | EXP_CASE); - - INTOFF; - saveifs = ifsfirst; - savelastp = ifslastp; - saveargbackq = argbackq; - saveherefd = herefd; - herefd = -1; - p = grabstackstr(dest); - evalbackcmd(cmd, &in); - ungrabstackstr(p, dest); - ifsfirst = saveifs; - ifslastp = savelastp; - argbackq = saveargbackq; - herefd = saveherefd; - - p = in.buf; - lastc = '\0'; - for (;;) { - if (--in.nleft < 0) { - if (in.fd < 0) - break; - while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); - TRACE(("expbackq: read returns %d\n", i)); - if (i <= 0) - break; - p = buf; - in.nleft = i - 1; - } - lastc = *p++; - if (lastc != '\0') { - if (quotes && syntax[(int)lastc] == CCTL) - STPUTC(CTLESC, dest); - STPUTC(lastc, dest); - } - } - - /* Eat all trailing newlines */ - p = stackblock() + startloc; - while (dest > p && dest[-1] == '\n') - STUNPUTC(dest); - - if (in.fd >= 0) - close(in.fd); - if (in.buf) - ckfree(in.buf); - if (in.jp) - back_exitstatus = waitforjob(in.jp); - if (quoted == 0) - recordregion(startloc, dest - stackblock(), 0); - TRACE(("evalbackq: size=%d: \"%.*s\"\n", - (dest - stackblock()) - startloc, - (dest - stackblock()) - startloc, - stackblock() + startloc)); - expdest = dest; - INTON; -} - - - -STATIC int -subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags) -{ - char *startp; - char *loc = NULL; - char *q; - int c = 0; - int saveherefd = herefd; - struct nodelist *saveargbackq = argbackq; - int amount; - - herefd = -1; - argstr(p, 0); - STACKSTRNUL(expdest); - herefd = saveherefd; - argbackq = saveargbackq; - startp = stackblock() + startloc; - if (str == NULL) - str = stackblock() + strloc; - - switch (subtype) { - case VSASSIGN: - setvar(str, startp, 0); - amount = startp - expdest; - STADJUST(amount, expdest); - varflags &= ~VSNUL; - if (c != 0) - *loc = c; - return 1; - - case VSQUESTION: - if (*p != CTLENDVAR) { - outfmt(&errout, "%s\n", startp); - error((char *)NULL); - } - error("%.*s: parameter %snot set", p - str - 1, - str, (varflags & VSNUL) ? "null or " - : nullstr); - /* NOTREACHED */ - - case VSTRIMLEFT: - for (loc = startp; loc < str; loc++) { - c = *loc; - *loc = '\0'; - if (patmatch(str, startp, varflags & VSQUOTE)) - goto recordleft; - *loc = c; - if ((varflags & VSQUOTE) && *loc == CTLESC) - loc++; - } - return 0; - - case VSTRIMLEFTMAX: - for (loc = str - 1; loc >= startp;) { - c = *loc; - *loc = '\0'; - if (patmatch(str, startp, varflags & VSQUOTE)) - goto recordleft; - *loc = c; - loc--; - if ((varflags & VSQUOTE) && loc > startp && - *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } - } - return 0; - - case VSTRIMRIGHT: - for (loc = str - 1; loc >= startp;) { - if (patmatch(str, loc, varflags & VSQUOTE)) - goto recordright; - loc--; - if ((varflags & VSQUOTE) && loc > startp && - *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } - } - return 0; - - case VSTRIMRIGHTMAX: - for (loc = startp; loc < str - 1; loc++) { - if (patmatch(str, loc, varflags & VSQUOTE)) - goto recordright; - if ((varflags & VSQUOTE) && *loc == CTLESC) - loc++; - } - return 0; - - default: - abort(); - } - -recordleft: - *loc = c; - amount = ((str - 1) - (loc - startp)) - expdest; - STADJUST(amount, expdest); - while (loc != str - 1) - *startp++ = *loc++; - return 1; - -recordright: - amount = loc - expdest; - STADJUST(amount, expdest); - STPUTC('\0', expdest); - STADJUST(-1, expdest); - return 1; -} - - -/* - * Expand a variable, and return a pointer to the next character in the - * input string. - */ - -STATIC char * -evalvar(char *p, int flag) -{ - int subtype; - int varflags; - char *var; - char *val; - int patloc; - int c; - int set; - int special; - int startloc; - int varlen; - int apply_ifs; - int quotes = flag & (EXP_FULL | EXP_CASE); - - varflags = (unsigned char)*p++; - subtype = varflags & VSTYPE; - var = p; - special = !is_name(*p); - p = strchr(p, '=') + 1; - -again: /* jump here after setting a variable with ${var=text} */ - if (special) { - set = varisset(var, varflags & VSNUL); - val = NULL; - } else { - val = lookupvar(var); - if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { - val = NULL; - set = 0; - } else - set = 1; - } - - varlen = 0; - startloc = expdest - stackblock(); - - if (!set && uflag) { - switch (subtype) { - case VSNORMAL: - case VSTRIMLEFT: - case VSTRIMLEFTMAX: - case VSTRIMRIGHT: - case VSTRIMRIGHTMAX: - case VSLENGTH: - error("%.*s: parameter not set", p - var - 1, var); - /* NOTREACHED */ - } - } - - if (set && subtype != VSPLUS) { - /* insert the value of the variable */ - if (special) { - varvalue(var, varflags & VSQUOTE, subtype, flag); - if (subtype == VSLENGTH) { - varlen = expdest - stackblock() - startloc; - STADJUST(-varlen, expdest); - } - } else { - char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX - : BASESYNTAX; - - if (subtype == VSLENGTH) { - for (;*val; val++) - varlen++; - } else { - while (*val) { - if (quotes && syntax[(int)*val] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*val++, expdest); - } - - } - } - } - - - apply_ifs = ((varflags & VSQUOTE) == 0 || - (*var == '@' && shellparam.nparam != 1)); - - switch (subtype) { - case VSLENGTH: - expdest = cvtnum(varlen, expdest); - break; - - case VSNORMAL: - break; - - case VSPLUS: - set = !set; - /* FALLTHROUGH */ - case VSMINUS: - if (!set) { - argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0)); - /* - * ${x-a b c} doesn't get split, but removing the - * 'apply_ifs = 0' apparantly breaks ${1+"$@"}.. - * ${x-'a b' c} should generate 2 args. - */ - /* We should have marked stuff already */ - apply_ifs = 0; - } - break; - - case VSTRIMLEFT: - case VSTRIMLEFTMAX: - case VSTRIMRIGHT: - case VSTRIMRIGHTMAX: - if (!set) - break; - /* - * Terminate the string and start recording the pattern - * right after it - */ - STPUTC('\0', expdest); - patloc = expdest - stackblock(); - if (subevalvar(p, NULL, patloc, subtype, - startloc, varflags) == 0) { - int amount = (expdest - stackblock() - patloc) + 1; - STADJUST(-amount, expdest); - } - /* Remove any recorded regions beyond start of variable */ - removerecordregions(startloc); - apply_ifs = 1; - break; - - case VSASSIGN: - case VSQUESTION: - if (set) - break; - if (subevalvar(p, var, 0, subtype, startloc, varflags)) { - varflags &= ~VSNUL; - /* - * Remove any recorded regions beyond - * start of variable - */ - removerecordregions(startloc); - goto again; - } - apply_ifs = 0; - break; - - default: - abort(); - } - - if (apply_ifs) - recordregion(startloc, expdest - stackblock(), - varflags & VSQUOTE); - - if (subtype != VSNORMAL) { /* skip to end of alternative */ - int nesting = 1; - for (;;) { - if ((c = *p++) == CTLESC) - p++; - else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { - if (set) - argbackq = argbackq->next; - } else if (c == CTLVAR) { - if ((*p++ & VSTYPE) != VSNORMAL) - nesting++; - } else if (c == CTLENDVAR) { - if (--nesting == 0) - break; - } - } - } - return p; -} - - - -/* - * Test whether a specialized variable is set. - */ - -STATIC int -varisset(char *name, int nulok) -{ - if (*name == '!') - return backgndpid != -1; - else if (*name == '@' || *name == '*') { - if (*shellparam.p == NULL) - return 0; - - if (nulok) { - char **av; - - for (av = shellparam.p; *av; av++) - if (**av != '\0') - return 1; - return 0; - } - } else if (is_digit(*name)) { - char *ap; - int num = atoi(name); - - if (num > shellparam.nparam) - return 0; - - if (num == 0) - ap = arg0; - else - ap = shellparam.p[num - 1]; - - if (nulok && (ap == NULL || *ap == '\0')) - return 0; - } - return 1; -} - - - -/* - * Add the value of a specialized variable to the stack string. - */ - -STATIC void -varvalue(char *name, int quoted, int subtype, int flag) -{ - int num; - char *p; - int i; - char sep; - char **ap; - char const *syntax; - -#define STRTODEST(p) \ - do {\ - if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \ - syntax = quoted? DQSYNTAX : BASESYNTAX; \ - while (*p) { \ - if (syntax[(int)*p] == CCTL) \ - STPUTC(CTLESC, expdest); \ - STPUTC(*p++, expdest); \ - } \ - } else \ - while (*p) \ - STPUTC(*p++, expdest); \ - } while (0) - - - switch (*name) { - case '$': - num = rootpid; - goto numvar; - case '?': - num = exitstatus; - goto numvar; - case '#': - num = shellparam.nparam; - goto numvar; - case '!': - num = backgndpid; -numvar: - expdest = cvtnum(num, expdest); - break; - case '-': - for (i = 0; optlist[i].name; i++) { - if (optlist[i].val) - STPUTC(optlist[i].letter, expdest); - } - break; - case '@': - if (flag & EXP_FULL && quoted) { - for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - STRTODEST(p); - if (*ap) - STPUTC('\0', expdest); - } - break; - } - /* fall through */ - case '*': - if (ifsset() != 0) - sep = ifsval()[0]; - else - sep = ' '; - for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - STRTODEST(p); - if (*ap && sep) - STPUTC(sep, expdest); - } - break; - case '0': - p = arg0; - STRTODEST(p); - break; - default: - if (is_digit(*name)) { - num = atoi(name); - if (num > 0 && num <= shellparam.nparam) { - p = shellparam.p[num - 1]; - STRTODEST(p); - } - } - break; - } -} - - - -/* - * Record the fact that we have to scan this region of the - * string for IFS characters. - */ - -STATIC void -recordregion(int start, int end, int inquotes) -{ - struct ifsregion *ifsp; - - if (ifslastp == NULL) { - ifsp = &ifsfirst; - } else { - if (ifslastp->endoff == start - && ifslastp->inquotes == inquotes) { - /* extend previous area */ - ifslastp->endoff = end; - return; - } - ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); - ifslastp->next = ifsp; - } - ifslastp = ifsp; - ifslastp->next = NULL; - ifslastp->begoff = start; - ifslastp->endoff = end; - ifslastp->inquotes = inquotes; -} - - - -/* - * Break the argument string into pieces based upon IFS and add the - * strings to the argument list. The regions of the string to be - * searched for IFS characters have been stored by recordregion. - */ -STATIC void -ifsbreakup(char *string, struct arglist *arglist) -{ - struct ifsregion *ifsp; - struct strlist *sp; - char *start; - char *p; - char *q; - const char *ifs; - const char *ifsspc; - int inquotes; - - start = string; - ifsspc = NULL; - inquotes = 0; - - if (ifslastp == NULL) { - /* Return entire argument, IFS doesn't apply to any of it */ - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; - return; - } - - ifs = ifsset() ? ifsval() : " \t\n"; - - for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) { - p = string + ifsp->begoff; - inquotes = ifsp->inquotes; - ifsspc = NULL; - while (p < string + ifsp->endoff) { - q = p; - if (*p == CTLESC) - p++; - if (inquotes) { - /* Only NULs (probably from "$@") end args */ - if (*p != 0) { - p++; - continue; - } - } else { - if (!strchr(ifs, *p)) { - p++; - continue; - } - ifsspc = strchr(" \t\n", *p); - - /* Ignore IFS whitespace at start */ - if (q == start && ifsspc != NULL) { - p++; - start = p; - continue; - } - } - - /* Save this argument... */ - *q = '\0'; - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; - p++; - - if (ifsspc != NULL) { - /* Ignore further trailing IFS whitespace */ - for (; p < string + ifsp->endoff; p++) { - q = p; - if (*p == CTLESC) - p++; - if (strchr(ifs, *p) == NULL) { - p = q; - break; - } - if (strchr(" \t\n", *p) == NULL) { - p++; - break; - } - } - } - start = p; - } - } - - /* - * Save anything left as an argument. - * Traditionally we have treated 'IFS=':'; set -- x$IFS' as - * generating 2 arguments, the second of which is empty. - * Some recent clarification of the Posix spec say that it - * should only generate one.... - */ - if (*start /* || (!ifsspc && start > string) */) { - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; - } -} - -STATIC void -ifsfree(void) -{ - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - ifslastp = NULL; - ifsfirst.next = NULL; -} - - - -/* - * Expand shell metacharacters. At this point, the only control characters - * should be escapes. The results are stored in the list exparg. - */ - -char *expdir; - - -STATIC void -expandmeta(struct strlist *str, int flag) -{ - char *p; - struct strlist **savelastp; - struct strlist *sp; - char c; - /* TODO - EXP_REDIR */ - - while (str) { - if (fflag) - goto nometa; - p = str->text; - for (;;) { /* fast check for meta chars */ - if ((c = *p++) == '\0') - goto nometa; - if (c == '*' || c == '?' || c == '[' || c == '!') - break; - } - savelastp = exparg.lastp; - INTOFF; - if (expdir == NULL) { - int i = strlen(str->text); - expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ - } - - expmeta(expdir, str->text); - ckfree(expdir); - expdir = NULL; - INTON; - if (exparg.lastp == savelastp) { - /* - * no matches - */ -nometa: - *exparg.lastp = str; - rmescapes(str->text); - exparg.lastp = &str->next; - } else { - *exparg.lastp = NULL; - *savelastp = sp = expsort(*savelastp); - while (sp->next != NULL) - sp = sp->next; - exparg.lastp = &sp->next; - } - str = str->next; - } -} - - -/* - * Do metacharacter (i.e. *, ?, [...]) expansion. - */ - -STATIC void -expmeta(char *enddir, char *name) -{ - char *p; - const char *cp; - char *q; - char *start; - char *endname; - int metaflag; - struct stat statb; - DIR *dirp; - struct dirent *dp; - int atend; - int matchdot; - - metaflag = 0; - start = name; - for (p = name ; ; p++) { - if (*p == '*' || *p == '?') - metaflag = 1; - else if (*p == '[') { - q = p + 1; - if (*q == '!') - q++; - for (;;) { - while (*q == CTLQUOTEMARK) - q++; - if (*q == CTLESC) - q++; - if (*q == '/' || *q == '\0') - break; - if (*++q == ']') { - metaflag = 1; - break; - } - } - } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { - metaflag = 1; - } else if (*p == '\0') - break; - else if (*p == CTLQUOTEMARK) - continue; - else if (*p == CTLESC) - p++; - if (*p == '/') { - if (metaflag) - break; - start = p + 1; - } - } - if (metaflag == 0) { /* we've reached the end of the file name */ - if (enddir != expdir) - metaflag++; - for (p = name ; ; p++) { - if (*p == CTLQUOTEMARK) - continue; - if (*p == CTLESC) - p++; - *enddir++ = *p; - if (*p == '\0') - break; - } - if (metaflag == 0 || lstat(expdir, &statb) >= 0) - addfname(expdir); - return; - } - endname = p; - if (start != name) { - p = name; - while (p < start) { - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - *enddir++ = *p++; - } - } - if (enddir == expdir) { - cp = "."; - } else if (enddir == expdir + 1 && *expdir == '/') { - cp = "/"; - } else { - cp = expdir; - enddir[-1] = '\0'; - } - if ((dirp = opendir(cp)) == NULL) - return; - if (enddir != expdir) - enddir[-1] = '/'; - if (*endname == 0) { - atend = 1; - } else { - atend = 0; - *endname++ = '\0'; - } - matchdot = 0; - p = start; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - if (*p == '.') - matchdot++; - while (! int_pending() && (dp = readdir(dirp)) != NULL) { - if (dp->d_name[0] == '.' && ! matchdot) - continue; - if (patmatch(start, dp->d_name, 0)) { - if (atend) { - scopy(dp->d_name, enddir); - addfname(expdir); - } else { - for (p = enddir, cp = dp->d_name; - (*p++ = *cp++) != '\0';) - continue; - p[-1] = '/'; - expmeta(p, endname); - } - } - } - closedir(dirp); - if (! atend) - endname[-1] = '/'; -} - - -/* - * Add a file name to the list. - */ - -STATIC void -addfname(char *name) -{ - char *p; - struct strlist *sp; - - p = stalloc(strlen(name) + 1); - scopy(name, p); - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; -} - - -/* - * Sort the results of file name expansion. It calculates the number of - * strings to sort and then calls msort (short for merge sort) to do the - * work. - */ - -STATIC struct strlist * -expsort(struct strlist *str) -{ - int len; - struct strlist *sp; - - len = 0; - for (sp = str ; sp ; sp = sp->next) - len++; - return msort(str, len); -} - - -STATIC struct strlist * -msort(struct strlist *list, int len) -{ - struct strlist *p, *q = NULL; - struct strlist **lpp; - int half; - int n; - - if (len <= 1) - return list; - half = len >> 1; - p = list; - for (n = half ; --n >= 0 ; ) { - q = p; - p = p->next; - } - q->next = NULL; /* terminate first half of list */ - q = msort(list, half); /* sort first half of list */ - p = msort(p, len - half); /* sort second half */ - lpp = &list; - for (;;) { - if (strcmp(p->text, q->text) < 0) { - *lpp = p; - lpp = &p->next; - if ((p = *lpp) == NULL) { - *lpp = q; - break; - } - } else { - *lpp = q; - lpp = &q->next; - if ((q = *lpp) == NULL) { - *lpp = p; - break; - } - } - } - return list; -} - - - -/* - * Returns true if the pattern matches the string. - */ - -int -patmatch(char *pattern, char *string, int squoted) -{ -#ifdef notdef - if (pattern[0] == '!' && pattern[1] == '!') - return 1 - pmatch(pattern + 2, string); - else -#endif - return pmatch(pattern, string, squoted); -} - - -STATIC int -pmatch(char *pattern, char *string, int squoted) -{ - char *p, *q; - char c; - - p = pattern; - q = string; - for (;;) { - switch (c = *p++) { - case '\0': - goto breakloop; - case CTLESC: - if (squoted && *q == CTLESC) - q++; - if (*q++ != *p++) - return 0; - break; - case CTLQUOTEMARK: - continue; - case '?': - if (squoted && *q == CTLESC) - q++; - if (*q++ == '\0') - return 0; - break; - case '*': - c = *p; - while (c == CTLQUOTEMARK || c == '*') - c = *++p; - if (c != CTLESC && c != CTLQUOTEMARK && - c != '?' && c != '*' && c != '[') { - while (*q != c) { - if (squoted && *q == CTLESC && - q[1] == c) - break; - if (*q == '\0') - return 0; - if (squoted && *q == CTLESC) - q++; - q++; - } - } - do { - if (pmatch(p, q, squoted)) - return 1; - if (squoted && *q == CTLESC) - q++; - } while (*q++ != '\0'); - return 0; - case '[': { - char *endp; - int invert, found; - char chr; - - endp = p; - if (*endp == '!') - endp++; - for (;;) { - while (*endp == CTLQUOTEMARK) - endp++; - if (*endp == '\0') - goto dft; /* no matching ] */ - if (*endp == CTLESC) - endp++; - if (*++endp == ']') - break; - } - invert = 0; - if (*p == '!') { - invert++; - p++; - } - found = 0; - chr = *q++; - if (squoted && chr == CTLESC) - chr = *q++; - if (chr == '\0') - return 0; - c = *p++; - do { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - c = *p++; - if (*p == '-' && p[1] != ']') { - p++; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - if (chr >= c && chr <= *p) - found = 1; - p++; - } else { - if (chr == c) - found = 1; - } - } while ((c = *p++) != ']'); - if (found == invert) - return 0; - break; - } -dft: default: - if (squoted && *q == CTLESC) - q++; - if (*q++ != c) - return 0; - break; - } - } -breakloop: - if (*q != '\0') - return 0; - return 1; -} - - - -/* - * Remove any CTLESC characters from a string. - */ - -void -rmescapes(char *str) -{ - char *p, *q; - - p = str; - while (*p != CTLESC && *p != CTLQUOTEMARK) { - if (*p++ == '\0') - return; - } - q = p; - while (*p) { - if (*p == CTLQUOTEMARK) { - p++; - continue; - } - if (*p == CTLESC) - p++; - *q++ = *p++; - } - *q = '\0'; -} - - - -/* - * See if a pattern matches in a case statement. - */ - -int -casematch(union node *pattern, char *val) -{ - struct stackmark smark; - int result; - char *p; - - setstackmark(&smark); - argbackq = pattern->narg.backquote; - STARTSTACKSTR(expdest); - ifslastp = NULL; - argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); - STPUTC('\0', expdest); - p = grabstackstr(expdest); - result = patmatch(p, val, 0); - popstackmark(&smark); - return result; -} - -/* - * Our own itoa(). - */ - -STATIC char * -cvtnum(int num, char *buf) -{ - char temp[32]; - int neg = num < 0; - char *p = temp + 31; - - temp[31] = '\0'; - - do { - *--p = num % 10 + '0'; - } while ((num /= 10) != 0); - - if (neg) - *--p = '-'; - - while (*p) - STPUTC(*p++, buf); - return buf; -} - -/* - * Do most of the work for wordexp(3). - */ - -int -wordexpcmd(int argc, char **argv) -{ - size_t len; - int i; - - out1fmt("%d", argc - 1); - out1c('\0'); - for (i = 1, len = 0; i < argc; i++) - len += strlen(argv[i]); - out1fmt("%zd", len); - out1c('\0'); - for (i = 1; i < argc; i++) { - out1str(argv[i]); - out1c('\0'); - } - return (0); -} diff --git a/sh/expand.h b/sh/expand.h deleted file mode 100644 index 1ea876d..0000000 --- a/sh/expand.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $NetBSD: expand.h,v 1.16 2004/07/13 15:05:59 seb Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)expand.h 8.2 (Berkeley) 5/4/95 - */ - -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_IFS_SPLIT 0x20 /* need to record arguments for ifs breakup */ - - -union node; -void expandhere(union node *, int); -void expandarg(union node *, struct arglist *, int); -void expari(int); -int patmatch(char *, char *, int); -void rmescapes(char *); -int casematch(union node *, char *); -int wordexpcmd(int, char **); - -/* From arith.y */ -int arith(const char *); -int expcmd(int , char **); -void arith_lex_reset(void); -int yylex(void); diff --git a/sh/funcs/cmv b/sh/funcs/cmv deleted file mode 100644 index 667f846..0000000 --- a/sh/funcs/cmv +++ /dev/null @@ -1,50 +0,0 @@ -# $NetBSD: cmv,v 1.7 1995/05/11 21:31:05 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)cmv 8.2 (Berkeley) 5/4/95 - -# Conditional move--don't replace an existing file. - -cmv() { - if test $# != 2 - then echo "cmv: arg count" - return 2 - fi - if test -f "$2" -o -w "$2" - then echo "$2 exists" - return 2 - fi - /bin/mv "$1" "$2" -} diff --git a/sh/funcs/dirs b/sh/funcs/dirs deleted file mode 100644 index 68bb317..0000000 --- a/sh/funcs/dirs +++ /dev/null @@ -1,74 +0,0 @@ -# $NetBSD: dirs,v 1.7 1995/05/11 21:31:08 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)dirs 8.2 (Berkeley) 5/4/95 - -# pushd, popd, and dirs --- written by Chris Bertin -# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris -# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW - -pushd () { - SAVE=`pwd` - if [ "$1" = "" ] - then if [ "$DSTACK" = "" ] - then echo "pushd: directory stack empty." - return 1 - fi - set $DSTACK - cd $1 || return - shift 1 - DSTACK="$*" - else cd $1 > /dev/null || return - fi - DSTACK="$SAVE $DSTACK" - dirs -} - -popd () { - if [ "$DSTACK" = "" ] - then echo "popd: directory stack empty." - return 1 - fi - set $DSTACK - cd $1 - shift - DSTACK=$* - dirs -} - -dirs () { - echo "`pwd` $DSTACK" - return 0 -} diff --git a/sh/funcs/kill b/sh/funcs/kill deleted file mode 100644 index 75b0180..0000000 --- a/sh/funcs/kill +++ /dev/null @@ -1,50 +0,0 @@ -# $NetBSD: kill,v 1.7 1995/05/11 21:31:10 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)kill 8.2 (Berkeley) 5/4/95 - -# Convert job names to process ids and then run /bin/kill. - -kill() { - local args x - args= - for x in "$@" - do case $x in - %*) x=`jobid "$x"` ;; - esac - args="$args $x" - done - /bin/kill $args -} diff --git a/sh/funcs/login b/sh/funcs/login deleted file mode 100644 index 7ae08b2..0000000 --- a/sh/funcs/login +++ /dev/null @@ -1,39 +0,0 @@ -# $NetBSD: login,v 1.7 1995/05/11 21:31:11 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)login 8.2 (Berkeley) 5/4/95 - -# replaces the login builtin in the BSD shell -login () exec login "$@" diff --git a/sh/funcs/newgrp b/sh/funcs/newgrp deleted file mode 100644 index 796a4f1..0000000 --- a/sh/funcs/newgrp +++ /dev/null @@ -1,38 +0,0 @@ -# $NetBSD: newgrp,v 1.7 1995/05/11 21:31:12 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)newgrp 8.2 (Berkeley) 5/4/95 - -newgrp() exec newgrp "$@" diff --git a/sh/funcs/popd b/sh/funcs/popd deleted file mode 100644 index b2b65d5..0000000 --- a/sh/funcs/popd +++ /dev/null @@ -1,74 +0,0 @@ -# $NetBSD: popd,v 1.7 1995/05/11 21:31:13 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)popd 8.2 (Berkeley) 5/4/95 - -# pushd, popd, and dirs --- written by Chris Bertin -# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris -# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW - -pushd () { - SAVE=`pwd` - if [ "$1" = "" ] - then if [ "$DSTACK" = "" ] - then echo "pushd: directory stack empty." - return 1 - fi - set $DSTACK - cd $1 || return - shift 1 - DSTACK="$*" - else cd $1 > /dev/null || return - fi - DSTACK="$SAVE $DSTACK" - dirs -} - -popd () { - if [ "$DSTACK" = "" ] - then echo "popd: directory stack empty." - return 1 - fi - set $DSTACK - cd $1 - shift - DSTACK=$* - dirs -} - -dirs () { - echo "`pwd` $DSTACK" - return 0 -} diff --git a/sh/funcs/pushd b/sh/funcs/pushd deleted file mode 100644 index b393038..0000000 --- a/sh/funcs/pushd +++ /dev/null @@ -1,74 +0,0 @@ -# $NetBSD: pushd,v 1.7 1995/05/11 21:31:15 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)pushd 8.2 (Berkeley) 5/4/95 - -# pushd, popd, and dirs --- written by Chris Bertin -# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris -# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW - -pushd () { - SAVE=`pwd` - if [ "$1" = "" ] - then if [ "$DSTACK" = "" ] - then echo "pushd: directory stack empty." - return 1 - fi - set $DSTACK - cd $1 || return - shift 1 - DSTACK="$*" - else cd $1 > /dev/null || return - fi - DSTACK="$SAVE $DSTACK" - dirs -} - -popd () { - if [ "$DSTACK" = "" ] - then echo "popd: directory stack empty." - return 1 - fi - set $DSTACK - cd $1 - shift - DSTACK=$* - dirs -} - -dirs () { - echo "`pwd` $DSTACK" - return 0 -} diff --git a/sh/funcs/suspend b/sh/funcs/suspend deleted file mode 100644 index 8a4197d..0000000 --- a/sh/funcs/suspend +++ /dev/null @@ -1,42 +0,0 @@ -# $NetBSD: suspend,v 1.7 1995/05/11 21:31:17 christos Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)suspend 8.2 (Berkeley) 5/4/95 - -suspend() { - local - - set +j - kill -TSTP 0 -} diff --git a/sh/histedit.c b/sh/histedit.c deleted file mode 100644 index 4bb2b34..0000000 --- a/sh/histedit.c +++ /dev/null @@ -1,540 +0,0 @@ -/* $NetBSD: histedit.c,v 1.34 2003/10/27 06:19:29 lukem Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: histedit.c,v 1.34 2003/10/27 06:19:29 lukem Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> -#include <paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -/* - * Editline and history functions (and glue). - */ -#include "shell.h" -#include "parser.h" -#include "var.h" -#include "options.h" -#include "main.h" -#include "output.h" -#include "mystring.h" -#include "myhistedit.h" -#include "error.h" -#ifndef SMALL -#include "eval.h" -#include "memalloc.h" - -#define MAXHISTLOOPS 4 /* max recursions through fc */ -#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ - -History *hist; /* history cookie */ -EditLine *el; /* editline cookie */ -int displayhist; -static FILE *el_in, *el_out; - -STATIC const char *fc_replace(const char *, char *, char *); - -#ifdef DEBUG -extern FILE *tracefile; -#endif - -/* - * Set history and editing status. Called whenever the status may - * have changed (figures out what to do). - */ -void -histedit(void) -{ - FILE *el_err; - -#define editing (Eflag || Vflag) - - if (iflag) { - if (!hist) { - /* - * turn history on - */ - INTOFF; - hist = history_init(); - INTON; - - if (hist != NULL) - sethistsize(histsizeval()); - else - out2str("sh: can't initialize history\n"); - } - if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ - /* - * turn editing on - */ - char *term, *shname; - - INTOFF; - if (el_in == NULL) - el_in = fdopen(0, "r"); - if (el_out == NULL) - el_out = fdopen(2, "w"); - if (el_in == NULL || el_out == NULL) - goto bad; - el_err = el_out; -#if DEBUG - if (tracefile) - el_err = tracefile; -#endif - term = lookupvar("TERM"); - if (term) - setenv("TERM", term, 1); - else - unsetenv("TERM"); - shname = arg0; - if (shname[0] == '-') - shname++; - el = el_init(shname, el_in, el_out, el_err); - if (el != NULL) { - if (hist) - el_set(el, EL_HIST, history, hist); - el_set(el, EL_PROMPT, getprompt); - el_set(el, EL_SIGNAL, 1); - } else { -bad: - out2str("sh: can't initialize editing\n"); - } - INTON; - } else if (!editing && el) { - INTOFF; - el_end(el); - el = NULL; - INTON; - } - if (el) { - if (Vflag) - el_set(el, EL_EDITOR, "vi"); - else if (Eflag) - el_set(el, EL_EDITOR, "emacs"); - el_source(el, NULL); - } - } else { - INTOFF; - if (el) { /* no editing if not interactive */ - el_end(el); - el = NULL; - } - if (hist) { - history_end(hist); - hist = NULL; - } - INTON; - } -} - - -void -sethistsize(const char *hs) -{ - int histsize; - HistEvent he; - - if (hist != NULL) { - if (hs == NULL || *hs == '\0' || - (histsize = atoi(hs)) < 0) - histsize = 100; - history(hist, &he, H_SETSIZE, histsize); - } -} - -void -setterm(const char *term) -{ - if (el != NULL && term != NULL) - if (el_set(el, EL_TERMINAL, term) != 0) { - outfmt(out2, "sh: Can't set terminal type %s\n", term); - outfmt(out2, "sh: Using dumb terminal settings.\n"); - } -} - -int -inputrc(argc, argv) - int argc; - char **argv; -{ - if (argc != 2) { - out2str("usage: inputrc file\n"); - return 1; - } - if (el != NULL) { - if (el_source(el, argv[1])) { - out2str("inputrc: failed\n"); - return 1; - } else - return 0; - } else { - out2str("sh: inputrc ignored, not editing\n"); - return 1; - } -} - -/* - * This command is provided since POSIX decided to standardize - * the Korn shell fc command. Oh well... - */ -int -histcmd(int argc, char **argv) -{ - int ch; - const char *editor = NULL; - HistEvent he; - int lflg = 0, nflg = 0, rflg = 0, sflg = 0; - int i, retval; - const char *firststr, *laststr; - int first, last, direction; - char *pat = NULL, *repl; /* ksh "fc old=new" crap */ - static int active = 0; - struct jmploc jmploc; - struct jmploc *volatile savehandler; - char editfile[MAXPATHLEN + 1]; - FILE *efp; -#ifdef __GNUC__ - /* Avoid longjmp clobbering */ - (void) &editor; - (void) &lflg; - (void) &nflg; - (void) &rflg; - (void) &sflg; - (void) &firststr; - (void) &laststr; - (void) &pat; - (void) &repl; - (void) &efp; - (void) &argc; - (void) &argv; -#endif - - if (hist == NULL) - error("history not active"); - - if (argc == 1) - error("missing history argument"); - - optreset = 1; optind = 1; /* initialize getopt */ - while (not_fcnumber(argv[optind]) && - (ch = getopt(argc, argv, ":e:lnrs")) != -1) - switch ((char)ch) { - case 'e': - editor = optionarg; - break; - case 'l': - lflg = 1; - break; - case 'n': - nflg = 1; - break; - case 'r': - rflg = 1; - break; - case 's': - sflg = 1; - break; - case ':': - error("option -%c expects argument", optopt); - /* NOTREACHED */ - case '?': - default: - error("unknown option: -%c", optopt); - /* NOTREACHED */ - } - argc -= optind, argv += optind; - - /* - * If executing... - */ - if (lflg == 0 || editor || sflg) { - lflg = 0; /* ignore */ - editfile[0] = '\0'; - /* - * Catch interrupts to reset active counter and - * cleanup temp files. - */ - if (setjmp(jmploc.loc)) { - active = 0; - if (*editfile) - unlink(editfile); - handler = savehandler; - longjmp(handler->loc, 1); - } - savehandler = handler; - handler = &jmploc; - if (++active > MAXHISTLOOPS) { - active = 0; - displayhist = 0; - error("called recursively too many times"); - } - /* - * Set editor. - */ - if (sflg == 0) { - if (editor == NULL && - (editor = bltinlookup("FCEDIT", 1)) == NULL && - (editor = bltinlookup("EDITOR", 1)) == NULL) - editor = DEFEDITOR; - if (editor[0] == '-' && editor[1] == '\0') { - sflg = 1; /* no edit */ - editor = NULL; - } - } - } - - /* - * If executing, parse [old=new] now - */ - if (lflg == 0 && argc > 0 && - ((repl = strchr(argv[0], '=')) != NULL)) { - pat = argv[0]; - *repl++ = '\0'; - argc--, argv++; - } - /* - * determine [first] and [last] - */ - switch (argc) { - case 0: - firststr = lflg ? "-16" : "-1"; - laststr = "-1"; - break; - case 1: - firststr = argv[0]; - laststr = lflg ? "-1" : argv[0]; - break; - case 2: - firststr = argv[0]; - laststr = argv[1]; - break; - default: - error("too many args"); - /* NOTREACHED */ - } - /* - * Turn into event numbers. - */ - first = str_to_event(firststr, 0); - last = str_to_event(laststr, 1); - - if (rflg) { - i = last; - last = first; - first = i; - } - /* - * XXX - this should not depend on the event numbers - * always increasing. Add sequence numbers or offset - * to the history element in next (diskbased) release. - */ - direction = first < last ? H_PREV : H_NEXT; - - /* - * If editing, grab a temp file. - */ - if (editor) { - int fd; - INTOFF; /* easier */ - snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP); - if ((fd = mkstemp(editfile)) < 0) - error("can't create temporary file %s", editfile); - if ((efp = fdopen(fd, "w")) == NULL) { - close(fd); - error("can't allocate stdio buffer for temp"); - } - } - - /* - * Loop through selected history events. If listing or executing, - * do it now. Otherwise, put into temp file and call the editor - * after. - * - * The history interface needs rethinking, as the following - * convolutions will demonstrate. - */ - history(hist, &he, H_FIRST); - retval = history(hist, &he, H_NEXT_EVENT, first); - for (;retval != -1; retval = history(hist, &he, direction)) { - if (lflg) { - if (!nflg) - out1fmt("%5d ", he.num); - out1str(he.str); - } else { - const char *s = pat ? - fc_replace(he.str, pat, repl) : he.str; - - if (sflg) { - if (displayhist) { - out2str(s); - } - - evalstring(strcpy(stalloc(strlen(s) + 1), s), 0); - if (displayhist && hist) { - /* - * XXX what about recursive and - * relative histnums. - */ - history(hist, &he, H_ENTER, s); - } - } else - fputs(s, efp); - } - /* - * At end? (if we were to lose last, we'd sure be - * messed up). - */ - if (he.num == last) - break; - } - if (editor) { - char *editcmd; - - fclose(efp); - editcmd = stalloc(strlen(editor) + strlen(editfile) + 2); - sprintf(editcmd, "%s %s", editor, editfile); - evalstring(editcmd, 0); /* XXX - should use no JC command */ - INTON; - readcmdfile(editfile); /* XXX - should read back - quick tst */ - unlink(editfile); - } - - if (lflg == 0 && active > 0) - --active; - if (displayhist) - displayhist = 0; - return 0; -} - -STATIC const char * -fc_replace(const char *s, char *p, char *r) -{ - char *dest; - int plen = strlen(p); - - STARTSTACKSTR(dest); - while (*s) { - if (*s == *p && strncmp(s, p, plen) == 0) { - while (*r) - STPUTC(*r++, dest); - s += plen; - *p = '\0'; /* so no more matches */ - } else - STPUTC(*s++, dest); - } - STACKSTRNUL(dest); - dest = grabstackstr(dest); - - return (dest); -} - -int -not_fcnumber(char *s) -{ - if (s == NULL) - return 0; - if (*s == '-') - s++; - return (!is_number(s)); -} - -int -str_to_event(const char *str, int last) -{ - HistEvent he; - const char *s = str; - int relative = 0; - int i, retval; - - retval = history(hist, &he, H_FIRST); - switch (*s) { - case '-': - relative = 1; - /*FALLTHROUGH*/ - case '+': - s++; - } - if (is_number(s)) { - i = atoi(s); - if (relative) { - while (retval != -1 && i--) { - retval = history(hist, &he, H_NEXT); - } - if (retval == -1) - retval = history(hist, &he, H_LAST); - } else { - retval = history(hist, &he, H_NEXT_EVENT, i); - if (retval == -1) { - /* - * the notion of first and last is - * backwards to that of the history package - */ - retval = history(hist, &he, - last ? H_FIRST : H_LAST); - } - } - if (retval == -1) - error("history number %s not found (internal error)", - str); - } else { - /* - * pattern - */ - retval = history(hist, &he, H_PREV_STR, str); - if (retval == -1) - error("history pattern not found: %s", str); - } - return (he.num); -} -#else -int -histcmd(int argc, char **argv) -{ - error("not compiled with history support"); - /* NOTREACHED */ -} -int -inputrc(int argc, char **argv) -{ - error("not compiled with history support"); - /* NOTREACHED */ -} -#endif diff --git a/sh/init.c b/sh/init.c deleted file mode 100644 index 55ad172..0000000 --- a/sh/init.c +++ /dev/null @@ -1,1090 +0,0 @@ -/* - * This file was generated by the mkinit program. - */ - -#include "shell.h" -#include "mystring.h" -#include "init.h" -#include "eval.h" -#include <stdio.h> -#include "input.h" -#include "error.h" -#include <stdlib.h> -#include "options.h" -#include "redir.h" -#include <signal.h> -#include "trap.h" -#include "output.h" -#include "memalloc.h" -#include "var.h" - - - -#undef ATABSIZE -#define ATABSIZE 39 -#undef YYBISON -#define YYBISON 1 -#undef YYSKELETON_NAME -#define YYSKELETON_NAME "yacc.c" -#undef YYPURE -#define YYPURE 0 -#undef YYLSP_NEEDED -#define YYLSP_NEEDED 0 -#undef ARITH_NUM -#define ARITH_NUM 258 -#undef ARITH_LPAREN -#define ARITH_LPAREN 259 -#undef ARITH_RPAREN -#define ARITH_RPAREN 260 -#undef ARITH_OR -#define ARITH_OR 261 -#undef ARITH_AND -#define ARITH_AND 262 -#undef ARITH_BOR -#define ARITH_BOR 263 -#undef ARITH_BXOR -#define ARITH_BXOR 264 -#undef ARITH_BAND -#define ARITH_BAND 265 -#undef ARITH_NE -#define ARITH_NE 266 -#undef ARITH_EQ -#define ARITH_EQ 267 -#undef ARITH_LE -#define ARITH_LE 268 -#undef ARITH_GE -#define ARITH_GE 269 -#undef ARITH_GT -#define ARITH_GT 270 -#undef ARITH_LT -#define ARITH_LT 271 -#undef ARITH_RSHIFT -#define ARITH_RSHIFT 272 -#undef ARITH_LSHIFT -#define ARITH_LSHIFT 273 -#undef ARITH_SUB -#define ARITH_SUB 274 -#undef ARITH_ADD -#define ARITH_ADD 275 -#undef ARITH_REM -#define ARITH_REM 276 -#undef ARITH_DIV -#define ARITH_DIV 277 -#undef ARITH_MUL -#define ARITH_MUL 278 -#undef ARITH_BNOT -#define ARITH_BNOT 279 -#undef ARITH_NOT -#define ARITH_NOT 280 -#undef ARITH_UNARYPLUS -#define ARITH_UNARYPLUS 281 -#undef ARITH_UNARYMINUS -#define ARITH_UNARYMINUS 282 -#undef YYFINAL -#define YYFINAL 14 -#undef YYLAST -#define YYLAST 170 -#undef YYNTOKENS -#define YYNTOKENS 28 -#undef YYNNTS -#define YYNNTS 3 -#undef YYNRULES -#define YYNRULES 26 -#undef YYNSTATES -#define YYNSTATES 52 -#undef YYUNDEFTOK -#define YYUNDEFTOK 2 -#undef YYMAXUTOK -#define YYMAXUTOK 282 -#undef YYPACT_NINF -#define YYPACT_NINF -13 -#undef YYTABLE_NINF -#define YYTABLE_NINF -1 -#undef yyerrok -#define yyerrok (yyerrstatus = 0) -#undef yyclearin -#define yyclearin (yychar = YYEMPTY) -#undef YYEMPTY -#define YYEMPTY (-2) -#undef YYEOF -#define YYEOF 0 -#undef YYACCEPT -#define YYACCEPT goto yyacceptlab -#undef YYABORT -#define YYABORT goto yyabortlab -#undef YYERROR -#define YYERROR goto yyerrorlab -#undef YYFAIL -#define YYFAIL goto yyerrlab -#undef YYTERROR -#define YYTERROR 1 -#undef YYERRCODE -#define YYERRCODE 256 -#undef YYPOPSTACK -#define YYPOPSTACK (yyvsp--, yyssp--) -#undef YY_INT_ALIGNED -#define YY_INT_ALIGNED short int -#undef FLEX_SCANNER -#define FLEX_SCANNER -#undef YY_FLEX_MAJOR_VERSION -#define YY_FLEX_MAJOR_VERSION 2 -#undef YY_FLEX_MINOR_VERSION -#define YY_FLEX_MINOR_VERSION 5 -#undef YY_FLEX_SUBMINOR_VERSION -#define YY_FLEX_SUBMINOR_VERSION 31 -#undef FLEX_BETA -#define FLEX_BETA -#undef FLEXINT_H -#define FLEXINT_H -#undef INT8_MIN -#define INT8_MIN (-128) -#undef INT16_MIN -#define INT16_MIN (-32767-1) -#undef INT32_MIN -#define INT32_MIN (-2147483647-1) -#undef INT8_MAX -#define INT8_MAX (127) -#undef INT16_MAX -#define INT16_MAX (32767) -#undef INT32_MAX -#define INT32_MAX (2147483647) -#undef UINT8_MAX -#define UINT8_MAX (255U) -#undef UINT16_MAX -#define UINT16_MAX (65535U) -#undef UINT32_MAX -#define UINT32_MAX (4294967295U) -#undef YY_USE_CONST -#define YY_USE_CONST -#undef YY_USE_CONST -#define YY_USE_CONST -#undef yyconst -#define yyconst const -#undef yyconst -#define yyconst -#undef YY_NULL -#define YY_NULL 0 -#undef BEGIN -#define BEGIN (yy_start) = 1 + 2 * -#undef YY_START -#define YY_START (((yy_start) - 1) / 2) -#undef YYSTATE -#define YYSTATE YY_START -#undef YY_NEW_FILE -#define YY_NEW_FILE yyrestart(yyin ) -#undef YY_END_OF_BUFFER_CHAR -#define YY_END_OF_BUFFER_CHAR 0 -#undef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#undef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -#undef EOB_ACT_CONTINUE_SCAN -#define EOB_ACT_CONTINUE_SCAN 0 -#undef EOB_ACT_END_OF_FILE -#define EOB_ACT_END_OF_FILE 1 -#undef EOB_ACT_LAST_MATCH -#define EOB_ACT_LAST_MATCH 2 -#undef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -#undef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -#undef YY_BUFFER_NEW -#define YY_BUFFER_NEW 0 -#undef YY_BUFFER_NORMAL -#define YY_BUFFER_NORMAL 1 -#undef YY_BUFFER_EOF_PENDING -#define YY_BUFFER_EOF_PENDING 2 -#undef YY_CURRENT_BUFFER -#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ -#undef YY_CURRENT_BUFFER_LVALUE -#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] -#undef YY_FLUSH_BUFFER -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) -#undef yy_new_buffer -#define yy_new_buffer yy_create_buffer -#undef YY_SKIP_YYWRAP -#define YY_SKIP_YYWRAP -#undef yytext_ptr -#define yytext_ptr yytext -#undef YY_DO_BEFORE_ACTION -#define YY_DO_BEFORE_ACTION \ -#undef YY_NUM_RULES -#define YY_NUM_RULES 29 -#undef YY_END_OF_BUFFER -#define YY_END_OF_BUFFER 30 -#undef REJECT -#define REJECT reject_used_but_not_detected -#undef YY_MORE_ADJ -#define YY_MORE_ADJ 0 -#undef YY_RESTORE_YY_MORE_OFFSET -#define YY_RESTORE_YY_MORE_OFFSET -#undef YY_NO_UNPUT -#define YY_NO_UNPUT -#undef INITIAL -#define INITIAL 0 -#undef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#undef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#undef ECHO -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#undef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#undef YY_DECL_IS_OURS -#define YY_DECL_IS_OURS 1 -#undef YY_DECL -#define YY_DECL int yylex (void) -#undef YY_USER_ACTION -#define YY_USER_ACTION -#undef YY_BREAK -#define YY_BREAK break; -#undef YY_RULE_SETUP -#define YY_RULE_SETUP \ -#undef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#undef YYTABLES_NAME -#define YYTABLES_NAME "yytables" -#undef MAXPWD -#define MAXPWD 256 -#undef signal -#define signal bsd_signal -#undef ALL -#define ALL (E_OPEN|E_CREAT|E_EXEC) -#undef EV_EXIT -#define EV_EXIT 01 /* exit after evaluating tree */ -#undef EV_TESTED -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#undef EV_BACKCMD -#define EV_BACKCMD 04 /* command executing within back quotes */ -#undef CMDTABLESIZE -#define CMDTABLESIZE 31 /* should be prime */ -#undef ARB -#define ARB 1 /* actual size determined at run time */ -#undef NEWARGS -#define NEWARGS 5 -#undef EOF_NLEFT -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ -#undef _PATH_DEVNULL -#define _PATH_DEVNULL "/dev/null" -#undef PROFILE -#define PROFILE 0 -#undef SIGSSIZE -#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) -#undef MINSIZE -#define MINSIZE 504 /* minimum size of a block */ -#undef DEFINE_OPTIONS -#define DEFINE_OPTIONS -#undef EOFMARKLEN -#define EOFMARKLEN 79 -#undef OPENBRACE -#define OPENBRACE '{' -#undef CLOSEBRACE -#define CLOSEBRACE '}' -#undef EMPTY -#define EMPTY -2 /* marks an unused slot in redirtab */ -#undef signal -#define signal bsd_signal -#undef sys_signame -#define sys_signame sys_siglist -#undef S_DFL -#define S_DFL 1 /* default signal handling (SIG_DFL) */ -#undef S_CATCH -#define S_CATCH 2 /* signal is caught */ -#undef S_IGN -#define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#undef S_HARD_IGN -#define S_HARD_IGN 4 /* signal is ignored permenantly */ -#undef S_RESET -#define S_RESET 5 /* temporary - to reset a hard ignored sig */ -#undef OUTBUFSIZ -#define OUTBUFSIZ BUFSIZ -#undef BLOCK_OUT -#define BLOCK_OUT -2 /* output to a fixed block of memory */ -#undef MEM_OUT -#define MEM_OUT -3 /* output to dynamically allocated memory */ -#undef OUTPUT_ERR -#define OUTPUT_ERR 01 /* error occurred on output */ -#undef TEMPSIZE -#define TEMPSIZE 24 -#undef HAVE_VASPRINTF -#define HAVE_VASPRINTF 1 -#undef VTABSIZE -#define VTABSIZE 39 -#undef VTABSIZE -#define VTABSIZE 517 -#undef ATABSIZE -#define ATABSIZE 39 -#undef YYBISON -#define YYBISON 1 -#undef YYSKELETON_NAME -#define YYSKELETON_NAME "yacc.c" -#undef YYPURE -#define YYPURE 0 -#undef YYLSP_NEEDED -#define YYLSP_NEEDED 0 -#undef ARITH_NUM -#define ARITH_NUM 258 -#undef ARITH_LPAREN -#define ARITH_LPAREN 259 -#undef ARITH_RPAREN -#define ARITH_RPAREN 260 -#undef ARITH_OR -#define ARITH_OR 261 -#undef ARITH_AND -#define ARITH_AND 262 -#undef ARITH_BOR -#define ARITH_BOR 263 -#undef ARITH_BXOR -#define ARITH_BXOR 264 -#undef ARITH_BAND -#define ARITH_BAND 265 -#undef ARITH_NE -#define ARITH_NE 266 -#undef ARITH_EQ -#define ARITH_EQ 267 -#undef ARITH_LE -#define ARITH_LE 268 -#undef ARITH_GE -#define ARITH_GE 269 -#undef ARITH_GT -#define ARITH_GT 270 -#undef ARITH_LT -#define ARITH_LT 271 -#undef ARITH_RSHIFT -#define ARITH_RSHIFT 272 -#undef ARITH_LSHIFT -#define ARITH_LSHIFT 273 -#undef ARITH_SUB -#define ARITH_SUB 274 -#undef ARITH_ADD -#define ARITH_ADD 275 -#undef ARITH_REM -#define ARITH_REM 276 -#undef ARITH_DIV -#define ARITH_DIV 277 -#undef ARITH_MUL -#define ARITH_MUL 278 -#undef ARITH_BNOT -#define ARITH_BNOT 279 -#undef ARITH_NOT -#define ARITH_NOT 280 -#undef ARITH_UNARYPLUS -#define ARITH_UNARYPLUS 281 -#undef ARITH_UNARYMINUS -#define ARITH_UNARYMINUS 282 -#undef YYFINAL -#define YYFINAL 14 -#undef YYLAST -#define YYLAST 170 -#undef YYNTOKENS -#define YYNTOKENS 28 -#undef YYNNTS -#define YYNNTS 3 -#undef YYNRULES -#define YYNRULES 26 -#undef YYNSTATES -#define YYNSTATES 52 -#undef YYUNDEFTOK -#define YYUNDEFTOK 2 -#undef YYMAXUTOK -#define YYMAXUTOK 282 -#undef YYPACT_NINF -#define YYPACT_NINF -13 -#undef YYTABLE_NINF -#define YYTABLE_NINF -1 -#undef yyerrok -#define yyerrok (yyerrstatus = 0) -#undef yyclearin -#define yyclearin (yychar = YYEMPTY) -#undef YYEMPTY -#define YYEMPTY (-2) -#undef YYEOF -#define YYEOF 0 -#undef YYACCEPT -#define YYACCEPT goto yyacceptlab -#undef YYABORT -#define YYABORT goto yyabortlab -#undef YYERROR -#define YYERROR goto yyerrorlab -#undef YYFAIL -#define YYFAIL goto yyerrlab -#undef YYTERROR -#define YYTERROR 1 -#undef YYERRCODE -#define YYERRCODE 256 -#undef YYPOPSTACK -#define YYPOPSTACK (yyvsp--, yyssp--) -#undef YY_INT_ALIGNED -#define YY_INT_ALIGNED short int -#undef FLEX_SCANNER -#define FLEX_SCANNER -#undef YY_FLEX_MAJOR_VERSION -#define YY_FLEX_MAJOR_VERSION 2 -#undef YY_FLEX_MINOR_VERSION -#define YY_FLEX_MINOR_VERSION 5 -#undef YY_FLEX_SUBMINOR_VERSION -#define YY_FLEX_SUBMINOR_VERSION 31 -#undef FLEX_BETA -#define FLEX_BETA -#undef FLEXINT_H -#define FLEXINT_H -#undef INT8_MIN -#define INT8_MIN (-128) -#undef INT16_MIN -#define INT16_MIN (-32767-1) -#undef INT32_MIN -#define INT32_MIN (-2147483647-1) -#undef INT8_MAX -#define INT8_MAX (127) -#undef INT16_MAX -#define INT16_MAX (32767) -#undef INT32_MAX -#define INT32_MAX (2147483647) -#undef UINT8_MAX -#define UINT8_MAX (255U) -#undef UINT16_MAX -#define UINT16_MAX (65535U) -#undef UINT32_MAX -#define UINT32_MAX (4294967295U) -#undef YY_USE_CONST -#define YY_USE_CONST -#undef YY_USE_CONST -#define YY_USE_CONST -#undef yyconst -#define yyconst const -#undef yyconst -#define yyconst -#undef YY_NULL -#define YY_NULL 0 -#undef BEGIN -#define BEGIN (yy_start) = 1 + 2 * -#undef YY_START -#define YY_START (((yy_start) - 1) / 2) -#undef YYSTATE -#define YYSTATE YY_START -#undef YY_NEW_FILE -#define YY_NEW_FILE yyrestart(yyin ) -#undef YY_END_OF_BUFFER_CHAR -#define YY_END_OF_BUFFER_CHAR 0 -#undef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#undef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -#undef EOB_ACT_CONTINUE_SCAN -#define EOB_ACT_CONTINUE_SCAN 0 -#undef EOB_ACT_END_OF_FILE -#define EOB_ACT_END_OF_FILE 1 -#undef EOB_ACT_LAST_MATCH -#define EOB_ACT_LAST_MATCH 2 -#undef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -#undef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -#undef YY_BUFFER_NEW -#define YY_BUFFER_NEW 0 -#undef YY_BUFFER_NORMAL -#define YY_BUFFER_NORMAL 1 -#undef YY_BUFFER_EOF_PENDING -#define YY_BUFFER_EOF_PENDING 2 -#undef YY_CURRENT_BUFFER -#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ -#undef YY_CURRENT_BUFFER_LVALUE -#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] -#undef YY_FLUSH_BUFFER -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) -#undef yy_new_buffer -#define yy_new_buffer yy_create_buffer -#undef YY_SKIP_YYWRAP -#define YY_SKIP_YYWRAP -#undef yytext_ptr -#define yytext_ptr yytext -#undef YY_DO_BEFORE_ACTION -#define YY_DO_BEFORE_ACTION \ -#undef YY_NUM_RULES -#define YY_NUM_RULES 29 -#undef YY_END_OF_BUFFER -#define YY_END_OF_BUFFER 30 -#undef REJECT -#define REJECT reject_used_but_not_detected -#undef YY_MORE_ADJ -#define YY_MORE_ADJ 0 -#undef YY_RESTORE_YY_MORE_OFFSET -#define YY_RESTORE_YY_MORE_OFFSET -#undef YY_NO_UNPUT -#define YY_NO_UNPUT -#undef INITIAL -#define INITIAL 0 -#undef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#undef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#undef ECHO -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#undef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#undef YY_DECL_IS_OURS -#define YY_DECL_IS_OURS 1 -#undef YY_DECL -#define YY_DECL int yylex (void) -#undef YY_USER_ACTION -#define YY_USER_ACTION -#undef YY_BREAK -#define YY_BREAK break; -#undef YY_RULE_SETUP -#define YY_RULE_SETUP \ -#undef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#undef YYTABLES_NAME -#define YYTABLES_NAME "yytables" -#undef MAXPWD -#define MAXPWD 256 -#undef signal -#define signal bsd_signal -#undef ALL -#define ALL (E_OPEN|E_CREAT|E_EXEC) -#undef EV_EXIT -#define EV_EXIT 01 /* exit after evaluating tree */ -#undef EV_TESTED -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#undef EV_BACKCMD -#define EV_BACKCMD 04 /* command executing within back quotes */ -#undef CMDTABLESIZE -#define CMDTABLESIZE 31 /* should be prime */ -#undef ARB -#define ARB 1 /* actual size determined at run time */ -#undef NEWARGS -#define NEWARGS 5 -#undef EOF_NLEFT -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ -#undef _PATH_DEVNULL -#define _PATH_DEVNULL "/dev/null" -#undef PROFILE -#define PROFILE 0 -#undef SIGSSIZE -#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) -#undef MINSIZE -#define MINSIZE 504 /* minimum size of a block */ -#undef DEFINE_OPTIONS -#define DEFINE_OPTIONS -#undef EOFMARKLEN -#define EOFMARKLEN 79 -#undef OPENBRACE -#define OPENBRACE '{' -#undef CLOSEBRACE -#define CLOSEBRACE '}' -#undef EMPTY -#define EMPTY -2 /* marks an unused slot in redirtab */ -#undef signal -#define signal bsd_signal -#undef sys_signame -#define sys_signame sys_siglist -#undef S_DFL -#define S_DFL 1 /* default signal handling (SIG_DFL) */ -#undef S_CATCH -#define S_CATCH 2 /* signal is caught */ -#undef S_IGN -#define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#undef S_HARD_IGN -#define S_HARD_IGN 4 /* signal is ignored permenantly */ -#undef S_RESET -#define S_RESET 5 /* temporary - to reset a hard ignored sig */ -#undef OUTBUFSIZ -#define OUTBUFSIZ BUFSIZ -#undef BLOCK_OUT -#define BLOCK_OUT -2 /* output to a fixed block of memory */ -#undef MEM_OUT -#define MEM_OUT -3 /* output to dynamically allocated memory */ -#undef OUTPUT_ERR -#define OUTPUT_ERR 01 /* error occurred on output */ -#undef TEMPSIZE -#define TEMPSIZE 24 -#undef HAVE_VASPRINTF -#define HAVE_VASPRINTF 1 -#undef VTABSIZE -#define VTABSIZE 39 -#undef VTABSIZE -#define VTABSIZE 517 -#undef main -#define main echocmd -#undef YYBISON -#define YYBISON 1 -#undef YYSKELETON_NAME -#define YYSKELETON_NAME "yacc.c" -#undef YYPURE -#define YYPURE 0 -#undef YYLSP_NEEDED -#define YYLSP_NEEDED 0 -#undef ARITH_NUM -#define ARITH_NUM 258 -#undef ARITH_LPAREN -#define ARITH_LPAREN 259 -#undef ARITH_RPAREN -#define ARITH_RPAREN 260 -#undef ARITH_OR -#define ARITH_OR 261 -#undef ARITH_AND -#define ARITH_AND 262 -#undef ARITH_BOR -#define ARITH_BOR 263 -#undef ARITH_BXOR -#define ARITH_BXOR 264 -#undef ARITH_BAND -#define ARITH_BAND 265 -#undef ARITH_NE -#define ARITH_NE 266 -#undef ARITH_EQ -#define ARITH_EQ 267 -#undef ARITH_LE -#define ARITH_LE 268 -#undef ARITH_GE -#define ARITH_GE 269 -#undef ARITH_GT -#define ARITH_GT 270 -#undef ARITH_LT -#define ARITH_LT 271 -#undef ARITH_RSHIFT -#define ARITH_RSHIFT 272 -#undef ARITH_LSHIFT -#define ARITH_LSHIFT 273 -#undef ARITH_SUB -#define ARITH_SUB 274 -#undef ARITH_ADD -#define ARITH_ADD 275 -#undef ARITH_REM -#define ARITH_REM 276 -#undef ARITH_DIV -#define ARITH_DIV 277 -#undef ARITH_MUL -#define ARITH_MUL 278 -#undef ARITH_BNOT -#define ARITH_BNOT 279 -#undef ARITH_NOT -#define ARITH_NOT 280 -#undef ARITH_UNARYPLUS -#define ARITH_UNARYPLUS 281 -#undef ARITH_UNARYMINUS -#define ARITH_UNARYMINUS 282 -#undef YYFINAL -#define YYFINAL 14 -#undef YYLAST -#define YYLAST 170 -#undef YYNTOKENS -#define YYNTOKENS 28 -#undef YYNNTS -#define YYNNTS 3 -#undef YYNRULES -#define YYNRULES 26 -#undef YYNSTATES -#define YYNSTATES 52 -#undef YYUNDEFTOK -#define YYUNDEFTOK 2 -#undef YYMAXUTOK -#define YYMAXUTOK 282 -#undef YYPACT_NINF -#define YYPACT_NINF -13 -#undef YYTABLE_NINF -#define YYTABLE_NINF -1 -#undef yyerrok -#define yyerrok (yyerrstatus = 0) -#undef yyclearin -#define yyclearin (yychar = YYEMPTY) -#undef YYEMPTY -#define YYEMPTY (-2) -#undef YYEOF -#define YYEOF 0 -#undef YYACCEPT -#define YYACCEPT goto yyacceptlab -#undef YYABORT -#define YYABORT goto yyabortlab -#undef YYERROR -#define YYERROR goto yyerrorlab -#undef YYFAIL -#define YYFAIL goto yyerrlab -#undef YYTERROR -#define YYTERROR 1 -#undef YYERRCODE -#define YYERRCODE 256 -#undef YYPOPSTACK -#define YYPOPSTACK (yyvsp--, yyssp--) -#undef YY_INT_ALIGNED -#define YY_INT_ALIGNED short int -#undef FLEX_SCANNER -#define FLEX_SCANNER -#undef YY_FLEX_MAJOR_VERSION -#define YY_FLEX_MAJOR_VERSION 2 -#undef YY_FLEX_MINOR_VERSION -#define YY_FLEX_MINOR_VERSION 5 -#undef YY_FLEX_SUBMINOR_VERSION -#define YY_FLEX_SUBMINOR_VERSION 31 -#undef FLEX_BETA -#define FLEX_BETA -#undef FLEXINT_H -#define FLEXINT_H -#undef INT8_MIN -#define INT8_MIN (-128) -#undef INT16_MIN -#define INT16_MIN (-32767-1) -#undef INT32_MIN -#define INT32_MIN (-2147483647-1) -#undef INT8_MAX -#define INT8_MAX (127) -#undef INT16_MAX -#define INT16_MAX (32767) -#undef INT32_MAX -#define INT32_MAX (2147483647) -#undef UINT8_MAX -#define UINT8_MAX (255U) -#undef UINT16_MAX -#define UINT16_MAX (65535U) -#undef UINT32_MAX -#define UINT32_MAX (4294967295U) -#undef YY_USE_CONST -#define YY_USE_CONST -#undef YY_USE_CONST -#define YY_USE_CONST -#undef yyconst -#define yyconst const -#undef yyconst -#define yyconst -#undef YY_NULL -#define YY_NULL 0 -#undef BEGIN -#define BEGIN (yy_start) = 1 + 2 * -#undef YY_START -#define YY_START (((yy_start) - 1) / 2) -#undef YYSTATE -#define YYSTATE YY_START -#undef YY_NEW_FILE -#define YY_NEW_FILE yyrestart(yyin ) -#undef YY_END_OF_BUFFER_CHAR -#define YY_END_OF_BUFFER_CHAR 0 -#undef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#undef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -#undef EOB_ACT_CONTINUE_SCAN -#define EOB_ACT_CONTINUE_SCAN 0 -#undef EOB_ACT_END_OF_FILE -#define EOB_ACT_END_OF_FILE 1 -#undef EOB_ACT_LAST_MATCH -#define EOB_ACT_LAST_MATCH 2 -#undef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -#undef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -#undef YY_BUFFER_NEW -#define YY_BUFFER_NEW 0 -#undef YY_BUFFER_NORMAL -#define YY_BUFFER_NORMAL 1 -#undef YY_BUFFER_EOF_PENDING -#define YY_BUFFER_EOF_PENDING 2 -#undef YY_CURRENT_BUFFER -#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ -#undef YY_CURRENT_BUFFER_LVALUE -#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] -#undef YY_FLUSH_BUFFER -#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) -#undef yy_new_buffer -#define yy_new_buffer yy_create_buffer -#undef yytext_ptr -#define yytext_ptr yytext -#undef YY_DO_BEFORE_ACTION -#define YY_DO_BEFORE_ACTION \ -#undef YY_NUM_RULES -#define YY_NUM_RULES 29 -#undef YY_END_OF_BUFFER -#define YY_END_OF_BUFFER 30 -#undef REJECT -#define REJECT reject_used_but_not_detected -#undef YY_MORE_ADJ -#define YY_MORE_ADJ 0 -#undef YY_RESTORE_YY_MORE_OFFSET -#define YY_RESTORE_YY_MORE_OFFSET -#undef YY_NO_UNPUT -#define YY_NO_UNPUT -#undef INITIAL -#define INITIAL 0 -#undef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#undef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#undef ECHO -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#undef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#undef YY_DECL_IS_OURS -#define YY_DECL_IS_OURS 1 -#undef YY_DECL -#define YY_DECL int yylex (void) -#undef YY_USER_ACTION -#define YY_USER_ACTION -#undef YY_BREAK -#define YY_BREAK break; -#undef YY_RULE_SETUP -#define YY_RULE_SETUP \ -#undef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#undef YYTABLES_NAME -#define YYTABLES_NAME "yytables" -#undef MAXPWD -#define MAXPWD 256 -#undef ALL -#define ALL (E_OPEN|E_CREAT|E_EXEC) -#undef EV_EXIT -#define EV_EXIT 01 /* exit after evaluating tree */ -#undef EV_TESTED -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#undef EV_BACKCMD -#define EV_BACKCMD 04 /* command executing within back quotes */ -#undef CMDTABLESIZE -#define CMDTABLESIZE 31 /* should be prime */ -#undef ARB -#define ARB 1 /* actual size determined at run time */ -#undef NEWARGS -#define NEWARGS 5 -#undef EOF_NLEFT -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ -#undef _PATH_DEVNULL -#define _PATH_DEVNULL "/dev/null" -#undef PROFILE -#define PROFILE 0 -#undef SIGSSIZE -#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) -#undef MINSIZE -#define MINSIZE 504 /* minimum size of a block */ -#undef DEFINE_OPTIONS -#define DEFINE_OPTIONS -#undef EOFMARKLEN -#define EOFMARKLEN 79 -#undef OPENBRACE -#define OPENBRACE '{' -#undef CLOSEBRACE -#define CLOSEBRACE '}' -#undef EMPTY -#define EMPTY -2 /* marks an unused slot in redirtab */ -#undef S_DFL -#define S_DFL 1 /* default signal handling (SIG_DFL) */ -#undef S_CATCH -#define S_CATCH 2 /* signal is caught */ -#undef S_IGN -#define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#undef S_HARD_IGN -#define S_HARD_IGN 4 /* signal is ignored permenantly */ -#undef S_RESET -#define S_RESET 5 /* temporary - to reset a hard ignored sig */ -#undef OUTBUFSIZ -#define OUTBUFSIZ BUFSIZ -#undef BLOCK_OUT -#define BLOCK_OUT -2 /* output to a fixed block of memory */ -#undef MEM_OUT -#define MEM_OUT -3 /* output to dynamically allocated memory */ -#undef OUTPUT_ERR -#define OUTPUT_ERR 01 /* error occurred on output */ -#undef TEMPSIZE -#define TEMPSIZE 24 -#undef HAVE_VASPRINTF -#define HAVE_VASPRINTF 1 -#undef VTABSIZE -#define VTABSIZE 39 -#undef VTABSIZE -#define VTABSIZE 517 -#undef main -#define main echocmd - - - -extern void rmaliases(void); - -extern int loopnest; /* current loop nesting level */ - -extern void deletefuncs(void); -extern void hash_special_builtins(void); - -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 */ -}; - -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 */ -}; - -extern int parselleft; /* copy of parsefile->lleft */ -extern struct parsefile basepf; /* top level input file */ -extern char basebuf[BUFSIZ]; /* buffer for top level input file */ - -extern pid_t backgndpid; /* pid of last background process */ -extern int jobctl; - -extern int tokpushback; /* last token pushed back */ -extern int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ - -struct redirtab { - struct redirtab *next; - short renamed[10]; -}; - -extern struct redirtab *redirlist; - -extern char sigmode[NSIG]; /* current value of signal */ - -extern char **environ; - - - -/* - * Initialization code. - */ - -void -init() { - - /* from exec.c: */ - { - hash_special_builtins(); - } - - /* from input.c: */ - { - basepf.nextc = basepf.buf = basebuf; - } - - /* from var.c: */ - { - char **envp; - - initvar(); - for (envp = environ ; *envp ; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } - } -} - - - -/* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop. - */ - -void -reset() { - - /* from eval.c: */ - { - evalskip = 0; - loopnest = 0; - funcnest = 0; - } - - /* from input.c: */ - { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); - } - - /* from parser.c: */ - { - tokpushback = 0; - checkkwd = 0; - } - - /* from redir.c: */ - { - while (redirlist) - popredir(); - } - - /* from output.c: */ - { - out1 = &output; - out2 = &errout; - if (memout.buf != NULL) { - ckfree(memout.buf); - memout.buf = NULL; - } - } -} - - - -/* - * This routine is called to initialize the shell to run a shell procedure. - */ - -void -initshellproc() { - - /* from alias.c: */ - { - rmaliases(); - } - - /* from eval.c: */ - { - exitstatus = 0; - } - - /* from exec.c: */ - { - deletefuncs(); - } - - /* from input.c: */ - { - popallfiles(); - } - - /* from jobs.c: */ - { - backgndpid = -1; -#if JOBS - jobctl = 0; -#endif - } - - /* from options.c: */ - { - int i; - - for (i = 0; optlist[i].name; i++) - optlist[i].val = 0; - optschanged(); - - } - - /* from redir.c: */ - { - clearredir(0); - } - - /* from trap.c: */ - { - char *sm; - - clear_traps(0); - for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; - } - } - - /* from var.c: */ - { - shprocvar(); - } -} diff --git a/sh/init.h b/sh/init.h deleted file mode 100644 index 60d924e..0000000 --- a/sh/init.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)init.h 8.2 (Berkeley) 5/4/95 - */ - -void init(void); -void reset(void); -void initshellproc(void); diff --git a/sh/input.c b/sh/input.c deleted file mode 100644 index 056ee8b..0000000 --- a/sh/input.c +++ /dev/null @@ -1,577 +0,0 @@ -/* $NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; -#else -__RCSID("$NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $"); -#endif -#endif /* not lint */ - -#include <stdio.h> /* defines BUFSIZ */ -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> - -/* - * This file implements the input routines used by the parser. - */ - -#include "shell.h" -#include "redir.h" -#include "syntax.h" -#include "input.h" -#include "output.h" -#include "options.h" -#include "memalloc.h" -#include "error.h" -#include "alias.h" -#include "parser.h" -#include "myhistedit.h" - -#ifdef WITH_LINENOISE -#include "linenoise.h" -#endif - -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ - -MKINIT -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. - */ - -MKINIT -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 */ -}; - - -int plinno = 1; /* input line number */ -int parsenleft; /* copy of parsefile->nleft */ -MKINIT int parselleft; /* copy of parsefile->lleft */ -char *parsenextc; /* copy of parsefile->nextc */ -MKINIT struct parsefile basepf; /* top level input file */ -MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */ -struct parsefile *parsefile = &basepf; /* current input file */ -int init_editline = 0; /* editline library initialized? */ -int whichprompt; /* 1 == PS1, 2 == PS2 */ - -#if WITH_HISTORY -EditLine *el; /* cookie for editline package */ -#endif - -STATIC void pushfile(void); -static int preadfd(void); - -#ifdef mkinit -INCLUDE <stdio.h> -INCLUDE "input.h" -INCLUDE "error.h" - -INIT { - basepf.nextc = basepf.buf = basebuf; -} - -RESET { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); -} - -SHELLPROC { - popallfiles(); -} -#endif - - -/* - * Read a line from the script. - */ - -char * -pfgets(char *line, int len) -{ - char *p = line; - int nleft = len; - int c; - - while (--nleft > 0) { - c = pgetc_macro(); - if (c == PEOF) { - if (p == line) - return NULL; - break; - } - *p++ = c; - if (c == '\n') - break; - } - *p = '\0'; - return line; -} - - - -/* - * Read a character from the script, returning PEOF on end of file. - * Nul characters in the input are silently discarded. - */ - -int -pgetc(void) -{ - return pgetc_macro(); -} - -int in_interactive_mode() { - return parsefile != NULL && parsefile->fd == 0; -} - -static int -preadfd(void) -{ - int nr; - char *buf = parsefile->buf; - parsenextc = buf; - -retry: -#ifdef WITH_HISTORY - if (parsefile->fd == 0 && el) { - static const char *rl_cp; - static int el_len; - - if (rl_cp == NULL) - rl_cp = el_gets(el, &el_len); - if (rl_cp == NULL) - nr = 0; - else { - nr = el_len; - if (nr > BUFSIZ - 8) - nr = BUFSIZ - 8; - memcpy(buf, rl_cp, nr); - if (nr != el_len) { - el_len -= nr; - rl_cp += nr; - } else - rl_cp = 0; - } - - } else -#endif -#ifdef WITH_LINENOISE - if (parsefile->fd == 0) { - static char *rl_start; - static const char *rl_cp; - static int el_len; - - if (rl_cp == NULL) { - rl_cp = rl_start = linenoise(getprompt("")); - if (rl_cp != NULL) { - el_len = strlen(rl_start); - if (el_len != 0) { - /* Add non-blank lines to history. */ - linenoiseHistoryAdd(rl_start); - } - out2str("\n"); - /* Client expects a newline at end of input, doesn't expect null */ - rl_start[el_len++] = '\n'; - } - } - if (rl_cp == NULL) - nr = 0; - else { - nr = el_len; - if (nr > BUFSIZ - 8) - nr = BUFSIZ - 8; - memcpy(buf, rl_cp, nr); - if (nr != el_len) { - el_len -= nr; - rl_cp += nr; - } else { - rl_cp = 0; - if (rl_start != NULL) { - free(rl_start); - rl_start = NULL; - } - } - } - } else -#endif - nr = read(parsefile->fd, buf, BUFSIZ - 8); - - - if (nr <= 0) { - if (nr < 0) { - if (errno == EINTR) - goto retry; - if (parsefile->fd == 0 && errno == EWOULDBLOCK) { - int flags = fcntl(0, F_GETFL, 0); - if (flags >= 0 && flags & O_NONBLOCK) { - flags &=~ O_NONBLOCK; - if (fcntl(0, F_SETFL, flags) >= 0) { - out2str("sh: turning off NDELAY mode\n"); - goto retry; - } - } - } - } - nr = -1; - } - return nr; -} - -/* - * Refill the input buffer and return the next input character: - * - * 1) If a string was pushed back on the input, pop it; - * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading - * from a string so we can't refill the buffer, return EOF. - * 3) If the is more stuff in this buffer, use it else call read to fill it. - * 4) Process input up to the next newline, deleting nul characters. - */ - -int -preadbuffer(void) -{ - char *p, *q; - int more; - int something; - char savec; - - if (parsefile->strpush) { - popstring(); - if (--parsenleft >= 0) - return (*parsenextc++); - } - if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) - return PEOF; - flushout(&output); - flushout(&errout); - -again: - if (parselleft <= 0) { - if ((parselleft = preadfd()) == -1) { - parselleft = parsenleft = EOF_NLEFT; - return PEOF; - } - } - - q = p = parsenextc; - - /* delete nul characters */ - something = 0; - for (more = 1; more;) { - switch (*p) { - case '\0': - p++; /* Skip nul */ - goto check; - - case '\t': - case ' ': - break; - - case '\n': - parsenleft = q - parsenextc; - more = 0; /* Stop processing here */ - break; - - default: - something = 1; - break; - } - - *q++ = *p++; -check: - if (--parselleft <= 0) { - parsenleft = q - parsenextc - 1; - if (parsenleft < 0) - goto again; - *q = '\0'; - more = 0; - } - } - - savec = *q; - *q = '\0'; - -#ifdef WITH_HISTORY - if (parsefile->fd == 0 && hist && something) { - HistEvent he; - INTOFF; - history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND, - parsenextc); - INTON; - } -#endif - - if (vflag) { - out2str(parsenextc); - flushout(out2); - } - - *q = savec; - - return *parsenextc++; -} - -/* - * Undo the last call to pgetc. Only one character may be pushed back. - * PEOF may be pushed back. - */ - -void -pungetc(void) -{ - parsenleft++; - parsenextc--; -} - -/* - * Push a string back onto the input at this current parsefile level. - * We handle aliases this way. - */ -void -pushstring(char *s, int len, void *ap) -{ - struct strpush *sp; - - INTOFF; -/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ - if (parsefile->strpush) { - sp = ckmalloc(sizeof (struct strpush)); - sp->prev = parsefile->strpush; - parsefile->strpush = sp; - } else - sp = parsefile->strpush = &(parsefile->basestrpush); - sp->prevstring = parsenextc; - sp->prevnleft = parsenleft; - sp->prevlleft = parselleft; - sp->ap = (struct alias *)ap; - if (ap) - ((struct alias *)ap)->flag |= ALIASINUSE; - parsenextc = s; - parsenleft = len; - INTON; -} - -void -popstring(void) -{ - struct strpush *sp = parsefile->strpush; - - INTOFF; - parsenextc = sp->prevstring; - parsenleft = sp->prevnleft; - parselleft = sp->prevlleft; -/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ - if (sp->ap) - sp->ap->flag &= ~ALIASINUSE; - parsefile->strpush = sp->prev; - if (sp != &(parsefile->basestrpush)) - ckfree(sp); - INTON; -} - -/* - * Set the input to take input from a file. If push is set, push the - * old input onto the stack first. - */ - -void -setinputfile(const char *fname, int push) -{ - int fd; - int fd2; - - INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); - if (fd < 10) { - fd2 = copyfd(fd, 10); - close(fd); - if (fd2 < 0) - error("Out of file descriptors"); - fd = fd2; - } - setinputfd(fd, push); - INTON; -} - - -/* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. - */ - -void -setinputfd(int fd, int push) -{ - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); - if (push) { - pushfile(); - parsefile->buf = ckmalloc(BUFSIZ); - } - if (parsefile->fd > 0) - close(parsefile->fd); - parsefile->fd = fd; - if (parsefile->buf == NULL) - parsefile->buf = ckmalloc(BUFSIZ); - parselleft = parsenleft = 0; - plinno = 1; -} - - -/* - * Like setinputfile, but takes input from a string. - */ - -void -setinputstring(char *string, int push) -{ - INTOFF; - if (push) - pushfile(); - parsenextc = string; - parselleft = parsenleft = strlen(string); - parsefile->buf = NULL; - plinno = 1; - INTON; -} - - - -/* - * To handle the "." command, a stack of input files is used. Pushfile - * adds a new entry to the stack and popfile restores the previous level. - */ - -STATIC void -pushfile(void) -{ - struct parsefile *pf; - - parsefile->nleft = parsenleft; - parsefile->lleft = parselleft; - parsefile->nextc = parsenextc; - parsefile->linno = plinno; - pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); - pf->prev = parsefile; - pf->fd = -1; - pf->strpush = NULL; - pf->basestrpush.prev = NULL; - parsefile = pf; -} - - -void -popfile(void) -{ - struct parsefile *pf = parsefile; - - INTOFF; - if (pf->fd >= 0) - close(pf->fd); - if (pf->buf) - ckfree(pf->buf); - while (pf->strpush) - popstring(); - parsefile = pf->prev; - ckfree(pf); - parsenleft = parsefile->nleft; - parselleft = parsefile->lleft; - parsenextc = parsefile->nextc; - plinno = parsefile->linno; - INTON; -} - - -/* - * Return to top level. - */ - -void -popallfiles(void) -{ - while (parsefile != &basepf) - popfile(); -} - - - -/* - * Close the file(s) that the shell is reading commands from. Called - * after a fork is done. - * - * Takes one arg, vfork, which tells it to not modify its global vars - * as it is still running in the parent. - * - * This code is (probably) unnecessary as the 'close on exec' flag is - * set and should be enough. In the vfork case it is definitely wrong - * to close the fds as another fork() may be done later to feed data - * from a 'here' document into a pipe and we don't want to close the - * pipe! - */ - -void -closescript(int vforked) -{ - if (vforked) - return; - popallfiles(); - if (parsefile->fd > 0) { - close(parsefile->fd); - parsefile->fd = 0; - } -} diff --git a/sh/input.h b/sh/input.h deleted file mode 100644 index 99c1b77..0000000 --- a/sh/input.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $NetBSD: input.h,v 1.15 2003/08/07 09:05:33 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)input.h 8.2 (Berkeley) 5/4/95 - */ - -/* PEOF (the end of file marker) is defined in syntax.h */ - -/* - * The input line number. Input.c just defines this variable, and saves - * and restores it when files are pushed and popped. The user of this - * package must set its value. - */ -extern int plinno; -extern int parsenleft; /* number of characters left in input buffer */ -extern char *parsenextc; /* next character in input buffer */ -extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */ - -int in_interactive_mode(); -char *pfgets(char *, int); -int pgetc(void); -int preadbuffer(void); -void pungetc(void); -void pushstring(char *, int, void *); -void popstring(void); -void setinputfile(const char *, int); -void setinputfd(int, int); -void setinputstring(char *, int); -void popfile(void); -void popallfiles(void); -void closescript(int); - -#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) diff --git a/sh/jobs.c b/sh/jobs.c deleted file mode 100644 index b9460b0..0000000 --- a/sh/jobs.c +++ /dev/null @@ -1,1487 +0,0 @@ -/* $NetBSD: jobs.c,v 1.62 2003/12/18 00:56:05 christos Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: jobs.c,v 1.62 2003/12/18 00:56:05 christos Exp $"); -#endif -#endif /* not lint */ - -#include <fcntl.h> -#include <signal.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#define _PATH_DEVNULL "/dev/null" -#include <sys/types.h> -#include <sys/param.h> -#ifdef BSD -#include <sys/wait.h> -#include <sys/time.h> -#include <sys/resource.h> -#endif -#include <sys/wait.h> -#define killpg(s,i) kill(-(s),i) -#include <sys/ioctl.h> - -#include "shell.h" -#if JOBS -#if OLD_TTY_DRIVER -#include "sgtty.h" -#else -#include <termios.h> -#endif -#undef CEOF /* syntax.h redefines this */ -#endif -#include "redir.h" -#include "show.h" -#include "main.h" -#include "parser.h" -#include "nodes.h" -#include "jobs.h" -#include "options.h" -#include "trap.h" -#include "syntax.h" -#include "input.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" -#include "mystring.h" - -// Use of process groups is disabled to allow adb shell children to terminate when the shell dies -#define USE_PROCESS_GROUPS - - -static struct job *jobtab; /* array of jobs */ -static int njobs; /* size of array */ -static int jobs_invalid; /* set in child */ -MKINIT pid_t backgndpid = -1; /* pid of last background process */ -#if JOBS -int initialpgrp; /* pgrp of shell on invocation */ -static int curjob = -1; /* current job */ -#endif -static int ttyfd = -1; - -STATIC void restartjob(struct job *); -STATIC void freejob(struct job *); -STATIC struct job *getjob(const char *, int); -STATIC int dowait(int, struct job *); -STATIC int onsigchild(void); -STATIC int waitproc(int, struct job *, int *); -STATIC void cmdtxt(union node *); -STATIC void cmdlist(union node *, int); -STATIC void cmdputs(const char *); - -#ifdef OLD_TTY_DRIVER -static pid_t tcgetpgrp(int fd); -static int tcsetpgrp(int fd, pid_t pgrp); - -static pid_t -tcgetpgrp(int fd) -{ - pid_t pgrp; - if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1) - return -1; - else - return pgrp; -} - -static int -tcsetpgrp(int fd, pid_tpgrp) -{ - return ioctl(fd, TIOCSPGRP, (char *)&pgrp); -} -#endif - -/* - * Turn job control on and off. - * - * Note: This code assumes that the third arg to ioctl is a character - * pointer, which is true on Berkeley systems but not System V. Since - * System V doesn't have job control yet, this isn't a problem now. - */ - -MKINIT int jobctl; - -void -setjobctl(int on) -{ -#ifdef OLD_TTY_DRIVER - int ldisc; -#endif - - if (on == jobctl || rootshell == 0) - return; - if (on) { -#if defined(FIOCLEX) || defined(FD_CLOEXEC) - int err; - int i; - if (ttyfd != -1) - close(ttyfd); - if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) { - for (i = 0; i < 3; i++) { - if (isatty(i) && (ttyfd = dup(i)) != -1) - break; - } - if (i == 3) - goto out; - } - /* Move to a high fd */ - for (i = 10; i > 2; i--) { - if ((err = fcntl(ttyfd, F_DUPFD, (1 << i) - 1)) != -1) - break; - } - if (err != -1) { - close(ttyfd); - ttyfd = err; - } -#ifdef FIOCLEX - err = ioctl(ttyfd, FIOCLEX, 0); -#elif FD_CLOEXEC - err = fcntl(ttyfd, F_SETFD, - fcntl(ttyfd, F_GETFD, 0) | FD_CLOEXEC); -#endif - if (err == -1) { - close(ttyfd); - ttyfd = -1; - goto out; - } -#else - out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control"); - goto out; -#endif - do { /* while we are in the background */ - if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) { -out: - out2str("sh: can't access tty; job control turned off\n"); - mflag = 0; - return; - } - if (initialpgrp == -1) - initialpgrp = getpgrp(); - else if (initialpgrp != getpgrp()) { - killpg(0, SIGTTIN); - continue; - } - } while (0); - -#ifdef OLD_TTY_DRIVER - if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0 - || ldisc != NTTYDISC) { - out2str("sh: need new tty driver to run job control; job control turned off\n"); - mflag = 0; - return; - } -#endif - setsignal(SIGTSTP, 0); - setsignal(SIGTTOU, 0); - setsignal(SIGTTIN, 0); -#ifdef USE_PROCESS_GROUPS - if (getpgid(0) != rootpid && setpgid(0, rootpid) == -1) - error("Cannot set process group (%s) at %d", - strerror(errno), __LINE__); - if (tcsetpgrp(ttyfd, rootpid) == -1) - error("Cannot set tty process group (%s) at %d", - strerror(errno), __LINE__); -#endif - } else { /* turning job control off */ -#ifdef USE_PROCESS_GROUPS - if (getpgid(0) != initialpgrp && setpgid(0, initialpgrp) == -1) - error("Cannot set process group (%s) at %d", - strerror(errno), __LINE__); - if (tcsetpgrp(ttyfd, initialpgrp) == -1) - error("Cannot set tty process group (%s) at %d", - strerror(errno), __LINE__); -#endif - close(ttyfd); - ttyfd = -1; - setsignal(SIGTSTP, 0); - setsignal(SIGTTOU, 0); - setsignal(SIGTTIN, 0); - } - jobctl = on; -} - - -#ifdef mkinit -INCLUDE <stdlib.h> - -SHELLPROC { - backgndpid = -1; -#if JOBS - jobctl = 0; -#endif -} - -#endif - - - -#if JOBS -int -fgcmd(int argc, char **argv) -{ - struct job *jp; - int i; - int status; - - nextopt(""); - jp = getjob(*argptr, 0); - if (jp->jobctl == 0) - error("job not created under job control"); - out1fmt("%s", jp->ps[0].cmd); - for (i = 1; i < jp->nprocs; i++) - out1fmt(" | %s", jp->ps[i].cmd ); - out1c('\n'); - flushall(); - - for (i = 0; i < jp->nprocs; i++) - if (tcsetpgrp(ttyfd, jp->ps[i].pid) != -1) - break; - - if (i >= jp->nprocs) { - error("Cannot set tty process group (%s) at %d", - strerror(errno), __LINE__); - } - restartjob(jp); - INTOFF; - status = waitforjob(jp); - INTON; - return status; -} - -static void -set_curjob(struct job *jp, int mode) -{ - struct job *jp1, *jp2; - int i, ji; - - ji = jp - jobtab; - - /* first remove from list */ - if (ji == curjob) - curjob = jp->prev_job; - else { - for (i = 0; i < njobs; i++) { - if (jobtab[i].prev_job != ji) - continue; - jobtab[i].prev_job = jp->prev_job; - break; - } - } - - /* Then re-insert in correct position */ - switch (mode) { - case 0: /* job being deleted */ - jp->prev_job = -1; - break; - case 1: /* newly created job or backgrounded job, - put after all stopped jobs. */ - if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) { - for (jp1 = jobtab + curjob; ; jp1 = jp2) { - if (jp1->prev_job == -1) - break; - jp2 = jobtab + jp1->prev_job; - if (jp2->state != JOBSTOPPED) - break; - } - jp->prev_job = jp1->prev_job; - jp1->prev_job = ji; - break; - } - /* FALLTHROUGH */ - case 2: /* newly stopped job - becomes curjob */ - jp->prev_job = curjob; - curjob = ji; - break; - } -} - -int -bgcmd(int argc, char **argv) -{ - struct job *jp; - int i; - - nextopt(""); - do { - jp = getjob(*argptr, 0); - if (jp->jobctl == 0) - error("job not created under job control"); - set_curjob(jp, 1); - out1fmt("[%ld] %s", (long)(jp - jobtab + 1), jp->ps[0].cmd); - for (i = 1; i < jp->nprocs; i++) - out1fmt(" | %s", jp->ps[i].cmd ); - out1c('\n'); - flushall(); - restartjob(jp); - } while (*argptr && *++argptr); - return 0; -} - - -STATIC void -restartjob(struct job *jp) -{ - struct procstat *ps; - int i; - - if (jp->state == JOBDONE) - return; - INTOFF; - for (i = 0; i < jp->nprocs; i++) - if (killpg(jp->ps[i].pid, SIGCONT) != -1) - break; - if (i >= jp->nprocs) - error("Cannot continue job (%s)", strerror(errno)); - for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { - if (WIFSTOPPED(ps->status)) { - ps->status = -1; - jp->state = JOBRUNNING; - } - } - INTON; -} -#endif - -static void -showjob(struct output *out, struct job *jp, int mode) -{ - int procno; - int st; - struct procstat *ps; - int col; - char s[64]; - -#if JOBS - if (mode & SHOW_PGID) { - /* just output process (group) id of pipeline */ - outfmt(out, "%ld\n", (long)jp->ps->pid); - return; - } -#endif - - procno = jp->nprocs; - if (!procno) - return; - - if (mode & SHOW_PID) - mode |= SHOW_MULTILINE; - - if ((procno > 1 && !(mode & SHOW_MULTILINE)) - || (mode & SHOW_SIGNALLED)) { - /* See if we have more than one status to report */ - ps = jp->ps; - st = ps->status; - do { - int st1 = ps->status; - if (st1 != st) - /* yes - need multi-line output */ - mode |= SHOW_MULTILINE; - if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1)) - continue; - if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f) - && st1 != SIGINT && st1 != SIGPIPE)) - mode |= SHOW_ISSIG; - - } while (ps++, --procno); - procno = jp->nprocs; - } - - if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) { - if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) { - TRACE(("showjob: freeing job %d\n", jp - jobtab + 1)); - freejob(jp); - } - return; - } - - for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */ - if (ps == jp->ps) - fmtstr(s, 16, "[%ld] %c ", - (long)(jp - jobtab + 1), -#if JOBS - jp == jobtab + curjob ? '+' : - curjob != -1 && jp == jobtab + - jobtab[curjob].prev_job ? '-' : -#endif - ' '); - else - fmtstr(s, 16, " " ); - col = strlen(s); - if (mode & SHOW_PID) { - fmtstr(s + col, 16, "%ld ", (long)ps->pid); - col += strlen(s + col); - } - if (ps->status == -1) { - scopy("Running", s + col); - } else if (WIFEXITED(ps->status)) { - st = WEXITSTATUS(ps->status); - if (st) - fmtstr(s + col, 16, "Done(%d)", st); - else - fmtstr(s + col, 16, "Done"); - } else { -#if JOBS - if (WIFSTOPPED(ps->status)) - st = WSTOPSIG(ps->status); - else /* WIFSIGNALED(ps->status) */ -#endif - st = WTERMSIG(ps->status); - st &= 0x7f; - if (st < NSIG && sys_siglist[st]) - scopyn(sys_siglist[st], s + col, 32); - else - fmtstr(s + col, 16, "Signal %d", st); - if (WCOREDUMP(ps->status)) { - col += strlen(s + col); - scopyn(" (core dumped)", s + col, 64 - col); - } - } - col += strlen(s + col); - outstr(s, out); - do { - outc(' ', out); - col++; - } while (col < 30); - outstr(ps->cmd, out); - if (mode & SHOW_MULTILINE) { - if (procno > 0) { - outc(' ', out); - outc('|', out); - } - } else { - while (--procno >= 0) - outfmt(out, " | %s", (++ps)->cmd ); - } - outc('\n', out); - } - flushout(out); - jp->changed = 0; - if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) - freejob(jp); -} - - -int -jobscmd(int argc, char **argv) -{ - int mode, m; - int sv = jobs_invalid; - - jobs_invalid = 0; - mode = 0; - while ((m = nextopt("lp"))) - if (m == 'l') - mode = SHOW_PID; - else - mode = SHOW_PGID; - if (*argptr) - do - showjob(out1, getjob(*argptr,0), mode); - while (*++argptr); - else - showjobs(out1, mode); - jobs_invalid = sv; - return 0; -} - - -/* - * Print a list of jobs. If "change" is nonzero, only print jobs whose - * statuses have changed since the last call to showjobs. - * - * If the shell is interrupted in the process of creating a job, the - * result may be a job structure containing zero processes. Such structures - * will be freed here. - */ - -void -showjobs(struct output *out, int mode) -{ - int jobno; - struct job *jp; - int silent = 0, gotpid; - - TRACE(("showjobs(%x) called\n", mode)); - - /* If not even one one job changed, there is nothing to do */ - gotpid = dowait(0, NULL); - while (dowait(0, NULL) > 0) - continue; -#ifdef JOBS - /* - * Check if we are not in our foreground group, and if not - * put us in it. - */ - if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) { - if (tcsetpgrp(ttyfd, getpid()) == -1) - error("Cannot set tty process group (%s) at %d", - strerror(errno), __LINE__); - TRACE(("repaired tty process group\n")); - silent = 1; - } -#endif - if (jobs_invalid) - return; - - for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { - if (!jp->used) - continue; - if (jp->nprocs == 0) { - freejob(jp); - continue; - } - if ((mode & SHOW_CHANGED) && !jp->changed) - continue; - if (silent && jp->changed) { - jp->changed = 0; - continue; - } - showjob(out, jp, mode); - } -} - -/* - * Mark a job structure as unused. - */ - -STATIC void -freejob(struct job *jp) -{ - INTOFF; - if (jp->ps != &jp->ps0) { - ckfree(jp->ps); - jp->ps = &jp->ps0; - } - jp->nprocs = 0; - jp->used = 0; -#if JOBS - set_curjob(jp, 0); -#endif - INTON; -} - - - -int -waitcmd(int argc, char **argv) -{ - struct job *job; - int status, retval = 127; - struct job *jp; - - nextopt(""); - - if (!*argptr) { - /* wait for all jobs */ - jp = jobtab; - if (jobs_invalid) - return 0; - for (;;) { - if (jp >= jobtab + njobs) { - /* no running procs */ - return 0; - } - if (!jp->used || jp->state != JOBRUNNING) { - jp++; - continue; - } - if (dowait(1, (struct job *)NULL) == -1) - return 128 + SIGINT; - jp = jobtab; - } - } - - for (; *argptr; argptr++) { - job = getjob(*argptr, 1); - if (!job) { - retval = 127; - continue; - } - /* loop until process terminated or stopped */ - while (job->state == JOBRUNNING) { - if (dowait(1, (struct job *)NULL) == -1) - return 128 + SIGINT; - } - status = job->ps[job->nprocs].status; - if (WIFEXITED(status)) - retval = WEXITSTATUS(status); -#if JOBS - else if (WIFSTOPPED(status)) - retval = WSTOPSIG(status) + 128; -#endif - else { - /* XXX: limits number of signals */ - retval = WTERMSIG(status) + 128; - } - if (!iflag) - freejob(job); - } - return retval; -} - - - -int -jobidcmd(int argc, char **argv) -{ - struct job *jp; - int i; - - nextopt(""); - jp = getjob(*argptr, 0); - for (i = 0 ; i < jp->nprocs ; ) { - out1fmt("%ld", (long)jp->ps[i].pid); - out1c(++i < jp->nprocs ? ' ' : '\n'); - } - return 0; -} - -int -getjobpgrp(const char *name) -{ - struct job *jp; - - jp = getjob(name, 1); - if (jp == 0) - return 0; - return -jp->ps[0].pid; -} - -/* - * Convert a job name to a job structure. - */ - -STATIC struct job * -getjob(const char *name, int noerror) -{ - int jobno = -1; - struct job *jp; - int pid; - int i; - const char *err_msg = "No such job: %s"; - - if (name == NULL) { -#if JOBS - jobno = curjob; -#endif - err_msg = "No current job"; - } else if (name[0] == '%') { - if (is_number(name + 1)) { - jobno = number(name + 1) - 1; - } else if (!name[2]) { - switch (name[1]) { -#if JOBS - case 0: - case '+': - case '%': - jobno = curjob; - err_msg = "No current job"; - break; - case '-': - jobno = curjob; - if (jobno != -1) - jobno = jobtab[jobno].prev_job; - err_msg = "No previous job"; - break; -#endif - default: - goto check_pattern; - } - } else { - struct job *found; - check_pattern: - found = NULL; - for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { - if (!jp->used || jp->nprocs <= 0) - continue; - if ((name[1] == '?' - && strstr(jp->ps[0].cmd, name + 2)) - || prefix(name + 1, jp->ps[0].cmd)) { - if (found) { - err_msg = "%s: ambiguous"; - found = 0; - break; - } - found = jp; - } - } - if (found) - return found; - } - - } else if (is_number(name)) { - pid = number(name); - for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { - if (jp->used && jp->nprocs > 0 - && jp->ps[jp->nprocs - 1].pid == pid) - return jp; - } - } - - if (!jobs_invalid && jobno >= 0 && jobno < njobs) { - jp = jobtab + jobno; - if (jp->used) - return jp; - } - if (!noerror) - error(err_msg, name); - return 0; -} - - - -/* - * Return a new job structure, - */ - -struct job * -makejob(union node *node, int nprocs) -{ - int i; - struct job *jp; - - if (jobs_invalid) { - for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) { - if (jp->used) - freejob(jp); - } - jobs_invalid = 0; - } - - for (i = njobs, jp = jobtab ; ; jp++) { - if (--i < 0) { - INTOFF; - if (njobs == 0) { - jobtab = ckmalloc(4 * sizeof jobtab[0]); - } else { - jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); - memcpy(jp, jobtab, njobs * sizeof jp[0]); - /* Relocate `ps' pointers */ - for (i = 0; i < njobs; i++) - if (jp[i].ps == &jobtab[i].ps0) - jp[i].ps = &jp[i].ps0; - ckfree(jobtab); - jobtab = jp; - } - jp = jobtab + njobs; - for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); - INTON; - break; - } - if (jp->used == 0) - break; - } - INTOFF; - jp->state = JOBRUNNING; - jp->used = 1; - jp->changed = 0; - jp->nprocs = 0; -#if JOBS - jp->jobctl = jobctl; - set_curjob(jp, 1); -#endif - if (nprocs > 1) { - jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); - } else { - jp->ps = &jp->ps0; - } - INTON; - TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, - jp - jobtab + 1)); - return jp; -} - - -/* - * Fork off a subshell. If we are doing job control, give the subshell its - * own process group. Jp is a job structure that the job is to be added to. - * N is the command that will be evaluated by the child. Both jp and n may - * be NULL. The mode parameter can be one of the following: - * FORK_FG - Fork off a foreground process. - * FORK_BG - Fork off a background process. - * FORK_NOJOB - Like FORK_FG, but don't give the process its own - * process group even if job control is on. - * - * When job control is turned off, background processes have their standard - * input redirected to /dev/null (except for the second and later processes - * in a pipeline). - */ - -int -forkshell(struct job *jp, union node *n, int mode) -{ - int pid; - - TRACE(("forkshell(%%%d, %p, %d) called\n", jp - jobtab, n, mode)); - switch ((pid = fork())) { - case -1: - TRACE(("Fork failed, errno=%d\n", errno)); - INTON; - error("Cannot fork"); - break; - case 0: - forkchild(jp, n, mode, 0); - return 0; - default: - return forkparent(jp, n, mode, pid); - } -} - -int -forkparent(struct job *jp, union node *n, int mode, pid_t pid) -{ - int pgrp; - - if (rootshell && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) - pgrp = pid; - else - pgrp = jp->ps[0].pid; -#ifdef USE_PROCESS_GROUPS - /* This can fail because we are doing it in the child also */ - (void)setpgid(pid, pgrp); -#endif - } - if (mode == FORK_BG) - backgndpid = pid; /* set $! */ - if (jp) { - struct procstat *ps = &jp->ps[jp->nprocs++]; - ps->pid = pid; - ps->status = -1; - ps->cmd[0] = 0; - if (/* iflag && rootshell && */ n) - commandtext(ps, n); - } - TRACE(("In parent shell: child = %d\n", pid)); - return pid; -} - -void -forkchild(struct job *jp, union node *n, int mode, int vforked) -{ - int wasroot; - int pgrp; - const char *devnull = _PATH_DEVNULL; - const char *nullerr = "Can't open %s"; - - wasroot = rootshell; - TRACE(("Child shell %d\n", getpid())); - if (!vforked) - rootshell = 0; - - closescript(vforked); - clear_traps(vforked); -#if JOBS - if (!vforked) - jobctl = 0; /* do job control only in root shell */ - if (wasroot && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) - pgrp = getpid(); - else - pgrp = jp->ps[0].pid; -#ifdef USE_PROCESS_GROUPS - /* This can fail because we are doing it in the parent also */ - (void)setpgid(0, pgrp); - if (mode == FORK_FG) { - if (tcsetpgrp(ttyfd, pgrp) == -1) - error("Cannot set tty process group (%s) at %d", - strerror(errno), __LINE__); - } -#endif - setsignal(SIGTSTP, vforked); - setsignal(SIGTTOU, vforked); - } else if (mode == FORK_BG) { - ignoresig(SIGINT, vforked); - ignoresig(SIGQUIT, vforked); - if ((jp == NULL || jp->nprocs == 0) && - ! fd0_redirected_p ()) { - close(0); - if (open(devnull, O_RDONLY) != 0) - error(nullerr, devnull); - } - } -#else - if (mode == FORK_BG) { - ignoresig(SIGINT, vforked); - ignoresig(SIGQUIT, vforked); - if ((jp == NULL || jp->nprocs == 0) && - ! fd0_redirected_p ()) { - close(0); - if (open(devnull, O_RDONLY) != 0) - error(nullerr, devnull); - } - } -#endif - if (wasroot && iflag) { - setsignal(SIGINT, vforked); - setsignal(SIGQUIT, vforked); - setsignal(SIGTERM, vforked); - } - - if (!vforked) - jobs_invalid = 1; -} - -/* - * Wait for job to finish. - * - * Under job control we have the problem that while a child process is - * running interrupts generated by the user are sent to the child but not - * to the shell. This means that an infinite loop started by an inter- - * active user may be hard to kill. With job control turned off, an - * interactive user may place an interactive program inside a loop. If - * the interactive program catches interrupts, the user doesn't want - * these interrupts to also abort the loop. The approach we take here - * is to have the shell ignore interrupt signals while waiting for a - * forground process to terminate, and then send itself an interrupt - * signal if the child process was terminated by an interrupt signal. - * Unfortunately, some programs want to do a bit of cleanup and then - * exit on interrupt; unless these processes terminate themselves by - * sending a signal to themselves (instead of calling exit) they will - * confuse this approach. - */ - -int -waitforjob(struct job *jp) -{ -#if JOBS - int mypgrp = getpgrp(); -#endif - int status; - int st; - - INTOFF; - TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); - while (jp->state == JOBRUNNING) { - dowait(1, jp); - } -#if JOBS - if (jp->jobctl) { - if (tcsetpgrp(ttyfd, mypgrp) == -1) - error("Cannot set tty process group (%s) at %d", - strerror(errno), __LINE__); - } - if (jp->state == JOBSTOPPED && curjob != jp - jobtab) - set_curjob(jp, 2); -#endif - status = jp->ps[jp->nprocs - 1].status; - /* convert to 8 bits */ - if (WIFEXITED(status)) - st = WEXITSTATUS(status); -#if JOBS - else if (WIFSTOPPED(status)) - st = WSTOPSIG(status) + 128; -#endif - else - st = WTERMSIG(status) + 128; - TRACE(("waitforjob: job %d, nproc %d, status %x, st %x\n", - jp - jobtab + 1, jp->nprocs, status, st )); -#if JOBS - if (jp->jobctl) { - /* - * This is truly gross. - * If we're doing job control, then we did a TIOCSPGRP which - * caused us (the shell) to no longer be in the controlling - * session -- so we wouldn't have seen any ^C/SIGINT. So, we - * intuit from the subprocess exit status whether a SIGINT - * occurred, and if so interrupt ourselves. Yuck. - mycroft - */ - if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) - raise(SIGINT); - } -#endif - if (! JOBS || jp->state == JOBDONE) - freejob(jp); - INTON; - return st; -} - - - -/* - * Wait for a process to terminate. - */ - -STATIC int -dowait(int block, struct job *job) -{ - int pid; - int status; - struct procstat *sp; - struct job *jp; - struct job *thisjob; - int done; - int stopped; - extern volatile char gotsig[]; - - TRACE(("dowait(%d) called\n", block)); - do { - pid = waitproc(block, job, &status); - TRACE(("wait returns pid %d, status %d\n", pid, status)); - } while (pid == -1 && errno == EINTR && gotsig[SIGINT - 1] == 0); - if (pid <= 0) - return pid; - INTOFF; - thisjob = NULL; - for (jp = jobtab ; jp < jobtab + njobs ; jp++) { - if (jp->used) { - done = 1; - stopped = 1; - for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { - if (sp->pid == -1) - continue; - if (sp->pid == pid) { - TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - jobtab + 1, pid, sp->status, status)); - sp->status = status; - thisjob = jp; - } - if (sp->status == -1) - stopped = 0; - else if (WIFSTOPPED(sp->status)) - done = 0; - } - if (stopped) { /* stopped or done */ - int state = done ? JOBDONE : JOBSTOPPED; - if (jp->state != state) { - TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); - jp->state = state; -#if JOBS - if (done) - set_curjob(jp, 0); -#endif - } - } - } - } - - if (thisjob && thisjob->state != JOBRUNNING) { - int mode = 0; - if (!rootshell || !iflag) - mode = SHOW_SIGNALLED; - if (job == thisjob) - mode = SHOW_SIGNALLED | SHOW_NO_FREE; - if (mode) - showjob(out2, thisjob, mode); - else { - TRACE(("Not printing status, rootshell=%d, job=%p\n", - rootshell, job)); - thisjob->changed = 1; - } - } - - INTON; - return pid; -} - - - -/* - * Do a wait system call. If job control is compiled in, we accept - * stopped processes. If block is zero, we return a value of zero - * rather than blocking. - * - * System V doesn't have a non-blocking wait system call. It does - * have a SIGCLD signal that is sent to a process when one of it's - * children dies. The obvious way to use SIGCLD would be to install - * a handler for SIGCLD which simply bumped a counter when a SIGCLD - * was received, and have waitproc bump another counter when it got - * the status of a process. Waitproc would then know that a wait - * system call would not block if the two counters were different. - * This approach doesn't work because if a process has children that - * have not been waited for, System V will send it a SIGCLD when it - * installs a signal handler for SIGCLD. What this means is that when - * a child exits, the shell will be sent SIGCLD signals continuously - * until is runs out of stack space, unless it does a wait call before - * restoring the signal handler. The code below takes advantage of - * this (mis)feature by installing a signal handler for SIGCLD and - * then checking to see whether it was called. If there are any - * children to be waited for, it will be. - * - * If neither SYSV nor BSD is defined, we don't implement nonblocking - * waits at all. In this case, the user will not be informed when - * a background process until the next time she runs a real program - * (as opposed to running a builtin command or just typing return), - * and the jobs command may give out of date information. - */ - -#ifdef SYSV -STATIC int gotsigchild; - -STATIC int onsigchild() { - gotsigchild = 1; -} -#endif - - -STATIC int -waitproc(int block, struct job *jp, int *status) -{ -#ifdef BSD - int flags = 0; - -#if JOBS - if (jp != NULL && jp->jobctl) - flags |= WUNTRACED; -#endif - if (block == 0) - flags |= WNOHANG; - return wait3(status, flags, (struct rusage *)NULL); -#else -#ifdef SYSV - int (*save)(); - - if (block == 0) { - gotsigchild = 0; - save = signal(SIGCLD, onsigchild); - signal(SIGCLD, save); - if (gotsigchild == 0) - return 0; - } - return wait(status); -#else - if (block == 0) - return 0; - return wait(status); -#endif -#endif -} - -/* - * return 1 if there are stopped jobs, otherwise 0 - */ -int job_warning = 0; -int -stoppedjobs(void) -{ - int jobno; - struct job *jp; - - if (job_warning || jobs_invalid) - return (0); - for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { - if (jp->used == 0) - continue; - if (jp->state == JOBSTOPPED) { - out2str("You have stopped jobs.\n"); - job_warning = 2; - return (1); - } - } - - return (0); -} - -/* - * Return a string identifying a command (to be printed by the - * jobs command). - */ - -STATIC char *cmdnextc; -STATIC int cmdnleft; - -void -commandtext(struct procstat *ps, union node *n) -{ - int len; - - cmdnextc = ps->cmd; - if (iflag || mflag || sizeof ps->cmd < 100) - len = sizeof(ps->cmd); - else - len = sizeof(ps->cmd) / 10; - cmdnleft = len; - cmdtxt(n); - if (cmdnleft <= 0) { - char *p = ps->cmd + len - 4; - p[0] = '.'; - p[1] = '.'; - p[2] = '.'; - p[3] = 0; - } else - *cmdnextc = '\0'; - TRACE(("commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n", - ps->cmd, cmdnextc, cmdnleft, ps->cmd)); -} - - -STATIC void -cmdtxt(union node *n) -{ - union node *np; - struct nodelist *lp; - const char *p; - int i; - char s[2]; - - if (n == NULL || cmdnleft <= 0) - return; - switch (n->type) { - case NSEMI: - cmdtxt(n->nbinary.ch1); - cmdputs("; "); - cmdtxt(n->nbinary.ch2); - break; - case NAND: - cmdtxt(n->nbinary.ch1); - cmdputs(" && "); - cmdtxt(n->nbinary.ch2); - break; - case NOR: - cmdtxt(n->nbinary.ch1); - cmdputs(" || "); - cmdtxt(n->nbinary.ch2); - break; - case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - cmdtxt(lp->n); - if (lp->next) - cmdputs(" | "); - } - break; - case NSUBSHELL: - cmdputs("("); - cmdtxt(n->nredir.n); - cmdputs(")"); - break; - case NREDIR: - case NBACKGND: - cmdtxt(n->nredir.n); - break; - case NIF: - cmdputs("if "); - cmdtxt(n->nif.test); - cmdputs("; then "); - cmdtxt(n->nif.ifpart); - if (n->nif.elsepart) { - cmdputs("; else "); - cmdtxt(n->nif.elsepart); - } - cmdputs("; fi"); - break; - case NWHILE: - cmdputs("while "); - goto until; - case NUNTIL: - cmdputs("until "); -until: - cmdtxt(n->nbinary.ch1); - cmdputs("; do "); - cmdtxt(n->nbinary.ch2); - cmdputs("; done"); - break; - case NFOR: - cmdputs("for "); - cmdputs(n->nfor.var); - cmdputs(" in "); - cmdlist(n->nfor.args, 1); - cmdputs("; do "); - cmdtxt(n->nfor.body); - cmdputs("; done"); - break; - case NCASE: - cmdputs("case "); - cmdputs(n->ncase.expr->narg.text); - cmdputs(" in "); - for (np = n->ncase.cases; np; np = np->nclist.next) { - cmdtxt(np->nclist.pattern); - cmdputs(") "); - cmdtxt(np->nclist.body); - cmdputs(";; "); - } - cmdputs("esac"); - break; - case NDEFUN: - cmdputs(n->narg.text); - cmdputs("() { ... }"); - break; - case NCMD: - cmdlist(n->ncmd.args, 1); - cmdlist(n->ncmd.redirect, 0); - break; - case NARG: - cmdputs(n->narg.text); - break; - case NTO: - p = ">"; i = 1; goto redir; - case NCLOBBER: - p = ">|"; i = 1; goto redir; - case NAPPEND: - p = ">>"; i = 1; goto redir; - case NTOFD: - p = ">&"; i = 1; goto redir; - case NFROM: - p = "<"; i = 0; goto redir; - case NFROMFD: - p = "<&"; i = 0; goto redir; - case NFROMTO: - p = "<>"; i = 0; goto redir; -redir: - if (n->nfile.fd != i) { - s[0] = n->nfile.fd + '0'; - s[1] = '\0'; - cmdputs(s); - } - cmdputs(p); - if (n->type == NTOFD || n->type == NFROMFD) { - s[0] = n->ndup.dupfd + '0'; - s[1] = '\0'; - cmdputs(s); - } else { - cmdtxt(n->nfile.fname); - } - break; - case NHERE: - case NXHERE: - cmdputs("<<..."); - break; - default: - cmdputs("???"); - break; - } -} - -STATIC void -cmdlist(union node *np, int sep) -{ - for (; np; np = np->narg.next) { - if (!sep) - cmdputs(" "); - cmdtxt(np); - if (sep && np->narg.next) - cmdputs(" "); - } -} - - -STATIC void -cmdputs(const char *s) -{ - const char *p, *str = 0; - char c, cc[2] = " "; - char *nextc; - int nleft; - int subtype = 0; - int quoted = 0; - static char vstype[16][4] = { "", "}", "-", "+", "?", "=", - "#", "##", "%", "%%" }; - - p = s; - nextc = cmdnextc; - nleft = cmdnleft; - while (nleft > 0 && (c = *p++) != 0) { - switch (c) { - case CTLESC: - c = *p++; - break; - case CTLVAR: - subtype = *p++; - if ((subtype & VSTYPE) == VSLENGTH) - str = "${#"; - else - str = "${"; - if (!(subtype & VSQUOTE) != !(quoted & 1)) { - quoted ^= 1; - c = '"'; - } else - c = *str++; - break; - case CTLENDVAR: - if (quoted & 1) { - c = '"'; - str = "}"; - } else - c = '}'; - quoted >>= 1; - subtype = 0; - break; - case CTLBACKQ: - c = '$'; - str = "(...)"; - break; - case CTLBACKQ+CTLQUOTE: - c = '"'; - str = "$(...)\""; - break; - case CTLARI: - c = '$'; - str = "(("; - break; - case CTLENDARI: - c = ')'; - str = ")"; - break; - case CTLQUOTEMARK: - quoted ^= 1; - c = '"'; - break; - case '=': - if (subtype == 0) - break; - str = vstype[subtype & VSTYPE]; - if (subtype & VSNUL) - c = ':'; - else - c = *str++; - if (c != '}') - quoted <<= 1; - break; - case '\'': - case '\\': - case '"': - case '$': - /* These can only happen inside quotes */ - cc[0] = c; - str = cc; - c = '\\'; - break; - default: - break; - } - do { - *nextc++ = c; - } while (--nleft > 0 && str && (c = *str++)); - str = 0; - } - if ((quoted & 1) && nleft) { - *nextc++ = '"'; - nleft--; - } - cmdnleft = nleft; - cmdnextc = nextc; -} diff --git a/sh/jobs.h b/sh/jobs.h deleted file mode 100644 index 47e76c2..0000000 --- a/sh/jobs.h +++ /dev/null @@ -1,106 +0,0 @@ -/* $NetBSD: jobs.h,v 1.19 2003/11/27 21:16:14 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)jobs.h 8.2 (Berkeley) 5/4/95 - */ - -#include "output.h" - -/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ -#define FORK_FG 0 -#define FORK_BG 1 -#define FORK_NOJOB 2 - -/* mode flags for showjob(s) */ -#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */ -#define SHOW_MULTILINE 0x02 /* one line per process */ -#define SHOW_PID 0x04 /* include process pid */ -#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ -#define SHOW_SIGNALLED 0x10 /* only if stopped/exited on signal */ -#define SHOW_ISSIG 0x20 /* job was signalled */ -#define SHOW_NO_FREE 0x40 /* do not free job */ - - -/* - * A job structure contains information about a job. A job is either a - * single process or a set of processes contained in a pipeline. In the - * latter case, pidlist will be non-NULL, and will point to a -1 terminated - * array of pids. - */ -#define MAXCMDTEXT 200 - -struct procstat { - pid_t pid; /* process id */ - int status; /* last process status from wait() */ - char cmd[MAXCMDTEXT];/* text of command being run */ -}; - -struct job { - struct procstat ps0; /* status of process */ - struct procstat *ps; /* status or processes when more than one */ - int nprocs; /* number of processes */ - pid_t pgrp; /* process group of this job */ - char state; -#define JOBRUNNING 0 /* at least one proc running */ -#define JOBSTOPPED 1 /* all procs are stopped */ -#define JOBDONE 2 /* all procs are completed */ - char used; /* true if this entry is in used */ - char changed; /* true if status has changed */ -#if JOBS - char jobctl; /* job running under job control */ - int prev_job; /* previous job index */ -#endif -}; - -extern pid_t backgndpid; /* pid of last background process */ -extern int job_warning; /* user was warned about stopped jobs */ - -void setjobctl(int); -int fgcmd(int, char **); -int bgcmd(int, char **); -int jobscmd(int, char **); -void showjobs(struct output *, int); -int waitcmd(int, char **); -int jobidcmd(int, char **); -struct job *makejob(union node *, int); -int forkshell(struct job *, union node *, int); -void forkchild(struct job *, union node *, int, int); -int forkparent(struct job *, union node *, int, pid_t); -int waitforjob(struct job *); -int stoppedjobs(void); -void commandtext(struct procstat *, union node *); -int getjobpgrp(const char *); - -#if ! JOBS -#define setjobctl(on) /* do nothing */ -#endif diff --git a/sh/machdep.h b/sh/machdep.h deleted file mode 100644 index 14e803b..0000000 --- a/sh/machdep.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)machdep.h 8.2 (Berkeley) 5/4/95 - */ - -/* - * Most machines require the value returned from malloc to be aligned - * in some way. The following macro will get this right on many machines. - */ - -#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1) -/* - * It appears that grabstackstr() will barf with such alignments - * because stalloc() will return a string allocated in a new stackblock. - */ -#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) diff --git a/sh/main.c b/sh/main.c deleted file mode 100644 index 43b154f..0000000 --- a/sh/main.c +++ /dev/null @@ -1,394 +0,0 @@ -/* $NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\ - The Regents of the University of California. All rights reserved.\n"); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95"; -#else -__RCSID("$NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $"); -#endif -#endif /* not lint */ - -#include <errno.h> -#include <stdio.h> -#include <signal.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> - - -#include "shell.h" -#include "main.h" -#include "options.h" -#include "output.h" -#include "parser.h" -#include "nodes.h" -#include "expand.h" -#include "eval.h" -#include "jobs.h" -#include "input.h" -#include "trap.h" -#include "var.h" -#include "show.h" -#include "memalloc.h" -#include "error.h" -#include "init.h" -#include "mystring.h" -#include "exec.h" -#include "cd.h" - -#define PROFILE 0 - -int rootpid; -int rootshell; -STATIC union node *curcmd; -STATIC union node *prevcmd; -#if PROFILE -short profile_buf[16384]; -extern int etext(); -#endif - -STATIC void read_profile(const char *); -STATIC char *find_dot_file(char *); -int main(int, char **); - -/* - * Main routine. We initialize things, parse the arguments, execute - * profiles if we're a login shell, and then call cmdloop to execute - * commands. The setjmp call sets up the location to jump to when an - * exception occurs. When an exception occurs the variable "state" - * is used to figure out how far we had gotten. - */ - -int -main(int argc, char **argv) -{ - struct jmploc jmploc; - struct stackmark smark; - volatile int state; - char *shinit; - -#if PROFILE - monitor(4, etext, profile_buf, sizeof profile_buf, 50); -#endif - state = 0; - if (setjmp(jmploc.loc)) { - /* - * When a shell procedure is executed, we raise the - * exception EXSHELLPROC to clean up before executing - * the shell procedure. - */ - switch (exception) { - case EXSHELLPROC: - rootpid = getpid(); - rootshell = 1; - minusc = NULL; - state = 3; - break; - - case EXEXEC: - exitstatus = exerrno; - break; - - case EXERROR: - exitstatus = 2; - break; - - default: - break; - } - - if (exception != EXSHELLPROC) { - if (state == 0 || iflag == 0 || ! rootshell) - exitshell(exitstatus); - } - reset(); - if (exception == EXINT -#if ATTY - && (! attyset() || equal(termval(), "emacs")) -#endif - ) { - out2c('\n'); - flushout(&errout); - } - popstackmark(&smark); - FORCEINTON; /* enable interrupts */ - if (state == 1) - goto state1; - else if (state == 2) - goto state2; - else if (state == 3) - goto state3; - else - goto state4; - } - handler = &jmploc; -#ifdef DEBUG -#if DEBUG == 2 - debug = 1; -#endif - opentrace(); - trputs("Shell args: "); trargs(argv); -#endif - rootpid = getpid(); - rootshell = 1; - init(); - setstackmark(&smark); - procargs(argc, argv); - if (argv[0] && argv[0][0] == '-') { - state = 1; - read_profile("/etc/profile"); -state1: - state = 2; - read_profile(".profile"); - } -state2: - state = 3; - if (getuid() == geteuid() && getgid() == getegid()) { - if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { - state = 3; - read_profile(shinit); - } - } -state3: - state = 4; - if (sflag == 0 || minusc) { - static int sigs[] = { - SIGINT, SIGQUIT, SIGHUP, -#ifdef SIGTSTP - SIGTSTP, -#endif - SIGPIPE - }; -#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) - int i; - - for (i = 0; i < SIGSSIZE; i++) - setsignal(sigs[i], 0); - } - - if (minusc) - evalstring(minusc, 0); - - if (sflag || minusc == NULL) { -state4: /* XXX ??? - why isn't this before the "if" statement */ - cmdloop(1); - } -#if PROFILE - monitor(0); -#endif - exitshell(exitstatus); - /* NOTREACHED */ -} - - -/* - * Read and execute commands. "Top" is nonzero for the top level command - * loop; it turns on prompting if the shell is interactive. - */ - -void -cmdloop(int top) -{ - union node *n; - struct stackmark smark; - int inter; - int numeof = 0; - - TRACE(("cmdloop(%d) called\n", top)); - setstackmark(&smark); - for (;;) { - if (pendingsigs) - dotrap(); - inter = 0; - if (iflag && top) { - inter = 1; - showjobs(out2, SHOW_CHANGED); - flushout(&errout); - } - n = parsecmd(inter); - /* showtree(n); DEBUG */ - if (n == NEOF) { - if (!top || numeof >= 50) - break; - if (!stoppedjobs()) { - if (!Iflag) - break; - out2str("\nUse \"exit\" to leave shell.\n"); - } - numeof++; - } else if (n != NULL && nflag == 0) { - job_warning = (job_warning == 2) ? 1 : 0; - numeof = 0; - evaltree(n, 0); - } - popstackmark(&smark); - setstackmark(&smark); - if (evalskip == SKIPFILE) { - evalskip = 0; - break; - } - } - popstackmark(&smark); -} - - - -/* - * Read /etc/profile or .profile. Return on error. - */ - -STATIC void -read_profile(const char *name) -{ - int fd; - int xflag_set = 0; - int vflag_set = 0; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - INTON; - if (fd < 0) - return; - /* -q turns off -x and -v just when executing init files */ - if (qflag) { - if (xflag) - xflag = 0, xflag_set = 1; - if (vflag) - vflag = 0, vflag_set = 1; - } - cmdloop(0); - if (qflag) { - if (xflag_set) - xflag = 1; - if (vflag_set) - vflag = 1; - } - popfile(); -} - - - -/* - * Read a file containing shell functions. - */ - -void -readcmdfile(char *name) -{ - int fd; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - else - error("Can't open %s", name); - INTON; - cmdloop(0); - popfile(); -} - - - -/* - * Take commands from a file. To be compatible we should do a path - * search for the file, which is necessary to find sub-commands. - */ - - -STATIC char * -find_dot_file(char *basename) -{ - char *fullname; - const char *path = pathval(); - struct stat statb; - - /* don't try this for absolute or relative paths */ - if (strchr(basename, '/')) - return basename; - - while ((fullname = padvance(&path, basename)) != NULL) { - if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { - /* - * Don't bother freeing here, since it will - * be freed by the caller. - */ - return fullname; - } - stunalloc(fullname); - } - - /* not found in the PATH */ - error("%s: not found", basename); - /* NOTREACHED */ -} - -int -dotcmd(int argc, char **argv) -{ - exitstatus = 0; - - if (argc >= 2) { /* That's what SVR2 does */ - char *fullname; - struct stackmark smark; - - setstackmark(&smark); - fullname = find_dot_file(argv[1]); - setinputfile(fullname, 1); - commandname = fullname; - cmdloop(0); - popfile(); - popstackmark(&smark); - } - return exitstatus; -} - - -int -exitcmd(int argc, char **argv) -{ - if (stoppedjobs()) - return 0; - if (argc > 1) - exitstatus = number(argv[1]); - exitshell(exitstatus); - /* NOTREACHED */ -} diff --git a/sh/main.h b/sh/main.h deleted file mode 100644 index d198e2d..0000000 --- a/sh/main.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $NetBSD: main.h,v 1.10 2003/08/07 09:05:34 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)main.h 8.2 (Berkeley) 5/4/95 - */ - -extern int rootpid; /* pid of main shell */ -extern int rootshell; /* true if we aren't a child of the main shell */ - -void readcmdfile(char *); -void cmdloop(int); -int dotcmd(int, char **); -int exitcmd(int, char **); diff --git a/sh/memalloc.c b/sh/memalloc.c deleted file mode 100644 index 07c14db..0000000 --- a/sh/memalloc.c +++ /dev/null @@ -1,307 +0,0 @@ -/* $NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> -#include <unistd.h> - -#include "shell.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" -#include "machdep.h" -#include "mystring.h" - -/* - * Like malloc, but returns an error when out of space. - */ - -pointer -ckmalloc(int nbytes) -{ - pointer p; - - p = malloc(nbytes); - if (p == NULL) - error("Out of space"); - return p; -} - - -/* - * Same for realloc. - */ - -pointer -ckrealloc(pointer p, int nbytes) -{ - p = realloc(p, nbytes); - if (p == NULL) - error("Out of space"); - return p; -} - - -/* - * Make a copy of a string in safe storage. - */ - -char * -savestr(const char *s) -{ - char *p; - - p = ckmalloc(strlen(s) + 1); - scopy(s, p); - return p; -} - - -/* - * Parse trees for commands are allocated in lifo order, so we use a stack - * to make this more efficient, and also to avoid all sorts of exception - * handling code to handle interrupts in the middle of a parse. - * - * The size 504 was chosen because the Ultrix malloc handles that size - * well. - */ - -#define MINSIZE 504 /* minimum size of a block */ - -struct stack_block { - struct stack_block *prev; - char space[MINSIZE]; -}; - -struct stack_block stackbase; -struct stack_block *stackp = &stackbase; -struct stackmark *markp; -char *stacknxt = stackbase.space; -int stacknleft = MINSIZE; -int sstrnleft; -int herefd = -1; - -pointer -stalloc(int nbytes) -{ - char *p; - - nbytes = SHELL_ALIGN(nbytes); - if (nbytes > stacknleft) { - int blocksize; - struct stack_block *sp; - - blocksize = nbytes; - if (blocksize < MINSIZE) - blocksize = MINSIZE; - INTOFF; - sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); - sp->prev = stackp; - stacknxt = sp->space; - stacknleft = blocksize; - stackp = sp; - INTON; - } - p = stacknxt; - stacknxt += nbytes; - stacknleft -= nbytes; - return p; -} - - -void -stunalloc(pointer p) -{ - if (p == NULL) { /*DEBUG */ - write(2, "stunalloc\n", 10); - abort(); - } - stacknleft += stacknxt - (char *)p; - stacknxt = p; -} - - - -void -setstackmark(struct stackmark *mark) -{ - mark->stackp = stackp; - mark->stacknxt = stacknxt; - mark->stacknleft = stacknleft; - mark->marknext = markp; - markp = mark; -} - - -void -popstackmark(struct stackmark *mark) -{ - struct stack_block *sp; - - INTOFF; - markp = mark->marknext; - while (stackp != mark->stackp) { - sp = stackp; - stackp = sp->prev; - ckfree(sp); - } - stacknxt = mark->stacknxt; - stacknleft = mark->stacknleft; - INTON; -} - - -/* - * When the parser reads in a string, it wants to stick the string on the - * stack and only adjust the stack pointer when it knows how big the - * string is. Stackblock (defined in stack.h) returns a pointer to a block - * of space on top of the stack and stackblocklen returns the length of - * this block. Growstackblock will grow this space by at least one byte, - * possibly moving it (like realloc). Grabstackblock actually allocates the - * part of the block that has been used. - */ - -void -growstackblock(void) -{ - int newlen = SHELL_ALIGN(stacknleft * 2 + 100); - - if (stacknxt == stackp->space && stackp != &stackbase) { - struct stack_block *oldstackp; - struct stackmark *xmark; - struct stack_block *sp; - - INTOFF; - oldstackp = stackp; - sp = stackp; - stackp = sp->prev; - sp = ckrealloc((pointer)sp, - sizeof(struct stack_block) - MINSIZE + newlen); - sp->prev = stackp; - stackp = sp; - stacknxt = sp->space; - stacknleft = newlen; - - /* - * Stack marks pointing to the start of the old block - * must be relocated to point to the new block - */ - xmark = markp; - while (xmark != NULL && xmark->stackp == oldstackp) { - xmark->stackp = stackp; - xmark->stacknxt = stacknxt; - xmark->stacknleft = stacknleft; - xmark = xmark->marknext; - } - INTON; - } else { - char *oldspace = stacknxt; - int oldlen = stacknleft; - char *p = stalloc(newlen); - - (void)memcpy(p, oldspace, oldlen); - stacknxt = p; /* free the space */ - stacknleft += newlen; /* we just allocated */ - } -} - -void -grabstackblock(int len) -{ - len = SHELL_ALIGN(len); - stacknxt += len; - stacknleft -= len; -} - -/* - * The following routines are somewhat easier to use than the above. - * The user declares a variable of type STACKSTR, which may be declared - * to be a register. The macro STARTSTACKSTR initializes things. Then - * the user uses the macro STPUTC to add characters to the string. In - * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is - * grown as necessary. When the user is done, she can just leave the - * string there and refer to it using stackblock(). Or she can allocate - * the space for it using grabstackstr(). If it is necessary to allow - * someone else to use the stack temporarily and then continue to grow - * the string, the user should use grabstack to allocate the space, and - * then call ungrabstr(p) to return to the previous mode of operation. - * - * USTPUTC is like STPUTC except that it doesn't check for overflow. - * CHECKSTACKSPACE can be called before USTPUTC to ensure that there - * is space for at least one character. - */ - -char * -growstackstr(void) -{ - int len = stackblocksize(); - if (herefd >= 0 && len >= 1024) { - xwrite(herefd, stackblock(), len); - sstrnleft = len - 1; - return stackblock(); - } - growstackblock(); - sstrnleft = stackblocksize() - len - 1; - return stackblock() + len; -} - -/* - * Called from CHECKSTRSPACE. - */ - -char * -makestrspace(void) -{ - int len = stackblocksize() - sstrnleft; - growstackblock(); - sstrnleft = stackblocksize() - len; - return stackblock() + len; -} - -void -ungrabstackstr(char *s, char *p) -{ - stacknleft += stacknxt - s; - stacknxt = s; - sstrnleft = stacknleft - (p - s); - -} diff --git a/sh/memalloc.h b/sh/memalloc.h deleted file mode 100644 index e793880..0000000 --- a/sh/memalloc.h +++ /dev/null @@ -1,77 +0,0 @@ -/* $NetBSD: memalloc.h,v 1.14 2003/08/07 09:05:34 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 - */ - -struct stackmark { - struct stack_block *stackp; - char *stacknxt; - int stacknleft; - struct stackmark *marknext; -}; - - -extern char *stacknxt; -extern int stacknleft; -extern int sstrnleft; -extern int herefd; - -pointer ckmalloc(int); -pointer ckrealloc(pointer, int); -char *savestr(const char *); -pointer stalloc(int); -void stunalloc(pointer); -void setstackmark(struct stackmark *); -void popstackmark(struct stackmark *); -void growstackblock(void); -void grabstackblock(int); -char *growstackstr(void); -char *makestrspace(void); -void ungrabstackstr(char *, char *); - - - -#define stackblock() stacknxt -#define stackblocksize() stacknleft -#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() -#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) -#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); } -#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) -#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) -#define STUNPUTC(p) (++sstrnleft, --p) -#define STTOPC(p) p[-1] -#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) -#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) - -#define ckfree(p) free((pointer)(p)) diff --git a/sh/miscbltin.c b/sh/miscbltin.c deleted file mode 100644 index d89029a..0000000 --- a/sh/miscbltin.c +++ /dev/null @@ -1,445 +0,0 @@ -/* $NetBSD: miscbltin.c,v 1.34.2.1 2005/04/07 11:34:20 tron Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: miscbltin.c,v 1.34.2.1 2005/04/07 11:34:20 tron Exp $"); -#endif -#endif /* not lint */ - -/* - * Miscelaneous builtins. - */ - -#include <sys/types.h> /* quad_t */ -#include <sys/param.h> /* BSD4_4 */ -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <unistd.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - -#include "shell.h" -#include "options.h" -#include "var.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" -#include "miscbltin.h" -#include "mystring.h" - -#undef rflag - - - -/* - * The read builtin. - * Backslahes escape the next char unless -r is specified. - * - * This uses unbuffered input, which may be avoidable in some cases. - * - * Note that if IFS=' :' then read x y should work so that: - * 'a b' x='a', y='b' - * ' a b ' x='a', y='b' - * ':b' x='', y='b' - * ':' x='', y='' - * '::' x='', y='' - * ': :' x='', y='' - * ':::' x='', y='::' - * ':b c:' x='', y='b c:' - */ - -int -readcmd(int argc, char **argv) -{ - char **ap; - char c; - int rflag; - char *prompt; - const char *ifs; - char *p; - int startword; - int status; - int i; - int is_ifs; - int saveall = 0; - - rflag = 0; - prompt = NULL; - while ((i = nextopt("p:r")) != '\0') { - if (i == 'p') - prompt = optionarg; - else - rflag = 1; - } - - if (prompt && isatty(0)) { - out2str(prompt); - flushall(); - } - - if (*(ap = argptr) == NULL) - error("arg count"); - - if ((ifs = bltinlookup("IFS", 1)) == NULL) - ifs = " \t\n"; - - status = 0; - startword = 2; - STARTSTACKSTR(p); - for (;;) { - if (read(0, &c, 1) != 1) { - status = 1; - break; - } - if (c == '\0') - continue; - if (c == '\\' && !rflag) { - if (read(0, &c, 1) != 1) { - status = 1; - break; - } - if (c != '\n') - STPUTC(c, p); - continue; - } - if (c == '\n') - break; - if (strchr(ifs, c)) - is_ifs = strchr(" \t\n", c) ? 1 : 2; - else - is_ifs = 0; - - if (startword != 0) { - if (is_ifs == 1) { - /* Ignore leading IFS whitespace */ - if (saveall) - STPUTC(c, p); - continue; - } - if (is_ifs == 2 && startword == 1) { - /* Only one non-whitespace IFS per word */ - startword = 2; - if (saveall) - STPUTC(c, p); - continue; - } - } - - if (is_ifs == 0) { - /* append this character to the current variable */ - startword = 0; - if (saveall) - /* Not just a spare terminator */ - saveall++; - STPUTC(c, p); - continue; - } - - /* end of variable... */ - startword = is_ifs; - - if (ap[1] == NULL) { - /* Last variable needs all IFS chars */ - saveall++; - STPUTC(c, p); - continue; - } - - STACKSTRNUL(p); - setvar(*ap, stackblock(), 0); - ap++; - STARTSTACKSTR(p); - } - STACKSTRNUL(p); - - /* Remove trailing IFS chars */ - for (; stackblock() <= --p; *p = 0) { - if (!strchr(ifs, *p)) - break; - if (strchr(" \t\n", *p)) - /* Always remove whitespace */ - continue; - if (saveall > 1) - /* Don't remove non-whitespace unless it was naked */ - break; - } - setvar(*ap, stackblock(), 0); - - /* Set any remaining args to "" */ - while (*++ap != NULL) - setvar(*ap, nullstr, 0); - return status; -} - - - -int -umaskcmd(int argc, char **argv) -{ - char *ap; - int mask; - int i; - int symbolic_mode = 0; - - while ((i = nextopt("S")) != '\0') { - symbolic_mode = 1; - } - - INTOFF; - mask = umask(0); - umask(mask); - INTON; - - if ((ap = *argptr) == NULL) { - if (symbolic_mode) { - char u[4], g[4], o[4]; - - i = 0; - if ((mask & S_IRUSR) == 0) - u[i++] = 'r'; - if ((mask & S_IWUSR) == 0) - u[i++] = 'w'; - if ((mask & S_IXUSR) == 0) - u[i++] = 'x'; - u[i] = '\0'; - - i = 0; - if ((mask & S_IRGRP) == 0) - g[i++] = 'r'; - if ((mask & S_IWGRP) == 0) - g[i++] = 'w'; - if ((mask & S_IXGRP) == 0) - g[i++] = 'x'; - g[i] = '\0'; - - i = 0; - if ((mask & S_IROTH) == 0) - o[i++] = 'r'; - if ((mask & S_IWOTH) == 0) - o[i++] = 'w'; - if ((mask & S_IXOTH) == 0) - o[i++] = 'x'; - o[i] = '\0'; - - out1fmt("u=%s,g=%s,o=%s\n", u, g, o); - } else { - out1fmt("%.4o\n", mask); - } - } else { - if (isdigit((unsigned char)*ap)) { - mask = 0; - do { - if (*ap >= '8' || *ap < '0') - error("Illegal number: %s", argv[1]); - mask = (mask << 3) + (*ap - '0'); - } while (*++ap != '\0'); - umask(mask); - } else - error("Illegal mode: %s", ap); - } - return 0; -} - -#if 1 -/* - * ulimit builtin - * - * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and - * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with - * ash by J.T. Conklin. - * - * Public domain. - */ - -struct limits { - const char *name; - int cmd; - int factor; /* multiply by to get rlim_{cur,max} values */ - char option; -}; - -static const struct limits limits[] = { -#ifdef RLIMIT_CPU - { "time(seconds)", RLIMIT_CPU, 1, 't' }, -#endif -#ifdef RLIMIT_FSIZE - { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, -#endif -#ifdef RLIMIT_DATA - { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, -#endif -#ifdef RLIMIT_STACK - { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, -#endif -#ifdef RLIMIT_CORE - { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, -#endif -#ifdef RLIMIT_RSS - { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, -#endif -#ifdef RLIMIT_MEMLOCK - { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, -#endif -#ifdef RLIMIT_NPROC - { "process(processes)", RLIMIT_NPROC, 1, 'p' }, -#endif -#ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, -#endif -#ifdef RLIMIT_VMEM - { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, -#endif -#ifdef RLIMIT_SWAP - { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, -#endif -#ifdef RLIMIT_SBSIZE - { "sbsize(bytes)", RLIMIT_SBSIZE, 1, 'b' }, -#endif - { (char *) 0, 0, 0, '\0' } -}; - -int -ulimitcmd(int argc, char **argv) -{ - int c; - rlim_t val = 0; - enum { SOFT = 0x1, HARD = 0x2 } - how = SOFT | HARD; - const struct limits *l; - int set, all = 0; - int optc, what; - struct rlimit limit; - - what = 'f'; - while ((optc = nextopt("HSabtfdsmcnpl")) != '\0') - switch (optc) { - case 'H': - how = HARD; - break; - case 'S': - how = SOFT; - break; - case 'a': - all = 1; - break; - default: - what = optc; - } - - for (l = limits; l->name && l->option != what; l++) - ; - if (!l->name) - error("internal error (%c)", what); - - set = *argptr ? 1 : 0; - if (set) { - char *p = *argptr; - - if (all || argptr[1]) - error("too many arguments"); - if (strcmp(p, "unlimited") == 0) - val = RLIM_INFINITY; - else { - val = (rlim_t) 0; - - while ((c = *p++) >= '0' && c <= '9') - { - val = (val * 10) + (long)(c - '0'); - if ((long)val < 0) - break; - } - if (c) - error("bad number"); - val *= l->factor; - } - } - if (all) { - for (l = limits; l->name; l++) { - getrlimit(l->cmd, &limit); - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - out1fmt("%-20s ", l->name); - if (val == RLIM_INFINITY) - out1fmt("unlimited\n"); - else - { - val /= l->factor; -#ifdef BSD4_4 - out1fmt("%lld\n", (long long) val); -#else - out1fmt("%ld\n", (long) val); -#endif - } - } - return 0; - } - - getrlimit(l->cmd, &limit); - if (set) { - if (how & HARD) - limit.rlim_max = val; - if (how & SOFT) - limit.rlim_cur = val; - if (setrlimit(l->cmd, &limit) < 0) - error("error setting limit (%s)", strerror(errno)); - } else { - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - if (val == RLIM_INFINITY) - out1fmt("unlimited\n"); - else - { - val /= l->factor; -#ifdef BSD4_4 - out1fmt("%lld\n", (long long) val); -#else - out1fmt("%ld\n", (long) val); -#endif - } - } - return 0; -} -#endif diff --git a/sh/miscbltin.h b/sh/miscbltin.h deleted file mode 100644 index 4c12c82..0000000 --- a/sh/miscbltin.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $ */ - -/* - * Copyright (c) 1997 Christos Zoulas. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -int readcmd(int, char **); -int umaskcmd(int, char **); -int ulimitcmd(int, char **); diff --git a/sh/mkbuiltins b/sh/mkbuiltins deleted file mode 100644 index 5b19269..0000000 --- a/sh/mkbuiltins +++ /dev/null @@ -1,136 +0,0 @@ -#!/bin/sh - -# $NetBSD: mkbuiltins,v 1.21 2004/06/06 07:03:11 christos Exp $ -# -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 - -havehist=1 -if [ "X$1" = "X-h" ]; then - havehist=0 - shift -fi - -shell=$1 -builtins=$2 -objdir=$3 - -havejobs=0 -if grep '^#define JOBS[ ]*1' ${shell} > /dev/null -then - havejobs=1 -fi - -exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h - -echo '/* - * This file was generated by the mkbuiltins program. - */ - -#include "shell.h" -#include "builtins.h" - -const struct builtincmd builtincmd[] = { -' >&3 - -echo '/* - * This file was generated by the mkbuiltins program. - */ - -#include <sys/cdefs.h> - -struct builtincmd { - const char *name; - int (*builtin)(int, char **); -}; - -extern const struct builtincmd builtincmd[]; -extern const struct builtincmd splbltincmd[]; - -' >&4 - -specials= - -while read line -do - set -- $line - [ -z "$1" ] && continue - case "$1" in - \#if*|\#def*|\#end*) - echo $line >&3 - echo $line >&4 - continue - ;; - esac - l1="${line###}" - [ "$l1" != "$line" ] && continue - - - func=$1 - shift - [ x"$1" = x'-j' ] && { - [ $havejobs = 0 ] && continue - shift - } - [ x"$1" = x'-h' ] && { - [ $havehist = 0 ] && continue - shift - } - echo 'int '"$func"'(int, char **);' >&4 - while - [ $# != 0 -a "$1" != '#' ] - do - [ "$1" = '-s' ] && { - specials="$specials $2 $func" - shift 2 - continue; - } - [ "$1" = '-u' ] && shift - echo ' { "'$1'", '"$func"' },' >&3 - shift - done -done - -echo ' { 0, 0 },' >&3 -echo '};' >&3 -echo >&3 -echo 'const struct builtincmd splbltincmd[] = {' >&3 - -set -- $specials -while - [ $# != 0 ] -do - echo ' { "'$1'", '"$2"' },' >&3 - shift 2 -done - -echo ' { 0, 0 },' >&3 -echo "};" >&3 diff --git a/sh/mkinit.sh b/sh/mkinit.sh deleted file mode 100644 index cae27dd..0000000 --- a/sh/mkinit.sh +++ /dev/null @@ -1,197 +0,0 @@ -#! /bin/sh -# $NetBSD: mkinit.sh,v 1.2 2004/06/15 23:09:54 dsl Exp $ - -# Copyright (c) 2003 The NetBSD Foundation, Inc. -# All rights reserved. -# -# This code is derived from software contributed to The NetBSD Foundation -# by David Laight. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of The NetBSD Foundation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -srcs="$*" - -nl=' -' -openparen='(' -backslash='\' - -includes=' "shell.h" "mystring.h" "init.h" ' -defines= -decles= -event_init= -event_reset= -event_shellproc= - -for src in $srcs; do - exec <$src - decnl="$nl" - while IFS=; read -r line; do - [ "$line" = x ] - case "$line " in - INIT["{ "]* ) event=init;; - RESET["{ "]* ) event=reset;; - SHELLPROC["{ "]* ) event=shellproc;; - INCLUDE[\ \ ]* ) - IFS=' ' - set -- $line - # ignore duplicates - [ "${includes}" != "${includes%* $2 }" ] && continue - includes="$includes$2 " - continue - ;; - MKINIT\ ) - # struct declaration - decles="$decles$nl" - while - read -r line - decles="${decles}${line}${nl}" - [ "$line" != "};" ] - do - : - done - decnl="$nl" - continue - ;; - MKINIT["{ "]* ) - # strip initialiser - def=${line#MKINIT} - comment="${def#*;}" - def="${def%;$comment}" - def="${def%%=*}" - def="${def% }" - decles="${decles}${decnl}extern${def};${comment}${nl}" - decnl= - continue - ;; - \#define[\ \ ]* ) - IFS=' ' - set -- $line - # Ignore those with arguments - [ "$2" = "${2##*$openparen}" ] || continue - # and multiline definitions - [ "$line" = "${line%$backslash}" ] || continue - defines="${defines}#undef $2${nl}${line}${nl}" - continue - ;; - * ) continue;; - esac - # code for events - ev="${nl} /* from $src: */${nl} {${nl}" - while - read -r line - [ "$line" != "}" ] - do - # The C program indented by an extra 6 chars using - # tabs then spaces. I need to compare the output :-( - indent=6 - while - l=${line# } - [ "$l" != "$line" ] - do - indent=$(($indent + 8)) - line="$l" - done - while - l=${line# } - [ "$l" != "$line" ] - do - indent=$(($indent + 1)) - line="$l" - done - [ -z "$line" -o "$line" != "${line###}" ] && indent=0 - while - [ $indent -ge 8 ] - do - ev="$ev " - indent="$(($indent - 8))" - done - while - [ $indent -gt 0 ] - do - ev="$ev " - indent="$(($indent - 1))" - done - ev="${ev}${line}${nl}" - done - ev="${ev} }${nl}" - eval event_$event=\"\$event_$event\$ev\" - done -done - -exec >init.c.tmp - -echo "/*" -echo " * This file was generated by the mkinit program." -echo " */" -echo - -IFS=' ' -for f in $includes; do - echo "#include $f" -done - -echo -echo -echo -echo "$defines" -echo -echo "$decles" -echo -echo -echo "/*" -echo " * Initialization code." -echo " */" -echo -echo "void" -echo "init() {" -echo "${event_init%$nl}" -echo "}" -echo -echo -echo -echo "/*" -echo " * This routine is called when an error or an interrupt occurs in an" -echo " * interactive shell and control is returned to the main command loop." -echo " */" -echo -echo "void" -echo "reset() {" -echo "${event_reset%$nl}" -echo "}" -echo -echo -echo -echo "/*" -echo " * This routine is called to initialize the shell to run a shell procedure." -echo " */" -echo -echo "void" -echo "initshellproc() {" -echo "${event_shellproc%$nl}" -echo "}" - -exec >&- -mv init.c.tmp init.c diff --git a/sh/mknodes.sh b/sh/mknodes.sh deleted file mode 100644 index 54d2e3d..0000000 --- a/sh/mknodes.sh +++ /dev/null @@ -1,217 +0,0 @@ -#! /bin/sh -# $NetBSD: mknodes.sh,v 1.1 2004/01/16 23:24:38 dsl Exp $ - -# Copyright (c) 2003 The NetBSD Foundation, Inc. -# All rights reserved. -# -# This code is derived from software contributed to The NetBSD Foundation -# by David Laight. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of The NetBSD Foundation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -nodetypes=$1 -nodes_pat=$2 -objdir="$3" - -exec <$nodetypes -exec >$objdir/nodes.h.tmp - -echo "/*" -echo " * This file was generated by mknodes.sh" -echo " */" -echo - -tagno=0 -while IFS=; read -r line; do - line="${line%%#*}" - IFS=' ' - set -- $line - IFS= - [ -z "$2" ] && continue - case "$line" in - [" "]* ) - IFS=' ' - [ $field = 0 ] && struct_list="$struct_list $struct" - eval field_${struct}_$field=\"\$*\" - eval numfld_$struct=\$field - field=$(($field + 1)) - ;; - * ) - define=$1 - struct=$2 - echo "#define $define $tagno" - tagno=$(($tagno + 1)) - eval define_$struct=\"\$define_$struct \$define\" - struct_define="$struct_define $struct" - field=0 - ;; - esac -done - -echo - -IFS=' ' -for struct in $struct_list; do - echo - echo - echo "struct $struct {" - field=0 - while - eval line=\"\$field_${struct}_$field\" - field=$(($field + 1)) - [ -n "$line" ] - do - IFS=' ' - set -- $line - name=$1 - case $2 in - nodeptr ) type="union node *";; - nodelist ) type="struct nodelist *";; - string ) type="char *";; - int ) type="int ";; - * ) name=; shift 2; type="$*";; - esac - echo " $type$name;" - done - echo "};" -done - -echo -echo -echo "union node {" -echo " int type;" -for struct in $struct_list; do - echo " struct $struct $struct;" -done -echo "};" -echo -echo -echo "struct nodelist {" -echo " struct nodelist *next;" -echo " union node *n;" -echo "};" -echo -echo -echo "union node *copyfunc(union node *);" -echo "void freefunc(union node *);" - -mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1 - -exec <$nodes_pat -exec >$objdir/nodes.c.tmp - -echo "/*" -echo " * This file was generated by mknodes.sh" -echo " */" -echo - -while IFS=; read -r line; do - IFS=' ' - set -- $line - IFS= - case "$1" in - '%SIZES' ) - echo "static const short nodesize[$tagno] = {" - IFS=' ' - for struct in $struct_define; do - echo " SHELL_ALIGN(sizeof (struct $struct))," - done - echo "};" - ;; - '%CALCSIZE' ) - echo " if (n == NULL)" - echo " return;" - echo " funcblocksize += nodesize[n->type];" - echo " switch (n->type) {" - IFS=' ' - for struct in $struct_list; do - eval defines=\"\$define_$struct\" - for define in $defines; do - echo " case $define:" - done - eval field=\$numfld_$struct - while - [ $field != 0 ] - do - eval line=\"\$field_${struct}_$field\" - field=$(($field - 1)) - IFS=' ' - set -- $line - name=$1 - cl=")" - case $2 in - nodeptr ) fn=calcsize;; - nodelist ) fn=sizenodelist;; - string ) fn="funcstringsize += strlen" - cl=") + 1";; - * ) continue;; - esac - echo " ${fn}(n->$struct.$name${cl};" - done - echo " break;" - done - echo " };" - ;; - '%COPY' ) - echo " if (n == NULL)" - echo " return NULL;" - echo " new = funcblock;" - echo " funcblock = (char *) funcblock + nodesize[n->type];" - echo " switch (n->type) {" - IFS=' ' - for struct in $struct_list; do - eval defines=\"\$define_$struct\" - for define in $defines; do - echo " case $define:" - done - eval field=\$numfld_$struct - while - [ $field != 0 ] - do - eval line=\"\$field_${struct}_$field\" - field=$(($field - 1)) - IFS=' ' - set -- $line - name=$1 - case $2 in - nodeptr ) fn="copynode(";; - nodelist ) fn="copynodelist(";; - string ) fn="nodesavestr(";; - int ) fn=;; - * ) continue;; - esac - f="$struct.$name" - echo " new->$f = ${fn}n->$f${fn:+)};" - done - echo " break;" - done - echo " };" - echo " new->type = n->type;" - ;; - * ) echo "$line";; - esac -done - -mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1 diff --git a/sh/mktokens b/sh/mktokens deleted file mode 100644 index 25f2e6e..0000000 --- a/sh/mktokens +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/sh - -# $NetBSD: mktokens,v 1.10 2003/08/22 11:22:23 agc Exp $ -# -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)mktokens 8.1 (Berkeley) 5/31/93 - -# The following is a list of tokens. The second column is nonzero if the -# token marks the end of a list. The third column is the name to print in -# error messages. - -cat > /tmp/ka$$ <<\! -TEOF 1 end of file -TNL 0 newline -TSEMI 0 ";" -TBACKGND 0 "&" -TAND 0 "&&" -TOR 0 "||" -TPIPE 0 "|" -TLP 0 "(" -TRP 1 ")" -TENDCASE 1 ";;" -TENDBQUOTE 1 "`" -TREDIR 0 redirection -TWORD 0 word -TIF 0 "if" -TTHEN 1 "then" -TELSE 1 "else" -TELIF 1 "elif" -TFI 1 "fi" -TWHILE 0 "while" -TUNTIL 0 "until" -TFOR 0 "for" -TDO 1 "do" -TDONE 1 "done" -TBEGIN 0 "{" -TEND 1 "}" -TCASE 0 "case" -TESAC 1 "esac" -TNOT 0 "!" -! -nl=`wc -l /tmp/ka$$` -exec > token.h -awk '{print "#define " $1 " " NR-1}' /tmp/ka$$ -echo ' -/* Array indicating which tokens mark the end of a list */ -const char tokendlist[] = {' -awk '{print "\t" $2 ","}' /tmp/ka$$ -echo '}; - -const char *const tokname[] = {' -sed -e 's/"/\\"/g' \ - -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \ - /tmp/ka$$ -echo '}; -' -sed 's/"//g' /tmp/ka$$ | awk ' -/TIF/{print "#define KWDOFFSET " NR-1; print ""; - print "const char *const parsekwd[] = {"} -/TIF/,/neverfound/{print " \"" $3 "\","}' -echo ' 0 -};' - -rm /tmp/ka$$ diff --git a/sh/myhistedit.h b/sh/myhistedit.h deleted file mode 100644 index 603a27b..0000000 --- a/sh/myhistedit.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $NetBSD: myhistedit.h,v 1.10 2003/08/07 09:05:35 agc Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95 - */ - -#ifdef WITH_HISTORY -#include <histedit.h> - -extern History *hist; -extern EditLine *el; -extern int displayhist; - -void histedit(void); -void sethistsize(const char *); -void setterm(const char *); -int histcmd(int, char **); -int inputrc(int, char **); -int not_fcnumber(char *); -int str_to_event(const char *, int); -#endif - diff --git a/sh/mystring.c b/sh/mystring.c deleted file mode 100644 index aecf83e..0000000 --- a/sh/mystring.c +++ /dev/null @@ -1,133 +0,0 @@ -/* $NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc Exp $"); -#endif -#endif /* not lint */ - -/* - * String functions. - * - * equal(s1, s2) Return true if strings are equal. - * scopy(from, to) Copy a string. - * scopyn(from, to, n) Like scopy, but checks for overflow. - * number(s) Convert a string of digits to an integer. - * is_number(s) Return true if s is a string of digits. - */ - -#include <stdlib.h> -#include "shell.h" -#include "syntax.h" -#include "error.h" -#include "mystring.h" - - -char nullstr[1]; /* zero length string */ - -/* - * equal - #defined in mystring.h - */ - -/* - * scopy - #defined in mystring.h - */ - - -/* - * scopyn - copy a string from "from" to "to", truncating the string - * if necessary. "To" is always nul terminated, even if - * truncation is performed. "Size" is the size of "to". - */ - -void -scopyn(const char *from, char *to, int size) -{ - - while (--size > 0) { - if ((*to++ = *from++) == '\0') - return; - } - *to = '\0'; -} - - -/* - * prefix -- see if pfx is a prefix of string. - */ - -int -prefix(const char *pfx, const char *string) -{ - while (*pfx) { - if (*pfx++ != *string++) - return 0; - } - return 1; -} - - -/* - * Convert a string of digits to an integer, printing an error message on - * failure. - */ - -int -number(const char *s) -{ - - if (! is_number(s)) - error("Illegal number: %s", s); - return atoi(s); -} - - - -/* - * Check for a valid number. This should be elsewhere. - */ - -int -is_number(const char *p) -{ - do { - if (! is_digit(*p)) - return 0; - } while (*++p != '\0'); - return 1; -} diff --git a/sh/mystring.h b/sh/mystring.h deleted file mode 100644 index 08a73e9..0000000 --- a/sh/mystring.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)mystring.h 8.2 (Berkeley) 5/4/95 - */ - -#include <string.h> - -void scopyn(const char *, char *, int); -int prefix(const char *, const char *); -int number(const char *); -int is_number(const char *); - -#define equal(s1, s2) (strcmp(s1, s2) == 0) -#define scopy(s1, s2) ((void)strcpy(s2, s1)) diff --git a/sh/nodes.c b/sh/nodes.c deleted file mode 100644 index 8a2c718..0000000 --- a/sh/nodes.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * This file was generated by mknodes.sh - */ - -/* $NetBSD: nodes.c.pat,v 1.12 2004/06/15 22:57:27 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 - */ - -#include <stdlib.h> -/* - * Routine for dealing with parsed shell commands. - */ - -#include "shell.h" -#include "nodes.h" -#include "memalloc.h" -#include "machdep.h" -#include "mystring.h" - - -int funcblocksize; /* size of structures in function */ -int funcstringsize; /* size of strings in node */ -pointer funcblock; /* block to allocate function from */ -char *funcstring; /* block to allocate strings from */ - -static const short nodesize[26] = { - SHELL_ALIGN(sizeof (struct nbinary)), - SHELL_ALIGN(sizeof (struct ncmd)), - SHELL_ALIGN(sizeof (struct npipe)), - SHELL_ALIGN(sizeof (struct nredir)), - SHELL_ALIGN(sizeof (struct nredir)), - SHELL_ALIGN(sizeof (struct nredir)), - SHELL_ALIGN(sizeof (struct nbinary)), - SHELL_ALIGN(sizeof (struct nbinary)), - SHELL_ALIGN(sizeof (struct nif)), - SHELL_ALIGN(sizeof (struct nbinary)), - SHELL_ALIGN(sizeof (struct nbinary)), - SHELL_ALIGN(sizeof (struct nfor)), - SHELL_ALIGN(sizeof (struct ncase)), - SHELL_ALIGN(sizeof (struct nclist)), - SHELL_ALIGN(sizeof (struct narg)), - SHELL_ALIGN(sizeof (struct narg)), - SHELL_ALIGN(sizeof (struct nfile)), - SHELL_ALIGN(sizeof (struct nfile)), - SHELL_ALIGN(sizeof (struct nfile)), - SHELL_ALIGN(sizeof (struct nfile)), - SHELL_ALIGN(sizeof (struct nfile)), - SHELL_ALIGN(sizeof (struct ndup)), - SHELL_ALIGN(sizeof (struct ndup)), - SHELL_ALIGN(sizeof (struct nhere)), - SHELL_ALIGN(sizeof (struct nhere)), - SHELL_ALIGN(sizeof (struct nnot)), -}; - - -STATIC void calcsize(union node *); -STATIC void sizenodelist(struct nodelist *); -STATIC union node *copynode(union node *); -STATIC struct nodelist *copynodelist(struct nodelist *); -STATIC char *nodesavestr(char *); - - - -/* - * Make a copy of a parse tree. - */ - -union node * -copyfunc(n) - union node *n; -{ - if (n == NULL) - return NULL; - funcblocksize = 0; - funcstringsize = 0; - calcsize(n); - funcblock = ckmalloc(funcblocksize + funcstringsize); - funcstring = (char *) funcblock + funcblocksize; - return copynode(n); -} - - - -STATIC void -calcsize(n) - union node *n; -{ - if (n == NULL) - return; - funcblocksize += nodesize[n->type]; - switch (n->type) { - case NSEMI: - case NAND: - case NOR: - case NWHILE: - case NUNTIL: - calcsize(n->nbinary.ch2); - calcsize(n->nbinary.ch1); - break; - case NCMD: - calcsize(n->ncmd.redirect); - calcsize(n->ncmd.args); - break; - case NPIPE: - sizenodelist(n->npipe.cmdlist); - break; - case NREDIR: - case NBACKGND: - case NSUBSHELL: - calcsize(n->nredir.redirect); - calcsize(n->nredir.n); - break; - case NIF: - calcsize(n->nif.elsepart); - calcsize(n->nif.ifpart); - calcsize(n->nif.test); - break; - case NFOR: - funcstringsize += strlen(n->nfor.var) + 1; - calcsize(n->nfor.body); - calcsize(n->nfor.args); - break; - case NCASE: - calcsize(n->ncase.cases); - calcsize(n->ncase.expr); - break; - case NCLIST: - calcsize(n->nclist.body); - calcsize(n->nclist.pattern); - calcsize(n->nclist.next); - break; - case NDEFUN: - case NARG: - sizenodelist(n->narg.backquote); - funcstringsize += strlen(n->narg.text) + 1; - calcsize(n->narg.next); - break; - case NTO: - case NCLOBBER: - case NFROM: - case NFROMTO: - case NAPPEND: - calcsize(n->nfile.fname); - calcsize(n->nfile.next); - break; - case NTOFD: - case NFROMFD: - calcsize(n->ndup.vname); - calcsize(n->ndup.next); - break; - case NHERE: - case NXHERE: - calcsize(n->nhere.doc); - calcsize(n->nhere.next); - break; - case NNOT: - calcsize(n->nnot.com); - break; - }; -} - - - -STATIC void -sizenodelist(lp) - struct nodelist *lp; -{ - while (lp) { - funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); - calcsize(lp->n); - lp = lp->next; - } -} - - - -STATIC union node * -copynode(n) - union node *n; -{ - union node *new; - - if (n == NULL) - return NULL; - new = funcblock; - funcblock = (char *) funcblock + nodesize[n->type]; - switch (n->type) { - case NSEMI: - case NAND: - case NOR: - case NWHILE: - case NUNTIL: - new->nbinary.ch2 = copynode(n->nbinary.ch2); - new->nbinary.ch1 = copynode(n->nbinary.ch1); - break; - case NCMD: - new->ncmd.redirect = copynode(n->ncmd.redirect); - new->ncmd.args = copynode(n->ncmd.args); - new->ncmd.backgnd = n->ncmd.backgnd; - break; - case NPIPE: - new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); - new->npipe.backgnd = n->npipe.backgnd; - break; - case NREDIR: - case NBACKGND: - case NSUBSHELL: - new->nredir.redirect = copynode(n->nredir.redirect); - new->nredir.n = copynode(n->nredir.n); - break; - case NIF: - new->nif.elsepart = copynode(n->nif.elsepart); - new->nif.ifpart = copynode(n->nif.ifpart); - new->nif.test = copynode(n->nif.test); - break; - case NFOR: - new->nfor.var = nodesavestr(n->nfor.var); - new->nfor.body = copynode(n->nfor.body); - new->nfor.args = copynode(n->nfor.args); - break; - case NCASE: - new->ncase.cases = copynode(n->ncase.cases); - new->ncase.expr = copynode(n->ncase.expr); - break; - case NCLIST: - new->nclist.body = copynode(n->nclist.body); - new->nclist.pattern = copynode(n->nclist.pattern); - new->nclist.next = copynode(n->nclist.next); - break; - case NDEFUN: - case NARG: - new->narg.backquote = copynodelist(n->narg.backquote); - new->narg.text = nodesavestr(n->narg.text); - new->narg.next = copynode(n->narg.next); - break; - case NTO: - case NCLOBBER: - case NFROM: - case NFROMTO: - case NAPPEND: - new->nfile.fname = copynode(n->nfile.fname); - new->nfile.fd = n->nfile.fd; - new->nfile.next = copynode(n->nfile.next); - break; - case NTOFD: - case NFROMFD: - new->ndup.vname = copynode(n->ndup.vname); - new->ndup.dupfd = n->ndup.dupfd; - new->ndup.fd = n->ndup.fd; - new->ndup.next = copynode(n->ndup.next); - break; - case NHERE: - case NXHERE: - new->nhere.doc = copynode(n->nhere.doc); - new->nhere.fd = n->nhere.fd; - new->nhere.next = copynode(n->nhere.next); - break; - case NNOT: - new->nnot.com = copynode(n->nnot.com); - break; - }; - new->type = n->type; - return new; -} - - -STATIC struct nodelist * -copynodelist(lp) - struct nodelist *lp; -{ - struct nodelist *start; - struct nodelist **lpp; - - lpp = &start; - while (lp) { - *lpp = funcblock; - funcblock = (char *) funcblock + - SHELL_ALIGN(sizeof(struct nodelist)); - (*lpp)->n = copynode(lp->n); - lp = lp->next; - lpp = &(*lpp)->next; - } - *lpp = NULL; - return start; -} - - - -STATIC char * -nodesavestr(s) - char *s; -{ - register char *p = s; - register char *q = funcstring; - char *rtn = funcstring; - - while ((*q++ = *p++) != 0) - continue; - funcstring = q; - return rtn; -} - - - -/* - * Free a parse tree. - */ - -void -freefunc(n) - union node *n; -{ - if (n) - ckfree(n); -} diff --git a/sh/nodes.c.pat b/sh/nodes.c.pat deleted file mode 100644 index e619a01..0000000 --- a/sh/nodes.c.pat +++ /dev/null @@ -1,166 +0,0 @@ -/* $NetBSD: nodes.c.pat,v 1.12 2004/06/15 22:57:27 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 - */ - -#include <stdlib.h> -/* - * Routine for dealing with parsed shell commands. - */ - -#include "shell.h" -#include "nodes.h" -#include "memalloc.h" -#include "machdep.h" -#include "mystring.h" - - -int funcblocksize; /* size of structures in function */ -int funcstringsize; /* size of strings in node */ -pointer funcblock; /* block to allocate function from */ -char *funcstring; /* block to allocate strings from */ - -%SIZES - - -STATIC void calcsize(union node *); -STATIC void sizenodelist(struct nodelist *); -STATIC union node *copynode(union node *); -STATIC struct nodelist *copynodelist(struct nodelist *); -STATIC char *nodesavestr(char *); - - - -/* - * Make a copy of a parse tree. - */ - -union node * -copyfunc(n) - union node *n; -{ - if (n == NULL) - return NULL; - funcblocksize = 0; - funcstringsize = 0; - calcsize(n); - funcblock = ckmalloc(funcblocksize + funcstringsize); - funcstring = (char *) funcblock + funcblocksize; - return copynode(n); -} - - - -STATIC void -calcsize(n) - union node *n; -{ - %CALCSIZE -} - - - -STATIC void -sizenodelist(lp) - struct nodelist *lp; -{ - while (lp) { - funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); - calcsize(lp->n); - lp = lp->next; - } -} - - - -STATIC union node * -copynode(n) - union node *n; -{ - union node *new; - - %COPY - return new; -} - - -STATIC struct nodelist * -copynodelist(lp) - struct nodelist *lp; -{ - struct nodelist *start; - struct nodelist **lpp; - - lpp = &start; - while (lp) { - *lpp = funcblock; - funcblock = (char *) funcblock + - SHELL_ALIGN(sizeof(struct nodelist)); - (*lpp)->n = copynode(lp->n); - lp = lp->next; - lpp = &(*lpp)->next; - } - *lpp = NULL; - return start; -} - - - -STATIC char * -nodesavestr(s) - char *s; -{ - register char *p = s; - register char *q = funcstring; - char *rtn = funcstring; - - while ((*q++ = *p++) != 0) - continue; - funcstring = q; - return rtn; -} - - - -/* - * Free a parse tree. - */ - -void -freefunc(n) - union node *n; -{ - if (n) - ckfree(n); -} diff --git a/sh/nodes.h b/sh/nodes.h deleted file mode 100644 index aa750ed..0000000 --- a/sh/nodes.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file was generated by mknodes.sh - */ - -#define NSEMI 0 -#define NCMD 1 -#define NPIPE 2 -#define NREDIR 3 -#define NBACKGND 4 -#define NSUBSHELL 5 -#define NAND 6 -#define NOR 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 NFROMFD 22 -#define NHERE 23 -#define NXHERE 24 -#define NNOT 25 - - - -struct nbinary { - int type; - union node *ch1; - union node *ch2; -}; - - -struct ncmd { - int type; - int backgnd; - union node *args; - union node *redirect; -}; - - -struct npipe { - int type; - int backgnd; - struct nodelist *cmdlist; -}; - - -struct nredir { - int type; - union node *n; - union node *redirect; -}; - - -struct nif { - int type; - union node *test; - union node *ifpart; - union node *elsepart; -}; - - -struct nfor { - int type; - union node *args; - union node *body; - char *var; -}; - - -struct ncase { - int type; - union node *expr; - union node *cases; -}; - - -struct nclist { - int type; - union node *next; - union node *pattern; - union node *body; -}; - - -struct narg { - int type; - union node *next; - char *text; - struct nodelist *backquote; -}; - - -struct nfile { - int type; - union node *next; - int fd; - union node *fname; - char *expfname; -}; - - -struct ndup { - int type; - union node *next; - int fd; - int dupfd; - union node *vname; -}; - - -struct nhere { - int type; - union node *next; - int fd; - union node *doc; -}; - - -struct nnot { - int type; - union node *com; -}; - - -union node { - int type; - struct nbinary nbinary; - struct ncmd ncmd; - struct npipe npipe; - struct nredir nredir; - struct nif nif; - struct nfor nfor; - struct ncase ncase; - struct nclist nclist; - struct narg narg; - struct nfile nfile; - struct ndup ndup; - struct nhere nhere; - struct nnot nnot; -}; - - -struct nodelist { - struct nodelist *next; - union node *n; -}; - - -union node *copyfunc(union node *); -void freefunc(union node *); diff --git a/sh/nodetypes b/sh/nodetypes deleted file mode 100644 index 4adebc0..0000000 --- a/sh/nodetypes +++ /dev/null @@ -1,143 +0,0 @@ -# $NetBSD: nodetypes,v 1.12 2003/08/22 11:22:23 agc Exp $ -# Copyright (c) 1991, 1993 -# The Regents of the University of California. All rights reserved. -# -# This code is derived from software contributed to Berkeley by -# Kenneth Almquist. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)nodetypes 8.2 (Berkeley) 5/4/95 - -# This file describes the nodes used in parse trees. Unindented lines -# contain a node type followed by a structure tag. Subsequent indented -# lines specify the fields of the structure. Several node types can share -# the same structure, in which case the fields of the structure should be -# specified only once. -# -# A field of a structure is described by the name of the field followed -# by a type. The currently implemented types are: -# nodeptr - a pointer to a node -# nodelist - a pointer to a list of nodes -# string - a pointer to a nul terminated string -# int - an integer -# other - any type that can be copied by assignment -# temp - a field that doesn't have to be copied when the node is copied -# The last two types should be followed by the text of a C declaration for -# the field. - -NSEMI nbinary # two commands separated by a semicolon - type int - ch1 nodeptr # the first child - ch2 nodeptr # the second child - -NCMD ncmd # a simple command - type int - backgnd int # set to run command in background - args nodeptr # the arguments - redirect nodeptr # list of file redirections - -NPIPE npipe # a pipeline - type int - backgnd int # set to run pipeline in background - cmdlist nodelist # the commands in the pipeline - -NREDIR nredir # redirection (of a complex command) - type int - n nodeptr # the command - redirect nodeptr # list of file redirections - -NBACKGND nredir # run command in background -NSUBSHELL nredir # run command in a subshell - -NAND nbinary # the && operator -NOR nbinary # the || operator - -NIF nif # the if statement. Elif clauses are handled - type int # using multiple if nodes. - test nodeptr # if test - ifpart nodeptr # then ifpart - elsepart nodeptr # else elsepart - -NWHILE nbinary # the while statement. First child is the test -NUNTIL nbinary # the until statement - -NFOR nfor # the for statement - type int - args nodeptr # for var in args - body nodeptr # do body; done - var string # the for variable - -NCASE ncase # a case statement - type int - expr nodeptr # the word to switch on - cases nodeptr # the list of cases (NCLIST nodes) - -NCLIST nclist # a case - type int - next nodeptr # the next case in list - pattern nodeptr # list of patterns for this case - body nodeptr # code to execute for this case - - -NDEFUN narg # define a function. The "next" field contains - # the body of the function. - -NARG narg # represents a word - type int - next nodeptr # next word in list - text string # the text of the word - backquote nodelist # list of commands in back quotes - -NTO nfile # fd> fname -NCLOBBER nfile # fd>| fname -NFROM nfile # fd< fname -NFROMTO nfile # fd<> fname -NAPPEND nfile # fd>> fname - type int - next nodeptr # next redirection in list - fd int # file descriptor being redirected - fname nodeptr # file name, in a NARG node - expfname temp char *expfname # actual file name - -NTOFD ndup # fd<&dupfd -NFROMFD ndup # fd>&dupfd - type int - next nodeptr # next redirection in list - fd int # file descriptor being redirected - dupfd int # file descriptor to duplicate - vname nodeptr # file name if fd>&$var - - -NHERE nhere # fd<<\! -NXHERE nhere # fd<<! - type int - next nodeptr # next redirection in list - fd int # file descriptor being redirected - doc nodeptr # input to command (NARG node) - -NNOT nnot # ! command (actually pipeline) - type int - com nodeptr diff --git a/sh/options.c b/sh/options.c deleted file mode 100644 index bc833c7..0000000 --- a/sh/options.c +++ /dev/null @@ -1,530 +0,0 @@ -/* $NetBSD: options.c,v 1.37 2004/10/30 19:29:27 christos Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: options.c,v 1.37 2004/10/30 19:29:27 christos Exp $"); -#endif -#endif /* not lint */ - -#include <signal.h> -#include <unistd.h> -#include <stdlib.h> - -#include "shell.h" -#define DEFINE_OPTIONS -#include "options.h" -#undef DEFINE_OPTIONS -#include "nodes.h" /* for other header files */ -#include "eval.h" -#include "jobs.h" -#include "input.h" -#include "output.h" -#include "trap.h" -#include "var.h" -#include "memalloc.h" -#include "error.h" -#include "mystring.h" -#ifndef SMALL -#include "myhistedit.h" -#endif -#include "show.h" - -char *arg0; /* value of $0 */ -struct shparam shellparam; /* current positional parameters */ -char **argptr; /* argument list for builtin commands */ -char *optionarg; /* set by nextopt (like getopt) */ -char *optptr; /* used by nextopt */ - -char *minusc; /* argument to -c option */ - - -STATIC void options(int); -STATIC void minus_o(char *, int); -STATIC void setoption(int, int); -STATIC int getopts(char *, char *, char **, char ***, char **); - - -/* - * Process the shell command line arguments. - */ - -void -procargs(int argc, char **argv) -{ - int i; - - argptr = argv; - if (argc > 0) - argptr++; - for (i = 0; i < NOPTS; i++) - optlist[i].val = 2; - options(1); - if (*argptr == NULL && minusc == NULL) - sflag = 1; - if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) - iflag = 1; - if (mflag == 2) - mflag = iflag; - for (i = 0; i < NOPTS; i++) - if (optlist[i].val == 2) - optlist[i].val = 0; -#if DEBUG == 2 - debug = 1; -#endif - arg0 = argv[0]; - if (sflag == 0 && minusc == NULL) { - commandname = argv[0]; - arg0 = *argptr++; - setinputfile(arg0, 0); - commandname = arg0; - } - /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ - if (minusc != NULL) { - if (argptr == NULL || *argptr == NULL) - error("Bad -c option"); - minusc = *argptr++; - if (*argptr != 0) - arg0 = *argptr++; - } - - shellparam.p = argptr; - shellparam.reset = 1; - /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ - while (*argptr) { - shellparam.nparam++; - argptr++; - } - optschanged(); -} - - -void -optschanged(void) -{ - setinteractive(iflag); -#ifdef WITH_HISTORY - histedit(); -#endif - setjobctl(mflag); -} - -/* - * Process shell options. The global variable argptr contains a pointer - * to the argument list; we advance it past the options. - */ - -STATIC void -options(int cmdline) -{ - static char empty[] = ""; - char *p; - int val; - int c; - - if (cmdline) - minusc = NULL; - while ((p = *argptr) != NULL) { - argptr++; - if ((c = *p++) == '-') { - val = 1; - if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { - if (!cmdline) { - /* "-" means turn off -x and -v */ - if (p[0] == '\0') - xflag = vflag = 0; - /* "--" means reset params */ - else if (*argptr == NULL) - setparam(argptr); - } - break; /* "-" or "--" terminates options */ - } - } else if (c == '+') { - val = 0; - } else { - argptr--; - break; - } - while ((c = *p++) != '\0') { - if (c == 'c' && cmdline) { - /* command is after shell args*/ - minusc = empty; - } else if (c == 'o') { - minus_o(*argptr, val); - if (*argptr) - argptr++; - } else { - setoption(c, val); - } - } - } -} - -static void -set_opt_val(int i, int val) -{ - int j; - int flag; - - if (val && (flag = optlist[i].opt_set)) { - /* some options (eg vi/emacs) are mutually exclusive */ - for (j = 0; j < NOPTS; j++) - if (optlist[j].opt_set == flag) - optlist[j].val = 0; - } - optlist[i].val = val; -#ifdef DEBUG - if (&optlist[i].val == &debug) - opentrace(); -#endif -} - -STATIC void -minus_o(char *name, int val) -{ - int i; - - if (name == NULL) { - out1str("Current option settings\n"); - for (i = 0; i < NOPTS; i++) - out1fmt("%-16s%s\n", optlist[i].name, - optlist[i].val ? "on" : "off"); - } else { - for (i = 0; i < NOPTS; i++) - if (equal(name, optlist[i].name)) { - set_opt_val(i, val); - return; - } - error("Illegal option -o %s", name); - } -} - - -STATIC void -setoption(int flag, int val) -{ - int i; - - for (i = 0; i < NOPTS; i++) - if (optlist[i].letter == flag) { - set_opt_val( i, val ); - return; - } - error("Illegal option -%c", flag); - /* NOTREACHED */ -} - - - -#ifdef mkinit -INCLUDE "options.h" - -SHELLPROC { - int i; - - for (i = 0; optlist[i].name; i++) - optlist[i].val = 0; - optschanged(); - -} -#endif - - -/* - * Set the shell parameters. - */ - -void -setparam(char **argv) -{ - char **newparam; - char **ap; - int nparam; - - for (nparam = 0 ; argv[nparam] ; nparam++); - ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); - while (*argv) { - *ap++ = savestr(*argv++); - } - *ap = NULL; - freeparam(&shellparam); - shellparam.malloc = 1; - shellparam.nparam = nparam; - shellparam.p = newparam; - shellparam.optnext = NULL; -} - - -/* - * Free the list of positional parameters. - */ - -void -freeparam(volatile struct shparam *param) -{ - char **ap; - - if (param->malloc) { - for (ap = param->p ; *ap ; ap++) - ckfree(*ap); - ckfree(param->p); - } -} - - - -/* - * The shift builtin command. - */ - -int -shiftcmd(int argc, char **argv) -{ - int n; - char **ap1, **ap2; - - n = 1; - if (argc > 1) - n = number(argv[1]); - if (n > shellparam.nparam) - error("can't shift that many"); - INTOFF; - shellparam.nparam -= n; - for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { - if (shellparam.malloc) - ckfree(*ap1); - } - ap2 = shellparam.p; - while ((*ap2++ = *ap1++) != NULL); - shellparam.optnext = NULL; - INTON; - return 0; -} - - - -/* - * The set command builtin. - */ - -int -setcmd(int argc, char **argv) -{ - if (argc == 1) - return showvars(0, 0, 1); - INTOFF; - options(0); - optschanged(); - if (*argptr != NULL) { - setparam(argptr); - } - INTON; - return 0; -} - - -void -getoptsreset(value) - const char *value; -{ - if (number(value) == 1) { - shellparam.optnext = NULL; - shellparam.reset = 1; - } -} - -/* - * The getopts builtin. Shellparam.optnext points to the next argument - * to be processed. Shellparam.optptr points to the next character to - * be processed in the current argument. If shellparam.optnext is NULL, - * then it's the first time getopts has been called. - */ - -int -getoptscmd(int argc, char **argv) -{ - char **optbase; - - if (argc < 3) - error("usage: getopts optstring var [arg]"); - else if (argc == 3) - optbase = shellparam.p; - else - optbase = &argv[3]; - - if (shellparam.reset == 1) { - shellparam.optnext = optbase; - shellparam.optptr = NULL; - shellparam.reset = 0; - } - - return getopts(argv[1], argv[2], optbase, &shellparam.optnext, - &shellparam.optptr); -} - -STATIC int -getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr) -{ - char *p, *q; - char c = '?'; - int done = 0; - int ind = 0; - int err = 0; - char s[12]; - - if ((p = *optpptr) == NULL || *p == '\0') { - /* Current word is done, advance */ - if (*optnext == NULL) - return 1; - p = **optnext; - if (p == NULL || *p != '-' || *++p == '\0') { -atend: - ind = *optnext - optfirst + 1; - *optnext = NULL; - p = NULL; - done = 1; - goto out; - } - (*optnext)++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ - goto atend; - } - - c = *p++; - for (q = optstr; *q != c; ) { - if (*q == '\0') { - if (optstr[0] == ':') { - s[0] = c; - s[1] = '\0'; - err |= setvarsafe("OPTARG", s, 0); - } else { - outfmt(&errout, "Illegal option -%c\n", c); - (void) unsetvar("OPTARG", 0); - } - c = '?'; - goto bad; - } - if (*++q == ':') - q++; - } - - if (*++q == ':') { - if (*p == '\0' && (p = **optnext) == NULL) { - if (optstr[0] == ':') { - s[0] = c; - s[1] = '\0'; - err |= setvarsafe("OPTARG", s, 0); - c = ':'; - } else { - outfmt(&errout, "No arg for -%c option\n", c); - (void) unsetvar("OPTARG", 0); - c = '?'; - } - goto bad; - } - - if (p == **optnext) - (*optnext)++; - err |= setvarsafe("OPTARG", p, 0); - p = NULL; - } else - err |= setvarsafe("OPTARG", "", 0); - ind = *optnext - optfirst + 1; - goto out; - -bad: - ind = 1; - *optnext = NULL; - p = NULL; -out: - *optpptr = p; - fmtstr(s, sizeof(s), "%d", ind); - err |= setvarsafe("OPTIND", s, VNOFUNC); - s[0] = c; - s[1] = '\0'; - err |= setvarsafe(optvar, s, 0); - if (err) { - *optnext = NULL; - *optpptr = NULL; - flushall(); - exraise(EXERROR); - } - return done; -} - -/* - * XXX - should get rid of. have all builtins use getopt(3). the - * library getopt must have the BSD extension static variable "optreset" - * otherwise it can't be used within the shell safely. - * - * Standard option processing (a la getopt) for builtin routines. The - * only argument that is passed to nextopt is the option string; the - * other arguments are unnecessary. It return the character, or '\0' on - * end of input. - */ - -int -nextopt(const char *optstring) -{ - char *p; - const char *q; - char c; - - if ((p = optptr) == NULL || *p == '\0') { - p = *argptr; - if (p == NULL || *p != '-' || *++p == '\0') - return '\0'; - argptr++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ - return '\0'; - } - c = *p++; - for (q = optstring ; *q != c ; ) { - if (*q == '\0') - error("Illegal option -%c", c); - if (*++q == ':') - q++; - } - if (*++q == ':') { - if (*p == '\0' && (p = *argptr++) == NULL) - error("No arg for -%c option", c); - optionarg = p; - p = NULL; - } - optptr = p; - return c; -} diff --git a/sh/options.h b/sh/options.h deleted file mode 100644 index 4cc7dbe..0000000 --- a/sh/options.h +++ /dev/null @@ -1,131 +0,0 @@ -/* $NetBSD: options.h,v 1.17 2003/08/07 09:05:36 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)options.h 8.2 (Berkeley) 5/4/95 - */ - -struct shparam { - int nparam; /* # of positional parameters (without $0) */ - unsigned char malloc; /* if parameter list dynamically allocated */ - unsigned char reset; /* if getopts has been reset */ - char **p; /* parameter list */ - char **optnext; /* next parameter to be processed by getopts */ - char *optptr; /* used by getopts */ -}; - - -struct optent { - const char *name; /* for set -o <name> */ - const char letter; /* set [+/-]<letter> and $- */ - const char opt_set; /* mutually exclusive option set */ - char val; /* value of <letter>flag */ -}; - -/* Those marked [U] are required by posix, but have no effect! */ - -#ifdef DEFINE_OPTIONS -#define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0}, -struct optent optlist[] = { -#else -#define DEF_OPTS(name, letter, opt_set) -#endif -#define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0) - -DEF_OPT( "errexit", 'e' ) /* exit on error */ -#define eflag optlist[0].val -DEF_OPT( "noglob", 'f' ) /* no pathname expansion */ -#define fflag optlist[1].val -DEF_OPT( "ignoreeof", 'I' ) /* do not exit on EOF */ -#define Iflag optlist[2].val -DEF_OPT( "interactive",'i' ) /* interactive shell */ -#define iflag optlist[3].val -DEF_OPT( "monitor", 'm' ) /* job control */ -#define mflag optlist[4].val -DEF_OPT( "noexec", 'n' ) /* [U] do not exec commands */ -#define nflag optlist[5].val -DEF_OPT( "stdin", 's' ) /* read from stdin */ -#define sflag optlist[6].val -DEF_OPT( "xtrace", 'x' ) /* trace after expansion */ -#define xflag optlist[7].val -DEF_OPT( "verbose", 'v' ) /* trace read input */ -#define vflag optlist[8].val -DEF_OPTS( "vi", 'V', 'V' ) /* vi style editing */ -#define Vflag optlist[9].val -DEF_OPTS( "emacs", 'E', 'V' ) /* emacs style editing */ -#define Eflag optlist[10].val -DEF_OPT( "noclobber", 'C' ) /* do not overwrite files with > */ -#define Cflag optlist[11].val -DEF_OPT( "allexport", 'a' ) /* export all variables */ -#define aflag optlist[12].val -DEF_OPT( "notify", 'b' ) /* [U] report completion of background jobs */ -#define bflag optlist[13].val -DEF_OPT( "nounset", 'u' ) /* error expansion of unset variables */ -#define uflag optlist[14].val -DEF_OPT( "quietprofile", 'q' ) -#define qflag optlist[15].val -DEF_OPT( "nolog", 0 ) /* [U] no functon defs in command history */ -#define nolog optlist[16].val -DEF_OPT( "cdprint", 0 ) /* always print result of cd */ -#define cdprint optlist[17].val -#ifdef DEBUG -DEF_OPT( "debug", 0 ) /* enable debug prints */ -#define debug optlist[18].val -#endif - -#ifdef DEFINE_OPTIONS - { 0, 0, 0, 0 }, -}; -#define NOPTS (sizeof optlist / sizeof optlist[0] - 1) -int sizeof_optlist = sizeof optlist; -#else -extern struct optent optlist[]; -extern int sizeof_optlist; -#endif - - -extern char *minusc; /* argument to -c option */ -extern char *arg0; /* $0 */ -extern struct shparam shellparam; /* $@ */ -extern char **argptr; /* argument list for builtin commands */ -extern char *optionarg; /* set by nextopt */ -extern char *optptr; /* used by nextopt */ - -void procargs(int, char **); -void optschanged(void); -void setparam(char **); -void freeparam(volatile struct shparam *); -int shiftcmd(int, char **); -int setcmd(int, char **); -int getoptscmd(int, char **); -int nextopt(const char *); -void getoptsreset(const char *); diff --git a/sh/output.c b/sh/output.c deleted file mode 100644 index b0e669e..0000000 --- a/sh/output.c +++ /dev/null @@ -1,516 +0,0 @@ -/* $NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $"); -#endif -#endif /* not lint */ - -/* - * Shell output routines. We use our own output routines because: - * When a builtin command is interrupted we have to discard - * any pending output. - * When a builtin command appears in back quotes, we want to - * save the output of the command in a region obtained - * via malloc, rather than doing a fork and reading the - * output of the command via a pipe. - * Our output routines may be smaller than the stdio routines. - */ - -#include <sys/types.h> /* quad_t */ -#include <sys/param.h> /* BSD4_4 */ -#include <sys/ioctl.h> - -#include <stdio.h> /* defines BUFSIZ */ -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> - -#include "shell.h" -#include "syntax.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" - - -#define OUTBUFSIZ BUFSIZ -#define BLOCK_OUT -2 /* output to a fixed block of memory */ -#define MEM_OUT -3 /* output to dynamically allocated memory */ -#define OUTPUT_ERR 01 /* error occurred on output */ - - -struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; -struct output errout = {NULL, 0, NULL, 100, 2, 0}; -struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; -struct output *out1 = &output; -struct output *out2 = &errout; - - - -#ifdef mkinit - -INCLUDE "output.h" -INCLUDE "memalloc.h" - -RESET { - out1 = &output; - out2 = &errout; - if (memout.buf != NULL) { - ckfree(memout.buf); - memout.buf = NULL; - } -} - -#endif - - -#ifdef notdef /* no longer used */ -/* - * Set up an output file to write to memory rather than a file. - */ - -void -open_mem(char *block, int length, struct output *file) -{ - file->nextc = block; - file->nleft = --length; - file->fd = BLOCK_OUT; - file->flags = 0; -} -#endif - - -void -out1str(const char *p) -{ - outstr(p, out1); -} - - -void -out2str(const char *p) -{ - outstr(p, out2); -} - - -void -outstr(const char *p, struct output *file) -{ - while (*p) - outc(*p++, file); - if (file == out2) - flushout(file); -} - - -char out_junk[16]; - - -void -emptyoutbuf(struct output *dest) -{ - int offset; - - if (dest->fd == BLOCK_OUT) { - dest->nextc = out_junk; - dest->nleft = sizeof out_junk; - dest->flags |= OUTPUT_ERR; - } else if (dest->buf == NULL) { - INTOFF; - dest->buf = ckmalloc(dest->bufsize); - dest->nextc = dest->buf; - dest->nleft = dest->bufsize; - INTON; - } else if (dest->fd == MEM_OUT) { - offset = dest->bufsize; - INTOFF; - dest->bufsize <<= 1; - dest->buf = ckrealloc(dest->buf, dest->bufsize); - dest->nleft = dest->bufsize - offset; - dest->nextc = dest->buf + offset; - INTON; - } else { - flushout(dest); - } - dest->nleft--; -} - - -void -flushall(void) -{ - flushout(&output); - flushout(&errout); -} - - -void -flushout(struct output *dest) -{ - - if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) - return; - if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) - dest->flags |= OUTPUT_ERR; - dest->nextc = dest->buf; - dest->nleft = dest->bufsize; -} - - -void -freestdout(void) -{ - INTOFF; - if (output.buf) { - ckfree(output.buf); - output.buf = NULL; - output.nleft = 0; - } - INTON; -} - - -void -outfmt(struct output *file, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - doformat(file, fmt, ap); - va_end(ap); -} - - -void -out1fmt(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - doformat(out1, fmt, ap); - va_end(ap); -} - -void -dprintf(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - doformat(out2, fmt, ap); - va_end(ap); - flushout(out2); -} - -void -fmtstr(char *outbuf, size_t length, const char *fmt, ...) -{ - va_list ap; - struct output strout; - - va_start(ap, fmt); - strout.nextc = outbuf; - strout.nleft = length; - strout.fd = BLOCK_OUT; - strout.flags = 0; - doformat(&strout, fmt, ap); - outc('\0', &strout); - if (strout.flags & OUTPUT_ERR) - outbuf[length - 1] = '\0'; - va_end(ap); -} - -/* - * Formatted output. This routine handles a subset of the printf formats: - * - Formats supported: d, u, o, p, X, s, and c. - * - The x format is also accepted but is treated like X. - * - The l, ll and q modifiers are accepted. - * - The - and # flags are accepted; # only works with the o format. - * - Width and precision may be specified with any format except c. - * - An * may be given for the width or precision. - * - The obsolete practice of preceding the width with a zero to get - * zero padding is not supported; use the precision field. - * - A % may be printed by writing %% in the format string. - */ - -#define TEMPSIZE 24 - -#ifdef BSD4_4 -#define HAVE_VASPRINTF 1 -#endif - -void -doformat(struct output *dest, const char *f, va_list ap) -{ -#if HAVE_VASPRINTF - char *s; - - vasprintf(&s, f, ap); - outstr(s, dest); - free(s); -#else /* !HAVE_VASPRINTF */ - static const char digit[] = "0123456789ABCDEF"; - char c; - char temp[TEMPSIZE]; - int flushleft; - int sharp; - int width; - int prec; - int islong; - int isquad; - char *p; - int sign; -#ifdef BSD4_4 - quad_t l; - u_quad_t num; -#else - long l; - u_long num; -#endif - unsigned base; - int len; - int size; - int pad; - - while ((c = *f++) != '\0') { - if (c != '%') { - outc(c, dest); - continue; - } - flushleft = 0; - sharp = 0; - width = 0; - prec = -1; - islong = 0; - isquad = 0; - for (;;) { - if (*f == '-') - flushleft++; - else if (*f == '#') - sharp++; - else - break; - f++; - } - if (*f == '*') { - width = va_arg(ap, int); - f++; - } else { - while (is_digit(*f)) { - width = 10 * width + digit_val(*f++); - } - } - if (*f == '.') { - if (*++f == '*') { - prec = va_arg(ap, int); - f++; - } else { - prec = 0; - while (is_digit(*f)) { - prec = 10 * prec + digit_val(*f++); - } - } - } - if (*f == 'l') { - f++; - if (*f == 'l') { - isquad++; - f++; - } else - islong++; - } else if (*f == 'q') { - isquad++; - f++; - } - switch (*f) { - case 'd': -#ifdef BSD4_4 - if (isquad) - l = va_arg(ap, quad_t); - else -#endif - if (islong) - l = va_arg(ap, long); - else - l = va_arg(ap, int); - sign = 0; - num = l; - if (l < 0) { - num = -l; - sign = 1; - } - base = 10; - goto number; - case 'u': - base = 10; - goto uns_number; - case 'o': - base = 8; - goto uns_number; - case 'p': - outc('0', dest); - outc('x', dest); - /*FALLTHROUGH*/ - case 'x': - /* we don't implement 'x'; treat like 'X' */ - case 'X': - base = 16; -uns_number: /* an unsigned number */ - sign = 0; -#ifdef BSD4_4 - if (isquad) - num = va_arg(ap, u_quad_t); - else -#endif - if (islong) - num = va_arg(ap, unsigned long); - else - num = va_arg(ap, unsigned int); -number: /* process a number */ - p = temp + TEMPSIZE - 1; - *p = '\0'; - while (num) { - *--p = digit[num % base]; - num /= base; - } - len = (temp + TEMPSIZE - 1) - p; - if (prec < 0) - prec = 1; - if (sharp && *f == 'o' && prec <= len) - prec = len + 1; - pad = 0; - if (width) { - size = len; - if (size < prec) - size = prec; - size += sign; - pad = width - size; - if (flushleft == 0) { - while (--pad >= 0) - outc(' ', dest); - } - } - if (sign) - outc('-', dest); - prec -= len; - while (--prec >= 0) - outc('0', dest); - while (*p) - outc(*p++, dest); - while (--pad >= 0) - outc(' ', dest); - break; - case 's': - p = va_arg(ap, char *); - pad = 0; - if (width) { - len = strlen(p); - if (prec >= 0 && len > prec) - len = prec; - pad = width - len; - if (flushleft == 0) { - while (--pad >= 0) - outc(' ', dest); - } - } - prec++; - while (--prec != 0 && *p) - outc(*p++, dest); - while (--pad >= 0) - outc(' ', dest); - break; - case 'c': - c = va_arg(ap, int); - outc(c, dest); - break; - default: - outc(*f, dest); - break; - } - f++; - } -#endif /* !HAVE_VASPRINTF */ -} - - - -/* - * Version of write which resumes after a signal is caught. - */ - -int -xwrite(int fd, char *buf, int nbytes) -{ - int ntry; - int i; - int n; - - n = nbytes; - ntry = 0; - for (;;) { - i = write(fd, buf, n); - if (i > 0) { - if ((n -= i) <= 0) - return nbytes; - buf += i; - ntry = 0; - } else if (i == 0) { - if (++ntry > 10) - return nbytes - n; - } else if (errno != EINTR) { - return -1; - } - } -} - - -/* - * Version of ioctl that retries after a signal is caught. - * XXX unused function - */ - -int -xioctl(int fd, unsigned long request, char *arg) -{ - int i; - - while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); - return i; -} diff --git a/sh/output.h b/sh/output.h deleted file mode 100644 index 9a199a0..0000000 --- a/sh/output.h +++ /dev/null @@ -1,81 +0,0 @@ -/* $NetBSD: output.h,v 1.17 2003/08/07 09:05:36 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)output.h 8.2 (Berkeley) 5/4/95 - */ - -#ifndef OUTPUT_INCL - -#include <stdarg.h> - -struct output { - char *nextc; - int nleft; - char *buf; - int bufsize; - short fd; - short flags; -}; - -extern struct output output; -extern struct output errout; -extern struct output memout; -extern struct output *out1; -extern struct output *out2; - -void open_mem(char *, int, struct output *); -void out1str(const char *); -void out2str(const char *); -void outstr(const char *, struct output *); -void emptyoutbuf(struct output *); -void flushall(void); -void flushout(struct output *); -void freestdout(void); -void outfmt(struct output *, const char *, ...) - __attribute__((__format__(__printf__,2,3))); -void out1fmt(const char *, ...) - __attribute__((__format__(__printf__,1,2))); -void dprintf(const char *, ...) - __attribute__((__format__(__printf__,1,2))); -void fmtstr(char *, size_t, const char *, ...) - __attribute__((__format__(__printf__,3,4))); -void doformat(struct output *, const char *, va_list); -int xwrite(int, char *, int); -int xioctl(int, unsigned long, char *); - -#define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c))) -#define out1c(c) outc(c, out1); -#define out2c(c) outc(c, out2); - -#define OUTPUT_INCL -#endif diff --git a/sh/parser.c b/sh/parser.c deleted file mode 100644 index faf0268..0000000 --- a/sh/parser.c +++ /dev/null @@ -1,1654 +0,0 @@ -/* $NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; -#else -__RCSID("$NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $"); -#endif -#endif /* not lint */ - -#include <stdlib.h> - -#include "shell.h" -#include "parser.h" -#include "nodes.h" -#include "expand.h" /* defines rmescapes() */ -#include "eval.h" /* defines commandname */ -#include "redir.h" /* defines copyfd() */ -#include "syntax.h" -#include "options.h" -#include "input.h" -#include "output.h" -#include "var.h" -#include "error.h" -#include "memalloc.h" -#include "mystring.h" -#include "alias.h" -#include "show.h" -#ifndef SMALL -#include "myhistedit.h" -#endif - -/* - * Shell command parser. - */ - -#define EOFMARKLEN 79 - -/* values returned by readtoken */ -#include "token.h" - -#define OPENBRACE '{' -#define CLOSEBRACE '}' - - -struct heredoc { - struct heredoc *next; /* next here document in list */ - union node *here; /* redirection node */ - char *eofmark; /* string indicating end of input */ - int striptabs; /* if set, strip leading tabs */ -}; - - - -static 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 */ -MKINIT int tokpushback; /* last token pushed back */ -char *wordtext; /* text of last word returned by readtoken */ -MKINIT 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 */ - - -STATIC union node *list(int); -STATIC union node *andor(void); -STATIC union node *pipeline(void); -STATIC union node *command(void); -STATIC union node *simplecmd(union node **, union node *); -STATIC union node *makename(void); -STATIC void parsefname(void); -STATIC void parseheredoc(void); -STATIC int peektoken(void); -STATIC int readtoken(void); -STATIC int xxreadtoken(void); -STATIC int readtoken1(int, char const *, char *, int); -STATIC int noexpand(char *); -STATIC void synexpect(int) __attribute__((__noreturn__)); -STATIC void synerror(const char *) __attribute__((__noreturn__)); -STATIC void setprompt(int); - - -/* - * Read and parse a command. Returns NEOF on end of file. (NULL is a - * valid parse tree indicating a blank line.) - */ - -union node * -parsecmd(int interact) -{ - int t; - - tokpushback = 0; - doprompt = interact; - if (doprompt) - setprompt(1); - else - setprompt(0); - needprompt = 0; - t = readtoken(); - if (t == TEOF) - return NEOF; - if (t == TNL) - return NULL; - tokpushback++; - return list(1); -} - - -STATIC union node * -list(int nlflag) -{ - union node *n1, *n2, *n3; - int tok; - - checkkwd = 2; - if (nlflag == 0 && tokendlist[peektoken()]) - return NULL; - n1 = NULL; - for (;;) { - n2 = andor(); - tok = readtoken(); - if (tok == TBACKGND) { - if (n2->type == NCMD || n2->type == NPIPE) { - n2->ncmd.backgnd = 1; - } else if (n2->type == NREDIR) { - n2->type = NBACKGND; - } else { - n3 = (union node *)stalloc(sizeof (struct nredir)); - n3->type = NBACKGND; - n3->nredir.n = n2; - n3->nredir.redirect = NULL; - n2 = n3; - } - } - if (n1 == NULL) { - n1 = n2; - } - else { - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = NSEMI; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; - } - switch (tok) { - case TBACKGND: - case TSEMI: - tok = readtoken(); - /* fall through */ - case TNL: - if (tok == TNL) { - parseheredoc(); - if (nlflag) - return n1; - } else { - tokpushback++; - } - checkkwd = 2; - if (tokendlist[peektoken()]) - return n1; - break; - case TEOF: - if (heredoclist) - parseheredoc(); - else - pungetc(); /* push back EOF on input */ - return n1; - default: - if (nlflag) - synexpect(-1); - tokpushback++; - return n1; - } - } -} - - - -STATIC union node * -andor(void) -{ - union node *n1, *n2, *n3; - int t; - - n1 = pipeline(); - for (;;) { - if ((t = readtoken()) == TAND) { - t = NAND; - } else if (t == TOR) { - t = NOR; - } else { - tokpushback++; - return n1; - } - n2 = pipeline(); - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = t; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; - } -} - - - -STATIC union node * -pipeline(void) -{ - union node *n1, *n2, *pipenode; - struct nodelist *lp, *prev; - int negate; - - negate = 0; - TRACE(("pipeline: entered\n")); - while (readtoken() == TNOT) - negate = !negate; - tokpushback++; - n1 = command(); - if (readtoken() == TPIPE) { - pipenode = (union node *)stalloc(sizeof (struct npipe)); - pipenode->type = NPIPE; - pipenode->npipe.backgnd = 0; - lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - pipenode->npipe.cmdlist = lp; - lp->n = n1; - do { - prev = lp; - lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - lp->n = command(); - prev->next = lp; - } while (readtoken() == TPIPE); - lp->next = NULL; - n1 = pipenode; - } - tokpushback++; - if (negate) { - n2 = (union node *)stalloc(sizeof (struct nnot)); - n2->type = NNOT; - n2->nnot.com = n1; - return n2; - } else - return n1; -} - - - -STATIC union node * -command(void) -{ - union node *n1, *n2; - union node *ap, **app; - union node *cp, **cpp; - union node *redir, **rpp; - int t, negate = 0; - - checkkwd = 2; - redir = NULL; - n1 = NULL; - rpp = &redir; - - /* Check for redirection which may precede command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; - - while (readtoken() == TNOT) { - TRACE(("command: TNOT recognized\n")); - negate = !negate; - } - tokpushback++; - - switch (readtoken()) { - case TIF: - n1 = (union node *)stalloc(sizeof (struct nif)); - n1->type = NIF; - n1->nif.test = list(0); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n1->nif.ifpart = list(0); - n2 = n1; - while (readtoken() == TELIF) { - n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); - n2 = n2->nif.elsepart; - n2->type = NIF; - n2->nif.test = list(0); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n2->nif.ifpart = list(0); - } - if (lasttoken == TELSE) - n2->nif.elsepart = list(0); - else { - n2->nif.elsepart = NULL; - tokpushback++; - } - if (readtoken() != TFI) - synexpect(TFI); - checkkwd = 1; - break; - case TWHILE: - case TUNTIL: { - int got; - n1 = (union node *)stalloc(sizeof (struct nbinary)); - n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; - n1->nbinary.ch1 = list(0); - if ((got=readtoken()) != TDO) { -TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); - synexpect(TDO); - } - n1->nbinary.ch2 = list(0); - if (readtoken() != TDONE) - synexpect(TDONE); - checkkwd = 1; - break; - } - case TFOR: - if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) - synerror("Bad for loop variable"); - n1 = (union node *)stalloc(sizeof (struct nfor)); - n1->type = NFOR; - n1->nfor.var = wordtext; - if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { - app = ≈ - while (readtoken() == TWORD) { - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - *app = n2; - app = &n2->narg.next; - } - *app = NULL; - n1->nfor.args = ap; - if (lasttoken != TNL && lasttoken != TSEMI) - synexpect(-1); - } else { - static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, - '@', '=', '\0'}; - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = argvars; - n2->narg.backquote = NULL; - n2->narg.next = NULL; - n1->nfor.args = n2; - /* - * Newline or semicolon here is optional (but note - * that the original Bourne shell only allowed NL). - */ - if (lasttoken != TNL && lasttoken != TSEMI) - tokpushback++; - } - checkkwd = 2; - if ((t = readtoken()) == TDO) - t = TDONE; - else if (t == TBEGIN) - t = TEND; - else - synexpect(-1); - n1->nfor.body = list(0); - if (readtoken() != t) - synexpect(t); - checkkwd = 1; - break; - case TCASE: - n1 = (union node *)stalloc(sizeof (struct ncase)); - n1->type = NCASE; - if (readtoken() != TWORD) - synexpect(TWORD); - n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - n2->narg.next = NULL; - while (readtoken() == TNL); - if (lasttoken != TWORD || ! equal(wordtext, "in")) - synerror("expecting \"in\""); - cpp = &n1->ncase.cases; - noalias = 1; - checkkwd = 2, readtoken(); - do { - *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); - cp->type = NCLIST; - app = &cp->nclist.pattern; - for (;;) { - *app = ap = (union node *)stalloc(sizeof (struct narg)); - ap->type = NARG; - ap->narg.text = wordtext; - ap->narg.backquote = backquotelist; - if (checkkwd = 2, readtoken() != TPIPE) - break; - app = &ap->narg.next; - readtoken(); - } - ap->narg.next = NULL; - noalias = 0; - if (lasttoken != TRP) { - synexpect(TRP); - } - cp->nclist.body = list(0); - - checkkwd = 2; - if ((t = readtoken()) != TESAC) { - if (t != TENDCASE) { - noalias = 0; - synexpect(TENDCASE); - } else { - noalias = 1; - checkkwd = 2; - readtoken(); - } - } - cpp = &cp->nclist.next; - } while(lasttoken != TESAC); - noalias = 0; - *cpp = NULL; - checkkwd = 1; - break; - case TLP: - n1 = (union node *)stalloc(sizeof (struct nredir)); - n1->type = NSUBSHELL; - n1->nredir.n = list(0); - n1->nredir.redirect = NULL; - if (readtoken() != TRP) - synexpect(TRP); - checkkwd = 1; - break; - case TBEGIN: - n1 = list(0); - if (readtoken() != TEND) - synexpect(TEND); - checkkwd = 1; - break; - /* Handle an empty command like other simple commands. */ - case TSEMI: - /* - * An empty command before a ; doesn't make much sense, and - * should certainly be disallowed in the case of `if ;'. - */ - if (!redir) - synexpect(-1); - case TAND: - case TOR: - case TNL: - case TEOF: - case TWORD: - case TRP: - tokpushback++; - n1 = simplecmd(rpp, redir); - goto checkneg; - default: - synexpect(-1); - /* NOTREACHED */ - } - - /* Now check for redirection which may follow command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; - *rpp = NULL; - if (redir) { - if (n1->type != NSUBSHELL) { - n2 = (union node *)stalloc(sizeof (struct nredir)); - n2->type = NREDIR; - n2->nredir.n = n1; - n1 = n2; - } - n1->nredir.redirect = redir; - } - -checkneg: - if (negate) { - n2 = (union node *)stalloc(sizeof (struct nnot)); - n2->type = NNOT; - n2->nnot.com = n1; - return n2; - } - else - return n1; -} - - -STATIC union node * -simplecmd(union node **rpp, union node *redir) -{ - union node *args, **app; - union node **orig_rpp = rpp; - union node *n = NULL, *n2; - int negate = 0; - - /* If we don't have any redirections already, then we must reset */ - /* rpp to be the address of the local redir variable. */ - if (redir == 0) - rpp = &redir; - - args = NULL; - app = &args; - /* - * We save the incoming value, because we need this for shell - * functions. There can not be a redirect or an argument between - * the function name and the open parenthesis. - */ - orig_rpp = rpp; - - while (readtoken() == TNOT) { - TRACE(("command: TNOT recognized\n")); - negate = !negate; - } - tokpushback++; - - for (;;) { - if (readtoken() == TWORD) { - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - *app = n; - app = &n->narg.next; - } else if (lasttoken == TREDIR) { - *rpp = n = redirnode; - rpp = &n->nfile.next; - parsefname(); /* read name of redirection file */ - } else if (lasttoken == TLP && app == &args->narg.next - && rpp == orig_rpp) { - /* We have a function */ - if (readtoken() != TRP) - synexpect(TRP); -#ifdef notdef - if (! goodname(n->narg.text)) - synerror("Bad function name"); -#endif - n->type = NDEFUN; - n->narg.next = command(); - goto checkneg; - } else { - tokpushback++; - break; - } - } - *app = NULL; - *rpp = NULL; - n = (union node *)stalloc(sizeof (struct ncmd)); - n->type = NCMD; - n->ncmd.backgnd = 0; - n->ncmd.args = args; - n->ncmd.redirect = redir; - -checkneg: - if (negate) { - n2 = (union node *)stalloc(sizeof (struct nnot)); - n2->type = NNOT; - n2->nnot.com = n; - return n2; - } - else - return n; -} - -STATIC union node * -makename(void) -{ - union node *n; - - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - return n; -} - -void fixredir(union node *n, const char *text, int err) - { - TRACE(("Fix redir %s %d\n", text, err)); - if (!err) - n->ndup.vname = NULL; - - if (is_digit(text[0]) && text[1] == '\0') - n->ndup.dupfd = digit_val(text[0]); - else if (text[0] == '-' && text[1] == '\0') - n->ndup.dupfd = -1; - else { - - if (err) - synerror("Bad fd number"); - else - n->ndup.vname = makename(); - } -} - - -STATIC void -parsefname(void) -{ - union node *n = redirnode; - - if (readtoken() != TWORD) - synexpect(-1); - if (n->type == NHERE) { - struct heredoc *here = heredoc; - struct heredoc *p; - int i; - - if (quoteflag == 0) - n->type = NXHERE; - TRACE(("Here document %d\n", n->type)); - if (here->striptabs) { - while (*wordtext == '\t') - wordtext++; - } - if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) - synerror("Illegal eof marker for << redirection"); - rmescapes(wordtext); - here->eofmark = wordtext; - here->next = NULL; - if (heredoclist == NULL) - heredoclist = here; - else { - for (p = heredoclist ; p->next ; p = p->next); - p->next = here; - } - } else if (n->type == NTOFD || n->type == NFROMFD) { - fixredir(n, wordtext, 0); - } else { - n->nfile.fname = makename(); - } -} - - -/* - * Input any here documents. - */ - -STATIC void -parseheredoc(void) -{ - struct heredoc *here; - union node *n; - - while (heredoclist) { - here = heredoclist; - heredoclist = here->next; - if (needprompt) { - setprompt(2); - needprompt = 0; - } - readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, - here->eofmark, here->striptabs); - n = (union node *)stalloc(sizeof (struct narg)); - n->narg.type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - here->here->nhere.doc = n; - } -} - -STATIC int -peektoken(void) -{ - int t; - - t = readtoken(); - tokpushback++; - return (t); -} - -STATIC int -readtoken(void) -{ - int t; - int savecheckkwd = checkkwd; -#ifdef DEBUG - int alreadyseen = tokpushback; -#endif - struct alias *ap; - - top: - t = xxreadtoken(); - - if (checkkwd) { - /* - * eat newlines - */ - if (checkkwd == 2) { - checkkwd = 0; - while (t == TNL) { - parseheredoc(); - t = xxreadtoken(); - } - } else - checkkwd = 0; - /* - * check for keywords and aliases - */ - if (t == TWORD && !quoteflag) - { - const char *const *pp; - - for (pp = parsekwd; *pp; pp++) { - if (**pp == *wordtext && equal(*pp, wordtext)) - { - lasttoken = t = pp - - parsekwd + KWDOFFSET; - TRACE(("keyword %s recognized\n", tokname[t])); - goto out; - } - } - if(!noalias && - (ap = lookupalias(wordtext, 1)) != NULL) { - pushstring(ap->val, strlen(ap->val), ap); - checkkwd = savecheckkwd; - goto top; - } - } -out: - checkkwd = (t == TNOT) ? savecheckkwd : 0; - } -#ifdef DEBUG - if (!alreadyseen) - TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); - else - TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); -#endif - return (t); -} - - -/* - * Read the next input token. - * If the token is a word, we set backquotelist to the list of cmds in - * backquotes. We set quoteflag to true if any part of the word was - * quoted. - * If the token is TREDIR, then we set redirnode to a structure containing - * the redirection. - * In all cases, the variable startlinno is set to the number of the line - * on which the token starts. - * - * [Change comment: here documents and internal procedures] - * [Readtoken shouldn't have any arguments. Perhaps we should make the - * word parsing code into a separate routine. In this case, readtoken - * doesn't need to have any internal procedures, but parseword does. - * We could also make parseoperator in essence the main routine, and - * have parseword (readtoken1?) handle both words and redirection.] - */ - -#define RETURN(token) return lasttoken = token - -STATIC int -xxreadtoken(void) -{ - int c; - - if (tokpushback) { - tokpushback = 0; - return lasttoken; - } - if (needprompt) { - setprompt(2); - needprompt = 0; - } - startlinno = plinno; - for (;;) { /* until token or start of word found */ - c = pgetc_macro(); - if (c == ' ' || c == '\t') - continue; /* quick check for white space first */ - switch (c) { - case ' ': case '\t': - continue; - case '#': - while ((c = pgetc()) != '\n' && c != PEOF); - pungetc(); - continue; - case '\\': - if (pgetc() == '\n') { - startlinno = ++plinno; - if (doprompt) - setprompt(2); - else - setprompt(0); - continue; - } - pungetc(); - goto breakloop; - case '\n': - plinno++; - needprompt = doprompt; - RETURN(TNL); - case PEOF: - RETURN(TEOF); - case '&': - if (pgetc() == '&') - RETURN(TAND); - pungetc(); - RETURN(TBACKGND); - case '|': - if (pgetc() == '|') - RETURN(TOR); - pungetc(); - RETURN(TPIPE); - case ';': - if (pgetc() == ';') - RETURN(TENDCASE); - pungetc(); - RETURN(TSEMI); - case '(': - RETURN(TLP); - case ')': - RETURN(TRP); - default: - goto breakloop; - } - } -breakloop: - return readtoken1(c, BASESYNTAX, (char *)NULL, 0); -#undef RETURN -} - - - -/* - * If eofmark is NULL, read a word or a redirection symbol. If eofmark - * is not NULL, read a here document. In the latter case, eofmark is the - * word which marks the end of the document and striptabs is true if - * leading tabs should be stripped from the document. The argument firstc - * is the first character of the input token or document. - * - * Because C does not have internal subroutines, I have simulated them - * using goto's to implement the subroutine linkage. The following macros - * will run code that appears at the end of readtoken1. - */ - -#define CHECKEND() {goto checkend; checkend_return:;} -#define PARSEREDIR() {goto parseredir; parseredir_return:;} -#define PARSESUB() {goto parsesub; parsesub_return:;} -#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} -#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} -#define PARSEARITH() {goto parsearith; parsearith_return:;} - -/* - * Keep track of nested doublequotes in dblquote and doublequotep. - * We use dblquote for the first 32 levels, and we expand to a malloc'ed - * region for levels above that. Usually we never need to malloc. - * This code assumes that an int is 32 bits. We don't use uint32_t, - * because the rest of the code does not. - */ -#define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \ - (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32)))) - -#define SETDBLQUOTE() \ - if (varnest < 32) \ - dblquote |= (1 << varnest); \ - else \ - dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32)) - -#define CLRDBLQUOTE() \ - if (varnest < 32) \ - dblquote &= ~(1 << varnest); \ - else \ - dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32)) - -STATIC int -readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) -{ - int c = firstc; - char *out; - int len; - char line[EOFMARKLEN + 1]; - struct nodelist *bqlist; - int quotef; - int *dblquotep = NULL; - size_t maxnest = 32; - int dblquote; - int varnest; /* levels of variables expansion */ - int arinest; /* levels of arithmetic expansion */ - int parenlevel; /* levels of parens in arithmetic */ - int oldstyle; - char const *prevsyntax = NULL; /* syntax before arithmetic */ -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &maxnest; - (void) &dblquotep; - (void) &out; - (void) "ef; - (void) &dblquote; - (void) &varnest; - (void) &arinest; - (void) &parenlevel; - (void) &oldstyle; - (void) &prevsyntax; - (void) &syntax; -#endif - - startlinno = plinno; - dblquote = 0; - varnest = 0; - if (syntax == DQSYNTAX) { - SETDBLQUOTE(); - } - quotef = 0; - bqlist = NULL; - arinest = 0; - parenlevel = 0; - - STARTSTACKSTR(out); - loop: { /* for each line, until end of word */ -#if ATTY - if (c == '\034' && doprompt - && attyset() && ! equal(termval(), "emacs")) { - attyline(); - if (syntax == BASESYNTAX) - return readtoken(); - c = pgetc(); - goto loop; - } -#endif - CHECKEND(); /* set c to PEOF if at end of here document */ - for (;;) { /* until end of line or end of word */ - CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ - switch(syntax[c]) { - case CNL: /* '\n' */ - if (syntax == BASESYNTAX) - goto endword; /* exit outer loop */ - USTPUTC(c, out); - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - c = pgetc(); - goto loop; /* continue outer loop */ - case CWORD: - USTPUTC(c, out); - break; - case CCTL: - if (eofmark == NULL || ISDBLQUOTE()) - USTPUTC(CTLESC, out); - USTPUTC(c, out); - break; - case CBACK: /* backslash */ - c = pgetc(); - if (c == PEOF) { - USTPUTC('\\', out); - pungetc(); - break; - } - if (c == '\n') { - if (doprompt) - setprompt(2); - else - setprompt(0); - break; - } - quotef = 1; - if (ISDBLQUOTE() && c != '\\' && - c != '`' && c != '$' && - (c != '"' || eofmark != NULL)) - USTPUTC('\\', out); - if (SQSYNTAX[c] == CCTL) - USTPUTC(CTLESC, out); - else if (eofmark == NULL) { - USTPUTC(CTLQUOTEMARK, out); - USTPUTC(c, out); - if (varnest != 0) - USTPUTC(CTLQUOTEEND, out); - break; - } - USTPUTC(c, out); - break; - case CSQUOTE: - if (syntax != SQSYNTAX) { - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - quotef = 1; - syntax = SQSYNTAX; - break; - } - if (eofmark != NULL && arinest == 0 && - varnest == 0) { - /* Ignore inside quoted here document */ - USTPUTC(c, out); - break; - } - /* End of single quotes... */ - if (arinest) - syntax = ARISYNTAX; - else { - syntax = BASESYNTAX; - if (varnest != 0) - USTPUTC(CTLQUOTEEND, out); - } - break; - case CDQUOTE: - if (eofmark != NULL && arinest == 0 && - varnest == 0) { - /* Ignore inside here document */ - USTPUTC(c, out); - break; - } - quotef = 1; - if (arinest) { - if (ISDBLQUOTE()) { - syntax = ARISYNTAX; - CLRDBLQUOTE(); - } else { - syntax = DQSYNTAX; - SETDBLQUOTE(); - USTPUTC(CTLQUOTEMARK, out); - } - break; - } - if (eofmark != NULL) - break; - if (ISDBLQUOTE()) { - if (varnest != 0) - USTPUTC(CTLQUOTEEND, out); - syntax = BASESYNTAX; - CLRDBLQUOTE(); - } else { - syntax = DQSYNTAX; - SETDBLQUOTE(); - USTPUTC(CTLQUOTEMARK, out); - } - break; - case CVAR: /* '$' */ - PARSESUB(); /* parse substitution */ - break; - case CENDVAR: /* CLOSEBRACE */ - if (varnest > 0 && !ISDBLQUOTE()) { - varnest--; - USTPUTC(CTLENDVAR, out); - } else { - USTPUTC(c, out); - } - break; - case CLP: /* '(' in arithmetic */ - parenlevel++; - USTPUTC(c, out); - break; - case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { - USTPUTC(c, out); - --parenlevel; - } else { - if (pgetc() == ')') { - if (--arinest == 0) { - USTPUTC(CTLENDARI, out); - syntax = prevsyntax; - if (syntax == DQSYNTAX) - SETDBLQUOTE(); - else - CLRDBLQUOTE(); - } else - USTPUTC(')', out); - } else { - /* - * unbalanced parens - * (don't 2nd guess - no error) - */ - pungetc(); - USTPUTC(')', out); - } - } - break; - case CBQUOTE: /* '`' */ - PARSEBACKQOLD(); - break; - case CEOF: - goto endword; /* exit outer loop */ - default: - if (varnest == 0) - goto endword; /* exit outer loop */ - USTPUTC(c, out); - } - c = pgetc_macro(); - } - } -endword: - if (syntax == ARISYNTAX) - synerror("Missing '))'"); - if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) - synerror("Unterminated quoted string"); - if (varnest != 0) { - startlinno = plinno; - /* { */ - synerror("Missing '}'"); - } - USTPUTC('\0', out); - len = out - stackblock(); - out = stackblock(); - if (eofmark == NULL) { - if ((c == '>' || c == '<') - && quotef == 0 - && len <= 2 - && (*out == '\0' || is_digit(*out))) { - PARSEREDIR(); - return lasttoken = TREDIR; - } else { - pungetc(); - } - } - quoteflag = quotef; - backquotelist = bqlist; - grabstackblock(len); - wordtext = out; - if (dblquotep != NULL) - ckfree(dblquotep); - return lasttoken = TWORD; -/* end of readtoken routine */ - - - -/* - * Check to see whether we are at the end of the here document. When this - * is called, c is set to the first character of the next input line. If - * we are at the end of the here document, this routine sets the c to PEOF. - */ - -checkend: { - if (eofmark) { - if (striptabs) { - while (c == '\t') - c = pgetc(); - } - if (c == *eofmark) { - if (pfgets(line, sizeof line) != NULL) { - char *p, *q; - - p = line; - for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); - if (*p == '\n' && *q == '\0') { - c = PEOF; - plinno++; - needprompt = doprompt; - } else { - pushstring(line, strlen(line), NULL); - } - } - } - } - goto checkend_return; -} - - -/* - * Parse a redirection operator. The variable "out" points to a string - * specifying the fd to be redirected. The variable "c" contains the - * first character of the redirection operator. - */ - -parseredir: { - char fd = *out; - union node *np; - - np = (union node *)stalloc(sizeof (struct nfile)); - if (c == '>') { - np->nfile.fd = 1; - c = pgetc(); - if (c == '>') - np->type = NAPPEND; - else if (c == '|') - np->type = NCLOBBER; - else if (c == '&') - np->type = NTOFD; - else { - np->type = NTO; - pungetc(); - } - } else { /* c == '<' */ - np->nfile.fd = 0; - switch (c = pgetc()) { - case '<': - if (sizeof (struct nfile) != sizeof (struct nhere)) { - np = (union node *)stalloc(sizeof (struct nhere)); - np->nfile.fd = 0; - } - np->type = NHERE; - heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); - heredoc->here = np; - if ((c = pgetc()) == '-') { - heredoc->striptabs = 1; - } else { - heredoc->striptabs = 0; - pungetc(); - } - break; - - case '&': - np->type = NFROMFD; - break; - - case '>': - np->type = NFROMTO; - break; - - default: - np->type = NFROM; - pungetc(); - break; - } - } - if (fd != '\0') - np->nfile.fd = digit_val(fd); - redirnode = np; - goto parseredir_return; -} - - -/* - * Parse a substitution. At this point, we have read the dollar sign - * and nothing else. - */ - -parsesub: { - int subtype; - int typeloc; - int flags; - char *p; - static const char types[] = "}-+?="; - - c = pgetc(); - if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) { - USTPUTC('$', out); - pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ - if (pgetc() == '(') { - PARSEARITH(); - } else { - pungetc(); - PARSEBACKQNEW(); - } - } else { - USTPUTC(CTLVAR, out); - typeloc = out - stackblock(); - USTPUTC(VSNORMAL, out); - subtype = VSNORMAL; - if (c == OPENBRACE) { - c = pgetc(); - if (c == '#') { - if ((c = pgetc()) == CLOSEBRACE) - c = '#'; - else - subtype = VSLENGTH; - } - else - subtype = 0; - } - if (is_name(c)) { - do { - STPUTC(c, out); - c = pgetc(); - } while (is_in_name(c)); - } else if (is_digit(c)) { - do { - USTPUTC(c, out); - c = pgetc(); - } while (is_digit(c)); - } - else if (is_special(c)) { - USTPUTC(c, out); - c = pgetc(); - } - else -badsub: synerror("Bad substitution"); - - STPUTC('=', out); - flags = 0; - if (subtype == 0) { - switch (c) { - case ':': - flags = VSNUL; - c = pgetc(); - /*FALLTHROUGH*/ - default: - p = strchr(types, c); - if (p == NULL) - goto badsub; - subtype = p - types + VSNORMAL; - break; - case '%': - case '#': - { - int cc = c; - subtype = c == '#' ? VSTRIMLEFT : - VSTRIMRIGHT; - c = pgetc(); - if (c == cc) - subtype++; - else - pungetc(); - break; - } - } - } else { - pungetc(); - } - if (ISDBLQUOTE() || arinest) - flags |= VSQUOTE; - *(stackblock() + typeloc) = subtype | flags; - if (subtype != VSNORMAL) { - varnest++; - if (varnest >= maxnest) { - dblquotep = ckrealloc(dblquotep, maxnest / 8); - dblquotep[(maxnest / 32) - 1] = 0; - maxnest += 32; - } - } - } - goto parsesub_return; -} - - -/* - * Called to parse command substitutions. Newstyle is set if the command - * is enclosed inside $(...); nlpp is a pointer to the head of the linked - * list of commands (passed by reference), and savelen is the number of - * characters on the top of the stack which must be preserved. - */ - -parsebackq: { - struct nodelist **nlpp; - int savepbq; - union node *n; - char *volatile str; - struct jmploc jmploc; - struct jmploc *volatile savehandler; - int savelen; - int saveprompt; -#ifdef __GNUC__ - (void) &saveprompt; -#endif - - savepbq = parsebackquote; - if (setjmp(jmploc.loc)) { - if (str) - ckfree(str); - parsebackquote = 0; - handler = savehandler; - longjmp(handler->loc, 1); - } - INTOFF; - str = NULL; - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - memcpy(str, stackblock(), savelen); - } - savehandler = handler; - handler = &jmploc; - INTON; - if (oldstyle) { - /* We must read until the closing backquote, giving special - treatment to some slashes, and then push the string and - reread it as input, interpreting it normally. */ - char *pout; - int pc; - int psavelen; - char *pstr; - - - STARTSTACKSTR(pout); - for (;;) { - if (needprompt) { - setprompt(2); - needprompt = 0; - } - switch (pc = pgetc()) { - case '`': - goto done; - - case '\\': - if ((pc = pgetc()) == '\n') { - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - /* - * If eating a newline, avoid putting - * the newline into the new character - * stream (via the STPUTC after the - * switch). - */ - continue; - } - if (pc != '\\' && pc != '`' && pc != '$' - && (!ISDBLQUOTE() || pc != '"')) - STPUTC('\\', pout); - break; - - case '\n': - plinno++; - needprompt = doprompt; - break; - - case PEOF: - startlinno = plinno; - synerror("EOF in backquote substitution"); - break; - - default: - break; - } - STPUTC(pc, pout); - } -done: - STPUTC('\0', pout); - psavelen = pout - stackblock(); - if (psavelen > 0) { - pstr = grabstackstr(pout); - setinputstring(pstr, 1); - } - } - nlpp = &bqlist; - while (*nlpp) - nlpp = &(*nlpp)->next; - *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - (*nlpp)->next = NULL; - parsebackquote = oldstyle; - - if (oldstyle) { - saveprompt = doprompt; - doprompt = 0; - } - - n = list(0); - - if (oldstyle) - doprompt = saveprompt; - else { - if (readtoken() != TRP) - synexpect(TRP); - } - - (*nlpp)->n = n; - if (oldstyle) { - /* - * Start reading from old file again, ignoring any pushed back - * tokens left from the backquote parsing - */ - popfile(); - tokpushback = 0; - } - while (stackblocksize() <= savelen) - growstackblock(); - STARTSTACKSTR(out); - if (str) { - memcpy(out, str, savelen); - STADJUST(savelen, out); - INTOFF; - ckfree(str); - str = NULL; - INTON; - } - parsebackquote = savepbq; - handler = savehandler; - if (arinest || ISDBLQUOTE()) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); - if (oldstyle) - goto parsebackq_oldreturn; - else - goto parsebackq_newreturn; -} - -/* - * Parse an arithmetic expansion (indicate start of one and set state) - */ -parsearith: { - - if (++arinest == 1) { - prevsyntax = syntax; - syntax = ARISYNTAX; - USTPUTC(CTLARI, out); - if (ISDBLQUOTE()) - USTPUTC('"',out); - else - USTPUTC(' ',out); - } else { - /* - * we collapse embedded arithmetic expansion to - * parenthesis, which should be equivalent - */ - USTPUTC('(', out); - } - goto parsearith_return; -} - -} /* end of readtoken */ - - - -#ifdef mkinit -RESET { - tokpushback = 0; - checkkwd = 0; -} -#endif - -/* - * Returns true if the text contains nothing to expand (no dollar signs - * or backquotes). - */ - -STATIC int -noexpand(char *text) -{ - char *p; - char c; - - p = text; - while ((c = *p++) != '\0') { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - p++; - else if (BASESYNTAX[(int)c] == CCTL) - return 0; - } - return 1; -} - - -/* - * Return true if the argument is a legal variable name (a letter or - * underscore followed by zero or more letters, underscores, and digits). - */ - -int -goodname(char *name) - { - char *p; - - p = name; - if (! is_name(*p)) - return 0; - while (*++p) { - if (! is_in_name(*p)) - return 0; - } - return 1; -} - - -/* - * Called when an unexpected token is read during the parse. The argument - * is the token that is expected, or -1 if more than one type of token can - * occur at this point. - */ - -STATIC void -synexpect(int token) -{ - char msg[64]; - - if (token >= 0) { - fmtstr(msg, 64, "%s unexpected (expecting %s)", - tokname[lasttoken], tokname[token]); - } else { - fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); - } - synerror(msg); - /* NOTREACHED */ -} - - -STATIC void -synerror(const char *msg) -{ - if (commandname) - outfmt(&errout, "%s: %d: ", commandname, startlinno); - outfmt(&errout, "Syntax error: %s\n", msg); - error((char *)NULL); - /* NOTREACHED */ -} - -STATIC void -setprompt(int which) -{ - whichprompt = which; - -#ifdef WITH_HISTORY - if (!el) -#endif -#ifdef WITH_LINENOISE - if (! in_interactive_mode() ) -#endif - out2str(getprompt(NULL)); -} - -/* - * called by editline -- any expansions to the prompt - * should be added here. - */ -const char * -getprompt(void *unused) - { - switch (whichprompt) { - case 0: - return ""; - case 1: - return ps1val(); - case 2: - return ps2val(); - default: - return "<internal prompt error>"; - } -} diff --git a/sh/parser.h b/sh/parser.h deleted file mode 100644 index b343c71..0000000 --- a/sh/parser.h +++ /dev/null @@ -1,82 +0,0 @@ -/* $NetBSD: parser.h,v 1.17 2004/06/26 22:09:49 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)parser.h 8.3 (Berkeley) 5/4/95 - */ - -/* control characters in argument strings */ -#define CTL_FIRST '\201' /* first 'special' character */ -#define CTLESC '\201' /* escape next character */ -#define CTLVAR '\202' /* variable defn */ -#define CTLENDVAR '\203' -#define CTLBACKQ '\204' -#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ -/* CTLBACKQ | CTLQUOTE == '\205' */ -#define CTLARI '\206' /* arithmetic expression */ -#define CTLENDARI '\207' -#define CTLQUOTEMARK '\210' -#define CTLQUOTEEND '\211' /* only inside ${...} */ -#define CTL_LAST '\211' /* last 'special' character */ - -/* variable substitution byte (follows CTLVAR) */ -#define VSTYPE 0x0f /* type of variable substitution */ -#define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ - -/* values of VSTYPE field */ -#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ -#define VSMINUS 0x2 /* ${var-text} */ -#define VSPLUS 0x3 /* ${var+text} */ -#define VSQUESTION 0x4 /* ${var?message} */ -#define VSASSIGN 0x5 /* ${var=text} */ -#define VSTRIMLEFT 0x6 /* ${var#pattern} */ -#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ -#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ -#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ -#define VSLENGTH 0xa /* ${#var} */ - - -/* - * NEOF is returned by parsecmd when it encounters an end of file. It - * must be distinct from NULL, so we use the address of a variable that - * happens to be handy. - */ -extern int tokpushback; -#define NEOF ((union node *)&tokpushback) -extern int whichprompt; /* 1 == PS1, 2 == PS2 */ - - -union node *parsecmd(int); -void fixredir(union node *, const char *, int); -int goodname(char *); -const char *getprompt(void *); diff --git a/sh/redir.c b/sh/redir.c deleted file mode 100644 index 5c4c286..0000000 --- a/sh/redir.c +++ /dev/null @@ -1,389 +0,0 @@ -/* $NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $"); -#endif -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/param.h> /* PIPE_BUF */ -#include <signal.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> - -/* - * Code for dealing with input/output redirection. - */ - -#include "main.h" -#include "shell.h" -#include "nodes.h" -#include "jobs.h" -#include "options.h" -#include "expand.h" -#include "redir.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" - - -#define EMPTY -2 /* marks an unused slot in redirtab */ -#ifndef PIPE_BUF -# define PIPESIZE 4096 /* amount of buffering in a pipe */ -#else -# define PIPESIZE PIPE_BUF -#endif - -#define signal bsd_signal - -MKINIT -struct redirtab { - struct redirtab *next; - short renamed[10]; -}; - - -MKINIT struct redirtab *redirlist; - -/* - * We keep track of whether or not fd0 has been redirected. This is for - * background commands, where we want to redirect fd0 to /dev/null only - * if it hasn't already been redirected. -*/ -int fd0_redirected = 0; - -STATIC void openredirect(union node *, char[10], int); -STATIC int openhere(union node *); - - -/* - * Process a list of redirection commands. If the REDIR_PUSH flag is set, - * old file descriptors are stashed away so that the redirection can be - * undone by calling popredir. If the REDIR_BACKQ flag is set, then the - * standard output, and the standard error if it becomes a duplicate of - * stdout, is saved in memory. - */ - -void -redirect(union node *redir, int flags) -{ - union node *n; - struct redirtab *sv = NULL; - int i; - int fd; - int try; - char memory[10]; /* file descriptors to write to memory */ - - for (i = 10 ; --i >= 0 ; ) - memory[i] = 0; - memory[1] = flags & REDIR_BACKQ; - if (flags & REDIR_PUSH) { - /* We don't have to worry about REDIR_VFORK here, as - * flags & REDIR_PUSH is never true if REDIR_VFORK is set. - */ - sv = ckmalloc(sizeof (struct redirtab)); - for (i = 0 ; i < 10 ; i++) - sv->renamed[i] = EMPTY; - sv->next = redirlist; - redirlist = sv; - } - for (n = redir ; n ; n = n->nfile.next) { - fd = n->nfile.fd; - try = 0; - if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && - n->ndup.dupfd == fd) - continue; /* redirect from/to same file descriptor */ - - if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { - INTOFF; -again: - if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { - switch (errno) { - case EBADF: - if (!try) { - openredirect(n, memory, flags); - try++; - goto again; - } - /* FALLTHROUGH*/ - default: - INTON; - error("%d: %s", fd, strerror(errno)); - /* NOTREACHED */ - } - } - if (!try) { - sv->renamed[fd] = i; - close(fd); - } - INTON; - } else { - close(fd); - } - if (fd == 0) - fd0_redirected++; - if (!try) - openredirect(n, memory, flags); - } - if (memory[1]) - out1 = &memout; - if (memory[2]) - out2 = &memout; -} - - -STATIC void -openredirect(union node *redir, char memory[10], int flags) -{ - int fd = redir->nfile.fd; - char *fname; - int f; - int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags; - - /* - * We suppress interrupts so that we won't leave open file - * descriptors around. This may not be such a good idea because - * an open of a device or a fifo can block indefinitely. - */ - INTOFF; - memory[fd] = 0; - switch (redir->nfile.type) { - case NFROM: - fname = redir->nfile.expfname; - if (flags & REDIR_VFORK) - eflags = O_NONBLOCK; - else - eflags = 0; - if ((f = open(fname, O_RDONLY|eflags)) < 0) - goto eopen; - if (eflags) - (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags); - break; - case NFROMTO: - fname = redir->nfile.expfname; - if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) - goto ecreate; - break; - case NTO: - if (Cflag) - oflags |= O_EXCL; - /* FALLTHROUGH */ - case NCLOBBER: - fname = redir->nfile.expfname; - if ((f = open(fname, oflags, 0666)) < 0) - goto ecreate; - break; - case NAPPEND: - fname = redir->nfile.expfname; - if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) - goto ecreate; - break; - case NTOFD: - case NFROMFD: - if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ - if (memory[redir->ndup.dupfd]) - memory[fd] = 1; - else - copyfd(redir->ndup.dupfd, fd); - } - INTON; - return; - case NHERE: - case NXHERE: - f = openhere(redir); - break; - default: - abort(); - } - - if (f != fd) { - copyfd(f, fd); - close(f); - } - INTON; - return; -ecreate: - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -eopen: - error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); -} - - -/* - * Handle here documents. Normally we fork off a process to write the - * data to a pipe. If the document is short, we can stuff the data in - * the pipe without forking. - */ - -STATIC int -openhere(union node *redir) -{ - int pip[2]; - int len = 0; - - if (pipe(pip) < 0) - error("Pipe call failed"); - if (redir->type == NHERE) { - len = strlen(redir->nhere.doc->narg.text); - if (len <= PIPESIZE) { - xwrite(pip[1], redir->nhere.doc->narg.text, len); - goto out; - } - } - if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { - close(pip[0]); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGHUP, SIG_IGN); -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif - signal(SIGPIPE, SIG_DFL); - if (redir->type == NHERE) - xwrite(pip[1], redir->nhere.doc->narg.text, len); - else - expandhere(redir->nhere.doc, pip[1]); - _exit(0); - } -out: - close(pip[1]); - return pip[0]; -} - - - -/* - * Undo the effects of the last redirection. - */ - -void -popredir(void) -{ - struct redirtab *rp = redirlist; - int i; - - for (i = 0 ; i < 10 ; i++) { - if (rp->renamed[i] != EMPTY) { - if (i == 0) - fd0_redirected--; - close(i); - if (rp->renamed[i] >= 0) { - copyfd(rp->renamed[i], i); - close(rp->renamed[i]); - } - } - } - INTOFF; - redirlist = rp->next; - ckfree(rp); - INTON; -} - -/* - * Undo all redirections. Called on error or interrupt. - */ - -#ifdef mkinit - -INCLUDE "redir.h" - -RESET { - while (redirlist) - popredir(); -} - -SHELLPROC { - clearredir(0); -} - -#endif - -/* Return true if fd 0 has already been redirected at least once. */ -int -fd0_redirected_p () { - return fd0_redirected != 0; -} - -/* - * Discard all saved file descriptors. - */ - -void -clearredir(vforked) - int vforked; -{ - struct redirtab *rp; - int i; - - for (rp = redirlist ; rp ; rp = rp->next) { - for (i = 0 ; i < 10 ; i++) { - if (rp->renamed[i] >= 0) { - close(rp->renamed[i]); - } - if (!vforked) - rp->renamed[i] = EMPTY; - } - } -} - - - -/* - * Copy a file descriptor to be >= to. Returns -1 - * if the source file descriptor is closed, EMPTY if there are no unused - * file descriptors left. - */ - -int -copyfd(int from, int to) -{ - int newfd; - - newfd = fcntl(from, F_DUPFD, to); - if (newfd < 0) { - if (errno == EMFILE) - return EMPTY; - else - error("%d: %s", from, strerror(errno)); - } - return newfd; -} diff --git a/sh/redir.h b/sh/redir.h deleted file mode 100644 index c9709e9..0000000 --- a/sh/redir.h +++ /dev/null @@ -1,48 +0,0 @@ -/* $NetBSD: redir.h,v 1.15 2003/08/07 09:05:37 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)redir.h 8.2 (Berkeley) 5/4/95 - */ - -/* flags passed to redirect */ -#define REDIR_PUSH 01 /* save previous values of file descriptors */ -#define REDIR_BACKQ 02 /* save the command output in memory */ -#define REDIR_VFORK 04 /* running under vfork(2), be careful */ - -union node; -void redirect(union node *, int); -void popredir(void); -int fd0_redirected_p(void); -void clearredir(int); -int copyfd(int, int); - diff --git a/sh/sh.1 b/sh/sh.1 deleted file mode 100644 index 3ef55b4..0000000 --- a/sh/sh.1 +++ /dev/null @@ -1,1928 +0,0 @@ -.\" $NetBSD: sh.1,v 1.78 2004/06/03 19:54:37 hubertf Exp $ -.\" Copyright (c) 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" This code is derived from software contributed to Berkeley by -.\" Kenneth Almquist. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)sh.1 8.6 (Berkeley) 5/4/95 -.\" -.Dd April 17, 2004 -.Os -.Dt SH 1 -.Sh NAME -.Nm sh -.Nd command interpreter (shell) -.Sh SYNOPSIS -.Nm -.Bk -words -.Op Fl aCefnuvxIimqVEb -.Op Cm +aCefnuvxIimqVEb -.Ek -.Bk -words -.Op Fl o Ar option_name -.Op Cm +o Ar option_name -.Ek -.Bk -words -.Op Ar command_file Oo Ar argument ... Oc -.Ek -.Nm -.Fl c -.Bk -words -.Op Fl aCefnuvxIimqVEb -.Op Cm +aCefnuvxIimqVEb -.Ek -.Bk -words -.Op Fl o Ar option_name -.Op Cm +o Ar option_name -.Ek -.Bk -words -.Ar command_string -.Op Ar command_name Oo Ar argument ... Oc -.Ek -.Nm -.Fl s -.Bk -words -.Op Fl aCefnuvxIimqVEb -.Op Cm +aCefnuvxIimqVEb -.Ek -.Bk -words -.Op Fl o Ar option_name -.Op Cm +o Ar option_name -.Ek -.Bk -words -.Op Ar argument ... -.Ek -.Sh DESCRIPTION -.Nm -is the standard command interpreter for the system. -The current version of -.Nm -is in the process of being changed to conform with the -.Tn POSIX -1003.2 and 1003.2a specifications for the shell. -This version has many -features which make it appear similar in some respects to the Korn shell, -but it is not a Korn shell clone (see -.Xr ksh 1 ) . -Only features designated by -.Tn POSIX , -plus a few Berkeley extensions, are being incorporated into this shell. -.\" We expect -.\" .Tn POSIX -.\" conformance by the time 4.4 BSD is released. -This man page is not intended -to be a tutorial or a complete specification of the shell. -.Ss Overview -The shell is a command that reads lines from either a file or the -terminal, interprets them, and generally executes other commands. -It is the program that is running when a user logs into the system -(although a user can select a different shell with the -.Xr chsh 1 -command). -The shell implements a language that has flow control -constructs, a macro facility that provides a variety of features in -addition to data storage, along with built in history and line editing -capabilities. -It incorporates many features to aid interactive use and -has the advantage that the interpretative language is common to both -interactive and non-interactive use (shell scripts). -That is, commands -can be typed directly to the running shell or can be put into a file and -the file can be executed directly by the shell. -.Ss Invocation -If no args are present and if the standard input of the shell -is connected to a terminal (or if the -.Fl i -flag is set), -and the -.Fl c -option is not present, the shell is considered an interactive shell. -An interactive shell generally prompts before each command and handles -programming and command errors differently (as described below). -When first starting, -the shell inspects argument 0, and if it begins with a dash -.Sq - , -the shell is also considered -a login shell. -This is normally done automatically by the system -when the user first logs in. -A login shell first reads commands -from the files -.Pa /etc/profile -and -.Pa .profile -if they exist. -If the environment variable -.Ev ENV -is set on entry to a shell, or is set in the -.Pa .profile -of a login shell, the shell next reads -commands from the file named in -.Ev ENV . -Therefore, a user should place commands that are to be executed only at -login time in the -.Pa .profile -file, and commands that are executed for every shell inside the -.Ev ENV -file. -To set the -.Ev ENV -variable to some file, place the following line in your -.Pa .profile -of your home directory -.Pp -.Dl ENV=$HOME/.shinit; export ENV -.Pp -substituting for -.Dq .shinit -any filename you wish. -Since the -.Ev ENV -file is read for every invocation of the shell, including shell scripts -and non-interactive shells, the following paradigm is useful for -restricting commands in the -.Ev ENV -file to interactive invocations. -Place commands within the -.Dq case -and -.Dq esac -below (these commands are described later): -.Pp -.Bl -item -compact -offset indent -.It -.Li case $- in *i*) -.Bl -item -compact -offset indent -.It -.Li # commands for interactive use only -.It -.Li ... -.El -.It -.Li esac -.El -.Pp -If command line arguments besides the options have been specified, then -the shell treats the first argument as the name of a file from which to -read commands (a shell script), and the remaining arguments are set as the -positional parameters of the shell ($1, $2, etc). -Otherwise, the shell -reads commands from its standard input. -.Ss Argument List Processing -All of the single letter options have a corresponding name that can be -used as an argument to the -.Fl o -option. -The set -.Fl o -name is provided next to the single letter option in -the description below. -Specifying a dash -.Dq - -turns the option on, while using a plus -.Dq + -disables the option. -The following options can be set from the command line or -with the -.Ic set -builtin (described later). -.Bl -tag -width aaaallexportfoo -offset indent -.It Fl a Em allexport -Export all variables assigned to. -.It Fl c -Read commands from the -.Ar command_string -operand instead of from the standard input. -Special parameter 0 will be set from the -.Ar command_name -operand and the positional parameters ($1, $2, etc.) -set from the remaining argument operands. -.It Fl C Em noclobber -Don't overwrite existing files with -.Dq \*[Gt] . -.It Fl e Em errexit -If not interactive, exit immediately if any untested command fails. -The exit status of a command is considered to be -explicitly tested if the command is used to control an -.Ic if , -.Ic elif , -.Ic while , -or -.Ic until ; -or if the command is the left hand operand of an -.Dq \*[Am]\*[Am] -or -.Dq || -operator. -.It Fl f Em noglob -Disable pathname expansion. -.It Fl n Em noexec -If not interactive, read commands but do not execute them. -This is useful for checking the syntax of shell scripts. -.It Fl u Em nounset -Write a message to standard error when attempting to expand a variable -that is not set, and if the shell is not interactive, exit immediately. -.It Fl v Em verbose -The shell writes its input to standard error as it is read. -Useful for debugging. -.It Fl x Em xtrace -Write each command to standard error (preceded by a -.Sq +\ ) -before it is executed. -Useful for debugging. -.It Fl q Em quietprofile -If the -.Fl v -or -.Fl x -options have been set, do not apply them when reading -initialization files, these being -.Pa /etc/profile , -.Pa .profile , -and the file specified by the -.Ev ENV -environment variable. -.It Fl I Em ignoreeof -Ignore EOF's from input when interactive. -.It Fl i Em interactive -Force the shell to behave interactively. -.It Fl m Em monitor -Turn on job control (set automatically when interactive). -.It Fl s Em stdin -Read commands from standard input (set automatically if no file arguments -are present). -This option has no effect when set after the shell has -already started running (i.e. with -.Ic set ) . -.It Fl V Em vi -Enable the built-in -.Xr vi 1 -command line editor (disables -.Fl E -if it has been set). -(See the -.Sx Command Line Editing -section below.) -.It Fl E Em emacs -Enable the built-in emacs style -command line editor (disables -.Fl V -if it has been set). -(See the -.Sx Command Line Editing -section below.) -.It Fl b Em notify -Enable asynchronous notification of background job completion. -(UNIMPLEMENTED for 4.4alpha) -.It "\ \ " Em cdprint -Make an interactive shell always print the new directory name when -changed by the -.Ic cd -command. -.El -.Ss Lexical Structure -The shell reads input in terms of lines from a file and breaks it up into -words at whitespace (blanks and tabs), and at certain sequences of -characters that are special to the shell called -.Dq operators . -There are two types of operators: control operators and redirection -operators (their meaning is discussed later). -Following is a list of operators: -.Bl -ohang -offset indent -.It "Control operators:" -.Dl \*[Am] \*[Am]\*[Am] \&( \&) \&; ;; | || \*[Lt]newline\*[Gt] -.It "Redirection operators:" -.Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]\*[Am] \*[Gt]\*[Am] \*[Lt]\*[Lt]- \*[Lt]\*[Gt] -.El -.Ss Quoting -Quoting is used to remove the special meaning of certain characters or -words to the shell, such as operators, whitespace, or keywords. -There are three types of quoting: matched single quotes, -matched double quotes, and backslash. -.Ss Backslash -A backslash preserves the literal meaning of the following -character, with the exception of -.Aq newline . -A backslash preceding a -.Aq newline -is treated as a line continuation. -.Ss Single Quotes -Enclosing characters in single quotes preserves the literal meaning of all -the characters (except single quotes, making it impossible to put -single-quotes in a single-quoted string). -.Ss Double Quotes -Enclosing characters within double quotes preserves the literal -meaning of all characters except dollarsign -.Pq $ , -backquote -.Pq ` , -and backslash -.Pq \e . -The backslash inside double quotes is historically weird, and serves to -quote only the following characters: -.Dl $ ` \*q \e \*[Lt]newline\*[Gt] . -Otherwise it remains literal. -.Ss Reserved Words -Reserved words are words that have special meaning to the -shell and are recognized at the beginning of a line and -after a control operator. -The following are reserved words: -.Bl -column while while while while while -offset indent -.It ! Ta elif Ta fi Ta while Ta case -.It else Ta for Ta then Ta { Ta } -.It do Ta done Ta until Ta if Ta esac -.El -.Pp -Their meaning is discussed later. -.Ss Aliases -An alias is a name and corresponding value set using the -.Ic alias -builtin command. -Whenever a reserved word may occur (see above), -and after checking for reserved words, the shell -checks the word to see if it matches an alias. -If it does, it replaces it in the input stream with its value. -For example, if there is an alias called -.Dq lf -with the value -.Dq "ls -F" , -then the input: -.Pp -.Dl lf foobar Aq return -.Pp -would become -.Pp -.Dl ls -F foobar Aq return -.Pp -Aliases provide a convenient way for naive users to create shorthands for -commands without having to learn how to create functions with arguments. -They can also be used to create lexically obscure code. -This use is discouraged. -.Ss Commands -The shell interprets the words it reads according to a language, the -specification of which is outside the scope of this man page (refer to the -BNF in the -.Tn POSIX -1003.2 document). -Essentially though, a line is read and if the first -word of the line (or after a control operator) is not a reserved word, -then the shell has recognized a simple command. -Otherwise, a complex -command or some other special construct may have been recognized. -.Ss Simple Commands -If a simple command has been recognized, the shell performs -the following actions: -.Bl -enum -offset indent -.It -Leading words of the form -.Dq name=value -are stripped off and assigned to the environment of the simple command. -Redirection operators and their arguments (as described below) are -stripped off and saved for processing. -.It -The remaining words are expanded as described in -the section called -.Dq Expansions , -and the first remaining word is considered the command name and the -command is located. -The remaining words are considered the arguments of the command. -If no command name resulted, then the -.Dq name=value -variable assignments recognized in item 1 affect the current shell. -.It -Redirections are performed as described in the next section. -.El -.Ss Redirections -Redirections are used to change where a command reads its input or sends -its output. -In general, redirections open, close, or duplicate an -existing reference to a file. -The overall format used for redirection is: -.Pp -.Dl [n] Va redir-op Ar file -.Pp -where -.Va redir-op -is one of the redirection operators mentioned previously. -Following is a list of the possible redirections. -The -.Bq n -is an optional number, as in -.Sq 3 -(not -.Sq Bq 3 ) , -that refers to a file descriptor. -.Bl -tag -width aaabsfiles -offset indent -.It [n] Ns \*[Gt] file -Redirect standard output (or n) to file. -.It [n] Ns \*[Gt]| file -Same, but override the -.Fl C -option. -.It [n] Ns \*[Gt]\*[Gt] file -Append standard output (or n) to file. -.It [n] Ns \*[Lt] file -Redirect standard input (or n) from file. -.It [n1] Ns \*[Lt]\*[Am] Ns n2 -Duplicate standard input (or n1) from file descriptor n2. -.It [n] Ns \*[Lt]\*[Am]- -Close standard input (or n). -.It [n1] Ns \*[Gt]\*[Am] Ns n2 -Duplicate standard output (or n1) to n2. -.It [n] Ns \*[Gt]\*[Am]- -Close standard output (or n). -.It [n] Ns \*[Lt]\*[Gt] file -Open file for reading and writing on standard input (or n). -.El -.Pp -The following redirection is often called a -.Dq here-document . -.Bl -item -offset indent -.It -.Li [n]\*[Lt]\*[Lt] delimiter -.Dl here-doc-text ... -.Li delimiter -.El -.Pp -All the text on successive lines up to the delimiter is saved away and -made available to the command on standard input, or file descriptor n if -it is specified. -If the delimiter as specified on the initial line is -quoted, then the here-doc-text is treated literally, otherwise the text is -subjected to parameter expansion, command substitution, and arithmetic -expansion (as described in the section on -.Dq Expansions ) . -If the operator is -.Dq \*[Lt]\*[Lt]- -instead of -.Dq \*[Lt]\*[Lt] , -then leading tabs in the here-doc-text are stripped. -.Ss Search and Execution -There are three types of commands: shell functions, builtin commands, and -normal programs -- and the command is searched for (by name) in that order. -They each are executed in a different way. -.Pp -When a shell function is executed, all of the shell positional parameters -(except $0, which remains unchanged) are set to the arguments of the shell -function. -The variables which are explicitly placed in the environment of -the command (by placing assignments to them before the function name) are -made local to the function and are set to the values given. -Then the command given in the function definition is executed. -The positional parameters are restored to their original values -when the command completes. -This all occurs within the current shell. -.Pp -Shell builtins are executed internally to the shell, without spawning a -new process. -.Pp -Otherwise, if the command name doesn't match a function or builtin, the -command is searched for as a normal program in the file system (as -described in the next section). -When a normal program is executed, the shell runs the program, -passing the arguments and the environment to the program. -If the program is not a normal executable file (i.e., if it does -not begin with the "magic number" whose -.Tn ASCII -representation is "#!", so -.Xr execve 2 -returns -.Er ENOEXEC -then) the shell will interpret the program in a subshell. -The child shell will reinitialize itself in this case, -so that the effect will be as if a -new shell had been invoked to handle the ad-hoc shell script, except that -the location of hashed commands located in the parent shell will be -remembered by the child. -.Pp -Note that previous versions of this document and the source code itself -misleadingly and sporadically refer to a shell script without a magic -number as a "shell procedure". -.Ss Path Search -When locating a command, the shell first looks to see if it has a shell -function by that name. -Then it looks for a builtin command by that name. -If a builtin command is not found, one of two things happen: -.Bl -enum -.It -Command names containing a slash are simply executed without performing -any searches. -.It -The shell searches each entry in -.Ev PATH -in turn for the command. -The value of the -.Ev PATH -variable should be a series of entries separated by colons. -Each entry consists of a directory name. -The current directory may be indicated -implicitly by an empty directory name, or explicitly by a single period. -.El -.Ss Command Exit Status -Each command has an exit status that can influence the behavior -of other shell commands. -The paradigm is that a command exits -with zero for normal or success, and non-zero for failure, -error, or a false indication. -The man page for each command -should indicate the various exit codes and what they mean. -Additionally, the builtin commands return exit codes, as does -an executed shell function. -.Pp -If a command consists entirely of variable assignments then the -exit status of the command is that of the last command substitution -if any, otherwise 0. -.Ss Complex Commands -Complex commands are combinations of simple commands with control -operators or reserved words, together creating a larger complex command. -More generally, a command is one of the following: -.Bl -bullet -.It -simple command -.It -pipeline -.It -list or compound-list -.It -compound command -.It -function definition -.El -.Pp -Unless otherwise stated, the exit status of a command is that of the last -simple command executed by the command. -.Ss Pipelines -A pipeline is a sequence of one or more commands separated -by the control operator |. -The standard output of all but -the last command is connected to the standard input -of the next command. -The standard output of the last -command is inherited from the shell, as usual. -.Pp -The format for a pipeline is: -.Pp -.Dl [!] command1 [ | command2 ...] -.Pp -The standard output of command1 is connected to the standard input of -command2. -The standard input, standard output, or both of a command is -considered to be assigned by the pipeline before any redirection specified -by redirection operators that are part of the command. -.Pp -If the pipeline is not in the background (discussed later), the shell -waits for all commands to complete. -.Pp -If the reserved word ! does not precede the pipeline, the exit status is -the exit status of the last command specified in the pipeline. -Otherwise, the exit status is the logical NOT of the exit status of the -last command. -That is, if the last command returns zero, the exit status -is 1; if the last command returns greater than zero, the exit status is -zero. -.Pp -Because pipeline assignment of standard input or standard output or both -takes place before redirection, it can be modified by redirection. -For example: -.Pp -.Dl $ command1 2\*[Gt]\*[Am]1 | command2 -.Pp -sends both the standard output and standard error of command1 -to the standard input of command2. -.Pp -A ; or -.Aq newline -terminator causes the preceding AND-OR-list (described -next) to be executed sequentially; a \*[Am] causes asynchronous execution of -the preceding AND-OR-list. -.Pp -Note that unlike some other shells, each process in the pipeline is a -child of the invoking shell (unless it is a shell builtin, in which case -it executes in the current shell -- but any effect it has on the -environment is wiped). -.Ss Background Commands -- \*[Am] -If a command is terminated by the control operator ampersand (\*[Am]), the -shell executes the command asynchronously -- that is, the shell does not -wait for the command to finish before executing the next command. -.Pp -The format for running a command in background is: -.Pp -.Dl command1 \*[Am] [command2 \*[Am] ...] -.Pp -If the shell is not interactive, the standard input of an asynchronous -command is set to -.Pa /dev/null . -.Ss Lists -- Generally Speaking -A list is a sequence of zero or more commands separated by newlines, -semicolons, or ampersands, and optionally terminated by one of these three -characters. -The commands in a list are executed in the order they are written. -If command is followed by an ampersand, the shell starts the -command and immediately proceed onto the next command; otherwise it waits -for the command to terminate before proceeding to the next one. -.Ss Short-Circuit List Operators -.Dq \*[Am]\*[Am] -and -.Dq || -are AND-OR list operators. -.Dq \*[Am]\*[Am] -executes the first command, and then executes the second command if and only -if the exit status of the first command is zero. -.Dq || -is similar, but executes the second command if and only if the exit status -of the first command is nonzero. -.Dq \*[Am]\*[Am] -and -.Dq || -both have the same priority. -Note that these operators are left-associative, so -.Dq true || echo bar && echo baz -writes -.Dq baz -and nothing else. -This is not the way it works in C. -.Ss Flow-Control Constructs -- if, while, for, case -The syntax of the if command is -.Bd -literal -offset indent -if list -then list -[ elif list -then list ] ... -[ else list ] -fi -.Ed -.Pp -The syntax of the while command is -.Bd -literal -offset indent -while list -do list -done -.Ed -.Pp -The two lists are executed repeatedly while the exit status of the -first list is zero. -The until command is similar, but has the word -until in place of while, which causes it to -repeat until the exit status of the first list is zero. -.Pp -The syntax of the for command is -.Bd -literal -offset indent -for variable in word ... -do list -done -.Ed -.Pp -The words are expanded, and then the list is executed repeatedly with the -variable set to each word in turn. -do and done may be replaced with -.Dq { -and -.Dq } . -.Pp -The syntax of the break and continue command is -.Bd -literal -offset indent -break [ num ] -continue [ num ] -.Ed -.Pp -Break terminates the num innermost for or while loops. -Continue continues with the next iteration of the innermost loop. -These are implemented as builtin commands. -.Pp -The syntax of the case command is -.Bd -literal -offset indent -case word in -pattern) list ;; -\&... -esac -.Ed -.Pp -The pattern can actually be one or more patterns (see -.Sx Shell Patterns -described later), separated by -.Dq \*(Ba -characters. -.Ss Grouping Commands Together -Commands may be grouped by writing either -.Pp -.Dl (list) -.Pp -or -.Pp -.Dl { list; } -.Pp -The first of these executes the commands in a subshell. -Builtin commands grouped into a (list) will not affect the current shell. -The second form does not fork another shell so is slightly more efficient. -Grouping commands together this way allows you to redirect -their output as though they were one program: -.Pp -.Bd -literal -offset indent -{ echo -n \*q hello \*q ; echo \*q world" ; } \*[Gt] greeting -.Ed -.Pp -Note that -.Dq } -must follow a control operator (here, -.Dq \&; ) -so that it is recognized as a reserved word and not as another command argument. -.Ss Functions -The syntax of a function definition is -.Pp -.Dl name ( ) command -.Pp -A function definition is an executable statement; when executed it -installs a function named name and returns an exit status of zero. -The command is normally a list enclosed between -.Dq { -and -.Dq } . -.Pp -Variables may be declared to be local to a function by using a local -command. -This should appear as the first statement of a function, and the syntax is -.Pp -.Dl local [ variable | - ] ... -.Pp -Local is implemented as a builtin command. -.Pp -When a variable is made local, it inherits the initial value and exported -and readonly flags from the variable with the same name in the surrounding -scope, if there is one. -Otherwise, the variable is initially unset. -The shell uses dynamic scoping, so that if you make the variable x local to -function f, which then calls function g, references to the variable x made -inside g will refer to the variable x declared inside f, not to the global -variable named x. -.Pp -The only special parameter that can be made local is -.Dq - . -Making -.Dq - -local any shell options that are changed via the set command inside the -function to be restored to their original values when the function -returns. -.Pp -The syntax of the return command is -.Pp -.Dl return [ exitstatus ] -.Pp -It terminates the currently executing function. -Return is implemented as a builtin command. -.Ss Variables and Parameters -The shell maintains a set of parameters. -A parameter denoted by a name is called a variable. -When starting up, the shell turns all the environment -variables into shell variables. -New variables can be set using the form -.Pp -.Dl name=value -.Pp -Variables set by the user must have a name consisting solely of -alphabetics, numerics, and underscores - the first of which must not be -numeric. -A parameter can also be denoted by a number or a special -character as explained below. -.Ss Positional Parameters -A positional parameter is a parameter denoted by a number (n \*[Gt] 0). -The shell sets these initially to the values of its command line arguments -that follow the name of the shell script. -The -.Ic set -builtin can also be used to set or reset them. -.Ss Special Parameters -A special parameter is a parameter denoted by one of the following special -characters. -The value of the parameter is listed next to its character. -.Bl -tag -width thinhyphena -.It * -Expands to the positional parameters, starting from one. -When the -expansion occurs within a double-quoted string it expands to a single -field with the value of each parameter separated by the first character of -the -.Ev IFS -variable, or by a -.Aq space -if -.Ev IFS -is unset. -.It @ -Expands to the positional parameters, starting from one. -When the expansion occurs within double-quotes, each positional -parameter expands as a separate argument. -If there are no positional parameters, the -expansion of @ generates zero arguments, even when @ is -double-quoted. -What this basically means, for example, is -if $1 is -.Dq abc -and $2 is -.Dq def ghi , -then -.Qq $@ -expands to -the two arguments: -.Pp -.Sm off -.Dl \*q abc \*q \ \*q def\ ghi \*q -.Sm on -.It # -Expands to the number of positional parameters. -.It \&? -Expands to the exit status of the most recent pipeline. -.It - (Hyphen.) -Expands to the current option flags (the single-letter -option names concatenated into a string) as specified on -invocation, by the set builtin command, or implicitly -by the shell. -.It $ -Expands to the process ID of the invoked shell. -A subshell retains the same value of $ as its parent. -.It \&! -Expands to the process ID of the most recent background -command executed from the current shell. -For a pipeline, the process ID is that of the last command in the pipeline. -.It 0 (Zero.) -Expands to the name of the shell or shell script. -.El -.Ss Word Expansions -This clause describes the various expansions that are performed on words. -Not all expansions are performed on every word, as explained later. -.Pp -Tilde expansions, parameter expansions, command substitutions, arithmetic -expansions, and quote removals that occur within a single word expand to a -single field. -It is only field splitting or pathname expansion that can -create multiple fields from a single word. -The single exception to this -rule is the expansion of the special parameter @ within double-quotes, as -was described above. -.Pp -The order of word expansion is: -.Bl -enum -.It -Tilde Expansion, Parameter Expansion, Command Substitution, -Arithmetic Expansion (these all occur at the same time). -.It -Field Splitting is performed on fields -generated by step (1) unless the -.Ev IFS -variable is null. -.It -Pathname Expansion (unless set -.Fl f -is in effect). -.It -Quote Removal. -.El -.Pp -The $ character is used to introduce parameter expansion, command -substitution, or arithmetic evaluation. -.Ss Tilde Expansion (substituting a user's home directory) -A word beginning with an unquoted tilde character (~) is -subjected to tilde expansion. -All the characters up to -a slash (/) or the end of the word are treated as a username -and are replaced with the user's home directory. -If the username is missing (as in -.Pa ~/foobar ) , -the tilde is replaced with the value of the -.Va HOME -variable (the current user's home directory). -.Ss Parameter Expansion -The format for parameter expansion is as follows: -.Pp -.Dl ${expression} -.Pp -where expression consists of all characters until the matching -.Dq } . -Any -.Dq } -escaped by a backslash or within a quoted string, and characters in -embedded arithmetic expansions, command substitutions, and variable -expansions, are not examined in determining the matching -.Dq } . -.Pp -The simplest form for parameter expansion is: -.Pp -.Dl ${parameter} -.Pp -The value, if any, of parameter is substituted. -.Pp -The parameter name or symbol can be enclosed in braces, which are -optional except for positional parameters with more than one digit or -when parameter is followed by a character that could be interpreted as -part of the name. -If a parameter expansion occurs inside double-quotes: -.Bl -enum -.It -Pathname expansion is not performed on the results of the expansion. -.It -Field splitting is not performed on the results of the -expansion, with the exception of @. -.El -.Pp -In addition, a parameter expansion can be modified by using one of the -following formats. -.Bl -tag -width aaparameterwordaaaaa -.It ${parameter:-word} -Use Default Values. -If parameter is unset or null, the expansion of word -is substituted; otherwise, the value of parameter is substituted. -.It ${parameter:=word} -Assign Default Values. -If parameter is unset or null, the expansion of -word is assigned to parameter. -In all cases, the final value of parameter is substituted. -Only variables, not positional parameters or special -parameters, can be assigned in this way. -.It ${parameter:?[word]} -Indicate Error if Null or Unset. -If parameter is unset or null, the -expansion of word (or a message indicating it is unset if word is omitted) -is written to standard error and the shell exits with a nonzero exit status. -Otherwise, the value of parameter is substituted. -An interactive shell need not exit. -.It ${parameter:+word} -Use Alternative Value. -If parameter is unset or null, null is -substituted; otherwise, the expansion of word is substituted. -.El -.Pp -In the parameter expansions shown previously, use of the colon in the -format results in a test for a parameter that is unset or null; omission -of the colon results in a test for a parameter that is only unset. -.Bl -tag -width aaparameterwordaaaaa -.It ${#parameter} -String Length. -The length in characters of the value of parameter. -.El -.Pp -The following four varieties of parameter expansion provide for substring -processing. -In each case, pattern matching notation (see -.Sx Shell Patterns ) , -rather than regular expression notation, is used to evaluate the patterns. -If parameter is * or @, the result of the expansion is unspecified. -Enclosing the full parameter expansion string in double-quotes does not -cause the following four varieties of pattern characters to be quoted, -whereas quoting characters within the braces has this effect. -.Bl -tag -width aaparameterwordaaaaa -.It ${parameter%word} -Remove Smallest Suffix Pattern. -The word is expanded to produce a pattern. -The parameter expansion then results in parameter, with the -smallest portion of the suffix matched by the pattern deleted. -.It ${parameter%%word} -Remove Largest Suffix Pattern. -The word is expanded to produce a pattern. -The parameter expansion then results in parameter, with the largest -portion of the suffix matched by the pattern deleted. -.It ${parameter#word} -Remove Smallest Prefix Pattern. -The word is expanded to produce a pattern. -The parameter expansion then results in parameter, with the -smallest portion of the prefix matched by the pattern deleted. -.It ${parameter##word} -Remove Largest Prefix Pattern. -The word is expanded to produce a pattern. -The parameter expansion then results in parameter, with the largest -portion of the prefix matched by the pattern deleted. -.El -.Ss Command Substitution -Command substitution allows the output of a command to be substituted in -place of the command name itself. -Command substitution occurs when the command is enclosed as follows: -.Pp -.Dl $(command) -.Pp -or -.Po -.Dq backquoted -version -.Pc : -.Pp -.Dl `command` -.Pp -The shell expands the command substitution by executing command in a -subshell environment and replacing the command substitution with the -standard output of the command, removing sequences of one or more -.Ao newline Ac Ns s -at the end of the substitution. -(Embedded -.Ao newline Ac Ns s -before -the end of the output are not removed; however, during field splitting, -they may be translated into -.Ao space Ac Ns s , -depending on the value of -.Ev IFS -and quoting that is in effect.) -.Ss Arithmetic Expansion -Arithmetic expansion provides a mechanism for evaluating an arithmetic -expression and substituting its value. -The format for arithmetic expansion is as follows: -.Pp -.Dl $((expression)) -.Pp -The expression is treated as if it were in double-quotes, except -that a double-quote inside the expression is not treated specially. -The shell expands all tokens in the expression for parameter expansion, -command substitution, and quote removal. -.Pp -Next, the shell treats this as an arithmetic expression and -substitutes the value of the expression. -.Ss White Space Splitting (Field Splitting) -After parameter expansion, command substitution, and -arithmetic expansion the shell scans the results of -expansions and substitutions that did not occur in double-quotes for -field splitting and multiple fields can result. -.Pp -The shell treats each character of the -.Ev IFS -as a delimiter and use the delimiters to split the results of parameter -expansion and command substitution into fields. -.Ss Pathname Expansion (File Name Generation) -Unless the -.Fl f -flag is set, file name generation is performed after word splitting is -complete. -Each word is viewed as a series of patterns, separated by slashes. -The process of expansion replaces the word with the names of all -existing files whose names can be formed by replacing each pattern with a -string that matches the specified pattern. -There are two restrictions on -this: first, a pattern cannot match a string containing a slash, and -second, a pattern cannot match a string starting with a period unless the -first character of the pattern is a period. -The next section describes the -patterns used for both Pathname Expansion and the -.Ic case -command. -.Ss Shell Patterns -A pattern consists of normal characters, which match themselves, -and meta-characters. -The meta-characters are -.Dq \&! , -.Dq * , -.Dq \&? , -and -.Dq \&[ . -These characters lose their special meanings if they are quoted. -When command or variable substitution is performed -and the dollar sign or back quotes are not double quoted, -the value of the variable or the output of -the command is scanned for these characters and they are turned into -meta-characters. -.Pp -An asterisk -.Pq Dq * -matches any string of characters. -A question mark matches any single character. -A left bracket -.Pq Dq \&[ -introduces a character class. -The end of the character class is indicated by a -.Pq Dq \&] ; -if the -.Dq \&] -is missing then the -.Dq \&[ -matches a -.Dq \&[ -rather than introducing a character class. -A character class matches any of the characters between the square brackets. -A range of characters may be specified using a minus sign. -The character class may be complemented -by making an exclamation point the first character of the character class. -.Pp -To include a -.Dq \&] -in a character class, make it the first character listed (after the -.Dq \&! , -if any). -To include a minus sign, make it the first or last character listed. -.Ss Builtins -This section lists the builtin commands which are builtin because they -need to perform some operation that can't be performed by a separate -process. -In addition to these, there are several other commands that may -be builtin for efficiency (e.g. -.Xr printf 1 , -.Xr echo 1 , -.Xr test 1 , -etc). -.Bl -tag -width 5n -.It : -A null command that returns a 0 (true) exit value. -.It \&. file -The commands in the specified file are read and executed by the shell. -.It alias Op Ar name Ns Op Ar "=string ..." -If -.Ar name=string -is specified, the shell defines the alias -.Ar name -with value -.Ar string . -If just -.Ar name -is specified, the value of the alias -.Ar name -is printed. -With no arguments, the -.Ic alias -builtin prints the -names and values of all defined aliases (see -.Ic unalias ) . -.It bg [ Ar job ] ... -Continue the specified jobs (or the current job if no -jobs are given) in the background. -.It Xo command -.Op Fl p -.Op Fl v -.Op Fl V -.Ar command -.Op Ar arg ... -.Xc -Execute the specified command but ignore shell functions when searching -for it. -(This is useful when you -have a shell function with the same name as a builtin command.) -.Bl -tag -width 5n -.It Fl p -search for command using a -.Ev PATH -that guarantees to find all the standard utilities. -.It Fl V -Do not execute the command but -search for the command and print the resolution of the -command search. -This is the same as the type builtin. -.It Fl v -Do not execute the command but -search for the command and print the absolute pathname -of utilities, the name for builtins or the expansion of aliases. -.El -.It cd Op Ar directory Op Ar replace -Switch to the specified directory (default -.Ev $HOME ) . -If -.Ar replace -is specified, then the new directory name is generated by replacing -the first occurrence of -.Ar directory -in the current directory name with -.Ar replace . -Otherwise if an entry for -.Ev CDPATH -appears in the environment of the -.Ic cd -command or the shell variable -.Ev CDPATH -is set and the directory name does not begin with a slash, then the -directories listed in -.Ev CDPATH -will be searched for the specified directory. -The format of -.Ev CDPATH -is the same as that of -.Ev PATH . -In an interactive shell, the -.Ic cd -command will print out the name of the -directory that it actually switched to if this is different from the name -that the user gave. -These may be different either because the -.Ev CDPATH -mechanism was used or because a symbolic link was crossed. -.It eval Ar string ... -Concatenate all the arguments with spaces. -Then re-parse and execute the command. -.It exec Op Ar command arg ... -Unless command is omitted, the shell process is replaced with the -specified program (which must be a real program, not a shell builtin or -function). -Any redirections on the -.Ic exec -command are marked as permanent, so that they are not undone when the -.Ic exec -command finishes. -.It exit Op Ar exitstatus -Terminate the shell process. -If -.Ar exitstatus -is given it is used as the exit status of the shell; otherwise the -exit status of the preceding command is used. -.It export Ar name ... -.It export Fl p -The specified names are exported so that they will appear in the -environment of subsequent commands. -The only way to un-export a variable is to unset it. -The shell allows the value of a variable to be set at the -same time it is exported by writing -.Pp -.Dl export name=value -.Pp -With no arguments the export command lists the names of all exported variables. -With the -.Fl p -option specified the output will be formatted suitably for non-interactive use. -.It Xo fc Op Fl e Ar editor -.Op Ar first Op Ar last -.Xc -.It Xo fc Fl l -.Op Fl nr -.Op Ar first Op Ar last -.Xc -.It Xo fc Fl s Op Ar old=new -.Op Ar first -.Xc -The -.Ic fc -builtin lists, or edits and re-executes, commands previously entered -to an interactive shell. -.Bl -tag -width 5n -.It Fl e No editor -Use the editor named by editor to edit the commands. -The editor string is a command name, subject to search via the -.Ev PATH -variable. -The value in the -.Ev FCEDIT -variable is used as a default when -.Fl e -is not specified. -If -.Ev FCEDIT -is null or unset, the value of the -.Ev EDITOR -variable is used. -If -.Ev EDITOR -is null or unset, -.Xr ed 1 -is used as the editor. -.It Fl l No (ell) -List the commands rather than invoking an editor on them. -The commands are written in the sequence indicated by -the first and last operands, as affected by -.Fl r , -with each command preceded by the command number. -.It Fl n -Suppress command numbers when listing with -l. -.It Fl r -Reverse the order of the commands listed (with -.Fl l ) -or edited (with neither -.Fl l -nor -.Fl s ) . -.It Fl s -Re-execute the command without invoking an editor. -.It first -.It last -Select the commands to list or edit. -The number of previous commands that -can be accessed are determined by the value of the -.Ev HISTSIZE -variable. -The value of first or last or both are one of the following: -.Bl -tag -width 5n -.It [+]number -A positive number representing a command number; command numbers can be -displayed with the -.Fl l -option. -.It Fl number -A negative decimal number representing the command that was executed -number of commands previously. -For example, \-1 is the immediately previous command. -.El -.It string -A string indicating the most recently entered command that begins with -that string. -If the old=new operand is not also specified with -.Fl s , -the string form of the first operand cannot contain an embedded equal sign. -.El -.Pp -The following environment variables affect the execution of fc: -.Bl -tag -width HISTSIZE -.It Ev FCEDIT -Name of the editor to use. -.It Ev HISTSIZE -The number of previous commands that are accessible. -.El -.It fg Op Ar job -Move the specified job or the current job to the foreground. -.It getopts Ar optstring var -The -.Tn POSIX -.Ic getopts -command, not to be confused with the -.Em Bell Labs --derived -.Xr getopt 1 . -.Pp -The first argument should be a series of letters, each of which may be -optionally followed by a colon to indicate that the option requires an -argument. -The variable specified is set to the parsed option. -.Pp -The -.Ic getopts -command deprecates the older -.Xr getopt 1 -utility due to its handling of arguments containing whitespace. -.Pp -The -.Ic getopts -builtin may be used to obtain options and their arguments -from a list of parameters. -When invoked, -.Ic getopts -places the value of the next option from the option string in the list in -the shell variable specified by -.Va var -and its index in the shell variable -.Ev OPTIND . -When the shell is invoked, -.Ev OPTIND -is initialized to 1. -For each option that requires an argument, the -.Ic getopts -builtin will place it in the shell variable -.Ev OPTARG . -If an option is not allowed for in the -.Va optstring , -then -.Ev OPTARG -will be unset. -.Pp -.Va optstring -is a string of recognized option letters (see -.Xr getopt 3 ) . -If a letter is followed by a colon, the option is expected to have an -argument which may or may not be separated from it by white space. -If an option character is not found where expected, -.Ic getopts -will set the variable -.Va var -to a -.Dq \&? ; -.Ic getopts -will then unset -.Ev OPTARG -and write output to standard error. -By specifying a colon as the first character of -.Va optstring -all errors will be ignored. -.Pp -A nonzero value is returned when the last option is reached. -If there are no remaining arguments, -.Ic getopts -will set -.Va var -to the special option, -.Dq -- , -otherwise, it will set -.Va var -to -.Dq \&? . -.Pp -The following code fragment shows how one might process the arguments -for a command that can take the options -.Op a -and -.Op b , -and the option -.Op c , -which requires an argument. -.Pp -.Bd -literal -offset indent -while getopts abc: f -do - case $f in - a | b) flag=$f;; - c) carg=$OPTARG;; - \\?) echo $USAGE; exit 1;; - esac -done -shift `expr $OPTIND - 1` -.Ed -.Pp -This code will accept any of the following as equivalent: -.Pp -.Bd -literal -offset indent -cmd \-acarg file file -cmd \-a \-c arg file file -cmd \-carg -a file file -cmd \-a \-carg \-\- file file -.Ed -.It hash Fl rv Ar command ... -The shell maintains a hash table which remembers the -locations of commands. -With no arguments whatsoever, -the -.Ic hash -command prints out the contents of this table. -Entries which have not been looked at since the last -.Ic cd -command are marked with an asterisk; it is possible for these entries -to be invalid. -.Pp -With arguments, the -.Ic hash -command removes the specified commands from the hash table (unless -they are functions) and then locates them. -With the -.Fl v -option, hash prints the locations of the commands as it finds them. -The -.Fl r -option causes the hash command to delete all the entries in the hash table -except for functions. -.It inputrc Ar file -Read the -.Va file -to set keybindings as defined by -.Xr editrc 5 . -.It jobid Op Ar job -Print the process id's of the processes in the job. -If the -.Ar job -argument is omitted, the current job is used. -.It jobs -This command lists out all the background processes -which are children of the current shell process. -.It pwd Op Fl LP -Print the current directory. -If -.Fl L -is specified the cached value (initially set from -.Ev PWD ) -is checked to see if it refers to the current directory, if it does -the value is printed. -Otherwise the current directory name is found using -.Xr getcwd(3) . -The environment variable -.Ev PWD -is set to printed value. -.Pp -The default is -.Ic pwd -.Fl L , -but note that the builtin -.Ic cd -command doesn't currently support -.Fl L -or -.Fl P -and will cache (almost) the absolute path. -If -.Ic cd -is changed, -.Ic pwd -may be changed to default to -.Ic pwd -.Fl P . -.Pp -If the current directory is renamed and replaced by a symlink to the -same directory, or the initial -.Ev PWD -value followed a symbolic link, then the cached value may not -be the absolute path. -.Pp -The builtin command may differ from the program of the same name because -the program will use -.Ev PWD -and the builtin uses a separately cached value. -.It Xo read Op Fl p Ar prompt -.Op Fl r -.Ar variable -.Op Ar ... -.Xc -The prompt is printed if the -.Fl p -option is specified and the standard input is a terminal. -Then a line is read from the standard input. -The trailing newline is deleted from the -line and the line is split as described in the section on word splitting -above, and the pieces are assigned to the variables in order. -If there are more pieces than variables, the remaining pieces -(along with the characters in -.Ev IFS -that separated them) are assigned to the last variable. -If there are more variables than pieces, -the remaining variables are assigned the null string. -The -.Ic read -builtin will indicate success unless EOF is encountered on input, in -which case failure is returned. -.Pp -By default, unless the -.Fl r -option is specified, the backslash -.Dq \e -acts as an escape character, causing the following character to be treated -literally. -If a backslash is followed by a newline, the backslash and the -newline will be deleted. -.It readonly Ar name ... -.It readonly Fl p -The specified names are marked as read only, so that they cannot be -subsequently modified or unset. -The shell allows the value of a variable -to be set at the same time it is marked read only by writing -.Pp -.Dl readonly name=value -.Pp -With no arguments the readonly command lists the names of all read only -variables. -With the -.Fl p -option specified the output will be formatted suitably for non-interactive use. -.Pp -.It Xo set -.Oo { -.Fl options | Cm +options | Cm -- } -.Oc Ar arg ... -.Xc -The -.Ic set -command performs three different functions. -.Pp -With no arguments, it lists the values of all shell variables. -.Pp -If options are given, it sets the specified option -flags, or clears them as described in the section called -.Sx Argument List Processing . -.Pp -The third use of the set command is to set the values of the shell's -positional parameters to the specified args. -To change the positional -parameters without changing any options, use -.Dq -- -as the first argument to set. -If no args are present, the set command -will clear all the positional parameters (equivalent to executing -.Dq shift $# . ) -.It setvar Ar variable Ar value -Assigns value to variable. -(In general it is better to write -variable=value rather than using -.Ic setvar . -.Ic setvar -is intended to be used in -functions that assign values to variables whose names are passed as -parameters.) -.It shift Op Ar n -Shift the positional parameters n times. -A -.Ic shift -sets the value of -.Va $1 -to the value of -.Va $2 , -the value of -.Va $2 -to the value of -.Va $3 , -and so on, decreasing -the value of -.Va $# -by one. -If there are zero positional parameters, -.Ic shift -does nothing. -.It Xo trap -.Op Fl l -.Xc -.It Xo trap -.Op Ar action -.Ar signal ... -.Xc -Cause the shell to parse and execute action when any of the specified -signals are received. -The signals are specified by signal number or as the name of the signal. -If -.Ar signal -is -.Li 0 , -the action is executed when the shell exits. -.Ar action -may be null, which cause the specified signals to be ignored. -With -.Ar action -omitted or set to `-' the specified signals are set to their default action. -When the shell forks off a subshell, it resets trapped (but not ignored) -signals to the default action. -The -.Ic trap -command has no effect on signals that were -ignored on entry to the shell. -Issuing -.Ic trap -with option -.Ar -l -will print a list of valid signal names. -.Ic trap -without any arguments cause it to write a list of signals and their -associated action to the standard output in a format that is suitable -as an input to the shell that achieves the same trapping results. -.Pp -Examples: -.Pp -.Dl trap -.Pp -List trapped signals and their corresponding action -.Pp -.Dl trap -l -.Pp -Print a list of valid signals -.Pp -.Dl trap '' INT QUIT tstp 30 -.Pp -Ignore signals INT QUIT TSTP USR1 -.Pp -.Dl trap date INT -.Pp -Print date upon receiving signal INT -.It type Op Ar name ... -Interpret each name as a command and print the resolution of the command -search. -Possible resolutions are: -shell keyword, alias, shell builtin, -command, tracked alias and not found. -For aliases the alias expansion is -printed; for commands and tracked aliases the complete pathname of the -command is printed. -.It ulimit Xo -.Op Fl H \*(Ba Fl S -.Op Fl a \*(Ba Fl tfdscmlpn Op Ar value -.Xc -Inquire about or set the hard or soft limits on processes or set new -limits. -The choice between hard limit (which no process is allowed to -violate, and which may not be raised once it has been lowered) and soft -limit (which causes processes to be signaled but not necessarily killed, -and which may be raised) is made with these flags: -.Bl -tag -width Fl -.It Fl H -set or inquire about hard limits -.It Fl S -set or inquire about soft limits. -If neither -.Fl H -nor -.Fl S -is specified, the soft limit is displayed or both limits are set. -If both are specified, the last one wins. -.El -.Pp -.Bl -tag -width Fl -The limit to be interrogated or set, then, is chosen by specifying -any one of these flags: -.It Fl a -show all the current limits -.It Fl b -show or set the limit on the socket buffer size of a process (in bytes) -.It Fl t -show or set the limit on CPU time (in seconds) -.It Fl f -show or set the limit on the largest file that can be created -(in 512-byte blocks) -.It Fl d -show or set the limit on the data segment size of a process (in kilobytes) -.It Fl s -show or set the limit on the stack size of a process (in kilobytes) -.It Fl c -show or set the limit on the largest core dump size that can be produced -(in 512-byte blocks) -.It Fl m -show or set the limit on the total physical memory that can be -in use by a process (in kilobytes) -.It Fl l -show or set the limit on how much memory a process can lock with -.Xr mlock 2 -(in kilobytes) -.It Fl p -show or set the limit on the number of processes this user can -have at one time -.It Fl n -show or set the limit on the number of files a process can have open at once -.El -.Pp -If none of these is specified, it is the limit on file size that is shown -or set. -If value is specified, the limit is set to that number; otherwise -the current limit is displayed. -.Pp -Limits of an arbitrary process can be displayed or set using the -.Xr sysctl 8 -utility. -.Pp -.It umask Op Ar mask -Set the value of umask (see -.Xr umask 2 ) -to the specified octal value. -If the argument is omitted, the umask value is printed. -.It unalias Xo -.Op Fl a -.Op Ar name -.Xc -If -.Ar name -is specified, the shell removes that alias. -If -.Fl a -is specified, all aliases are removed. -.It unset Ar name ... -The specified variables and functions are unset and unexported. -If a given name corresponds to both a variable and a function, both -the variable and the function are unset. -.It wait Op Ar job -Wait for the specified job to complete and return the exit status of the -last process in the job. -If the argument is omitted, wait for all jobs to -complete and then return an exit status of zero. -.El -.Ss Command Line Editing -When -.Nm -is being used interactively from a terminal, the current command -and the command history (see -.Ic fc -in -.Sx Builtins ) -can be edited using emacs-mode or vi-mode command-line editing. -The command -.Ql set -o emacs -enables emacs-mode editing. -The command -.Ql set -o vi -enables vi-mode editing and places sh into vi insert mode. -(See the -.Sx Argument List Processing -section above.) -.Pp -The vi mode uses commands similar to a subset of those described in the -.Xr vi 1 -man page. -With vi-mode -enabled, sh can be switched between insert mode and command mode. -It's similar to vi: typing -.Aq ESC -will throw you into command VI command mode. -Hitting -.Aq return -while in command mode will pass the line to the shell. -.Pp -The emacs mode uses commands similar to a subset available in -the emacs editor. -With emacs-mode enabled, special keys can be used to modify the text -in the buffer using the control key. -.Pp -.Nm -uses the -.Xr editline 3 -library. -.Sh EXIT STATUS -Errors that are detected by the shell, such as a syntax error, will cause the -shell to exit with a non-zero exit status. -If the shell is not an -interactive shell, the execution of the shell file will be aborted. -Otherwise -the shell will return the exit status of the last command executed, or -if the exit builtin is used with a numeric argument, it will return the -argument. -.Sh ENVIRONMENT -.Bl -tag -width MAILCHECK -.It Ev HOME -Set automatically by -.Xr login 1 -from the user's login directory in the password file -.Pq Xr passwd 5 . -This environment variable also functions as the default argument for the -cd builtin. -.It Ev PATH -The default search path for executables. -See the above section -.Sx Path Search . -.It Ev CDPATH -The search path used with the cd builtin. -.It Ev LANG -The string used to specify localization information that allows users -to work with different culture-specific and language conventions. -See -.Xr nls 7 . -.It Ev MAIL -The name of a mail file, that will be checked for the arrival of new mail. -Overridden by -.Ev MAILPATH . -.It Ev MAILCHECK -The frequency in seconds that the shell checks for the arrival of mail -in the files specified by the -.Ev MAILPATH -or the -.Ev MAIL -file. -If set to 0, the check will occur at each prompt. -.It Ev MAILPATH -A colon -.Dq \&: -separated list of file names, for the shell to check for incoming mail. -This environment setting overrides the -.Ev MAIL -setting. -There is a maximum of 10 mailboxes that can be monitored at once. -.It Ev PS1 -The primary prompt string, which defaults to -.Dq $ \ , -unless you are the superuser, in which case it defaults to -.Dq # \ . -.It Ev PS2 -The secondary prompt string, which defaults to -.Dq \*[Gt] \ . -.It Ev PS4 -Output before each line when execution trace (set -x) is enabled, -defaults to -.Dq + \ . -.It Ev IFS -Input Field Separators. -This is normally set to -.Aq space , -.Aq tab , -and -.Aq newline . -See the -.Sx White Space Splitting -section for more details. -.It Ev TERM -The default terminal setting for the shell. -This is inherited by -children of the shell, and is used in the history editing modes. -.It Ev HISTSIZE -The number of lines in the history buffer for the shell. -.El -.Sh FILES -.Bl -item -width HOMEprofilexxxx -.It -.Pa $HOME/.profile -.It -.Pa /etc/profile -.El -.Sh SEE ALSO -.Xr csh 1 , -.Xr echo 1 , -.Xr getopt 1 , -.Xr ksh 1 , -.Xr login 1 , -.Xr printf 1 , -.Xr test 1 , -.Xr editline 3 , -.Xr getopt 3 , -.\" .Xr profile 4 , -.Xr editrc 5 , -.Xr passwd 5 , -.Xr environ 7 , -.Xr nls 7 , -.Xr sysctl 8 -.Sh HISTORY -A -.Nm -command appeared in -.At v1 . -It was, however, unmaintainable so we wrote this one. -.Sh BUGS -Setuid shell scripts should be avoided at all costs, as they are a -significant security risk. -.Pp -PS1, PS2, and PS4 should be subject to parameter expansion before -being displayed. diff --git a/sh/shell.h b/sh/shell.h deleted file mode 100644 index 94be27a..0000000 --- a/sh/shell.h +++ /dev/null @@ -1,83 +0,0 @@ -/* $NetBSD: shell.h,v 1.17 2003/08/07 09:05:38 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)shell.h 8.2 (Berkeley) 5/4/95 - */ - -/* - * The follow should be set to reflect the type of system you have: - * JOBS -> 1 if you have Berkeley job control, 0 otherwise. - * SHORTNAMES -> 1 if your linker cannot handle long names. - * define BSD if you are running 4.2 BSD or later. - * 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. - * define DO_SHAREDVFORK to indicate that vfork(2) shares its address - * with its parent. - * - * When debugging is on, debugging info will be written to ./trace and - * a quit signal will generate a core dump. - */ - -#include <sys/param.h> - -#define JOBS 1 -#ifndef BSD -#define BSD 1 -#endif - -#ifndef DO_SHAREDVFORK -#if __NetBSD_Version__ >= 104000000 -#define DO_SHAREDVFORK -#endif -#endif - -typedef void *pointer; -#ifndef NULL -#define NULL (void *)0 -#endif -#define STATIC /* empty */ -#define MKINIT /* empty */ - -#include <sys/cdefs.h> - -extern char nullstr[1]; /* null string */ - - -#ifdef DEBUG -#define TRACE(param) trace param -#define TRACEV(param) tracev param -#else -#define TRACE(param) -#define TRACEV(param) -#endif diff --git a/sh/show.c b/sh/show.c deleted file mode 100644 index e92aa51..0000000 --- a/sh/show.c +++ /dev/null @@ -1,425 +0,0 @@ -/* $NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $"); -#endif -#endif /* not lint */ - -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> - -#include "shell.h" -#include "parser.h" -#include "nodes.h" -#include "mystring.h" -#include "show.h" -#include "options.h" - - -#ifdef DEBUG -static void shtree(union node *, int, char *, FILE*); -static void shcmd(union node *, FILE *); -static void sharg(union node *, FILE *); -static void indent(int, char *, FILE *); -static void trstring(char *); - - -void -showtree(union node *n) -{ - trputs("showtree called\n"); - shtree(n, 1, NULL, stdout); -} - - -static void -shtree(union node *n, int ind, char *pfx, FILE *fp) -{ - struct nodelist *lp; - const char *s; - - if (n == NULL) - return; - - indent(ind, pfx, fp); - switch(n->type) { - case NSEMI: - s = "; "; - goto binop; - case NAND: - s = " && "; - goto binop; - case NOR: - s = " || "; -binop: - shtree(n->nbinary.ch1, ind, NULL, fp); - /* if (ind < 0) */ - fputs(s, fp); - shtree(n->nbinary.ch2, ind, NULL, fp); - break; - case NCMD: - shcmd(n, fp); - if (ind >= 0) - putc('\n', fp); - break; - case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - shcmd(lp->n, fp); - if (lp->next) - fputs(" | ", fp); - } - if (n->npipe.backgnd) - fputs(" &", fp); - if (ind >= 0) - putc('\n', fp); - break; - default: - fprintf(fp, "<node type %d>", n->type); - if (ind >= 0) - putc('\n', fp); - break; - } -} - - - -static void -shcmd(union node *cmd, FILE *fp) -{ - union node *np; - int first; - const char *s; - int dftfd; - - first = 1; - for (np = cmd->ncmd.args ; np ; np = np->narg.next) { - if (! first) - putchar(' '); - sharg(np, fp); - first = 0; - } - for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { - if (! first) - putchar(' '); - switch (np->nfile.type) { - case NTO: s = ">"; dftfd = 1; break; - case NCLOBBER: s = ">|"; dftfd = 1; break; - case NAPPEND: s = ">>"; dftfd = 1; break; - case NTOFD: s = ">&"; dftfd = 1; break; - case NFROM: s = "<"; dftfd = 0; break; - case NFROMFD: s = "<&"; dftfd = 0; break; - case NFROMTO: s = "<>"; dftfd = 0; break; - default: s = "*error*"; dftfd = 0; break; - } - if (np->nfile.fd != dftfd) - fprintf(fp, "%d", np->nfile.fd); - fputs(s, fp); - if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { - fprintf(fp, "%d", np->ndup.dupfd); - } else { - sharg(np->nfile.fname, fp); - } - first = 0; - } -} - - - -static void -sharg(union node *arg, FILE *fp) -{ - char *p; - struct nodelist *bqlist; - int subtype; - - if (arg->type != NARG) { - printf("<node type %d>\n", arg->type); - abort(); - } - bqlist = arg->narg.backquote; - for (p = arg->narg.text ; *p ; p++) { - switch (*p) { - case CTLESC: - putc(*++p, fp); - break; - case CTLVAR: - putc('$', fp); - putc('{', fp); - subtype = *++p; - if (subtype == VSLENGTH) - putc('#', fp); - - while (*p != '=') - putc(*p++, fp); - - if (subtype & VSNUL) - putc(':', fp); - - switch (subtype & VSTYPE) { - case VSNORMAL: - putc('}', fp); - break; - case VSMINUS: - putc('-', fp); - break; - case VSPLUS: - putc('+', fp); - break; - case VSQUESTION: - putc('?', fp); - break; - case VSASSIGN: - putc('=', fp); - break; - case VSTRIMLEFT: - putc('#', fp); - break; - case VSTRIMLEFTMAX: - putc('#', fp); - putc('#', fp); - break; - case VSTRIMRIGHT: - putc('%', fp); - break; - case VSTRIMRIGHTMAX: - putc('%', fp); - putc('%', fp); - break; - case VSLENGTH: - break; - default: - printf("<subtype %d>", subtype); - } - break; - case CTLENDVAR: - putc('}', fp); - break; - case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: - putc('$', fp); - putc('(', fp); - shtree(bqlist->n, -1, NULL, fp); - putc(')', fp); - break; - default: - putc(*p, fp); - break; - } - } -} - - -static void -indent(int amount, char *pfx, FILE *fp) -{ - int i; - - for (i = 0 ; i < amount ; i++) { - if (pfx && i == amount - 1) - fputs(pfx, fp); - putc('\t', fp); - } -} -#endif - - - -/* - * Debugging stuff. - */ - - -FILE *tracefile; - - -#ifdef DEBUG -void -trputc(int c) -{ - if (debug != 1) - return; - putc(c, tracefile); -} -#endif - -void -trace(const char *fmt, ...) -{ -#ifdef DEBUG - va_list va; - - if (debug != 1) - return; - va_start(va, fmt); - (void) vfprintf(tracefile, fmt, va); - va_end(va); -#endif -} - -void -tracev(const char *fmt, va_list va) -{ -#ifdef DEBUG - if (debug != 1) - return; - (void) vfprintf(tracefile, fmt, va); -#endif -} - - -#ifdef DEBUG -void -trputs(const char *s) -{ - if (debug != 1) - return; - fputs(s, tracefile); -} - - -static void -trstring(char *s) -{ - char *p; - char c; - - if (debug != 1) - return; - putc('"', tracefile); - for (p = s ; *p ; p++) { - switch (*p) { - case '\n': c = 'n'; goto backslash; - case '\t': c = 't'; goto backslash; - case '\r': c = 'r'; goto backslash; - case '"': c = '"'; goto backslash; - case '\\': c = '\\'; goto backslash; - case CTLESC: c = 'e'; goto backslash; - case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; - case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; -backslash: putc('\\', tracefile); - putc(c, tracefile); - break; - default: - if (*p >= ' ' && *p <= '~') - putc(*p, tracefile); - else { - putc('\\', tracefile); - putc(*p >> 6 & 03, tracefile); - putc(*p >> 3 & 07, tracefile); - putc(*p & 07, tracefile); - } - break; - } - } - putc('"', tracefile); -} -#endif - - -void -trargs(char **ap) -{ -#ifdef DEBUG - if (debug != 1) - return; - while (*ap) { - trstring(*ap++); - if (*ap) - putc(' ', tracefile); - else - putc('\n', tracefile); - } -#endif -} - - -#ifdef DEBUG -void -opentrace(void) -{ - char s[100]; -#ifdef O_APPEND - int flags; -#endif - - if (debug != 1) { - if (tracefile) - fflush(tracefile); - /* leave open because libedit might be using it */ - return; - } -#ifdef not_this_way - { - char *p; - if ((p = getenv("HOME")) == NULL) { - if (geteuid() == 0) - p = "/"; - else - p = "/tmp"; - } - scopy(p, s); - strcat(s, "/trace"); - } -#else - scopy("./trace", s); -#endif /* not_this_way */ - if (tracefile) { - if (!freopen(s, "a", tracefile)) { - fprintf(stderr, "Can't re-open %s\n", s); - debug = 0; - return; - } - } else { - if ((tracefile = fopen(s, "a")) == NULL) { - fprintf(stderr, "Can't open %s\n", s); - debug = 0; - return; - } - } -#ifdef O_APPEND - if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) - fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); -#endif - setlinebuf(tracefile); - fputs("\nTracing started.\n", tracefile); -} -#endif /* DEBUG */ diff --git a/sh/show.h b/sh/show.h deleted file mode 100644 index 3152ff2..0000000 --- a/sh/show.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $ */ - -/*- - * Copyright (c) 1995 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)show.h 1.1 (Berkeley) 5/4/95 - */ - -#include <stdarg.h> - -union node; -void showtree(union node *); -void trace(const char *, ...); -void tracev(const char *, va_list); -void trargs(char **); -#ifdef DEBUG -void trputc(int); -void trputs(const char *); -void opentrace(void); -#endif diff --git a/sh/syntax.c b/sh/syntax.c deleted file mode 100644 index 094f674..0000000 --- a/sh/syntax.c +++ /dev/null @@ -1,102 +0,0 @@ -/* $NetBSD: syntax.c,v 1.1 2004/01/17 17:38:12 dsl Exp $ */ - -#include "shell.h" -#include "syntax.h" -#include "parser.h" -#include <limits.h> - -#if CWORD != 0 -#error initialisation assumes 'CWORD' is zero -#endif - -#define ndx(ch) (ch + 1 - CHAR_MIN) -#define set(ch, val) [ndx(ch)] = val, -#define set_range(s, e, val) [ndx(s) ... ndx(e)] = val, - -/* syntax table used when not in quotes */ -const char basesyntax[257] = { CEOF, - set_range(CTL_FIRST, CTL_LAST, CCTL) - set('\n', CNL) - set('\\', CBACK) - set('\'', CSQUOTE) - set('"', CDQUOTE) - set('`', CBQUOTE) - set('$', CVAR) - set('}', CENDVAR) - set('<', CSPCL) - set('>', CSPCL) - set('(', CSPCL) - set(')', CSPCL) - set(';', CSPCL) - set('&', CSPCL) - set('|', CSPCL) - set(' ', CSPCL) - set('\t', CSPCL) -}; - -/* syntax table used when in double quotes */ -const char dqsyntax[257] = { CEOF, - set_range(CTL_FIRST, CTL_LAST, CCTL) - set('\n', CNL) - set('\\', CBACK) - set('"', CDQUOTE) - set('`', CBQUOTE) - set('$', CVAR) - set('}', CENDVAR) - /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ - set('!', CCTL) - set('*', CCTL) - set('?', CCTL) - set('[', CCTL) - set('=', CCTL) - set('~', CCTL) - set(':', CCTL) - set('/', CCTL) - set('-', CCTL) -}; - -/* syntax table used when in single quotes */ -const char sqsyntax[257] = { CEOF, - set_range(CTL_FIRST, CTL_LAST, CCTL) - set('\n', CNL) - set('\'', CSQUOTE) - /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ - set('!', CCTL) - set('*', CCTL) - set('?', CCTL) - set('[', CCTL) - set('=', CCTL) - set('~', CCTL) - set(':', CCTL) - set('/', CCTL) - set('-', CCTL) -}; - -/* syntax table used when in arithmetic */ -const char arisyntax[257] = { CEOF, - set_range(CTL_FIRST, CTL_LAST, CCTL) - set('\n', CNL) - set('\\', CBACK) - set('`', CBQUOTE) - set('\'', CSQUOTE) - set('"', CDQUOTE) - set('$', CVAR) - set('}', CENDVAR) - set('(', CLP) - set(')', CRP) -}; - -/* character classification table */ -const char is_type[257] = { 0, - set_range('0', '9', ISDIGIT) - set_range('a', 'z', ISLOWER) - set_range('A', 'Z', ISUPPER) - set('_', ISUNDER) - set('#', ISSPECL) - set('?', ISSPECL) - set('$', ISSPECL) - set('!', ISSPECL) - set('-', ISSPECL) - set('*', ISSPECL) - set('@', ISSPECL) -}; diff --git a/sh/syntax.h b/sh/syntax.h deleted file mode 100644 index 89a32dc..0000000 --- a/sh/syntax.h +++ /dev/null @@ -1,83 +0,0 @@ -/* $NetBSD: syntax.h,v 1.2 2004/01/17 17:38:12 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#include <ctype.h> - -/* Syntax classes */ -#define CWORD 0 /* character is nothing special */ -#define CNL 1 /* newline character */ -#define CBACK 2 /* a backslash character */ -#define CSQUOTE 3 /* single quote */ -#define CDQUOTE 4 /* double quote */ -#define CBQUOTE 5 /* backwards single quote */ -#define CVAR 6 /* a dollar sign */ -#define CENDVAR 7 /* a '}' character */ -#define CLP 8 /* a left paren in arithmetic */ -#define CRP 9 /* a right paren in arithmetic */ -#define CEOF 10 /* end of file */ -#define CCTL 11 /* like CWORD, except it must be escaped */ -#define CSPCL 12 /* these terminate a word */ - -/* Syntax classes for is_ functions */ -#define ISDIGIT 01 /* a digit */ -#define ISUPPER 02 /* an upper case letter */ -#define ISLOWER 04 /* a lower case letter */ -#define ISUNDER 010 /* an underscore */ -#define ISSPECL 020 /* the name of a special parameter */ - -#define PEOF (CHAR_MIN - 1) -#define SYNBASE (-PEOF) -/* XXX UPEOF is CHAR_MAX, so is a valid 'char' value... */ -#define UPEOF ((char)PEOF) - - -#define BASESYNTAX (basesyntax + SYNBASE) -#define DQSYNTAX (dqsyntax + SYNBASE) -#define SQSYNTAX (sqsyntax + SYNBASE) -#define ARISYNTAX (arisyntax + SYNBASE) - -/* These defines assume that the digits are contiguous */ -#define is_digit(c) ((unsigned)((c) - '0') <= 9) -#define is_alpha(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char)(c))) -#define is_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char)(c)))) -#define is_in_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char)(c)))) -#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT)) -#define digit_val(c) ((c) - '0') - -extern const char basesyntax[]; -extern const char dqsyntax[]; -extern const char sqsyntax[]; -extern const char arisyntax[]; -extern const char is_type[]; diff --git a/sh/token.h b/sh/token.h deleted file mode 100644 index c961f01..0000000 --- a/sh/token.h +++ /dev/null @@ -1,112 +0,0 @@ -#define TEOF 0 -#define TNL 1 -#define TSEMI 2 -#define TBACKGND 3 -#define TAND 4 -#define TOR 5 -#define TPIPE 6 -#define TLP 7 -#define TRP 8 -#define TENDCASE 9 -#define TENDBQUOTE 10 -#define TREDIR 11 -#define TWORD 12 -#define TIF 13 -#define TTHEN 14 -#define TELSE 15 -#define TELIF 16 -#define TFI 17 -#define TWHILE 18 -#define TUNTIL 19 -#define TFOR 20 -#define TDO 21 -#define TDONE 22 -#define TBEGIN 23 -#define TEND 24 -#define TCASE 25 -#define TESAC 26 -#define TNOT 27 - -/* Array indicating which tokens mark the end of a list */ -const char tokendlist[] = { - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 0, - 1, - 0, -}; - -const char *const tokname[] = { - "end of file", - "newline", - "\";\"", - "\"&\"", - "\"&&\"", - "\"||\"", - "\"|\"", - "\"(\"", - "\")\"", - "\";;\"", - "\"`\"", - "redirection", - "word", - "\"if\"", - "\"then\"", - "\"else\"", - "\"elif\"", - "\"fi\"", - "\"while\"", - "\"until\"", - "\"for\"", - "\"do\"", - "\"done\"", - "\"{\"", - "\"}\"", - "\"case\"", - "\"esac\"", - "\"!\"", -}; - -#define KWDOFFSET 13 - -const char *const parsekwd[] = { - "if", - "then", - "else", - "elif", - "fi", - "while", - "until", - "for", - "do", - "done", - "{", - "}", - "case", - "esac", - "!", - 0 -}; diff --git a/sh/trap.c b/sh/trap.c deleted file mode 100644 index dcd76ac..0000000 --- a/sh/trap.c +++ /dev/null @@ -1,456 +0,0 @@ -/* $NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; -#else -__RCSID("$NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos Exp $"); -#endif -#endif /* not lint */ - -#include <signal.h> -#include <unistd.h> -#include <stdlib.h> - -#include "shell.h" -#include "main.h" -#include "nodes.h" /* for other headers */ -#include "eval.h" -#include "jobs.h" -#include "show.h" -#include "options.h" -#include "syntax.h" -#include "output.h" -#include "memalloc.h" -#include "error.h" -#include "trap.h" -#include "mystring.h" -#include "var.h" - -/* - * Sigmode records the current value of the signal handlers for the various - * modes. A value of zero means that the current handler is not known. - * S_HARD_IGN indicates that the signal was ignored on entry to the shell, - */ - -#define S_DFL 1 /* default signal handling (SIG_DFL) */ -#define S_CATCH 2 /* signal is caught */ -#define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#define S_HARD_IGN 4 /* signal is ignored permenantly */ -#define S_RESET 5 /* temporary - to reset a hard ignored sig */ - - -char *trap[NSIG+1]; /* trap handler commands */ -MKINIT char sigmode[NSIG]; /* current value of signal */ -char gotsig[NSIG]; /* indicates specified signal received */ -int pendingsigs; /* indicates some signal received */ - -static int getsigaction(int, sig_t *); - -/* - * return the signal number described by `p' (as a number or a name) - * or -1 if it isn't one - */ - -static int -signame_to_signum(const char *p) -{ - int i; - - if (is_number(p)) - return number(p); - - if (strcasecmp(p, "exit") == 0 ) - return 0; - - if (strncasecmp(p, "sig", 3) == 0) - p += 3; - - for (i = 0; i < NSIG; ++i) - if (sys_signame[i] && (strcasecmp (p, sys_signame[i]) == 0)) - return i; - return -1; -} - -/* - * Print a list of valid signal names - */ -static void -printsignals(void) -{ - int n; - - out1str("EXIT "); - - for (n = 1; n < NSIG; n++) { - out1fmt("%s", sys_signame[n]); - if ((n == NSIG/2) || n == (NSIG - 1)) - out1str("\n"); - else - out1c(' '); - } -} - -/* - * The trap builtin. - */ - -int -trapcmd(int argc, char **argv) -{ - char *action; - char **ap; - int signo; - - if (argc <= 1) { - for (signo = 0 ; signo <= NSIG ; signo++) - if (trap[signo] != NULL) { - out1fmt("trap -- "); - print_quoted(trap[signo]); - out1fmt(" %s\n", - (signo) ? sys_signame[signo] : "EXIT"); - } - return 0; - } - ap = argv + 1; - - action = NULL; - - if (strcmp(*ap, "--") == 0) - if (*++ap == NULL) - return 0; - - if (signame_to_signum(*ap) == -1) { - if ((*ap)[0] == '-') { - if ((*ap)[1] == '\0') - ap++; - else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') { - printsignals(); - return 0; - } - else - error("bad option %s\n", *ap); - } - else - action = *ap++; - } - - while (*ap) { - if (is_number(*ap)) - signo = number(*ap); - else - signo = signame_to_signum(*ap); - - if (signo < 0 || signo > NSIG) - error("%s: bad trap", *ap); - - INTOFF; - if (action) - action = savestr(action); - - if (trap[signo]) - ckfree(trap[signo]); - - trap[signo] = action; - - if (signo != 0) - setsignal(signo, 0); - INTON; - ap++; - } - return 0; -} - - - -/* - * Clear traps on a fork or vfork. - * Takes one arg vfork, to tell it to not be destructive of - * the parents variables. - */ - -void -clear_traps(int vforked) -{ - char **tp; - - for (tp = trap ; tp <= &trap[NSIG] ; tp++) { - if (*tp && **tp) { /* trap not NULL or SIG_IGN */ - INTOFF; - if (!vforked) { - ckfree(*tp); - *tp = NULL; - } - if (tp != &trap[0]) - setsignal(tp - trap, vforked); - INTON; - } - } -} - - - -/* - * Set the signal handler for the specified signal. The routine figures - * out what it should be set to. - */ - -long -setsignal(int signo, int vforked) -{ - int action; - sig_t sigact = SIG_DFL; - struct sigaction act, oact; - char *t, tsig; - - if ((t = trap[signo]) == NULL) - action = S_DFL; - else if (*t != '\0') - action = S_CATCH; - else - action = S_IGN; - if (rootshell && !vforked && action == S_DFL) { - switch (signo) { - case SIGINT: - if (iflag || minusc || sflag == 0) - action = S_CATCH; - break; - case SIGQUIT: -#ifdef DEBUG - if (debug) - break; -#endif - /* FALLTHROUGH */ - case SIGTERM: - if (iflag) - action = S_IGN; - break; -#if JOBS - case SIGTSTP: - case SIGTTOU: - if (mflag) - action = S_IGN; - break; -#endif - } - } - - t = &sigmode[signo - 1]; - tsig = *t; - if (tsig == 0) { - /* - * current setting unknown - */ - if (!getsigaction(signo, &sigact)) { - /* - * Pretend it worked; maybe we should give a warning - * here, but other shells don't. We don't alter - * sigmode, so that we retry every time. - */ - return 0; - } - if (sigact == SIG_IGN) { - if (mflag && (signo == SIGTSTP || - signo == SIGTTIN || signo == SIGTTOU)) { - tsig = S_IGN; /* don't hard ignore these */ - } else - tsig = S_HARD_IGN; - } else { - tsig = S_RESET; /* force to be set */ - } - } - if (tsig == S_HARD_IGN || tsig == action) - return 0; - switch (action) { - case S_DFL: sigact = SIG_DFL; break; - case S_CATCH: sigact = onsig; break; - case S_IGN: sigact = SIG_IGN; break; - } - if (!vforked) - *t = action; - act.sa_handler = sigact; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_INTERRUPT - act.sa_flags |= SA_INTERRUPT; -#endif - if(sigaction(signo, &act, &oact) < 0) - return (long) SIG_ERR; - return (long) oact.sa_handler; -} - -/* - * Return the current setting for sig w/o changing it. - */ -static int -getsigaction(int signo, sig_t *sigact) -{ - struct sigaction sa; - - if (sigaction(signo, (struct sigaction *)0, &sa) == -1) - return 0; - *sigact = (sig_t) sa.sa_handler; - return 1; -} - -/* - * Ignore a signal. - */ - -void -ignoresig(int signo, int vforked) -{ - if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) - bsd_signal(signo, SIG_IGN); - if (!vforked) - sigmode[signo - 1] = S_HARD_IGN; -} - - -#ifdef mkinit -INCLUDE <signal.h> -INCLUDE "trap.h" - -SHELLPROC { - char *sm; - - clear_traps(0); - for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; - } -} -#endif - - - -/* - * Signal handler. - */ - -void -onsig(int signo) -{ - bsd_signal(signo, onsig); - if (signo == SIGINT && trap[SIGINT] == NULL) { - onint(); - return; - } - gotsig[signo - 1] = 1; - pendingsigs++; -} - - - -/* - * Called to execute a trap. Perhaps we should avoid entering new trap - * handlers while we are executing a trap handler. - */ - -void -dotrap(void) -{ - int i; - int savestatus; - - for (;;) { - for (i = 1 ; ; i++) { - if (gotsig[i - 1]) - break; - if (i >= NSIG) - goto done; - } - gotsig[i - 1] = 0; - savestatus=exitstatus; - evalstring(trap[i], 0); - exitstatus=savestatus; - } -done: - pendingsigs = 0; -} - - - -/* - * Controls whether the shell is interactive or not. - */ - - -void -setinteractive(int on) -{ - static int is_interactive; - - if (on == is_interactive) - return; - setsignal(SIGINT, 0); - setsignal(SIGQUIT, 0); - setsignal(SIGTERM, 0); - is_interactive = on; -} - - - -/* - * Called to exit the shell. - */ - -void -exitshell(int status) -{ - struct jmploc loc1, loc2; - char *p; - - TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (setjmp(loc1.loc)) { - goto l1; - } - if (setjmp(loc2.loc)) { - goto l2; - } - handler = &loc1; - if ((p = trap[0]) != NULL && *p != '\0') { - trap[0] = NULL; - evalstring(p, 0); - } -l1: handler = &loc2; /* probably unnecessary */ - flushall(); -#if JOBS - setjobctl(0); -#endif -l2: _exit(status); - /* NOTREACHED */ -} diff --git a/sh/trap.h b/sh/trap.h deleted file mode 100644 index 125ef40..0000000 --- a/sh/trap.h +++ /dev/null @@ -1,46 +0,0 @@ -/* $NetBSD: trap.h,v 1.17 2003/08/07 09:05:39 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)trap.h 8.3 (Berkeley) 6/5/95 - */ - -extern int pendingsigs; - -int trapcmd(int, char **); -void clear_traps(int); -long setsignal(int, int); -void ignoresig(int, int); -void onsig(int); -void dotrap(void); -void setinteractive(int); -void exitshell(int) __attribute__((__noreturn__)); diff --git a/sh/var.c b/sh/var.c deleted file mode 100644 index a1f1689..0000000 --- a/sh/var.c +++ /dev/null @@ -1,825 +0,0 @@ -/* $NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $"); -#endif -#endif /* not lint */ - -#include <unistd.h> -#include <stdlib.h> -#include <paths.h> - -/* - * Shell variables. - */ - -#include "shell.h" -#include "output.h" -#include "expand.h" -#include "nodes.h" /* for other headers */ -#include "eval.h" /* defines cmdenviron */ -#include "exec.h" -#include "syntax.h" -#include "options.h" -#include "var.h" -#include "memalloc.h" -#include "error.h" -#include "mystring.h" -#include "parser.h" -#include "show.h" -#ifndef SMALL -#include "myhistedit.h" -#endif - -#ifdef SMALL -#define VTABSIZE 39 -#else -#define VTABSIZE 517 -#endif - - -struct varinit { - struct var *var; - int flags; - const char *text; - void (*func)(const char *); -}; - - -#if ATTY -struct var vatty; -#endif -#ifdef WITH_HISTORY -struct var vhistsize; -struct var vterm; -#endif -struct var vifs; -struct var vmpath; -struct var vpath; -struct var vps1; -struct var vps2; -struct var vps4; -struct var vvers; -struct var voptind; - -const struct varinit varinit[] = { -#if ATTY - { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", - NULL }, -#endif -#ifdef WITH_HISTORY - { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", - sethistsize }, -#endif - { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", - NULL }, - { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", - NULL }, - { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, - changepath }, - /* - * vps1 depends on uid - */ - { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", - NULL }, - { &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ", - NULL }, -#ifdef WITH_HISTORY - { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", - setterm }, -#endif - { &voptind, VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1", - getoptsreset }, - { NULL, 0, NULL, - NULL } -}; - -struct var *vartab[VTABSIZE]; - -STATIC int strequal(const char *, const char *); -STATIC struct var *find_var(const char *, struct var ***, int *); - -/* - * Initialize the varable symbol tables and import the environment - */ - -#ifdef mkinit -INCLUDE "var.h" -MKINIT char **environ; -INIT { - char **envp; - - initvar(); - for (envp = environ ; *envp ; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } -} -#endif - - -/* - * This routine initializes the builtin variables. It is called when the - * shell is initialized and again when a shell procedure is spawned. - */ - -void -initvar(void) -{ - const struct varinit *ip; - struct var *vp; - struct var **vpp; - - for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { - if (find_var(ip->text, &vpp, &vp->name_len) != NULL) - continue; - vp->next = *vpp; - *vpp = vp; - vp->text = strdup(ip->text); - vp->flags = ip->flags; - vp->func = ip->func; - } - /* - * PS1 depends on uid - */ - if (find_var("PS1", &vpp, &vps1.name_len) == NULL) { - vps1.next = *vpp; - *vpp = &vps1; - vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); - vps1.flags = VSTRFIXED|VTEXTFIXED; - } -} - -/* - * Safe version of setvar, returns 1 on success 0 on failure. - */ - -int -setvarsafe(const char *name, const char *val, int flags) -{ - struct jmploc jmploc; - struct jmploc *volatile savehandler = handler; - int err = 0; -#ifdef __GNUC__ - (void) &err; -#endif - - if (setjmp(jmploc.loc)) - err = 1; - else { - handler = &jmploc; - setvar(name, val, flags); - } - handler = savehandler; - return err; -} - -/* - * Set the value of a variable. The flags argument is ored with the - * flags of the variable. If val is NULL, the variable is unset. - */ - -void -setvar(const char *name, const char *val, int flags) -{ - const char *p; - const char *q; - char *d; - int len; - int namelen; - char *nameeq; - int isbad; - - isbad = 0; - p = name; - if (! is_name(*p)) - isbad = 1; - p++; - for (;;) { - if (! is_in_name(*p)) { - if (*p == '\0' || *p == '=') - break; - isbad = 1; - } - p++; - } - namelen = p - name; - if (isbad) - error("%.*s: bad variable name", namelen, name); - len = namelen + 2; /* 2 is space for '=' and '\0' */ - if (val == NULL) { - flags |= VUNSET; - } else { - len += strlen(val); - } - d = nameeq = ckmalloc(len); - q = name; - while (--namelen >= 0) - *d++ = *q++; - *d++ = '='; - *d = '\0'; - if (val) - scopy(val, d); - setvareq(nameeq, flags); -} - - - -/* - * Same as setvar except that the variable and value are passed in - * the first argument as name=value. Since the first argument will - * be actually stored in the table, it should not be a string that - * will go away. - */ - -void -setvareq(char *s, int flags) -{ - struct var *vp, **vpp; - int nlen; - - if (aflag) - flags |= VEXPORT; - vp = find_var(s, &vpp, &nlen); - if (vp != NULL) { - if (vp->flags & VREADONLY) - error("%.*s: is read only", vp->name_len, s); - if (flags & VNOSET) - return; - INTOFF; - - if (vp->func && (flags & VNOFUNC) == 0) - (*vp->func)(s + vp->name_len + 1); - - if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) - ckfree(vp->text); - - vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); - vp->flags |= flags & ~VNOFUNC; - vp->text = s; - - INTON; - return; - } - /* not found */ - if (flags & VNOSET) - return; - vp = ckmalloc(sizeof (*vp)); - vp->flags = flags & ~VNOFUNC; - vp->text = s; - vp->name_len = nlen; - vp->next = *vpp; - vp->func = NULL; - *vpp = vp; -} - - - -/* - * Process a linked list of variable assignments. - */ - -void -listsetvar(struct strlist *list, int flags) -{ - struct strlist *lp; - - INTOFF; - for (lp = list ; lp ; lp = lp->next) { - setvareq(savestr(lp->text), flags); - } - INTON; -} - -void -listmklocal(struct strlist *list, int flags) -{ - struct strlist *lp; - - for (lp = list ; lp ; lp = lp->next) - mklocal(lp->text, flags); -} - - -/* - * Find the value of a variable. Returns NULL if not set. - */ - -char * -lookupvar(const char *name) -{ - struct var *v; - - v = find_var(name, NULL, NULL); - if (v == NULL || v->flags & VUNSET) - return NULL; - return v->text + v->name_len + 1; -} - - - -/* - * Search the environment of a builtin command. If the second argument - * is nonzero, return the value of a variable even if it hasn't been - * exported. - */ - -char * -bltinlookup(const char *name, int doall) -{ - struct strlist *sp; - struct var *v; - - for (sp = cmdenviron ; sp ; sp = sp->next) { - if (strequal(sp->text, name)) - return strchr(sp->text, '=') + 1; - } - - v = find_var(name, NULL, NULL); - - if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT))) - return NULL; - return v->text + v->name_len + 1; -} - - - -/* - * Generate a list of exported variables. This routine is used to construct - * the third argument to execve when executing a program. - */ - -char ** -environment(void) -{ - int nenv; - struct var **vpp; - struct var *vp; - char **env; - char **ep; - - nenv = 0; - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) - if (vp->flags & VEXPORT) - nenv++; - } - ep = env = stalloc((nenv + 1) * sizeof *env); - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) - if (vp->flags & VEXPORT) - *ep++ = vp->text; - } - *ep = NULL; - return env; -} - - -/* - * Called when a shell procedure is invoked to clear out nonexported - * variables. It is also necessary to reallocate variables of with - * VSTACK set since these are currently allocated on the stack. - */ - -#ifdef mkinit -void shprocvar(void); - -SHELLPROC { - shprocvar(); -} -#endif - -void -shprocvar(void) -{ - struct var **vpp; - struct var *vp, **prev; - - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (prev = vpp ; (vp = *prev) != NULL ; ) { - if ((vp->flags & VEXPORT) == 0) { - *prev = vp->next; - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - if ((vp->flags & VSTRFIXED) == 0) - ckfree(vp); - } else { - if (vp->flags & VSTACK) { - vp->text = savestr(vp->text); - vp->flags &=~ VSTACK; - } - prev = &vp->next; - } - } - } - initvar(); -} - - - -/* - * Command to list all variables which are set. Currently this command - * is invoked from the set command when the set command is called without - * any variables. - */ - -void -print_quoted(const char *p) -{ - const char *q; - - if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) { - out1fmt("%s", p); - return; - } - while (*p) { - if (*p == '\'') { - out1fmt("\\'"); - p++; - continue; - } - q = index(p, '\''); - if (!q) { - out1fmt("'%s'", p ); - return; - } - out1fmt("'%.*s'", (int)(q - p), p ); - p = q; - } -} - -static int -sort_var(const void *v_v1, const void *v_v2) -{ - const struct var * const *v1 = v_v1; - const struct var * const *v2 = v_v2; - - /* XXX Will anyone notice we include the '=' of the shorter name? */ - return strcmp((*v1)->text, (*v2)->text); -} - -/* - * POSIX requires that 'set' (but not export or readonly) output the - * variables in lexicographic order - by the locale's collating order (sigh). - * Maybe we could keep them in an ordered balanced binary tree - * instead of hashed lists. - * For now just roll 'em through qsort for printing... - */ - -int -showvars(const char *name, int flag, int show_value) -{ - struct var **vpp; - struct var *vp; - const char *p; - - static struct var **list; /* static in case we are interrupted */ - static int list_len; - int count = 0; - - if (!list) { - list_len = 32; - list = ckmalloc(list_len * sizeof *list); - } - - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) { - if (flag && !(vp->flags & flag)) - continue; - if (vp->flags & VUNSET && !(show_value & 2)) - continue; - if (count >= list_len) { - list = ckrealloc(list, - (list_len << 1) * sizeof *list); - list_len <<= 1; - } - list[count++] = vp; - } - } - - qsort(list, count, sizeof *list, sort_var); - - for (vpp = list; count--; vpp++) { - vp = *vpp; - if (name) - out1fmt("%s ", name); - for (p = vp->text ; *p != '=' ; p++) - out1c(*p); - if (!(vp->flags & VUNSET) && show_value) { - out1fmt("="); - print_quoted(++p); - } - out1c('\n'); - } - return 0; -} - - - -/* - * The export and readonly commands. - */ - -int -exportcmd(int argc, char **argv) -{ - struct var *vp; - char *name; - const char *p; - int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; - int pflag; - - pflag = nextopt("p") == 'p' ? 3 : 0; - if (argc <= 1 || pflag) { - showvars( pflag ? argv[0] : 0, flag, pflag ); - return 0; - } - - while ((name = *argptr++) != NULL) { - if ((p = strchr(name, '=')) != NULL) { - p++; - } else { - vp = find_var(name, NULL, NULL); - if (vp != NULL) { - vp->flags |= flag; - continue; - } - } - setvar(name, p, flag); - } - return 0; -} - - -/* - * The "local" command. - */ - -int -localcmd(int argc, char **argv) -{ - char *name; - - if (! in_function()) - error("Not in a function"); - while ((name = *argptr++) != NULL) { - mklocal(name, 0); - } - return 0; -} - - -/* - * Make a variable a local variable. When a variable is made local, it's - * value and flags are saved in a localvar structure. The saved values - * will be restored when the shell function returns. We handle the name - * "-" as a special case. - */ - -void -mklocal(const char *name, int flags) -{ - struct localvar *lvp; - struct var **vpp; - struct var *vp; - - INTOFF; - lvp = ckmalloc(sizeof (struct localvar)); - if (name[0] == '-' && name[1] == '\0') { - char *p; - p = ckmalloc(sizeof_optlist); - lvp->text = memcpy(p, optlist, sizeof_optlist); - vp = NULL; - } else { - vp = find_var(name, &vpp, NULL); - if (vp == NULL) { - if (strchr(name, '=')) - setvareq(savestr(name), VSTRFIXED|flags); - else - setvar(name, NULL, VSTRFIXED|flags); - vp = *vpp; /* the new variable */ - lvp->text = NULL; - lvp->flags = VUNSET; - } else { - lvp->text = vp->text; - lvp->flags = vp->flags; - vp->flags |= VSTRFIXED|VTEXTFIXED; - if (name[vp->name_len] == '=') - setvareq(savestr(name), flags); - } - } - lvp->vp = vp; - lvp->next = localvars; - localvars = lvp; - INTON; -} - - -/* - * Called after a function returns. - */ - -void -poplocalvars(void) -{ - struct localvar *lvp; - struct var *vp; - - while ((lvp = localvars) != NULL) { - localvars = lvp->next; - vp = lvp->vp; - TRACE(("poplocalvar %s", vp ? vp->text : "-")); - if (vp == NULL) { /* $- saved */ - memcpy(optlist, lvp->text, sizeof_optlist); - ckfree(lvp->text); - } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { - (void)unsetvar(vp->text, 0); - } else { - if (vp->func && (vp->flags & VNOFUNC) == 0) - (*vp->func)(lvp->text + vp->name_len + 1); - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - vp->flags = lvp->flags; - vp->text = lvp->text; - } - ckfree(lvp); - } -} - - -int -setvarcmd(int argc, char **argv) -{ - if (argc <= 2) - return unsetcmd(argc, argv); - else if (argc == 3) - setvar(argv[1], argv[2], 0); - else - error("List assignment not implemented"); - return 0; -} - - -/* - * The unset builtin command. We unset the function before we unset the - * variable to allow a function to be unset when there is a readonly variable - * with the same name. - */ - -int -unsetcmd(int argc, char **argv) -{ - char **ap; - int i; - int flg_func = 0; - int flg_var = 0; - int ret = 0; - - while ((i = nextopt("evf")) != '\0') { - if (i == 'f') - flg_func = 1; - else - flg_var = i; - } - if (flg_func == 0 && flg_var == 0) - flg_var = 1; - - for (ap = argptr; *ap ; ap++) { - if (flg_func) - ret |= unsetfunc(*ap); - if (flg_var) - ret |= unsetvar(*ap, flg_var == 'e'); - } - return ret; -} - - -/* - * Unset the specified variable. - */ - -int -unsetvar(const char *s, int unexport) -{ - struct var **vpp; - struct var *vp; - - vp = find_var(s, &vpp, NULL); - if (vp == NULL) - return 1; - - if (vp->flags & VREADONLY) - return (1); - - INTOFF; - if (unexport) { - vp->flags &= ~VEXPORT; - } else { - if (vp->text[vp->name_len + 1] != '\0') - setvar(s, nullstr, 0); - vp->flags &= ~VEXPORT; - vp->flags |= VUNSET; - if ((vp->flags & VSTRFIXED) == 0) { - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - *vpp = vp->next; - ckfree(vp); - } - } - INTON; - return 0; -} - - -/* - * Returns true if the two strings specify the same varable. The first - * variable name is terminated by '='; the second may be terminated by - * either '=' or '\0'. - */ - -STATIC int -strequal(const char *p, const char *q) -{ - while (*p == *q++) { - if (*p++ == '=') - return 1; - } - if (*p == '=' && *(q - 1) == '\0') - return 1; - return 0; -} - -/* - * Search for a variable. - * 'name' may be terminated by '=' or a NUL. - * vppp is set to the pointer to vp, or the list head if vp isn't found - * lenp is set to the number of charactets in 'name' - */ - -STATIC struct var * -find_var(const char *name, struct var ***vppp, int *lenp) -{ - unsigned int hashval; - int len; - struct var *vp, **vpp; - const char *p = name; - - hashval = 0; - while (*p && *p != '=') - hashval = 2 * hashval + (unsigned char)*p++; - len = p - name; - - if (lenp) - *lenp = len; - vpp = &vartab[hashval % VTABSIZE]; - if (vppp) - *vppp = vpp; - - for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { - if (vp->name_len != len) - continue; - if (memcmp(vp->text, name, len) != 0) - continue; - if (vppp) - *vppp = vpp; - return vp; - } - return NULL; -} diff --git a/sh/var.h b/sh/var.h deleted file mode 100644 index b7b7db8..0000000 --- a/sh/var.h +++ /dev/null @@ -1,131 +0,0 @@ -/* $NetBSD: var.h,v 1.23 2004/10/02 12:16:53 dsl Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)var.h 8.2 (Berkeley) 5/4/95 - */ - -/* - * Shell variables. - */ - -/* flags */ -#define VEXPORT 0x01 /* variable is exported */ -#define VREADONLY 0x02 /* variable cannot be modified */ -#define VSTRFIXED 0x04 /* variable struct is statically allocated */ -#define VTEXTFIXED 0x08 /* text is statically allocated */ -#define VSTACK 0x10 /* text is allocated on the stack */ -#define VUNSET 0x20 /* the variable is not set */ -#define VNOFUNC 0x40 /* don't call the callback function */ -#define VNOSET 0x80 /* do not set variable - just readonly test */ - - -struct var { - struct var *next; /* next entry in hash list */ - int flags; /* flags are defined above */ - char *text; /* name=value */ - int name_len; /* length of name */ - void (*func)(const char *); - /* function to be called when */ - /* the variable gets set/unset */ -}; - - -struct localvar { - struct localvar *next; /* next local variable in list */ - struct var *vp; /* the variable that was made local */ - int flags; /* saved flags */ - char *text; /* saved text */ -}; - - -struct localvar *localvars; - -#if ATTY -extern struct var vatty; -#endif -extern struct var vifs; -extern struct var vmpath; -extern struct var vpath; -extern struct var vps1; -extern struct var vps2; -extern struct var vps4; -#ifdef WITH_HISTORY -extern struct var vterm; -extern struct var vtermcap; -extern struct var vhistsize; -#endif - -/* - * The following macros access the values of the above variables. - * They have to skip over the name. They return the null string - * for unset variables. - */ - -#define ifsval() (vifs.text + 4) -#define ifsset() ((vifs.flags & VUNSET) == 0) -#define mpathval() (vmpath.text + 9) -#define pathval() (vpath.text + 5) -#define ps1val() (vps1.text + 4) -#define ps2val() (vps2.text + 4) -#define ps4val() (vps4.text + 4) -#define optindval() (voptind.text + 7) -#ifdef WITH_HISTORY -#define histsizeval() (vhistsize.text + 9) -#define termval() (vterm.text + 5) -#endif - -#if ATTY -#define attyset() ((vatty.flags & VUNSET) == 0) -#endif -#define mpathset() ((vmpath.flags & VUNSET) == 0) - -void initvar(void); -void setvar(const char *, const char *, int); -void setvareq(char *, int); -struct strlist; -void listsetvar(struct strlist *, int); -char *lookupvar(const char *); -char *bltinlookup(const char *, int); -char **environment(void); -void shprocvar(void); -int showvars(const char *, int, int); -int exportcmd(int, char **); -int localcmd(int, char **); -void mklocal(const char *, int); -void listmklocal(struct strlist *, int); -void poplocalvars(void); -int setvarcmd(int, char **); -int unsetcmd(int, char **); -int unsetvar(const char *, int); -int setvarsafe(const char *, const char *, int); -void print_quoted(const char *); diff --git a/toolbox/nandread.c b/toolbox/nandread.c index b124731..4666f26 100644 --- a/toolbox/nandread.c +++ b/toolbox/nandread.c @@ -12,7 +12,7 @@ static int test_empty(const char *buf, size_t size) { while(size--) { - if (*buf++ != 0xff) + if (*buf++ != (char) 0xff) return 0; } return 1; @@ -44,7 +44,7 @@ int nandread_main(int argc, char **argv) struct mtd_info_user mtdinfo; struct mtd_ecc_stats initial_ecc, last_ecc, ecc; struct mtd_oob_buf oobbuf; - struct nand_ecclayout ecclayout; + nand_ecclayout_t ecclayout; do { c = getopt(argc, argv, "d:f:s:S:L:Rhv"); @@ -177,7 +177,11 @@ int nandread_main(int argc, char **argv) if (rawmode) { rawmode = mtdinfo.oobsize; +#if !defined(MTD_STUPID_LOCK) /* using uapi kernel headers */ + ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW); +#else /* still using old kernel headers */ ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW); +#endif if (ret) { fprintf(stderr, "failed set raw mode for %s, %s\n", devname, strerror(errno)); |
