aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2013-08-27 16:10:53 +0100
committerRon Yorston <rmy@pobox.com>2013-08-27 16:10:53 +0100
commit3fd34651ea72ea1c335d3170f234cb0517fd897f (patch)
tree36e8fc40cffd464ffda4759020777dd3ca23ca31
parente3ac39098326de084a805d0dd31db9666b734f20 (diff)
parentd6ae4fb446daedfe3073d67be655942e9fa7eb18 (diff)
downloadbusybox-w32-3fd34651ea72ea1c335d3170f234cb0517fd897f.tar.gz
busybox-w32-3fd34651ea72ea1c335d3170f234cb0517fd897f.tar.bz2
busybox-w32-3fd34651ea72ea1c335d3170f234cb0517fd897f.zip
Merge branch 'busybox' into merge
-rw-r--r--Config.in5
-rw-r--r--Makefile.custom7
-rw-r--r--TODO11
-rwxr-xr-xapplets/busybox.mksuid54
-rw-r--r--archival/bbunzip.c36
-rw-r--r--archival/libarchive/Kbuild.src38
-rw-r--r--archival/libarchive/data_extract_to_command.c2
-rw-r--r--archival/tar.c6
-rw-r--r--archival/unzip.c64
-rw-r--r--coreutils/catv.c43
-rw-r--r--coreutils/dd.c115
-rw-r--r--coreutils/head.c4
-rw-r--r--coreutils/head_tail.c14
-rw-r--r--coreutils/head_tail.h6
-rw-r--r--coreutils/md5_sha1_sum.c4
-rw-r--r--coreutils/od_bloaty.c12
-rw-r--r--coreutils/split.c11
-rw-r--r--coreutils/stty.c105
-rw-r--r--coreutils/tail.c27
-rw-r--r--docs/tcp.txt82
-rw-r--r--editors/awk.c12
-rw-r--r--editors/sed.c26
-rw-r--r--editors/vi.c68
-rw-r--r--findutils/find.c70
-rw-r--r--findutils/grep.c24
-rw-r--r--include/applets.src.h9
-rw-r--r--include/bb_e2fs_defs.h2
-rw-r--r--include/libbb.h27
-rw-r--r--include/liblzo_interface.h2
-rw-r--r--include/platform.h1
-rw-r--r--init/init.c68
-rw-r--r--libbb/Kbuild.src2
-rw-r--r--libbb/appletlib.c2
-rw-r--r--libbb/bb_askpass.c4
-rw-r--r--libbb/create_icmp6_socket.c38
-rw-r--r--libbb/create_icmp_socket.c36
-rw-r--r--libbb/hash_md5_sha.c6
-rw-r--r--libbb/in_ether.c58
-rw-r--r--libbb/lineedit.c82
-rw-r--r--libbb/printable.c24
-rw-r--r--libbb/time.c33
-rw-r--r--libbb/unicode.c38
-rw-r--r--libbb/xatonum.c7
-rw-r--r--libbb/xfuncs_printf.c12
-rw-r--r--loginutils/cryptpw.c19
-rw-r--r--loginutils/getty.c2
-rw-r--r--loginutils/sulogin.c6
-rw-r--r--miscutils/chrt.c3
-rw-r--r--miscutils/less.c29
-rw-r--r--miscutils/man.c2
-rw-r--r--miscutils/setsid.c14
-rw-r--r--miscutils/ubi_tools.c305
-rw-r--r--modutils/modprobe.c2
-rw-r--r--networking/httpd.c4
-rw-r--r--networking/ifconfig.c45
-rw-r--r--networking/ifplugd.c14
-rw-r--r--networking/interface.c57
-rw-r--r--networking/libiproute/ipaddress.c22
-rw-r--r--networking/libiproute/iplink.c139
-rw-r--r--networking/libiproute/iprule.c8
-rw-r--r--networking/libiproute/iptunnel.c6
-rw-r--r--networking/nc.c2
-rw-r--r--networking/nc_bloaty.c91
-rw-r--r--networking/nslookup.c15
-rw-r--r--networking/ntpd.c73
-rw-r--r--networking/ping.c91
-rw-r--r--networking/tc.c2
-rw-r--r--networking/telnet.c17
-rw-r--r--networking/udhcp/common.c32
-rw-r--r--networking/udhcp/dhcpc.c53
-rw-r--r--networking/wget.c26
-rw-r--r--procps/lsof.c9
-rw-r--r--procps/pstree.c13
-rw-r--r--runit/svlogd.c5
-rw-r--r--scripts/kconfig/confdata.c24
-rw-r--r--shell/ash.c22
-rw-r--r--shell/hush.c40
-rw-r--r--shell/hush_test/hush-misc/while4.right1
-rwxr-xr-xshell/hush_test/hush-misc/while4.tests6
-rw-r--r--shell/shell_common.c2
-rw-r--r--sysklogd/logread.c9
-rw-r--r--sysklogd/syslogd.c11
-rwxr-xr-xtestsuite/awk.tests39
-rwxr-xr-xtestsuite/grep.tests20
-rwxr-xr-xtestsuite/sed.tests21
-rw-r--r--util-linux/Config.src246
-rw-r--r--util-linux/fdisk_gpt.c4
-rw-r--r--util-linux/hexdump.c9
-rw-r--r--util-linux/losetup.c37
-rw-r--r--util-linux/mdev.c47
-rw-r--r--util-linux/swaponoff.c14
-rw-r--r--util-linux/volume_id/Config.src15
-rw-r--r--util-linux/volume_id/Kbuild.src38
-rw-r--r--util-linux/volume_id/btrfs.c11
-rw-r--r--util-linux/volume_id/cramfs.c11
-rw-r--r--util-linux/volume_id/exfat.c13
-rw-r--r--util-linux/volume_id/ext.c11
-rw-r--r--util-linux/volume_id/f2fs.c95
-rw-r--r--util-linux/volume_id/fat.c11
-rw-r--r--util-linux/volume_id/get_devname.c5
-rw-r--r--util-linux/volume_id/hfs.c11
-rw-r--r--util-linux/volume_id/iso9660.c11
-rw-r--r--util-linux/volume_id/jfs.c11
-rw-r--r--util-linux/volume_id/linux_raid.c11
-rw-r--r--util-linux/volume_id/linux_swap.c11
-rw-r--r--util-linux/volume_id/luks.c11
-rw-r--r--util-linux/volume_id/nilfs.c20
-rw-r--r--util-linux/volume_id/ntfs.c13
-rw-r--r--util-linux/volume_id/ocfs2.c11
-rw-r--r--util-linux/volume_id/reiserfs.c11
-rw-r--r--util-linux/volume_id/romfs.c11
-rw-r--r--util-linux/volume_id/squashfs.c12
-rw-r--r--util-linux/volume_id/sysv.c11
-rw-r--r--util-linux/volume_id/udf.c11
-rw-r--r--util-linux/volume_id/unused_highpoint.c11
-rw-r--r--util-linux/volume_id/unused_hpfs.c11
-rw-r--r--util-linux/volume_id/unused_isw_raid.c11
-rw-r--r--util-linux/volume_id/unused_lsi_raid.c11
-rw-r--r--util-linux/volume_id/unused_lvm.c11
-rw-r--r--util-linux/volume_id/unused_mac.c11
-rw-r--r--util-linux/volume_id/unused_minix.c11
-rw-r--r--util-linux/volume_id/unused_msdos.c11
-rw-r--r--util-linux/volume_id/unused_nvidia_raid.c11
-rw-r--r--util-linux/volume_id/unused_promise_raid.c11
-rw-r--r--util-linux/volume_id/unused_silicon_raid.c11
-rw-r--r--util-linux/volume_id/unused_ufs.c11
-rw-r--r--util-linux/volume_id/unused_via_raid.c11
-rw-r--r--util-linux/volume_id/volume_id.c5
-rw-r--r--util-linux/volume_id/volume_id_internal.h54
-rw-r--r--util-linux/volume_id/xfs.c11
130 files changed, 2217 insertions, 1327 deletions
diff --git a/Config.in b/Config.in
index 8999e1699..8c0e64988 100644
--- a/Config.in
+++ b/Config.in
@@ -184,12 +184,13 @@ config UNICODE_USING_LOCALE
184 Internal implementation is smaller. 184 Internal implementation is smaller.
185 185
186config FEATURE_CHECK_UNICODE_IN_ENV 186config FEATURE_CHECK_UNICODE_IN_ENV
187 bool "Check $LANG environment variable" 187 bool "Check $LC_ALL, $LC_CTYPE and $LANG environment variables"
188 default n 188 default n
189 depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE 189 depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE
190 help 190 help
191 With this option on, Unicode support is activated 191 With this option on, Unicode support is activated
192 only if LANG variable has the value of the form "xxxx.utf8" 192 only if locale-related variables have the value of the form
193 "xxxx.utf8"
193 194
194 Otherwise, Unicode support will be always enabled and active. 195 Otherwise, Unicode support will be always enabled and active.
195 196
diff --git a/Makefile.custom b/Makefile.custom
index 6da79e6e4..3561e5768 100644
--- a/Makefile.custom
+++ b/Makefile.custom
@@ -3,7 +3,12 @@
3# ========================================================================== 3# ==========================================================================
4 4
5busybox.links: $(srctree)/applets/busybox.mkll $(objtree)/include/autoconf.h include/applets.h 5busybox.links: $(srctree)/applets/busybox.mkll $(objtree)/include/autoconf.h include/applets.h
6 $(Q)-$(SHELL) $^ >$@ 6 $(Q)-$(SHELL) $^ > $@
7
8busybox.cfg.suid: $(srctree)/applets/busybox.mksuid $(objtree)/include/autoconf.h include/applets.h
9 $(Q)-SUID="yes" $(SHELL) $^ > $@
10busybox.cfg.nosuid: $(srctree)/applets/busybox.mksuid $(objtree)/include/autoconf.h include/applets.h
11 $(Q)-SUID="DROP" $(SHELL) $^ > $@
7 12
8.PHONY: install 13.PHONY: install
9ifeq ($(CONFIG_INSTALL_APPLET_SYMLINKS),y) 14ifeq ($(CONFIG_INSTALL_APPLET_SYMLINKS),y)
diff --git a/TODO b/TODO
index 44364690f..d2a085ede 100644
--- a/TODO
+++ b/TODO
@@ -128,15 +128,6 @@ patch
128 And while we're at it, a new patch filename quoting format is apparently 128 And while we're at it, a new patch filename quoting format is apparently
129 coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 129 coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
130--- 130---
131stty / catv
132 stty's visible() function and catv's guts are identical. Merge them into
133 an appropriate libbb function.
134---
135struct suffix_mult
136 Several duplicate users of: grep -r "1024\*1024" * -B2 -A1
137 Merge to a single size_suffixes[] in libbb.
138 Users: head tail od_bloaty hexdump and (partially as it wouldn't hurt) svlogd
139---
140tail 131tail
141 ./busybox tail -f foo.c~ TODO 132 ./busybox tail -f foo.c~ TODO
142 should not print fmt=header_fmt for subsequent date >> TODO; i.e. only 133 should not print fmt=header_fmt for subsequent date >> TODO; i.e. only
@@ -234,8 +225,6 @@ Minor stuff:
234 See grep -r strtod 225 See grep -r strtod
235 Alot of duplication that wants cleanup. 226 Alot of duplication that wants cleanup.
236--- 227---
237 in_ether duplicated in network/{interface,ifconfig}.c
238---
239 unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. 228 unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles.
240--- 229---
241 support start-stop-daemon -d <chdir-path> 230 support start-stop-daemon -d <chdir-path>
diff --git a/applets/busybox.mksuid b/applets/busybox.mksuid
new file mode 100755
index 000000000..6492c079a
--- /dev/null
+++ b/applets/busybox.mksuid
@@ -0,0 +1,54 @@
1#!/bin/sh
2# Make list of configuration variables regarding suid handling
3
4# input $1: full path to autoconf.h
5# input $2: full path to applets.h
6# input $3: full path to .config
7# output (stdout): list of CONFIG_ that do or may require suid
8
9# If the environment variable SUID is not set or set to DROP,
10# lists all config options that do not require suid permissions.
11# Otherwise, lists all config options for applets that DO or MAY require
12# suid permissions.
13
14# Maintainer: Bernhard Reutner-Fischer
15
16export LC_ALL=POSIX
17export LC_CTYPE=POSIX
18
19CONFIG_H=${1:-include/autoconf.h}
20APPLETS_H=${2:-include/applets.h}
21DOT_CONFIG=${3:-.config}
22
23case ${SUID:-DROP} in
24[dD][rR][oO][pP]) USE="DROP" ;;
25*) USE="suid" ;;
26esac
27
28$HOSTCC -E -DMAKE_SUID -include $CONFIG_H $APPLETS_H |
29 awk -v USE=${USE} '
30 /^SUID[ \t]/{
31 if (USE == "DROP") {
32 if ($2 != "BB_SUID_DROP") next
33 } else {
34 if ($2 == "BB_SUID_DROP") next
35 }
36 cfg = $NF
37 gsub("\"", "", cfg)
38 cfg = substr(cfg, 8)
39 s[i++] = "CONFIG_" cfg
40 s[i++] = "CONFIG_FEATURE_" cfg "_.*"
41 }
42 END{
43 while (getline < ARGV[2]) {
44 for (j in s) {
45 if ($0 ~ "^" s[j] "=y$") {
46 sub(/=.*/, "")
47 print
48 if (s[j] !~ /\*$/) delete s[j] # can drop this applet now
49 }
50 }
51 }
52 }
53' - $DOT_CONFIG
54
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index f77ac8383..9d1cd9485 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -132,7 +132,10 @@ int FAST_FUNC bbunpack(char **argv,
132 132
133 if (filename) { 133 if (filename) {
134 char *del = new_name; 134 char *del = new_name;
135
135 if (status >= 0) { 136 if (status >= 0) {
137 unsigned new_name_len;
138
136 /* TODO: restore other things? */ 139 /* TODO: restore other things? */
137 if (aux.mtime != 0) { 140 if (aux.mtime != 0) {
138 struct timeval times[2]; 141 struct timeval times[2];
@@ -146,24 +149,31 @@ int FAST_FUNC bbunpack(char **argv,
146 utimes(new_name, times); /* ignoring errors */ 149 utimes(new_name, times); /* ignoring errors */
147 } 150 }
148 151
149 /* Delete _compressed_ file */ 152 if (ENABLE_DESKTOP)
153 new_name_len = strlen(new_name);
154 /* Restore source filename (unless tgz -> tar case) */
155 if (new_name == filename) {
156 new_name_len = strlen(filename);
157 filename[new_name_len] = '.';
158 }
159 /* Extreme bloat for gunzip compat */
160 /* Some users do want this info... */
161 if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE)) {
162 unsigned percent = status
163 ? ((uoff_t)stat_buf.st_size * 100u / (unsigned long long)status)
164 : 0;
165 fprintf(stderr, "%s: %u%% - replaced with %.*s\n",
166 filename,
167 100u - percent,
168 new_name_len, new_name
169 );
170 }
171 /* Delete _source_ file */
150 del = filename; 172 del = filename;
151 /* restore extension (unless tgz -> tar case) */
152 if (new_name == filename)
153 filename[strlen(filename)] = '.';
154 } 173 }
155 if (ENABLE_PLATFORM_MINGW32) 174 if (ENABLE_PLATFORM_MINGW32)
156 xclose(STDIN_FILENO); 175 xclose(STDIN_FILENO);
157 xunlink(del); 176 xunlink(del);
158
159#if 0 /* Currently buggy - wrong name: "a.gz: 261% - replaced with a.gz" */
160 /* Extreme bloat for gunzip compat */
161 if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) {
162 fprintf(stderr, "%s: %u%% - replaced with %s\n",
163 filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name);
164 }
165#endif
166
167 free_name: 177 free_name:
168 if (new_name != filename) 178 if (new_name != filename)
169 free(new_name); 179 free(new_name);
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index 58457fc22..968fdf8ab 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -38,31 +38,45 @@ DPKG_FILES:= \
38 38
39INSERT 39INSERT
40 40
41lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
42lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o
43lib-$(CONFIG_UNLZMA) += decompress_unlzma.o
44lib-$(CONFIG_UNXZ) += decompress_unxz.o
45lib-$(CONFIG_CPIO) += get_header_cpio.o
46lib-$(CONFIG_DPKG) += $(DPKG_FILES) 41lib-$(CONFIG_DPKG) += $(DPKG_FILES)
47lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) 42lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
48lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o 43
49lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o 44lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
50lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o 45lib-$(CONFIG_CPIO) += get_header_cpio.o
51lib-$(CONFIG_TAR) += get_header_tar.o 46lib-$(CONFIG_TAR) += get_header_tar.o
52lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o 47lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
53lib-$(CONFIG_UNZIP) += decompress_gunzip.o
54lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o 48lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
55lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o 49lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
50lib-$(CONFIG_BUNZIP2) += open_transformer.o decompress_bunzip2.o
51lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o
52lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o
53lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o
54lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o
55lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.o
56lib-$(CONFIG_RPM2CPIO) += open_transformer.o decompress_gunzip.o get_header_cpio.o
57lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o
58
59lib-$(CONFIG_GZIP) += open_transformer.o
60lib-$(CONFIG_BZIP2) += open_transformer.o
61lib-$(CONFIG_LZOP) += open_transformer.o
62lib-$(CONFIG_MAN) += open_transformer.o
63lib-$(CONFIG_SETFONT) += open_transformer.o
64lib-$(CONFIG_FEATURE_2_4_MODULES) += open_transformer.o
56lib-$(CONFIG_MODINFO) += open_transformer.o 65lib-$(CONFIG_MODINFO) += open_transformer.o
57lib-$(CONFIG_INSMOD) += open_transformer.o 66lib-$(CONFIG_INSMOD) += open_transformer.o
67lib-$(CONFIG_DEPMOD) += open_transformer.o
68lib-$(CONFIG_RMMOD) += open_transformer.o
69lib-$(CONFIG_LSMOD) += open_transformer.o
70lib-$(CONFIG_MODPROBE) += open_transformer.o
71lib-$(CONFIG_MODPROBE_SMALL) += open_transformer.o
72
58lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o 73lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o
59lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o 74lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o
60lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o 75lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o
61lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o 76lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o
62lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o 77lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
63lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o 78lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o
64lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o 79lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o
65lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
66 80
67ifneq ($(lib-y),) 81ifneq ($(lib-y),)
68lib-y += $(COMMON_FILES) 82lib-y += $(COMMON_FILES)
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index a2ce33b51..5b32c2ec8 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -103,7 +103,7 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
103 archive_handle->tar__to_command_shell, 103 archive_handle->tar__to_command_shell,
104 "-c", 104 "-c",
105 archive_handle->tar__to_command, 105 archive_handle->tar__to_command,
106 NULL); 106 (char *)0);
107 bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell); 107 bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell);
108 } 108 }
109 close(p[0]); 109 close(p[0]);
diff --git a/archival/tar.c b/archival/tar.c
index 648d1256d..3129781d2 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -569,7 +569,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip)
569 xmove_fd(gzipDataPipe.rd, 0); 569 xmove_fd(gzipDataPipe.rd, 0);
570 xmove_fd(tar_fd, 1); 570 xmove_fd(tar_fd, 1);
571 /* exec gzip/bzip2 program/applet */ 571 /* exec gzip/bzip2 program/applet */
572 BB_EXECLP(zip_exec, zip_exec, "-f", NULL); 572 BB_EXECLP(zip_exec, zip_exec, "-f", (char *)0);
573 vfork_exec_errno = errno; 573 vfork_exec_errno = errno;
574 _exit(EXIT_FAILURE); 574 _exit(EXIT_FAILURE);
575 } 575 }
@@ -681,14 +681,12 @@ static llist_t *append_file_list_to_list(llist_t *list)
681 char *cp = last_char_is(line, '/'); 681 char *cp = last_char_is(line, '/');
682 if (cp > line) 682 if (cp > line)
683 *cp = '\0'; 683 *cp = '\0';
684 llist_add_to(&newlist, line); 684 llist_add_to_end(&newlist, line);
685 } 685 }
686 fclose(src_stream); 686 fclose(src_stream);
687 } 687 }
688 return newlist; 688 return newlist;
689} 689}
690#else
691# define append_file_list_to_list(x) 0
692#endif 690#endif
693 691
694//usage:#define tar_trivial_usage 692//usage:#define tar_trivial_usage
diff --git a/archival/unzip.c b/archival/unzip.c
index e4c824850..673e5fe08 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -163,7 +163,17 @@ enum { zip_fd = 3 };
163 163
164#if ENABLE_DESKTOP 164#if ENABLE_DESKTOP
165 165
166#define PEEK_FROM_END 16384 166/* Seen in the wild:
167 * Self-extracting PRO2K3XP_32.exe contains 19078464 byte zip archive,
168 * where CDE was nearly 48 kbytes before EOF.
169 * (Surprisingly, it also apparently has *another* CDE structure
170 * closer to the end, with bogus cdf_offset).
171 * To make extraction work, bumped PEEK_FROM_END from 16k to 64k.
172 */
173#define PEEK_FROM_END (64*1024)
174
175/* This value means that we failed to find CDF */
176#define BAD_CDF_OFFSET ((uint32_t)0xffffffff)
167 177
168/* NB: does not preserve file position! */ 178/* NB: does not preserve file position! */
169static uint32_t find_cdf_offset(void) 179static uint32_t find_cdf_offset(void)
@@ -180,6 +190,7 @@ static uint32_t find_cdf_offset(void)
180 xlseek(zip_fd, end, SEEK_SET); 190 xlseek(zip_fd, end, SEEK_SET);
181 full_read(zip_fd, buf, PEEK_FROM_END); 191 full_read(zip_fd, buf, PEEK_FROM_END);
182 192
193 cde_header.formatted.cdf_offset = BAD_CDF_OFFSET;
183 p = buf; 194 p = buf;
184 while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { 195 while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
185 if (*p != 'P') { 196 if (*p != 'P') {
@@ -195,11 +206,17 @@ static uint32_t find_cdf_offset(void)
195 /* we found CDE! */ 206 /* we found CDE! */
196 memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); 207 memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
197 FIX_ENDIANNESS_CDE(cde_header); 208 FIX_ENDIANNESS_CDE(cde_header);
198 free(buf); 209 /*
199 return cde_header.formatted.cdf_offset; 210 * I've seen .ZIP files with seemingly valid CDEs
211 * where cdf_offset points past EOF - ??
212 * Ignore such CDEs:
213 */
214 if (cde_header.formatted.cdf_offset < end + (p - buf))
215 break;
216 cde_header.formatted.cdf_offset = BAD_CDF_OFFSET;
200 } 217 }
201 //free(buf); 218 free(buf);
202 bb_error_msg_and_die("can't find file table"); 219 return cde_header.formatted.cdf_offset;
203}; 220};
204 221
205static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) 222static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
@@ -211,13 +228,15 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
211 if (!cdf_offset) 228 if (!cdf_offset)
212 cdf_offset = find_cdf_offset(); 229 cdf_offset = find_cdf_offset();
213 230
214 xlseek(zip_fd, cdf_offset + 4, SEEK_SET); 231 if (cdf_offset != BAD_CDF_OFFSET) {
215 xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); 232 xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
216 FIX_ENDIANNESS_CDF(*cdf_ptr); 233 xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
217 cdf_offset += 4 + CDF_HEADER_LEN 234 FIX_ENDIANNESS_CDF(*cdf_ptr);
218 + cdf_ptr->formatted.file_name_length 235 cdf_offset += 4 + CDF_HEADER_LEN
219 + cdf_ptr->formatted.extra_field_length 236 + cdf_ptr->formatted.file_name_length
220 + cdf_ptr->formatted.file_comment_length; 237 + cdf_ptr->formatted.extra_field_length
238 + cdf_ptr->formatted.file_comment_length;
239 }
221 240
222 xlseek(zip_fd, org, SEEK_SET); 241 xlseek(zip_fd, org, SEEK_SET);
223 return cdf_offset; 242 return cdf_offset;
@@ -226,8 +245,9 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
226 245
227static void unzip_skip(off_t skip) 246static void unzip_skip(off_t skip)
228{ 247{
229 if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1) 248 if (skip != 0)
230 bb_copyfd_exact_size(zip_fd, -1, skip); 249 if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1)
250 bb_copyfd_exact_size(zip_fd, -1, skip);
231} 251}
232 252
233static void unzip_create_leading_dirs(const char *fn) 253static void unzip_create_leading_dirs(const char *fn)
@@ -528,21 +548,31 @@ int unzip_main(int argc, char **argv)
528 bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); 548 bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
529 } 549 }
530 550
531 { 551 if (cdf_offset != BAD_CDF_OFFSET) {
532 cdf_header_t cdf_header; 552 cdf_header_t cdf_header;
533 cdf_offset = read_next_cdf(cdf_offset, &cdf_header); 553 cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
554 /*
555 * Note: cdf_offset can become BAD_CDF_OFFSET after the above call.
556 */
534 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) { 557 if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
535 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten 558 /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
536 * only from Central Directory. See unzip_doc.txt */ 559 * only from Central Directory. See unzip_doc.txt
560 */
537 zip_header.formatted.crc32 = cdf_header.formatted.crc32; 561 zip_header.formatted.crc32 = cdf_header.formatted.crc32;
538 zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize; 562 zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize;
539 zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize; 563 zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
540 } 564 }
541 if ((cdf_header.formatted.version_made_by >> 8) == 3) { 565 if ((cdf_header.formatted.version_made_by >> 8) == 3) {
542 /* this archive is created on Unix */ 566 /* This archive is created on Unix */
543 dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16); 567 dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
544 } 568 }
545 } 569 }
570 if (cdf_offset == BAD_CDF_OFFSET
571 && (zip_header.formatted.zip_flags & SWAP_LE16(0x0008))
572 ) {
573 /* If it's a streaming zip, we _require_ CDF */
574 bb_error_msg_and_die("can't find file table");
575 }
546#endif 576#endif
547 577
548 /* Read filename */ 578 /* Read filename */
diff --git a/coreutils/catv.c b/coreutils/catv.c
index 214b4311a..e3499c597 100644
--- a/coreutils/catv.c
+++ b/coreutils/catv.c
@@ -25,14 +25,23 @@ int catv_main(int argc UNUSED_PARAM, char **argv)
25{ 25{
26 int retval = EXIT_SUCCESS; 26 int retval = EXIT_SUCCESS;
27 int fd; 27 int fd;
28 unsigned flags; 28 unsigned opts;
29
30 flags = getopt32(argv, "etv");
31#define CATV_OPT_e (1<<0) 29#define CATV_OPT_e (1<<0)
32#define CATV_OPT_t (1<<1) 30#define CATV_OPT_t (1<<1)
33#define CATV_OPT_v (1<<2) 31#define CATV_OPT_v (1<<2)
34 flags ^= CATV_OPT_v; 32 typedef char BUG_const_mismatch[
33 CATV_OPT_e == VISIBLE_ENDLINE && CATV_OPT_t == VISIBLE_SHOW_TABS
34 ? 1 : -1
35 ];
36
37 opts = getopt32(argv, "etv");
35 argv += optind; 38 argv += optind;
39#if 0 /* These consts match, we can just pass "opts" to visible() */
40 if (opts & CATV_OPT_e)
41 flags |= VISIBLE_ENDLINE;
42 if (opts & CATV_OPT_t)
43 flags |= VISIBLE_SHOW_TABS;
44#endif
36 45
37 /* Read from stdin if there's nothing else to do. */ 46 /* Read from stdin if there's nothing else to do. */
38 if (!argv[0]) 47 if (!argv[0])
@@ -50,29 +59,17 @@ int catv_main(int argc UNUSED_PARAM, char **argv)
50 res = read(fd, read_buf, COMMON_BUFSIZE); 59 res = read(fd, read_buf, COMMON_BUFSIZE);
51 if (res < 0) 60 if (res < 0)
52 retval = EXIT_FAILURE; 61 retval = EXIT_FAILURE;
53 if (res < 1) 62 if (res <= 0)
54 break; 63 break;
55 for (i = 0; i < res; i++) { 64 for (i = 0; i < res; i++) {
56 unsigned char c = read_buf[i]; 65 unsigned char c = read_buf[i];
57 66 if (opts & CATV_OPT_v) {
58 if (c > 126 && (flags & CATV_OPT_v)) { 67 putchar(c);
59 if (c == 127) { 68 } else {
60 printf("^?"); 69 char buf[sizeof("M-^c")];
61 continue; 70 visible(c, buf, opts);
62 } 71 fputs(buf, stdout);
63 printf("M-");
64 c -= 128;
65 }
66 if (c < 32) {
67 if (c == 10) {
68 if (flags & CATV_OPT_e)
69 bb_putchar('$');
70 } else if (flags & (c==9 ? CATV_OPT_t : CATV_OPT_v)) {
71 printf("^%c", c+'@');
72 continue;
73 }
74 } 72 }
75 bb_putchar(c);
76 } 73 }
77 } 74 }
78 if (ENABLE_FEATURE_CLEAN_UP && fd) 75 if (ENABLE_FEATURE_CLEAN_UP && fd)
diff --git a/coreutils/dd.c b/coreutils/dd.c
index f6869cb26..db61f665e 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -30,10 +30,10 @@
30//usage: "\n conv=noerror Continue after read errors" 30//usage: "\n conv=noerror Continue after read errors"
31//usage: "\n conv=sync Pad blocks with zeros" 31//usage: "\n conv=sync Pad blocks with zeros"
32//usage: "\n conv=fsync Physically write data out before finishing" 32//usage: "\n conv=fsync Physically write data out before finishing"
33//usage: "\n conv=swab Swap every pair of bytes"
33//usage: ) 34//usage: )
34//usage: "\n" 35//usage: "\n"
35//usage: "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024)," 36//usage: "\nN may be suffixed by c (1), w (2), b (512), kD (1000), k (1024), MD, M, GD, G"
36//usage: "\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)"
37//usage: 37//usage:
38//usage:#define dd_example_usage 38//usage:#define dd_example_usage
39//usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" 39//usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n"
@@ -151,13 +151,14 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
151 enum { 151 enum {
152 /* Must be in the same order as OP_conv_XXX! */ 152 /* Must be in the same order as OP_conv_XXX! */
153 /* (see "flags |= (1 << what)" below) */ 153 /* (see "flags |= (1 << what)" below) */
154 FLAG_NOTRUNC = 1 << 0, 154 FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS,
155 FLAG_SYNC = 1 << 1, 155 FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS,
156 FLAG_NOERROR = 1 << 2, 156 FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS,
157 FLAG_FSYNC = 1 << 3, 157 FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS,
158 FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS,
158 /* end of conv flags */ 159 /* end of conv flags */
159 FLAG_TWOBUFS = 1 << 4, 160 FLAG_TWOBUFS = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
160 FLAG_COUNT = 1 << 5, 161 FLAG_COUNT = 1 << 6,
161 }; 162 };
162 static const char keywords[] ALIGN1 = 163 static const char keywords[] ALIGN1 =
163 "bs\0""count\0""seek\0""skip\0""if\0""of\0" 164 "bs\0""count\0""seek\0""skip\0""if\0""of\0"
@@ -167,7 +168,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
167 ; 168 ;
168#if ENABLE_FEATURE_DD_IBS_OBS 169#if ENABLE_FEATURE_DD_IBS_OBS
169 static const char conv_words[] ALIGN1 = 170 static const char conv_words[] ALIGN1 =
170 "notrunc\0""sync\0""noerror\0""fsync\0"; 171 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
171#endif 172#endif
172 enum { 173 enum {
173 OP_bs = 0, 174 OP_bs = 0,
@@ -185,11 +186,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
185 OP_conv_sync, 186 OP_conv_sync,
186 OP_conv_noerror, 187 OP_conv_noerror,
187 OP_conv_fsync, 188 OP_conv_fsync,
189 OP_conv_swab,
188 /* Unimplemented conv=XXX: */ 190 /* Unimplemented conv=XXX: */
189 //nocreat do not create the output file 191 //nocreat do not create the output file
190 //excl fail if the output file already exists 192 //excl fail if the output file already exists
191 //fdatasync physically write output file data before finishing 193 //fdatasync physically write output file data before finishing
192 //swab swap every pair of input bytes
193 //lcase change upper case to lower case 194 //lcase change upper case to lower case
194 //ucase change lower case to upper case 195 //ucase change lower case to upper case
195 //block pad newline-terminated records with spaces to cbs-size 196 //block pad newline-terminated records with spaces to cbs-size
@@ -197,23 +198,34 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
197 //ascii from EBCDIC to ASCII 198 //ascii from EBCDIC to ASCII
198 //ebcdic from ASCII to EBCDIC 199 //ebcdic from ASCII to EBCDIC
199 //ibm from ASCII to alternate EBCDIC 200 //ibm from ASCII to alternate EBCDIC
201 /* Partially implemented: */
202 //swab swap every pair of input bytes: will abort on non-even reads
200#endif 203#endif
201 }; 204 };
202 int exitcode = EXIT_FAILURE; 205 smallint exitcode = EXIT_FAILURE;
203 int devzero = 0; 206 int devzero = 0;
204 size_t ibs = 512, obs = 512; 207 int i;
205 ssize_t n, w; 208 size_t ibs = 512;
206 char *ibuf, *obuf; 209 char *ibuf;
207 /* And these are all zeroed at once! */ 210#if ENABLE_FEATURE_DD_IBS_OBS
211 size_t obs = 512;
212 char *obuf;
213#else
214# define obs ibs
215# define obuf ibuf
216#endif
217 /* These are all zeroed at once! */
208 struct { 218 struct {
209 int flags; 219 int flags;
210 size_t oc; 220 size_t oc;
221 ssize_t prev_read_size; /* for detecting swab failure */
211 off_t count; 222 off_t count;
212 off_t seek, skip; 223 off_t seek, skip;
213 const char *infile, *outfile; 224 const char *infile, *outfile;
214 } Z; 225 } Z;
215#define flags (Z.flags ) 226#define flags (Z.flags )
216#define oc (Z.oc ) 227#define oc (Z.oc )
228#define prev_read_size (Z.prev_read_size)
217#define count (Z.count ) 229#define count (Z.count )
218#define seek (Z.seek ) 230#define seek (Z.seek )
219#define skip (Z.skip ) 231#define skip (Z.skip )
@@ -224,10 +236,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
224 INIT_G(); 236 INIT_G();
225 //fflush_all(); - is this needed because of NOEXEC? 237 //fflush_all(); - is this needed because of NOEXEC?
226 238
227 for (n = 1; argv[n]; n++) { 239 for (i = 1; argv[i]; i++) {
228 int what; 240 int what;
229 char *val; 241 char *val;
230 char *arg = argv[n]; 242 char *arg = argv[i];
231 243
232#if ENABLE_DESKTOP 244#if ENABLE_DESKTOP
233 /* "dd --". NB: coreutils 6.9 will complain if they see 245 /* "dd --". NB: coreutils 6.9 will complain if they see
@@ -256,6 +268,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
256 } 268 }
257 if (what == OP_conv) { 269 if (what == OP_conv) {
258 while (1) { 270 while (1) {
271 int n;
259 /* find ',', replace them with NUL so we can use val for 272 /* find ',', replace them with NUL so we can use val for
260 * index_in_strings() without copying. 273 * index_in_strings() without copying.
261 * We rely on val being non-null, else strchr would fault. 274 * We rely on val being non-null, else strchr would fault.
@@ -263,20 +276,21 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
263 arg = strchr(val, ','); 276 arg = strchr(val, ',');
264 if (arg) 277 if (arg)
265 *arg = '\0'; 278 *arg = '\0';
266 what = index_in_strings(conv_words, val); 279 n = index_in_strings(conv_words, val);
267 if (what < 0) 280 if (n < 0)
268 bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); 281 bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv");
269 flags |= (1 << what); 282 flags |= (1 << n);
270 if (!arg) /* no ',' left, so this was the last specifier */ 283 if (!arg) /* no ',' left, so this was the last specifier */
271 break; 284 break;
272 /* *arg = ','; - to preserve ps listing? */ 285 /* *arg = ','; - to preserve ps listing? */
273 val = arg + 1; /* skip this keyword and ',' */ 286 val = arg + 1; /* skip this keyword and ',' */
274 } 287 }
275 continue; /* we trashed 'what', can't fall through */ 288 /*continue;*/
276 } 289 }
277#endif 290#endif
278 if (what == OP_bs) { 291 if (what == OP_bs) {
279 ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); 292 ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
293 obs = ibs;
280 /*continue;*/ 294 /*continue;*/
281 } 295 }
282 /* These can be large: */ 296 /* These can be large: */
@@ -301,14 +315,17 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
301 outfile = val; 315 outfile = val;
302 /*continue;*/ 316 /*continue;*/
303 } 317 }
304 } /* end of "for (argv[n])" */ 318 } /* end of "for (argv[i])" */
305 319
306//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever 320//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
307 ibuf = obuf = xmalloc(ibs); 321 ibuf = xmalloc(ibs);
322 obuf = ibuf;
323#if ENABLE_FEATURE_DD_IBS_OBS
308 if (ibs != obs) { 324 if (ibs != obs) {
309 flags |= FLAG_TWOBUFS; 325 flags |= FLAG_TWOBUFS;
310 obuf = xmalloc(obs); 326 obuf = xmalloc(obs);
311 } 327 }
328#endif
312 329
313#if ENABLE_FEATURE_DD_SIGNAL_HANDLING 330#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
314 signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); 331 signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
@@ -317,17 +334,17 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
317 G.begin_time_us = monotonic_us(); 334 G.begin_time_us = monotonic_us();
318#endif 335#endif
319 336
320 if (infile != NULL) 337 if (infile) {
321 if (ENABLE_PLATFORM_MINGW32 && !strcmp(infile, "/dev/zero")) { 338 if (ENABLE_PLATFORM_MINGW32 && !strcmp(infile, "/dev/zero")) {
322 flags |= FLAG_NOERROR; 339 flags |= FLAG_NOERROR;
323 devzero = 1; 340 devzero = 1;
324 } 341 } else {
325 else
326 xmove_fd(xopen(infile, O_RDONLY), ifd); 342 xmove_fd(xopen(infile, O_RDONLY), ifd);
327 else { 343 }
344 } else {
328 infile = bb_msg_standard_input; 345 infile = bb_msg_standard_input;
329 } 346 }
330 if (outfile != NULL) { 347 if (outfile) {
331 int oflag = O_WRONLY | O_CREAT; 348 int oflag = O_WRONLY | O_CREAT;
332 349
333 if (!seek && !(flags & FLAG_NOTRUNC)) 350 if (!seek && !(flags & FLAG_NOTRUNC))
@@ -352,13 +369,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
352 } 369 }
353 if (skip && !devzero) { 370 if (skip && !devzero) {
354 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) { 371 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
355 while (skip-- > 0) { 372 do {
356 n = safe_read(ifd, ibuf, ibs); 373 ssize_t n = safe_read(ifd, ibuf, ibs);
357 if (n < 0) 374 if (n < 0)
358 goto die_infile; 375 goto die_infile;
359 if (n == 0) 376 if (n == 0)
360 break; 377 break;
361 } 378 } while (--skip != 0);
362 } 379 }
363 } 380 }
364 if (seek) { 381 if (seek) {
@@ -367,6 +384,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
367 } 384 }
368 385
369 while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 386 while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
387 ssize_t n;
388
370 if (devzero) { 389 if (devzero) {
371 memset(ibuf, 0, ibs); 390 memset(ibuf, 0, ibs);
372 n = ibs; 391 n = ibs;
@@ -386,6 +405,27 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
386 * conv=noerror just ignores input bad blocks */ 405 * conv=noerror just ignores input bad blocks */
387 n = 0; 406 n = 0;
388 } 407 }
408 if (flags & FLAG_SWAB) {
409 uint16_t *p16;
410 ssize_t n2;
411
412 /* Our code allows only last read to be odd-sized */
413 if (prev_read_size & 1)
414 bb_error_msg_and_die("can't swab %lu byte buffer",
415 (unsigned long)prev_read_size);
416 prev_read_size = n;
417
418 /* If n is odd, last byte is not swapped:
419 * echo -n "qwe" | dd conv=swab
420 * prints "wqe".
421 */
422 p16 = (void*) ibuf;
423 n2 = (n >> 1);
424 while (--n2 >= 0) {
425 *p16 = bswap_16(*p16);
426 p16++;
427 }
428 }
389 if ((size_t)n == ibs) 429 if ((size_t)n == ibs)
390 G.in_full++; 430 G.in_full++;
391 else { 431 else {
@@ -412,8 +452,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
412 oc = 0; 452 oc = 0;
413 } 453 }
414 } 454 }
415 } else if (write_and_stats(ibuf, n, obs, outfile)) 455 } else {
416 goto out_status; 456 if (write_and_stats(ibuf, n, obs, outfile))
457 goto out_status;
458 }
417 459
418 if (flags & FLAG_FSYNC) { 460 if (flags & FLAG_FSYNC) {
419 if (fsync(ofd) < 0) 461 if (fsync(ofd) < 0)
@@ -422,9 +464,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
422 } 464 }
423 465
424 if (ENABLE_FEATURE_DD_IBS_OBS && oc) { 466 if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
425 w = full_write_or_warn(obuf, oc, outfile); 467 if (write_and_stats(obuf, oc, obs, outfile))
426 if (w < 0) goto out_status; 468 goto out_status;
427 if (w > 0) G.out_part++;
428 } 469 }
429 470
430 if (!devzero && close(ifd) < 0) { 471 if (!devzero && close(ifd) < 0) {
diff --git a/coreutils/head.c b/coreutils/head.c
index 291e1ce37..9388b026a 100644
--- a/coreutils/head.c
+++ b/coreutils/head.c
@@ -12,7 +12,6 @@
12/* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ 12/* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */
13 13
14//kbuild:lib-$(CONFIG_HEAD) += head.o 14//kbuild:lib-$(CONFIG_HEAD) += head.o
15//kbuild:lib-$(CONFIG_HEAD) += head_tail.o
16 15
17//usage:#define head_trivial_usage 16//usage:#define head_trivial_usage
18//usage: "[OPTIONS] [FILE]..." 17//usage: "[OPTIONS] [FILE]..."
@@ -35,7 +34,6 @@
35//usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" 34//usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
36 35
37#include "libbb.h" 36#include "libbb.h"
38#include "head_tail.h"
39 37
40/* This is a NOEXEC applet. Be very careful! */ 38/* This is a NOEXEC applet. Be very careful! */
41 39
@@ -140,7 +138,7 @@ eat_num(bool *negative_N, const char *p)
140 p++; 138 p++;
141 } 139 }
142#endif 140#endif
143 return xatoul_sfx(p, head_tail_suffixes); 141 return xatoul_sfx(p, bkm_suffixes);
144} 142}
145 143
146static const char head_opts[] ALIGN1 = 144static const char head_opts[] ALIGN1 =
diff --git a/coreutils/head_tail.c b/coreutils/head_tail.c
deleted file mode 100644
index 1658c0d1b..000000000
--- a/coreutils/head_tail.c
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * Copyright (C) 2013 Denys Vlasenko
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6#include "libbb.h"
7#include "head_tail.h"
8
9const struct suffix_mult head_tail_suffixes[] = {
10 { "b", 512 },
11 { "k", 1024 },
12 { "m", 1024*1024 },
13 { "", 0 }
14};
diff --git a/coreutils/head_tail.h b/coreutils/head_tail.h
deleted file mode 100644
index df19e41e0..000000000
--- a/coreutils/head_tail.h
+++ /dev/null
@@ -1,6 +0,0 @@
1/*
2 * Copyright (C) 2013 Denys Vlasenko
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6extern const struct suffix_mult head_tail_suffixes[];
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index 92a4d4462..1a5342e87 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -151,7 +151,9 @@ static uint8_t *hash_file(const char *filename)
151 update(&context, in_buf, count); 151 update(&context, in_buf, count);
152 } 152 }
153 hash_value = NULL; 153 hash_value = NULL;
154 if (count == 0) { 154 if (count < 0)
155 bb_perror_msg("can't read '%s'", filename);
156 else /* count == 0 */ {
155 final(&context, in_buf); 157 final(&context, in_buf);
156 hash_value = hash_bin_to_hex(in_buf, hash_len); 158 hash_value = hash_bin_to_hex(in_buf, hash_len);
157 } 159 }
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index ee4f72ca1..c4d11601f 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -1173,12 +1173,6 @@ parse_old_offset(const char *s, off_t *offset)
1173int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1173int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1174int od_main(int argc UNUSED_PARAM, char **argv) 1174int od_main(int argc UNUSED_PARAM, char **argv)
1175{ 1175{
1176 static const struct suffix_mult bkm[] = {
1177 { "b", 512 },
1178 { "k", 1024 },
1179 { "m", 1024*1024 },
1180 { "", 0 }
1181 };
1182#if ENABLE_LONG_OPTS 1176#if ENABLE_LONG_OPTS
1183 static const char od_longopts[] ALIGN1 = 1177 static const char od_longopts[] ALIGN1 =
1184 "skip-bytes\0" Required_argument "j" 1178 "skip-bytes\0" Required_argument "j"
@@ -1237,7 +1231,7 @@ int od_main(int argc UNUSED_PARAM, char **argv)
1237 address_pad_len_char = doxn_address_pad_len_char[pos]; 1231 address_pad_len_char = doxn_address_pad_len_char[pos];
1238 } 1232 }
1239 if (opt & OPT_N) { 1233 if (opt & OPT_N) {
1240 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm); 1234 max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes);
1241 } 1235 }
1242 if (opt & OPT_a) decode_format_string("a"); 1236 if (opt & OPT_a) decode_format_string("a");
1243 if (opt & OPT_b) decode_format_string("oC"); 1237 if (opt & OPT_b) decode_format_string("oC");
@@ -1246,7 +1240,7 @@ int od_main(int argc UNUSED_PARAM, char **argv)
1246 if (opt & OPT_f) decode_format_string("fF"); 1240 if (opt & OPT_f) decode_format_string("fF");
1247 if (opt & OPT_h) decode_format_string("x2"); 1241 if (opt & OPT_h) decode_format_string("x2");
1248 if (opt & OPT_i) decode_format_string("d2"); 1242 if (opt & OPT_i) decode_format_string("d2");
1249 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm); 1243 if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes);
1250 if (opt & OPT_l) decode_format_string("d4"); 1244 if (opt & OPT_l) decode_format_string("d4");
1251 if (opt & OPT_o) decode_format_string("o2"); 1245 if (opt & OPT_o) decode_format_string("o2");
1252 while (lst_t) { 1246 while (lst_t) {
@@ -1255,7 +1249,7 @@ int od_main(int argc UNUSED_PARAM, char **argv)
1255 if (opt & OPT_x) decode_format_string("x2"); 1249 if (opt & OPT_x) decode_format_string("x2");
1256 if (opt & OPT_s) decode_format_string("d2"); 1250 if (opt & OPT_s) decode_format_string("d2");
1257 if (opt & OPT_S) { 1251 if (opt & OPT_S) {
1258 string_min = xstrtou_sfx(str_S, 0, bkm); 1252 string_min = xstrtou_sfx(str_S, 0, bkm_suffixes);
1259 } 1253 }
1260 1254
1261 // Bloat: 1255 // Bloat:
diff --git a/coreutils/split.c b/coreutils/split.c
index 11e640442..1e1673efb 100644
--- a/coreutils/split.c
+++ b/coreutils/split.c
@@ -23,17 +23,15 @@
23 23
24#include "libbb.h" 24#include "libbb.h"
25 25
26static const struct suffix_mult split_suffices[] = {
27#if ENABLE_FEATURE_SPLIT_FANCY 26#if ENABLE_FEATURE_SPLIT_FANCY
27static const struct suffix_mult split_suffixes[] = {
28 { "b", 512 }, 28 { "b", 512 },
29#endif
30 { "k", 1024 }, 29 { "k", 1024 },
31 { "m", 1024*1024 }, 30 { "m", 1024*1024 },
32#if ENABLE_FEATURE_SPLIT_FANCY
33 { "g", 1024*1024*1024 }, 31 { "g", 1024*1024*1024 },
34#endif
35 { "", 0 } 32 { "", 0 }
36}; 33};
34#endif
37 35
38/* Increment the suffix part of the filename. 36/* Increment the suffix part of the filename.
39 * Returns NULL if we are out of filenames. 37 * Returns NULL if we are out of filenames.
@@ -86,7 +84,10 @@ int split_main(int argc UNUSED_PARAM, char **argv)
86 if (opt & SPLIT_OPT_l) 84 if (opt & SPLIT_OPT_l)
87 cnt = XATOOFF(count_p); 85 cnt = XATOOFF(count_p);
88 if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF 86 if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF
89 cnt = xatoull_sfx(count_p, split_suffices); 87 cnt = xatoull_sfx(count_p,
88 IF_FEATURE_SPLIT_FANCY(split_suffixes)
89 IF_NOT_FEATURE_SPLIT_FANCY(km_suffixes)
90 );
90 sfx = "x"; 91 sfx = "x";
91 92
92 argv += optind; 93 argv += optind;
diff --git a/coreutils/stty.c b/coreutils/stty.c
index 96754dd84..378a848e7 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -246,10 +246,21 @@ enum speed_setting {
246 246
247/* Which member(s) of 'struct termios' a mode uses */ 247/* Which member(s) of 'struct termios' a mode uses */
248enum { 248enum {
249 /* Do NOT change the order or values, as mode_type_flag()
250 * depends on them */
251 control, input, output, local, combination 249 control, input, output, local, combination
252}; 250};
251static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
252{
253 static const uint8_t tcflag_offsets[] ALIGN1 = {
254 offsetof(struct termios, c_cflag), /* control */
255 offsetof(struct termios, c_iflag), /* input */
256 offsetof(struct termios, c_oflag), /* output */
257 offsetof(struct termios, c_lflag) /* local */
258 };
259 if (type <= local) {
260 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
261 }
262 return NULL;
263}
253 264
254/* Flags for 'struct mode_info' */ 265/* Flags for 'struct mode_info' */
255#define SANE_SET 1 /* Set in 'sane' mode */ 266#define SANE_SET 1 /* Set in 'sane' mode */
@@ -770,51 +781,6 @@ struct globals {
770 G.max_col = 80; \ 781 G.max_col = 80; \
771} while (0) 782} while (0)
772 783
773
774/* Return a string that is the printable representation of character CH */
775/* Adapted from 'cat' by Torbjorn Granlund */
776static const char *visible(unsigned ch)
777{
778 char *bpout = G.buf;
779
780 if (ch == _POSIX_VDISABLE)
781 return "<undef>";
782
783 if (ch >= 128) {
784 ch -= 128;
785 *bpout++ = 'M';
786 *bpout++ = '-';
787 }
788
789 if (ch < 32) {
790 *bpout++ = '^';
791 *bpout++ = ch + 64;
792 } else if (ch < 127) {
793 *bpout++ = ch;
794 } else {
795 *bpout++ = '^';
796 *bpout++ = '?';
797 }
798
799 *bpout = '\0';
800 return G.buf;
801}
802
803static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
804{
805 static const uint8_t tcflag_offsets[] ALIGN1 = {
806 offsetof(struct termios, c_cflag), /* control */
807 offsetof(struct termios, c_iflag), /* input */
808 offsetof(struct termios, c_oflag), /* output */
809 offsetof(struct termios, c_lflag) /* local */
810 };
811
812 if (type <= local) {
813 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
814 }
815 return NULL;
816}
817
818static void set_speed_or_die(enum speed_setting type, const char *arg, 784static void set_speed_or_die(enum speed_setting type, const char *arg,
819 struct termios *mode) 785 struct termios *mode)
820{ 786{
@@ -1042,6 +1008,7 @@ static void do_display(const struct termios *mode, int all)
1042#endif 1008#endif
1043 1009
1044 for (i = 0; i != CIDX_min; ++i) { 1010 for (i = 0; i != CIDX_min; ++i) {
1011 char ch;
1045 /* If swtch is the same as susp, don't print both */ 1012 /* If swtch is the same as susp, don't print both */
1046#if VSWTCH == VSUSP 1013#if VSWTCH == VSUSP
1047 if (i == CIDX_swtch) 1014 if (i == CIDX_swtch)
@@ -1055,8 +1022,12 @@ static void do_display(const struct termios *mode, int all)
1055 continue; 1022 continue;
1056 } 1023 }
1057#endif 1024#endif
1058 wrapf("%s = %s;", nth_string(control_name, i), 1025 ch = mode->c_cc[control_info[i].offset];
1059 visible(mode->c_cc[control_info[i].offset])); 1026 if (ch == _POSIX_VDISABLE)
1027 strcpy(G.buf, "<undef>");
1028 else
1029 visible(ch, G.buf, 0);
1030 wrapf("%s = %s;", nth_string(control_name, i), G.buf);
1060 } 1031 }
1061#if VEOF == VMIN 1032#if VEOF == VMIN
1062 if ((mode->c_lflag & ICANON) == 0) 1033 if ((mode->c_lflag & ICANON) == 0)
@@ -1072,7 +1043,7 @@ static void do_display(const struct termios *mode, int all)
1072 prev_type = mode_info[i].type; 1043 prev_type = mode_info[i].type;
1073 } 1044 }
1074 1045
1075 bitsp = mode_type_flag(mode_info[i].type, mode); 1046 bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1076 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; 1047 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1077 if ((*bitsp & mask) == mode_info[i].bits) { 1048 if ((*bitsp & mask) == mode_info[i].bits) {
1078 if (all || (mode_info[i].flags & SANE_UNSET)) 1049 if (all || (mode_info[i].flags & SANE_UNSET))
@@ -1091,7 +1062,6 @@ static void do_display(const struct termios *mode, int all)
1091static void sane_mode(struct termios *mode) 1062static void sane_mode(struct termios *mode)
1092{ 1063{
1093 int i; 1064 int i;
1094 tcflag_t *bitsp;
1095 1065
1096 for (i = 0; i < NUM_control_info; ++i) { 1066 for (i = 0; i < NUM_control_info; ++i) {
1097#if VMIN == VEOF 1067#if VMIN == VEOF
@@ -1102,14 +1072,17 @@ static void sane_mode(struct termios *mode)
1102 } 1072 }
1103 1073
1104 for (i = 0; i < NUM_mode_info; ++i) { 1074 for (i = 0; i < NUM_mode_info; ++i) {
1075 tcflag_t val;
1076 tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1077
1078 if (!bitsp)
1079 continue;
1080 val = *bitsp & ~((unsigned long)mode_info[i].mask);
1105 if (mode_info[i].flags & SANE_SET) { 1081 if (mode_info[i].flags & SANE_SET) {
1106 bitsp = mode_type_flag(mode_info[i].type, mode); 1082 *bitsp = val | mode_info[i].bits;
1107 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) 1083 } else
1108 | mode_info[i].bits; 1084 if (mode_info[i].flags & SANE_UNSET) {
1109 } else if (mode_info[i].flags & SANE_UNSET) { 1085 *bitsp = val & ~mode_info[i].bits;
1110 bitsp = mode_type_flag(mode_info[i].type, mode);
1111 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1112 & ~mode_info[i].bits;
1113 } 1086 }
1114 } 1087 }
1115} 1088}
@@ -1119,17 +1092,18 @@ static void set_mode(const struct mode_info *info, int reversed,
1119{ 1092{
1120 tcflag_t *bitsp; 1093 tcflag_t *bitsp;
1121 1094
1122 bitsp = mode_type_flag(info->type, mode); 1095 bitsp = get_ptr_to_tcflag(info->type, mode);
1123 1096
1124 if (bitsp) { 1097 if (bitsp) {
1098 tcflag_t val = *bitsp & ~info->mask;
1125 if (reversed) 1099 if (reversed)
1126 *bitsp = *bitsp & ~info->mask & ~info->bits; 1100 *bitsp = val & ~info->bits;
1127 else 1101 else
1128 *bitsp = (*bitsp & ~info->mask) | info->bits; 1102 *bitsp = val | info->bits;
1129 return; 1103 return;
1130 } 1104 }
1131 1105
1132 /* Combination mode */ 1106 /* !bitsp - it's a "combination" mode */
1133 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) { 1107 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1134 if (reversed) 1108 if (reversed)
1135 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 1109 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
@@ -1534,7 +1508,12 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1534 perror_on_device_and_die("%s"); 1508 perror_on_device_and_die("%s");
1535 1509
1536 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { 1510 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1537#if CIBAUD 1511/*
1512 * I think the below chunk is not necessary on Linux.
1513 * If you are deleting it, also delete STTY_speed_was_set bit -
1514 * it is only ever checked here.
1515 */
1516#if 0 /* was "if CIBAUD" */
1538 /* SunOS 4.1.3 (at least) has the problem that after this sequence, 1517 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1539 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); 1518 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1540 sometimes (m1 != m2). The only difference is in the four bits 1519 sometimes (m1 != m2). The only difference is in the four bits
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 19fd8f695..07c71ca4b 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -25,7 +25,6 @@
25 */ 25 */
26 26
27//kbuild:lib-$(CONFIG_TAIL) += tail.o 27//kbuild:lib-$(CONFIG_TAIL) += tail.o
28//kbuild:lib-$(CONFIG_TAIL) += head_tail.o
29 28
30//usage:#define tail_trivial_usage 29//usage:#define tail_trivial_usage
31//usage: "[OPTIONS] [FILE]..." 30//usage: "[OPTIONS] [FILE]..."
@@ -51,7 +50,6 @@
51//usage: "nameserver 10.0.0.1\n" 50//usage: "nameserver 10.0.0.1\n"
52 51
53#include "libbb.h" 52#include "libbb.h"
54#include "head_tail.h"
55 53
56struct globals { 54struct globals {
57 bool from_top; 55 bool from_top;
@@ -69,15 +67,6 @@ static void tail_xprint_header(const char *fmt, const char *filename)
69static ssize_t tail_read(int fd, char *buf, size_t count) 67static ssize_t tail_read(int fd, char *buf, size_t count)
70{ 68{
71 ssize_t r; 69 ssize_t r;
72 off_t current;
73 struct stat sbuf;
74
75 /* /proc files report zero st_size, don't lseek them. */
76 if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) {
77 current = lseek(fd, 0, SEEK_CUR);
78 if (sbuf.st_size < current)
79 xlseek(fd, 0, SEEK_SET);
80 }
81 70
82 r = full_read(fd, buf, count); 71 r = full_read(fd, buf, count);
83 if (r < 0) { 72 if (r < 0) {
@@ -98,7 +87,7 @@ static unsigned eat_num(const char *p)
98 p++; 87 p++;
99 G.from_top = 1; 88 G.from_top = 1;
100 } 89 }
101 return xatou_sfx(p, head_tail_suffixes); 90 return xatou_sfx(p, bkm_suffixes);
102} 91}
103 92
104int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 93int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -363,7 +352,19 @@ int tail_main(int argc, char **argv)
363 if (nfiles > header_threshhold) { 352 if (nfiles > header_threshhold) {
364 fmt = header_fmt_str; 353 fmt = header_fmt_str;
365 } 354 }
366 while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) { 355 for (;;) {
356 /* tail -f keeps following files even if they are truncated */
357 struct stat sbuf;
358 /* /proc files report zero st_size, don't lseek them */
359 if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) {
360 off_t current = lseek(fd, 0, SEEK_CUR);
361 if (sbuf.st_size < current)
362 xlseek(fd, 0, SEEK_SET);
363 }
364
365 nread = tail_read(fd, tailbuf, BUFSIZ);
366 if (nread <= 0)
367 break;
367 if (fmt) { 368 if (fmt) {
368 tail_xprint_header(fmt, filename); 369 tail_xprint_header(fmt, filename);
369 fmt = NULL; 370 fmt = NULL;
diff --git a/docs/tcp.txt b/docs/tcp.txt
new file mode 100644
index 000000000..766766387
--- /dev/null
+++ b/docs/tcp.txt
@@ -0,0 +1,82 @@
1 Some less-widely known details of TCP connections.
2
3 Properly closing the connection.
4
5After this code sequence:
6
7 sock = socket(AF_INET, SOCK_STREAM, 0);
8 connect(sock, &remote, sizeof(remote));
9 write(sock, buffer, 1000000);
10
11a large block of data is only buffered by kernel, it can't be sent all at once.
12What will happen if we close the socket?
13
14"A host MAY implement a 'half-duplex' TCP close sequence, so that
15 an application that has called close() cannot continue to read
16 data from the connection. If such a host issues a close() call
17 while received data is still pending in TCP, or if new data is
18 received after close() is called, its TCP SHOULD send a RST
19 to show that data was lost."
20
21IOW: if we just close(sock) now, kernel can reset the TCP connection,
22discarding some not-yet sent data.
23
24What can be done about it?
25
26Solution #1: block until sending is done:
27
28 /* When enabled, a close(2) or shutdown(2) will not return until
29 * all queued messages for the socket have been successfully sent
30 * or the linger timeout has been reached.
31 */
32 struct linger {
33 int l_onoff; /* linger active */
34 int l_linger; /* how many seconds to linger for */
35 } linger;
36 linger.l_onoff = 1;
37 linger.l_linger = SOME_NUM;
38 setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
39 close(sock);
40
41Solution #2: tell kernel that you are done sending.
42This makes kernel send FIN after all data is written:
43
44 shutdown(sock, SHUT_WR);
45 close(sock);
46
47However, experiments on Linux 3.9.4 show that kernel can return from
48shutdown() and from close() before all data is sent,
49and if peer sends any data to us after this, kernel stll responds with
50RST before all our data is sent.
51
52In practice the protocol in use often does not allow peer to send
53such data to us, in which case this solution is acceptable.
54
55If you know that peer is going to close its end after it sees our FIN
56(as EOF), it might be a good idea to perform a read after shutdown().
57When read finishes with 0-sized result, we conclude that peer received all
58the data, saw EOF, and closed its end.
59
60However, this incurs small performance penalty (we run for a longer time)
61and requires safeguards (nonblocking reads, timeouts etc) against
62malicious peers which don't close the connection.
63
64
65 Defeating Nagle.
66
67Method #1: manually control whether partial sends are allowed:
68
69This prevents partially filled packets being sent:
70
71 int state = 1;
72 setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
73
74and this forces last, partially filled packet (if any) to be sent:
75
76 int state = 0;
77 setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
78
79Method #2: make any write to immediately send data, even if it's partial:
80
81 int state = 1;
82 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &state, sizeof(state));
diff --git a/editors/awk.c b/editors/awk.c
index 0b573a065..77784dfc1 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -190,7 +190,7 @@ typedef struct tsplitter_s {
190 190
191/* combined token classes */ 191/* combined token classes */
192#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) 192#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
193#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) 193//#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
194#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ 194#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
195 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER) 195 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
196 196
@@ -2015,8 +2015,8 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i
2015 char c; 2015 char c;
2016 const char *s = format; 2016 const char *s = format;
2017 2017
2018 if (int_as_int && n == (int)n) { 2018 if (int_as_int && n == (long long)n) {
2019 r = snprintf(b, size, "%d", (int)n); 2019 r = snprintf(b, size, "%lld", (long long)n);
2020 } else { 2020 } else {
2021 do { c = *s; } while (c && *++s); 2021 do { c = *s; } while (c && *++s);
2022 if (strchr("diouxX", c)) { 2022 if (strchr("diouxX", c)) {
@@ -2662,7 +2662,7 @@ static var *evaluate(node *op, var *res)
2662 const char *sv_progname; 2662 const char *sv_progname;
2663 2663
2664 /* The body might be empty, still has to eval the args */ 2664 /* The body might be empty, still has to eval the args */
2665 if (!op->r.n->info) 2665 if (!op->r.n->info && !op->r.f->body.first)
2666 syntax_error(EMSG_UNDEF_FUNC); 2666 syntax_error(EMSG_UNDEF_FUNC);
2667 2667
2668 vbeg = v = nvalloc(op->r.f->nargs + 1); 2668 vbeg = v = nvalloc(op->r.f->nargs + 1);
@@ -2733,7 +2733,7 @@ static var *evaluate(node *op, var *res)
2733 2733
2734 switch (opn) { 2734 switch (opn) {
2735 case F_in: 2735 case F_in:
2736 R_d = (int)L_d; 2736 R_d = (long long)L_d;
2737 break; 2737 break;
2738 2738
2739 case F_rn: 2739 case F_rn:
@@ -2931,7 +2931,7 @@ static var *evaluate(node *op, var *res)
2931 case '%': 2931 case '%':
2932 if (R_d == 0) 2932 if (R_d == 0)
2933 syntax_error(EMSG_DIV_BY_ZERO); 2933 syntax_error(EMSG_DIV_BY_ZERO);
2934 L_d -= (int)(L_d / R_d) * R_d; 2934 L_d -= (long long)(L_d / R_d) * R_d;
2935 break; 2935 break;
2936 } 2936 }
2937 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d); 2937 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
diff --git a/editors/sed.c b/editors/sed.c
index f8ca5d351..3a0d917aa 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -330,7 +330,7 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex)
330 next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); 330 next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
331 temp = copy_parsing_escapes(pos, next); 331 temp = copy_parsing_escapes(pos, next);
332 *regex = xzalloc(sizeof(regex_t)); 332 *regex = xzalloc(sizeof(regex_t));
333 xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); 333 xregcomp(*regex, temp, G.regex_type);
334 free(temp); 334 free(temp);
335 /* Move position to next character after last delimiter */ 335 /* Move position to next character after last delimiter */
336 pos += (next+1); 336 pos += (next+1);
@@ -649,6 +649,12 @@ static void add_cmd(const char *cmdstr)
649 sed_cmd->cmd = *cmdstr++; 649 sed_cmd->cmd = *cmdstr++;
650 cmdstr = parse_cmd_args(sed_cmd, cmdstr); 650 cmdstr = parse_cmd_args(sed_cmd, cmdstr);
651 651
652 /* cmdstr now points past args.
653 * GNU sed requires a separator, if there are more commands,
654 * else it complains "char N: extra characters after command".
655 * Example: "sed 'p;d'". We also allow "sed 'pd'".
656 */
657
652 /* Add the command to the command array */ 658 /* Add the command to the command array */
653 *G.sed_cmd_tail = sed_cmd; 659 *G.sed_cmd_tail = sed_cmd;
654 G.sed_cmd_tail = &sed_cmd->next; 660 G.sed_cmd_tail = &sed_cmd->next;
@@ -1371,7 +1377,7 @@ static void process_files(void)
1371/* It is possible to have a command line argument with embedded 1377/* It is possible to have a command line argument with embedded
1372 * newlines. This counts as multiple command lines. 1378 * newlines. This counts as multiple command lines.
1373 * However, newline can be escaped: 's/e/z\<newline>z/' 1379 * However, newline can be escaped: 's/e/z\<newline>z/'
1374 * We check for this. 1380 * add_cmd() handles this.
1375 */ 1381 */
1376 1382
1377static void add_cmd_block(char *cmdstr) 1383static void add_cmd_block(char *cmdstr)
@@ -1381,22 +1387,8 @@ static void add_cmd_block(char *cmdstr)
1381 cmdstr = sv = xstrdup(cmdstr); 1387 cmdstr = sv = xstrdup(cmdstr);
1382 do { 1388 do {
1383 eol = strchr(cmdstr, '\n'); 1389 eol = strchr(cmdstr, '\n');
1384 next: 1390 if (eol)
1385 if (eol) {
1386 /* Count preceding slashes */
1387 int slashes = 0;
1388 char *sl = eol;
1389
1390 while (sl != cmdstr && *--sl == '\\')
1391 slashes++;
1392 /* Odd number of preceding slashes - newline is escaped */
1393 if (slashes & 1) {
1394 overlapping_strcpy(eol - 1, eol);
1395 eol = strchr(eol, '\n');
1396 goto next;
1397 }
1398 *eol = '\0'; 1391 *eol = '\0';
1399 }
1400 add_cmd(cmdstr); 1392 add_cmd(cmdstr);
1401 cmdstr = eol + 1; 1393 cmdstr = eol + 1;
1402 } while (eol); 1394 } while (eol);
diff --git a/editors/vi.c b/editors/vi.c
index d6c8c0dd8..ab49b3f7d 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -1707,65 +1707,53 @@ static char *new_screen(int ro, int co)
1707// search for pattern starting at p 1707// search for pattern starting at p
1708static char *char_search(char *p, const char *pat, int dir, int range) 1708static char *char_search(char *p, const char *pat, int dir, int range)
1709{ 1709{
1710 char *q;
1711 struct re_pattern_buffer preg; 1710 struct re_pattern_buffer preg;
1711 const char *err;
1712 char *q;
1712 int i; 1713 int i;
1713 int size; 1714 int size;
1714 1715
1715 re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; 1716 re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
1716 preg.translate = 0; 1717 if (ignorecase)
1717 preg.fastmap = 0; 1718 re_syntax_options = RE_SYNTAX_POSIX_EXTENDED | RE_ICASE;
1718 preg.buffer = 0; 1719
1719 preg.allocated = 0; 1720 memset(&preg, 0, sizeof(preg));
1721 err = re_compile_pattern(pat, strlen(pat), &preg);
1722 if (err != NULL) {
1723 status_line_bold("bad search pattern '%s': %s", pat, err);
1724 return p;
1725 }
1720 1726
1721 // assume a LIMITED forward search 1727 // assume a LIMITED forward search
1722 q = next_line(p);
1723 q = end_line(q);
1724 q = end - 1; 1728 q = end - 1;
1725 if (dir == BACK) { 1729 if (dir == BACK)
1726 q = prev_line(p);
1727 q = text; 1730 q = text;
1728 }
1729 // count the number of chars to search over, forward or backward
1730 size = q - p;
1731 if (size < 0)
1732 size = p - q;
1733 // RANGE could be negative if we are searching backwards 1731 // RANGE could be negative if we are searching backwards
1734 range = q - p; 1732 range = q - p;
1735
1736 q = (char *)re_compile_pattern(pat, strlen(pat), (struct re_pattern_buffer *)&preg);
1737 if (q != 0) {
1738 // The pattern was not compiled
1739 status_line_bold("bad search pattern: '%s': %s", pat, q);
1740 i = 0; // return p if pattern not compiled
1741 goto cs1;
1742 }
1743
1744 q = p; 1733 q = p;
1734 size = range;
1745 if (range < 0) { 1735 if (range < 0) {
1736 size = -size;
1746 q = p - size; 1737 q = p - size;
1747 if (q < text) 1738 if (q < text)
1748 q = text; 1739 q = text;
1749 } 1740 }
1750 // search for the compiled pattern, preg, in p[] 1741 // search for the compiled pattern, preg, in p[]
1751 // range < 0- search backward 1742 // range < 0: search backward
1752 // range > 0- search forward 1743 // range > 0: search forward
1753 // 0 < start < size 1744 // 0 < start < size
1754 // re_search() < 0 not found or error 1745 // re_search() < 0: not found or error
1755 // re_search() > 0 index of found pattern 1746 // re_search() >= 0: index of found pattern
1756 // struct pattern char int int int struct reg 1747 // struct pattern char int int int struct reg
1757 // re_search (*pattern_buffer, *string, size, start, range, *regs) 1748 // re_search(*pattern_buffer, *string, size, start, range, *regs)
1758 i = re_search(&preg, q, size, 0, range, 0); 1749 i = re_search(&preg, q, size, /*start:*/ 0, range, /*struct re_registers*:*/ NULL);
1759 if (i == -1) { 1750 regfree(&preg);
1760 p = 0; 1751 if (i < 0)
1761 i = 0; // return NULL if pattern not found 1752 return NULL;
1762 } 1753 if (dir == FORWARD)
1763 cs1:
1764 if (dir == FORWARD) {
1765 p = p + i; 1754 p = p + i;
1766 } else { 1755 else
1767 p = p - i; 1756 p = p - i;
1768 }
1769 return p; 1757 return p;
1770} 1758}
1771 1759
@@ -1790,7 +1778,7 @@ static char *char_search(char *p, const char *pat, int dir, int range)
1790 1778
1791 len = strlen(pat); 1779 len = strlen(pat);
1792 if (dir == FORWARD) { 1780 if (dir == FORWARD) {
1793 stop = end - 1; // assume range is p - end-1 1781 stop = end - 1; // assume range is p..end-1
1794 if (range == LIMITED) 1782 if (range == LIMITED)
1795 stop = next_line(p); // range is to next line 1783 stop = next_line(p); // range is to next line
1796 for (start = p; start < stop; start++) { 1784 for (start = p; start < stop; start++) {
@@ -1799,7 +1787,7 @@ static char *char_search(char *p, const char *pat, int dir, int range)
1799 } 1787 }
1800 } 1788 }
1801 } else if (dir == BACK) { 1789 } else if (dir == BACK) {
1802 stop = text; // assume range is text - p 1790 stop = text; // assume range is text..p
1803 if (range == LIMITED) 1791 if (range == LIMITED)
1804 stop = prev_line(p); // range is to prev line 1792 stop = prev_line(p); // range is to prev line
1805 for (start = p - len; start >= stop; start--) { 1793 for (start = p - len; start >= stop; start--) {
diff --git a/findutils/find.c b/findutils/find.c
index 2235b5049..53d8239c7 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -231,12 +231,13 @@
231//kbuild:lib-$(CONFIG_FIND) += find.o 231//kbuild:lib-$(CONFIG_FIND) += find.o
232 232
233//usage:#define find_trivial_usage 233//usage:#define find_trivial_usage
234//usage: "[PATH]... [OPTIONS] [ACTIONS]" 234//usage: "[-HL] [PATH]... [OPTIONS] [ACTIONS]"
235//usage:#define find_full_usage "\n\n" 235//usage:#define find_full_usage "\n\n"
236//usage: "Search for files and perform actions on them.\n" 236//usage: "Search for files and perform actions on them.\n"
237//usage: "First failed action stops processing of current file.\n" 237//usage: "First failed action stops processing of current file.\n"
238//usage: "Defaults: PATH is current directory, action is '-print'\n" 238//usage: "Defaults: PATH is current directory, action is '-print'\n"
239//usage: "\n -follow Follow symlinks" 239//usage: "\n -L,-follow Follow symlinks"
240//usage: "\n -H ...on command line only"
240//usage: IF_FEATURE_FIND_XDEV( 241//usage: IF_FEATURE_FIND_XDEV(
241//usage: "\n -xdev Don't descend directories on other filesystems" 242//usage: "\n -xdev Don't descend directories on other filesystems"
242//usage: ) 243//usage: )
@@ -814,6 +815,31 @@ static const char* plus_minus_num(const char* str)
814} 815}
815#endif 816#endif
816 817
818/* Say no to GCCism */
819#define USE_NESTED_FUNCTION 0
820
821#if !USE_NESTED_FUNCTION
822struct pp_locals {
823 action*** appp;
824 unsigned cur_group;
825 unsigned cur_action;
826 IF_FEATURE_FIND_NOT( bool invert_flag; )
827};
828static action* alloc_action(struct pp_locals *ppl, int sizeof_struct, action_fp f)
829{
830 action *ap = xzalloc(sizeof_struct);
831 action **app;
832 action ***group = &ppl->appp[ppl->cur_group];
833 *group = app = xrealloc(*group, (ppl->cur_action+2) * sizeof(ppl->appp[0][0]));
834 app[ppl->cur_action++] = ap;
835 app[ppl->cur_action] = NULL;
836 ap->f = f;
837 IF_FEATURE_FIND_NOT( ap->invert = ppl->invert_flag; )
838 IF_FEATURE_FIND_NOT( ppl->invert_flag = 0; )
839 return ap;
840}
841#endif
842
817static action*** parse_params(char **argv) 843static action*** parse_params(char **argv)
818{ 844{
819 enum { 845 enum {
@@ -900,10 +926,18 @@ static action*** parse_params(char **argv)
900 IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") 926 IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
901 ; 927 ;
902 928
929#if !USE_NESTED_FUNCTION
930 struct pp_locals ppl;
931#define appp (ppl.appp )
932#define cur_group (ppl.cur_group )
933#define cur_action (ppl.cur_action )
934#define invert_flag (ppl.invert_flag)
935#define ALLOC_ACTION(name) (action_##name*)alloc_action(&ppl, sizeof(action_##name), (action_fp) func_##name)
936#else
903 action*** appp; 937 action*** appp;
904 unsigned cur_group = 0; 938 unsigned cur_group;
905 unsigned cur_action = 0; 939 unsigned cur_action;
906 IF_FEATURE_FIND_NOT( bool invert_flag = 0; ) 940 IF_FEATURE_FIND_NOT( bool invert_flag; )
907 941
908 /* This is the only place in busybox where we use nested function. 942 /* This is the only place in busybox where we use nested function.
909 * So far more standard alternatives were bigger. */ 943 * So far more standard alternatives were bigger. */
@@ -912,7 +946,7 @@ static action*** parse_params(char **argv)
912 action* alloc_action(int sizeof_struct, action_fp f) 946 action* alloc_action(int sizeof_struct, action_fp f)
913 { 947 {
914 action *ap; 948 action *ap;
915 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp)); 949 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(appp[0][0]));
916 appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct); 950 appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct);
917 appp[cur_group][cur_action] = NULL; 951 appp[cur_group][cur_action] = NULL;
918 ap->f = f; 952 ap->f = f;
@@ -920,9 +954,12 @@ static action*** parse_params(char **argv)
920 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 954 IF_FEATURE_FIND_NOT( invert_flag = 0; )
921 return ap; 955 return ap;
922 } 956 }
923
924#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name) 957#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
958#endif
925 959
960 cur_group = 0;
961 cur_action = 0;
962 IF_FEATURE_FIND_NOT( invert_flag = 0; )
926 appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ 963 appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */
927 964
928 while (*argv) { 965 while (*argv) {
@@ -948,8 +985,8 @@ static action*** parse_params(char **argv)
948 */ 985 */
949 /* Options */ 986 /* Options */
950 if (parm == OPT_FOLLOW) { 987 if (parm == OPT_FOLLOW) {
951 dbg("follow enabled: %d", __LINE__); 988 dbg("follow enabled: %d", __LINE__);
952 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; 989 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
953 } 990 }
954#if ENABLE_FEATURE_FIND_XDEV 991#if ENABLE_FEATURE_FIND_XDEV
955 else if (parm == OPT_XDEV) { 992 else if (parm == OPT_XDEV) {
@@ -987,7 +1024,7 @@ static action*** parse_params(char **argv)
987 dbg("%d", __LINE__); 1024 dbg("%d", __LINE__);
988 /* start new OR group */ 1025 /* start new OR group */
989 cur_group++; 1026 cur_group++;
990 appp = xrealloc(appp, (cur_group+2) * sizeof(*appp)); 1027 appp = xrealloc(appp, (cur_group+2) * sizeof(appp[0]));
991 /*appp[cur_group] = NULL; - already NULL */ 1028 /*appp[cur_group] = NULL; - already NULL */
992 appp[cur_group+1] = NULL; 1029 appp[cur_group+1] = NULL;
993 cur_action = 0; 1030 cur_action = 0;
@@ -1245,6 +1282,9 @@ static action*** parse_params(char **argv)
1245 dbg("exiting %s", __func__); 1282 dbg("exiting %s", __func__);
1246 return appp; 1283 return appp;
1247#undef ALLOC_ACTION 1284#undef ALLOC_ACTION
1285#undef appp
1286#undef cur_action
1287#undef invert_flag
1248} 1288}
1249 1289
1250int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1290int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -1254,7 +1294,15 @@ int find_main(int argc UNUSED_PARAM, char **argv)
1254 1294
1255 INIT_G(); 1295 INIT_G();
1256 1296
1257 argv++; 1297 /* "+": stop on first non-option */
1298 i = getopt32(argv, "+HLP");
1299 if (i & (1<<0))
1300 G.recurse_flags |= ACTION_FOLLOWLINKS_L0 | ACTION_DANGLING_OK;
1301 if (i & (1<<1))
1302 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
1303 /* -P is default and is ignored */
1304 argv += optind;
1305
1258 for (firstopt = 0; argv[firstopt]; firstopt++) { 1306 for (firstopt = 0; argv[firstopt]; firstopt++) {
1259 if (argv[firstopt][0] == '-') 1307 if (argv[firstopt][0] == '-')
1260 break; 1308 break;
diff --git a/findutils/grep.c b/findutils/grep.c
index 6b47f4327..5bbe61100 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -381,6 +381,8 @@ static int grep_file(FILE *file)
381 opt_f_not_found: ; 381 opt_f_not_found: ;
382 } 382 }
383 } else { 383 } else {
384 char *match_at;
385
384 if (!(gl->flg_mem_alocated_compiled & COMPILED)) { 386 if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
385 gl->flg_mem_alocated_compiled |= COMPILED; 387 gl->flg_mem_alocated_compiled |= COMPILED;
386#if !ENABLE_EXTRA_COMPAT 388#if !ENABLE_EXTRA_COMPAT
@@ -396,32 +398,36 @@ static int grep_file(FILE *file)
396 gl->matched_range.rm_so = 0; 398 gl->matched_range.rm_so = 0;
397 gl->matched_range.rm_eo = 0; 399 gl->matched_range.rm_eo = 0;
398#endif 400#endif
401 match_at = line;
402 opt_w_again:
399 if ( 403 if (
400#if !ENABLE_EXTRA_COMPAT 404#if !ENABLE_EXTRA_COMPAT
401 regexec(&gl->compiled_regex, line, 1, &gl->matched_range, 0) == 0 405 regexec(&gl->compiled_regex, match_at, 1, &gl->matched_range, 0) == 0
402#else 406#else
403 re_search(&gl->compiled_regex, line, line_len, 407 re_search(&gl->compiled_regex, match_at, line_len,
404 /*start:*/ 0, /*range:*/ line_len, 408 /*start:*/ 0, /*range:*/ line_len,
405 &gl->matched_range) >= 0 409 &gl->matched_range) >= 0
406#endif 410#endif
407 ) { 411 ) {
408 if (option_mask32 & OPT_x) { 412 if (option_mask32 & OPT_x) {
409 found = (gl->matched_range.rm_so == 0 413 found = (gl->matched_range.rm_so == 0
410 && line[gl->matched_range.rm_eo] == '\0'); 414 && match_at[gl->matched_range.rm_eo] == '\0');
411 } else 415 } else
412 if (!(option_mask32 & OPT_w)) { 416 if (!(option_mask32 & OPT_w)) {
413 found = 1; 417 found = 1;
414 } else { 418 } else {
415 char c = ' '; 419 char c = ' ';
416 if (gl->matched_range.rm_so) 420 if (gl->matched_range.rm_so)
417 c = line[gl->matched_range.rm_so - 1]; 421 c = match_at[gl->matched_range.rm_so - 1];
418 if (!isalnum(c) && c != '_') { 422 if (!isalnum(c) && c != '_') {
419 c = line[gl->matched_range.rm_eo]; 423 c = match_at[gl->matched_range.rm_eo];
420 if (!c || (!isalnum(c) && c != '_')) 424 if (!c || (!isalnum(c) && c != '_')) {
421 found = 1; 425 found = 1;
426 } else {
427 match_at += gl->matched_range.rm_eo;
428 goto opt_w_again;
429 }
422 } 430 }
423//BUG: "echo foop foo | grep -w foo" should match, but doesn't:
424//we bail out on first "mismatch" because it's not a word.
425 } 431 }
426 } 432 }
427 } 433 }
@@ -718,7 +724,7 @@ int grep_main(int argc UNUSED_PARAM, char **argv)
718 option_mask32 |= OPT_F; 724 option_mask32 |= OPT_F;
719 725
720#if !ENABLE_EXTRA_COMPAT 726#if !ENABLE_EXTRA_COMPAT
721 if (!(option_mask32 & (OPT_o | OPT_w))) 727 if (!(option_mask32 & (OPT_o | OPT_w | OPT_x)))
722 reflags = REG_NOSUB; 728 reflags = REG_NOSUB;
723#endif 729#endif
724 730
diff --git a/include/applets.src.h b/include/applets.src.h
index 00172b1bc..aa319bbc9 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -52,6 +52,12 @@ s - suid type:
52# define APPLET_NOEXEC(name,main,l,s,name2) LINK l name 52# define APPLET_NOEXEC(name,main,l,s,name2) LINK l name
53# define APPLET_NOFORK(name,main,l,s,name2) LINK l name 53# define APPLET_NOFORK(name,main,l,s,name2) LINK l name
54 54
55#elif defined(MAKE_SUID)
56# define APPLET(name,l,s) SUID s l name
57# define APPLET_ODDNAME(name,main,l,s,name2) SUID s l name
58# define APPLET_NOEXEC(name,main,l,s,name2) SUID s l name
59# define APPLET_NOFORK(name,main,l,s,name2) SUID s l name
60
55#else 61#else
56 static struct bb_applet applets[] = { /* name, main, location, need_suid */ 62 static struct bb_applet applets[] = { /* name, main, location, need_suid */
57# define APPLET(name,l,s) { #name, #name, l, s }, 63# define APPLET(name,l,s) { #name, #name, l, s },
@@ -415,7 +421,8 @@ IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes))
415IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat)) 421IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
416IF_ZCIP(APPLET(zcip, BB_DIR_SBIN, BB_SUID_DROP)) 422IF_ZCIP(APPLET(zcip, BB_DIR_SBIN, BB_SUID_DROP))
417 423
418#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) 424#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) \
425 && !defined(MAKE_LINKS) && !defined(MAKE_SUID)
419}; 426};
420#endif 427#endif
421 428
diff --git a/include/bb_e2fs_defs.h b/include/bb_e2fs_defs.h
index b400f8c11..3f5e3c45b 100644
--- a/include/bb_e2fs_defs.h
+++ b/include/bb_e2fs_defs.h
@@ -442,7 +442,7 @@ struct ext2_super_block {
442 uint32_t s_reserved[162]; /* Padding to the end of the block */ 442 uint32_t s_reserved[162]; /* Padding to the end of the block */
443}; 443};
444struct BUG_ext2_super_block { 444struct BUG_ext2_super_block {
445 char bug[sizeof(struct ext2_super_block) == 1024 ? 1 : -1]; 445 char bug[sizeof(struct ext2_super_block) == 1024 ? 1 : -1];
446}; 446};
447 447
448/* 448/*
diff --git a/include/libbb.h b/include/libbb.h
index f5b7d8dc7..9adb037ca 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -496,9 +496,9 @@ int xmkstemp(char *template) FAST_FUNC;
496off_t fdlength(int fd) FAST_FUNC; 496off_t fdlength(int fd) FAST_FUNC;
497 497
498uoff_t FAST_FUNC get_volume_size_in_bytes(int fd, 498uoff_t FAST_FUNC get_volume_size_in_bytes(int fd,
499 const char *override, 499 const char *override,
500 unsigned override_units, 500 unsigned override_units,
501 int extend); 501 int extend);
502 502
503void xpipe(int filedes[2]) FAST_FUNC; 503void xpipe(int filedes[2]) FAST_FUNC;
504/* In this form code with pipes is much more readable */ 504/* In this form code with pipes is much more readable */
@@ -691,6 +691,13 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str);
691 * else it is printed as-is (except for ch = 0x9b) */ 691 * else it is printed as-is (except for ch = 0x9b) */
692enum { PRINTABLE_META = 0x100 }; 692enum { PRINTABLE_META = 0x100 };
693void fputc_printable(int ch, FILE *file) FAST_FUNC; 693void fputc_printable(int ch, FILE *file) FAST_FUNC;
694/* Return a string that is the printable representation of character ch.
695 * Buffer must hold at least four characters. */
696enum {
697 VISIBLE_ENDLINE = 1 << 0,
698 VISIBLE_SHOW_TABS = 1 << 1,
699};
700void visible(unsigned ch, char *buf, int flags) FAST_FUNC;
694 701
695/* dmalloc will redefine these to it's own implementation. It is safe 702/* dmalloc will redefine these to it's own implementation. It is safe
696 * to have the prototypes here unconditionally. */ 703 * to have the prototypes here unconditionally. */
@@ -848,6 +855,9 @@ struct suffix_mult {
848 char suffix[4]; 855 char suffix[4];
849 unsigned mult; 856 unsigned mult;
850}; 857};
858extern const struct suffix_mult bkm_suffixes[];
859#define km_suffixes (bkm_suffixes + 1)
860
851#include "xatonum.h" 861#include "xatonum.h"
852/* Specialized: */ 862/* Specialized: */
853 863
@@ -1125,9 +1135,6 @@ void bb_displayroutes(int noresolve, int netstatfmt) FAST_FUNC;
1125 1135
1126 1136
1127/* Networking */ 1137/* Networking */
1128int create_icmp_socket(void) FAST_FUNC;
1129int create_icmp6_socket(void) FAST_FUNC;
1130/* interface.c */
1131/* This structure defines protocol families and their handlers. */ 1138/* This structure defines protocol families and their handlers. */
1132struct aftype { 1139struct aftype {
1133 const char *name; 1140 const char *name;
@@ -1156,6 +1163,7 @@ struct hwtype {
1156}; 1163};
1157extern smallint interface_opt_a; 1164extern smallint interface_opt_a;
1158int display_interfaces(char *ifname) FAST_FUNC; 1165int display_interfaces(char *ifname) FAST_FUNC;
1166int in_ether(const char *bufp, struct sockaddr *sap) FAST_FUNC;
1159#if ENABLE_FEATURE_HWIB 1167#if ENABLE_FEATURE_HWIB
1160int in_ib(const char *bufp, struct sockaddr *sap) FAST_FUNC; 1168int in_ib(const char *bufp, struct sockaddr *sap) FAST_FUNC;
1161#else 1169#else
@@ -1452,7 +1460,7 @@ void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC;
1452/* It's NOT just ENABLEd or disabled. It's a number: */ 1460/* It's NOT just ENABLEd or disabled. It's a number: */
1453# if defined CONFIG_FEATURE_EDITING_HISTORY && CONFIG_FEATURE_EDITING_HISTORY > 0 1461# if defined CONFIG_FEATURE_EDITING_HISTORY && CONFIG_FEATURE_EDITING_HISTORY > 0
1454# define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0) 1462# define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0)
1455unsigned size_from_HISTFILESIZE(const char *hp); 1463unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC;
1456# else 1464# else
1457# define MAX_HISTORY 0 1465# define MAX_HISTORY 0
1458# endif 1466# endif
@@ -1494,6 +1502,7 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC;
1494 * >0 length of input string, including terminating '\n' 1502 * >0 length of input string, including terminating '\n'
1495 */ 1503 */
1496int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; 1504int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
1505void show_history(const line_input_t *st) FAST_FUNC;
1497# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1506# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1498void save_history(line_input_t *st); 1507void save_history(line_input_t *st);
1499# endif 1508# endif
@@ -1825,7 +1834,7 @@ extern const char bb_default_login_shell[] ALIGN1;
1825# define VC_4 "/dev/vc/4" 1834# define VC_4 "/dev/vc/4"
1826# define VC_5 "/dev/vc/5" 1835# define VC_5 "/dev/vc/5"
1827# define VC_FORMAT "/dev/vc/%d" 1836# define VC_FORMAT "/dev/vc/%d"
1828# define LOOP_FORMAT "/dev/loop/%d" 1837# define LOOP_FORMAT "/dev/loop/%u"
1829# define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) 1838# define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1)
1830# define LOOP_NAME "/dev/loop/" 1839# define LOOP_NAME "/dev/loop/"
1831# define FB_0 "/dev/fb/0" 1840# define FB_0 "/dev/fb/0"
@@ -1838,7 +1847,7 @@ extern const char bb_default_login_shell[] ALIGN1;
1838# define VC_4 "/dev/tty4" 1847# define VC_4 "/dev/tty4"
1839# define VC_5 "/dev/tty5" 1848# define VC_5 "/dev/tty5"
1840# define VC_FORMAT "/dev/tty%d" 1849# define VC_FORMAT "/dev/tty%d"
1841# define LOOP_FORMAT "/dev/loop%d" 1850# define LOOP_FORMAT "/dev/loop%u"
1842# define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) 1851# define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1)
1843# define LOOP_NAME "/dev/loop" 1852# define LOOP_NAME "/dev/loop"
1844# define FB_0 "/dev/fb0" 1853# define FB_0 "/dev/fb0"
diff --git a/include/liblzo_interface.h b/include/liblzo_interface.h
index 9a84c0b6b..b7f1b639b 100644
--- a/include/liblzo_interface.h
+++ b/include/liblzo_interface.h
@@ -30,7 +30,7 @@
30/* 30/*
31static void die_at(int line) 31static void die_at(int line)
32{ 32{
33 bb_error_msg_and_die("internal error at %d", line); 33 bb_error_msg_and_die("internal error at %d", line);
34} 34}
35#define assert(v) if (!(v)) die_at(__LINE__) 35#define assert(v) if (!(v)) die_at(__LINE__)
36*/ 36*/
diff --git a/include/platform.h b/include/platform.h
index 432cb9cae..f18d5b74e 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -225,6 +225,7 @@ typedef int bb__aliased_int FIX_ALIASING;
225typedef long bb__aliased_long FIX_ALIASING; 225typedef long bb__aliased_long FIX_ALIASING;
226typedef uint16_t bb__aliased_uint16_t FIX_ALIASING; 226typedef uint16_t bb__aliased_uint16_t FIX_ALIASING;
227typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; 227typedef uint32_t bb__aliased_uint32_t FIX_ALIASING;
228typedef uint64_t bb__aliased_uint64_t FIX_ALIASING;
228 229
229/* NB: unaligned parameter should be a pointer, aligned one - 230/* NB: unaligned parameter should be a pointer, aligned one -
230 * a lvalue. This makes it more likely to not swap them by mistake 231 * a lvalue. This makes it more likely to not swap them by mistake
diff --git a/init/init.c b/init/init.c
index 15aad474f..edb5be696 100644
--- a/init/init.c
+++ b/init/init.c
@@ -140,12 +140,11 @@
140 * not fully functional init by switching it on! */ 140 * not fully functional init by switching it on! */
141#define DEBUG_INIT 0 141#define DEBUG_INIT 0
142 142
143#define COMMAND_SIZE 256
144#define CONSOLE_NAME_SIZE 32 143#define CONSOLE_NAME_SIZE 32
145 144
146/* Default sysinit script. */ 145/* Default sysinit script. */
147#ifndef INIT_SCRIPT 146#ifndef INIT_SCRIPT
148#define INIT_SCRIPT "/etc/init.d/rcS" 147# define INIT_SCRIPT "/etc/init.d/rcS"
149#endif 148#endif
150 149
151/* Each type of actions can appear many times. They will be 150/* Each type of actions can appear many times. They will be
@@ -195,7 +194,7 @@ struct init_action {
195 pid_t pid; 194 pid_t pid;
196 uint8_t action_type; 195 uint8_t action_type;
197 char terminal[CONSOLE_NAME_SIZE]; 196 char terminal[CONSOLE_NAME_SIZE];
198 char command[COMMAND_SIZE]; 197 char command[1];
199}; 198};
200 199
201static struct init_action *init_action_list = NULL; 200static struct init_action *init_action_list = NULL;
@@ -398,7 +397,7 @@ static void reset_sighandlers_and_unblock_sigs(void)
398} 397}
399 398
400/* Wrapper around exec: 399/* Wrapper around exec:
401 * Takes string (max COMMAND_SIZE chars). 400 * Takes string.
402 * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'. 401 * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'.
403 * Otherwise splits words on whitespace, deals with leading dash, 402 * Otherwise splits words on whitespace, deals with leading dash,
404 * and uses plain exec(). 403 * and uses plain exec().
@@ -406,10 +405,15 @@ static void reset_sighandlers_and_unblock_sigs(void)
406 */ 405 */
407static void init_exec(const char *command) 406static void init_exec(const char *command)
408{ 407{
409 char *cmd[COMMAND_SIZE / 2]; 408 /* +8 allows to write VLA sizes below more efficiently: */
410 char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ 409 unsigned command_size = strlen(command) + 8;
411 int dash = (command[0] == '-' /* maybe? && command[1] == '/' */); 410 /* strlen(command) + strlen("exec ")+1: */
412 411 char buf[command_size];
412 /* strlen(command) / 2 + 4: */
413 char *cmd[command_size / 2];
414 int dash;
415
416 dash = (command[0] == '-' /* maybe? && command[1] == '/' */);
413 command += dash; 417 command += dash;
414 418
415 /* See if any special /bin/sh requiring characters are present */ 419 /* See if any special /bin/sh requiring characters are present */
@@ -626,21 +630,21 @@ static void new_init_action(uint8_t action_type, const char *command, const char
626 nextp = &a->next; 630 nextp = &a->next;
627 } 631 }
628 632
629 a = xzalloc(sizeof(*a)); 633 a = xzalloc(sizeof(*a) + strlen(command));
630 634
631 /* Append to the end of the list */ 635 /* Append to the end of the list */
632 append: 636 append:
633 *nextp = a; 637 *nextp = a;
634 a->action_type = action_type; 638 a->action_type = action_type;
635 safe_strncpy(a->command, command, sizeof(a->command)); 639 strcpy(a->command, command);
636 safe_strncpy(a->terminal, cons, sizeof(a->terminal)); 640 safe_strncpy(a->terminal, cons, sizeof(a->terminal));
637 dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", 641 dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%x tty='%s'\n",
638 a->command, a->action_type, a->terminal); 642 a->command, a->action_type, a->terminal);
639} 643}
640 644
641/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, 645/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
642 * then parse_inittab() simply adds in some default 646 * then parse_inittab() simply adds in some default
643 * actions(i.e., runs INIT_SCRIPT and then starts a pair 647 * actions (i.e., runs INIT_SCRIPT and then starts a pair
644 * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB 648 * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB
645 * _is_ defined, but /etc/inittab is missing, this 649 * _is_ defined, but /etc/inittab is missing, this
646 * results in the same set of default behaviors. 650 * results in the same set of default behaviors.
@@ -655,23 +659,22 @@ static void parse_inittab(void)
655#endif 659#endif
656 { 660 {
657 /* No inittab file - set up some default behavior */ 661 /* No inittab file - set up some default behavior */
658 /* Reboot on Ctrl-Alt-Del */ 662 /* Sysinit */
659 new_init_action(CTRLALTDEL, "reboot", ""); 663 new_init_action(SYSINIT, INIT_SCRIPT, "");
660 /* Umount all filesystems on halt/reboot */
661 new_init_action(SHUTDOWN, "umount -a -r", "");
662 /* Swapoff on halt/reboot */
663 if (ENABLE_SWAPONOFF)
664 new_init_action(SHUTDOWN, "swapoff -a", "");
665 /* Prepare to restart init when a QUIT is received */
666 new_init_action(RESTART, "init", "");
667 /* Askfirst shell on tty1-4 */ 664 /* Askfirst shell on tty1-4 */
668 new_init_action(ASKFIRST, bb_default_login_shell, ""); 665 new_init_action(ASKFIRST, bb_default_login_shell, "");
669//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users 666//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
670 new_init_action(ASKFIRST, bb_default_login_shell, VC_2); 667 new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
671 new_init_action(ASKFIRST, bb_default_login_shell, VC_3); 668 new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
672 new_init_action(ASKFIRST, bb_default_login_shell, VC_4); 669 new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
673 /* sysinit */ 670 /* Reboot on Ctrl-Alt-Del */
674 new_init_action(SYSINIT, INIT_SCRIPT, ""); 671 new_init_action(CTRLALTDEL, "reboot", "");
672 /* Umount all filesystems on halt/reboot */
673 new_init_action(SHUTDOWN, "umount -a -r", "");
674 /* Swapoff on halt/reboot */
675 new_init_action(SHUTDOWN, "swapoff -a", "");
676 /* Restart init when a QUIT is received */
677 new_init_action(RESTART, "init", "");
675 return; 678 return;
676 } 679 }
677 680
@@ -931,10 +934,17 @@ static void reload_inittab(void)
931 934
932 /* Remove stale entries and SYSINIT entries. 935 /* Remove stale entries and SYSINIT entries.
933 * We never rerun SYSINIT entries anyway, 936 * We never rerun SYSINIT entries anyway,
934 * removing them too saves a few bytes */ 937 * removing them too saves a few bytes
938 */
935 nextp = &init_action_list; 939 nextp = &init_action_list;
936 while ((a = *nextp) != NULL) { 940 while ((a = *nextp) != NULL) {
937 if ((a->action_type & ~SYSINIT) == 0) { 941 /*
942 * Why pid == 0 check?
943 * Process can be removed from inittab and added *later*.
944 * If we delete its entry but process still runs,
945 * duplicate is spawned when the entry is re-added.
946 */
947 if ((a->action_type & ~SYSINIT) == 0 && a->pid == 0) {
938 *nextp = a->next; 948 *nextp = a->next;
939 free(a); 949 free(a);
940 } else { 950 } else {
@@ -1058,10 +1068,13 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1058 message(L_CONSOLE | L_LOG, "init started: %s", bb_banner); 1068 message(L_CONSOLE | L_LOG, "init started: %s", bb_banner);
1059#endif 1069#endif
1060 1070
1071#if 0
1072/* It's 2013, does anyone really still depend on this? */
1073/* If you do, consider adding swapon to sysinot actions then! */
1061/* struct sysinfo is linux-specific */ 1074/* struct sysinfo is linux-specific */
1062#ifdef __linux__ 1075# ifdef __linux__
1063 /* Make sure there is enough memory to do something useful. */ 1076 /* Make sure there is enough memory to do something useful. */
1064 if (ENABLE_SWAPONOFF) { 1077 /*if (ENABLE_SWAPONOFF) - WRONG: we may have non-bbox swapon*/ {
1065 struct sysinfo info; 1078 struct sysinfo info;
1066 1079
1067 if (sysinfo(&info) == 0 1080 if (sysinfo(&info) == 0
@@ -1075,6 +1088,7 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1075 run_actions(SYSINIT); /* wait and removing */ 1088 run_actions(SYSINIT); /* wait and removing */
1076 } 1089 }
1077 } 1090 }
1091# endif
1078#endif 1092#endif
1079 1093
1080 /* Check if we are supposed to be in single user mode */ 1094 /* Check if we are supposed to be in single user mode */
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index ad81ce46b..db79ff62b 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -27,8 +27,6 @@ lib-y += concat_subpath_file.o
27lib-y += copy_file.o 27lib-y += copy_file.o
28lib-y += copyfd.o 28lib-y += copyfd.o
29lib-y += crc32.o 29lib-y += crc32.o
30lib-y += create_icmp6_socket.o
31lib-y += create_icmp_socket.o
32lib-y += default_error_retval.o 30lib-y += default_error_retval.o
33lib-y += device_open.o 31lib-y += device_open.o
34lib-y += dump.o 32lib-y += dump.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index f0df4e080..44161a219 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -29,7 +29,7 @@
29#include "busybox.h" 29#include "busybox.h"
30 30
31#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ 31#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
32 || defined(__APPLE__) \ 32 || defined(__APPLE__) \
33 ) 33 )
34# include <malloc.h> /* for mallopt */ 34# include <malloc.h> /* for mallopt */
35#endif 35#endif
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
index fe2b50677..77c1bcd95 100644
--- a/libbb/bb_askpass.c
+++ b/libbb/bb_askpass.c
@@ -65,7 +65,9 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
65 i = 0; 65 i = 0;
66 while (1) { 66 while (1) {
67 int r = read(fd, &ret[i], 1); 67 int r = read(fd, &ret[i], 1);
68 if (r < 0) { 68 if ((i == 0 && r == 0) /* EOF (^D) with no password */
69 || r < 0
70 ) {
69 /* read is interrupted by timeout or ^C */ 71 /* read is interrupted by timeout or ^C */
70 ret = NULL; 72 ret = NULL;
71 break; 73 break;
diff --git a/libbb/create_icmp6_socket.c b/libbb/create_icmp6_socket.c
deleted file mode 100644
index 368c69028..000000000
--- a/libbb/create_icmp6_socket.c
+++ /dev/null
@@ -1,38 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * create raw socket for icmp (IPv6 version) protocol
6 * and drop root privileges if running setuid
7 *
8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */
10
11#include "libbb.h"
12
13#if ENABLE_FEATURE_IPV6
14int FAST_FUNC create_icmp6_socket(void)
15{
16 int sock;
17#if 0
18 struct protoent *proto;
19 proto = getprotobyname("ipv6-icmp");
20 /* if getprotobyname failed, just silently force
21 * proto->p_proto to have the correct value for "ipv6-icmp" */
22 sock = socket(AF_INET6, SOCK_RAW,
23 (proto ? proto->p_proto : IPPROTO_ICMPV6));
24#else
25 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
26#endif
27 if (sock < 0) {
28 if (errno == EPERM)
29 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
30 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
31 }
32
33 /* drop root privs if running setuid */
34 xsetuid(getuid());
35
36 return sock;
37}
38#endif
diff --git a/libbb/create_icmp_socket.c b/libbb/create_icmp_socket.c
deleted file mode 100644
index 585626983..000000000
--- a/libbb/create_icmp_socket.c
+++ /dev/null
@@ -1,36 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * create raw socket for icmp protocol
6 * and drop root privileges if running setuid
7 *
8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */
10
11#include "libbb.h"
12
13int FAST_FUNC create_icmp_socket(void)
14{
15 int sock;
16#if 0
17 struct protoent *proto;
18 proto = getprotobyname("icmp");
19 /* if getprotobyname failed, just silently force
20 * proto->p_proto to have the correct value for "icmp" */
21 sock = socket(AF_INET, SOCK_RAW,
22 (proto ? proto->p_proto : 1)); /* 1 == ICMP */
23#else
24 sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
25#endif
26 if (sock < 0) {
27 if (errno == EPERM)
28 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
29 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
30 }
31
32 /* drop root privs if running setuid */
33 xsetuid(getuid());
34
35 return sock;
36}
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index b4d955e5a..3f743ac75 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -84,7 +84,7 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
84 if (swap_needed) 84 if (swap_needed)
85 t = bb_bswap_64(t); 85 t = bb_bswap_64(t);
86 /* wbuffer is suitably aligned for this */ 86 /* wbuffer is suitably aligned for this */
87 *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; 87 *(bb__aliased_uint64_t *) (&ctx->wbuffer[64 - 8]) = t;
88 } 88 }
89 ctx->process_block(ctx); 89 ctx->process_block(ctx);
90 if (remaining >= 8) 90 if (remaining >= 8)
@@ -883,10 +883,10 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
883 uint64_t t; 883 uint64_t t;
884 t = ctx->total64[0] << 3; 884 t = ctx->total64[0] << 3;
885 t = SWAP_BE64(t); 885 t = SWAP_BE64(t);
886 *(uint64_t *) (&ctx->wbuffer[128 - 8]) = t; 886 *(bb__aliased_uint64_t *) (&ctx->wbuffer[128 - 8]) = t;
887 t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61); 887 t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61);
888 t = SWAP_BE64(t); 888 t = SWAP_BE64(t);
889 *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t; 889 *(bb__aliased_uint64_t *) (&ctx->wbuffer[128 - 16]) = t;
890 } 890 }
891 sha512_process_block128(ctx); 891 sha512_process_block128(ctx);
892 if (remaining >= 16) 892 if (remaining >= 16)
diff --git a/libbb/in_ether.c b/libbb/in_ether.c
new file mode 100644
index 000000000..dadadbafe
--- /dev/null
+++ b/libbb/in_ether.c
@@ -0,0 +1,58 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 */
5
6//kbuild:lib-$(CONFIG_IFCONFIG) += in_ether.o
7//kbuild:lib-$(CONFIG_IFENSLAVE) += in_ether.o
8
9#include "libbb.h"
10#include <net/if_arp.h>
11#include <net/ethernet.h>
12
13/* Convert Ethernet address from "XX[:]XX[:]XX[:]XX[:]XX[:]XX" to sockaddr.
14 * Return nonzero on error.
15 */
16int FAST_FUNC in_ether(const char *bufp, struct sockaddr *sap)
17{
18 char *ptr;
19 int i, j;
20 unsigned char val;
21 unsigned char c;
22
23 sap->sa_family = ARPHRD_ETHER;
24 ptr = (char *) sap->sa_data;
25
26 i = ETH_ALEN;
27 goto first;
28 do {
29 /* We might get a semicolon here */
30 if (*bufp == ':')
31 bufp++;
32 first:
33 j = val = 0;
34 do {
35 c = *bufp;
36 if (((unsigned char)(c - '0')) <= 9) {
37 c -= '0';
38 } else if ((unsigned char)((c|0x20) - 'a') <= 5) {
39 c = (unsigned char)((c|0x20) - 'a') + 10;
40 } else {
41 if (j && (c == ':' || c == '\0'))
42 /* One-digit byte: __:X:__ */
43 break;
44 return -1;
45 }
46 ++bufp;
47 val <<= 4;
48 val += c;
49 j ^= 1;
50 } while (j);
51
52 *ptr++ = val;
53
54 } while (--i);
55
56 /* Error if we aren't at end of string */
57 return *bufp;
58}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 7f64a9691..20d75cf56 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -38,6 +38,14 @@
38 * and the \] escape to signal the end of such a sequence. Example: 38 * and the \] escape to signal the end of such a sequence. Example:
39 * 39 *
40 * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] ' 40 * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
41 *
42 * Unicode in PS1 is not fully supported: prompt length calulation is wrong,
43 * resulting in line wrap problems with long (multi-line) input.
44 *
45 * Multi-line PS1 (e.g. PS1="\n[\w]\n$ ") has problems with history
46 * browsing: up/down arrows result in scrolling.
47 * It stems from simplistic "cmdedit_y = cmdedit_prmt_len / cmdedit_termw"
48 * calculation of how many lines the prompt takes.
41 */ 49 */
42#include "libbb.h" 50#include "libbb.h"
43#include "unicode.h" 51#include "unicode.h"
@@ -1268,7 +1276,7 @@ line_input_t* FAST_FUNC new_line_input_t(int flags)
1268 1276
1269#if MAX_HISTORY > 0 1277#if MAX_HISTORY > 0
1270 1278
1271unsigned size_from_HISTFILESIZE(const char *hp) 1279unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
1272{ 1280{
1273 int size = MAX_HISTORY; 1281 int size = MAX_HISTORY;
1274 if (hp) { 1282 if (hp) {
@@ -1323,6 +1331,17 @@ static int get_next_history(void)
1323 return 0; 1331 return 0;
1324} 1332}
1325 1333
1334/* Lists command history. Used by shell 'history' builtins */
1335void FAST_FUNC show_history(const line_input_t *st)
1336{
1337 int i;
1338
1339 if (!st)
1340 return;
1341 for (i = 0; i < st->cnt_history; i++)
1342 printf("%4d %s\n", i, st->history[i]);
1343}
1344
1326# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1345# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1327/* We try to ensure that concurrent additions to the history 1346/* We try to ensure that concurrent additions to the history
1328 * do not overwrite each other. 1347 * do not overwrite each other.
@@ -1762,34 +1781,36 @@ static void ask_terminal(void)
1762#define ask_terminal() ((void)0) 1781#define ask_terminal() ((void)0)
1763#endif 1782#endif
1764 1783
1784/* Called just once at read_line_input() init time */
1765#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1785#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
1766static void parse_and_put_prompt(const char *prmt_ptr) 1786static void parse_and_put_prompt(const char *prmt_ptr)
1767{ 1787{
1788 const char *p;
1768 cmdedit_prompt = prmt_ptr; 1789 cmdedit_prompt = prmt_ptr;
1769 cmdedit_prmt_len = strlen(prmt_ptr); 1790 p = strrchr(prmt_ptr, '\n');
1791 cmdedit_prmt_len = unicode_strwidth(p ? p+1 : prmt_ptr);
1770 put_prompt(); 1792 put_prompt();
1771} 1793}
1772#else 1794#else
1773static void parse_and_put_prompt(const char *prmt_ptr) 1795static void parse_and_put_prompt(const char *prmt_ptr)
1774{ 1796{
1775 int prmt_len = 0; 1797 int prmt_size = 0;
1776 size_t cur_prmt_len = 0;
1777 char flg_not_length = '[';
1778 char *prmt_mem_ptr = xzalloc(1); 1798 char *prmt_mem_ptr = xzalloc(1);
1779# if ENABLE_USERNAME_OR_HOMEDIR 1799# if ENABLE_USERNAME_OR_HOMEDIR
1780 char *cwd_buf = NULL; 1800 char *cwd_buf = NULL;
1781# endif 1801# endif
1782 char timebuf[sizeof("HH:MM:SS")]; 1802 char flg_not_length = '[';
1783 char cbuf[2]; 1803 char cbuf[2];
1784 char c;
1785 char *pbuf;
1786 1804
1787 cmdedit_prmt_len = 0; 1805 /*cmdedit_prmt_len = 0; - already is */
1788 1806
1789 cbuf[1] = '\0'; /* never changes */ 1807 cbuf[1] = '\0'; /* never changes */
1790 1808
1791 while (*prmt_ptr) { 1809 while (*prmt_ptr) {
1810 char timebuf[sizeof("HH:MM:SS")];
1792 char *free_me = NULL; 1811 char *free_me = NULL;
1812 char *pbuf;
1813 char c;
1793 1814
1794 pbuf = cbuf; 1815 pbuf = cbuf;
1795 c = *prmt_ptr++; 1816 c = *prmt_ptr++;
@@ -1922,7 +1943,8 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1922 } 1943 }
1923 case '[': case ']': 1944 case '[': case ']':
1924 if (c == flg_not_length) { 1945 if (c == flg_not_length) {
1925 flg_not_length = (flg_not_length == '[' ? ']' : '['); 1946 /* Toggle '['/']' hex 5b/5d */
1947 flg_not_length ^= 6;
1926 continue; 1948 continue;
1927 } 1949 }
1928 break; 1950 break;
@@ -1930,11 +1952,22 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1930 } /* if */ 1952 } /* if */
1931 } /* if */ 1953 } /* if */
1932 cbuf[0] = c; 1954 cbuf[0] = c;
1933 cur_prmt_len = strlen(pbuf); 1955 {
1934 prmt_len += cur_prmt_len; 1956 int n = strlen(pbuf);
1935 if (flg_not_length != ']') 1957 prmt_size += n;
1936 cmdedit_prmt_len += cur_prmt_len; 1958 if (c == '\n')
1937 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); 1959 cmdedit_prmt_len = 0;
1960 else if (flg_not_length != ']') {
1961#if 0 /*ENABLE_UNICODE_SUPPORT*/
1962/* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */
1963/* FIXME */
1964 cmdedit_prmt_len += unicode_strwidth(pbuf);
1965#else
1966 cmdedit_prmt_len += n;
1967#endif
1968 }
1969 }
1970 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf);
1938 free(free_me); 1971 free(free_me);
1939 } /* while */ 1972 } /* while */
1940 1973
@@ -2003,7 +2036,15 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2003 S.sent_ESC_br6n = 0; 2036 S.sent_ESC_br6n = 0;
2004 if (cursor == 0) { /* otherwise it may be bogus */ 2037 if (cursor == 0) { /* otherwise it may be bogus */
2005 int col = ((ic >> 32) & 0x7fff) - 1; 2038 int col = ((ic >> 32) & 0x7fff) - 1;
2006 if (col > cmdedit_prmt_len) { 2039 /*
2040 * Is col > cmdedit_prmt_len?
2041 * If yes (terminal says cursor is farther to the right
2042 * of where we think it should be),
2043 * the prompt wasn't printed starting at col 1,
2044 * there was additional text before it.
2045 */
2046 if ((int)(col - cmdedit_prmt_len) > 0) {
2047 /* Fix our understanding of current x position */
2007 cmdedit_x += (col - cmdedit_prmt_len); 2048 cmdedit_x += (col - cmdedit_prmt_len);
2008 while (cmdedit_x >= cmdedit_termw) { 2049 while (cmdedit_x >= cmdedit_termw) {
2009 cmdedit_x -= cmdedit_termw; 2050 cmdedit_x -= cmdedit_termw;
@@ -2094,6 +2135,7 @@ static int32_t reverse_i_search(void)
2094 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 2135 char read_key_buffer[KEYCODE_BUFFER_SIZE];
2095 const char *matched_history_line; 2136 const char *matched_history_line;
2096 const char *saved_prompt; 2137 const char *saved_prompt;
2138 unsigned saved_prmt_len;
2097 int32_t ic; 2139 int32_t ic;
2098 2140
2099 matched_history_line = NULL; 2141 matched_history_line = NULL;
@@ -2102,6 +2144,7 @@ static int32_t reverse_i_search(void)
2102 2144
2103 /* Save and replace the prompt */ 2145 /* Save and replace the prompt */
2104 saved_prompt = cmdedit_prompt; 2146 saved_prompt = cmdedit_prompt;
2147 saved_prmt_len = cmdedit_prmt_len;
2105 goto set_prompt; 2148 goto set_prompt;
2106 2149
2107 while (1) { 2150 while (1) {
@@ -2177,7 +2220,7 @@ static int32_t reverse_i_search(void)
2177 free((char*)cmdedit_prompt); 2220 free((char*)cmdedit_prompt);
2178 set_prompt: 2221 set_prompt:
2179 cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf); 2222 cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf);
2180 cmdedit_prmt_len = strlen(cmdedit_prompt); 2223 cmdedit_prmt_len = unicode_strwidth(cmdedit_prompt);
2181 goto do_redraw; 2224 goto do_redraw;
2182 } 2225 }
2183 } 2226 }
@@ -2199,7 +2242,7 @@ static int32_t reverse_i_search(void)
2199 2242
2200 free((char*)cmdedit_prompt); 2243 free((char*)cmdedit_prompt);
2201 cmdedit_prompt = saved_prompt; 2244 cmdedit_prompt = saved_prompt;
2202 cmdedit_prmt_len = strlen(cmdedit_prompt); 2245 cmdedit_prmt_len = saved_prmt_len;
2203 redraw(cmdedit_y, command_len - cursor); 2246 redraw(cmdedit_y, command_len - cursor);
2204 2247
2205 return ic; 2248 return ic;
@@ -2774,8 +2817,9 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2774 free(command_ps); 2817 free(command_ps);
2775#endif 2818#endif
2776 2819
2777 if (command_len > 0) 2820 if (command_len > 0) {
2778 remember_in_history(command); 2821 remember_in_history(command);
2822 }
2779 2823
2780 if (break_out > 0) { 2824 if (break_out > 0) {
2781 command[command_len++] = '\n'; 2825 command[command_len++] = '\n';
diff --git a/libbb/printable.c b/libbb/printable.c
index f6ada4904..9a423431e 100644
--- a/libbb/printable.c
+++ b/libbb/printable.c
@@ -32,3 +32,27 @@ void FAST_FUNC fputc_printable(int ch, FILE *file)
32 } 32 }
33 fputc(ch, file); 33 fputc(ch, file);
34} 34}
35
36void FAST_FUNC visible(unsigned ch, char *buf, int flags)
37{
38 if (ch == '\t' && !(flags & VISIBLE_SHOW_TABS)) {
39 goto raw;
40 }
41 if (ch == '\n') {
42 if (flags & VISIBLE_ENDLINE)
43 *buf++ = '$';
44 } else {
45 if (ch >= 128) {
46 ch -= 128;
47 *buf++ = 'M';
48 *buf++ = '-';
49 }
50 if (ch < 32 || ch == 127) {
51 *buf++ = '^';
52 ch ^= 0x40;
53 }
54 }
55 raw:
56 *buf++ = ch;
57 *buf = '\0';
58}
diff --git a/libbb/time.c b/libbb/time.c
index 57e14b66c..ea2f72e3b 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -23,14 +23,16 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
23 if (sscanf(date_str, "%u:%u%c", 23 if (sscanf(date_str, "%u:%u%c",
24 &ptm->tm_hour, 24 &ptm->tm_hour,
25 &ptm->tm_min, 25 &ptm->tm_min,
26 &end) >= 2) { 26 &end) >= 2
27 ) {
27 /* no adjustments needed */ 28 /* no adjustments needed */
28 } else 29 } else
29 /* mm.dd-HH:MM */ 30 /* mm.dd-HH:MM */
30 if (sscanf(date_str, "%u.%u-%u:%u%c", 31 if (sscanf(date_str, "%u.%u-%u:%u%c",
31 &ptm->tm_mon, &ptm->tm_mday, 32 &ptm->tm_mon, &ptm->tm_mday,
32 &ptm->tm_hour, &ptm->tm_min, 33 &ptm->tm_hour, &ptm->tm_min,
33 &end) >= 4) { 34 &end) >= 4
35 ) {
34 /* Adjust month from 1-12 to 0-11 */ 36 /* Adjust month from 1-12 to 0-11 */
35 ptm->tm_mon -= 1; 37 ptm->tm_mon -= 1;
36 } else 38 } else
@@ -38,15 +40,13 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
38 if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year, 40 if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year,
39 &ptm->tm_mon, &ptm->tm_mday, 41 &ptm->tm_mon, &ptm->tm_mday,
40 &ptm->tm_hour, &ptm->tm_min, 42 &ptm->tm_hour, &ptm->tm_min,
41 &end) >= 5) { 43 &end) >= 5
42 ptm->tm_year -= 1900; /* Adjust years */
43 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
44 } else
45 /* yyyy-mm-dd HH:MM */ 44 /* yyyy-mm-dd HH:MM */
46 if (sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year, 45 || sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year,
47 &ptm->tm_mon, &ptm->tm_mday, 46 &ptm->tm_mon, &ptm->tm_mday,
48 &ptm->tm_hour, &ptm->tm_min, 47 &ptm->tm_hour, &ptm->tm_min,
49 &end) >= 5) { 48 &end) >= 5
49 ) {
50 ptm->tm_year -= 1900; /* Adjust years */ 50 ptm->tm_year -= 1900; /* Adjust years */
51 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ 51 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
52 } else 52 } else
@@ -58,7 +58,6 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
58 return; /* don't fall through to end == ":" check */ 58 return; /* don't fall through to end == ":" check */
59 } else 59 } else
60#endif 60#endif
61//TODO: coreutils 6.9 also accepts "yyyy-mm-dd HH" (no minutes)
62 { 61 {
63 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 62 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
64 } 63 }
@@ -68,7 +67,21 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
68 end = '\0'; 67 end = '\0';
69 /* else end != NUL and we error out */ 68 /* else end != NUL and we error out */
70 } 69 }
71 } else if (date_str[0] == '@') { 70 } else
71 /* yyyy-mm-dd HH */
72 if (sscanf(date_str, "%u-%u-%u %u%c", &ptm->tm_year,
73 &ptm->tm_mon, &ptm->tm_mday,
74 &ptm->tm_hour,
75 &end) >= 4
76 /* yyyy-mm-dd */
77 || sscanf(date_str, "%u-%u-%u%c", &ptm->tm_year,
78 &ptm->tm_mon, &ptm->tm_mday,
79 &end) >= 3
80 ) {
81 ptm->tm_year -= 1900; /* Adjust years */
82 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
83 } else
84 if (date_str[0] == '@') {
72 time_t t = bb_strtol(date_str + 1, NULL, 10); 85 time_t t = bb_strtol(date_str + 1, NULL, 10);
73 if (!errno) { 86 if (!errno) {
74 struct tm *lt = localtime(&t); 87 struct tm *lt = localtime(&t);
diff --git a/libbb/unicode.c b/libbb/unicode.c
index 99dc1dfa6..9c4da50d3 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -28,19 +28,37 @@ void FAST_FUNC reinit_unicode(const char *LANG)
28 static const char unicode_0x394[] = { 0xce, 0x94, 0 }; 28 static const char unicode_0x394[] = { 0xce, 0x94, 0 };
29 size_t width; 29 size_t width;
30 30
31 /* We pass "" instead of "C" because some libc's have
32 * non-ASCII default locale for setlocale("") call
33 * (this allows users of such libc to have Unicoded
34 * system without having to mess with env).
35 *
36 * We set LC_CTYPE because (a) we may be called with $LC_CTYPE
37 * value in LANG, not with $LC_ALL, (b) internationalized
38 * LC_NUMERIC and LC_TIME are more PITA than benefit
39 * (for one, some utilities have hard time with comma
40 * used as a fractional separator).
41 */
31//TODO: avoid repeated calls by caching last string? 42//TODO: avoid repeated calls by caching last string?
32 setlocale(LC_ALL, (LANG && LANG[0]) ? LANG : "C"); 43 setlocale(LC_CTYPE, LANG ? LANG : "");
33 44
34 /* In unicode, this is a one character string */ 45 /* In unicode, this is a one character string */
35// can use unicode_strlen(string) too, but otherwise unicode_strlen() is unused 46 width = unicode_strlen(unicode_0x394);
36 width = mbstowcs(NULL, unicode_0x394, INT_MAX);
37 unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF); 47 unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF);
38} 48}
39 49
40void FAST_FUNC init_unicode(void) 50void FAST_FUNC init_unicode(void)
41{ 51{
42 if (unicode_status == UNICODE_UNKNOWN) 52 /* Some people set only $LC_CTYPE, not $LC_ALL, because they want
43 reinit_unicode(getenv("LANG")); 53 * only Unicode to be activated on their system, not the whole
54 * shebang of wrong decimal points, strange date formats and so on.
55 */
56 if (unicode_status == UNICODE_UNKNOWN) {
57 char *s = getenv("LC_ALL");
58 if (!s) s = getenv("LC_CTYPE");
59 if (!s) s = getenv("LANG");
60 reinit_unicode(s);
61 }
44} 62}
45 63
46#else 64#else
@@ -58,8 +76,12 @@ void FAST_FUNC reinit_unicode(const char *LANG)
58 76
59void FAST_FUNC init_unicode(void) 77void FAST_FUNC init_unicode(void)
60{ 78{
61 if (unicode_status == UNICODE_UNKNOWN) 79 if (unicode_status == UNICODE_UNKNOWN) {
62 reinit_unicode(getenv("LANG")); 80 char *s = getenv("LC_ALL");
81 if (!s) s = getenv("LC_CTYPE");
82 if (!s) s = getenv("LANG");
83 reinit_unicode(s);
84 }
63} 85}
64# endif 86# endif
65 87
@@ -963,7 +985,6 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc)
963 985
964/* The rest is mostly same for libc and for "homegrown" support */ 986/* The rest is mostly same for libc and for "homegrown" support */
965 987
966#if 0 // UNUSED
967size_t FAST_FUNC unicode_strlen(const char *string) 988size_t FAST_FUNC unicode_strlen(const char *string)
968{ 989{
969 size_t width = mbstowcs(NULL, string, INT_MAX); 990 size_t width = mbstowcs(NULL, string, INT_MAX);
@@ -971,7 +992,6 @@ size_t FAST_FUNC unicode_strlen(const char *string)
971 return strlen(string); 992 return strlen(string);
972 return width; 993 return width;
973} 994}
974#endif
975 995
976size_t FAST_FUNC unicode_strwidth(const char *string) 996size_t FAST_FUNC unicode_strwidth(const char *string)
977{ 997{
diff --git a/libbb/xatonum.c b/libbb/xatonum.c
index 62bbe53e7..6f4e023bb 100644
--- a/libbb/xatonum.c
+++ b/libbb/xatonum.c
@@ -68,3 +68,10 @@ uint16_t FAST_FUNC xatou16(const char *numstr)
68{ 68{
69 return xatou_range(numstr, 0, 0xffff); 69 return xatou_range(numstr, 0, 0xffff);
70} 70}
71
72const struct suffix_mult bkm_suffixes[] = {
73 { "b", 512 },
74 { "k", 1024 },
75 { "m", 1024*1024 },
76 { "", 0 }
77};
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 05aa07ce8..a70683241 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -541,13 +541,11 @@ int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp)
541 541
542char* FAST_FUNC xmalloc_ttyname(int fd) 542char* FAST_FUNC xmalloc_ttyname(int fd)
543{ 543{
544 char *buf = xzalloc(128); 544 char buf[128];
545 int r = ttyname_r(fd, buf, 127); 545 int r = ttyname_r(fd, buf, sizeof(buf) - 1);
546 if (r) { 546 if (r)
547 free(buf); 547 return NULL;
548 buf = NULL; 548 return xstrdup(buf);
549 }
550 return buf;
551} 549}
552 550
553void FAST_FUNC generate_uuid(uint8_t *buf) 551void FAST_FUNC generate_uuid(uint8_t *buf)
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c
index a36f920f4..29f0fbe91 100644
--- a/loginutils/cryptpw.c
+++ b/loginutils/cryptpw.c
@@ -92,6 +92,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv)
92{ 92{
93 char salt[MAX_PW_SALT_LEN]; 93 char salt[MAX_PW_SALT_LEN];
94 char *salt_ptr; 94 char *salt_ptr;
95 char *password;
95 const char *opt_m, *opt_S; 96 const char *opt_m, *opt_S;
96 int fd; 97 int fd;
97 98
@@ -123,15 +124,19 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv)
123 124
124 xmove_fd(fd, STDIN_FILENO); 125 xmove_fd(fd, STDIN_FILENO);
125 126
126 puts(pw_encrypt( 127 password = argv[0];
127 argv[0] ? argv[0] : ( 128 if (!password) {
128 /* Only mkpasswd, and only from tty, prompts. 129 /* Only mkpasswd, and only from tty, prompts.
129 * Otherwise it is a plain read. */ 130 * Otherwise it is a plain read. */
130 (isatty(STDIN_FILENO) && applet_name[0] == 'm') 131 password = (isatty(STDIN_FILENO) && applet_name[0] == 'm')
131 ? bb_ask_stdin("Password: ") 132 ? bb_ask_stdin("Password: ")
132 : xmalloc_fgetline(stdin) 133 : xmalloc_fgetline(stdin)
133 ), 134 ;
134 salt, 1)); 135 /* may still be NULL on EOF/error */
136 }
137
138 if (password)
139 puts(pw_encrypt(password, salt, 1));
135 140
136 return EXIT_SUCCESS; 141 return EXIT_SUCCESS;
137} 142}
diff --git a/loginutils/getty.c b/loginutils/getty.c
index e5d13bed6..0f060ae6c 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -695,6 +695,6 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
695 /* We use PATH because we trust that root doesn't set "bad" PATH, 695 /* We use PATH because we trust that root doesn't set "bad" PATH,
696 * and getty is not suid-root applet */ 696 * and getty is not suid-root applet */
697 /* With -n, logname == NULL, and login will ask for username instead */ 697 /* With -n, logname == NULL, and login will ask for username instead */
698 BB_EXECLP(G.login, G.login, "--", logname, NULL); 698 BB_EXECLP(G.login, G.login, "--", logname, (char *)0);
699 bb_error_msg_and_die("can't execute '%s'", G.login); 699 bb_error_msg_and_die("can't execute '%s'", G.login);
700} 700}
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c
index bd2b09eed..65e638489 100644
--- a/loginutils/sulogin.c
+++ b/loginutils/sulogin.c
@@ -79,12 +79,12 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
79 char *encrypted; 79 char *encrypted;
80 int r; 80 int r;
81 81
82 /* cp points to a static buffer that is zeroed every time */ 82 /* cp points to a static buffer */
83 cp = bb_ask(STDIN_FILENO, timeout, 83 cp = bb_ask(STDIN_FILENO, timeout,
84 "Give root password for system maintenance\n" 84 "Give root password for system maintenance\n"
85 "(or type Control-D for normal startup):"); 85 "(or type Control-D for normal startup):");
86 86 if (!cp) {
87 if (!cp || !*cp) { 87 /* ^D, ^C, timeout, or read error */
88 bb_info_msg("Normal startup"); 88 bb_info_msg("Normal startup");
89 return 0; 89 return 0;
90 } 90 }
diff --git a/miscutils/chrt.c b/miscutils/chrt.c
index 91b5397c4..f2f559fd7 100644
--- a/miscutils/chrt.c
+++ b/miscutils/chrt.c
@@ -23,9 +23,6 @@
23 23
24#include <sched.h> 24#include <sched.h>
25#include "libbb.h" 25#include "libbb.h"
26#ifndef _POSIX_PRIORITY_SCHEDULING
27#warning your system may be foobared
28#endif
29 26
30static const struct { 27static const struct {
31 int policy; 28 int policy;
diff --git a/miscutils/less.c b/miscutils/less.c
index 5ce0a1203..60105f42b 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -1608,6 +1608,9 @@ static void sigwinch_handler(int sig UNUSED_PARAM)
1608int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1608int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1609int less_main(int argc, char **argv) 1609int less_main(int argc, char **argv)
1610{ 1610{
1611 char *tty_name;
1612 int tty_fd;
1613
1611 INIT_G(); 1614 INIT_G();
1612 1615
1613 /* TODO: -x: do not interpret backspace, -xx: tab also */ 1616 /* TODO: -x: do not interpret backspace, -xx: tab also */
@@ -1637,10 +1640,28 @@ int less_main(int argc, char **argv)
1637 if (option_mask32 & FLAG_TILDE) 1640 if (option_mask32 & FLAG_TILDE)
1638 empty_line_marker = ""; 1641 empty_line_marker = "";
1639 1642
1640 kbd_fd = open(CURRENT_TTY, O_RDONLY); 1643 /* Some versions of less can survive w/o controlling tty,
1641 if (kbd_fd < 0) 1644 * try to do the same. This also allows to specify an alternative
1642 return bb_cat(argv); 1645 * tty via "less 1<>TTY".
1643 ndelay_on(kbd_fd); 1646 * We don't try to use STDOUT_FILENO directly,
1647 * since we want to set this fd to non-blocking mode,
1648 * and not bother with restoring it on exit.
1649 */
1650 tty_name = xmalloc_ttyname(STDOUT_FILENO);
1651 if (tty_name) {
1652 tty_fd = open(tty_name, O_RDONLY);
1653 free(tty_name);
1654 if (tty_fd < 0)
1655 goto try_ctty;
1656 } else {
1657 /* Try controlling tty */
1658 try_ctty:
1659 tty_fd = open(CURRENT_TTY, O_RDONLY);
1660 if (tty_fd < 0)
1661 return bb_cat(argv);
1662 }
1663 ndelay_on(tty_fd);
1664 kbd_fd = tty_fd; /* save in a global */
1644 1665
1645 tcgetattr(kbd_fd, &term_orig); 1666 tcgetattr(kbd_fd, &term_orig);
1646 term_less = term_orig; 1667 term_less = term_orig;
diff --git a/miscutils/man.c b/miscutils/man.c
index b8b15b83b..429898643 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -162,7 +162,7 @@ int man_main(int argc UNUSED_PARAM, char **argv)
162 opt = getopt32(argv, "+aw"); 162 opt = getopt32(argv, "+aw");
163 argv += optind; 163 argv += optind;
164 164
165 sec_list = xstrdup("1:2:3:4:5:6:7:8:9"); 165 sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9");
166 /* Last valid man_path_list[] is [0x10] */ 166 /* Last valid man_path_list[] is [0x10] */
167 count_mp = 0; 167 count_mp = 0;
168 man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); 168 man_path_list = xzalloc(0x11 * sizeof(man_path_list[0]));
diff --git a/miscutils/setsid.c b/miscutils/setsid.c
index ad2c8a4de..637081b6c 100644
--- a/miscutils/setsid.c
+++ b/miscutils/setsid.c
@@ -31,7 +31,17 @@ int setsid_main(int argc UNUSED_PARAM, char **argv)
31 31
32 /* setsid() is allowed only when we are not a process group leader. 32 /* setsid() is allowed only when we are not a process group leader.
33 * Otherwise our PID serves as PGID of some existing process group 33 * Otherwise our PID serves as PGID of some existing process group
34 * and cannot be used as PGID of a new process group. */ 34 * and cannot be used as PGID of a new process group.
35 *
36 * Example: setsid() below fails when run alone in interactive shell:
37 * $ setsid PROG
38 * because shell's child (setsid) is put in a new process group.
39 * But doesn't fail if shell is not interactive
40 * (and therefore doesn't create process groups for pipes),
41 * or if setsid is not the first process in the process group:
42 * $ true | setsid PROG
43 * or if setsid is executed in backquotes (`setsid PROG`)...
44 */
35 if (setsid() < 0) { 45 if (setsid() < 0) {
36 pid_t pid = fork_or_rexec(argv); 46 pid_t pid = fork_or_rexec(argv);
37 if (pid != 0) { 47 if (pid != 0) {
@@ -43,7 +53,7 @@ int setsid_main(int argc UNUSED_PARAM, char **argv)
43 * However, the code is larger and upstream 53 * However, the code is larger and upstream
44 * does not do such trick. 54 * does not do such trick.
45 */ 55 */
46 exit(EXIT_SUCCESS); 56 return EXIT_SUCCESS;
47 } 57 }
48 58
49 /* child */ 59 /* child */
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c
index dd99a44f4..b71393532 100644
--- a/miscutils/ubi_tools.c
+++ b/miscutils/ubi_tools.c
@@ -66,14 +66,6 @@
66#endif 66#endif
67#include <mtd/ubi-user.h> 67#include <mtd/ubi-user.h>
68 68
69#define OPTION_M (1 << 0)
70#define OPTION_D (1 << 1)
71#define OPTION_n (1 << 2)
72#define OPTION_N (1 << 3)
73#define OPTION_s (1 << 4)
74#define OPTION_a (1 << 5)
75#define OPTION_t (1 << 6)
76
77#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') 69#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a')
78#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') 70#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd')
79#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') 71#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm')
@@ -81,191 +73,250 @@
81#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') 73#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's')
82#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u') 74#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u')
83 75
84//usage:#define ubiattach_trivial_usage 76static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg)
85//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV" 77{
86//usage:#define ubiattach_full_usage "\n\n" 78 char buf[sizeof(long long)*3];
87//usage: "Attach MTD device to UBI\n" 79 unsigned long long num;
88//usage: "\n -m MTD_NUM MTD device number to attach" 80
89//usage: "\n -d UBI_NUM UBI device number to assign" 81 if (open_read_close(path, buf, sizeof(buf)) < 0)
90//usage: 82 bb_perror_msg_and_die(errmsg, path);
91//usage:#define ubidetach_trivial_usage 83 /* It can be \n terminated, xatoull won't work well */
92//usage: "-d UBI_NUM UBI_CTRL_DEV" 84 if (sscanf(buf, "%llu", &num) != 1 || num > max)
93//usage:#define ubidetach_full_usage "\n\n" 85 bb_error_msg_and_die(errmsg, path);
94//usage: "Detach MTD device from UBI\n" 86 return num;
95//usage: "\n -d UBI_NUM UBI device number" 87}
96//usage:
97//usage:#define ubimkvol_trivial_usage
98//usage: "UBI_DEVICE -N NAME -s SIZE"
99//usage:#define ubimkvol_full_usage "\n\n"
100//usage: "Create UBI volume\n"
101//usage: "\n -a ALIGNMENT Volume alignment (default 1)"
102//usage: "\n -n VOLID Volume ID, if not specified, it"
103//usage: "\n will be assigned automatically"
104//usage: "\n -N NAME Volume name"
105//usage: "\n -s SIZE Size in bytes"
106//usage: "\n -t TYPE Volume type (static|dynamic)"
107//usage:
108//usage:#define ubirmvol_trivial_usage
109//usage: "UBI_DEVICE -n VOLID"
110//usage:#define ubirmvol_full_usage "\n\n"
111//usage: "Remove UBI volume\n"
112//usage: "\n -n VOLID Volume ID"
113//usage:
114//usage:#define ubirsvol_trivial_usage
115//usage: "UBI_DEVICE -n VOLID -s SIZE"
116//usage:#define ubirsvol_full_usage "\n\n"
117//usage: "Resize UBI volume\n"
118//usage: "\n -n VOLID Volume ID to resize"
119//usage: "\n -s SIZE Size in bytes"
120//usage:
121//usage:#define ubiupdatevol_trivial_usage
122//usage: "UBI_DEVICE [IMG_FILE]"
123//usage:#define ubiupdatevol_full_usage "\n\n"
124//usage: "Update UBI volume\n"
125//usage: "\n -t Truncate UBI volume"
126//usage: "\n -s SIZE Bytes in input (if reading stdin)"
127 88
89/* To prevent malloc(1G) accidents */
90#define MAX_SANE_ERASEBLOCK (16*1024*1024)
128 91
129int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 92int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
130int ubi_tools_main(int argc UNUSED_PARAM, char **argv) 93int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
131{ 94{
95 static const struct suffix_mult size_suffixes[] = {
96 { "KiB", 1024 },
97 { "MiB", 1024*1024 },
98 { "GiB", 1024*1024*1024 },
99 { "", 0 }
100 };
101
132 unsigned opts; 102 unsigned opts;
133 char *ubi_ctrl; 103 char *ubi_ctrl;
134 //struct stat st;
135 int fd; 104 int fd;
136 int mtd_num; 105 int mtd_num;
137 int dev_num = UBI_DEV_NUM_AUTO; 106 int dev_num = UBI_DEV_NUM_AUTO;
138 int vol_id = UBI_VOL_NUM_AUTO; 107 int vol_id = UBI_VOL_NUM_AUTO;
139 char *vol_name = NULL; 108 char *vol_name;
140 int size_bytes; 109 unsigned long long size_bytes = size_bytes; /* for compiler */
110 char *size_bytes_str;
141 int alignment = 1; 111 int alignment = 1;
142 char *type = NULL; 112 char *type;
113 union {
114 struct ubi_attach_req attach_req;
115 struct ubi_mkvol_req mkvol_req;
116 struct ubi_rsvol_req rsvol_req;
117 } req_structs;
118#define attach_req req_structs.attach_req
119#define mkvol_req req_structs.mkvol_req
120#define rsvol_req req_structs.rsvol_req
121 char path[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size")
122 + 2 * sizeof(int)*3 + /*just in case:*/ 16];
123#define path_sys_class_ubi_ubi (path + sizeof("/sys/class/ubi/ubi")-1)
124
125 strcpy(path, "/sys/class/ubi/ubi");
126 memset(&req_structs, 0, sizeof(req_structs));
127
128 if (do_mkvol) {
129 opt_complementary = "-1:d+:n+:a+";
130 opts = getopt32(argv, "md:n:N:s:a:t:",
131 &dev_num, &vol_id,
132 &vol_name, &size_bytes_str, &alignment, &type
133 );
134 } else {
135 opt_complementary = "-1:m+:d+:n+:a+";
136 opts = getopt32(argv, "m:d:n:N:s:a:t:",
137 &mtd_num, &dev_num, &vol_id,
138 &vol_name, &size_bytes_str, &alignment, &type
139 );
140 }
141#define OPTION_m (1 << 0)
142#define OPTION_d (1 << 1)
143#define OPTION_n (1 << 2)
144#define OPTION_N (1 << 3)
145#define OPTION_s (1 << 4)
146#define OPTION_a (1 << 5)
147#define OPTION_t (1 << 6)
143 148
144 opt_complementary = "-1:m+:d+:n+:s+:a+"; 149 if (opts & OPTION_s)
145 opts = getopt32(argv, "m:d:n:N:s:a:t::", 150 size_bytes = xatoull_sfx(size_bytes_str, size_suffixes);
146 &mtd_num, &dev_num, &vol_id, 151 argv += optind;
147 &vol_name, &size_bytes, &alignment, &type 152 ubi_ctrl = *argv++;
148 );
149 ubi_ctrl = argv[optind];
150 153
151 fd = xopen(ubi_ctrl, O_RDWR); 154 fd = xopen(ubi_ctrl, O_RDWR);
152 //xfstat(fd, &st, ubi_ctrl); 155 //xfstat(fd, &st, ubi_ctrl);
153 //if (!S_ISCHR(st.st_mode)) 156 //if (!S_ISCHR(st.st_mode))
154 // bb_error_msg_and_die("%s: not a char device", ubi_ctrl); 157 // bb_error_msg_and_die("%s: not a char device", ubi_ctrl);
155 158
159//usage:#define ubiattach_trivial_usage
160//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV"
161//usage:#define ubiattach_full_usage "\n\n"
162//usage: "Attach MTD device to UBI\n"
163//usage: "\n -m MTD_NUM MTD device number to attach"
164//usage: "\n -d UBI_NUM UBI device number to assign"
156 if (do_attach) { 165 if (do_attach) {
157 struct ubi_attach_req req; 166 if (!(opts & OPTION_m))
158 if (!(opts & OPTION_M))
159 bb_error_msg_and_die("%s device not specified", "MTD"); 167 bb_error_msg_and_die("%s device not specified", "MTD");
160 168
161 memset(&req, 0, sizeof(req)); 169 attach_req.mtd_num = mtd_num;
162 req.mtd_num = mtd_num; 170 attach_req.ubi_num = dev_num;
163 req.ubi_num = dev_num;
164 171
165 xioctl(fd, UBI_IOCATT, &req); 172 xioctl(fd, UBI_IOCATT, &attach_req);
166 } else 173 } else
174
175//usage:#define ubidetach_trivial_usage
176//usage: "-d UBI_NUM UBI_CTRL_DEV"
177//usage:#define ubidetach_full_usage "\n\n"
178//usage: "Detach MTD device from UBI\n"
179//usage: "\n -d UBI_NUM UBI device number"
167 if (do_detach) { 180 if (do_detach) {
168 if (!(opts & OPTION_D)) 181 if (!(opts & OPTION_d))
169 bb_error_msg_and_die("%s device not specified", "UBI"); 182 bb_error_msg_and_die("%s device not specified", "UBI");
170 183
184 /* FIXME? kernel expects int32_t* here: */
171 xioctl(fd, UBI_IOCDET, &dev_num); 185 xioctl(fd, UBI_IOCDET, &dev_num);
172 } else 186 } else
187
188//usage:#define ubimkvol_trivial_usage
189//usage: "UBI_DEVICE -N NAME [-s SIZE | -m]"
190//usage:#define ubimkvol_full_usage "\n\n"
191//usage: "Create UBI volume\n"
192//usage: "\n -a ALIGNMENT Volume alignment (default 1)"
193//usage: "\n -m Set volume size to maximum available"
194//usage: "\n -n VOLID Volume ID. If not specified,"
195//usage: "\n assigned automatically"
196//usage: "\n -N NAME Volume name"
197//usage: "\n -s SIZE Size in bytes"
198//usage: "\n -t TYPE Volume type (static|dynamic)"
173 if (do_mkvol) { 199 if (do_mkvol) {
174 struct ubi_mkvol_req req; 200 if (opts & OPTION_m) {
175 int vol_name_len; 201 unsigned leb_avail;
202 unsigned leb_size;
203 unsigned num;
204 char *p;
205
206 if (sscanf(ubi_ctrl, "/dev/ubi%u", &num) != 1)
207 bb_error_msg_and_die("wrong format of UBI device name");
208
209 p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num);
210
211 strcpy(p, "avail_eraseblocks");
212 leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'");
213
214 strcpy(p, "eraseblock_size");
215 leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'");
216
217 size_bytes = leb_avail * (unsigned long long)leb_size;
218 //if (size_bytes <= 0)
219 // bb_error_msg_and_die("%s invalid maximum size calculated", "UBI");
220 } else
176 if (!(opts & OPTION_s)) 221 if (!(opts & OPTION_s))
177 bb_error_msg_and_die("%s size not specified", "UBI"); 222 bb_error_msg_and_die("size not specified");
223
178 if (!(opts & OPTION_N)) 224 if (!(opts & OPTION_N))
179 bb_error_msg_and_die("%s name not specified", "UBI"); 225 bb_error_msg_and_die("name not specified");
180 vol_name_len = strlen(vol_name); 226
181 if (vol_name_len > UBI_MAX_VOLUME_NAME) 227 mkvol_req.vol_id = vol_id;
182 bb_error_msg_and_die("%s volume name too long", "UBI"); 228 mkvol_req.vol_type = UBI_DYNAMIC_VOLUME;
183 229 if ((opts & OPTION_t) && type[0] == 's')
184 memset(&req, 0, sizeof(req)); 230 mkvol_req.vol_type = UBI_STATIC_VOLUME;
185 req.vol_id = vol_id; 231 mkvol_req.alignment = alignment;
186 if ((opts & OPTION_t) && type) { 232 mkvol_req.bytes = size_bytes; /* signed int64_t */
187 if (type[0] == 's') 233 strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME);
188 req.vol_type = UBI_STATIC_VOLUME; 234 mkvol_req.name_len = strlen(vol_name);
189 else 235 if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME)
190 req.vol_type = UBI_DYNAMIC_VOLUME; 236 bb_error_msg_and_die("volume name too long: '%s'", vol_name);
191 } else {
192 req.vol_type = UBI_DYNAMIC_VOLUME;
193 }
194 req.alignment = alignment;
195 req.bytes = size_bytes;
196 strncpy(req.name, vol_name, UBI_MAX_VOLUME_NAME);
197 req.name_len = vol_name_len;
198 237
199 xioctl(fd, UBI_IOCMKVOL, &req); 238 xioctl(fd, UBI_IOCMKVOL, &mkvol_req);
200 } else 239 } else
240
241//usage:#define ubirmvol_trivial_usage
242//usage: "UBI_DEVICE -n VOLID"
243//usage:#define ubirmvol_full_usage "\n\n"
244//usage: "Remove UBI volume\n"
245//usage: "\n -n VOLID Volume ID"
201 if (do_rmvol) { 246 if (do_rmvol) {
202 if (!(opts & OPTION_n)) 247 if (!(opts & OPTION_n))
203 bb_error_msg_and_die("%s volume id not specified", "UBI"); 248 bb_error_msg_and_die("volume id not specified");
204 249
250 /* FIXME? kernel expects int32_t* here: */
205 xioctl(fd, UBI_IOCRMVOL, &vol_id); 251 xioctl(fd, UBI_IOCRMVOL, &vol_id);
206 } else 252 } else
253
254//usage:#define ubirsvol_trivial_usage
255//usage: "UBI_DEVICE -n VOLID -s SIZE"
256//usage:#define ubirsvol_full_usage "\n\n"
257//usage: "Resize UBI volume\n"
258//usage: "\n -n VOLID Volume ID"
259//usage: "\n -s SIZE Size in bytes"
207 if (do_rsvol) { 260 if (do_rsvol) {
208 struct ubi_rsvol_req req;
209 if (!(opts & OPTION_s)) 261 if (!(opts & OPTION_s))
210 bb_error_msg_and_die("%s size not specified", "UBI"); 262 bb_error_msg_and_die("size not specified");
211 if (!(opts & OPTION_n)) 263 if (!(opts & OPTION_n))
212 bb_error_msg_and_die("%s volume id not specified", "UBI"); 264 bb_error_msg_and_die("volume id not specified");
213 265
214 memset(&req, 0, sizeof(req)); 266 rsvol_req.bytes = size_bytes; /* signed int64_t */
215 req.bytes = size_bytes; 267 rsvol_req.vol_id = vol_id;
216 req.vol_id = vol_id;
217 268
218 xioctl(fd, UBI_IOCRSVOL, &req); 269 xioctl(fd, UBI_IOCRSVOL, &rsvol_req);
219 } else 270 } else
271
272//usage:#define ubiupdatevol_trivial_usage
273//usage: "UBI_DEVICE [-t | [-s SIZE] IMG_FILE]"
274//usage:#define ubiupdatevol_full_usage "\n\n"
275//usage: "Update UBI volume\n"
276//usage: "\n -t Truncate to zero size"
277//usage: "\n -s SIZE Size in bytes to resize to"
220 if (do_update) { 278 if (do_update) {
221 long long bytes; 279 int64_t bytes64;
222 280
223 if (opts & OPTION_t) { 281 if (opts & OPTION_t) {
224 // truncate the volume by starting an update for size 0 282 /* truncate the volume by starting an update for size 0 */
225 bytes = 0; 283 bytes64 = 0;
226 xioctl(fd, UBI_IOCVOLUP, &bytes); 284 /* this ioctl expects int64_t* parameter */
285 xioctl(fd, UBI_IOCVOLUP, &bytes64);
227 } 286 }
228 else { 287 else {
229 struct stat st; 288 struct stat st;
230 char buf[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size") + 2 * sizeof(int)*3];
231 int input_fd;
232 unsigned ubinum, volnum; 289 unsigned ubinum, volnum;
233 unsigned leb_size; 290 unsigned leb_size;
234 ssize_t len; 291 ssize_t len;
235 char *input_data; 292 char *input_data;
236 293
237 // Make assumption that device not is in normal format. 294 /* Assume that device is in normal format. */
238 // Removes need for scanning sysfs tree as full libubi does 295 /* Removes need for scanning sysfs tree as full libubi does. */
239 if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) 296 if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2)
240 bb_error_msg_and_die("%s volume node not in correct format", "UBI"); 297 bb_error_msg_and_die("wrong format of UBI device name");
241 298
242 sprintf(buf, "/sys/class/ubi/ubi%u_%u/usable_eb_size", ubinum, volnum); 299 sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum);
243 if (open_read_close(buf, buf, sizeof(buf)) <= 0) 300 leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'");
244 bb_error_msg_and_die("%s could not get LEB size", "UBI"); 301
245 if (sscanf(buf, "%u", &leb_size) != 1) 302 if (!(opts & OPTION_s)) {
246 bb_error_msg_and_die("%s could not get LEB size", "UBI"); 303 if (!*argv)
247
248 if (opts & OPTION_s) {
249 input_fd = 0;
250 } else {
251 if (!argv[optind+1])
252 bb_show_usage(); 304 bb_show_usage();
253 xstat(argv[optind+1], &st); 305 xstat(*argv, &st);
254 size_bytes = st.st_size; 306 size_bytes = st.st_size;
255 input_fd = xopen(argv[optind+1], O_RDONLY); 307 xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO);
256 } 308 }
257 309
258 bytes = size_bytes; 310 bytes64 = size_bytes;
259 xioctl(fd, UBI_IOCVOLUP, &bytes); 311 /* this ioctl expects signed int64_t* parameter */
312 xioctl(fd, UBI_IOCVOLUP, &bytes64);
260 313
261 input_data = xmalloc(leb_size); 314 input_data = xmalloc(leb_size);
262 while ((len = full_read(input_fd, input_data, leb_size)) > 0) { 315 while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) {
263 xwrite(fd, input_data, len); 316 xwrite(fd, input_data, len);
264 } 317 }
265 if (len < 0) 318 if (len < 0)
266 bb_error_msg_and_die("%s volume update failed", "UBI"); 319 bb_perror_msg_and_die("UBI volume update failed");
267 if (ENABLE_FEATURE_CLEAN_UP)
268 close(input_fd);
269 } 320 }
270 } 321 }
271 322
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index fb6c65990..7f7446d8e 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -171,7 +171,7 @@ struct globals {
171} FIX_ALIASING; 171} FIX_ALIASING;
172#define G (*ptr_to_globals) 172#define G (*ptr_to_globals)
173#define INIT_G() do { \ 173#define INIT_G() do { \
174 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 174 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
175} while (0) 175} while (0)
176 176
177 177
diff --git a/networking/httpd.c b/networking/httpd.c
index b46eb0fab..cef9b8baf 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1709,8 +1709,8 @@ static int pam_talker(int num_msg,
1709 s = userinfo->pw; 1709 s = userinfo->pw;
1710 break; 1710 break;
1711 case PAM_ERROR_MSG: 1711 case PAM_ERROR_MSG:
1712 case PAM_TEXT_INFO: 1712 case PAM_TEXT_INFO:
1713 s = ""; 1713 s = "";
1714 break; 1714 break;
1715 default: 1715 default:
1716 free(response); 1716 free(response);
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 782374b35..8984b0207 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -56,7 +56,7 @@
56#endif 56#endif
57 57
58#if ENABLE_FEATURE_IFCONFIG_SLIP 58#if ENABLE_FEATURE_IFCONFIG_SLIP
59# include <net/if_slip.h> 59# include <linux/if_slip.h>
60#endif 60#endif
61 61
62/* I don't know if this is needed for busybox or not. Anyone? */ 62/* I don't know if this is needed for busybox or not. Anyone? */
@@ -265,49 +265,6 @@ static const struct options OptArray[] = {
265 { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING) } 265 { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING) }
266}; 266};
267 267
268#if ENABLE_FEATURE_IFCONFIG_HW
269/* Input an Ethernet address and convert to binary. */
270static int in_ether(const char *bufp, struct sockaddr *sap)
271{
272 char *ptr;
273 int i, j;
274 unsigned char val;
275 unsigned char c;
276
277 sap->sa_family = ARPHRD_ETHER;
278 ptr = (char *) sap->sa_data;
279
280 i = 0;
281 do {
282 j = val = 0;
283
284 /* We might get a semicolon here - not required. */
285 if (i && (*bufp == ':')) {
286 bufp++;
287 }
288
289 do {
290 c = *bufp;
291 if (((unsigned char)(c - '0')) <= 9) {
292 c -= '0';
293 } else if ((unsigned char)((c|0x20) - 'a') <= 5) {
294 c = (unsigned char)((c|0x20) - 'a') + 10;
295 } else if (j && (c == ':' || c == 0)) {
296 break;
297 } else {
298 return -1;
299 }
300 ++bufp;
301 val <<= 4;
302 val += c;
303 } while (++j < 2);
304 *ptr++ = val;
305 } while (++i < ETH_ALEN);
306
307 return *bufp; /* Error if we don't end at end of string. */
308}
309#endif
310
311int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 268int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
312int ifconfig_main(int argc UNUSED_PARAM, char **argv) 269int ifconfig_main(int argc UNUSED_PARAM, char **argv)
313{ 270{
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index 3cdc2c9d2..b578f4c61 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -451,20 +451,24 @@ static smallint detect_link(void)
451static NOINLINE int check_existence_through_netlink(void) 451static NOINLINE int check_existence_through_netlink(void)
452{ 452{
453 int iface_len; 453 int iface_len;
454 char replybuf[1024]; 454 /* Buffer was 1K, but on linux-3.9.9 it was reported to be too small.
455 * netlink.h: "limit to 8K to avoid MSG_TRUNC when PAGE_SIZE is very large".
456 * Note: on error returns (-1) we exit, no need to free replybuf.
457 */
458 enum { BUF_SIZE = 8 * 1024 };
459 char *replybuf = xmalloc(BUF_SIZE);
455 460
456 iface_len = strlen(G.iface); 461 iface_len = strlen(G.iface);
457 while (1) { 462 while (1) {
458 struct nlmsghdr *mhdr; 463 struct nlmsghdr *mhdr;
459 ssize_t bytes; 464 ssize_t bytes;
460 465
461 bytes = recv(netlink_fd, &replybuf, sizeof(replybuf), MSG_DONTWAIT); 466 bytes = recv(netlink_fd, replybuf, BUF_SIZE, MSG_DONTWAIT);
462 if (bytes < 0) { 467 if (bytes < 0) {
463 if (errno == EAGAIN) 468 if (errno == EAGAIN)
464 return G.iface_exists; 469 goto ret;
465 if (errno == EINTR) 470 if (errno == EINTR)
466 continue; 471 continue;
467
468 bb_perror_msg("netlink: recv"); 472 bb_perror_msg("netlink: recv");
469 return -1; 473 return -1;
470 } 474 }
@@ -507,6 +511,8 @@ static NOINLINE int check_existence_through_netlink(void)
507 } 511 }
508 } 512 }
509 513
514 ret:
515 free(replybuf);
510 return G.iface_exists; 516 return G.iface_exists;
511} 517}
512 518
diff --git a/networking/interface.c b/networking/interface.c
index 9ae8b3f03..bf7d2b1b4 100644
--- a/networking/interface.c
+++ b/networking/interface.c
@@ -722,68 +722,15 @@ static char* FAST_FUNC ether_print(unsigned char *ptr)
722 return buff; 722 return buff;
723} 723}
724 724
725static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap);
726
727static const struct hwtype ether_hwtype = { 725static const struct hwtype ether_hwtype = {
728 .name = "ether", 726 .name = "ether",
729 .title = "Ethernet", 727 .title = "Ethernet",
730 .type = ARPHRD_ETHER, 728 .type = ARPHRD_ETHER,
731 .alen = ETH_ALEN, 729 .alen = ETH_ALEN,
732 .print = ether_print, 730 .print = ether_print,
733 .input = ether_input 731 .input = in_ether
734}; 732};
735 733
736static unsigned hexchar2int(char c)
737{
738 if (isdigit(c))
739 return c - '0';
740 c &= ~0x20; /* a -> A */
741 if ((unsigned)(c - 'A') <= 5)
742 return c - ('A' - 10);
743 return ~0U;
744}
745
746/* Input an Ethernet address and convert to binary. */
747static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap)
748{
749 unsigned char *ptr;
750 char c;
751 int i;
752 unsigned val;
753
754 sap->sa_family = ether_hwtype.type;
755 ptr = (unsigned char*) sap->sa_data;
756
757 i = 0;
758 while ((*bufp != '\0') && (i < ETH_ALEN)) {
759 val = hexchar2int(*bufp++) * 0x10;
760 if (val > 0xff) {
761 errno = EINVAL;
762 return -1;
763 }
764 c = *bufp;
765 if (c == ':' || c == 0)
766 val >>= 4;
767 else {
768 val |= hexchar2int(c);
769 if (val > 0xff) {
770 errno = EINVAL;
771 return -1;
772 }
773 }
774 if (c != 0)
775 bufp++;
776 *ptr++ = (unsigned char) val;
777 i++;
778
779 /* We might get a semicolon here - not required. */
780 if (*bufp == ':') {
781 bufp++;
782 }
783 }
784 return 0;
785}
786
787static const struct hwtype ppp_hwtype = { 734static const struct hwtype ppp_hwtype = {
788 .name = "ppp", 735 .name = "ppp",
789 .title = "Point-to-Point Protocol", 736 .title = "Point-to-Point Protocol",
@@ -927,7 +874,7 @@ static void print_bytes_scaled(unsigned long long ull, const char *end)
927static void ife_print6(struct interface *ptr) 874static void ife_print6(struct interface *ptr)
928{ 875{
929 FILE *f; 876 FILE *f;
930 char addr6[40], devname[20]; 877 char addr6[40], devname[21];
931 struct sockaddr_in6 sap; 878 struct sockaddr_in6 sap;
932 int plen, scope, dad_status, if_idx; 879 int plen, scope, dad_status, if_idx;
933 char addr6p[8][5]; 880 char addr6p[8][5];
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 3fd3f4478..aa4779ad1 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -627,10 +627,12 @@ static int ipaddr_modify(int cmd, char **argv)
627 req.ifa.ifa_family = preferred_family; 627 req.ifa.ifa_family = preferred_family;
628 628
629 while (*argv) { 629 while (*argv) {
630 const smalluint arg = index_in_strings(option, *argv); 630 unsigned arg = index_in_strings(option, *argv);
631 if (arg <= 1) { /* peer, remote */ 631 /* if search fails, "local" is assumed */
632 if ((int)arg >= 0)
632 NEXT_ARG(); 633 NEXT_ARG();
633 634
635 if (arg <= 1) { /* peer, remote */
634 if (peer_len) { 636 if (peer_len) {
635 duparg("peer", *argv); 637 duparg("peer", *argv);
636 } 638 }
@@ -643,7 +645,6 @@ static int ipaddr_modify(int cmd, char **argv)
643 req.ifa.ifa_prefixlen = peer.bitlen; 645 req.ifa.ifa_prefixlen = peer.bitlen;
644 } else if (arg <= 3) { /* broadcast, brd */ 646 } else if (arg <= 3) { /* broadcast, brd */
645 inet_prefix addr; 647 inet_prefix addr;
646 NEXT_ARG();
647 if (brd_len) { 648 if (brd_len) {
648 duparg("broadcast", *argv); 649 duparg("broadcast", *argv);
649 } 650 }
@@ -660,7 +661,6 @@ static int ipaddr_modify(int cmd, char **argv)
660 } 661 }
661 } else if (arg == 4) { /* anycast */ 662 } else if (arg == 4) { /* anycast */
662 inet_prefix addr; 663 inet_prefix addr;
663 NEXT_ARG();
664 if (any_len) { 664 if (any_len) {
665 duparg("anycast", *argv); 665 duparg("anycast", *argv);
666 } 666 }
@@ -672,22 +672,18 @@ static int ipaddr_modify(int cmd, char **argv)
672 any_len = addr.bytelen; 672 any_len = addr.bytelen;
673 } else if (arg == 5) { /* scope */ 673 } else if (arg == 5) { /* scope */
674 uint32_t scope = 0; 674 uint32_t scope = 0;
675 NEXT_ARG();
676 if (rtnl_rtscope_a2n(&scope, *argv)) { 675 if (rtnl_rtscope_a2n(&scope, *argv)) {
677 invarg(*argv, "scope"); 676 invarg(*argv, "scope");
678 } 677 }
679 req.ifa.ifa_scope = scope; 678 req.ifa.ifa_scope = scope;
680 scoped = 1; 679 scoped = 1;
681 } else if (arg == 6) { /* dev */ 680 } else if (arg == 6) { /* dev */
682 NEXT_ARG();
683 d = *argv; 681 d = *argv;
684 } else if (arg == 7) { /* label */ 682 } else if (arg == 7) { /* label */
685 NEXT_ARG();
686 l = *argv; 683 l = *argv;
687 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1); 684 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
688 } else { 685 } else {
689 if (arg == 8) /* local */ 686 /* local (specified or assumed) */
690 NEXT_ARG();
691 if (local_len) { 687 if (local_len) {
692 duparg2("local", *argv); 688 duparg2("local", *argv);
693 } 689 }
@@ -724,7 +720,7 @@ static int ipaddr_modify(int cmd, char **argv)
724 } 720 }
725 brd = peer; 721 brd = peer;
726 if (brd.bitlen <= 30) { 722 if (brd.bitlen <= 30) {
727 for (i=31; i>=brd.bitlen; i--) { 723 for (i = 31; i >= brd.bitlen; i--) {
728 if (brd_len == -1) 724 if (brd_len == -1)
729 brd.data[0] |= htonl(1<<(31-i)); 725 brd.data[0] |= htonl(1<<(31-i));
730 else 726 else
@@ -754,11 +750,11 @@ int FAST_FUNC do_ipaddr(char **argv)
754{ 750{
755 static const char commands[] ALIGN1 = 751 static const char commands[] ALIGN1 =
756 "add\0""delete\0""list\0""show\0""lst\0""flush\0"; 752 "add\0""delete\0""list\0""show\0""lst\0""flush\0";
757 smalluint cmd = 2; 753 int cmd = 2;
758 if (*argv) { 754 if (*argv) {
759 cmd = index_in_substrings(commands, *argv); 755 cmd = index_in_substrings(commands, *argv);
760 if (cmd > 5) 756 if (cmd < 0)
761 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 757 invarg(*argv, applet_name);
762 argv++; 758 argv++;
763 if (cmd <= 1) 759 if (cmd <= 1)
764 return ipaddr_modify((cmd == 0) ? RTM_NEWADDR : RTM_DELADDR, argv); 760 return ipaddr_modify((cmd == 0) ? RTM_NEWADDR : RTM_DELADDR, argv);
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index bad2017fe..286e59ebf 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -1,18 +1,33 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 3 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
4 * Patrick McHardy <kaber@trash.net>
4 * 5 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */ 7 */
7#include <net/if.h> 8#include <net/if.h>
8#include <net/if_packet.h> 9/*#include <net/if_packet.h> - not needed? */
9#include <netpacket/packet.h> 10#include <netpacket/packet.h>
10#include <netinet/if_ether.h> 11#include <netinet/if_ether.h>
11 12
13#include <linux/if_vlan.h>
12#include "ip_common.h" /* #include "libbb.h" is inside */ 14#include "ip_common.h" /* #include "libbb.h" is inside */
13#include "rt_names.h" 15#include "rt_names.h"
14#include "utils.h" 16#include "utils.h"
15 17
18#undef ETH_P_8021AD
19#define ETH_P_8021AD 0x88A8
20#undef VLAN_FLAG_REORDER_HDR
21#define VLAN_FLAG_REORDER_HDR 0x1
22#undef VLAN_FLAG_GVRP
23#define VLAN_FLAG_GVRP 0x2
24#undef VLAN_FLAG_LOOSE_BINDING
25#define VLAN_FLAG_LOOSE_BINDING 0x4
26#undef VLAN_FLAG_MVRP
27#define VLAN_FLAG_MVRP 0x8
28#undef IFLA_VLAN_PROTOCOL
29#define IFLA_VLAN_PROTOCOL 5
30
16#ifndef IFLA_LINKINFO 31#ifndef IFLA_LINKINFO
17# define IFLA_LINKINFO 18 32# define IFLA_LINKINFO 18
18# define IFLA_INFO_KIND 1 33# define IFLA_INFO_KIND 1
@@ -277,12 +292,103 @@ static int ipaddr_list_link(char **argv)
277 return ipaddr_list_or_flush(argv, 0); 292 return ipaddr_list_or_flush(argv, 0);
278} 293}
279 294
295static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
296{
297 static const char keywords[] ALIGN1 =
298 "id\0"
299 "protocol\0"
300 "reorder_hdr\0"
301 "gvrp\0"
302 "mvrp\0"
303 "loose_binding\0"
304 ;
305 static const char protocols[] ALIGN1 =
306 "802.1q\0"
307 "802.1ad\0"
308 ;
309 static const char str_on_off[] ALIGN1 =
310 "on\0"
311 "off\0"
312 ;
313 enum {
314 ARG_id = 0,
315 ARG_reorder_hdr,
316 ARG_gvrp,
317 ARG_mvrp,
318 ARG_loose_binding,
319 ARG_protocol,
320 };
321 enum {
322 PROTO_8021Q = 0,
323 PROTO_8021AD,
324 };
325 enum {
326 PARM_on = 0,
327 PARM_off
328 };
329 int arg;
330 uint16_t id, proto;
331 struct ifla_vlan_flags flags = {};
332
333 while (*argv) {
334 arg = index_in_substrings(keywords, *argv);
335 if (arg < 0)
336 invarg(*argv, "type vlan");
337
338 NEXT_ARG();
339 if (arg == ARG_id) {
340 id = get_u16(*argv, "id");
341 addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id));
342 } else if (arg == ARG_protocol) {
343 arg = index_in_substrings(protocols, *argv);
344 if (arg == PROTO_8021Q)
345 proto = ETH_P_8021Q;
346 else if (arg == PROTO_8021AD)
347 proto = ETH_P_8021AD;
348 else
349 bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'",
350 *argv);
351 addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
352 } else {
353 int param = index_in_strings(str_on_off, *argv);
354 if (param < 0)
355 die_must_be_on_off(nth_string(keywords, arg));
356
357 if (arg == ARG_reorder_hdr) {
358 flags.mask |= VLAN_FLAG_REORDER_HDR;
359 flags.flags &= ~VLAN_FLAG_REORDER_HDR;
360 if (param == PARM_on)
361 flags.flags |= VLAN_FLAG_REORDER_HDR;
362 } else if (arg == ARG_gvrp) {
363 flags.mask |= VLAN_FLAG_GVRP;
364 flags.flags &= ~VLAN_FLAG_GVRP;
365 if (param == PARM_on)
366 flags.flags |= VLAN_FLAG_GVRP;
367 } else if (arg == ARG_mvrp) {
368 flags.mask |= VLAN_FLAG_MVRP;
369 flags.flags &= ~VLAN_FLAG_MVRP;
370 if (param == PARM_on)
371 flags.flags |= VLAN_FLAG_MVRP;
372 } else { /*if (arg == ARG_loose_binding) */
373 flags.mask |= VLAN_FLAG_LOOSE_BINDING;
374 flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
375 if (param == PARM_on)
376 flags.flags |= VLAN_FLAG_LOOSE_BINDING;
377 }
378 }
379 argv++;
380 }
381
382 if (flags.mask)
383 addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
384}
385
280#ifndef NLMSG_TAIL 386#ifndef NLMSG_TAIL
281#define NLMSG_TAIL(nmsg) \ 387#define NLMSG_TAIL(nmsg) \
282 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 388 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
283#endif 389#endif
284/* Return value becomes exitcode. It's okay to not return at all */ 390/* Return value becomes exitcode. It's okay to not return at all */
285static int do_change(char **argv, const unsigned rtm) 391static int do_add_or_delete(char **argv, const unsigned rtm)
286{ 392{
287 static const char keywords[] ALIGN1 = 393 static const char keywords[] ALIGN1 =
288 "link\0""name\0""type\0""dev\0"; 394 "link\0""name\0""type\0""dev\0";
@@ -312,15 +418,17 @@ static int do_change(char **argv, const unsigned rtm)
312 418
313 while (*argv) { 419 while (*argv) {
314 arg = index_in_substrings(keywords, *argv); 420 arg = index_in_substrings(keywords, *argv);
421 if (arg == ARG_type) {
422 NEXT_ARG();
423 type_str = *argv++;
424 break;
425 }
315 if (arg == ARG_link) { 426 if (arg == ARG_link) {
316 NEXT_ARG(); 427 NEXT_ARG();
317 link_str = *argv; 428 link_str = *argv;
318 } else if (arg == ARG_name) { 429 } else if (arg == ARG_name) {
319 NEXT_ARG(); 430 NEXT_ARG();
320 name_str = *argv; 431 name_str = *argv;
321 } else if (arg == ARG_type) {
322 NEXT_ARG();
323 type_str = *argv;
324 } else { 432 } else {
325 if (arg == ARG_dev) { 433 if (arg == ARG_dev) {
326 if (dev_str) 434 if (dev_str)
@@ -339,6 +447,17 @@ static int do_change(char **argv, const unsigned rtm)
339 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); 447 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
340 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str, 448 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
341 strlen(type_str)); 449 strlen(type_str));
450
451 if (*argv) {
452 struct rtattr *data = NLMSG_TAIL(&req.n);
453 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
454
455 if (strcmp(type_str, "vlan") == 0)
456 vlan_parse_opt(argv, &req.n, sizeof(req));
457
458 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
459 }
460
342 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; 461 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
343 } 462 }
344 if (rtm != RTM_NEWLINK) { 463 if (rtm != RTM_NEWLINK) {
@@ -370,13 +489,13 @@ int FAST_FUNC do_iplink(char **argv)
370 static const char keywords[] ALIGN1 = 489 static const char keywords[] ALIGN1 =
371 "add\0""delete\0""set\0""show\0""lst\0""list\0"; 490 "add\0""delete\0""set\0""show\0""lst\0""list\0";
372 if (*argv) { 491 if (*argv) {
373 smalluint key = index_in_substrings(keywords, *argv); 492 int key = index_in_substrings(keywords, *argv);
374 if (key > 5) /* invalid argument */ 493 if (key < 0) /* invalid argument */
375 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 494 invarg(*argv, applet_name);
376 argv++; 495 argv++;
377 if (key <= 1) /* add/delete */ 496 if (key <= 1) /* add/delete */
378 return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK); 497 return do_add_or_delete(argv, key ? RTM_DELLINK : RTM_NEWLINK);
379 else if (key == 2) /* set */ 498 if (key == 2) /* set */
380 return do_set(argv); 499 return do_set(argv);
381 } 500 }
382 /* show, lst, list */ 501 /* show, lst, list */
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
index 241a6bf9d..8dbe6bd92 100644
--- a/networking/libiproute/iprule.c
+++ b/networking/libiproute/iprule.c
@@ -215,7 +215,7 @@ static int iprule_modify(int cmd, char **argv)
215 while (*argv) { 215 while (*argv) {
216 key = index_in_substrings(keywords, *argv) + 1; 216 key = index_in_substrings(keywords, *argv) + 1;
217 if (key == 0) /* no match found in keywords array, bail out. */ 217 if (key == 0) /* no match found in keywords array, bail out. */
218 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 218 invarg(*argv, applet_name);
219 if (key == ARG_from) { 219 if (key == ARG_from) {
220 inet_prefix dst; 220 inet_prefix dst;
221 NEXT_ARG(); 221 NEXT_ARG();
@@ -308,9 +308,9 @@ int FAST_FUNC do_iprule(char **argv)
308 static const char ip_rule_commands[] ALIGN1 = 308 static const char ip_rule_commands[] ALIGN1 =
309 "add\0""delete\0""list\0""show\0"; 309 "add\0""delete\0""list\0""show\0";
310 if (*argv) { 310 if (*argv) {
311 smalluint cmd = index_in_substrings(ip_rule_commands, *argv); 311 int cmd = index_in_substrings(ip_rule_commands, *argv);
312 if (cmd > 3) 312 if (cmd < 0)
313 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 313 invarg(*argv, applet_name);
314 argv++; 314 argv++;
315 if (cmd < 2) 315 if (cmd < 2)
316 return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv); 316 return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv);
diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c
index 2b651b926..b54c3c53f 100644
--- a/networking/libiproute/iptunnel.c
+++ b/networking/libiproute/iptunnel.c
@@ -561,9 +561,9 @@ int FAST_FUNC do_iptunnel(char **argv)
561 enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst }; 561 enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst };
562 562
563 if (*argv) { 563 if (*argv) {
564 smalluint key = index_in_substrings(keywords, *argv); 564 int key = index_in_substrings(keywords, *argv);
565 if (key > 5) 565 if (key < 0)
566 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 566 invarg(*argv, applet_name);
567 argv++; 567 argv++;
568 if (key == ARG_add) 568 if (key == ARG_add)
569 return do_add(SIOCADDTUNNEL, argv); 569 return do_add(SIOCADDTUNNEL, argv);
diff --git a/networking/nc.c b/networking/nc.c
index 126bec906..2f9e17466 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -261,7 +261,7 @@ int nc_main(int argc, char **argv)
261 if (nread < 1) { 261 if (nread < 1) {
262 /* Close outgoing half-connection so they get EOF, 262 /* Close outgoing half-connection so they get EOF,
263 * but leave incoming alone so we can see response */ 263 * but leave incoming alone so we can see response */
264 shutdown(cfd, 1); 264 shutdown(cfd, SHUT_WR);
265 FD_CLR(STDIN_FILENO, &readfds); 265 FD_CLR(STDIN_FILENO, &readfds);
266 } 266 }
267 ofd = cfd; 267 ofd = cfd;
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 00ba6f114..b9eff3da4 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -48,6 +48,12 @@
48 * - TCP connects from wrong ip/ports (if peer ip:port is specified 48 * - TCP connects from wrong ip/ports (if peer ip:port is specified
49 * on the command line, but accept() says that it came from different addr) 49 * on the command line, but accept() says that it came from different addr)
50 * are closed, but we don't exit - we continue to listen/accept. 50 * are closed, but we don't exit - we continue to listen/accept.
51 * Since bbox 1.22:
52 * - nc exits when _both_ stdin and network are closed.
53 * This makes these two commands:
54 * echo "Yes" | nc 127.0.0.1 1234
55 * echo "no" | nc -lp 1234
56 * exchange their data _and exit_ instead of being stuck.
51 */ 57 */
52 58
53/* done in nc.c: #include "libbb.h" */ 59/* done in nc.c: #include "libbb.h" */
@@ -134,8 +140,6 @@ struct globals {
134 140
135 jmp_buf jbuf; /* timer crud */ 141 jmp_buf jbuf; /* timer crud */
136 142
137 fd_set ding1; /* for select loop */
138 fd_set ding2;
139 char bigbuf_in[BIGSIZ]; /* data buffers */ 143 char bigbuf_in[BIGSIZ]; /* data buffers */
140 char bigbuf_net[BIGSIZ]; 144 char bigbuf_net[BIGSIZ];
141}; 145};
@@ -147,8 +151,6 @@ struct globals {
147#define themaddr (G.themaddr ) 151#define themaddr (G.themaddr )
148#define remend (G.remend ) 152#define remend (G.remend )
149#define jbuf (G.jbuf ) 153#define jbuf (G.jbuf )
150#define ding1 (G.ding1 )
151#define ding2 (G.ding2 )
152#define bigbuf_in (G.bigbuf_in ) 154#define bigbuf_in (G.bigbuf_in )
153#define bigbuf_net (G.bigbuf_net) 155#define bigbuf_net (G.bigbuf_net)
154#define o_verbose (G.o_verbose ) 156#define o_verbose (G.o_verbose )
@@ -590,26 +592,27 @@ static int readwrite(void)
590 unsigned rzleft; 592 unsigned rzleft;
591 unsigned rnleft; 593 unsigned rnleft;
592 unsigned netretry; /* net-read retry counter */ 594 unsigned netretry; /* net-read retry counter */
593 unsigned wretry; /* net-write sanity counter */ 595 unsigned fds_open;
594 unsigned wfirst; /* one-shot flag to skip first net read */
595 596
596 /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to 597 /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to
597 either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */ 598 either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */
598 FD_SET(netfd, &ding1); /* global: the net is open */ 599 fd_set ding1; /* for select loop */
600 fd_set ding2;
601 FD_ZERO(&ding1);
602 FD_SET(netfd, &ding1);
603 FD_SET(STDIN_FILENO, &ding1);
604 fds_open = 2;
605
599 netretry = 2; 606 netretry = 2;
600 wfirst = 0;
601 rzleft = rnleft = 0; 607 rzleft = rnleft = 0;
602 if (o_interval) 608 if (o_interval)
603 sleep(o_interval); /* pause *before* sending stuff, too */ 609 sleep(o_interval); /* pause *before* sending stuff, too */
604 610
605 errno = 0; /* clear from sleep, close, whatever */
606 /* and now the big ol' select shoveling loop ... */ 611 /* and now the big ol' select shoveling loop ... */
607 while (FD_ISSET(netfd, &ding1)) { /* i.e. till the *net* closes! */ 612 /* nc 1.10 has "while (FD_ISSET(netfd)" here */
608 wretry = 8200; /* more than we'll ever hafta write */ 613 while (fds_open) {
609 if (wfirst) { /* any saved stdin buffer? */ 614 unsigned wretry = 8200; /* net-write sanity counter */
610 wfirst = 0; /* clear flag for the duration */ 615
611 goto shovel; /* and go handle it first */
612 }
613 ding2 = ding1; /* FD_COPY ain't portable... */ 616 ding2 = ding1; /* FD_COPY ain't portable... */
614 /* some systems, notably linux, crap into their select timers on return, so 617 /* some systems, notably linux, crap into their select timers on return, so
615 we create a expendable copy and give *that* to select. */ 618 we create a expendable copy and give *that* to select. */
@@ -629,13 +632,14 @@ static int readwrite(void)
629 /* if we have a timeout AND stdin is closed AND we haven't heard anything 632 /* if we have a timeout AND stdin is closed AND we haven't heard anything
630 from the net during that time, assume it's dead and close it too. */ 633 from the net during that time, assume it's dead and close it too. */
631 if (rr == 0) { 634 if (rr == 0) {
632 if (!FD_ISSET(STDIN_FILENO, &ding1)) 635 if (!FD_ISSET(STDIN_FILENO, &ding1)) {
633 netretry--; /* we actually try a coupla times. */ 636 netretry--; /* we actually try a coupla times. */
634 if (!netretry) { 637 if (!netretry) {
635 if (o_verbose > 1) /* normally we don't care */ 638 if (o_verbose > 1) /* normally we don't care */
636 fprintf(stderr, "net timeout\n"); 639 fprintf(stderr, "net timeout\n");
637 close(netfd); 640 /*close(netfd); - redundant, exit will do it */
638 return 0; /* not an error! */ 641 return 0; /* not an error! */
642 }
639 } 643 }
640 } /* select timeout */ 644 } /* select timeout */
641 /* xxx: should we check the exception fds too? The read fds seem to give 645 /* xxx: should we check the exception fds too? The read fds seem to give
@@ -649,7 +653,8 @@ static int readwrite(void)
649 /* nc 1.10 doesn't do this */ 653 /* nc 1.10 doesn't do this */
650 bb_perror_msg("net read"); 654 bb_perror_msg("net read");
651 } 655 }
652 FD_CLR(netfd, &ding1); /* net closed, we'll finish up... */ 656 FD_CLR(netfd, &ding1); /* net closed */
657 fds_open--;
653 rzleft = 0; /* can't write anymore: broken pipe */ 658 rzleft = 0; /* can't write anymore: broken pipe */
654 } else { 659 } else {
655 rnleft = rr; 660 rnleft = rr;
@@ -669,11 +674,12 @@ Debug("got %d from the net, errno %d", rr, errno);
669 /* Considered making reads here smaller for UDP mode, but 8192-byte 674 /* Considered making reads here smaller for UDP mode, but 8192-byte
670 mobygrams are kinda fun and exercise the reassembler. */ 675 mobygrams are kinda fun and exercise the reassembler. */
671 if (rr <= 0) { /* at end, or fukt, or ... */ 676 if (rr <= 0) { /* at end, or fukt, or ... */
672 FD_CLR(STDIN_FILENO, &ding1); /* disable and close stdin */ 677 FD_CLR(STDIN_FILENO, &ding1); /* disable stdin */
673 close(STDIN_FILENO); 678 /*close(STDIN_FILENO); - not really necessary */
674// Does it make sense to shutdown(net_fd, SHUT_WR) 679 /* Let peer know we have no more data */
675// to let other side know that we won't write anything anymore? 680 /* nc 1.10 doesn't do this: */
676// (and what about keeping compat if we do that?) 681 shutdown(netfd, SHUT_WR);
682 fds_open--;
677 } else { 683 } else {
678 rzleft = rr; 684 rzleft = rr;
679 zp = bigbuf_in; 685 zp = bigbuf_in;
@@ -684,24 +690,14 @@ Debug("got %d from the net, errno %d", rr, errno);
684 Geez, why does this look an awful lot like the big loop in "rsh"? ... 690 Geez, why does this look an awful lot like the big loop in "rsh"? ...
685 not sure if the order of this matters, but write net -> stdout first. */ 691 not sure if the order of this matters, but write net -> stdout first. */
686 692
687 /* sanity check. Works because they're both unsigned... */
688 if ((rzleft > 8200) || (rnleft > 8200)) {
689 holler_error("bogus buffers: %u, %u", rzleft, rnleft);
690 rzleft = rnleft = 0;
691 }
692 /* net write retries sometimes happen on UDP connections */
693 if (!wretry) { /* is something hung? */
694 holler_error("too many output retries");
695 return 1;
696 }
697 if (rnleft) { 693 if (rnleft) {
698 rr = write(STDOUT_FILENO, np, rnleft); 694 rr = write(STDOUT_FILENO, np, rnleft);
699 if (rr > 0) { 695 if (rr > 0) {
700 if (o_ofile) /* log the stdout */ 696 if (o_ofile) /* log the stdout */
701 oprint('<', (unsigned char *)np, rr); 697 oprint('<', (unsigned char *)np, rr);
702 np += rr; /* fix up ptrs and whatnot */ 698 np += rr;
703 rnleft -= rr; /* will get sanity-checked above */ 699 rnleft -= rr;
704 wrote_out += rr; /* global count */ 700 wrote_out += rr; /* global count */
705 } 701 }
706Debug("wrote %d to stdout, errno %d", rr, errno); 702Debug("wrote %d to stdout, errno %d", rr, errno);
707 } /* rnleft */ 703 } /* rnleft */
@@ -716,20 +712,24 @@ Debug("wrote %d to stdout, errno %d", rr, errno);
716 oprint('>', (unsigned char *)zp, rr); 712 oprint('>', (unsigned char *)zp, rr);
717 zp += rr; 713 zp += rr;
718 rzleft -= rr; 714 rzleft -= rr;
719 wrote_net += rr; /* global count */ 715 wrote_net += rr; /* global count */
720 } 716 }
721Debug("wrote %d to net, errno %d", rr, errno); 717Debug("wrote %d to net, errno %d", rr, errno);
722 } /* rzleft */ 718 } /* rzleft */
723 if (o_interval) { /* cycle between slow lines, or ... */ 719 if (o_interval) { /* cycle between slow lines, or ... */
724 sleep(o_interval); 720 sleep(o_interval);
725 errno = 0; /* clear from sleep */
726 continue; /* ...with hairy select loop... */ 721 continue; /* ...with hairy select loop... */
727 } 722 }
728 if ((rzleft) || (rnleft)) { /* shovel that shit till they ain't */ 723 if (rzleft || rnleft) { /* shovel that shit till they ain't */
729 wretry--; /* none left, and get another load */ 724 wretry--; /* none left, and get another load */
725 /* net write retries sometimes happen on UDP connections */
726 if (!wretry) { /* is something hung? */
727 holler_error("too many output retries");
728 return 1;
729 }
730 goto shovel; 730 goto shovel;
731 } 731 }
732 } /* while ding1:netfd is open */ 732 } /* while (fds_open) */
733 733
734 /* XXX: maybe want a more graceful shutdown() here, or screw around with 734 /* XXX: maybe want a more graceful shutdown() here, or screw around with
735 linger times?? I suspect that I don't need to since I'm always doing 735 linger times?? I suspect that I don't need to since I'm always doing
@@ -876,9 +876,8 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
876 } 876 }
877#endif 877#endif
878 878
879 FD_SET(STDIN_FILENO, &ding1); /* stdin *is* initially open */
880 if (proggie) { 879 if (proggie) {
881 close(0); /* won't need stdin */ 880 close(STDIN_FILENO); /* won't need stdin */
882 option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */ 881 option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */
883 } 882 }
884#if ENABLE_NC_EXTRA 883#if ENABLE_NC_EXTRA
diff --git a/networking/nslookup.c b/networking/nslookup.c
index f4fd407dd..dd4b1ffed 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -138,6 +138,9 @@ static void set_default_dns(const char *server)
138{ 138{
139 len_and_sockaddr *lsa; 139 len_and_sockaddr *lsa;
140 140
141 if (!server)
142 return;
143
141 /* NB: this works even with, say, "[::1]:5353"! :) */ 144 /* NB: this works even with, say, "[::1]:5353"! :) */
142 lsa = xhost2sockaddr(server, 53); 145 lsa = xhost2sockaddr(server, 53);
143 146
@@ -181,9 +184,17 @@ int nslookup_main(int argc, char **argv)
181 /* (but it also says "may be enabled in /etc/resolv.conf") */ 184 /* (but it also says "may be enabled in /etc/resolv.conf") */
182 /*_res.options |= RES_USE_INET6;*/ 185 /*_res.options |= RES_USE_INET6;*/
183 186
184 if (argv[2]) 187 set_default_dns(argv[2]);
185 set_default_dns(argv[2]);
186 188
187 server_print(); 189 server_print();
190
191 /* getaddrinfo and friends are free to request a resolver
192 * reinitialization. Just in case, set_default_dns() again
193 * after getaddrinfo (in server_print). This reportedly helps
194 * with bug 675 "nslookup does not properly use second argument"
195 * at least on Debian Wheezy and Openwrt AA (eglibc based).
196 */
197 set_default_dns(argv[2]);
198
188 return print_host(argv[1], "Name:"); 199 return print_host(argv[1], "Name:");
189} 200}
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 0f4319ef2..99817e83b 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -95,6 +95,7 @@
95#define RETRY_INTERVAL 5 /* on error, retry in N secs */ 95#define RETRY_INTERVAL 5 /* on error, retry in N secs */
96#define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */ 96#define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */
97#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ 97#define INITIAL_SAMPLES 4 /* how many samples do we want for init */
98#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */
98 99
99/* Clock discipline parameters and constants */ 100/* Clock discipline parameters and constants */
100 101
@@ -227,8 +228,8 @@ typedef struct {
227 uint8_t lastpkt_status; 228 uint8_t lastpkt_status;
228 uint8_t lastpkt_stratum; 229 uint8_t lastpkt_stratum;
229 uint8_t reachable_bits; 230 uint8_t reachable_bits;
230 /* when to send new query (if p_fd == -1) 231 /* when to send new query (if p_fd == -1)
231 * or when receive times out (if p_fd >= 0): */ 232 * or when receive times out (if p_fd >= 0): */
232 double next_action_time; 233 double next_action_time;
233 double p_xmttime; 234 double p_xmttime;
234 double lastpkt_recv_time; 235 double lastpkt_recv_time;
@@ -804,22 +805,34 @@ send_query_to_peer(peer_t *p)
804 p->p_xmt_msg.m_xmttime.fractionl = random(); 805 p->p_xmt_msg.m_xmttime.fractionl = random();
805 p->p_xmttime = gettime1900d(); 806 p->p_xmttime = gettime1900d();
806 807
808 /* Were doing it only if sendto worked, but
809 * loss of sync detection needs reachable_bits updated
810 * even if sending fails *locally*:
811 * "network is unreachable" because cable was pulled?
812 * We still need to declare "unsync" if this condition persists.
813 */
814 p->reachable_bits <<= 1;
815
807 if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len, 816 if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len,
808 &p->p_xmt_msg, NTP_MSGSIZE_NOAUTH) == -1 817 &p->p_xmt_msg, NTP_MSGSIZE_NOAUTH) == -1
809 ) { 818 ) {
810 close(p->p_fd); 819 close(p->p_fd);
811 p->p_fd = -1; 820 p->p_fd = -1;
821 /*
822 * We know that we sent nothing.
823 * We can retry *soon* without fearing
824 * that we are flooding the peer.
825 */
812 set_next(p, RETRY_INTERVAL); 826 set_next(p, RETRY_INTERVAL);
813 return; 827 return;
814 } 828 }
815 829
816 p->reachable_bits <<= 1;
817 set_next(p, RESPONSE_INTERVAL); 830 set_next(p, RESPONSE_INTERVAL);
818} 831}
819 832
820 833
821/* Note that there is no provision to prevent several run_scripts 834/* Note that there is no provision to prevent several run_scripts
822 * to be done in quick succession. In fact, it happens rather often 835 * to be started in quick succession. In fact, it happens rather often
823 * if initial syncronization results in a step. 836 * if initial syncronization results in a step.
824 * You will see "step" and then "stratum" script runs, sometimes 837 * You will see "step" and then "stratum" script runs, sometimes
825 * as close as only 0.002 seconds apart. 838 * as close as only 0.002 seconds apart.
@@ -830,6 +843,8 @@ static void run_script(const char *action, double offset)
830 char *argv[3]; 843 char *argv[3];
831 char *env1, *env2, *env3, *env4; 844 char *env1, *env2, *env3, *env4;
832 845
846 G.last_script_run = G.cur_time;
847
833 if (!G.script_name) 848 if (!G.script_name)
834 return; 849 return;
835 850
@@ -866,8 +881,6 @@ static void run_script(const char *action, double offset)
866 free(env2); 881 free(env2);
867 free(env3); 882 free(env3);
868 free(env4); 883 free(env4);
869
870 G.last_script_run = G.cur_time;
871} 884}
872 885
873static NOINLINE void 886static NOINLINE void
@@ -1616,6 +1629,7 @@ recv_and_process_peer_pkt(peer_t *p)
1616 ssize_t size; 1629 ssize_t size;
1617 msg_t msg; 1630 msg_t msg;
1618 double T1, T2, T3, T4; 1631 double T1, T2, T3, T4;
1632 double dv;
1619 unsigned interval; 1633 unsigned interval;
1620 datapoint_t *datapoint; 1634 datapoint_t *datapoint;
1621 peer_t *q; 1635 peer_t *q;
@@ -1665,9 +1679,8 @@ recv_and_process_peer_pkt(peer_t *p)
1665// TODO: stratum 0 responses may have commands in 32-bit m_refid field: 1679// TODO: stratum 0 responses may have commands in 32-bit m_refid field:
1666// "DENY", "RSTR" - peer does not like us at all 1680// "DENY", "RSTR" - peer does not like us at all
1667// "RATE" - peer is overloaded, reduce polling freq 1681// "RATE" - peer is overloaded, reduce polling freq
1668 interval = poll_interval(0); 1682 bb_error_msg("reply from %s: peer is unsynced", p->p_dotted);
1669 bb_error_msg("reply from %s: peer is unsynced, next query in %us", p->p_dotted, interval); 1683 goto pick_normal_interval;
1670 goto set_next_and_ret;
1671 } 1684 }
1672 1685
1673// /* Verify valid root distance */ 1686// /* Verify valid root distance */
@@ -1700,21 +1713,31 @@ recv_and_process_peer_pkt(peer_t *p)
1700 T4 = G.cur_time; 1713 T4 = G.cur_time;
1701 1714
1702 p->lastpkt_recv_time = T4; 1715 p->lastpkt_recv_time = T4;
1703
1704 VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); 1716 VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
1705 p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0; 1717
1706 datapoint = &p->filter_datapoint[p->datapoint_idx];
1707 datapoint->d_recv_time = T4;
1708 datapoint->d_offset = ((T2 - T1) + (T3 - T4)) / 2;
1709 /* The delay calculation is a special case. In cases where the 1718 /* The delay calculation is a special case. In cases where the
1710 * server and client clocks are running at different rates and 1719 * server and client clocks are running at different rates and
1711 * with very fast networks, the delay can appear negative. In 1720 * with very fast networks, the delay can appear negative. In
1712 * order to avoid violating the Principle of Least Astonishment, 1721 * order to avoid violating the Principle of Least Astonishment,
1713 * the delay is clamped not less than the system precision. 1722 * the delay is clamped not less than the system precision.
1714 */ 1723 */
1724 dv = p->lastpkt_delay;
1715 p->lastpkt_delay = (T4 - T1) - (T3 - T2); 1725 p->lastpkt_delay = (T4 - T1) - (T3 - T2);
1716 if (p->lastpkt_delay < G_precision_sec) 1726 if (p->lastpkt_delay < G_precision_sec)
1717 p->lastpkt_delay = G_precision_sec; 1727 p->lastpkt_delay = G_precision_sec;
1728 /*
1729 * If this packet's delay is much bigger than the last one,
1730 * it's better to just ignore it than use its much less precise value.
1731 */
1732 if (p->reachable_bits && p->lastpkt_delay > dv * BAD_DELAY_GROWTH) {
1733 bb_error_msg("reply from %s: delay %f is too high, ignoring", p->p_dotted, p->lastpkt_delay);
1734 goto pick_normal_interval;
1735 }
1736
1737 p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0;
1738 datapoint = &p->filter_datapoint[p->datapoint_idx];
1739 datapoint->d_recv_time = T4;
1740 datapoint->d_offset = ((T2 - T1) + (T3 - T4)) / 2;
1718 datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec; 1741 datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec;
1719 if (!p->reachable_bits) { 1742 if (!p->reachable_bits) {
1720 /* 1st datapoint ever - replicate offset in every element */ 1743 /* 1st datapoint ever - replicate offset in every element */
@@ -1811,6 +1834,7 @@ recv_and_process_peer_pkt(peer_t *p)
1811 } 1834 }
1812 1835
1813 /* Decide when to send new query for this peer */ 1836 /* Decide when to send new query for this peer */
1837 pick_normal_interval:
1814 interval = poll_interval(0); 1838 interval = poll_interval(0);
1815 1839
1816 set_next_and_ret: 1840 set_next_and_ret:
@@ -2159,12 +2183,14 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2159 did_poll: 2183 did_poll:
2160 gettime1900d(); /* sets G.cur_time */ 2184 gettime1900d(); /* sets G.cur_time */
2161 if (nfds <= 0) { 2185 if (nfds <= 0) {
2162 if (G.script_name && G.cur_time - G.last_script_run > 11*60) { 2186 if (!bb_got_signal /* poll wasn't interrupted by a signal */
2187 && G.cur_time - G.last_script_run > 11*60
2188 ) {
2163 /* Useful for updating battery-backed RTC and such */ 2189 /* Useful for updating battery-backed RTC and such */
2164 run_script("periodic", G.last_update_offset); 2190 run_script("periodic", G.last_update_offset);
2165 gettime1900d(); /* sets G.cur_time */ 2191 gettime1900d(); /* sets G.cur_time */
2166 } 2192 }
2167 continue; 2193 goto check_unsync;
2168 } 2194 }
2169 2195
2170 /* Process any received packets */ 2196 /* Process any received packets */
@@ -2195,6 +2221,21 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2195 gettime1900d(); /* sets G.cur_time */ 2221 gettime1900d(); /* sets G.cur_time */
2196 } 2222 }
2197 } 2223 }
2224
2225 check_unsync:
2226 if (G.ntp_peers && G.stratum != MAXSTRAT) {
2227 for (item = G.ntp_peers; item != NULL; item = item->link) {
2228 peer_t *p = (peer_t *) item->data;
2229 if (p->reachable_bits)
2230 goto have_reachable_peer;
2231 }
2232 /* No peer responded for last 8 packets, panic */
2233 G.polladj_count = 0;
2234 G.poll_exp = MINPOLL;
2235 G.stratum = MAXSTRAT;
2236 run_script("unsync", 0.0);
2237 have_reachable_peer: ;
2238 }
2198 } /* while (!bb_got_signal) */ 2239 } /* while (!bb_got_signal) */
2199 2240
2200 remove_pidfile(CONFIG_PID_FILE_PATH "/ntpd.pid"); 2241 remove_pidfile(CONFIG_PID_FILE_PATH "/ntpd.pid");
diff --git a/networking/ping.c b/networking/ping.c
index e919b3a09..f27e2143d 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -149,8 +149,33 @@ enum {
149 MAX_DUP_CHK = (8 * 128), 149 MAX_DUP_CHK = (8 * 128),
150 MAXWAIT = 10, 150 MAXWAIT = 10,
151 PINGINTERVAL = 1, /* 1 second */ 151 PINGINTERVAL = 1, /* 1 second */
152 pingsock = 0,
152}; 153};
153 154
155static void
156#if ENABLE_PING6
157create_icmp_socket(len_and_sockaddr *lsa)
158#else
159create_icmp_socket(void)
160#define create_icmp_socket(lsa) create_icmp_socket()
161#endif
162{
163 int sock;
164#if ENABLE_PING6
165 if (lsa->u.sa.sa_family == AF_INET6)
166 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
167 else
168#endif
169 sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
170 if (sock < 0) {
171 if (errno == EPERM)
172 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
173 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
174 }
175
176 xmove_fd(sock, pingsock);
177}
178
154#if !ENABLE_FEATURE_FANCY_PING 179#if !ENABLE_FEATURE_FANCY_PING
155 180
156/* Simple version */ 181/* Simple version */
@@ -171,12 +196,10 @@ static void noresp(int ign UNUSED_PARAM)
171static void ping4(len_and_sockaddr *lsa) 196static void ping4(len_and_sockaddr *lsa)
172{ 197{
173 struct icmp *pkt; 198 struct icmp *pkt;
174 int pingsock, c; 199 int c;
175
176 pingsock = create_icmp_socket();
177 200
178 pkt = (struct icmp *) G.packet; 201 pkt = (struct icmp *) G.packet;
179 memset(pkt, 0, sizeof(G.packet)); 202 /*memset(pkt, 0, sizeof(G.packet)); already is */
180 pkt->icmp_type = ICMP_ECHO; 203 pkt->icmp_type = ICMP_ECHO;
181 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); 204 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet));
182 205
@@ -184,11 +207,15 @@ static void ping4(len_and_sockaddr *lsa)
184 207
185 /* listen for replies */ 208 /* listen for replies */
186 while (1) { 209 while (1) {
210#if 0
187 struct sockaddr_in from; 211 struct sockaddr_in from;
188 socklen_t fromlen = sizeof(from); 212 socklen_t fromlen = sizeof(from);
189 213
190 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0, 214 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
191 (struct sockaddr *) &from, &fromlen); 215 (struct sockaddr *) &from, &fromlen);
216#else
217 c = recv(pingsock, G.packet, sizeof(G.packet), 0);
218#endif
192 if (c < 0) { 219 if (c < 0) {
193 if (errno != EINTR) 220 if (errno != EINTR)
194 bb_perror_msg("recvfrom"); 221 bb_perror_msg("recvfrom");
@@ -210,13 +237,11 @@ static void ping4(len_and_sockaddr *lsa)
210static void ping6(len_and_sockaddr *lsa) 237static void ping6(len_and_sockaddr *lsa)
211{ 238{
212 struct icmp6_hdr *pkt; 239 struct icmp6_hdr *pkt;
213 int pingsock, c; 240 int c;
214 int sockopt; 241 int sockopt;
215 242
216 pingsock = create_icmp6_socket();
217
218 pkt = (struct icmp6_hdr *) G.packet; 243 pkt = (struct icmp6_hdr *) G.packet;
219 memset(pkt, 0, sizeof(G.packet)); 244 /*memset(pkt, 0, sizeof(G.packet)); already is */
220 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 245 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
221 246
222 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 247 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
@@ -226,18 +251,21 @@ static void ping6(len_and_sockaddr *lsa)
226 251
227 /* listen for replies */ 252 /* listen for replies */
228 while (1) { 253 while (1) {
254#if 0
229 struct sockaddr_in6 from; 255 struct sockaddr_in6 from;
230 socklen_t fromlen = sizeof(from); 256 socklen_t fromlen = sizeof(from);
231 257
232 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0, 258 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
233 (struct sockaddr *) &from, &fromlen); 259 (struct sockaddr *) &from, &fromlen);
260#else
261 c = recv(pingsock, G.packet, sizeof(G.packet), 0);
262#endif
234 if (c < 0) { 263 if (c < 0) {
235 if (errno != EINTR) 264 if (errno != EINTR)
236 bb_perror_msg("recvfrom"); 265 bb_perror_msg("recvfrom");
237 continue; 266 continue;
238 } 267 }
239 if (c >= ICMP_MINLEN) { /* icmp6_hdr */ 268 if (c >= ICMP_MINLEN) { /* icmp6_hdr */
240 pkt = (struct icmp6_hdr *) G.packet;
241 if (pkt->icmp6_type == ICMP6_ECHO_REPLY) 269 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
242 break; 270 break;
243 } 271 }
@@ -285,6 +313,7 @@ static int common_ping_main(sa_family_t af, char **argv)
285 signal(SIGALRM, noresp); 313 signal(SIGALRM, noresp);
286 alarm(5); /* give the host 5000ms to respond */ 314 alarm(5); /* give the host 5000ms to respond */
287 315
316 create_icmp_socket(lsa);
288#if ENABLE_PING6 317#if ENABLE_PING6
289 if (lsa->u.sa.sa_family == AF_INET6) 318 if (lsa->u.sa.sa_family == AF_INET6)
290 ping6(lsa); 319 ping6(lsa);
@@ -318,7 +347,6 @@ enum {
318 347
319 348
320struct globals { 349struct globals {
321 int pingsock;
322 int if_index; 350 int if_index;
323 char *str_I; 351 char *str_I;
324 len_and_sockaddr *source_lsa; 352 len_and_sockaddr *source_lsa;
@@ -344,10 +372,9 @@ struct globals {
344 struct sockaddr_in6 sin6; 372 struct sockaddr_in6 sin6;
345#endif 373#endif
346 } pingaddr; 374 } pingaddr;
347 char rcvd_tbl[MAX_DUP_CHK / 8]; 375 unsigned char rcvd_tbl[MAX_DUP_CHK / 8];
348} FIX_ALIASING; 376} FIX_ALIASING;
349#define G (*(struct globals*)&bb_common_bufsiz1) 377#define G (*(struct globals*)&bb_common_bufsiz1)
350#define pingsock (G.pingsock )
351#define if_index (G.if_index ) 378#define if_index (G.if_index )
352#define source_lsa (G.source_lsa ) 379#define source_lsa (G.source_lsa )
353#define str_I (G.str_I ) 380#define str_I (G.str_I )
@@ -369,20 +396,17 @@ void BUG_ping_globals_too_big(void);
369#define INIT_G() do { \ 396#define INIT_G() do { \
370 if (sizeof(G) > COMMON_BUFSIZE) \ 397 if (sizeof(G) > COMMON_BUFSIZE) \
371 BUG_ping_globals_too_big(); \ 398 BUG_ping_globals_too_big(); \
372 pingsock = -1; \
373 datalen = DEFDATALEN; \ 399 datalen = DEFDATALEN; \
374 timeout = MAXWAIT; \ 400 timeout = MAXWAIT; \
375 tmin = UINT_MAX; \ 401 tmin = UINT_MAX; \
376} while (0) 402} while (0)
377 403
378 404
379#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 405#define BYTE(bit) rcvd_tbl[(bit)>>3]
380#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 406#define MASK(bit) (1 << ((bit) & 7))
381#define SET(bit) (A(bit) |= B(bit)) 407#define SET(bit) (BYTE(bit) |= MASK(bit))
382#define CLR(bit) (A(bit) &= (~B(bit))) 408#define CLR(bit) (BYTE(bit) &= (~MASK(bit)))
383#define TST(bit) (A(bit) & B(bit)) 409#define TST(bit) (BYTE(bit) & MASK(bit))
384
385/**************************************************************************/
386 410
387static void print_stats_and_exit(int junk) NORETURN; 411static void print_stats_and_exit(int junk) NORETURN;
388static void print_stats_and_exit(int junk UNUSED_PARAM) 412static void print_stats_and_exit(int junk UNUSED_PARAM)
@@ -552,11 +576,10 @@ static void unpack_tail(int sz, uint32_t *tp,
552 const char *from_str, 576 const char *from_str,
553 uint16_t recv_seq, int ttl) 577 uint16_t recv_seq, int ttl)
554{ 578{
579 unsigned char *b, m;
555 const char *dupmsg = " (DUP!)"; 580 const char *dupmsg = " (DUP!)";
556 unsigned triptime = triptime; /* for gcc */ 581 unsigned triptime = triptime; /* for gcc */
557 582
558 ++G.nreceived;
559
560 if (tp) { 583 if (tp) {
561 /* (int32_t) cast is for hypothetical 64-bit unsigned */ 584 /* (int32_t) cast is for hypothetical 64-bit unsigned */
562 /* (doesn't hurt 32-bit real-world anyway) */ 585 /* (doesn't hurt 32-bit real-world anyway) */
@@ -568,11 +591,15 @@ static void unpack_tail(int sz, uint32_t *tp,
568 tmax = triptime; 591 tmax = triptime;
569 } 592 }
570 593
571 if (TST(recv_seq % MAX_DUP_CHK)) { 594 b = &BYTE(recv_seq % MAX_DUP_CHK);
595 m = MASK(recv_seq % MAX_DUP_CHK);
596 /*if TST(recv_seq % MAX_DUP_CHK):*/
597 if (*b & m) {
572 ++G.nrepeats; 598 ++G.nrepeats;
573 --G.nreceived;
574 } else { 599 } else {
575 SET(recv_seq % MAX_DUP_CHK); 600 /*SET(recv_seq % MAX_DUP_CHK):*/
601 *b |= m;
602 ++G.nreceived;
576 dupmsg += 7; 603 dupmsg += 7;
577 } 604 }
578 605
@@ -655,7 +682,6 @@ static void ping4(len_and_sockaddr *lsa)
655{ 682{
656 int sockopt; 683 int sockopt;
657 684
658 pingsock = create_icmp_socket();
659 pingaddr.sin = lsa->u.sin; 685 pingaddr.sin = lsa->u.sin;
660 if (source_lsa) { 686 if (source_lsa) {
661 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF, 687 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF,
@@ -663,8 +689,6 @@ static void ping4(len_and_sockaddr *lsa)
663 bb_error_msg_and_die("can't set multicast source interface"); 689 bb_error_msg_and_die("can't set multicast source interface");
664 xbind(pingsock, &source_lsa->u.sa, source_lsa->len); 690 xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
665 } 691 }
666 if (str_I)
667 setsockopt_bindtodevice(pingsock, str_I);
668 692
669 /* enable broadcast pings */ 693 /* enable broadcast pings */
670 setsockopt_broadcast(pingsock); 694 setsockopt_broadcast(pingsock);
@@ -713,13 +737,9 @@ static void ping6(len_and_sockaddr *lsa)
713 struct iovec iov; 737 struct iovec iov;
714 char control_buf[CMSG_SPACE(36)]; 738 char control_buf[CMSG_SPACE(36)];
715 739
716 pingsock = create_icmp6_socket();
717 pingaddr.sin6 = lsa->u.sin6; 740 pingaddr.sin6 = lsa->u.sin6;
718 /* untested whether "-I addr" really works for IPv6: */
719 if (source_lsa) 741 if (source_lsa)
720 xbind(pingsock, &source_lsa->u.sa, source_lsa->len); 742 xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
721 if (str_I)
722 setsockopt_bindtodevice(pingsock, str_I);
723 743
724#ifdef ICMP6_FILTER 744#ifdef ICMP6_FILTER
725 { 745 {
@@ -806,6 +826,11 @@ static void ping(len_and_sockaddr *lsa)
806 } 826 }
807 printf(": %d data bytes\n", datalen); 827 printf(": %d data bytes\n", datalen);
808 828
829 create_icmp_socket(lsa);
830 /* untested whether "-I addr" really works for IPv6: */
831 if (str_I)
832 setsockopt_bindtodevice(pingsock, str_I);
833
809 G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN; 834 G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN;
810 G.rcv_packet = xzalloc(G.sizeof_rcv_packet); 835 G.rcv_packet = xzalloc(G.sizeof_rcv_packet);
811#if ENABLE_PING6 836#if ENABLE_PING6
diff --git a/networking/tc.c b/networking/tc.c
index f968707a9..b9a4d16cc 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -65,7 +65,7 @@ struct globals {
65} FIX_ALIASING; 65} FIX_ALIASING;
66#define G (*(struct globals*)&bb_common_bufsiz1) 66#define G (*(struct globals*)&bb_common_bufsiz1)
67struct BUG_G_too_big { 67struct BUG_G_too_big {
68 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 68 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
69}; 69};
70#define filter_ifindex (G.filter_ifindex) 70#define filter_ifindex (G.filter_ifindex)
71#define filter_qdisc (G.filter_qdisc) 71#define filter_qdisc (G.filter_qdisc)
diff --git a/networking/telnet.c b/networking/telnet.c
index 58a691916..a25579773 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -125,12 +125,10 @@ static void subneg(byte c);
125 125
126static void iac_flush(void) 126static void iac_flush(void)
127{ 127{
128 write(netfd, G.iacbuf, G.iaclen); 128 full_write(netfd, G.iacbuf, G.iaclen);
129 G.iaclen = 0; 129 G.iaclen = 0;
130} 130}
131 131
132#define write_str(fd, str) write(fd, str, sizeof(str) - 1)
133
134static void doexit(int ev) NORETURN; 132static void doexit(int ev) NORETURN;
135static void doexit(int ev) 133static void doexit(int ev)
136{ 134{
@@ -145,7 +143,7 @@ static void con_escape(void)
145 if (bb_got_signal) /* came from line mode... go raw */ 143 if (bb_got_signal) /* came from line mode... go raw */
146 rawmode(); 144 rawmode();
147 145
148 write_str(1, "\r\nConsole escape. Commands are:\r\n\n" 146 full_write1_str("\r\nConsole escape. Commands are:\r\n\n"
149 " l go to line mode\r\n" 147 " l go to line mode\r\n"
150 " c go to character mode\r\n" 148 " c go to character mode\r\n"
151 " z suspend telnet\r\n" 149 " z suspend telnet\r\n"
@@ -176,7 +174,7 @@ static void con_escape(void)
176 doexit(EXIT_SUCCESS); 174 doexit(EXIT_SUCCESS);
177 } 175 }
178 176
179 write_str(1, "continuing...\r\n"); 177 full_write1_str("continuing...\r\n");
180 178
181 if (bb_got_signal) 179 if (bb_got_signal)
182 cookmode(); 180 cookmode();
@@ -383,10 +381,11 @@ static void put_iac_naws(byte c, int x, int y)
383 put_iac(SB); 381 put_iac(SB);
384 put_iac(c); 382 put_iac(c);
385 383
386 put_iac((x >> 8) & 0xff); 384 /* "... & 0xff" implicitly done below */
387 put_iac(x & 0xff); 385 put_iac(x >> 8);
388 put_iac((y >> 8) & 0xff); 386 put_iac(x);
389 put_iac(y & 0xff); 387 put_iac(y >> 8);
388 put_iac(y);
390 389
391 put_iac(IAC); 390 put_iac(IAC);
392 put_iac(SE); 391 put_iac(SE);
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index ae0e0d306..11b7b1f06 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -371,20 +371,23 @@ static NOINLINE void attach_option(
371 char *buffer, 371 char *buffer,
372 int length) 372 int length)
373{ 373{
374 struct option_set *existing, *new, **curr; 374 struct option_set *existing;
375 char *allocated = NULL; 375 char *allocated;
376 376
377 existing = udhcp_find_option(*opt_list, optflag->code); 377 allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
378 if (!existing) {
379 log2("Attaching option %02x to list", optflag->code);
380 allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
381#if ENABLE_FEATURE_UDHCP_RFC3397 378#if ENABLE_FEATURE_UDHCP_RFC3397
382 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { 379 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
383 /* reuse buffer and length for RFC1035-formatted string */ 380 /* reuse buffer and length for RFC1035-formatted string */
384 allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); 381 allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length);
385 } 382 }
386#endif 383#endif
384
385 existing = udhcp_find_option(*opt_list, optflag->code);
386 if (!existing) {
387 struct option_set *new, **curr;
388
387 /* make a new option */ 389 /* make a new option */
390 log2("Attaching option %02x to list", optflag->code);
388 new = xmalloc(sizeof(*new)); 391 new = xmalloc(sizeof(*new));
389 new->data = xmalloc(length + OPT_DATA); 392 new->data = xmalloc(length + OPT_DATA);
390 new->data[OPT_CODE] = optflag->code; 393 new->data[OPT_CODE] = optflag->code;
@@ -405,14 +408,7 @@ static NOINLINE void attach_option(
405 408
406 /* add it to an existing option */ 409 /* add it to an existing option */
407 log2("Attaching option %02x to existing member of list", optflag->code); 410 log2("Attaching option %02x to existing member of list", optflag->code);
408 allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
409 old_len = existing->data[OPT_LEN]; 411 old_len = existing->data[OPT_LEN];
410#if ENABLE_FEATURE_UDHCP_RFC3397
411 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
412 /* reuse buffer and length for RFC1035-formatted string */
413 allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length);
414 }
415#endif
416 if (old_len + length < 255) { 412 if (old_len + length < 255) {
417 /* actually 255 is ok too, but adding a space can overlow it */ 413 /* actually 255 is ok too, but adding a space can overlow it */
418 414
@@ -424,7 +420,7 @@ static NOINLINE void attach_option(
424 existing->data[OPT_DATA + old_len] = ' '; 420 existing->data[OPT_DATA + old_len] = ' ';
425 old_len++; 421 old_len++;
426 } 422 }
427 memcpy(existing->data + OPT_DATA + old_len, buffer, length); 423 memcpy(existing->data + OPT_DATA + old_len, (allocated ? allocated : buffer), length);
428 existing->data[OPT_LEN] = old_len + length; 424 existing->data[OPT_LEN] = old_len + length;
429 } /* else, ignore the data, we could put this in a second option in the future */ 425 } /* else, ignore the data, we could put this in a second option in the future */
430 } /* else, ignore the new data */ 426 } /* else, ignore the new data */
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 086228871..53d8a5e08 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1135,34 +1135,35 @@ static void client_background(void)
1135//usage:# define IF_UDHCP_VERBOSE(...) 1135//usage:# define IF_UDHCP_VERBOSE(...)
1136//usage:#endif 1136//usage:#endif
1137//usage:#define udhcpc_trivial_usage 1137//usage:#define udhcpc_trivial_usage
1138//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" 1138//usage: "[-fbq"IF_UDHCP_VERBOSE("v")IF_FEATURE_UDHCPC_ARPING("a")"RB] [-t N] [-T SEC] [-A SEC/-n]\n"
1139//usage: " [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 1139//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n"
1140//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..."
1140//usage:#define udhcpc_full_usage "\n" 1141//usage:#define udhcpc_full_usage "\n"
1141//usage: IF_LONG_OPTS( 1142//usage: IF_LONG_OPTS(
1142//usage: "\n -i,--interface IFACE Interface to use (default eth0)" 1143//usage: "\n -i,--interface IFACE Interface to use (default eth0)"
1143//usage: "\n -p,--pidfile FILE Create pidfile" 1144//usage: IF_FEATURE_UDHCP_PORT(
1145//usage: "\n -P,--client-port PORT Use PORT (default 68)"
1146//usage: )
1144//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 1147//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1148//usage: "\n -p,--pidfile FILE Create pidfile"
1145//usage: "\n -B,--broadcast Request broadcast replies" 1149//usage: "\n -B,--broadcast Request broadcast replies"
1146//usage: "\n -t,--retries N Send up to N discover packets" 1150//usage: "\n -t,--retries N Send up to N discover packets (default 3)"
1147//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" 1151//usage: "\n -T,--timeout SEC Pause between packets (default 3)"
1148//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" 1152//usage: "\n -A,--tryagain SEC Wait if lease is not obtained (default 20)"
1153//usage: "\n -n,--now Exit if lease is not obtained"
1154//usage: "\n -q,--quit Exit after obtaining lease"
1155//usage: "\n -R,--release Release IP on exit"
1149//usage: "\n -f,--foreground Run in foreground" 1156//usage: "\n -f,--foreground Run in foreground"
1150//usage: USE_FOR_MMU( 1157//usage: USE_FOR_MMU(
1151//usage: "\n -b,--background Background if lease is not obtained" 1158//usage: "\n -b,--background Background if lease is not obtained"
1152//usage: ) 1159//usage: )
1153//usage: "\n -n,--now Exit if lease is not obtained"
1154//usage: "\n -q,--quit Exit after obtaining lease"
1155//usage: "\n -R,--release Release IP on exit"
1156//usage: "\n -S,--syslog Log to syslog too" 1160//usage: "\n -S,--syslog Log to syslog too"
1157//usage: IF_FEATURE_UDHCP_PORT(
1158//usage: "\n -P,--client-port N Use port N (default 68)"
1159//usage: )
1160//usage: IF_FEATURE_UDHCPC_ARPING( 1161//usage: IF_FEATURE_UDHCPC_ARPING(
1161//usage: "\n -a,--arping Use arping to validate offered address" 1162//usage: "\n -a,--arping Use arping to validate offered address"
1162//usage: ) 1163//usage: )
1163//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
1164//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
1165//usage: "\n -r,--request IP Request this IP address" 1164//usage: "\n -r,--request IP Request this IP address"
1165//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
1166//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
1166//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1167//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1167//usage: "\n Examples of string, numeric, and hex byte opts:" 1168//usage: "\n Examples of string, numeric, and hex byte opts:"
1168//usage: "\n -x hostname:bbox - option 12" 1169//usage: "\n -x hostname:bbox - option 12"
@@ -1177,29 +1178,29 @@ static void client_background(void)
1177//usage: ) 1178//usage: )
1178//usage: IF_NOT_LONG_OPTS( 1179//usage: IF_NOT_LONG_OPTS(
1179//usage: "\n -i IFACE Interface to use (default eth0)" 1180//usage: "\n -i IFACE Interface to use (default eth0)"
1180//usage: "\n -p FILE Create pidfile" 1181//usage: IF_FEATURE_UDHCP_PORT(
1182//usage: "\n -P PORT Use PORT (default 68)"
1183//usage: )
1181//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 1184//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1185//usage: "\n -p FILE Create pidfile"
1182//usage: "\n -B Request broadcast replies" 1186//usage: "\n -B Request broadcast replies"
1183//usage: "\n -t N Send up to N discover packets" 1187//usage: "\n -t N Send up to N discover packets (default 3)"
1184//usage: "\n -T N Pause between packets (default 3 seconds)" 1188//usage: "\n -T SEC Pause between packets (default 3)"
1185//usage: "\n -A N Wait N seconds (default 20) after failure" 1189//usage: "\n -A SEC Wait if lease is not obtained (default 20)"
1190//usage: "\n -n Exit if lease is not obtained"
1191//usage: "\n -q Exit after obtaining lease"
1192//usage: "\n -R Release IP on exit"
1186//usage: "\n -f Run in foreground" 1193//usage: "\n -f Run in foreground"
1187//usage: USE_FOR_MMU( 1194//usage: USE_FOR_MMU(
1188//usage: "\n -b Background if lease is not obtained" 1195//usage: "\n -b Background if lease is not obtained"
1189//usage: ) 1196//usage: )
1190//usage: "\n -n Exit if lease is not obtained"
1191//usage: "\n -q Exit after obtaining lease"
1192//usage: "\n -R Release IP on exit"
1193//usage: "\n -S Log to syslog too" 1197//usage: "\n -S Log to syslog too"
1194//usage: IF_FEATURE_UDHCP_PORT(
1195//usage: "\n -P N Use port N (default 68)"
1196//usage: )
1197//usage: IF_FEATURE_UDHCPC_ARPING( 1198//usage: IF_FEATURE_UDHCPC_ARPING(
1198//usage: "\n -a Use arping to validate offered address" 1199//usage: "\n -a Use arping to validate offered address"
1199//usage: ) 1200//usage: )
1200//usage: "\n -O OPT Request option OPT from server (cumulative)"
1201//usage: "\n -o Don't request any options (unless -O is given)"
1202//usage: "\n -r IP Request this IP address" 1201//usage: "\n -r IP Request this IP address"
1202//usage: "\n -o Don't request any options (unless -O is given)"
1203//usage: "\n -O OPT Request option OPT from server (cumulative)"
1203//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1204//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1204//usage: "\n Examples of string, numeric, and hex byte opts:" 1205//usage: "\n Examples of string, numeric, and hex byte opts:"
1205//usage: "\n -x hostname:bbox - option 12" 1206//usage: "\n -x hostname:bbox - option 12"
diff --git a/networking/wget.c b/networking/wget.c
index 4eafebe40..5dac2b500 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -62,14 +62,14 @@ struct globals {
62 const char *curfile; /* Name of current file being transferred */ 62 const char *curfile; /* Name of current file being transferred */
63 bb_progress_t pmt; 63 bb_progress_t pmt;
64#endif 64#endif
65 char *dir_prefix; 65 char *dir_prefix;
66#if ENABLE_FEATURE_WGET_LONG_OPTIONS 66#if ENABLE_FEATURE_WGET_LONG_OPTIONS
67 char *post_data; 67 char *post_data;
68 char *extra_headers; 68 char *extra_headers;
69#endif 69#endif
70 char *fname_out; /* where to direct output (-O) */ 70 char *fname_out; /* where to direct output (-O) */
71 const char *proxy_flag; /* Use proxies if env vars are set */ 71 const char *proxy_flag; /* Use proxies if env vars are set */
72 const char *user_agent; /* "User-Agent" header field */ 72 const char *user_agent; /* "User-Agent" header field */
73#if ENABLE_FEATURE_WGET_TIMEOUT 73#if ENABLE_FEATURE_WGET_TIMEOUT
74 unsigned timeout_seconds; 74 unsigned timeout_seconds;
75#endif 75#endif
@@ -86,7 +86,7 @@ struct globals {
86} FIX_ALIASING; 86} FIX_ALIASING;
87#define G (*ptr_to_globals) 87#define G (*ptr_to_globals)
88#define INIT_G() do { \ 88#define INIT_G() do { \
89 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 89 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
90 IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \ 90 IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \
91} while (0) 91} while (0)
92 92
@@ -328,8 +328,16 @@ static char *gethdr(FILE *fp)
328 return NULL; 328 return NULL;
329 329
330 /* convert the header name to lower case */ 330 /* convert the header name to lower case */
331 for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { 331 for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.' || *s == '_'; ++s) {
332 /* tolower for "A-Z", no-op for "0-9a-z-." */ 332 /*
333 * No-op for 20-3f and 60-7f. "0-9a-z-." are in these ranges.
334 * 40-5f range ("@A-Z[\]^_") maps to 60-7f.
335 * "A-Z" maps to "a-z".
336 * "@[\]" can't occur in header names.
337 * "^_" maps to "~,DEL" (which is wrong).
338 * "^" was never seen yet, "_" was seen from web.archive.org
339 * (x-archive-orig-x_commoncrawl_Signature: HEXSTRING).
340 */
333 *s |= 0x20; 341 *s |= 0x20;
334 } 342 }
335 343
diff --git a/procps/lsof.c b/procps/lsof.c
index 7e0ffa4e5..b0156a538 100644
--- a/procps/lsof.c
+++ b/procps/lsof.c
@@ -61,9 +61,12 @@ int lsof_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
61 d_fd = opendir(name); 61 d_fd = opendir(name);
62 if (d_fd) { 62 if (d_fd) {
63 while ((entry = readdir(d_fd)) != NULL) { 63 while ((entry = readdir(d_fd)) != NULL) {
64 if (entry->d_type == DT_LNK) { 64 /* Skip entries '.' and '..' (and any hidden file) */
65 safe_strncpy(name + baseofs, entry->d_name, 10); 65 if (entry->d_name[0] == '.')
66 fdlink = xmalloc_readlink(name); 66 continue;
67
68 safe_strncpy(name + baseofs, entry->d_name, 10);
69 if ((fdlink = xmalloc_readlink(name)) != NULL) {
67 printf("%d\t%s\t%s\n", proc->pid, proc->exe, fdlink); 70 printf("%d\t%s\t%s\n", proc->pid, proc->exe, fdlink);
68 free(fdlink); 71 free(fdlink);
69 } 72 }
diff --git a/procps/pstree.c b/procps/pstree.c
index 8ba30795d..ed1a41289 100644
--- a/procps/pstree.c
+++ b/procps/pstree.c
@@ -34,8 +34,15 @@
34 34
35struct child; 35struct child;
36 36
37#ifdef ENABLE_FEATURE_SHOW_THREADS
38/* For threads, we add {...} around the comm, so we need two extra bytes */
39# define COMM_DISP_LEN (COMM_LEN + 2)
40#else
41# define COMM_DISP_LEN COMM_LEN
42#endif
43
37typedef struct proc { 44typedef struct proc {
38 char comm[COMM_LEN + 1]; 45 char comm[COMM_DISP_LEN + 1];
39// char flags; - unused, delete? 46// char flags; - unused, delete?
40 pid_t pid; 47 pid_t pid;
41 uid_t uid; 48 uid_t uid;
@@ -341,8 +348,8 @@ static void dump_by_user(PROC *current, uid_t uid)
341#if ENABLE_FEATURE_SHOW_THREADS 348#if ENABLE_FEATURE_SHOW_THREADS
342static void handle_thread(const char *comm, pid_t pid, pid_t ppid, uid_t uid) 349static void handle_thread(const char *comm, pid_t pid, pid_t ppid, uid_t uid)
343{ 350{
344 char threadname[COMM_LEN + 2]; 351 char threadname[COMM_DISP_LEN + 1];
345 sprintf(threadname, "{%.*s}", COMM_LEN - 2, comm); 352 sprintf(threadname, "{%.*s}", (int)sizeof(threadname) - 3, comm);
346 add_proc(threadname, pid, ppid, uid/*, 1*/); 353 add_proc(threadname, pid, ppid, uid/*, 1*/);
347} 354}
348#endif 355#endif
diff --git a/runit/svlogd.c b/runit/svlogd.c
index b7a0a6e71..8b8a6d858 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -745,11 +745,6 @@ static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn)
745 ld->inst = new; 745 ld->inst = new;
746 break; 746 break;
747 case 's': { 747 case 's': {
748 static const struct suffix_mult km_suffixes[] = {
749 { "k", 1024 },
750 { "m", 1024*1024 },
751 { "", 0 }
752 };
753 ld->sizemax = xatou_sfx(&s[1], km_suffixes); 748 ld->sizemax = xatou_sfx(&s[1], km_suffixes);
754 break; 749 break;
755 } 750 }
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index bd2d70e19..303df0be7 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -474,7 +474,11 @@ int conf_write(const char *name)
474 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); 474 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
475 /* bbox */ 475 /* bbox */
476 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 476 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
477 fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); 477 fprintf(out_h, "#ifdef MAKE_SUID\n");
478 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
479 fprintf(out_h, "#else\n");
480 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
481 fprintf(out_h, "#endif\n");
478 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); 482 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
479 } 483 }
480 break; 484 break;
@@ -506,7 +510,11 @@ int conf_write(const char *name)
506 fputs("\"\n", out_h); 510 fputs("\"\n", out_h);
507 /* bbox */ 511 /* bbox */
508 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 512 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
509 fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); 513 fprintf(out_h, "#ifdef MAKE_SUID\n");
514 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
515 fprintf(out_h, "#else\n");
516 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
517 fprintf(out_h, "#endif\n");
510 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); 518 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
511 } 519 }
512 break; 520 break;
@@ -518,7 +526,11 @@ int conf_write(const char *name)
518 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); 526 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
519 /* bbox */ 527 /* bbox */
520 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 528 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
521 fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); 529 fprintf(out_h, "#ifdef MAKE_SUID\n");
530 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
531 fprintf(out_h, "#else\n");
532 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
533 fprintf(out_h, "#endif\n");
522 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); 534 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
523 } 535 }
524 break; 536 break;
@@ -532,7 +544,11 @@ int conf_write(const char *name)
532 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); 544 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
533 /* bbox */ 545 /* bbox */
534 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 546 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
535 fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); 547 fprintf(out_h, "#ifdef MAKE_SUID\n");
548 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
549 fprintf(out_h, "#else\n");
550 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
551 fprintf(out_h, "#endif\n");
536 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); 552 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
537 } 553 }
538 break; 554 break;
diff --git a/shell/ash.c b/shell/ash.c
index 8f59dccda..6e6fc6a71 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -9501,6 +9501,9 @@ static int getoptscmd(int, char **) FAST_FUNC;
9501#if !ENABLE_FEATURE_SH_EXTRA_QUIET 9501#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9502static int helpcmd(int, char **) FAST_FUNC; 9502static int helpcmd(int, char **) FAST_FUNC;
9503#endif 9503#endif
9504#if MAX_HISTORY
9505static int historycmd(int, char **) FAST_FUNC;
9506#endif
9504#if ENABLE_SH_MATH_SUPPORT 9507#if ENABLE_SH_MATH_SUPPORT
9505static int letcmd(int, char **) FAST_FUNC; 9508static int letcmd(int, char **) FAST_FUNC;
9506#endif 9509#endif
@@ -9574,6 +9577,9 @@ static const struct builtincmd builtintab[] = {
9574#if !ENABLE_FEATURE_SH_EXTRA_QUIET 9577#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9575 { BUILTIN_NOSPEC "help" , helpcmd }, 9578 { BUILTIN_NOSPEC "help" , helpcmd },
9576#endif 9579#endif
9580#if MAX_HISTORY
9581 { BUILTIN_NOSPEC "history" , historycmd },
9582#endif
9577#if JOBS 9583#if JOBS
9578 { BUILTIN_REGULAR "jobs" , jobscmd }, 9584 { BUILTIN_REGULAR "jobs" , jobscmd },
9579 { BUILTIN_REGULAR "kill" , killcmd }, 9585 { BUILTIN_REGULAR "kill" , killcmd },
@@ -10155,7 +10161,12 @@ preadfd(void)
10155 * _during_ shell execution, not only if it was set when 10161 * _during_ shell execution, not only if it was set when
10156 * shell was started. Therefore, re-check LANG every time: 10162 * shell was started. Therefore, re-check LANG every time:
10157 */ 10163 */
10158 reinit_unicode(lookupvar("LANG")); 10164 {
10165 const char *s = lookupvar("LC_ALL");
10166 if (!s) s = lookupvar("LC_CTYPE");
10167 if (!s) s = lookupvar("LANG");
10168 reinit_unicode(s);
10169 }
10159 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); 10170 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
10160 if (nr == 0) { 10171 if (nr == 0) {
10161 /* Ctrl+C pressed */ 10172 /* Ctrl+C pressed */
@@ -13163,6 +13174,15 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13163} 13174}
13164#endif /* FEATURE_SH_EXTRA_QUIET */ 13175#endif /* FEATURE_SH_EXTRA_QUIET */
13165 13176
13177#if MAX_HISTORY
13178static int FAST_FUNC
13179historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13180{
13181 show_history(line_input_state);
13182 return EXIT_SUCCESS;
13183}
13184#endif
13185
13166/* 13186/*
13167 * The export and readonly commands. 13187 * The export and readonly commands.
13168 */ 13188 */
diff --git a/shell/hush.c b/shell/hush.c
index b23325725..912ecf15f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -850,6 +850,9 @@ static int builtin_jobs(char **argv) FAST_FUNC;
850#if ENABLE_HUSH_HELP 850#if ENABLE_HUSH_HELP
851static int builtin_help(char **argv) FAST_FUNC; 851static int builtin_help(char **argv) FAST_FUNC;
852#endif 852#endif
853#if MAX_HISTORY && ENABLE_FEATURE_EDITING
854static int builtin_history(char **argv) FAST_FUNC;
855#endif
853#if ENABLE_HUSH_LOCAL 856#if ENABLE_HUSH_LOCAL
854static int builtin_local(char **argv) FAST_FUNC; 857static int builtin_local(char **argv) FAST_FUNC;
855#endif 858#endif
@@ -919,6 +922,9 @@ static const struct built_in_command bltins1[] = {
919#if ENABLE_HUSH_HELP 922#if ENABLE_HUSH_HELP
920 BLTIN("help" , builtin_help , NULL), 923 BLTIN("help" , builtin_help , NULL),
921#endif 924#endif
925#if MAX_HISTORY && ENABLE_FEATURE_EDITING
926 BLTIN("history" , builtin_history , "Show command history"),
927#endif
922#if ENABLE_HUSH_JOB 928#if ENABLE_HUSH_JOB
923 BLTIN("jobs" , builtin_jobs , "List jobs"), 929 BLTIN("jobs" , builtin_jobs , "List jobs"),
924#endif 930#endif
@@ -1383,7 +1389,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1383 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1389 * are set to '' (ignore) are NOT reset to defaults. We do the same.
1384 * 1390 *
1385 * Problem: the above approach makes it unwieldy to catch signals while 1391 * Problem: the above approach makes it unwieldy to catch signals while
1386 * we are in read builtin, of while we read commands from stdin: 1392 * we are in read builtin, or while we read commands from stdin:
1387 * masked signals are not visible! 1393 * masked signals are not visible!
1388 * 1394 *
1389 * New implementation 1395 * New implementation
@@ -2038,7 +2044,10 @@ static void get_user_input(struct in_str *i)
2038 * _during_ shell execution, not only if it was set when 2044 * _during_ shell execution, not only if it was set when
2039 * shell was started. Therefore, re-check LANG every time: 2045 * shell was started. Therefore, re-check LANG every time:
2040 */ 2046 */
2041 reinit_unicode(get_local_var_value("LANG")); 2047 const char *s = get_local_var_value("LC_ALL");
2048 if (!s) s = get_local_var_value("LC_CTYPE");
2049 if (!s) s = get_local_var_value("LANG");
2050 reinit_unicode(s);
2042 2051
2043 G.flag_SIGINT = 0; 2052 G.flag_SIGINT = 0;
2044 /* buglet: SIGINT will not make new prompt to appear _at once_, 2053 /* buglet: SIGINT will not make new prompt to appear _at once_,
@@ -7354,7 +7363,7 @@ static int run_list(struct pipe *pi)
7354 * and we should not execute CMD */ 7363 * and we should not execute CMD */
7355 debug_printf_exec("skipped cmd because of || or &&\n"); 7364 debug_printf_exec("skipped cmd because of || or &&\n");
7356 last_followup = pi->followup; 7365 last_followup = pi->followup;
7357 continue; 7366 goto dont_check_jobs_but_continue;
7358 } 7367 }
7359 } 7368 }
7360 last_followup = pi->followup; 7369 last_followup = pi->followup;
@@ -7493,8 +7502,10 @@ static int run_list(struct pipe *pi)
7493 G.flag_break_continue = 0; 7502 G.flag_break_continue = 0;
7494 /* else: e.g. "continue 2" should *break* once, *then* continue */ 7503 /* else: e.g. "continue 2" should *break* once, *then* continue */
7495 } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */ 7504 } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */
7496 if (G.depth_break_continue != 0 || fbc == BC_BREAK) 7505 if (G.depth_break_continue != 0 || fbc == BC_BREAK) {
7497 goto check_jobs_and_break; 7506 checkjobs(NULL);
7507 break;
7508 }
7498 /* "continue": simulate end of loop */ 7509 /* "continue": simulate end of loop */
7499 rword = RES_DONE; 7510 rword = RES_DONE;
7500 continue; 7511 continue;
@@ -7502,7 +7513,6 @@ static int run_list(struct pipe *pi)
7502#endif 7513#endif
7503#if ENABLE_HUSH_FUNCTIONS 7514#if ENABLE_HUSH_FUNCTIONS
7504 if (G.flag_return_in_progress == 1) { 7515 if (G.flag_return_in_progress == 1) {
7505 /* same as "goto check_jobs_and_break" */
7506 checkjobs(NULL); 7516 checkjobs(NULL);
7507 break; 7517 break;
7508 } 7518 }
@@ -7544,6 +7554,9 @@ static int run_list(struct pipe *pi)
7544 if (rword == RES_IF || rword == RES_ELIF) 7554 if (rword == RES_IF || rword == RES_ELIF)
7545 cond_code = rcode; 7555 cond_code = rcode;
7546#endif 7556#endif
7557 check_jobs_and_continue:
7558 checkjobs(NULL);
7559 dont_check_jobs_but_continue: ;
7547#if ENABLE_HUSH_LOOPS 7560#if ENABLE_HUSH_LOOPS
7548 /* Beware of "while false; true; do ..."! */ 7561 /* Beware of "while false; true; do ..."! */
7549 if (pi->next 7562 if (pi->next
@@ -7555,22 +7568,17 @@ static int run_list(struct pipe *pi)
7555 /* "while false; do...done" - exitcode 0 */ 7568 /* "while false; do...done" - exitcode 0 */
7556 G.last_exitcode = rcode = EXIT_SUCCESS; 7569 G.last_exitcode = rcode = EXIT_SUCCESS;
7557 debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n"); 7570 debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n");
7558 goto check_jobs_and_break; 7571 break;
7559 } 7572 }
7560 } 7573 }
7561 if (rword == RES_UNTIL) { 7574 if (rword == RES_UNTIL) {
7562 if (!rcode) { 7575 if (!rcode) {
7563 debug_printf_exec(": until expr is true: breaking\n"); 7576 debug_printf_exec(": until expr is true: breaking\n");
7564 check_jobs_and_break:
7565 checkjobs(NULL);
7566 break; 7577 break;
7567 } 7578 }
7568 } 7579 }
7569 } 7580 }
7570#endif 7581#endif
7571
7572 check_jobs_and_continue:
7573 checkjobs(NULL);
7574 } /* for (pi) */ 7582 } /* for (pi) */
7575 7583
7576#if ENABLE_HUSH_JOB 7584#if ENABLE_HUSH_JOB
@@ -8628,6 +8636,14 @@ static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
8628} 8636}
8629#endif 8637#endif
8630 8638
8639#if MAX_HISTORY && ENABLE_FEATURE_EDITING
8640static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
8641{
8642 show_history(G.line_input_state);
8643 return EXIT_SUCCESS;
8644}
8645#endif
8646
8631#if ENABLE_HUSH_JOB 8647#if ENABLE_HUSH_JOB
8632static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM) 8648static int FAST_FUNC builtin_jobs(char **argv UNUSED_PARAM)
8633{ 8649{
diff --git a/shell/hush_test/hush-misc/while4.right b/shell/hush_test/hush-misc/while4.right
new file mode 100644
index 000000000..7b24a35ff
--- /dev/null
+++ b/shell/hush_test/hush-misc/while4.right
@@ -0,0 +1 @@
Ok:0
diff --git a/shell/hush_test/hush-misc/while4.tests b/shell/hush_test/hush-misc/while4.tests
new file mode 100755
index 000000000..ba80e603a
--- /dev/null
+++ b/shell/hush_test/hush-misc/while4.tests
@@ -0,0 +1,6 @@
1false
2while false && echo Not reached; do
3 echo BUG
4 break
5done
6echo Ok:$?
diff --git a/shell/shell_common.c b/shell/shell_common.c
index f7503cac5..84e0604ed 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -39,7 +39,7 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
39 39
40/* read builtin */ 40/* read builtin */
41 41
42/* Needs to be interruptible: shell mush handle traps and shell-special signals 42/* Needs to be interruptible: shell must handle traps and shell-special signals
43 * while inside read. To implement this, be sure to not loop on EINTR 43 * while inside read. To implement this, be sure to not loop on EINTR
44 * and return errno == EINTR reliably. 44 * and return errno == EINTR reliably.
45 */ 45 */
diff --git a/sysklogd/logread.c b/sysklogd/logread.c
index 993956904..2b6415f47 100644
--- a/sysklogd/logread.c
+++ b/sysklogd/logread.c
@@ -52,7 +52,7 @@ struct globals {
52static void error_exit(const char *str) NORETURN; 52static void error_exit(const char *str) NORETURN;
53static void error_exit(const char *str) 53static void error_exit(const char *str)
54{ 54{
55 //release all acquired resources 55 /* Release all acquired resources */
56 shmdt(shbuf); 56 shmdt(shbuf);
57 bb_perror_msg_and_die(str); 57 bb_perror_msg_and_die(str);
58} 58}
@@ -66,11 +66,10 @@ static void sem_up(int semid)
66 error_exit("semop[SMrup]"); 66 error_exit("semop[SMrup]");
67} 67}
68 68
69static void interrupted(int sig UNUSED_PARAM) 69static void interrupted(int sig)
70{ 70{
71 signal(SIGINT, SIG_IGN);
72 shmdt(shbuf); 71 shmdt(shbuf);
73 exit(EXIT_SUCCESS); 72 kill_myself_with_sig(sig);
74} 73}
75 74
76int logread_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 75int logread_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -96,7 +95,7 @@ int logread_main(int argc UNUSED_PARAM, char **argv)
96 if (log_semid == -1) 95 if (log_semid == -1)
97 error_exit("can't get access to semaphores for syslogd buffer"); 96 error_exit("can't get access to semaphores for syslogd buffer");
98 97
99 signal(SIGINT, interrupted); 98 bb_signals(BB_FATAL_SIGS, interrupted);
100 99
101 /* Suppose atomic memory read */ 100 /* Suppose atomic memory read */
102 /* Max possible value for tail is shbuf->size - 1 */ 101 /* Max possible value for tail is shbuf->size - 1 */
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 4f45b4f7f..a6a4ff25c 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -58,6 +58,9 @@
58#define SYSLOG_NAMES_CONST 58#define SYSLOG_NAMES_CONST
59#include <syslog.h> 59#include <syslog.h>
60*/ 60*/
61#ifndef _PATH_LOG
62#define _PATH_LOG "/dev/log"
63#endif
61 64
62#include <sys/un.h> 65#include <sys/un.h>
63#include <sys/uio.h> 66#include <sys/uio.h>
@@ -824,8 +827,8 @@ static NOINLINE int create_socket(void)
824 827
825 /* Unlink old /dev/log or object it points to. */ 828 /* Unlink old /dev/log or object it points to. */
826 /* (if it exists, bind will fail) */ 829 /* (if it exists, bind will fail) */
827 strcpy(sunx.sun_path, "/dev/log"); 830 strcpy(sunx.sun_path, _PATH_LOG);
828 dev_log_name = xmalloc_follow_symlinks("/dev/log"); 831 dev_log_name = xmalloc_follow_symlinks(_PATH_LOG);
829 if (dev_log_name) { 832 if (dev_log_name) {
830 safe_strncpy(sunx.sun_path, dev_log_name, sizeof(sunx.sun_path)); 833 safe_strncpy(sunx.sun_path, dev_log_name, sizeof(sunx.sun_path));
831 free(dev_log_name); 834 free(dev_log_name);
@@ -834,7 +837,7 @@ static NOINLINE int create_socket(void)
834 837
835 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0); 838 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
836 xbind(sock_fd, (struct sockaddr *) &sunx, sizeof(sunx)); 839 xbind(sock_fd, (struct sockaddr *) &sunx, sizeof(sunx));
837 chmod("/dev/log", 0666); 840 chmod(_PATH_LOG, 0666);
838 841
839 return sock_fd; 842 return sock_fd;
840} 843}
@@ -905,7 +908,7 @@ static void do_syslogd(void)
905 sz = read(sock_fd, recvbuf, MAX_READ - 1); 908 sz = read(sock_fd, recvbuf, MAX_READ - 1);
906 if (sz < 0) { 909 if (sz < 0) {
907 if (!bb_got_signal) 910 if (!bb_got_signal)
908 bb_perror_msg("read from /dev/log"); 911 bb_perror_msg("read from %s", _PATH_LOG);
909 break; 912 break;
910 } 913 }
911 914
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index dad49c3f5..6af6072b8 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -24,7 +24,7 @@ testing "awk if operator < " "awk 'BEGIN{if(2 < 13) print \"foo\"}'" "foo\n" "
24testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" "" "" 24testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" "" ""
25 25
26# 4294967295 = 0xffffffff 26# 4294967295 = 0xffffffff
27testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" 27testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4294967295\n" "" "\n"
28 28
29# we were testing for a non-empty body when deciding if a function was 29# we were testing for a non-empty body when deciding if a function was
30# defined or not. The testcase below caused: 30# defined or not. The testcase below caused:
@@ -44,9 +44,37 @@ testing "awk handles empty function f(arg){}" \
44 "L1\n\nL2\n\n" \ 44 "L1\n\nL2\n\n" \
45 "" "" 45 "" ""
46 46
47prg='
48function outer_fun() {
49 return 1
50}
51END {
52 i=1
53 print "L" i "\n"
54 i += outer_fun()
55 print "L" i "\n"
56}'
57testing "awk properly handles function from other scope" \
58 "awk '$prg'" \
59 "L1\n\nL2\n\n" \
60 "" ""
61
62prg='
63END {
64 i=1
65 print "L" i "\n"
66 i + trigger_error_fun()
67 print "L" i "\n"
68}'
69testing "awk properly handles undefined function" \
70 "awk '$prg' 2>&1" \
71 "L1\n\nawk: cmd. line:5: Call to undefined function\n" \
72 "" ""
73
74
47optional DESKTOP 75optional DESKTOP
48testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" 76testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4294967295\n" "" "\n"
49testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" 77testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2147483649\n" "" "\n"
50testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n" 78testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n"
51SKIP= 79SKIP=
52 80
@@ -241,6 +269,11 @@ testing "awk FS assignment" "awk '{FS=\":\"; print \$1}'" \
241 "" \ 269 "" \
242 "a:b c:d\ne:f g:h" 270 "a:b c:d\ne:f g:h"
243 271
272testing "awk large integer" \
273 "awk 'BEGIN{n=(2^31)-1; print n, int(n), n%1, ++n, int(n), n%1}'" \
274 "2147483647 2147483647 0 2147483648 2147483648 0\n" \
275 "" ""
276
244# testing "description" "command" "result" "infile" "stdin" 277# testing "description" "command" "result" "infile" "stdin"
245 278
246exit $FAILCOUNT 279exit $FAILCOUNT
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index 4781f2284..64d99a905 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -82,6 +82,20 @@ testing "grep -F handles -i" "grep -F -i foo input ; echo \$?" \
82testing "grep can read regexps from stdin" "grep -f - input ; echo \$?" \ 82testing "grep can read regexps from stdin" "grep -f - input ; echo \$?" \
83 "two\nthree\n0\n" "tw\ntwo\nthree\n" "tw.\nthr\n" 83 "two\nthree\n0\n" "tw\ntwo\nthree\n" "tw.\nthr\n"
84 84
85# -x (whole line match)
86testing "grep -x (full match)" "grep -x foo input ; echo \$?" \
87 "foo\n0\n" "foo\n" ""
88testing "grep -x (partial match 1)" "grep -x foo input ; echo \$?" \
89 "1\n" "foo bar\n" ""
90testing "grep -x (partial match 2)" "grep -x foo input ; echo \$?" \
91 "1\n" "bar foo\n" ""
92testing "grep -x -F (full match)" "grep -x -F foo input ; echo \$?" \
93 "foo\n0\n" "foo\n" ""
94testing "grep -x -F (partial match 1)" "grep -x -F foo input ; echo \$?" \
95 "1\n" "foo bar\n" ""
96testing "grep -x -F (partial match 2)" "grep -x -F foo input ; echo \$?" \
97 "1\n" "bar foo\n" ""
98
85optional FEATURE_GREP_EGREP_ALIAS 99optional FEATURE_GREP_EGREP_ALIAS
86testing "grep -E supports extended regexps" "grep -E fo+" "foo\n" "" \ 100testing "grep -E supports extended regexps" "grep -E fo+" "foo\n" "" \
87 "b\ar\nfoo\nbaz" 101 "b\ar\nfoo\nbaz"
@@ -127,6 +141,12 @@ testing "grep -Fw doesn't stop on 1st mismatch" \
127 "foop foo\n" \ 141 "foop foo\n" \
128 "" 142 ""
129 143
144testing "grep -w doesn't stop on 1st mismatch" \
145 "grep -w foo input" \
146 "foop foo\n" \
147 "foop foo\n" \
148 ""
149
130# testing "test name" "commands" "expected result" "file input" "stdin" 150# testing "test name" "commands" "expected result" "file input" "stdin"
131# file input will be file called "input" 151# file input will be file called "input"
132# test can create a file "actual" instead of writing to stdout 152# test can create a file "actual" instead of writing to stdout
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 468565f47..2af1e4c97 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -310,6 +310,27 @@ testing "sed zero chars match/replace logic must not falsely trigger here 2" \
310 "sed 's/ *$/_/g'" \ 310 "sed 's/ *$/_/g'" \
311 "qwerty_\n" "" "qwerty\n" 311 "qwerty_\n" "" "qwerty\n"
312 312
313testing "sed /\$_in_regex/ should not match newlines, only end-of-line" \
314 "sed ': testcont; /\\\\$/{ =; N; b testcont }'" \
315 "\
316this is a regular line
3172
318line with \\
319continuation
320more regular lines
3215
322line with \\
323continuation
324" \
325 "" "\
326this is a regular line
327line with \\
328continuation
329more regular lines
330line with \\
331continuation
332"
333
313# testing "description" "commands" "result" "infile" "stdin" 334# testing "description" "commands" "result" "infile" "stdin"
314 335
315exit $FAILCOUNT 336exit $FAILCOUNT
diff --git a/util-linux/Config.src b/util-linux/Config.src
index 6c1b928da..5a8b0063b 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -699,250 +699,6 @@ config FEATURE_MTAB_SUPPORT
699 About the only reason to use this is if you've removed /proc from 699 About the only reason to use this is if you've removed /proc from
700 your kernel. 700 your kernel.
701 701
702config VOLUMEID 702source util-linux/volume_id/Config.in
703 bool #No description makes it a hidden option
704 default n
705
706menu "Filesystem/Volume identification"
707 depends on VOLUMEID
708
709config FEATURE_VOLUMEID_EXT
710 bool "Ext filesystem"
711 default y
712 depends on VOLUMEID
713 help
714 TODO
715
716config FEATURE_VOLUMEID_BTRFS
717 bool "btrfs filesystem"
718 default y
719 depends on VOLUMEID
720 help
721 TODO
722
723config FEATURE_VOLUMEID_REISERFS
724 bool "Reiser filesystem"
725 default y
726 depends on VOLUMEID
727 help
728 TODO
729
730config FEATURE_VOLUMEID_FAT
731 bool "fat filesystem"
732 default y
733 depends on VOLUMEID
734 help
735 TODO
736
737config FEATURE_VOLUMEID_EXFAT
738 bool "exFAT filesystem"
739 default y
740 depends on VOLUMEID
741 help
742 exFAT (extended FAT) is a proprietary file system designed especially
743 for flash drives. It has many features from NTFS, but with less
744 overhead. exFAT is used on most SDXC cards for consumer electronics.
745
746config FEATURE_VOLUMEID_HFS
747 bool "hfs filesystem"
748 default y
749 depends on VOLUMEID
750 help
751 TODO
752
753config FEATURE_VOLUMEID_JFS
754 bool "jfs filesystem"
755 default y
756 depends on VOLUMEID
757 help
758 TODO
759
760### config FEATURE_VOLUMEID_UFS
761### bool "ufs filesystem"
762### default y
763### depends on VOLUMEID
764### help
765### TODO
766
767config FEATURE_VOLUMEID_XFS
768 bool "xfs filesystem"
769 default y
770 depends on VOLUMEID
771 help
772 TODO
773
774config FEATURE_VOLUMEID_NILFS
775 bool "nilfs filesystem"
776 default y
777 depends on VOLUMEID
778 help
779 TODO
780
781config FEATURE_VOLUMEID_NTFS
782 bool "ntfs filesystem"
783 default y
784 depends on VOLUMEID
785 help
786 TODO
787
788config FEATURE_VOLUMEID_ISO9660
789 bool "iso9660 filesystem"
790 default y
791 depends on VOLUMEID
792 help
793 TODO
794
795config FEATURE_VOLUMEID_UDF
796 bool "udf filesystem"
797 default y
798 depends on VOLUMEID
799 help
800 TODO
801
802config FEATURE_VOLUMEID_LUKS
803 bool "luks filesystem"
804 default y
805 depends on VOLUMEID
806 help
807 TODO
808
809config FEATURE_VOLUMEID_LINUXSWAP
810 bool "linux swap filesystem"
811 default y
812 depends on VOLUMEID
813 help
814 TODO
815
816### config FEATURE_VOLUMEID_LVM
817### bool "lvm"
818### default y
819### depends on VOLUMEID
820### help
821### TODO
822
823config FEATURE_VOLUMEID_CRAMFS
824 bool "cramfs filesystem"
825 default y
826 depends on VOLUMEID
827 help
828 TODO
829
830### config FEATURE_VOLUMEID_HPFS
831### bool "hpfs filesystem"
832### default y
833### depends on VOLUMEID
834### help
835### TODO
836
837config FEATURE_VOLUMEID_ROMFS
838 bool "romfs filesystem"
839 default y
840 depends on VOLUMEID
841 help
842 TODO
843
844config FEATURE_VOLUMEID_SQUASHFS
845 bool "SquashFS filesystem"
846 default y
847 depends on VOLUMEID && FEATURE_BLKID_TYPE
848 help
849 Squashfs is a compressed read-only filesystem for Linux. Squashfs is
850 intended for general read-only filesystem use and in constrained block
851 device/memory systems (e.g. embedded systems) where low overhead is
852 needed.
853
854config FEATURE_VOLUMEID_SYSV
855 bool "sysv filesystem"
856 default y
857 depends on VOLUMEID
858 help
859 TODO
860
861### config FEATURE_VOLUMEID_MINIX
862### bool "minix filesystem"
863### default y
864### depends on VOLUMEID
865### help
866### TODO
867
868### These only detect partition tables - not used (yet?)
869### config FEATURE_VOLUMEID_MAC
870### bool "mac filesystem"
871### default y
872### depends on VOLUMEID
873### help
874### TODO
875###
876### config FEATURE_VOLUMEID_MSDOS
877### bool "msdos filesystem"
878### default y
879### depends on VOLUMEID
880### help
881### TODO
882
883config FEATURE_VOLUMEID_OCFS2
884 bool "ocfs2 filesystem"
885 default y
886 depends on VOLUMEID
887 help
888 TODO
889
890### config FEATURE_VOLUMEID_HIGHPOINTRAID
891### bool "highpoint raid"
892### default y
893### depends on VOLUMEID
894### help
895### TODO
896
897### config FEATURE_VOLUMEID_ISWRAID
898### bool "intel raid"
899### default y
900### depends on VOLUMEID
901### help
902### TODO
903
904### config FEATURE_VOLUMEID_LSIRAID
905### bool "lsi raid"
906### default y
907### depends on VOLUMEID
908### help
909### TODO
910
911### config FEATURE_VOLUMEID_VIARAID
912### bool "via raid"
913### default y
914### depends on VOLUMEID
915### help
916### TODO
917
918### config FEATURE_VOLUMEID_SILICONRAID
919### bool "silicon raid"
920### default y
921### depends on VOLUMEID
922### help
923### TODO
924
925### config FEATURE_VOLUMEID_NVIDIARAID
926### bool "nvidia raid"
927### default y
928### depends on VOLUMEID
929### help
930### TODO
931
932### config FEATURE_VOLUMEID_PROMISERAID
933### bool "promise raid"
934### default y
935### depends on VOLUMEID
936### help
937### TODO
938
939config FEATURE_VOLUMEID_LINUXRAID
940 bool "linuxraid"
941 default y
942 depends on VOLUMEID
943 help
944 TODO
945
946endmenu
947 703
948endmenu 704endmenu
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c
index d43d9c709..f45f68af0 100644
--- a/util-linux/fdisk_gpt.c
+++ b/util-linux/fdisk_gpt.c
@@ -95,7 +95,7 @@ gpt_list_table(int xtra UNUSED_PARAM)
95 95
96 numstr6[5] = '\0'; 96 numstr6[5] = '\0';
97 97
98 smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY"); 98 smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY");
99 printf("Disk %s: %llu sectors, %s\n", disk_device, 99 printf("Disk %s: %llu sectors, %s\n", disk_device,
100 (unsigned long long)total_number_of_sectors, 100 (unsigned long long)total_number_of_sectors,
101 numstr6); 101 numstr6);
@@ -112,7 +112,7 @@ gpt_list_table(int xtra UNUSED_PARAM)
112 for (i = 0; i < n_parts; i++) { 112 for (i = 0; i < n_parts; i++) {
113 gpt_partition *p = gpt_part(i); 113 gpt_partition *p = gpt_part(i);
114 if (p->lba_start) { 114 if (p->lba_start) {
115 smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start), 115 smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
116 numstr6, " KMGTPEZY"); 116 numstr6, " KMGTPEZY");
117 printf("%4u %15llu %15llu %11s %04x ", 117 printf("%4u %15llu %15llu %11s %04x ",
118 i + 1, 118 i + 1,
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c
index 4d998b916..ac7e24ff8 100644
--- a/util-linux/hexdump.c
+++ b/util-linux/hexdump.c
@@ -66,13 +66,6 @@ static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
66 66
67static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R"); 67static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R");
68 68
69static const struct suffix_mult suffixes[] = {
70 { "b", 512 },
71 { "k", 1024 },
72 { "m", 1024*1024 },
73 { "", 0 }
74};
75
76int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 69int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
77int hexdump_main(int argc, char **argv) 70int hexdump_main(int argc, char **argv)
78{ 71{
@@ -120,7 +113,7 @@ int hexdump_main(int argc, char **argv)
120 optarg, 113 optarg,
121 /*base:*/ 0, 114 /*base:*/ 0,
122 /*lo:*/ 0, /*hi:*/ OFF_T_MAX, 115 /*lo:*/ 0, /*hi:*/ OFF_T_MAX,
123 suffixes 116 bkm_suffixes
124 ); 117 );
125 } /* else */ 118 } /* else */
126 if (ch == 'v') { 119 if (ch == 'v') {
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index c69763335..d450b5a78 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -10,12 +10,12 @@
10//usage:#define losetup_trivial_usage 10//usage:#define losetup_trivial_usage
11//usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" 11//usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n"
12//usage: " losetup -d LOOPDEV - disassociate\n" 12//usage: " losetup -d LOOPDEV - disassociate\n"
13//usage: " losetup -a - show status of all\n" 13//usage: " losetup -a - show status\n"
14//usage: " losetup -f - show next available" 14//usage: " losetup -f - show next free loop device"
15//usage:#define losetup_full_usage "\n\n" 15//usage:#define losetup_full_usage "\n\n"
16//usage: " -o OFS Start OFS bytes into FILE" 16//usage: " -o OFS Start OFS bytes into FILE"
17//usage: "\n -r Read-only" 17//usage: "\n -r Read-only"
18//usage: "\n -f Show/find first free loop device" 18//usage: "\n -f Show/use next free loop device"
19//usage: 19//usage:
20//usage:#define losetup_notes_usage 20//usage:#define losetup_notes_usage
21//usage: "One argument (losetup /dev/loop1) will display the current association\n" 21//usage: "One argument (losetup /dev/loop1) will display the current association\n"
@@ -27,6 +27,10 @@
27 27
28#include "libbb.h" 28#include "libbb.h"
29 29
30/* 1048575 is a max possible minor number in Linux circa 2010 */
31/* for now use something less extreme */
32#define MAX_LOOP_NUM 1023
33
30int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 34int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
31int losetup_main(int argc UNUSED_PARAM, char **argv) 35int losetup_main(int argc UNUSED_PARAM, char **argv)
32{ 36{
@@ -59,7 +63,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
59 } 63 }
60 64
61 /* -d LOOPDEV */ 65 /* -d LOOPDEV */
62 if (opt == OPT_d) { 66 if (opt == OPT_d && argv[0]) {
63 if (del_loop(argv[0])) 67 if (del_loop(argv[0]))
64 bb_simple_perror_msg_and_die(argv[0]); 68 bb_simple_perror_msg_and_die(argv[0]);
65 return EXIT_SUCCESS; 69 return EXIT_SUCCESS;
@@ -68,15 +72,14 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
68 /* -a */ 72 /* -a */
69 if (opt == OPT_a) { 73 if (opt == OPT_a) {
70 int n; 74 int n;
71 for (n = 0; n < 10; n++) { 75 for (n = 0; n < MAX_LOOP_NUM; n++) {
72 char *s; 76 char *s;
73 77
74 sprintf(dev, LOOP_FORMAT, n); 78 sprintf(dev, LOOP_FORMAT, n);
75 s = query_loop(dev); 79 s = query_loop(dev);
76 if (s) { 80 if (s) {
77 printf("%s: %s\n", dev, s); 81 printf("%s: %s\n", dev, s);
78 if (ENABLE_FEATURE_CLEAN_UP) 82 free(s);
79 free(s);
80 } 83 }
81 } 84 }
82 return EXIT_SUCCESS; 85 return EXIT_SUCCESS;
@@ -88,11 +91,13 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
88 int n = 0; 91 int n = 0;
89 92
90 do { 93 do {
91 sprintf(dev, LOOP_FORMAT, n); 94 if (n > MAX_LOOP_NUM)
95 bb_error_msg_and_die("no free loop devices");
96 sprintf(dev, LOOP_FORMAT, n++);
92 s = query_loop(dev); 97 s = query_loop(dev);
93 if (s && ENABLE_FEATURE_CLEAN_UP) 98 free(s);
94 free(s);
95 } while (s); 99 } while (s);
100 /* now: dev is next free "/dev/loopN" */
96 if ((opt == OPT_f) && !argv[0]) { 101 if ((opt == OPT_f) && !argv[0]) {
97 puts(dev); 102 puts(dev);
98 return EXIT_SUCCESS; 103 return EXIT_SUCCESS;
@@ -104,18 +109,18 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
104 unsigned long long offset = 0; 109 unsigned long long offset = 0;
105 char *d = dev; 110 char *d = dev;
106 111
107 if (opt == OPT_o) 112 if (opt & OPT_o)
108 offset = xatoull(opt_o); 113 offset = xatoull(opt_o);
109 if (opt != OPT_f) 114 if (!(opt & OPT_f))
110 d = *(argv++); 115 d = *argv++;
111 116
112 if (argv[0]) { 117 if (argv[0]) {
113 if (set_loop(&d, argv[0], offset, (opt / OPT_r)) < 0) 118 if (set_loop(&d, argv[0], offset, (opt & OPT_r)) < 0)
114 bb_simple_perror_msg_and_die(argv[0]); 119 bb_simple_perror_msg_and_die(argv[0]);
115 return EXIT_SUCCESS; 120 return EXIT_SUCCESS;
116 } 121 }
117 } 122 }
118 123
119 bb_show_usage(); 124 bb_show_usage(); /* does not return */
120 return EXIT_FAILURE; 125 /*return EXIT_FAILURE;*/
121} 126}
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 1d741367e..e80b58f2e 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -295,8 +295,8 @@ struct globals {
295/* Prevent infinite loops in /sys symlinks */ 295/* Prevent infinite loops in /sys symlinks */
296#define MAX_SYSFS_DEPTH 3 296#define MAX_SYSFS_DEPTH 3
297 297
298/* We use additional 64+ bytes in make_device() */ 298/* We use additional bytes in make_device() */
299#define SCRATCH_SIZE 80 299#define SCRATCH_SIZE 128
300 300
301#if ENABLE_FEATURE_MDEV_CONF 301#if ENABLE_FEATURE_MDEV_CONF
302 302
@@ -541,7 +541,7 @@ static char *build_alias(char *alias, const char *device_name)
541 541
542/* mknod in /dev based on a path like "/sys/block/hda/hda1" 542/* mknod in /dev based on a path like "/sys/block/hda/hda1"
543 * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes 543 * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes
544 * after NUL, but we promise to not mangle (IOW: to restore if needed) 544 * after NUL, but we promise to not mangle (IOW: to restore NUL if needed)
545 * path string. 545 * path string.
546 * NB2: "mdev -s" may call us many times, do not leak memory/fds! 546 * NB2: "mdev -s" may call us many times, do not leak memory/fds!
547 * 547 *
@@ -551,6 +551,7 @@ static char *build_alias(char *alias, const char *device_name)
551static void make_device(char *device_name, char *path, int operation) 551static void make_device(char *device_name, char *path, int operation)
552{ 552{
553 int major, minor, type, len; 553 int major, minor, type, len;
554 char *path_end = path + strlen(path);
554 555
555 /* Try to read major/minor string. Note that the kernel puts \n after 556 /* Try to read major/minor string. Note that the kernel puts \n after
556 * the data, so we don't need to worry about null terminating the string 557 * the data, so we don't need to worry about null terminating the string
@@ -559,17 +560,15 @@ static void make_device(char *device_name, char *path, int operation)
559 */ 560 */
560 major = -1; 561 major = -1;
561 if (operation == OP_add) { 562 if (operation == OP_add) {
562 char *dev_maj_min = path + strlen(path); 563 strcpy(path_end, "/dev");
563 564 len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1);
564 strcpy(dev_maj_min, "/dev"); 565 *path_end = '\0';
565 len = open_read_close(path, dev_maj_min + 1, 64);
566 *dev_maj_min = '\0';
567 if (len < 1) { 566 if (len < 1) {
568 if (!ENABLE_FEATURE_MDEV_EXEC) 567 if (!ENABLE_FEATURE_MDEV_EXEC)
569 return; 568 return;
570 /* no "dev" file, but we can still run scripts 569 /* no "dev" file, but we can still run scripts
571 * based on device name */ 570 * based on device name */
572 } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { 571 } else if (sscanf(path_end + 1, "%u:%u", &major, &minor) == 2) {
573 dbg1("dev %u,%u", major, minor); 572 dbg1("dev %u,%u", major, minor);
574 } else { 573 } else {
575 major = -1; 574 major = -1;
@@ -577,9 +576,33 @@ static void make_device(char *device_name, char *path, int operation)
577 } 576 }
578 /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ 577 /* else: for delete, -1 still deletes the node, but < -1 suppresses that */
579 578
580 /* Determine device name, type, major and minor */ 579 /* Determine device name */
581 if (!device_name) 580 if (!device_name) {
582 device_name = (char*) bb_basename(path); 581 /*
582 * There was no $DEVNAME envvar (for example, mdev -s never has).
583 * But it is very useful: it contains the *path*, not only basename,
584 * Thankfully, uevent file has it.
585 * Example of .../sound/card0/controlC0/uevent file on Linux-3.7.7:
586 * MAJOR=116
587 * MINOR=7
588 * DEVNAME=snd/controlC0
589 */
590 strcpy(path_end, "/uevent");
591 len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1);
592 if (len < 0)
593 len = 0;
594 *path_end = '\0';
595 path_end[1 + len] = '\0';
596 device_name = strstr(path_end + 1, "\nDEVNAME=");
597 if (device_name) {
598 device_name += sizeof("\nDEVNAME=")-1;
599 strchrnul(device_name, '\n')[0] = '\0';
600 } else {
601 /* Fall back to just basename */
602 device_name = (char*) bb_basename(path);
603 }
604 }
605 /* Determine device type */
583 /* 606 /*
584 * http://kernel.org/doc/pending/hotplug.txt says that only 607 * http://kernel.org/doc/pending/hotplug.txt says that only
585 * "/sys/block/..." is for block devices. "/sys/bus" etc is not. 608 * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index 54867ec36..afad4ab8f 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -95,6 +95,20 @@ static int do_em_all(void)
95 if (applet_name[5] != 'n' 95 if (applet_name[5] != 'n'
96 || hasmntopt(m, MNTOPT_NOAUTO) == NULL 96 || hasmntopt(m, MNTOPT_NOAUTO) == NULL
97 ) { 97 ) {
98#if ENABLE_FEATURE_SWAPON_PRI
99 char *p;
100 g_flags = 0; /* each swap space might have different flags */
101 p = strstr(m->mnt_opts, "pri=");
102 if (p) {
103 /* Max allowed 32767 (==SWAP_FLAG_PRIO_MASK) */
104 int swap_prio = MIN(bb_strtoull(p + 4 , NULL, 10), SWAP_FLAG_PRIO_MASK);
105 /* We want to allow "NNNN,foo", thus errno == EINVAL is allowed too */
106 if (errno != ERANGE) {
107 g_flags = SWAP_FLAG_PREFER |
108 (swap_prio << SWAP_FLAG_PRIO_SHIFT);
109 }
110 }
111#endif
98 err += swap_enable_disable(m->mnt_fsname); 112 err += swap_enable_disable(m->mnt_fsname);
99 } 113 }
100 } 114 }
diff --git a/util-linux/volume_id/Config.src b/util-linux/volume_id/Config.src
new file mode 100644
index 000000000..ac208c9cc
--- /dev/null
+++ b/util-linux/volume_id/Config.src
@@ -0,0 +1,15 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6config VOLUMEID
7 bool #No description makes it a hidden option
8 default n
9
10menu "Filesystem/Volume identification"
11 depends on VOLUMEID
12
13INSERT
14
15endmenu
diff --git a/util-linux/volume_id/Kbuild.src b/util-linux/volume_id/Kbuild.src
index 759fdaae5..6b4fb7470 100644
--- a/util-linux/volume_id/Kbuild.src
+++ b/util-linux/volume_id/Kbuild.src
@@ -7,41 +7,3 @@
7lib-y:= 7lib-y:=
8 8
9INSERT 9INSERT
10
11lib-$(CONFIG_BLKID) += get_devname.o
12lib-$(CONFIG_FINDFS) += get_devname.o
13lib-$(CONFIG_FEATURE_MOUNT_LABEL) += get_devname.o
14
15lib-$(CONFIG_VOLUMEID) += volume_id.o util.o
16lib-$(CONFIG_FEATURE_VOLUMEID_BTRFS) += btrfs.o
17lib-$(CONFIG_FEATURE_VOLUMEID_EXT) += ext.o
18lib-$(CONFIG_FEATURE_VOLUMEID_FAT) += fat.o
19lib-$(CONFIG_FEATURE_VOLUMEID_HFS) += hfs.o
20### lib-$(CONFIG_FEATURE_VOLUMEID_HIGHPOINTRAID) += highpoint.o
21### lib-$(CONFIG_FEATURE_VOLUMEID_ISWRAID) += isw_raid.o
22### lib-$(CONFIG_FEATURE_VOLUMEID_LSIRAID) += lsi_raid.o
23### lib-$(CONFIG_FEATURE_VOLUMEID_VIARAID) += via_raid.o
24### lib-$(CONFIG_FEATURE_VOLUMEID_SILICONRAID) += silicon_raid.o
25### lib-$(CONFIG_FEATURE_VOLUMEID_NVIDIARAID) += nvidia_raid.o
26### lib-$(CONFIG_FEATURE_VOLUMEID_PROMISERAID) += promise_raid.o
27lib-$(CONFIG_FEATURE_VOLUMEID_ISO9660) += iso9660.o
28lib-$(CONFIG_FEATURE_VOLUMEID_JFS) += jfs.o
29lib-$(CONFIG_FEATURE_VOLUMEID_LINUXRAID) += linux_raid.o
30lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o
31### lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o
32### lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o
33### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o
34lib-$(CONFIG_FEATURE_VOLUMEID_NILFS) += nilfs.o
35lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
36lib-$(CONFIG_FEATURE_VOLUMEID_EXFAT) += exfat.o
37lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o
38lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o
39### lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o
40lib-$(CONFIG_FEATURE_VOLUMEID_XFS) += xfs.o
41lib-$(CONFIG_FEATURE_VOLUMEID_CRAMFS) += cramfs.o
42### lib-$(CONFIG_FEATURE_VOLUMEID_HPFS) += hpfs.o
43lib-$(CONFIG_FEATURE_VOLUMEID_ROMFS) += romfs.o
44lib-$(CONFIG_FEATURE_VOLUMEID_SYSV) += sysv.o
45### lib-$(CONFIG_FEATURE_VOLUMEID_MINIX) += minix.o
46lib-$(CONFIG_FEATURE_VOLUMEID_LUKS) += luks.o
47lib-$(CONFIG_FEATURE_VOLUMEID_OCFS2) += ocfs2.o
diff --git a/util-linux/volume_id/btrfs.c b/util-linux/volume_id/btrfs.c
index ee71d2e00..e4dddf26d 100644
--- a/util-linux/volume_id/btrfs.c
+++ b/util-linux/volume_id/btrfs.c
@@ -19,6 +19,17 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_BTRFS) += btrfs.o
23
24//config:
25//config:config FEATURE_VOLUMEID_BTRFS
26//config: bool "btrfs filesystem"
27//config: default y
28//config: depends on VOLUMEID
29//config: help
30//config: TODO
31//config:
32
22#include "volume_id_internal.h" 33#include "volume_id_internal.h"
23 34
24#define BTRFS_UUID_SIZE 16 35#define BTRFS_UUID_SIZE 16
diff --git a/util-linux/volume_id/cramfs.c b/util-linux/volume_id/cramfs.c
index 28e997043..aeb7f20ac 100644
--- a/util-linux/volume_id/cramfs.c
+++ b/util-linux/volume_id/cramfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_CRAMFS) += cramfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_CRAMFS
25//config: bool "cramfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct cramfs_super { 34struct cramfs_super {
diff --git a/util-linux/volume_id/exfat.c b/util-linux/volume_id/exfat.c
index a38a8916d..c3aa36804 100644
--- a/util-linux/volume_id/exfat.c
+++ b/util-linux/volume_id/exfat.c
@@ -18,6 +18,19 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_EXFAT) += exfat.o
22
23//config:
24//config:config FEATURE_VOLUMEID_EXFAT
25//config: bool "exFAT filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: exFAT (extended FAT) is a proprietary file system designed especially
30//config: for flash drives. It has many features from NTFS, but with less
31//config: overhead. exFAT is used on most SDXC cards for consumer electronics.
32//config:
33
21#include "volume_id_internal.h" 34#include "volume_id_internal.h"
22 35
23#define EXFAT_SB_OFFSET 0 36#define EXFAT_SB_OFFSET 0
diff --git a/util-linux/volume_id/ext.c b/util-linux/volume_id/ext.c
index 97451067f..df39d9342 100644
--- a/util-linux/volume_id/ext.c
+++ b/util-linux/volume_id/ext.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_EXT) += ext.o
22
23//config:
24//config:config FEATURE_VOLUMEID_EXT
25//config: bool "Ext filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22#include "bb_e2fs_defs.h" 33#include "bb_e2fs_defs.h"
23 34
diff --git a/util-linux/volume_id/f2fs.c b/util-linux/volume_id/f2fs.c
new file mode 100644
index 000000000..bf0b66278
--- /dev/null
+++ b/util-linux/volume_id/f2fs.c
@@ -0,0 +1,95 @@
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2012 S-G Bergh <sgb@systemasis.org>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8
9//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_F2FS) += f2fs.o
10
11//config:
12//config:config FEATURE_VOLUMEID_F2FS
13//config: bool "f2fs filesystem"
14//config: default y
15//config: depends on VOLUMEID
16//config: help
17//config: F2FS (aka Flash-Friendly File System) is a log-structured file system,
18//config: which is adapted to newer forms of storage. F2FS also remedies some
19//config: known issues of the older log structured file systems, such as high
20//config: cleaning overhead.
21//config:
22
23#include "volume_id_internal.h"
24
25#define F2FS_MAGIC 0xF2F52010 // F2FS Magic Number
26#define F2FS_UUID_SIZE 16
27#define F2FS_LABEL_SIZE 512
28#define F2FS_LABEL_BYTES 1024
29#define F2FS_SB1_OFFSET 0x400 // offset for 1:st super block
30/*
31#define F2FS_SB2_OFFSET 0x1400 // offset for 2:nd super block
32*/
33
34struct f2fs_super_block { // According to version 1.1
35/* 0x00 */ uint32_t magic; // Magic Number
36/* 0x04 */ uint16_t major_ver; // Major Version
37/* 0x06 */ uint16_t minor_ver; // Minor Version
38/* 0x08 */ uint32_t log_sectorsize; // log2 sector size in bytes
39/* 0x0C */ uint32_t log_sectors_per_block; // log2 # of sectors per block
40/* 0x10 */ uint32_t log_blocksize; // log2 block size in bytes
41/* 0x14 */ uint32_t log_blocks_per_seg; // log2 # of blocks per segment
42/* 0x18 */ uint32_t segs_per_sec; // # of segments per section
43/* 0x1C */ uint32_t secs_per_zone; // # of sections per zone
44/* 0x20 */ uint32_t checksum_offset; // checksum offset inside super block
45/* 0x24 */ uint64_t block_count; // total # of user blocks
46/* 0x2C */ uint32_t section_count; // total # of sections
47/* 0x30 */ uint32_t segment_count; // total # of segments
48/* 0x34 */ uint32_t segment_count_ckpt; // # of segments for checkpoint
49/* 0x38 */ uint32_t segment_count_sit; // # of segments for SIT
50/* 0x3C */ uint32_t segment_count_nat; // # of segments for NAT
51/* 0x40 */ uint32_t segment_count_ssa; // # of segments for SSA
52/* 0x44 */ uint32_t segment_count_main; // # of segments for main area
53/* 0x48 */ uint32_t segment0_blkaddr; // start block address of segment 0
54/* 0x4C */ uint32_t cp_blkaddr; // start block address of checkpoint
55/* 0x50 */ uint32_t sit_blkaddr; // start block address of SIT
56/* 0x54 */ uint32_t nat_blkaddr; // start block address of NAT
57/* 0x58 */ uint32_t ssa_blkaddr; // start block address of SSA
58/* 0x5C */ uint32_t main_blkaddr; // start block address of main area
59/* 0x60 */ uint32_t root_ino; // root inode number
60/* 0x64 */ uint32_t node_ino; // node inode number
61/* 0x68 */ uint32_t meta_ino; // meta inode number
62/* 0x6C */ uint8_t uuid[F2FS_UUID_SIZE]; // 128-bit uuid for volume
63/* 0x7C */ uint16_t volume_name[F2FS_LABEL_SIZE]; // volume name
64// /* 0x47C */ uint32_t extension_count; // # of extensions below
65// /* 0x480 */ uint8_t extension_list[64][8]; // extension array
66} PACKED;
67
68
69int FAST_FUNC volume_id_probe_f2fs(struct volume_id *id /*,uint64_t off*/)
70{
71 struct f2fs_super_block *sb;
72
73 // Go for primary super block (ignore second sb)
74 dbg("f2fs: probing at offset 0x%x", F2FS_SB1_OFFSET);
75 sb = volume_id_get_buffer(id, F2FS_SB1_OFFSET, sizeof(*sb));
76
77 if (!sb)
78 return -1;
79
80 if (sb->magic != cpu_to_le32(F2FS_MAGIC))
81 return -1;
82
83 IF_FEATURE_BLKID_TYPE(id->type = "f2fs");
84
85 // For version 1.0 we don't know sb structure and can't set label/uuid
86 if (sb->major_ver == cpu_to_le16(1) && sb->minor_ver == cpu_to_le16(0))
87 return 0;
88
89 volume_id_set_label_unicode16(id, (uint8_t *)sb->volume_name,
90 LE, MIN(F2FS_LABEL_BYTES, VOLUME_ID_LABEL_SIZE));
91
92 volume_id_set_uuid(id, sb->uuid, UUID_DCE);
93
94 return 0;
95}
diff --git a/util-linux/volume_id/fat.c b/util-linux/volume_id/fat.c
index 904fbb201..476d500a6 100644
--- a/util-linux/volume_id/fat.c
+++ b/util-linux/volume_id/fat.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_FAT) += fat.o
22
23//config:
24//config:config FEATURE_VOLUMEID_FAT
25//config: bool "fat filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23/* linux/msdos_fs.h says: */ 34/* linux/msdos_fs.h says: */
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
index 665cb9b6e..0c6bdfddf 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -7,6 +7,11 @@
7 * 7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */ 9 */
10
11//kbuild:lib-$(CONFIG_BLKID) += get_devname.o
12//kbuild:lib-$(CONFIG_FINDFS) += get_devname.o
13//kbuild:lib-$(CONFIG_FEATURE_MOUNT_LABEL) += get_devname.o
14
10#include <sys/mount.h> /* BLKGETSIZE64 */ 15#include <sys/mount.h> /* BLKGETSIZE64 */
11#if !defined(BLKGETSIZE64) 16#if !defined(BLKGETSIZE64)
12# define BLKGETSIZE64 _IOR(0x12,114,size_t) 17# define BLKGETSIZE64 _IOR(0x12,114,size_t)
diff --git a/util-linux/volume_id/hfs.c b/util-linux/volume_id/hfs.c
index 3d9704d12..8d34aaf68 100644
--- a/util-linux/volume_id/hfs.c
+++ b/util-linux/volume_id/hfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_HFS) += hfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_HFS
25//config: bool "hfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct hfs_finder_info{ 34struct hfs_finder_info{
diff --git a/util-linux/volume_id/iso9660.c b/util-linux/volume_id/iso9660.c
index 1d7693a9c..3848de453 100644
--- a/util-linux/volume_id/iso9660.c
+++ b/util-linux/volume_id/iso9660.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_ISO9660) += iso9660.o
22
23//config:
24//config:config FEATURE_VOLUMEID_ISO9660
25//config: bool "iso9660 filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23#define ISO_SUPERBLOCK_OFFSET 0x8000 34#define ISO_SUPERBLOCK_OFFSET 0x8000
diff --git a/util-linux/volume_id/jfs.c b/util-linux/volume_id/jfs.c
index 5333af2c3..a6eaff45b 100644
--- a/util-linux/volume_id/jfs.c
+++ b/util-linux/volume_id/jfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_JFS) += jfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_JFS
25//config: bool "jfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct jfs_super_block { 34struct jfs_super_block {
diff --git a/util-linux/volume_id/linux_raid.c b/util-linux/volume_id/linux_raid.c
index 209eaabe9..f20823a6e 100644
--- a/util-linux/volume_id/linux_raid.c
+++ b/util-linux/volume_id/linux_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_LINUXRAID) += linux_raid.o
22
23//config:
24//config:config FEATURE_VOLUMEID_LINUXRAID
25//config: bool "linuxraid"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct mdp_super_block { 34struct mdp_super_block {
diff --git a/util-linux/volume_id/linux_swap.c b/util-linux/volume_id/linux_swap.c
index 1ee534ab0..39470d48c 100644
--- a/util-linux/volume_id/linux_swap.c
+++ b/util-linux/volume_id/linux_swap.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o
22
23//config:
24//config:config FEATURE_VOLUMEID_LINUXSWAP
25//config: bool "linux swap filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct swap_header_v1_2 { 34struct swap_header_v1_2 {
diff --git a/util-linux/volume_id/luks.c b/util-linux/volume_id/luks.c
index f9b376672..42bf87659 100644
--- a/util-linux/volume_id/luks.c
+++ b/util-linux/volume_id/luks.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_LUKS) += luks.o
22
23//config:
24//config:config FEATURE_VOLUMEID_LUKS
25//config: bool "luks filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23#define LUKS_MAGIC_L 6 34#define LUKS_MAGIC_L 6
diff --git a/util-linux/volume_id/nilfs.c b/util-linux/volume_id/nilfs.c
index b88a9e435..f3a9ef58d 100644
--- a/util-linux/volume_id/nilfs.c
+++ b/util-linux/volume_id/nilfs.c
@@ -19,6 +19,26 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_NILFS) += nilfs.o
23
24//config:
25//config:config FEATURE_VOLUMEID_NILFS
26//config: bool "nilfs filesystem"
27//config: default y
28//config: depends on VOLUMEID
29//config: help
30//config: NILFS is a New Implementation of a Log-Structured File System (LFS)
31//config: that supports continuous snapshots. This provides features like
32//config: versioning of the entire filesystem, restoration of files that
33//config: were deleted a few minutes ago. NILFS keeps consistency like
34//config: conventional LFS, so it provides quick recovery after system crashes.
35//config:
36//config: The possible use of NILFS includes versioning, tamper detection,
37//config: SOX compliance logging, and so forth. It can serve as an alternative
38//config: filesystem for Linux desktop environment, or as a basis of advanced
39//config: storage appliances.
40//config:
41
22#include "volume_id_internal.h" 42#include "volume_id_internal.h"
23 43
24#define NILFS_UUID_SIZE 16 44#define NILFS_UUID_SIZE 16
diff --git a/util-linux/volume_id/ntfs.c b/util-linux/volume_id/ntfs.c
index 7b2612f01..46f687a56 100644
--- a/util-linux/volume_id/ntfs.c
+++ b/util-linux/volume_id/ntfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_NTFS
25//config: bool "ntfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct ntfs_super_block { 34struct ntfs_super_block {
@@ -150,7 +161,7 @@ int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/)
150 161
151 attr = (struct file_attribute*) &buf[attr_off]; 162 attr = (struct file_attribute*) &buf[attr_off];
152 attr_type = le32_to_cpu(attr->type); 163 attr_type = le32_to_cpu(attr->type);
153 attr_len = le16_to_cpu(attr->len); 164 attr_len = le32_to_cpu(attr->len);
154 val_off = le16_to_cpu(attr->value_offset); 165 val_off = le16_to_cpu(attr->value_offset);
155 val_len = le32_to_cpu(attr->value_len); 166 val_len = le32_to_cpu(attr->value_len);
156 attr_off += attr_len; 167 attr_off += attr_len;
diff --git a/util-linux/volume_id/ocfs2.c b/util-linux/volume_id/ocfs2.c
index fcdb15192..415e0bf61 100644
--- a/util-linux/volume_id/ocfs2.c
+++ b/util-linux/volume_id/ocfs2.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_OCFS2) += ocfs2.o
22
23//config:
24//config:config FEATURE_VOLUMEID_OCFS2
25//config: bool "ocfs2 filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23/* All these values are taken from ocfs2-tools's ocfs2_fs.h */ 34/* All these values are taken from ocfs2-tools's ocfs2_fs.h */
diff --git a/util-linux/volume_id/reiserfs.c b/util-linux/volume_id/reiserfs.c
index 67b4a1877..24979fb1c 100644
--- a/util-linux/volume_id/reiserfs.c
+++ b/util-linux/volume_id/reiserfs.c
@@ -19,6 +19,17 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o
23
24//config:
25//config:config FEATURE_VOLUMEID_REISERFS
26//config: bool "Reiser filesystem"
27//config: default y
28//config: depends on VOLUMEID
29//config: help
30//config: TODO
31//config:
32
22#include "volume_id_internal.h" 33#include "volume_id_internal.h"
23 34
24struct reiserfs_super_block { 35struct reiserfs_super_block {
diff --git a/util-linux/volume_id/romfs.c b/util-linux/volume_id/romfs.c
index 15653bedf..4754fdb37 100644
--- a/util-linux/volume_id/romfs.c
+++ b/util-linux/volume_id/romfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_ROMFS) += romfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_ROMFS
25//config: bool "romfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct romfs_super { 34struct romfs_super {
diff --git a/util-linux/volume_id/squashfs.c b/util-linux/volume_id/squashfs.c
index c5b4f9ced..079b6cc31 100644
--- a/util-linux/volume_id/squashfs.c
+++ b/util-linux/volume_id/squashfs.c
@@ -8,6 +8,18 @@
8 8
9//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_SQUASHFS) += squashfs.o 9//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_SQUASHFS) += squashfs.o
10 10
11//config:
12//config:config FEATURE_VOLUMEID_SQUASHFS
13//config: bool "SquashFS filesystem"
14//config: default y
15//config: depends on VOLUMEID && FEATURE_BLKID_TYPE
16//config: help
17//config: Squashfs is a compressed read-only filesystem for Linux. Squashfs is
18//config: intended for general read-only filesystem use and in constrained block
19//config: device/memory systems (e.g. embedded systems) where low overhead is
20//config: needed.
21//config:
22
11#include "volume_id_internal.h" 23#include "volume_id_internal.h"
12 24
13struct squashfs_superblock { 25struct squashfs_superblock {
diff --git a/util-linux/volume_id/sysv.c b/util-linux/volume_id/sysv.c
index 6eb96464d..7b4b5360b 100644
--- a/util-linux/volume_id/sysv.c
+++ b/util-linux/volume_id/sysv.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_SYSV) += sysv.o
22
23//config:
24//config:config FEATURE_VOLUMEID_SYSV
25//config: bool "sysv filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23#define SYSV_NICINOD 100 34#define SYSV_NICINOD 100
diff --git a/util-linux/volume_id/udf.c b/util-linux/volume_id/udf.c
index d3747fb8e..921454503 100644
--- a/util-linux/volume_id/udf.c
+++ b/util-linux/volume_id/udf.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o
22
23//config:
24//config:config FEATURE_VOLUMEID_UDF
25//config: bool "udf filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct volume_descriptor { 34struct volume_descriptor {
diff --git a/util-linux/volume_id/unused_highpoint.c b/util-linux/volume_id/unused_highpoint.c
index 17b7b3291..7231a1db2 100644
--- a/util-linux/volume_id/unused_highpoint.c
+++ b/util-linux/volume_id/unused_highpoint.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_HIGHPOINTRAID) += highpoint.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_HIGHPOINTRAID
25//config:### bool "highpoint raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct hpt37x_meta { 34struct hpt37x_meta {
diff --git a/util-linux/volume_id/unused_hpfs.c b/util-linux/volume_id/unused_hpfs.c
index 442952464..a87c89fb3 100644
--- a/util-linux/volume_id/unused_hpfs.c
+++ b/util-linux/volume_id/unused_hpfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_HPFS) += hpfs.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_HPFS
25//config:### bool "hpfs filesystem"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct hpfs_super { 34struct hpfs_super {
diff --git a/util-linux/volume_id/unused_isw_raid.c b/util-linux/volume_id/unused_isw_raid.c
index 7ab47b3a1..851bd2f8f 100644
--- a/util-linux/volume_id/unused_isw_raid.c
+++ b/util-linux/volume_id/unused_isw_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_ISWRAID) += isw_raid.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_ISWRAID
25//config:### bool "intel raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct isw_meta { 34struct isw_meta {
diff --git a/util-linux/volume_id/unused_lsi_raid.c b/util-linux/volume_id/unused_lsi_raid.c
index e6cc8edd3..52d68deab 100644
--- a/util-linux/volume_id/unused_lsi_raid.c
+++ b/util-linux/volume_id/unused_lsi_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_LSIRAID) += lsi_raid.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_LSIRAID
25//config:### bool "lsi raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct lsi_meta { 34struct lsi_meta {
diff --git a/util-linux/volume_id/unused_lvm.c b/util-linux/volume_id/unused_lvm.c
index 2206498bf..08fa05243 100644
--- a/util-linux/volume_id/unused_lvm.c
+++ b/util-linux/volume_id/unused_lvm.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_LVM
25//config:### bool "lvm"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct lvm1_super_block { 34struct lvm1_super_block {
diff --git a/util-linux/volume_id/unused_mac.c b/util-linux/volume_id/unused_mac.c
index e8deb9720..a1a53d1fb 100644
--- a/util-linux/volume_id/unused_mac.c
+++ b/util-linux/volume_id/unused_mac.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_MAC
25//config:### bool "mac filesystem"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct mac_driver_desc { 34struct mac_driver_desc {
diff --git a/util-linux/volume_id/unused_minix.c b/util-linux/volume_id/unused_minix.c
index a3e1077b0..50afd5c3e 100644
--- a/util-linux/volume_id/unused_minix.c
+++ b/util-linux/volume_id/unused_minix.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_MINIX) += minix.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_MINIX
25//config:### bool "minix filesystem"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct minix_super_block { 34struct minix_super_block {
diff --git a/util-linux/volume_id/unused_msdos.c b/util-linux/volume_id/unused_msdos.c
index 2e8cb196a..d2fc66caa 100644
--- a/util-linux/volume_id/unused_msdos.c
+++ b/util-linux/volume_id/unused_msdos.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_MSDOS
25//config:### bool "msdos filesystem"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct msdos_partition_entry { 34struct msdos_partition_entry {
diff --git a/util-linux/volume_id/unused_nvidia_raid.c b/util-linux/volume_id/unused_nvidia_raid.c
index 9e8472921..d99a108f3 100644
--- a/util-linux/volume_id/unused_nvidia_raid.c
+++ b/util-linux/volume_id/unused_nvidia_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_NVIDIARAID) += nvidia_raid.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_NVIDIARAID
25//config:### bool "nvidia raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct nvidia_meta { 34struct nvidia_meta {
diff --git a/util-linux/volume_id/unused_promise_raid.c b/util-linux/volume_id/unused_promise_raid.c
index 0b0d0063c..cebebe35f 100644
--- a/util-linux/volume_id/unused_promise_raid.c
+++ b/util-linux/volume_id/unused_promise_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_PROMISERAID) += promise_raid.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_PROMISERAID
25//config:### bool "promise raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct promise_meta { 34struct promise_meta {
diff --git a/util-linux/volume_id/unused_silicon_raid.c b/util-linux/volume_id/unused_silicon_raid.c
index 878b88197..40c8faa9e 100644
--- a/util-linux/volume_id/unused_silicon_raid.c
+++ b/util-linux/volume_id/unused_silicon_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_SILICONRAID) += silicon_raid.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_SILICONRAID
25//config:### bool "silicon raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct silicon_meta { 34struct silicon_meta {
diff --git a/util-linux/volume_id/unused_ufs.c b/util-linux/volume_id/unused_ufs.c
index 9f925d983..d33c10fc4 100644
--- a/util-linux/volume_id/unused_ufs.c
+++ b/util-linux/volume_id/unused_ufs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_UFS
25//config:### bool "ufs filesystem"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct ufs_super_block { 34struct ufs_super_block {
diff --git a/util-linux/volume_id/unused_via_raid.c b/util-linux/volume_id/unused_via_raid.c
index a11eec13a..258f93a4f 100644
--- a/util-linux/volume_id/unused_via_raid.c
+++ b/util-linux/volume_id/unused_via_raid.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:### lib-$(CONFIG_FEATURE_VOLUMEID_VIARAID) += via_raid.o
22
23//config:
24//config:### config FEATURE_VOLUMEID_VIARAID
25//config:### bool "via raid"
26//config:### default y
27//config:### depends on VOLUMEID
28//config:### help
29//config:### TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct via_meta { 34struct via_meta {
diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c
index f0fc84c05..5c459a0e2 100644
--- a/util-linux/volume_id/volume_id.c
+++ b/util-linux/volume_id/volume_id.c
@@ -18,6 +18,8 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_VOLUMEID) += volume_id.o util.o
22
21#include "volume_id_internal.h" 23#include "volume_id_internal.h"
22 24
23 25
@@ -136,6 +138,9 @@ static const probe_fptr fs2[] = {
136#if ENABLE_FEATURE_VOLUMEID_UFS 138#if ENABLE_FEATURE_VOLUMEID_UFS
137 volume_id_probe_ufs, 139 volume_id_probe_ufs,
138#endif 140#endif
141#if ENABLE_FEATURE_VOLUMEID_F2FS
142 volume_id_probe_f2fs,
143#endif
139#if ENABLE_FEATURE_VOLUMEID_NILFS 144#if ENABLE_FEATURE_VOLUMEID_NILFS
140 volume_id_probe_nilfs, 145 volume_id_probe_nilfs,
141#endif 146#endif
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h
index 3f02bd50d..6e2dbd7bb 100644
--- a/util-linux/volume_id/volume_id_internal.h
+++ b/util-linux/volume_id/volume_id_internal.h
@@ -96,44 +96,24 @@ void FAST_FUNC free_volume_id(struct volume_id *id);
96/* size of seek buffer, FAT cluster is 32k max */ 96/* size of seek buffer, FAT cluster is 32k max */
97#define SEEK_BUFFER_SIZE 0x10000 97#define SEEK_BUFFER_SIZE 0x10000
98 98
99#define bswap16(x) (uint16_t) ( \
100 (((uint16_t)(x) & 0x00ffu) << 8) | \
101 (((uint16_t)(x) & 0xff00u) >> 8))
102
103#define bswap32(x) (uint32_t) ( \
104 (((uint32_t)(x) & 0xff000000u) >> 24) | \
105 (((uint32_t)(x) & 0x00ff0000u) >> 8) | \
106 (((uint32_t)(x) & 0x0000ff00u) << 8) | \
107 (((uint32_t)(x) & 0x000000ffu) << 24))
108
109#define bswap64(x) (uint64_t) ( \
110 (((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \
111 (((uint64_t)(x) & 0x00ff000000000000ull) >> 40) | \
112 (((uint64_t)(x) & 0x0000ff0000000000ull) >> 24) | \
113 (((uint64_t)(x) & 0x000000ff00000000ull) >> 8) | \
114 (((uint64_t)(x) & 0x00000000ff000000ull) << 8) | \
115 (((uint64_t)(x) & 0x0000000000ff0000ull) << 24) | \
116 (((uint64_t)(x) & 0x000000000000ff00ull) << 40) | \
117 (((uint64_t)(x) & 0x00000000000000ffull) << 56))
118
119#if BB_LITTLE_ENDIAN 99#if BB_LITTLE_ENDIAN
120#define le16_to_cpu(x) (x) 100# define le16_to_cpu(x) (uint16_t)(x)
121#define le32_to_cpu(x) (x) 101# define le32_to_cpu(x) (uint32_t)(x)
122#define le64_to_cpu(x) (x) 102# define le64_to_cpu(x) (uint64_t)(x)
123#define be16_to_cpu(x) bswap16(x) 103# define be16_to_cpu(x) (uint16_t)(bswap_16(x))
124#define be32_to_cpu(x) bswap32(x) 104# define be32_to_cpu(x) (uint32_t)(bswap_32(x))
125#define cpu_to_le16(x) (x) 105# define cpu_to_le16(x) (uint16_t)(x)
126#define cpu_to_le32(x) (x) 106# define cpu_to_le32(x) (uint32_t)(x)
127#define cpu_to_be32(x) bswap32(x) 107# define cpu_to_be32(x) (uint32_t)(bswap_32(x))
128#else 108#else
129#define le16_to_cpu(x) bswap16(x) 109# define le16_to_cpu(x) (uint16_t)(bswap_16(x))
130#define le32_to_cpu(x) bswap32(x) 110# define le32_to_cpu(x) (uint32_t)(bswap_32(x))
131#define le64_to_cpu(x) bswap64(x) 111# define le64_to_cpu(x) (uint64_t)(bb_bswap_64(x))
132#define be16_to_cpu(x) (x) 112# define be16_to_cpu(x) (uint16_t)(x)
133#define be32_to_cpu(x) (x) 113# define be32_to_cpu(x) (uint32_t)(x)
134#define cpu_to_le16(x) bswap16(x) 114# define cpu_to_le16(x) (uint16_t)(bswap_16(x))
135#define cpu_to_le32(x) bswap32(x) 115# define cpu_to_le32(x) (uint32_t)(bswap_32(x))
136#define cpu_to_be32(x) (x) 116# define cpu_to_be32(x) (uint32_t)(x)
137#endif 117#endif
138 118
139/* volume_id_set_uuid(id,buf,fmt) assumes size of uuid buf 119/* volume_id_set_uuid(id,buf,fmt) assumes size of uuid buf
@@ -215,6 +195,8 @@ int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/);
215 195
216//int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id /*,uint64_t off*/); 196//int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id /*,uint64_t off*/);
217 197
198int FAST_FUNC volume_id_probe_f2fs(struct volume_id *id /*,uint64_t off*/);
199
218int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/); 200int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/);
219 201
220int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/); 202int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/);
diff --git a/util-linux/volume_id/xfs.c b/util-linux/volume_id/xfs.c
index 84746020e..5eefc201d 100644
--- a/util-linux/volume_id/xfs.c
+++ b/util-linux/volume_id/xfs.c
@@ -18,6 +18,17 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_XFS) += xfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_XFS
25//config: bool "xfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
21#include "volume_id_internal.h" 32#include "volume_id_internal.h"
22 33
23struct xfs_super_block { 34struct xfs_super_block {