From bugzilla at busybox.net Wed Apr 1 04:20:13 2009 From: bugzilla at busybox.net (bugzilla at busybox.net) Date: Wed, 1 Apr 2009 04:20:13 +0000 (UTC) Subject: [Bug 235] ash: incorrect word splitting with read builtin In-Reply-To: References: Message-ID: <20090401042013.69B6977650@busybox.osuosl.org> https://bugs.busybox.net/show_bug.cgi?id=235 --- Comment #5 from Harald van D?k 2009-04-01 04:20:12 UTC --- hush's read simply doesn't do word splitting at all. -- Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug. From vda at busybox.net Wed Apr 1 11:24:04 2009 From: vda at busybox.net (vda at busybox.net) Date: Wed, 1 Apr 2009 11:24:04 +0000 (UTC) Subject: svn commit: [25915] trunk/busybox: archival/libunarchive docs/busybox.net e etc... Message-ID: <20090401112405.2446477657@busybox.osuosl.org> Author: vda Date: 2009-04-01 11:24:04 +0000 (Wed, 01 Apr 2009) New Revision: 25915 Log: trailing whitespace removal Modified: trunk/busybox/archival/libunarchive/get_header_tar.c trunk/busybox/docs/busybox.net/svnindex.xsl trunk/busybox/editors/vi.c trunk/busybox/findutils/grep.c trunk/busybox/include/libbb.h trunk/busybox/loginutils/login.c trunk/busybox/miscutils/ionice.c Changeset: Modified: trunk/busybox/archival/libunarchive/get_header_tar.c =================================================================== --- trunk/busybox/archival/libunarchive/get_header_tar.c 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/archival/libunarchive/get_header_tar.c 2009-04-01 11:24:04 UTC (rev 25915) @@ -48,7 +48,7 @@ while (1) { if (c) bb_error_msg_and_die("overflow in base-256 encoded file size"); - if (--len == sizeof(off_t)) + if (--len == sizeof(off_t)) break; c = *str++; } Modified: trunk/busybox/docs/busybox.net/svnindex.xsl =================================================================== --- trunk/busybox/docs/busybox.net/svnindex.xsl 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/docs/busybox.net/svnindex.xsl 2009-04-01 11:24:04 UTC (rev 25915) @@ -25,9 +25,9 @@
BUSYBOX
-
- -
+
+ +
Modified: trunk/busybox/editors/vi.c =================================================================== --- trunk/busybox/editors/vi.c 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/editors/vi.c 2009-04-01 11:24:04 UTC (rev 25915) @@ -1677,12 +1677,12 @@ q = prev_line(p); // use prev line as template len = strspn(q, " \t"); // space or tab if (len) { - uintptr_t bias; + uintptr_t bias; bias = text_hole_make(p, len); p += bias; q += bias; memcpy(p, q, len); - p += len; + p += len; } } #endif Modified: trunk/busybox/findutils/grep.c =================================================================== --- trunk/busybox/findutils/grep.c 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/findutils/grep.c 2009-04-01 11:24:04 UTC (rev 25915) @@ -30,7 +30,7 @@ USE_DESKTOP("w") \ USE_EXTRA_COMPAT("z") \ "aI" - + /* ignored: -a "assume all files to be text" */ /* ignored: -I "assume binary files have no matches" */ Modified: trunk/busybox/include/libbb.h =================================================================== --- trunk/busybox/include/libbb.h 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/include/libbb.h 2009-04-01 11:24:04 UTC (rev 25915) @@ -1301,7 +1301,7 @@ PSSCAN_ARGVN = (1 << 16) * (ENABLE_KILLALL || ENABLE_PGREP || ENABLE_PKILL || ENABLE_PIDOF - || ENABLE_SESTATUS + || ENABLE_SESTATUS ), USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,) PSSCAN_START_TIME = 1 << 18, Modified: trunk/busybox/loginutils/login.c =================================================================== --- trunk/busybox/loginutils/login.c 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/loginutils/login.c 2009-04-01 11:24:04 UTC (rev 25915) @@ -465,7 +465,7 @@ fchmod(0, 0600); /* We trust environment only if we run by root */ - if (ENABLE_LOGIN_SCRIPTS && run_by_root) + if (ENABLE_LOGIN_SCRIPTS && run_by_root) run_login_script(pw, full_tty); change_identity(pw); Modified: trunk/busybox/miscutils/ionice.c =================================================================== --- trunk/busybox/miscutils/ionice.c 2009-03-31 23:41:53 UTC (rev 25914) +++ trunk/busybox/miscutils/ionice.c 2009-04-01 11:24:04 UTC (rev 25915) @@ -57,7 +57,7 @@ /* '+': stop at first non-option */ opt = getopt32(argv, "+n:c:p:", &pri, &ioclass, &pid); argv += optind; - + if (opt & OPT_c) { if (ioclass > 3) bb_error_msg_and_die("bad class %d", ioclass); @@ -70,7 +70,7 @@ // pri = 7; // } } - + if (!(opt & (OPT_n|OPT_c))) { if (!(opt & OPT_p) && *argv) pid = xatoi_u(*argv); From vda at busybox.net Wed Apr 1 12:36:09 2009 From: vda at busybox.net (vda at busybox.net) Date: Wed, 1 Apr 2009 12:36:09 +0000 (UTC) Subject: svn commit: [25916] trunk/busybox/networking/udhcp Message-ID: <20090401123609.8FA9F77669@busybox.osuosl.org> Author: vda Date: 2009-04-01 12:36:09 +0000 (Wed, 01 Apr 2009) New Revision: 25916 Log: dhcpd: remember and record hostnames; optimize get_option dumpleases: show hostnames function old new delta add_lease 230 292 +62 send_offer 403 421 +18 send_ACK 232 249 +17 read_leases 249 258 +9 dumpleases_main 604 609 +5 nobody_responds_to_arp 84 86 +2 udhcp_end_option 32 30 -2 udhcp_get_option 222 171 -51 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/2 up/down: 113/-53) Total: 60 bytes Modified: trunk/busybox/networking/udhcp/dhcpd.h trunk/busybox/networking/udhcp/dumpleases.c trunk/busybox/networking/udhcp/files.c trunk/busybox/networking/udhcp/leases.c trunk/busybox/networking/udhcp/options.c trunk/busybox/networking/udhcp/options.h trunk/busybox/networking/udhcp/script.c trunk/busybox/networking/udhcp/serverpacket.c Changeset: Modified: trunk/busybox/networking/udhcp/dhcpd.h =================================================================== --- trunk/busybox/networking/udhcp/dhcpd.h 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/dhcpd.h 2009-04-01 12:36:09 UTC (rev 25916) @@ -74,9 +74,7 @@ #define SERVER_PORT 67 #endif -extern struct dhcpOfferedAddr *leases; - /*** leases.h ***/ typedef uint32_t leasetime_t; @@ -92,9 +90,15 @@ * and optionally adjusted (current time subtracted) * if server_config.remaining = 1 */ leasetime_t expires; + uint8_t hostname[20]; /* (size is a multiply of 4) */ }; -struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) FAST_FUNC; +extern struct dhcpOfferedAddr *leases; + +struct dhcpOfferedAddr *add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, uint8_t *hostname + ) FAST_FUNC; int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC; struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC; struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; Modified: trunk/busybox/networking/udhcp/dumpleases.c =================================================================== --- trunk/busybox/networking/udhcp/dumpleases.c 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/dumpleases.c 2009-04-01 12:36:09 UTC (rev 25916) @@ -47,8 +47,9 @@ fd = xopen(file, O_RDONLY); - printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in"); - /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */ + printf("Mac Address IP Address Host Name Expires %s\n", (opt & OPT_a) ? "at" : "in"); + /* "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */ + /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */ if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) return 0; @@ -64,7 +65,9 @@ fmt = ":%02x"; } addr.s_addr = lease.yiaddr; - printf(" %-15s ", inet_ntoa(addr)); + /* actually, 15+1 and 19+1, +1 is a space between columns */ + /* lease.hostname is char[20] and is always NUL terminated */ + printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname); expires_abs = ntohl(lease.expires) + written_at; if (expires_abs <= curr) { puts("expired"); Modified: trunk/busybox/networking/udhcp/files.c =================================================================== --- trunk/busybox/networking/udhcp/files.c 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/files.c 2009-04-01 12:36:09 UTC (rev 25916) @@ -420,7 +420,7 @@ continue; /* NB: add_lease takes "relative time", IOW, * lease duration, not lease deadline. */ - if (!(add_lease(lease.chaddr, lease.yiaddr, expires))) { + if (!(add_lease(lease.chaddr, lease.yiaddr, expires, lease.hostname))) { bb_error_msg("too many leases while loading %s", file); break; } Modified: trunk/busybox/networking/udhcp/leases.c =================================================================== --- trunk/busybox/networking/udhcp/leases.c 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/leases.c 2009-04-01 12:36:09 UTC (rev 25916) @@ -48,9 +48,12 @@ /* Add a lease into the table, clearing out any old ones */ -struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) +struct dhcpOfferedAddr* FAST_FUNC add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, uint8_t *hostname) { struct dhcpOfferedAddr *oldest; + uint8_t hostname_length; /* clean out any old ones */ clear_lease(chaddr, yiaddr); @@ -58,6 +61,19 @@ oldest = oldest_expired_lease(); if (oldest) { + oldest->hostname[0] = '\0'; + if (hostname) { + hostname_length = hostname[-1]; /* look at option size byte */ + if (hostname_length > sizeof(oldest->hostname)) + hostname_length = sizeof(oldest->hostname); + hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length); + /* sanitization (s/non-ACSII/^/g) */ + while (*hostname) { + if (*hostname < ' ' || *hostname > 126) + *hostname = '^'; + hostname++; + } + } memcpy(oldest->chaddr, chaddr, 16); oldest->yiaddr = yiaddr; oldest->expires = time(NULL) + leasetime; @@ -117,7 +133,7 @@ temp.s_addr = addr; bb_info_msg("%s belongs to someone, reserving it for %u seconds", inet_ntoa(temp), (unsigned)server_config.conflict_time); - add_lease(blank_chaddr, addr, server_config.conflict_time); + add_lease(blank_chaddr, addr, server_config.conflict_time, NULL); return 0; } Modified: trunk/busybox/networking/udhcp/options.c =================================================================== --- trunk/busybox/networking/udhcp/options.c 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/options.c 2009-04-01 12:36:09 UTC (rev 25916) @@ -119,58 +119,61 @@ }; -/* get an option with bounds checking (warning, not aligned). */ +/* get an option with bounds checking (warning, result is not aligned). */ uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) { - int i, length; uint8_t *optionptr; - int over = 0; - int curr = OPTION_FIELD; + int len; + int rem; + int overload = 0; + enum { + FILE_FIELD101 = FILE_FIELD * 0x101, + SNAME_FIELD101 = SNAME_FIELD * 0x101, + }; + /* option bytes: [code][len][data1][data2]..[dataLEN] */ optionptr = packet->options; - i = 0; - length = sizeof(packet->options); + rem = sizeof(packet->options); while (1) { - if (i >= length) { - bb_error_msg("bogus packet, option fields too long"); + if (rem <= 0) { + bb_error_msg("bogus packet, malformed option field"); return NULL; } - if (optionptr[i + OPT_CODE] == code) { - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - return optionptr + i + 2; + if (optionptr[OPT_CODE] == DHCP_PADDING) { + rem--; + optionptr++; + continue; } - switch (optionptr[i + OPT_CODE]) { - case DHCP_PADDING: - i++; - break; - case DHCP_OPTION_OVER: - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; + if (optionptr[OPT_CODE] == DHCP_END) { + if ((overload & FILE_FIELD101) == FILE_FIELD) { + /* can use packet->file, and didn't look at it yet */ + overload |= FILE_FIELD101; /* "we looked at it" */ + optionptr = packet->file; + rem = sizeof(packet->file); + continue; } - over = optionptr[i + 3]; - i += optionptr[OPT_LEN] + 2; - break; - case DHCP_END: - if (curr == OPTION_FIELD && (over & FILE_FIELD)) { - optionptr = packet->file; - i = 0; - length = sizeof(packet->file); - curr = FILE_FIELD; - } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { + if ((overload & SNAME_FIELD101) == SNAME_FIELD) { + /* can use packet->sname, and didn't look at it yet */ + overload |= SNAME_FIELD101; /* "we looked at it" */ optionptr = packet->sname; - i = 0; - length = sizeof(packet->sname); - curr = SNAME_FIELD; - } else - return NULL; - break; - default: - i += optionptr[OPT_LEN + i] + 2; + rem = sizeof(packet->sname); + continue; + } + return NULL; } + len = 2 + optionptr[OPT_LEN]; + rem -= len; + if (rem < 0) + continue; /* complain and return NULL */ + + if (optionptr[OPT_CODE] == code) + return optionptr + OPT_DATA; + + if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { + overload |= optionptr[OPT_DATA]; + /* fall through */ + } + optionptr += len; } return NULL; } @@ -182,17 +185,16 @@ int i = 0; while (optionptr[i] != DHCP_END) { - if (optionptr[i] == DHCP_PADDING) - i++; - else - i += optionptr[i + OPT_LEN] + 2; + if (optionptr[i] != DHCP_PADDING) + i += optionptr[i + OPT_LEN] + 1; + i++; } return i; } -/* add an option string to the options (an option string contains an option code, - * length, then data) */ +/* add an option string to the options */ +/* option bytes: [code][len][data1][data2]..[dataLEN] */ int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) { int end = end_option(optionptr); Modified: trunk/busybox/networking/udhcp/options.h =================================================================== --- trunk/busybox/networking/udhcp/options.h 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/options.h 2009-04-01 12:36:09 UTC (rev 25916) @@ -7,7 +7,7 @@ # pragma GCC visibility push(hidden) #endif -#define TYPE_MASK 0x0F +#define TYPE_MASK 0x0F enum { OPTION_IP = 1, @@ -24,8 +24,8 @@ OPTION_S32 }; -#define OPTION_REQ 0x10 /* have the client request this option */ -#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ +#define OPTION_REQ 0x10 /* have the client request this option */ +#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ /*****************************************************************/ /* Do not modify below here unless you know what you are doing!! */ @@ -34,68 +34,65 @@ /* DHCP protocol -- see RFC 2131 */ #define DHCP_MAGIC 0x63825363 - /* DHCP option codes (partial list) */ -#define DHCP_PADDING 0x00 -#define DHCP_SUBNET 0x01 -#define DHCP_TIME_OFFSET 0x02 -#define DHCP_ROUTER 0x03 -#define DHCP_TIME_SERVER 0x04 -#define DHCP_NAME_SERVER 0x05 -#define DHCP_DNS_SERVER 0x06 -#define DHCP_LOG_SERVER 0x07 -#define DHCP_COOKIE_SERVER 0x08 -#define DHCP_LPR_SERVER 0x09 -#define DHCP_HOST_NAME 0x0c -#define DHCP_BOOT_SIZE 0x0d -#define DHCP_DOMAIN_NAME 0x0f -#define DHCP_SWAP_SERVER 0x10 -#define DHCP_ROOT_PATH 0x11 -#define DHCP_IP_TTL 0x17 -#define DHCP_MTU 0x1a -#define DHCP_BROADCAST 0x1c -#define DHCP_NTP_SERVER 0x2a -#define DHCP_WINS_SERVER 0x2c -#define DHCP_REQUESTED_IP 0x32 -#define DHCP_LEASE_TIME 0x33 -#define DHCP_OPTION_OVER 0x34 -#define DHCP_MESSAGE_TYPE 0x35 -#define DHCP_SERVER_ID 0x36 -#define DHCP_PARAM_REQ 0x37 -#define DHCP_MESSAGE 0x38 -#define DHCP_MAX_SIZE 0x39 -#define DHCP_T1 0x3a -#define DHCP_T2 0x3b -#define DHCP_VENDOR 0x3c -#define DHCP_CLIENT_ID 0x3d -#define DHCP_FQDN 0x51 -#define DHCP_END 0xFF +#define DHCP_PADDING 0x00 +#define DHCP_SUBNET 0x01 +#define DHCP_TIME_OFFSET 0x02 +#define DHCP_ROUTER 0x03 +#define DHCP_TIME_SERVER 0x04 +#define DHCP_NAME_SERVER 0x05 +#define DHCP_DNS_SERVER 0x06 +#define DHCP_LOG_SERVER 0x07 +#define DHCP_COOKIE_SERVER 0x08 +#define DHCP_LPR_SERVER 0x09 +#define DHCP_HOST_NAME 0x0c +#define DHCP_BOOT_SIZE 0x0d +#define DHCP_DOMAIN_NAME 0x0f +#define DHCP_SWAP_SERVER 0x10 +#define DHCP_ROOT_PATH 0x11 +#define DHCP_IP_TTL 0x17 +#define DHCP_MTU 0x1a +#define DHCP_BROADCAST 0x1c +#define DHCP_NTP_SERVER 0x2a +#define DHCP_WINS_SERVER 0x2c +#define DHCP_REQUESTED_IP 0x32 +#define DHCP_LEASE_TIME 0x33 +#define DHCP_OPTION_OVERLOAD 0x34 +#define DHCP_MESSAGE_TYPE 0x35 +#define DHCP_SERVER_ID 0x36 +#define DHCP_PARAM_REQ 0x37 +#define DHCP_MESSAGE 0x38 +#define DHCP_MAX_SIZE 0x39 +#define DHCP_T1 0x3a +#define DHCP_T2 0x3b +#define DHCP_VENDOR 0x3c +#define DHCP_CLIENT_ID 0x3d +#define DHCP_FQDN 0x51 +#define DHCP_END 0xFF +/* Offsets in option byte sequence */ +#define OPT_CODE 0 +#define OPT_LEN 1 +#define OPT_DATA 2 +/* Bits in "overload" option */ +#define OPTION_FIELD 0 +#define FILE_FIELD 1 +#define SNAME_FIELD 2 +#define BOOTREQUEST 1 +#define BOOTREPLY 2 -#define BOOTREQUEST 1 -#define BOOTREPLY 2 +#define ETH_10MB 1 +#define ETH_10MB_LEN 6 -#define ETH_10MB 1 -#define ETH_10MB_LEN 6 +#define DHCPDISCOVER 1 /* client -> server */ +#define DHCPOFFER 2 /* client <- server */ +#define DHCPREQUEST 3 /* client -> server */ +#define DHCPDECLINE 4 /* client -> server */ +#define DHCPACK 5 /* client <- server */ +#define DHCPNAK 6 /* client <- server */ +#define DHCPRELEASE 7 /* client -> server */ +#define DHCPINFORM 8 /* client -> server */ -#define DHCPDISCOVER 1 /* client -> server */ -#define DHCPOFFER 2 /* client <- server */ -#define DHCPREQUEST 3 /* client -> server */ -#define DHCPDECLINE 4 /* client -> server */ -#define DHCPACK 5 /* client <- server */ -#define DHCPNAK 6 /* client <- server */ -#define DHCPRELEASE 7 /* client -> server */ -#define DHCPINFORM 8 /* client -> server */ - -#define OPTION_FIELD 0 -#define FILE_FIELD 1 -#define SNAME_FIELD 2 - -/* miscellaneous defines */ -#define OPT_CODE 0 -#define OPT_LEN 1 -#define OPT_DATA 2 - struct dhcp_option { uint8_t flags; uint8_t code; Modified: trunk/busybox/networking/udhcp/script.c =================================================================== --- trunk/busybox/networking/udhcp/script.c 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/script.c 2009-04-01 12:36:09 UTC (rev 25916) @@ -135,7 +135,7 @@ char **envp, **curr; const char *opt_name; uint8_t *temp; - char over = 0; + uint8_t over = 0; if (packet) { for (i = 0; dhcp_options[i].code; i++) { @@ -147,7 +147,7 @@ } if (packet->siaddr) num_options++; - temp = get_option(packet, DHCP_OPTION_OVER); + temp = get_option(packet, DHCP_OPTION_OVERLOAD); if (temp) over = *temp; if (!(over & FILE_FIELD) && packet->file[0]) Modified: trunk/busybox/networking/udhcp/serverpacket.c =================================================================== --- trunk/busybox/networking/udhcp/serverpacket.c 2009-04-01 11:24:04 UTC (rev 25915) +++ trunk/busybox/networking/udhcp/serverpacket.c 2009-04-01 12:36:09 UTC (rev 25916) @@ -105,7 +105,7 @@ uint32_t req_align; uint32_t lease_time_aligned = server_config.lease; uint32_t static_lease_ip; - uint8_t *req, *lease_time; + uint8_t *req, *lease_time, *p_host_name; struct option_set *curr; struct in_addr addr; @@ -146,7 +146,8 @@ bb_error_msg("no IP addresses to give - OFFER abandoned"); return -1; } - if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { + p_host_name = get_option(oldpacket, DHCP_HOST_NAME); + if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) { bb_error_msg("lease pool is full - OFFER abandoned"); return -1; } @@ -201,6 +202,7 @@ uint8_t *lease_time; uint32_t lease_time_aligned = server_config.lease; struct in_addr addr; + uint8_t *p_host_name; init_packet(&packet, oldpacket, DHCPACK); packet.yiaddr = yiaddr; @@ -232,7 +234,8 @@ if (send_packet(&packet, 0) < 0) return -1; - add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned); + p_host_name = get_option(oldpacket, DHCP_HOST_NAME); + add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned, p_host_name); if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { /* rewrite the file with leases at every new acceptance */ write_leases(); From vda at busybox.net Wed Apr 1 19:48:06 2009 From: vda at busybox.net (vda at busybox.net) Date: Wed, 1 Apr 2009 19:48:06 +0000 (UTC) Subject: svn commit: [25923] trunk/busybox: e2fsprogs/old_e2fsprogs/blkid include mi etc... Message-ID: <20090401194806.5050C77673@busybox.osuosl.org> Author: vda Date: 2009-04-01 19:48:05 +0000 (Wed, 01 Apr 2009) New Revision: 25923 Log: more of pointless whitespace fixes Modified: trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h trunk/busybox/include/platform.h trunk/busybox/include/rtc_.h trunk/busybox/miscutils/crond.c trunk/busybox/miscutils/hdparm.c trunk/busybox/networking/udhcp/leases.c trunk/busybox/shell/ash.c trunk/busybox/util-linux/fbset.c Changeset: Modified: trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h =================================================================== --- trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/e2fsprogs/old_e2fsprogs/blkid/probe.h 2009-04-01 19:48:05 UTC (rev 25923) @@ -308,9 +308,9 @@ #ifdef EXT2FS_REQUIRE_486 __asm__("bswap %0" : "=r" (val) : "0" (val)); #else - __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ - "rorl $16,%0\n\t" /* swap words */ - "xchgb %b0,%h0" /* swap higher bytes */ + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ :"=q" (val) : "0" (val)); #endif @@ -319,9 +319,9 @@ _INLINE_ __u16 blkid_swab16(__u16 val) { - __asm__("xchgb %b0,%h0" /* swap bytes */ \ - : "=q" (val) \ - : "0" (val)); \ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (val) + : "0" (val)); return val; } Modified: trunk/busybox/include/platform.h =================================================================== --- trunk/busybox/include/platform.h 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/include/platform.h 2009-04-01 19:48:05 UTC (rev 25923) @@ -371,4 +371,4 @@ #endif #endif -#endif /* platform.h */ +#endif /* platform.h */ Modified: trunk/busybox/include/rtc_.h =================================================================== --- trunk/busybox/include/rtc_.h 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/include/rtc_.h 2009-04-01 19:48:05 UTC (rev 25923) @@ -44,28 +44,27 @@ * ioctl calls that are permitted to the /dev/rtc interface, if * any of the RTC drivers are enabled. */ +#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ +#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ +#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ +#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ +#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ +#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ +#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ +#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ -#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ -#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ -#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ -#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ -#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ -#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ +#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */ +#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */ +#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */ +#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */ +#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ +#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ -#define RTC_ALM_SET _IOW('p', 0x07, struct linux_rtc_time) /* Set alarm time */ -#define RTC_ALM_READ _IOR('p', 0x08, struct linux_rtc_time) /* Read alarm time */ -#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */ -#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ -#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ +#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ +#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ -#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ -#define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ - /* interrupt flags */ #define RTC_IRQF 0x80 /* any of the following is active */ #define RTC_PF 0x40 Modified: trunk/busybox/miscutils/crond.c =================================================================== --- trunk/busybox/miscutils/crond.c 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/miscutils/crond.c 2009-04-01 19:48:05 UTC (rev 25923) @@ -55,7 +55,7 @@ #if ENABLE_FEATURE_CROND_CALL_SENDMAIL int cl_MailPos; /* 'empty file' size */ smallint cl_MailFlag; /* running pid is for mail */ - char *cl_MailTo; /* whom to mail results */ + char *cl_MailTo; /* whom to mail results */ #endif /* ordered by size, not in natural order. makes code smaller: */ char cl_Dow[7]; /* 0-6, beginning sunday */ Modified: trunk/busybox/miscutils/hdparm.c =================================================================== --- trunk/busybox/miscutils/hdparm.c 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/miscutils/hdparm.c 2009-04-01 19:48:05 UTC (rev 25923) @@ -59,7 +59,7 @@ #define ADV_PIO_MODES 64 /* advanced PIO modes supported */ /* multiword DMA xfer cycle time: */ #define DMA_TIME_MIN 65 /* - minimum */ -#define DMA_TIME_NORM 66 /* - manufacturer's recommended */ +#define DMA_TIME_NORM 66 /* - manufacturer's recommended */ /* minimum PIO xfer cycle time: */ #define PIO_NO_FLOW 67 /* - without flow control */ #define PIO_FLOW 68 /* - with IORDY flow control */ @@ -82,7 +82,7 @@ #define ENH_ERASE_TIME 90 /* - enhanced */ #define ADV_PWR 91 /* current advanced power management level in low byte, 0x40 in high byte. */ -#define PSWD_CODE 92 /* master password revision code */ +#define PSWD_CODE 92 /* master password revision code */ #define HWRST_RSLT 93 /* hardware reset result */ #define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */ #define LBA_LSB 100 /* LBA: maximum. Currently only 48 */ Modified: trunk/busybox/networking/udhcp/leases.c =================================================================== --- trunk/busybox/networking/udhcp/leases.c 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/networking/udhcp/leases.c 2009-04-01 19:48:05 UTC (rev 25923) @@ -67,7 +67,7 @@ if (hostname_length > sizeof(oldest->hostname)) hostname_length = sizeof(oldest->hostname); hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length); - /* sanitization (s/non-ACSII/^/g) */ + /* sanitization (s/non-ASCII/^/g) */ while (*hostname) { if (*hostname < ' ' || *hostname > 126) *hostname = '^'; Modified: trunk/busybox/shell/ash.c =================================================================== --- trunk/busybox/shell/ash.c 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/shell/ash.c 2009-04-01 19:48:05 UTC (rev 25923) @@ -12619,7 +12619,7 @@ if (c == '\n') break; /* $IFS splitting */ -/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ +/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ is_ifs = strchr(ifs, c); if (startword && is_ifs) { if (isspace(c)) Modified: trunk/busybox/util-linux/fbset.c =================================================================== --- trunk/busybox/util-linux/fbset.c 2009-04-01 18:39:02 UTC (rev 25922) +++ trunk/busybox/util-linux/fbset.c 2009-04-01 19:48:05 UTC (rev 25923) @@ -91,7 +91,7 @@ uint32_t height; /* height of picture in mm */ uint32_t width; /* width of picture in mm */ - uint32_t accel_flags; /* acceleration flags (hints) */ + uint32_t accel_flags; /* acceleration flags (hints) */ /* Timing: All values in pixclocks, except pixclock (of course) */ uint32_t pixclock; /* pixel clock in ps (pico seconds) */ From bugzilla at busybox.net Thu Apr 2 09:00:13 2009 From: bugzilla at busybox.net (bugzilla at busybox.net) Date: Thu, 2 Apr 2009 09:00:13 +0000 (UTC) Subject: [Bug 185] Add an option not to reload command line history with ash shell In-Reply-To: References: Message-ID: <20090402090013.C0C2077663@busybox.osuosl.org> https://bugs.busybox.net/show_bug.cgi?id=185 --- Comment #9 from Andre Klapper 2009-04-02 09:00:12 UTC --- Alexander said that "This particular problem actually does not exist in the trunk, at least, from what I see here." The patch that was used for Maemo Fremantle (Busybox 1.10.x) is at https://bugs.maemo.org/attachment.cgi?id=1162 -- Configure bugmail: https://bugs.busybox.net/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug. From vapier at busybox.net Thu Apr 2 09:18:34 2009 From: vapier at busybox.net (vapier at busybox.net) Date: Thu, 2 Apr 2009 09:18:34 +0000 (UTC) Subject: svn commit: [25927] trunk/busybox/shell/ash_test: ash-alias ash-arith ash-heredoc ash-inv etc... Message-ID: <20090402091834.37C1877673@busybox.osuosl.org> Author: vapier Date: 2009-04-02 09:18:33 +0000 (Thu, 02 Apr 2009) New Revision: 25927 Log: set svn:ignore Modified: trunk/busybox/shell/ash_test/ trunk/busybox/shell/ash_test/ash-alias/ trunk/busybox/shell/ash_test/ash-arith/ trunk/busybox/shell/ash_test/ash-heredoc/ trunk/busybox/shell/ash_test/ash-invert/ trunk/busybox/shell/ash_test/ash-misc/ trunk/busybox/shell/ash_test/ash-quoting/ trunk/busybox/shell/ash_test/ash-read/ trunk/busybox/shell/ash_test/ash-redir/ trunk/busybox/shell/ash_test/ash-signals/ trunk/busybox/shell/ash_test/ash-standalone/ trunk/busybox/shell/ash_test/ash-vars/ Changeset: Property changes on: trunk/busybox/shell/ash_test ___________________________________________________________________ Added: svn:ignore + ash *.fail Property changes on: trunk/busybox/shell/ash_test/ash-alias ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-arith ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-heredoc ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-invert ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-misc ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-quoting ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-read ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-redir ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-signals ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-standalone ___________________________________________________________________ Added: svn:ignore + *.xx Property changes on: trunk/busybox/shell/ash_test/ash-vars ___________________________________________________________________ Added: svn:ignore + *.xx From vapier at busybox.net Thu Apr 2 10:02:38 2009 From: vapier at busybox.net (vapier at busybox.net) Date: Thu, 2 Apr 2009 10:02:38 +0000 (UTC) Subject: svn commit: [25928] trunk/busybox/shell Message-ID: <20090402100238.4C66077673@busybox.osuosl.org> Author: vapier Date: 2009-04-02 10:02:37 +0000 (Thu, 02 Apr 2009) New Revision: 25928 Log: split math code out of ash and into a standalone library so we can use it in any shell (like hush!) Added: trunk/busybox/shell/math.c trunk/busybox/shell/math.h Modified: trunk/busybox/shell/Config.in trunk/busybox/shell/Kbuild trunk/busybox/shell/ash.c trunk/busybox/shell/hush.c Changeset: Sorry, the patch is too large to include (2029 lines). Please use ViewCVS to see it! http://busybox.net/cgi-bin/viewcvs.cgi?view=rev&root=svn&rev=25928 From vda at busybox.net Thu Apr 2 12:57:38 2009 From: vda at busybox.net (vda at busybox.net) Date: Thu, 2 Apr 2009 12:57:38 +0000 (UTC) Subject: svn commit: [25929] trunk/busybox/shell Message-ID: <20090402125738.AEF1277673@busybox.osuosl.org> Author: vda Date: 2009-04-02 12:57:38 +0000 (Thu, 02 Apr 2009) New Revision: 25929 Log: fix ash-alias/alias.tests failure Modified: trunk/busybox/shell/ash.c Changeset: Modified: trunk/busybox/shell/ash.c =================================================================== --- trunk/busybox/shell/ash.c 2009-04-02 10:02:37 UTC (rev 25928) +++ trunk/busybox/shell/ash.c 2009-04-02 12:57:38 UTC (rev 25929) @@ -354,39 +354,25 @@ } while (0) #endif -#if ENABLE_ASH_OPTIMIZE_FOR_SIZE -static void +static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void int_on(void) { + xbarrier(); if (--suppressint == 0 && intpending) { raise_interrupt(); } } #define INT_ON int_on() -static void +static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void force_int_on(void) { + xbarrier(); suppressint = 0; if (intpending) raise_interrupt(); } #define FORCE_INT_ON force_int_on() -#else /* !ASH_OPTIMIZE_FOR_SIZE */ - -#define INT_ON do { \ - xbarrier(); \ - if (--suppressint == 0 && intpending) \ - raise_interrupt(); \ -} while (0) -#define FORCE_INT_ON do { \ - xbarrier(); \ - suppressint = 0; \ - if (intpending) \ - raise_interrupt(); \ -} while (0) -#endif /* !ASH_OPTIMIZE_FOR_SIZE */ - #define SAVE_INT(v) ((v) = suppressint) #define RESTORE_INT(v) do { \ @@ -2700,23 +2686,26 @@ const char *s; int indx; - if (c == PEOF) /* 2^8+2 */ + if (c == PEOF) { /* 2^8+2 */ return CENDFILE; + } #if ENABLE_ASH_ALIAS - if (c == PEOA) /* 2^8+1 */ + if (c == PEOA) { /* 2^8+1 */ indx = 0; - else + } else #endif - - if ((unsigned char)c >= (unsigned char)(CTLESC) - && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) - ) { - return CCTL; + { + if ((unsigned char)c >= (unsigned char)(CTLESC) + && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) + ) { + return CCTL; + } + s = strchrnul(spec_symbls, c); + if (*s == '\0') { + return CWORD; + } + indx = syntax_index_table[s - spec_symbls]; } - s = strchrnul(spec_symbls, c); - if (*s == '\0') - return CWORD; - indx = syntax_index_table[s - spec_symbls]; return S_I_T[indx][syntax]; } @@ -3019,7 +3008,7 @@ /* 257 127 */ CWORD_CWORD_CWORD_CWORD, }; -#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]) +#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[(int)(c) + SYNBASE]][syntax]) #endif /* USE_SIT_FUNCTION */ From vda at busybox.net Thu Apr 2 13:46:28 2009 From: vda at busybox.net (vda at busybox.net) Date: Thu, 2 Apr 2009 13:46:28 +0000 (UTC) Subject: svn commit: [25930] trunk/busybox/shell Message-ID: <20090402134628.68A017767A@busybox.osuosl.org> Author: vda Date: 2009-04-02 13:46:27 +0000 (Thu, 02 Apr 2009) New Revision: 25930 Log: shells: do not need to have math state global function old new delta ash_arith - 143 +143 expand_variables 2102 2124 +22 popstring 134 140 +6 parse_command 1460 1463 +3 trapcmd 236 238 +2 changepath 197 196 -1 raise_interrupt 86 83 -3 hush_main 1012 991 -21 ash_main 1388 1364 -24 arith_set_local_var 73 34 -39 dash_arith 117 - -117 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 4/5 up/down: 176/-205) Total: -29 bytes Modified: trunk/busybox/shell/ash.c trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/ash.c =================================================================== --- trunk/busybox/shell/ash.c 2009-04-02 12:57:38 UTC (rev 25929) +++ trunk/busybox/shell/ash.c 2009-04-02 13:46:27 UTC (rev 25930) @@ -185,10 +185,6 @@ #define debug optlist[15] #endif -#if ENABLE_SH_MATH_SUPPORT - arith_eval_hooks_t math_hooks; -#endif - /* trap handler commands */ /* * Sigmode records the current value of the signal handlers for the various @@ -238,7 +234,6 @@ #define random_LCG (G_misc.random_LCG ) #define backgndpid (G_misc.backgndpid ) #define job_warning (G_misc.job_warning) -#define math_hooks (G_misc.math_hooks ) #define INIT_G_misc() do { \ (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ barrier(); \ @@ -1103,6 +1098,14 @@ va_end(ap); } +static void raise_error_syntax(const char *) NORETURN; +static void +raise_error_syntax(const char *msg) +{ + ash_msg_and_raise_error("syntax error: %s", msg); + /* NOTREACHED */ +} + static void ash_msg_and_raise(int, const char *, ...) NORETURN; static void ash_msg_and_raise(int cond, const char *msg, ...) @@ -5241,7 +5244,32 @@ */ #if ENABLE_SH_MATH_SUPPORT -static arith_t dash_arith(const char *); +static arith_t +ash_arith(const char *s) +{ + arith_eval_hooks_t math_hooks; + arith_t result; + int errcode = 0; + + math_hooks.lookupvar = lookupvar; + math_hooks.setvar = setvar; + math_hooks.endofname = endofname; + + INT_OFF; + result = arith(s, &errcode, &math_hooks); + if (errcode < 0) { + if (errcode == -3) + ash_msg_and_raise_error("exponent less than 0"); + if (errcode == -2) + ash_msg_and_raise_error("divide by zero"); + if (errcode == -5) + ash_msg_and_raise_error("expression recursion loop detected"); + raise_error_syntax(s); + } + INT_ON; + + return result; +} #endif /* @@ -5720,7 +5748,7 @@ if (quotes) rmescapes(p + 2); - len = cvtnum(dash_arith(p + 2)); + len = cvtnum(ash_arith(p + 2)); if (flag != '"') recordregion(begoff, begoff + len, 0); @@ -10127,14 +10155,6 @@ */ #define NEOF ((union node *)&tokpushback) -static void raise_error_syntax(const char *) NORETURN; -static void -raise_error_syntax(const char *msg) -{ - ash_msg_and_raise_error("syntax error: %s", msg); - /* NOTREACHED */ -} - /* * 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 @@ -12353,33 +12373,11 @@ } #if ENABLE_SH_MATH_SUPPORT -static arith_t -dash_arith(const char *s) -{ - arith_t result; - int errcode = 0; - - INT_OFF; - result = arith(s, &errcode, &math_hooks); - if (errcode < 0) { - if (errcode == -3) - ash_msg_and_raise_error("exponent less than 0"); - if (errcode == -2) - ash_msg_and_raise_error("divide by zero"); - if (errcode == -5) - ash_msg_and_raise_error("expression recursion loop detected"); - raise_error_syntax(s); - } - INT_ON; - - return result; -} - /* - * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. - * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. + * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. + * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. * - * Copyright (C) 2003 Vladimir Oleynik + * Copyright (C) 2003 Vladimir Oleynik */ static int letcmd(int argc UNUSED_PARAM, char **argv) @@ -12390,7 +12388,7 @@ if (!*argv) ash_msg_and_raise_error("expression expected"); do { - i = dash_arith(*argv); + i = ash_arith(*argv); } while (*++argv); return !i; @@ -13119,11 +13117,6 @@ INIT_G_alias(); #endif INIT_G_cmdtable(); -#if ENABLE_SH_MATH_SUPPORT - math_hooks.lookupvar = lookupvar; - math_hooks.setvar = setvar; - math_hooks.endofname = endofname; -#endif #if PROFILE monitor(4, etext, profile_buf, sizeof(profile_buf), 50); Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 12:57:38 UTC (rev 25929) +++ trunk/busybox/shell/hush.c 2009-04-02 13:46:27 UTC (rev 25930) @@ -454,9 +454,6 @@ #if ENABLE_FEATURE_EDITING line_input_t *line_input_state; #endif -#if ENABLE_SH_MATH_SUPPORT - arith_eval_hooks_t hooks; -#endif pid_t root_pid; pid_t last_bg_pid; #if ENABLE_HUSH_JOB @@ -1189,12 +1186,12 @@ static void arith_set_local_var(const char *name, const char *val, int flags) { /* arith code doesnt malloc space, so do it for it */ - char *var = xmalloc(strlen(name) + 1 + strlen(val) + 1); - sprintf(var, "%s=%s", name, val); + char *var = xasprintf("%s=%s", name, val); set_local_var(var, flags); } #endif + /* * in_str support */ @@ -1807,20 +1804,26 @@ #endif #if ENABLE_SH_MATH_SUPPORT case '+': { /* (cmd */ + arith_eval_hooks_t hooks; arith_t res; char buf[30]; int errcode; + *p = '\0'; ++arg; debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); - res = arith(arg, &errcode, &G.hooks); - if (errcode < 0) + hooks.lookupvar = lookup_param; + hooks.setvar = arith_set_local_var; + hooks.endofname = endofname; + res = arith(arg, &errcode, &hooks); + if (errcode < 0) { switch (errcode) { case -3: maybe_die("arith", "exponent less than 0"); break; case -2: maybe_die("arith", "divide by zero"); break; case -5: maybe_die("arith", "expression recursion loop detected"); break; - default: maybe_die("arith", "syntax error"); + default: maybe_die("arith", "syntax error"); break; } + } sprintf(buf, arith_t_fmt, res); o_addstrauto(output, buf); debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); @@ -4601,11 +4604,6 @@ #if ENABLE_FEATURE_EDITING G.line_input_state = new_line_input_t(FOR_SHELL); #endif -#if ENABLE_SH_MATH_SUPPORT - G.hooks.lookupvar = lookup_param; - G.hooks.setvar = arith_set_local_var; - G.hooks.endofname = endofname; -#endif /* XXX what should these be while sourcing /etc/profile? */ G.global_argc = argc; G.global_argv = argv; From vda at busybox.net Thu Apr 2 16:31:30 2009 From: vda at busybox.net (vda at busybox.net) Date: Thu, 2 Apr 2009 16:31:30 +0000 (UTC) Subject: svn commit: [25931] trunk/busybox/shell Message-ID: <20090402163130.56A3A77674@busybox.osuosl.org> Author: vda Date: 2009-04-02 16:31:29 +0000 (Thu, 02 Apr 2009) New Revision: 25931 Log: hush: make a=55; echo $(($a + 1)) $((1 + $((2)) + `echo $a`)) work as expected function old new delta handle_dollar - 667 +667 parse_stream_dquoted - 316 +316 expand_variables 2124 2272 +148 is_assignment 134 215 +81 parse_stream 2038 1240 -798 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 2/1 up/down: 1212/-798) Total: 414 bytes Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 13:46:27 UTC (rev 25930) +++ trunk/busybox/shell/hush.c 2009-04-02 16:31:29 UTC (rev 25931) @@ -1510,7 +1510,7 @@ } if (n) { const char *p = o->data + (int)list[n - 1] + string_start; - fprintf(stderr, " total_sz:%ld\n", (p + strlen(p) + 1) - o->data); + fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); } } #else @@ -1644,6 +1644,14 @@ } +/* Expansion can recurse */ +#if ENABLE_HUSH_TICK +static int process_command_subs(o_string *dest, + struct in_str *input, const char *subst_end); +#endif +static char *expand_string_to_string(const char *str); +static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); + /* expand_strvec_to_strvec() takes a list of strings, expands * all variable references within and returns a pointer to * a list of expanded strings, possibly with larger number @@ -1678,11 +1686,6 @@ return n; } -#if ENABLE_HUSH_TICK -static int process_command_subs(o_string *dest, - struct in_str *input, const char *subst_end); -#endif - /* Expand all variable references in given string, adding words to list[] * at n, n+1,... positions. Return updated n (so that list[n] is next one * to be filled). This routine is extremely tricky: has to deal with @@ -1710,6 +1713,9 @@ #if ENABLE_HUSH_TICK o_string subst_result = NULL_O_STRING; #endif +#if ENABLE_SH_MATH_SUPPORT + char arith_buf[sizeof(arith_t)*3 + 2]; +#endif o_addstr(output, arg, p - arg); debug_print_list("expand_vars_to_list[1]", output, n); arg = ++p; @@ -1720,6 +1726,7 @@ * expand to nothing (not even an empty string) */ if ((first_ch & 0x7f) != '@') ored_ch |= first_ch; + val = NULL; switch (first_ch & 0x7f) { /* Highest bit in first_ch indicates that var is double-quoted */ @@ -1803,19 +1810,52 @@ } #endif #if ENABLE_SH_MATH_SUPPORT - case '+': { /* (cmd */ + case '+': { /* +cmd */ arith_eval_hooks_t hooks; arith_t res; - char buf[30]; int errcode; + char *exp_str; - *p = '\0'; - ++arg; + arg++; /* skip '+' */ + *p = '\0'; /* replace trailing */ debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); + + /* Optional: skip expansion if expr is simple ("a + 3", "i++" etc) */ + exp_str = arg; + while (1) { + unsigned char c = *exp_str++; + if (c == '\0') { + exp_str = NULL; + goto skip_expand; + } + if (isdigit(c)) + continue; + if (strchr(" \t+-*/%_", c) != NULL) + continue; + c |= 0x20; /* tolower */ + if (c >= 'a' && c <= 'z') + continue; + break; + } + /* We need to expand. Example: "echo $(($a + 1)) $((1 + $((2)) ))" */ + { + struct in_str input; + o_string dest = NULL_O_STRING; + + setup_string_in_str(&input, arg); + parse_stream_dquoted(&dest, &input, EOF); + //bb_error_msg("'%s' -> '%s'", arg, dest.data); + exp_str = expand_string_to_string(dest.data); + //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); + o_free(&dest); + } + skip_expand: hooks.lookupvar = lookup_param; hooks.setvar = arith_set_local_var; hooks.endofname = endofname; - res = arith(arg, &errcode, &hooks); + res = arith(exp_str ? exp_str : arg, &errcode, &hooks); + free(exp_str); + if (errcode < 0) { switch (errcode) { case -3: maybe_die("arith", "exponent less than 0"); break; @@ -1824,9 +1864,9 @@ default: maybe_die("arith", "syntax error"); break; } } - sprintf(buf, arith_t_fmt, res); - o_addstrauto(output, buf); debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); + sprintf(arith_buf, arith_t_fmt, res); + val = arith_buf; break; } #endif @@ -1918,13 +1958,14 @@ } else { /* quoted $VAR, val will be appended below */ debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); } - } - } + } /* default: */ + } /* switch (char after ) */ + if (val) { o_addQstr(output, val, strlen(val)); } /* Do the check to avoid writing to a const string */ - if (p && *p != SPECIAL_VAR_SYMBOL) + if (*p != SPECIAL_VAR_SYMBOL) *p = SPECIAL_VAR_SYMBOL; #if ENABLE_HUSH_TICK @@ -3756,11 +3797,11 @@ } debug_printf("done reading from pipe, pclose()ing\n"); - /* This is the step that waits for the child. Should be pretty - * safe, since we just read an EOF from its stdout. We could try - * to do better, by using waitpid, and keeping track of background jobs - * at the same time. That would be a lot of work, and contrary - * to the KISS philosophy of this program. */ + /* Note: we got EOF, and we just close the read end of the pipe. + * We do not wait for the `cmd` child to terminate. bash and ash do. + * Try this: + * echo `echo Hi; exec 1>&-; sleep 2` + */ retcode = fclose(p); free_pipe_list(inner.list_head, /* indent: */ 0); debug_printf("closed FILE from child, retcode=%d\n", retcode); @@ -4056,7 +4097,7 @@ if (i_peek(input) == '(') { i_getch(input); o_addchr(dest, SPECIAL_VAR_SYMBOL); - o_addchr(dest, quote_mask | '+'); + o_addchr(dest, /*quote_mask |*/ '+'); add_till_closing_paren(dest, input, true); o_addchr(dest, SPECIAL_VAR_SYMBOL); break; @@ -4093,6 +4134,86 @@ return 0; } +static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end) +{ + int ch, m; + int next; + + again: + ch = i_getch(input); + if (ch == dquote_end) { /* may be only '"' or EOF */ + dest->nonnull = 1; + if (dest->o_assignment == NOT_ASSIGNMENT) + dest->o_quote ^= 1; + debug_printf_parse("parse_stream_dquoted return 0\n"); + return 0; + } + if (ch == EOF) { + syntax("unterminated \""); + debug_printf_parse("parse_stream_dquoted return 1: unterminated \"\n"); + return 1; + } + next = '\0'; + m = G.charmap[ch]; + if (ch != '\n') { + next = i_peek(input); + } + debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", + ch, ch, m, dest->o_quote); + if (m != CHAR_SPECIAL) { + o_addQchr(dest, ch); + if ((dest->o_assignment == MAYBE_ASSIGNMENT + || dest->o_assignment == WORD_IS_KEYWORD) + && ch == '=' + && is_assignment(dest->data) + ) { + dest->o_assignment = DEFINITELY_ASSIGNMENT; + } + goto again; + } + if (ch == '\\') { + if (next == EOF) { + syntax("\\"); + debug_printf_parse("parse_stream_dquoted return 1: \\\n"); + return 1; + } + /* bash: + * "The backslash retains its special meaning [in "..."] + * only when followed by one of the following characters: + * $, `, ", \, or . A double quote may be quoted + * within double quotes by preceding it with a backslash. + * If enabled, history expansion will be performed unless + * an ! appearing in double quotes is escaped using + * a backslash. The backslash preceding the ! is not removed." + */ + if (strchr("$`\"\\", next) != NULL) { + o_addqchr(dest, i_getch(input)); + } else { + o_addqchr(dest, '\\'); + } + goto again; + } + if (ch == '$') { + if (handle_dollar(dest, input) != 0) { + debug_printf_parse("parse_stream_dquoted return 1: handle_dollar returned non-0\n"); + return 1; + } + goto again; + } +#if ENABLE_HUSH_TICK + if (ch == '`') { + //int pos = dest->length; + o_addchr(dest, SPECIAL_VAR_SYMBOL); + o_addchr(dest, 0x80 | '`'); + add_till_backquote(dest, input); + o_addchr(dest, SPECIAL_VAR_SYMBOL); + //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); + /* fall through */ + } +#endif + goto again; +} + /* Scan input, call done_word() whenever full IFS delimited word was seen. * Call done_pipe if '\n' was seen (and end_trigger != NULL). * Return code is 0 if end_trigger char is met, @@ -4104,7 +4225,7 @@ int ch, m; int redir_fd; redir_type redir_style; - int shadow_quote = dest->o_quote; + int is_in_dquote; int next; /* Only double-quote state is handled in the state variable dest->o_quote. @@ -4113,7 +4234,14 @@ debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); + is_in_dquote = dest->o_quote; while (1) { + if (is_in_dquote) { + if (parse_stream_dquoted(dest, input, '"')) + return 1; /* propagate parse error */ + /* If we're here, we reached closing '"' */ + is_in_dquote = 0; + } m = CHAR_IFS; next = '\0'; ch = i_getch(input); @@ -4125,14 +4253,7 @@ } debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", ch, ch, m, dest->o_quote); - if (m == CHAR_ORDINARY - || (m != CHAR_SPECIAL && shadow_quote) - ) { - if (ch == EOF) { - syntax("unterminated \""); - debug_printf_parse("parse_stream return 1: unterminated \"\n"); - return 1; - } + if (m == CHAR_ORDINARY) { o_addQchr(dest, ch); if ((dest->o_assignment == MAYBE_ASSIGNMENT || dest->o_assignment == WORD_IS_KEYWORD) @@ -4143,6 +4264,8 @@ } continue; } + /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) + */ if (m == CHAR_IFS) { if (done_word(dest, ctx)) { debug_printf_parse("parse_stream return 1: done_word!=0\n"); @@ -4152,7 +4275,7 @@ break; /* If we aren't performing a substitution, treat * a newline as a command separator. - * [why we don't handle it exactly like ';'? --vda] */ + * [why don't we handle it exactly like ';'? --vda] */ if (end_trigger && ch == '\n') { #if ENABLE_HUSH_CASE /* "case ... in word) ..." - @@ -4168,7 +4291,7 @@ } } if (end_trigger) { - if (!shadow_quote && strchr(end_trigger, ch)) { + if (strchr(end_trigger, ch)) { /* Special case: (...word) makes last word terminate, * as if ';' is seen */ if (ch == ')') { @@ -4188,15 +4311,17 @@ if (m == CHAR_IFS) continue; + /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */ + if (dest->o_assignment == MAYBE_ASSIGNMENT) { /* ch is a special char and thus this word - * cannot be an assignment: */ + * cannot be an assignment */ dest->o_assignment = NOT_ASSIGNMENT; } switch (ch) { case '#': - if (dest->length == 0 && !shadow_quote) { + if (dest->length == 0) { while (1) { ch = i_peek(input); if (ch == EOF || ch == '\n') @@ -4213,25 +4338,8 @@ debug_printf_parse("parse_stream return 1: \\\n"); return 1; } - /* bash: - * "The backslash retains its special meaning [in "..."] - * only when followed by one of the following characters: - * $, `, ", \, or . A double quote may be quoted - * within double quotes by preceding it with a backslash. - * If enabled, history expansion will be performed unless - * an ! appearing in double quotes is escaped using - * a backslash. The backslash preceding the ! is not removed." - */ - if (shadow_quote) { //NOT SURE dest->o_quote) { - if (strchr("$`\"\\", next) != NULL) { - o_addqchr(dest, i_getch(input)); - } else { - o_addqchr(dest, '\\'); - } - } else { - o_addchr(dest, '\\'); - o_addchr(dest, i_getch(input)); - } + o_addchr(dest, '\\'); + o_addchr(dest, i_getch(input)); break; case '$': if (handle_dollar(dest, input) != 0) { @@ -4258,7 +4366,7 @@ break; case '"': dest->nonnull = 1; - shadow_quote ^= 1; /* invert */ + is_in_dquote ^= 1; /* invert */ if (dest->o_assignment == NOT_ASSIGNMENT) dest->o_quote ^= 1; break; @@ -4266,7 +4374,7 @@ case '`': { //int pos = dest->length; o_addchr(dest, SPECIAL_VAR_SYMBOL); - o_addchr(dest, shadow_quote /*or dest->o_quote??*/ ? 0x80 | '`' : '`'); + o_addchr(dest, '`'); add_till_backquote(dest, input); o_addchr(dest, SPECIAL_VAR_SYMBOL); //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); From vda at busybox.net Thu Apr 2 16:55:38 2009 From: vda at busybox.net (vda at busybox.net) Date: Thu, 2 Apr 2009 16:55:38 +0000 (UTC) Subject: svn commit: [25932] trunk/busybox/shell Message-ID: <20090402165538.ADEEF77674@busybox.osuosl.org> Author: vda Date: 2009-04-02 16:55:38 +0000 (Thu, 02 Apr 2009) New Revision: 25932 Log: hush: do not inadvertently parse $((1 + "22")) as ok. -20 bytes code size Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 16:31:29 UTC (rev 25931) +++ trunk/busybox/shell/hush.c 2009-04-02 16:55:38 UTC (rev 25932) @@ -432,7 +432,7 @@ CHAR_ORDINARY = 0, CHAR_ORDINARY_IF_QUOTED = 1, /* example: *, # */ CHAR_IFS = 2, /* treated as ordinary if quoted */ - CHAR_SPECIAL = 3, /* example: $ */ + CHAR_SPECIAL = 3, /* \, $, ", maybe ` */ }; enum { @@ -4160,17 +4160,7 @@ } debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", ch, ch, m, dest->o_quote); - if (m != CHAR_SPECIAL) { - o_addQchr(dest, ch); - if ((dest->o_assignment == MAYBE_ASSIGNMENT - || dest->o_assignment == WORD_IS_KEYWORD) - && ch == '=' - && is_assignment(dest->data) - ) { - dest->o_assignment = DEFINITELY_ASSIGNMENT; - } - goto again; - } + /* Basically, checking every CHAR_SPECIAL char except '"' */ if (ch == '\\') { if (next == EOF) { syntax("\\"); @@ -4208,9 +4198,17 @@ add_till_backquote(dest, input); o_addchr(dest, SPECIAL_VAR_SYMBOL); //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); - /* fall through */ + goto again; } #endif + o_addQchr(dest, ch); + if (ch == '=' + && (dest->o_assignment == MAYBE_ASSIGNMENT + || dest->o_assignment == WORD_IS_KEYWORD) + && is_assignment(dest->data) + ) { + dest->o_assignment = DEFINITELY_ASSIGNMENT; + } goto again; } From vapier at busybox.net Thu Apr 2 17:06:35 2009 From: vapier at busybox.net (vapier at busybox.net) Date: Thu, 2 Apr 2009 17:06:35 +0000 (UTC) Subject: svn commit: [25933] trunk/busybox/shell Message-ID: <20090402170636.0A8E677674@busybox.osuosl.org> Author: vapier Date: 2009-04-02 17:06:35 +0000 (Thu, 02 Apr 2009) New Revision: 25933 Log: Arithmetic Expansion is supported now in hush, so drop from TODO Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 16:55:38 UTC (rev 25932) +++ trunk/busybox/shell/hush.c 2009-04-02 17:06:35 UTC (rev 25933) @@ -38,7 +38,6 @@ * * POSIX syntax not implemented: * aliases - * Arithmetic Expansion * <(list) and >(list) Process Substitution * Here Documents ( << word ) * Functions From vda at busybox.net Thu Apr 2 20:17:50 2009 From: vda at busybox.net (vda at busybox.net) Date: Thu, 2 Apr 2009 20:17:50 +0000 (UTC) Subject: svn commit: [25934] trunk/busybox/shell: hush_test hush_test/hush-arith Message-ID: <20090402201750.3C3E976399@busybox.osuosl.org> Author: vda Date: 2009-04-02 20:17:49 +0000 (Thu, 02 Apr 2009) New Revision: 25934 Log: hush: rename ->o_quote to ->o_escape hush_test/hush-arith/*: new tests for arithmetic evaluation Added: trunk/busybox/shell/hush_test/hush-arith/ trunk/busybox/shell/hush_test/hush-arith/arith.right trunk/busybox/shell/hush_test/hush-arith/arith.tests trunk/busybox/shell/hush_test/hush-arith/arith1.sub trunk/busybox/shell/hush_test/hush-arith/arith2.sub Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 17:06:35 UTC (rev 25933) +++ trunk/busybox/shell/hush.c 2009-04-02 20:17:49 UTC (rev 25934) @@ -392,9 +392,9 @@ char *data; int length; /* position where data is appended */ int maxlen; - /* Misnomer! it's not "quoting", it's "protection against globbing"! - * (by prepending \ to *, ?, [ and to \ too) */ - smallint o_quote; + /* Protect newly added chars against globbing + * (by prepending \ to *, ?, [, \) */ + smallint o_escape; smallint o_glob; smallint nonnull; smallint has_empty_slot; @@ -1440,7 +1440,7 @@ static void o_addQchr(o_string *o, int ch) { int sz = 1; - if (o->o_quote && strchr("*?[\\", ch)) { + if (o->o_escape && strchr("*?[\\", ch)) { sz++; o->data[o->length] = '\\'; o->length++; @@ -1453,7 +1453,7 @@ static void o_addQstr(o_string *o, const char *str, int len) { - if (!o->o_quote) { + if (!o->o_escape) { o_addstr(o, str, len); return; } @@ -1668,7 +1668,7 @@ while (1) { int word_len = strcspn(str, G.ifs); if (word_len) { - if (output->o_quote || !output->o_glob) + if (output->o_escape || !output->o_glob) o_addQstr(output, str, word_len); else /* protect backslashes against globbing up :) */ o_addstr_duplicate_backslash(output, str, word_len); @@ -1751,9 +1751,9 @@ break; ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ - smallint sv = output->o_quote; - /* unquoted var's contents should be globbed, so don't quote */ - output->o_quote = 0; + smallint sv = output->o_escape; + /* unquoted var's contents should be globbed, so don't escape */ + output->o_escape = 0; while (G.global_argv[i]) { n = expand_on_ifs(output, n, G.global_argv[i]); debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); @@ -1766,7 +1766,7 @@ debug_print_list("expand_vars_to_list[3]", output, n); } } - output->o_quote = sv; + output->o_escape = sv; } else /* If or_mask is nonzero, we handle assignment 'a=....$@.....' * and in this case should treat it like '$*' - see 'else...' below */ @@ -1945,17 +1945,17 @@ store_val: #endif if (!(first_ch & 0x80)) { /* unquoted $VAR */ - debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote); + debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, output->o_escape); if (val) { - /* unquoted var's contents should be globbed, so don't quote */ - smallint sv = output->o_quote; - output->o_quote = 0; + /* unquoted var's contents should be globbed, so don't escape */ + smallint sv = output->o_escape; + output->o_escape = 0; n = expand_on_ifs(output, n, val); val = NULL; - output->o_quote = sv; + output->o_escape = sv; } } else { /* quoted $VAR, val will be appended below */ - debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); + debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, output->o_escape); } } /* default: */ } /* switch (char after ) */ @@ -1999,7 +1999,7 @@ o_string output = NULL_O_STRING; if (or_mask & 0x100) { - output.o_quote = 1; /* protect against globbing for "$var" */ + output.o_escape = 1; /* protect against globbing for "$var" */ /* (unquoted $var will temporarily switch it off) */ output.o_glob = 1; } @@ -3979,7 +3979,7 @@ { int expansion; int ch = i_peek(input); /* first character after the $ */ - unsigned char quote_mask = dest->o_quote ? 0x80 : 0; + unsigned char quote_mask = dest->o_escape ? 0x80 : 0; debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); if (isalpha(ch)) { @@ -4143,7 +4143,7 @@ if (ch == dquote_end) { /* may be only '"' or EOF */ dest->nonnull = 1; if (dest->o_assignment == NOT_ASSIGNMENT) - dest->o_quote ^= 1; + dest->o_escape ^= 1; debug_printf_parse("parse_stream_dquoted return 0\n"); return 0; } @@ -4157,8 +4157,8 @@ if (ch != '\n') { next = i_peek(input); } - debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", - ch, ch, m, dest->o_quote); + debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", + ch, ch, m, dest->o_escape); /* Basically, checking every CHAR_SPECIAL char except '"' */ if (ch == '\\') { if (next == EOF) { @@ -4225,13 +4225,13 @@ int is_in_dquote; int next; - /* Only double-quote state is handled in the state variable dest->o_quote. + /* Double-quote state is handled in the state variable is_in_dquote. * A single-quote triggers a bypass of the main loop until its mate is - * found. When recursing, quote state is passed in via dest->o_quote. */ + * found. When recursing, quote state is passed in via dest->o_escape. */ debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); - is_in_dquote = dest->o_quote; + is_in_dquote = dest->o_escape; while (1) { if (is_in_dquote) { if (parse_stream_dquoted(dest, input, '"')) @@ -4248,8 +4248,8 @@ next = i_peek(input); } } - debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", - ch, ch, m, dest->o_quote); + debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", + ch, ch, m, dest->o_escape); if (m == CHAR_ORDINARY) { o_addQchr(dest, ch); if ((dest->o_assignment == MAYBE_ASSIGNMENT @@ -4365,7 +4365,7 @@ dest->nonnull = 1; is_in_dquote ^= 1; /* invert */ if (dest->o_assignment == NOT_ASSIGNMENT) - dest->o_quote ^= 1; + dest->o_escape ^= 1; break; #if ENABLE_HUSH_TICK case '`': { @@ -4594,7 +4594,7 @@ } #endif /*temp.nonnull = 0; - o_free does it below */ - /*temp.o_quote = 0; - o_free does it below */ + /*temp.o_escape = 0; - o_free does it below */ free_pipe_list(ctx.list_head, /* indent: */ 0); /* Discard all unprocessed line input, force prompt on */ inp->p = NULL; Added: trunk/busybox/shell/hush_test/hush-arith/arith.right =================================================================== --- trunk/busybox/shell/hush_test/hush-arith/arith.right (rev 0) +++ trunk/busybox/shell/hush_test/hush-arith/arith.right 2009-04-02 20:17:49 UTC (rev 25934) @@ -0,0 +1,138 @@ +Format: 'expected actual' +163 163 +4 4 +16 16 +8 8 +2 2 +4 4 +2 2 +2 2 +1 1 +0 0 +0 0 +0 0 +1 1 +1 1 +2 2 +-3 -3 +-2 -2 +1 1 +0 0 +2 2 +131072 131072 +29 29 +33 33 +49 49 +1 1 +1 1 +0 0 +0 0 +1 1 +1 1 +1 1 +2 2 +3 3 +1 1 +58 58 +2 2 +60 60 +1 1 +256 256 +16 16 +62 62 +4 4 +29 29 +5 5 +-4 -4 +4 4 +1 1 +32 32 +32 32 +1 1 +1 1 +32 32 +20 20 +30 30 +20 20 +30 30 +hush: arith: syntax error +6 6 +6,5,3 6,5,3 +263 263 +255 255 +40 40 +hush: arith: syntax error +hush: arith: divide by zero +hush: can't exec 'let': No such file or directory +hush: arith: syntax error +hush: can't exec 'let': No such file or directory +abc +def +ghi +hush: arith: syntax error +16 16 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +9 9 +hush: arith: syntax error +hush: arith: syntax error +9 9 +9 9 +9 9 +7 7 +7 +4 4 +32767 32767 +32768 32768 +131072 131072 +2147483647 2147483647 +1 1 +4 4 +4 4 +5 5 +5 5 +4 4 +3 3 +3 3 +4 4 +4 4 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +4 4 +7 7 +-7 -7 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +6 6 +3 3 +7 7 +4 4 +0 0 +3 3 +7 7 +2 2 +-2 -2 +1 1 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +5 5 +1 1 +4 4 +0 0 +hush: arith: syntax error +hush: arith: syntax error +8 12 +hush: arith: syntax error +42 +42 +42 +hush: can't exec 'a[b[c]d]=e': No such file or directory Added: trunk/busybox/shell/hush_test/hush-arith/arith.tests =================================================================== --- trunk/busybox/shell/hush_test/hush-arith/arith.tests (rev 0) +++ trunk/busybox/shell/hush_test/hush-arith/arith.tests 2009-04-02 20:17:49 UTC (rev 25934) @@ -0,0 +1,302 @@ +#ash# set +o posix +#ash# declare -i iv jv + +echo "Format: 'expected actual'" + +iv=$(( 3 + 5 * 32 )) +echo 163 $iv +#ash# iv=iv+3 +#ash# echo 166 $iv +iv=2 +jv=iv + +: $((jv *= 2)) ##hush## let "jv *= 2" +echo 4 $jv +jv=$(( $jv << 2 )) +echo 16 $jv + +: $((jv=$jv / 2)) ##hush## let jv="$jv / 2" +echo 8 $jv +#ash# jv="jv >> 2" +: $((jv=jv >> 2)) ##hush## let jv="jv >> 2" +echo 2 $jv + +iv=$((iv+ $jv)) +echo 4 $iv +echo 2 $((iv -= jv)) +echo 2 $iv +echo 1 $(( iv == jv )) +echo 0 $(( iv != $jv )) +echo 0 $(( iv < jv )) +echo 0 $(( $iv > $jv )) +echo 1 $(( iv <= $jv )) +echo 1 $(( $iv >= jv )) + +echo 2 $jv +echo -3 $(( ~$jv )) +echo -2 $(( ~1 )) +echo 1 $(( ! 0 )) + +echo 0 $(( jv % 2 )) +echo 2 $(( $iv % 4 )) + +echo 131072 $(( iv <<= 16 )) +echo 29 $(( iv %= 33 )) + +echo 33 $(( 33 & 55 )) +echo 49 $(( 33 | 17 )) + +echo 1 $(( iv && $jv )) +echo 1 $(( $iv || jv )) + +echo 0 $(( iv && 0 )) +echo 0 $(( iv & 0 )) +echo 1 $(( iv && 1 )) +echo 1 $(( iv & 1 )) + +echo 1 $(( $jv || 0 )) +echo 2 $(( jv | 0 )) +echo 3 $(( jv | 1 )) +echo 1 $(( $jv || 1 )) + +: $((iv *= jv)) ##hush## let 'iv *= jv' +echo 58 $iv +echo 2 $jv +: $((jv += $iv)) ##hush## let "jv += $iv" +echo 60 $jv + +echo 1 $(( jv /= iv )) +echo 256 $(( jv <<= 8 )) +echo 16 $(( jv >>= 4 )) + +echo 62 $(( iv |= 4 )) +echo 4 $(( iv &= 4 )) + +echo 29 $(( iv += (jv + 9))) +echo 5 $(( (iv + 4) % 7 )) + +# unary plus, minus +echo -4 $(( +4 - 8 )) +echo 4 $(( -4 + 8 )) + +# conditional expressions +echo 1 $(( 4<5 ? 1 : 32)) +echo 32 $(( 4>5 ? 1 : 32)) +echo 32 $(( 4>(2+3) ? 1 : 32)) +echo 1 $(( 4<(2+3) ? 1 : 32)) +echo 1 $(( (2+2)<(2+3) ? 1 : 32)) +echo 32 $(( (2+2)>(2+3) ? 1 : 32)) + +# check that the unevaluated part of the ternary operator does not do +# evaluation or assignment +x=i+=2 +y=j+=2 +#ash# declare -i i=1 j=1 + i=1 + j=1 +echo 20 $((1 ? 20 : (x+=2))) +#ash# echo $i,$x # ash mishandles this +echo 30 $((0 ? (y+=2) : 30)) +#ash# echo $j,$y # ash mishandles this + +x=i+=2 +y=j+=2 +#ash# declare -i i=1 j=1 + i=1 + j=1 +echo 20 $((1 ? 20 : (x+=2))) +#ash# echo $i,$x # ash mishandles this +echo 30 $((0 ? (y+=2) : 30)) +#ash# echo $i,$y # ash mishandles this + +# check precedence of assignment vs. conditional operator +# should be an error +#ash# declare -i x=2 + x=2 +#ashnote# bash reports error but continues, ash aborts - using subshell to 'emulate' bash: +( y=$((1 ? 20 : x+=2)) ) + +# check precedence of assignment vs. conditional operator +#ash# declare -i x=2 + x=2 +# ash says "line NNN: syntax error: 0 ? x+=2 : 20" +#ash# echo 20 $((0 ? x+=2 : 20)) + +# associativity of assignment-operator operator +#ash# declare -i i=1 j=2 k=3 +i=1 +j=2 +k=3 +echo 6 $((i += j += k)) +echo 6,5,3 $i,$j,$k + +# octal, hex +echo 263 $(( 0x100 | 007 )) +echo 255 $(( 0xff )) +#ash# echo 255 $(( 16#ff )) +#ash# echo 127 $(( 16#FF/2 )) +#ash# echo 36 $(( 8#44 )) + +echo 40 $(( 8 ^ 32 )) + +#ash# # other bases +#ash# echo 10 $(( 16#a )) +#ash# echo 10 $(( 32#a )) +#ash# echo 10 $(( 56#a )) +#ash# echo 10 $(( 64#a )) +#ash# +#ash# echo 10 $(( 16#A )) +#ash# echo 10 $(( 32#A )) +#ash# echo 36 $(( 56#A )) +#ash# echo 36 $(( 64#A )) +#ash# +#ash# echo 62 $(( 64#@ )) +#ash# echo 63 $(( 64#_ )) + +#ash# # weird bases (error) +#ash# echo $(( 3425#56 )) + +#ash# # missing number after base +#ash# echo 0 $(( 2# )) + +# these should generate errors +( echo $(( 7 = 43 )) ) +#ash# echo $(( 2#44 )) +( echo $(( 44 / 0 )) ) +( let 'jv += $iv' ) +( echo $(( jv += \$iv )) ) +( let 'rv = 7 + (43 * 6' ) + +#ash# # more errors +#ash# declare -i i +#ash# i=0#4 +#ash# i=2#110#11 + +((echo abc; echo def;); echo ghi) + +#ash# if (((4+4) + (4 + 7))); then +#ash# echo ok +#ash# fi + +#ash# (()) # make sure the null expression works OK + +#ash# a=(0 2 4 6) +#ash# echo 6 $(( a[1] + a[2] )) +#ash# echo 1 $(( (a[1] + a[2]) == a[3] )) +#ash# (( (a[1] + a[2]) == a[3] )) ; echo 0 $? + +# test pushing and popping the expression stack +unset A +A="4 + " +( echo A $(( ( 4 + A ) + 4 )) ) +A="3 + 5" +echo 16 $(( ( 4 + A ) + 4 )) + +# badly-formed conditional expressions +( echo $(( 4 ? : $A )) ) +( echo $(( 1 ? 20 )) ) +( echo $(( 4 ? 20 : )) ) + +# precedence and short-circuit evaluation +B=9 +echo 9 $B + +# error +( echo $(( 0 && B=42 )); echo 9 $B ) + +# error +( echo $(( 1 || B=88 )); echo 9 $B ) + +# ash mistakenly evaluates B=... below +#ash# echo 0 $(( 0 && (B=42) )) +echo 9 $B +#ash# echo 0 $(( (${$} - $$) && (B=42) )) +echo 9 $B +#ash# echo 1 $(( 1 || (B=88) )) +echo 9 $B + + +# until command with (( )) command +x=7 + +echo 7 $x +#ash# until (( x == 4 )) + until test "$x" = 4 +do + echo $x + x=4 +done + +echo 4 $x + +# exponentiation +echo 32767 $(( 2**15 - 1)) +echo 32768 $(( 2**(16-1))) +echo 131072 $(( 2**16*2 )) +echo 2147483647 $(( 2**31-1)) +echo 1 $(( 2**0 )) + +# {pre,post}-{inc,dec}rement and associated errors + +x=4 + +echo 4 $x +echo 4 $(( x++ )) +echo 5 $x +echo 5 $(( x-- )) +echo 4 $x + +echo 3 $(( --x )) +echo 3 $x + +echo 4 $(( ++x )) +echo 4 $x + +# bash 3.2 apparently thinks that ++7 is 7 +#ash# echo 7 $(( ++7 )) +( echo $(( 7-- )) ) + +( echo $(( --x=7 )) ) +( echo $(( ++x=7 )) ) + +( echo $(( x++=7 )) ) +( echo $(( x--=7 )) ) + +echo 4 $x + +echo 7 $(( +7 )) +echo -7 $(( -7 )) + +# bash 3.2 apparently thinks that ++7 is 7 +#ash# echo $(( ++7 )) +#ash# echo $(( --7 )) + +${THIS_SH} ./arith1.sub +${THIS_SH} ./arith2.sub + +x=4 +y=7 + +#ash# (( x=8 , y=12 )) + x=8 + y=12 +echo $x $y + +#ash# # should be an error +#ash# (( x=9 y=41 )) + +# These are errors +unset b +( echo $((a b)) ) +#ash# ((a b)) + +n=42 +printf "%d\n" $n +printf "%i\n" $n +#ash# echo $(( 8#$(printf "%o\n" $n) )) +printf "%u\n" $n +#ash# echo $(( 16#$(printf "%x\n" $n) )) +#ash# echo $(( 16#$(printf "%X\n" $n) )) + +# causes longjmp botches through bash-2.05b +a[b[c]d]=e Property changes on: trunk/busybox/shell/hush_test/hush-arith/arith.tests ___________________________________________________________________ Added: svn:executable + * Added: trunk/busybox/shell/hush_test/hush-arith/arith1.sub =================================================================== --- trunk/busybox/shell/hush_test/hush-arith/arith1.sub (rev 0) +++ trunk/busybox/shell/hush_test/hush-arith/arith1.sub 2009-04-02 20:17:49 UTC (rev 25934) @@ -0,0 +1,40 @@ +# test of redone post-increment and post-decrement code +( echo $(( 4-- )) ) +( echo $(( 4++ )) ) +( echo $(( 4 -- )) ) +( echo $(( 4 ++ )) ) + +#ash# (( array[0]++ )) +#ash# echo ${array} + +#ash# (( array[0] ++ )) +#ash# echo ${array} + +#ash# (( a++ )) +#ash# echo $a +#ash# (( a ++ )) +#ash# echo $a + a=2 + +echo 6 $(( a ++ + 4 )) +echo 3 $a + +echo 7 $(( a+++4 )) +echo 4 $a + +echo 0 $(( a---4 )) +echo 3 $a + +echo 7 $(( a -- + 4 )) +echo 2 $a + +echo -2 $(( a -- - 4 )) +echo 1 $a + +#ash# (( ++ + 7 )) + +#ash# (( ++ )) +( echo $(( +++7 )) ) +# bash 3.2 apparently thinks that ++ +7 is 7 +#ash# echo $(( ++ + 7 )) +#ash# (( -- )) Property changes on: trunk/busybox/shell/hush_test/hush-arith/arith1.sub ___________________________________________________________________ Added: svn:executable + * Added: trunk/busybox/shell/hush_test/hush-arith/arith2.sub =================================================================== --- trunk/busybox/shell/hush_test/hush-arith/arith2.sub (rev 0) +++ trunk/busybox/shell/hush_test/hush-arith/arith2.sub 2009-04-02 20:17:49 UTC (rev 25934) @@ -0,0 +1,57 @@ +# bash 3.2 apparently thinks that ++7 is 7 etc +( echo $(( --7 )) ) +( echo $(( ++7 )) ) +( echo $(( -- 7 )) ) +( echo $(( ++ 7 )) ) + +#ash# ((++array[0] )) +#ash# echo 1 $array +#ash# (( ++ array[0] )) +#ash# echo 2 $array + +#ash# (( ++a )) +#ash# echo 1 $a +#ash# (( ++ a )) +#ash# echo 2 $a + +#ash# (( --a )) +#ash# echo 1 $a +#ash# (( -- a )) +#ash# echo 0 $a + a=0 + +echo 5 $(( 4 + ++a )) +echo 1 $a + +# ash doesn't handle it right... +#ash# echo 6 $(( 4+++a )) +#ash# echo 2 $a + a=2 + +# ash doesn't handle it right... +#ash# echo 3 $(( 4---a )) +#ash# echo 1 $a + a=1 + +echo 4 $(( 4 - -- a )) +echo 0 $a + +#ash# (( -- )) +# bash 3.2 apparently thinks that ---7 is -7 +#ash# echo $(( ---7 )) +( echo $(( -- - 7 )) ) + +#ash# (( ++ )) +# bash 3.2: 7 +#ash# echo 7 $(( ++7 )) +( echo $(( ++ + 7 )) ) + +# bash 3.2: -7 +#ash# echo -7 $(( ++-7 )) +# bash 3.2: -7 +#ash# echo -7 $(( ++ - 7 )) + +# bash 3.2: 7 +#ash# echo 7 $(( +--7 )) +# bash 3.2: 7 +#ash# echo 7 $(( -- + 7 )) Property changes on: trunk/busybox/shell/hush_test/hush-arith/arith2.sub ___________________________________________________________________ Added: svn:executable + * From vapier at busybox.net Thu Apr 2 22:46:53 2009 From: vapier at busybox.net (vapier at busybox.net) Date: Thu, 2 Apr 2009 22:46:53 +0000 (UTC) Subject: svn commit: [25935] trunk/busybox/shell/hush_test Message-ID: <20090402224653.89E2476399@busybox.osuosl.org> Author: vapier Date: 2009-04-02 22:46:52 +0000 (Thu, 02 Apr 2009) New Revision: 25935 Log: trim trailing slashes from specified subdir so we output to the right place Modified: trunk/busybox/shell/hush_test/run-all Changeset: Modified: trunk/busybox/shell/hush_test/run-all =================================================================== --- trunk/busybox/shell/hush_test/run-all 2009-04-02 20:17:49 UTC (rev 25934) +++ trunk/busybox/shell/hush_test/run-all 2009-04-02 22:46:52 UTC (rev 25935) @@ -23,6 +23,7 @@ do_test() { test -d "$1" || return 0 + d=${d%/} # echo Running tests in directory "$1" ( tret=0 From vda at busybox.net Thu Apr 2 22:50:41 2009 From: vda at busybox.net (vda at busybox.net) Date: Thu, 2 Apr 2009 22:50:41 +0000 (UTC) Subject: svn commit: [25936] trunk/busybox/shell Message-ID: <20090402225041.6BDED76399@busybox.osuosl.org> Author: vda Date: 2009-04-02 22:50:40 +0000 (Thu, 02 Apr 2009) New Revision: 25936 Log: hush: straighten parse_stream() API a bit function old new delta parse_stream 1240 1238 -2 expand_variables 2272 2242 -30 parse_and_run_stream 338 292 -46 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-78) Total: -78 bytes Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 22:46:52 UTC (rev 25935) +++ trunk/busybox/shell/hush.c 2009-04-02 22:50:40 UTC (rev 25936) @@ -3765,14 +3765,10 @@ FILE *p; struct in_str pipe_str; - initialize_context(&inner); - /* Recursion to generate command */ retcode = parse_stream(&result, &inner, input, subst_end); if (retcode != 0) return retcode; /* syntax error or EOF */ - done_word(&result, &inner); - done_pipe(&inner, PIPE_SEQ); o_free(&result); p = generate_stream_from_list(inner.list_head); @@ -3812,10 +3808,10 @@ struct in_str *input, int ch) { /* dest contains characters seen prior to ( or {. - * Typically it's empty, but for functions defs, + * Typically it's empty, but for function defs, * it contains function name (without '()'). */ int rcode; - const char *endch = NULL; + const char *endch; struct parse_context sub; struct command *command = ctx->command; @@ -3837,7 +3833,6 @@ debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); return 1; } - initialize_context(&sub); endch = "}"; if (ch == '(') { endch = ")"; @@ -3845,8 +3840,6 @@ } rcode = parse_stream(dest, &sub, input, endch); if (rcode == 0) { - done_word(dest, &sub); /* finish off the final word in the subcontext */ - done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ command->group = sub.list_head; } debug_printf_parse("parse_group return %d\n", rcode); @@ -4211,11 +4204,14 @@ goto again; } -/* Scan input, call done_word() whenever full IFS delimited word was seen. +/* Initalize ctx (i.e. caller does not need to do that). + * Scan input, call done_word() whenever full IFS delimited word was seen. * Call done_pipe if '\n' was seen (and end_trigger != NULL). * Return code is 0 if end_trigger char is met, * -1 on EOF (but if end_trigger == NULL then return 0), - * 1 for syntax error */ + * 1 for syntax error + * Net result is a list of pipes in ctx->list_head. + */ static int parse_stream(o_string *dest, struct parse_context *ctx, struct in_str *input, const char *end_trigger) { @@ -4230,6 +4226,7 @@ * found. When recursing, quote state is passed in via dest->o_escape. */ debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); + initialize_context(ctx); is_in_dquote = dest->o_escape; while (1) { @@ -4269,7 +4266,7 @@ return 1; } if (ch == EOF) - break; + goto ret_EOF; /* If we aren't performing a substitution, treat * a newline as a command separator. * [why don't we handle it exactly like ';'? --vda] */ @@ -4297,11 +4294,14 @@ done_pipe(ctx, PIPE_SEQ); dest->o_assignment = MAYBE_ASSIGNMENT; } + /* What do we check here? */ if (!HAS_KEYWORDS IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) ) { debug_printf_parse("parse_stream return 0: end_trigger char found\n"); - return 0; + /* this makes us return 0, not -1 */ + end_trigger = NULL; + goto ret; } } } @@ -4522,9 +4522,16 @@ bb_error_msg_and_die("BUG: unexpected %c\n", ch); } } /* while (1) */ + + /* Non-error returns */ + ret_EOF: debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); - if (end_trigger) - return -1; + ret: + done_word(dest, ctx); + done_pipe(ctx, PIPE_SEQ); + if (end_trigger) { + return -1; /* EOF found while expecting end_trigger */ + } return 0; } @@ -4564,7 +4571,6 @@ int rcode; do { - initialize_context(&ctx); update_charmap(); #if ENABLE_HUSH_INTERACTIVE inp->promptmode = 0; /* PS1 */ @@ -4574,16 +4580,15 @@ * TEST should be printed */ temp.o_assignment = MAYBE_ASSIGNMENT; rcode = parse_stream(&temp, &ctx, inp, ";\n"); + debug_printf_parse("rcode %d ctx.old_flag %x\n", rcode, ctx.old_flag); #if HAS_KEYWORDS if (rcode != 1 && ctx.old_flag != 0) { syntax(NULL); } #endif if (rcode != 1 IF_HAS_KEYWORDS(&& ctx.old_flag == 0)) { - done_word(&temp, &ctx); - done_pipe(&ctx, PIPE_SEQ); debug_print_tree(ctx.list_head, 0); - debug_printf_exec("parse_stream_outer: run_and_free_list\n"); + debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); run_and_free_list(ctx.list_head); } else { /* We arrive here also if rcode == 1 (error in parse_stream) */ From vda at busybox.net Fri Apr 3 00:07:06 2009 From: vda at busybox.net (vda at busybox.net) Date: Fri, 3 Apr 2009 00:07:06 +0000 (UTC) Subject: svn commit: [25937] trunk/busybox/shell Message-ID: <20090403000706.C973276395@busybox.osuosl.org> Author: vda Date: 2009-04-03 00:07:05 +0000 (Fri, 03 Apr 2009) New Revision: 25937 Log: hush: explain parsing context structure plug leak in setup_redirect on error path function old new delta done_command 84 86 +2 done_word 657 658 +1 done_pipe 105 106 +1 initialize_context 39 38 -1 setup_redirect 219 212 -7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 4/-8) Total: -4 bytes Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-02 22:50:40 UTC (rev 25936) +++ trunk/busybox/shell/hush.c 2009-04-03 00:07:05 UTC (rev 25937) @@ -359,9 +359,13 @@ /* This holds pointers to the various results of parsing */ struct parse_context { - struct command *command; + /* linked list of pipes */ struct pipe *list_head; + /* last pipe (being constructed right now) */ struct pipe *pipe; + /* last command in pipe (being constructed right now) */ + struct command *command; + /* last redirect in command->redirects list */ struct redir_struct *pending_redirect; #if HAS_KEYWORDS smallint ctx_res_w; @@ -369,7 +373,15 @@ #if ENABLE_HUSH_CASE smallint ctx_dsemicolon; /* ";;" seen */ #endif - int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ + /* bitmask of FLAG_xxx, for figuring out valid reserved words */ + int old_flag; + /* group we are enclosed in: + * example 1: "{ { false; ..." + * example 2: "if true; then { false; ..." + * example 3: "if true; then if false; ..." + * when we find closing "}" / "fi" / whatever, we move list_head + * into stack->command->group and delete ourself. + */ struct parse_context *stack; #endif }; @@ -3288,37 +3300,36 @@ * for file descriptor duplication, e.g., "2>&1". * Return code is 0 normally, 1 if a syntax error is detected in src. * Resource errors (in xmalloc) cause the process to exit */ -static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, - struct in_str *input) +static int setup_redirect(struct parse_context *ctx, + int fd, + redir_type style, + struct in_str *input) { struct command *command = ctx->command; - struct redir_struct *redir = command->redirects; - struct redir_struct *last_redir = NULL; + struct redir_struct *redir; + struct redir_struct **redirp; + int dup_num; + /* Check for a '2>&1' type redirect */ + dup_num = redirect_dup_num(input); + if (dup_num == -2) + return 1; /* syntax error */ + /* Create a new redir_struct and drop it onto the end of the linked list */ - while (redir) { - last_redir = redir; - redir = redir->next; + redirp = &command->redirects; + while ((redir = *redirp) != NULL) { + redirp = &(redir->next); } - redir = xzalloc(sizeof(struct redir_struct)); + *redirp = redir = xzalloc(sizeof(*redir)); /* redir->next = NULL; */ /* redir->rd_filename = NULL; */ - if (last_redir) { - last_redir->next = redir; - } else { - command->redirects = redir; - } - redir->rd_type = style; redir->fd = (fd == -1) ? redir_table[style].default_fd : fd; debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); - /* Check for a '2>&1' type redirect */ - redir->dup = redirect_dup_num(input); - if (redir->dup == -2) - return 1; /* syntax error */ - if (redir->dup != -1) { + redir->dup = dup_num; + if (dup_num != -1) { /* Erik had a check here that the file descriptor in question * is legit; I postpone that to "run time" * A "-" representation of "close me" shows up as a -3 here */ From vda at busybox.net Fri Apr 3 03:19:16 2009 From: vda at busybox.net (vda at busybox.net) Date: Fri, 3 Apr 2009 03:19:16 +0000 (UTC) Subject: svn commit: [25938] trunk/busybox/shell: hush_test/hush-vars Message-ID: <20090403031916.8A68B763A1@busybox.osuosl.org> Author: vda Date: 2009-04-03 03:19:15 +0000 (Fri, 03 Apr 2009) New Revision: 25938 Log: hush: fix bug with local environment vars in pipes; simplify parse_stream() function old new delta parse_stream 1238 1218 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Added: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-03 00:07:05 UTC (rev 25937) +++ trunk/busybox/shell/hush.c 2009-04-03 03:19:15 UTC (rev 25938) @@ -1657,8 +1657,7 @@ /* Expansion can recurse */ #if ENABLE_HUSH_TICK -static int process_command_subs(o_string *dest, - struct in_str *input, const char *subst_end); +static int process_command_subs(o_string *dest, struct in_str *input); #endif static char *expand_string_to_string(const char *str); static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); @@ -1814,7 +1813,7 @@ //TODO: can we just stuff it into "output" directly? debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); setup_string_in_str(&input, arg); - process_command_subs(&subst_result, &input, NULL); + process_command_subs(&subst_result, &input); debug_printf_subst("SUBST RES '%s'\n", subst_result.data); val = subst_result.data; goto store_val; @@ -1971,7 +1970,6 @@ } } /* default: */ } /* switch (char after ) */ - if (val) { o_addQstr(output, val, strlen(val)); } @@ -2265,7 +2263,7 @@ if (argv_expanded) { argv = argv_expanded; } else { - argv = expand_strvec_to_strvec(argv); + argv = expand_strvec_to_strvec(argv + assignment_cnt); #if !BB_MMU nommu_save->argv = argv; #endif @@ -3628,7 +3626,6 @@ ctx->ctx_dsemicolon = 0; } else #endif - if (!command->argv /* if it's the first word... */ #if ENABLE_HUSH_LOOPS && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ @@ -3767,8 +3764,7 @@ /* Return code is exit status of the process that is run. */ static int process_command_subs(o_string *dest, - struct in_str *input, - const char *subst_end) + struct in_str *input) { int retcode, ch, eol_cnt; o_string result = NULL_O_STRING; @@ -3777,7 +3773,7 @@ struct in_str pipe_str; /* Recursion to generate command */ - retcode = parse_stream(&result, &inner, input, subst_end); + retcode = parse_stream(&result, &inner, input, NULL); if (retcode != 0) return retcode; /* syntax error or EOF */ o_free(&result); @@ -4236,9 +4232,11 @@ * A single-quote triggers a bypass of the main loop until its mate is * found. When recursing, quote state is passed in via dest->o_escape. */ - debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); - initialize_context(ctx); + debug_printf_parse("parse_stream entered, end_trigger='%s' " + "dest->o_assignment:%d\n", end_trigger, dest->o_assignment); + dest->o_assignment = MAYBE_ASSIGNMENT; + initialize_context(ctx); is_in_dquote = dest->o_escape; while (1) { if (is_in_dquote) { @@ -4269,52 +4267,48 @@ } continue; } - /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) - */ + /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */ if (m == CHAR_IFS) { + if (ch == EOF) + goto ret_EOF; if (done_word(dest, ctx)) { debug_printf_parse("parse_stream return 1: done_word!=0\n"); return 1; } - if (ch == EOF) - goto ret_EOF; - /* If we aren't performing a substitution, treat - * a newline as a command separator. - * [why don't we handle it exactly like ';'? --vda] */ - if (end_trigger && ch == '\n') { + if (ch == '\n') { #if ENABLE_HUSH_CASE /* "case ... in word) ..." - * newlines are ignored (but ';' wouldn't be) */ - if (dest->length == 0 // && argv[0] == NULL + if (ctx->command->argv == NULL && ctx->ctx_res_w == RES_MATCH ) { continue; } #endif + /* Treat newline as a command separator. + * [why don't we handle it exactly like ';'? --vda] */ done_pipe(ctx, PIPE_SEQ); dest->o_assignment = MAYBE_ASSIGNMENT; } } - if (end_trigger) { - if (strchr(end_trigger, ch)) { - /* Special case: (...word) makes last word terminate, - * as if ';' is seen */ - if (ch == ')') { - done_word(dest, ctx); + if (end_trigger && strchr(end_trigger, ch)) { + /* Special case: (...word) makes last word terminate, + * as if ';' is seen */ + if (ch == ')') { + done_word(dest, ctx); //err chk? - done_pipe(ctx, PIPE_SEQ); - dest->o_assignment = MAYBE_ASSIGNMENT; - } - /* What do we check here? */ - if (!HAS_KEYWORDS - IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) - ) { - debug_printf_parse("parse_stream return 0: end_trigger char found\n"); - /* this makes us return 0, not -1 */ - end_trigger = NULL; - goto ret; - } + done_pipe(ctx, PIPE_SEQ); + dest->o_assignment = MAYBE_ASSIGNMENT; } + /* What do we check here? */ + if (!HAS_KEYWORDS + IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) + ) { + debug_printf_parse("parse_stream return 0: end_trigger char found\n"); + /* this makes us return 0, not -1 */ + end_trigger = NULL; + goto ret; + } } if (m == CHAR_IFS) continue; Added: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right =================================================================== --- trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right (rev 0) +++ trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.right 2009-04-03 03:19:15 UTC (rev 25938) @@ -0,0 +1,6 @@ +b=1 +b=2 +b=3 +b=4 +b=5 +b=6 Added: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests =================================================================== --- trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests (rev 0) +++ trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests 2009-04-03 03:19:15 UTC (rev 25938) @@ -0,0 +1,7 @@ +b=1 env | grep ^b= +true | b=2 env | grep ^b= +a=1 true | b=3 env | grep ^b= + +(b=4 env) | grep ^b= +(true | b=5 env) | grep ^b= +(a=1 true | b=6 env) | grep ^b= Property changes on: trunk/busybox/shell/hush_test/hush-vars/var_in_pipes.tests ___________________________________________________________________ Added: svn:executable + * From vda at busybox.net Fri Apr 3 03:45:05 2009 From: vda at busybox.net (vda at busybox.net) Date: Fri, 3 Apr 2009 03:45:05 +0000 (UTC) Subject: svn commit: [25939] trunk/busybox/shell Message-ID: <20090403034505.CCDB5763A1@busybox.osuosl.org> Author: vda Date: 2009-04-03 03:45:05 +0000 (Fri, 03 Apr 2009) New Revision: 25939 Log: hush: simplify parse_stream function old new delta parse_and_run_stream 292 289 -3 parse_stream 1218 1204 -14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-17) Total: -17 bytes Modified: trunk/busybox/shell/hush.c Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-03 03:19:15 UTC (rev 25938) +++ trunk/busybox/shell/hush.c 2009-04-03 03:45:05 UTC (rev 25939) @@ -3717,7 +3717,7 @@ } static int parse_stream(o_string *dest, struct parse_context *ctx, - struct in_str *input0, const char *end_trigger); + struct in_str *input0, int end_trigger); #if ENABLE_HUSH_TICK static FILE *generate_stream_from_list(struct pipe *head) @@ -3773,7 +3773,7 @@ struct in_str pipe_str; /* Recursion to generate command */ - retcode = parse_stream(&result, &inner, input, NULL); + retcode = parse_stream(&result, &inner, input, '\0'); if (retcode != 0) return retcode; /* syntax error or EOF */ o_free(&result); @@ -3818,7 +3818,7 @@ * Typically it's empty, but for function defs, * it contains function name (without '()'). */ int rcode; - const char *endch; + int endch; struct parse_context sub; struct command *command = ctx->command; @@ -3840,9 +3840,9 @@ debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); return 1; } - endch = "}"; + endch = '}'; if (ch == '(') { - endch = ")"; + endch = ')'; command->grp_type = GRP_SUBSHELL; } rcode = parse_stream(dest, &sub, input, endch); @@ -4220,7 +4220,7 @@ * Net result is a list of pipes in ctx->list_head. */ static int parse_stream(o_string *dest, struct parse_context *ctx, - struct in_str *input, const char *end_trigger) + struct in_str *input, int end_trigger) { int ch, m; int redir_fd; @@ -4232,8 +4232,9 @@ * A single-quote triggers a bypass of the main loop until its mate is * found. When recursing, quote state is passed in via dest->o_escape. */ - debug_printf_parse("parse_stream entered, end_trigger='%s' " - "dest->o_assignment:%d\n", end_trigger, dest->o_assignment); + debug_printf_parse("parse_stream entered, end_trigger='%c' " + "dest->o_assignment:%d\n", end_trigger ? : 'X' + , dest->o_assignment); dest->o_assignment = MAYBE_ASSIGNMENT; initialize_context(ctx); @@ -4267,7 +4268,9 @@ } continue; } + /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */ + if (m == CHAR_IFS) { if (ch == EOF) goto ret_EOF; @@ -4285,29 +4288,25 @@ continue; } #endif - /* Treat newline as a command separator. - * [why don't we handle it exactly like ';'? --vda] */ + /* Treat newline as a command separator. */ done_pipe(ctx, PIPE_SEQ); dest->o_assignment = MAYBE_ASSIGNMENT; + ch = ';'; + /* note: if (m == CHAR_IFS) continue; + * will still trigger for us */ } } - if (end_trigger && strchr(end_trigger, ch)) { - /* Special case: (...word) makes last word terminate, - * as if ';' is seen */ - if (ch == ')') { - done_word(dest, ctx); -//err chk? - done_pipe(ctx, PIPE_SEQ); - dest->o_assignment = MAYBE_ASSIGNMENT; - } - /* What do we check here? */ + if (end_trigger && end_trigger == ch) { +//TODO: disallow "{ cmd }" without semicolon + done_word(dest, ctx); + done_pipe(ctx, PIPE_SEQ); + dest->o_assignment = MAYBE_ASSIGNMENT; + /* Do we sit outside of any if's, loops or case's? */ if (!HAS_KEYWORDS IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) ) { debug_printf_parse("parse_stream return 0: end_trigger char found\n"); - /* this makes us return 0, not -1 */ - end_trigger = NULL; - goto ret; + return 0; } } if (m == CHAR_IFS) @@ -4531,7 +4530,6 @@ /* Non-error returns */ ret_EOF: debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); - ret: done_word(dest, ctx); done_pipe(ctx, PIPE_SEQ); if (end_trigger) { @@ -4584,7 +4582,7 @@ * Example: "sleep 9999; echo TEST" + ctrl-C: * TEST should be printed */ temp.o_assignment = MAYBE_ASSIGNMENT; - rcode = parse_stream(&temp, &ctx, inp, ";\n"); + rcode = parse_stream(&temp, &ctx, inp, ';'); debug_printf_parse("rcode %d ctx.old_flag %x\n", rcode, ctx.old_flag); #if HAS_KEYWORDS if (rcode != 1 && ctx.old_flag != 0) { From vda at busybox.net Fri Apr 3 16:49:05 2009 From: vda at busybox.net (vda at busybox.net) Date: Fri, 3 Apr 2009 16:49:05 +0000 (UTC) Subject: svn commit: [25941] trunk/busybox/shell: hush_test/hush-misc Message-ID: <20090403164905.F37C1763A9@busybox.osuosl.org> Author: vda Date: 2009-04-03 16:49:04 +0000 (Fri, 03 Apr 2009) New Revision: 25941 Log: hush: improve parse_stream: does not require parsing context struct; cleans up on syntax errors (we used to leak memory in this case); much simplified interface to the rest of hush. function old new delta parse_stream 1204 1447 +243 done_word 658 669 +11 static_get 22 28 +6 builtin_source 84 89 +5 parse_and_run_file 27 30 +3 parse_and_run_string 31 27 -4 builtin_eval 55 50 -5 hush_main 991 985 -6 free_pipe_list 39 31 -8 free_pipe 210 189 -21 expand_variables 2242 2199 -43 parse_and_run_stream 289 153 -136 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/7 up/down: 268/-223) Total: 45 bytes Modified: trunk/busybox/shell/hush.c trunk/busybox/shell/hush_test/hush-misc/syntax_err_negate.right Changeset: Modified: trunk/busybox/shell/hush.c =================================================================== --- trunk/busybox/shell/hush.c 2009-04-03 13:51:00 UTC (rev 25940) +++ trunk/busybox/shell/hush.c 2009-04-03 16:49:04 UTC (rev 25941) @@ -217,24 +217,24 @@ void *xxmalloc(int lineno, size_t size) { void *ptr = xmalloc((size + 0xff) & ~0xff); - fprintf(stderr, "line %d: malloc %p\n", lineno, ptr); + fdprintf(2, "line %d: malloc %p\n", lineno, ptr); return ptr; } void *xxrealloc(int lineno, void *ptr, size_t size) { ptr = xrealloc(ptr, (size + 0xff) & ~0xff); - fprintf(stderr, "line %d: realloc %p\n", lineno, ptr); + fdprintf(2, "line %d: realloc %p\n", lineno, ptr); return ptr; } char *xxstrdup(int lineno, const char *str) { char *ptr = xstrdup(str); - fprintf(stderr, "line %d: strdup %p\n", lineno, ptr); + fdprintf(2, "line %d: strdup %p\n", lineno, ptr); return ptr; } void xxfree(void *ptr) { - fprintf(stderr, "free %p\n", ptr); + fdprintf(2, "free %p\n", ptr); free(ptr); } #define xmalloc(s) xxmalloc(__LINE__, s) @@ -244,12 +244,13 @@ #endif +#define ERR_PTR ((void*)(long)1) + static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR; #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" -#define SPECIAL_VAR_SYMBOL 3 -#define PARSEFLAG_EXIT_FROM_LOOP 1 +#define SPECIAL_VAR_SYMBOL 3 typedef enum redir_type { REDIRECT_INPUT = 1, @@ -1209,8 +1210,10 @@ static int static_get(struct in_str *i) { int ch = *i->p++; - if (ch == '\0') return EOF; - return ch; + if (ch != '\0') + return ch; + i->p--; + return EOF; } static int static_peek(struct in_str *i) @@ -2147,18 +2150,18 @@ #define free_pipe_list(head, indent) free_pipe_list(head) #define free_pipe(pi, indent) free_pipe(pi) #endif -static int free_pipe_list(struct pipe *head, int indent); +static void free_pipe_list(struct pipe *head, int indent); /* return code is the exit status of the pipe */ -static int free_pipe(struct pipe *pi, int indent) +static void free_pipe(struct pipe *pi, int indent) { char **p; struct command *command; struct redir_struct *r, *rnext; - int a, i, ret_code = 0; + int a, i; if (pi->stopped_cmds > 0) - return ret_code; + return; debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); for (i = 0; i < pi->num_cmds; i++) { command = &pi->cmds[i]; @@ -2169,12 +2172,13 @@ } free_strings(command->argv); command->argv = NULL; - } else if (command->group) { + } + /* not "else if": on syntax error, we may have both! */ + if (command->group) { debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type); - ret_code = free_pipe_list(command->group, indent+3); + free_pipe_list(command->group, indent+3); debug_printf_clean("%s end group\n", indenter(indent)); - } else { - debug_printf_clean("%s (nil)\n", indenter(indent)); + command->group = NULL; } for (r = command->redirects; r; r = rnext) { debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); @@ -2199,25 +2203,22 @@ free(pi->cmdtext); pi->cmdtext = NULL; #endif - return ret_code; } -static int free_pipe_list(struct pipe *head, int indent) +static void free_pipe_list(struct pipe *head, int indent) { - int rcode = 0; /* if list has no members */ struct pipe *pi, *next; for (pi = head; pi; pi = next) { #if HAS_KEYWORDS debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); #endif - rcode = free_pipe(pi, indent); + free_pipe(pi, indent); debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); next = pi->next; /*pi->next = NULL;*/ free(pi); } - return rcode; } @@ -3412,7 +3413,6 @@ new_p = new_pipe(); ctx->pipe->next = new_p; ctx->pipe = new_p; - ctx->command = NULL; /* needed! */ /* RES_THEN, RES_DO etc are "sticky" - * they remain set for commands inside if/while. * This is used to control execution. @@ -3428,6 +3428,7 @@ if (ctx->ctx_res_w == RES_MATCH) ctx->ctx_res_w = RES_CASEI; #endif + ctx->command = NULL; /* trick done_command below */ /* Create the memory for command, roughly: * ctx->pipe->cmds = new struct command; * ctx->command = &ctx->pipe->cmds[0]; @@ -3542,21 +3543,21 @@ #endif if (r->flag == 0) { /* '!' */ if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ - syntax(NULL); + syntax("! ! command"); IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) } ctx->ctx_inverted = 1; return 1; } if (r->flag & FLAG_START) { - struct parse_context *new; - debug_printf("push stack\n"); - new = xmalloc(sizeof(*new)); - *new = *ctx; /* physical copy */ + struct parse_context *old; + old = xmalloc(sizeof(*old)); + debug_printf_parse("push stack %p\n", old); + *old = *ctx; /* physical copy */ initialize_context(ctx); - ctx->stack = new; + ctx->stack = old; } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { - syntax(NULL); + syntax(word->data); ctx->ctx_res_w = RES_SNTX; return 1; } @@ -3564,8 +3565,8 @@ ctx->old_flag = r->flag; if (ctx->old_flag & FLAG_END) { struct parse_context *old; - debug_printf("pop stack\n"); done_pipe(ctx, PIPE_SEQ); + debug_printf_parse("pop stack %p\n", ctx->stack); old = ctx->stack; old->command->group = ctx->list_head; old->command->grp_type = GRP_NORMAL; @@ -3577,10 +3578,10 @@ } #endif -//TODO: many, many callers don't check error from done_word() - /* Word is complete, look at it and update parsing context. - * Normal return is 0. Syntax errors return 1. */ + * Normal return is 0. Syntax errors return 1. + * Note: on return, word is reset, but not o_free'd! + */ static int done_word(o_string *word, struct parse_context *ctx) { struct command *command = ctx->command; @@ -3610,10 +3611,14 @@ debug_printf("word stored in rd_filename: '%s'\n", word->data); } else { /* "{ echo foo; } echo bar" - bad */ - /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */ + /* NB: bash allows e.g.: + * if true; then { echo foo; } fi + * while if false; then false; fi do break; done + * TODO? */ if (command->group) { - syntax(NULL); - debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); + syntax(word->data); + debug_printf_parse("done_word return 1: syntax error, " + "groups and arglists don't mix\n"); return 1; } #if HAS_KEYWORDS @@ -3716,8 +3721,7 @@ return num; } -static int parse_stream(o_string *dest, struct parse_context *ctx, - struct in_str *input0, int end_trigger); +static struct pipe *parse_stream(struct in_str *input, int end_trigger); #if ENABLE_HUSH_TICK static FILE *generate_stream_from_list(struct pipe *head) @@ -3767,24 +3771,25 @@ struct in_str *input) { int retcode, ch, eol_cnt; - o_string result = NULL_O_STRING; - struct parse_context inner; + struct pipe *pipe_list; FILE *p; struct in_str pipe_str; /* Recursion to generate command */ - retcode = parse_stream(&result, &inner, input, '\0'); - if (retcode != 0) - return retcode; /* syntax error or EOF */ - o_free(&result); + pipe_list = parse_stream(input, '\0'); + if (pipe_list == NULL) + return 0; /* EOF: empty `cmd`: ``, ` ` etc */ + if (pipe_list == ERR_PTR) + return 1; /* parse error. can this really happen? */ - p = generate_stream_from_list(inner.list_head); + p = generate_stream_from_list(pipe_list); + free_pipe_list(pipe_list, /* indent: */ 0); if (p == NULL) return 1; close_on_exec_on(fileno(p)); - setup_file_in_str(&pipe_str, p); /* Now send results of command back into original context */ + setup_file_in_str(&pipe_str, p); eol_cnt = 0; while ((ch = i_getch(&pipe_str)) != EOF) { if (ch == '\n') { @@ -3805,7 +3810,6 @@ * echo `echo Hi; exec 1>&-; sleep 2` */ retcode = fclose(p); - free_pipe_list(inner.list_head, /* indent: */ 0); debug_printf("closed FILE from child, retcode=%d\n", retcode); return retcode; } @@ -3817,9 +3821,8 @@ /* dest contains characters seen prior to ( or {. * Typically it's empty, but for function defs, * it contains function name (without '()'). */ - int rcode; + struct pipe *pipe_list; int endch; - struct parse_context sub; struct command *command = ctx->command; debug_printf_parse("parse_group entered\n"); @@ -3845,12 +3848,16 @@ endch = ')'; command->grp_type = GRP_SUBSHELL; } - rcode = parse_stream(dest, &sub, input, endch); - if (rcode == 0) { - command->group = sub.list_head; + pipe_list = parse_stream(input, endch); + /* empty ()/{} or parse error? */ + if (!pipe_list || pipe_list == ERR_PTR) { + syntax(NULL); + debug_printf_parse("parse_group return 1: parse_stream returned %p\n", pipe_list); + return 1; } - debug_printf_parse("parse_group return %d\n", rcode); - return rcode; + command->group = pipe_list; + debug_printf_parse("parse_group return 0\n"); + return 0; /* command remains "open", available for possible redirects */ } @@ -4211,17 +4218,18 @@ goto again; } -/* Initalize ctx (i.e. caller does not need to do that). - * Scan input, call done_word() whenever full IFS delimited word was seen. - * Call done_pipe if '\n' was seen (and end_trigger != NULL). - * Return code is 0 if end_trigger char is met, - * -1 on EOF (but if end_trigger == NULL then return 0), - * 1 for syntax error - * Net result is a list of pipes in ctx->list_head. +/* + * Scan input until EOF or end_trigger char. + * Return a list of pipes to execute, or NULL on EOF + * or if end_trigger character is met. + * On syntax error, exit is shell is not interactive, + * reset parsing machinery and start parsing anew, + * or return ERR_PTR. */ -static int parse_stream(o_string *dest, struct parse_context *ctx, - struct in_str *input, int end_trigger) +static struct pipe *parse_stream(struct in_str *input, int end_trigger) { + struct parse_context ctx; + o_string dest = NULL_O_STRING; int ch, m; int redir_fd; redir_type redir_style; @@ -4232,18 +4240,22 @@ * A single-quote triggers a bypass of the main loop until its mate is * found. When recursing, quote state is passed in via dest->o_escape. */ - debug_printf_parse("parse_stream entered, end_trigger='%c' " - "dest->o_assignment:%d\n", end_trigger ? : 'X' - , dest->o_assignment); + debug_printf_parse("parse_stream entered, end_trigger='%c'\n", + end_trigger ? : 'X'); - dest->o_assignment = MAYBE_ASSIGNMENT; - initialize_context(ctx); - is_in_dquote = dest->o_escape; + reset: +#if ENABLE_HUSH_INTERACTIVE + input->promptmode = 0; /* PS1 */ +#endif + /* dest.o_assignment = MAYBE_ASSIGNMENT; - already is */ + initialize_context(&ctx); + is_in_dquote = 0; while (1) { if (is_in_dquote) { - if (parse_stream_dquoted(dest, input, '"')) - return 1; /* propagate parse error */ - /* If we're here, we reached closing '"' */ + if (parse_stream_dquoted(&dest, input, '"')) { + goto parse_error; + } + /* We reached closing '"' */ is_in_dquote = 0; } m = CHAR_IFS; @@ -4256,15 +4268,15 @@ } } debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", - ch, ch, m, dest->o_escape); + ch, ch, m, dest.o_escape); if (m == CHAR_ORDINARY) { - o_addQchr(dest, ch); - if ((dest->o_assignment == MAYBE_ASSIGNMENT - || dest->o_assignment == WORD_IS_KEYWORD) + o_addQchr(&dest, ch); + if ((dest.o_assignment == MAYBE_ASSIGNMENT + || dest.o_assignment == WORD_IS_KEYWORD) && ch == '=' - && is_assignment(dest->data) + && is_assignment(dest.data) ) { - dest->o_assignment = DEFINITELY_ASSIGNMENT; + dest.o_assignment = DEFINITELY_ASSIGNMENT; } continue; } @@ -4272,25 +4284,40 @@ /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */ if (m == CHAR_IFS) { - if (ch == EOF) - goto ret_EOF; - if (done_word(dest, ctx)) { - debug_printf_parse("parse_stream return 1: done_word!=0\n"); - return 1; + if (ch == EOF) { + struct pipe *pi; + if (done_word(&dest, &ctx)) { + goto parse_error; + } + o_free(&dest); + done_pipe(&ctx, PIPE_SEQ); + /* If we got nothing... */ + pi = ctx.list_head; + if (pi->num_cmds == 0 + && pi->res_word == RES_NONE + ) { + free_pipe_list(pi, 0); + pi = NULL; + } + debug_printf_parse("parse_stream return %p\n", pi); + return pi; } + if (done_word(&dest, &ctx)) { + goto parse_error; + } if (ch == '\n') { #if ENABLE_HUSH_CASE /* "case ... in word) ..." - * newlines are ignored (but ';' wouldn't be) */ - if (ctx->command->argv == NULL - && ctx->ctx_res_w == RES_MATCH + if (ctx.command->argv == NULL + && ctx.ctx_res_w == RES_MATCH ) { continue; } #endif /* Treat newline as a command separator. */ - done_pipe(ctx, PIPE_SEQ); - dest->o_assignment = MAYBE_ASSIGNMENT; + done_pipe(&ctx, PIPE_SEQ); + dest.o_assignment = MAYBE_ASSIGNMENT; ch = ';'; /* note: if (m == CHAR_IFS) continue; * will still trigger for us */ @@ -4298,15 +4325,20 @@ } if (end_trigger && end_trigger == ch) { //TODO: disallow "{ cmd }" without semicolon - done_word(dest, ctx); - done_pipe(ctx, PIPE_SEQ); - dest->o_assignment = MAYBE_ASSIGNMENT; + if (done_word(&dest, &ctx)) { + goto parse_error; + } + done_pipe(&ctx, PIPE_SEQ); + dest.o_assignment = MAYBE_ASSIGNMENT; /* Do we sit outside of any if's, loops or case's? */ if (!HAS_KEYWORDS - IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) + IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) ) { - debug_printf_parse("parse_stream return 0: end_trigger char found\n"); - return 0; + debug_printf_parse("parse_stream return %p: " + "end_trigger char found\n", + ctx.list_head); + o_free(&dest); + return ctx.list_head; } } if (m == CHAR_IFS) @@ -4314,15 +4346,15 @@ /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */ - if (dest->o_assignment == MAYBE_ASSIGNMENT) { + if (dest.o_assignment == MAYBE_ASSIGNMENT) { /* ch is a special char and thus this word * cannot be an assignment */ - dest->o_assignment = NOT_ASSIGNMENT; + dest.o_assignment = NOT_ASSIGNMENT; } switch (ch) { case '#': - if (dest->length == 0) { + if (dest.length == 0) { while (1) { ch = i_peek(input); if (ch == EOF || ch == '\n') @@ -4330,61 +4362,61 @@ i_getch(input); } } else { - o_addQchr(dest, ch); + o_addQchr(&dest, ch); } break; case '\\': if (next == EOF) { syntax("\\"); - debug_printf_parse("parse_stream return 1: \\\n"); - return 1; + goto parse_error; } - o_addchr(dest, '\\'); - o_addchr(dest, i_getch(input)); + o_addchr(&dest, '\\'); + o_addchr(&dest, i_getch(input)); break; case '$': - if (handle_dollar(dest, input) != 0) { - debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n"); - return 1; + if (handle_dollar(&dest, input) != 0) { + debug_printf_parse("parse_stream parse error: handle_dollar returned non-0\n"); + goto parse_error; } break; case '\'': - dest->nonnull = 1; + dest.nonnull = 1; while (1) { ch = i_getch(input); if (ch == EOF) { syntax("unterminated '"); - debug_printf_parse("parse_stream return 1: unterminated '\n"); - return 1; + goto parse_error; } if (ch == '\'') break; - if (dest->o_assignment == NOT_ASSIGNMENT) - o_addqchr(dest, ch); + if (dest.o_assignment == NOT_ASSIGNMENT) + o_addqchr(&dest, ch); else - o_addchr(dest, ch); + o_addchr(&dest, ch); } break; case '"': - dest->nonnull = 1; + dest.nonnull = 1; is_in_dquote ^= 1; /* invert */ - if (dest->o_assignment == NOT_ASSIGNMENT) - dest->o_escape ^= 1; + if (dest.o_assignment == NOT_ASSIGNMENT) + dest.o_escape ^= 1; break; #if ENABLE_HUSH_TICK case '`': { - //int pos = dest->length; - o_addchr(dest, SPECIAL_VAR_SYMBOL); - o_addchr(dest, '`'); - add_till_backquote(dest, input); - o_addchr(dest, SPECIAL_VAR_SYMBOL); - //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); + //int pos = dest.length; + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + o_addchr(&dest, '`'); + add_till_backquote(&dest, input); + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); break; } #endif case '>': - redir_fd = redirect_opt_num(dest); - done_word(dest, ctx); + redir_fd = redirect_opt_num(&dest); + if (done_word(&dest, &ctx)) { + goto parse_error; + } redir_style = REDIRECT_OVERWRITE; if (next == '>') { redir_style = REDIRECT_APPEND; @@ -4393,15 +4425,16 @@ #if 0 else if (next == '(') { syntax(">(process) not supported"); - debug_printf_parse("parse_stream return 1: >(process) not supported\n"); - return 1; + goto parse_error; } #endif - setup_redirect(ctx, redir_fd, redir_style, input); + setup_redirect(&ctx, redir_fd, redir_style, input); break; case '<': - redir_fd = redirect_opt_num(dest); - done_word(dest, ctx); + redir_fd = redirect_opt_num(&dest); + if (done_word(&dest, &ctx)) { + goto parse_error; + } redir_style = REDIRECT_INPUT; if (next == '<') { redir_style = REDIRECT_HEREIS; @@ -4413,18 +4446,19 @@ #if 0 else if (next == '(') { syntax("<(process) not supported"); - debug_printf_parse("parse_stream return 1: <(process) not supported\n"); - return 1; + goto parse_error; } #endif - setup_redirect(ctx, redir_fd, redir_style, input); + setup_redirect(&ctx, redir_fd, redir_style, input); break; case ';': #if ENABLE_HUSH_CASE case_semi: #endif - done_word(dest, ctx); - done_pipe(ctx, PIPE_SEQ); + if (done_word(&dest, &ctx)) { + goto parse_error; + } + done_pipe(&ctx, PIPE_SEQ); #if ENABLE_HUSH_CASE /* Eat multiple semicolons, detect * whether it means something special */ @@ -4433,9 +4467,9 @@ if (ch != ';') break; i_getch(input); - if (ctx->ctx_res_w == RES_CASEI) { - ctx->ctx_dsemicolon = 1; - ctx->ctx_res_w = RES_MATCH; + if (ctx.ctx_res_w == RES_CASEI) { + ctx.ctx_dsemicolon = 1; + ctx.ctx_res_w = RES_MATCH; break; } } @@ -4443,51 +4477,55 @@ new_cmd: /* We just finished a cmd. New one may start * with an assignment */ - dest->o_assignment = MAYBE_ASSIGNMENT; + dest.o_assignment = MAYBE_ASSIGNMENT; break; case '&': - done_word(dest, ctx); + if (done_word(&dest, &ctx)) { + goto parse_error; + } if (next == '&') { i_getch(input); - done_pipe(ctx, PIPE_AND); + done_pipe(&ctx, PIPE_AND); } else { - done_pipe(ctx, PIPE_BG); + done_pipe(&ctx, PIPE_BG); } goto new_cmd; case '|': - done_word(dest, ctx); + if (done_word(&dest, &ctx)) { + goto parse_error; + } #if ENABLE_HUSH_CASE - if (ctx->ctx_res_w == RES_MATCH) + if (ctx.ctx_res_w == RES_MATCH) break; /* we are in case's "word | word)" */ #endif if (next == '|') { /* || */ i_getch(input); - done_pipe(ctx, PIPE_OR); + done_pipe(&ctx, PIPE_OR); } else { /* we could pick up a file descriptor choice here * with redirect_opt_num(), but bash doesn't do it. * "echo foo 2| cat" yields "foo 2". */ - done_command(ctx); + done_command(&ctx); } goto new_cmd; case '(': #if ENABLE_HUSH_CASE /* "case... in [(]word)..." - skip '(' */ - if (ctx->ctx_res_w == RES_MATCH - && ctx->command->argv == NULL /* not (word|(... */ - && dest->length == 0 /* not word(... */ - && dest->nonnull == 0 /* not ""(... */ + if (ctx.ctx_res_w == RES_MATCH + && ctx.command->argv == NULL /* not (word|(... */ + && dest.length == 0 /* not word(... */ + && dest.nonnull == 0 /* not ""(... */ ) { continue; } #endif #if ENABLE_HUSH_FUNCTIONS - if (dest->length != 0 /* not just () but word() */ - && dest->nonnull == 0 /* not a"b"c() */ - && ctx->command->argv == NULL /* it's the first word */ + if (dest.length != 0 /* not just () but word() */ + && dest.nonnull == 0 /* not a"b"c() */ + && ctx.command->argv == NULL /* it's the first word */ //TODO: "func ( ) {...}" - note spaces - is valid format too in bash && i_peek(input) == ')' - && !match_reserved_word(dest) + && !match_reserved_word(&dest) ) { bb_error_msg("seems like a function definition"); i_getch(input); @@ -4497,21 +4535,19 @@ } while (ch == ' ' || ch == '\n'); if (ch != '{') { syntax("was expecting {"); - debug_printf_parse("parse_stream return 1\n"); - return 1; + goto parse_error; } ch = 'F'; /* magic value */ } #endif case '{': - if (parse_group(dest, ctx, input, ch) != 0) { - debug_printf_parse("parse_stream return 1: parse_group returned non-0\n"); - return 1; + if (parse_group(&dest, &ctx, input, ch) != 0) { + goto parse_error; } goto new_cmd; case ')': #if ENABLE_HUSH_CASE - if (ctx->ctx_res_w == RES_MATCH) + if (ctx.ctx_res_w == RES_MATCH) goto case_semi; #endif case '}': @@ -4519,23 +4555,51 @@ * if we see {, we call parse_group(..., end_trigger='}') * and it will match } earlier (not here). */ syntax("unexpected } or )"); - debug_printf_parse("parse_stream return 1: unexpected '}'\n"); - return 1; + goto parse_error; default: if (HUSH_DEBUG) bb_error_msg_and_die("BUG: unexpected %c\n", ch); } } /* while (1) */ - /* Non-error returns */ - ret_EOF: - debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); - done_word(dest, ctx); - done_pipe(ctx, PIPE_SEQ); - if (end_trigger) { - return -1; /* EOF found while expecting end_trigger */ + parse_error: + { + struct parse_context *pctx, *p2; + + /* Clean up allocated tree. + * Samples for finding leaks on syntax error recovery path. + * Execute them from interactive shell and watch pmap `pidof hush`. + * while if false; then false; fi do break; done (bash accepts it) + * while if false; then false; fi; do break; fi + */ + pctx = &ctx; + do { + /* Update pipe/command counts, + * otherwise freeing may miss some */ + done_pipe(pctx, PIPE_SEQ); + debug_printf_clean("freeing list %p from ctx %p\n", + pctx->list_head, pctx); + debug_print_tree(pctx->list_head, 0); + free_pipe_list(pctx->list_head, 0); + debug_printf_clean("freed list %p\n", pctx->list_head); + p2 = pctx->stack; + if (pctx != &ctx) { + free(pctx); + } + pctx = p2; + } while (pctx); + /* Free text, clear all dest fields */ + o_free(&dest); + /* If we are not in top-level parse, we return, + * our caller will propagate error. + */ + if (end_trigger != ';') + return ERR_PTR; + /* Discard cached input, force prompt */ + input->p = NULL; + input->promptme = 1; + goto reset; } - return 0; } static void set_in_charmap(const char *set, int code) @@ -4565,71 +4629,41 @@ set_in_charmap(G.ifs, CHAR_IFS); /* are ordinary if quoted */ } -/* Most recursion does not come through here, the exception is - * from builtin_source() and builtin_eval() */ -static int parse_and_run_stream(struct in_str *inp, int parse_flag) +/* Execiting from string: eval, sh -c '...' + * or from file: /etc/profile, . file, sh