From bluca at debian.org Wed Nov 2 12:05:33 2022 From: bluca at debian.org (Luca Boccassi) Date: Wed, 2 Nov 2022 12:05:33 +0000 Subject: [PATCH v2] udhcpc: add support for sending DHCPINFORM packets In-Reply-To: <530912df10d28daa536b94d7b6efa814c4e41200.camel@debian.org> References: <20220830213443.1922500-1-luca.boccassi@gmail.com> <20220830214151.1923924-1-bluca@debian.org> <530912df10d28daa536b94d7b6efa814c4e41200.camel@debian.org> Message-ID: On Thu, 22 Sept 2022 at 13:31, Luca Boccassi wrote: > > On Tue, 2022-08-30 at 22:41 +0100, bluca at debian.org wrote: > > From: Luca Boccassi > > > > It is useful for applications to be able to query DHCP options > > without renewing IP address. Instead of a full DHCP handshake, > > using -I will cause a single DHCPINFORM packet to be sent, and > > the server response (including DHCP options received) to be > > printed and terminate. No configuration will be changed. > > > > This is useful for clients that want to query additional information > > from a server, that might not be normally processed, like custom > > server options. Also useful for checking specific options via -O. > > > > As per RFC 2131, allow targeting the already-known DHCP server via > > unicast instead of broadcast, via new -e option. > > > > Tested by running isc-dhcp-server with the following configuration: > > > > option domain-name "example.org"; > > option domain-name-servers 1.1.1.1, 8.8.8.8; > > subnet 192.168.11.0 netmask 255.255.255.0 { > > range 192.168.11.1 192.168.11.100; > > authoritative; > > option default-url "default.url"; > > } > > > > $ busybox udhcpc -I -i host0 -O 114 -r 192.168.11.1 > > udhcpc: started, v1.36.0.git > > udhcpc: broadcasting inform for 192.168.11.1, server 0.0.0.0 > > udhcpc: lease of 0.0.0.0 obtained from 0.0.0.0, lease time 3600 (default) > > udhcpc: option: opt53=0x05 > > udhcpc: option: serverid=192.168.11.101 > > udhcpc: option: subnet=255.255.255.0 > > udhcpc: option: dns=1.1.1.1 8.8.8.8 > > udhcpc: option: domain=example.org > > udhcpc: option: opt114=0x64656661756c742e75726c > > > > $ busybox udhcpc -e 192.168.11.101 -I -i host0 -O 114 -r 192.168.11.1 > > udhcpc: started, v1.36.0.git > > udhcpc: unicasting inform for 192.168.11.1, server 192.168.11.101 > > udhcpc: lease of 0.0.0.0 obtained from 192.168.11.101, lease time 3600 (default) > > udhcpc: option: opt53=0x05 > > udhcpc: option: serverid=192.168.11.101 > > udhcpc: option: subnet=255.255.255.0 > > udhcpc: option: dns=1.1.1.1 8.8.8.8 > > udhcpc: option: domain=example.org > > udhcpc: option: opt114=0x64656661756c742e75726c > > > > Co-authored-by: Sinan Kaya > > Signed-off-by: Luca Boccassi > > --- > > v2: updated commit message and comments > > applied all review comments > > print received DHCP options and exit > > > > networking/udhcp/dhcpc.c | 116 ++++++++++++++++++++++++++++++++++----- > > 1 file changed, 103 insertions(+), 13 deletions(-) > > Hello Denys, > > Any chance for a second review? Thank you! Hello, One more ping for a re-review. Thank you! Kind regards, Luca Boccassi From guille.rodriguez at gmail.com Thu Nov 3 14:05:24 2022 From: guille.rodriguez at gmail.com (=?UTF-8?q?Guillermo=20Rodr=C3=ADguez?=) Date: Thu, 3 Nov 2022 15:05:24 +0100 Subject: [PATCH] beep: Don't start beep if length is 0 Message-ID: <20221103140524.96026-1-guille.rodriguez@gmail.com> Calling beep -l 0 is useful to stop a beep (for example if it was left on by a process that died). In this case, do not try to start the beep, as this results in audible clics for some devices. Signed-off-by: Guillermo Rodriguez diff --git a/miscutils/beep.c b/miscutils/beep.c index 7c60aed08..01977a564 100644 --- a/miscutils/beep.c +++ b/miscutils/beep.c @@ -113,8 +113,10 @@ int beep_main(int argc, char **argv) } while (rep) { //bb_error_msg("rep[%d] freq=%d, length=%d, delay=%d", rep, freq, length, delay); - xioctl(speaker, KIOCSOUND, (void*)(uintptr_t)tickrate_div_freq); - msleep(length); + if (length) { + xioctl(speaker, KIOCSOUND, (void*)(uintptr_t)tickrate_div_freq); + msleep(length); + } ioctl(speaker, KIOCSOUND, (void*)0); if (--rep) msleep(delay); -- 2.32.0 (Apple Git-132) From tdtemccnp at gmail.com Thu Nov 3 15:12:05 2022 From: tdtemccnp at gmail.com (Turritopsis Dohrnii Teo En Ming) Date: Thu, 3 Nov 2022 23:12:05 +0800 Subject: SSH Weak Key Exchange Algorithms Enabled on UniFi Wireless Access Points In-Reply-To: References: <5uaa8ecqc4tecqq75j4b8uk4.1666876441348@lysator.liu.se> Message-ID: On Fri, 28 Oct 2022 at 13:49, Alexander Dahl wrote: > Hei hei, > > Am Thu, Oct 27, 2022 at 09:17:40PM +0800 schrieb Turritopsis Dohrnii Teo > En Ming: > > On Thu, 27 Oct 2022 at 21:14, Markus Gothe > wrote: > > > > > Hi, you are unfortunately reaching out to the wrong people. BusyBox > does > > > NOT provide a ssh server. > > > > > > Please contact the manufacturer of the product. > > > > > > //Markus > > > > > > Sent via BlackBerry Hub+ Inbox for Android > > > > > > > > > > Noted with thanks. I will contact Ubiquiti. > > You can certainly do that, but it is usually not that hard to find out > which ssh software the remote server is running. You could try > > ssh -v root at host > > and would get something like this: > > debug1: Local version string SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1 > debug1: Remote protocol version 2.0, remote software version dropbear > debug1: no match: dropbear > > Or this: > > debug1: Local version string SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u2 > debug1: Remote protocol version 2.0, remote software version > OpenSSH_8.4p1 Debian-5+deb11u1 > debug1: match: OpenSSH_8.4p1 Debian-5+deb11u1 pat OpenSSH* compat > 0x04000000 > > Another possibility would be to use nmap with the option -sV and you > would get something like this: > > PORT STATE SERVICE VERSION > 22/tcp open ssh Dropbear sshd (protocol 2.0) > MAC Address: 74:AC:B9:66:04:74 (Ubiquiti Networks) > Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel > > Or this: > > PORT STATE SERVICE VERSION > 22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0) > MAC Address: 00:0C:29:4E:BE:9E (VMware) > Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel > > Note: one of the devices I tried here is a Unifi AP AC-Lite. ;-) > > Greets > Alex > Hi Alex, My client has decided to disable/turn off the SSH server on all the UniFi wireless access points. So for the moment we will not be investigating what the SSH server is on the UniFi wireless access points. Thank you for your reply! > > > > > > > *From:* tdtemccnp at gmail.com > > > *Sent:* 27 October 2022 15:02 > > > *To:* busybox at busybox.net > > > *Cc:* ceo at teo-en-ming-corp.com > > > *Subject:* SSH Weak Key Exchange Algorithms Enabled on UniFi Wireless > > > Access Points > > > > > > Subject: SSH Weak Key Exchange Algorithms Enabled on UniFi Wireless > Access > > > Points > > > > > > Good day from Singapore, > > > > > > I have discovered that UniFi Wireless Access Points are powered by > Busybox. > > > > > > Vulnerability scanning of my client's corporate network shows SSH weak > key > > > exchange algorithms enabled on UniFi wireless access points. > > > > > > Article: SSH WEAK KEY EXCHANGE ALGORITHMS ENABLED > > > Link: > > > > https://www.virtuesecurity.com/kb/ssh-weak-key-exchange-algorithms-enabled/ > > > > > > According to the above article, we must make changes to > > > /etc/sshd/sshd_config, especially the KexAlgorithms directive. > > > > > > However, when I putty/SSH into Busybox, I cannot find the file > > > /etc/sshd/sshd_config. What SSH server is running inside Busybox? > > > > > > How can I make changes to the SSH server within Busybox so that I can > > > disable the SSH weak key exchange algorithms? > > > > > > Please advise. > > > > > > Thank you. > > > > > > By the way, I also noticed that Hikvision Face Recognition Terminal > Door > > > Access Systems are also powered by Busybox. > > > > > > I am doing this for an investment company at Keppel Road, Singapore. > > > > > > Regards, > > > > > > Mr. Turritopsis Dohrnii Teo En Ming > > > Targeted Individual in Singapore > > > Blogs: > > > https://tdtemcerts.blogspot.com > > > https://tdtemcerts.wordpress.com > > > > > > > > > > > > > > > _______________________________________________ > > busybox mailing list > > busybox at busybox.net > > http://lists.busybox.net/mailman/listinfo/busybox > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mjt at tls.msk.ru Fri Nov 4 16:49:41 2022 From: mjt at tls.msk.ru (Michael Tokarev) Date: Fri, 4 Nov 2022 19:49:41 +0300 Subject: [PATCH] use libresolv on non-linux too Message-ID: <20221104164941.95861-1-mjt@msgid.tls.msk.ru> nslookup uses symbols from libresolv, no matter it is on linux or not. This also eliminates hackish way to detect linux. --- Makefile.flags | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile.flags b/Makefile.flags index 84cb00a75..be0a3c4bb 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -184,10 +184,8 @@ LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=% endif ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y) -ifneq (,$(findstring linux,$(shell $(CC) $(CFLAGS) -dumpmachine))) LDLIBS += resolv endif -endif ifeq ($(CONFIG_EFENCE),y) LDLIBS += efence -- 2.30.2 From mjt at tls.msk.ru Fri Nov 4 16:49:27 2022 From: mjt at tls.msk.ru (Michael Tokarev) Date: Fri, 4 Nov 2022 19:49:27 +0300 Subject: [PATCH] buildsys: resurrect PLATFORM_LINUX and depend on it for linux-specific applets Message-ID: <20221104164927.95804-1-mjt@msgid.tls.msk.ru> This effectively reverts the following two commits: commit e3b1a1fd28558f7a1b3c0ec33313bedb675be8a1 Author: Denys Vlasenko Date: Sat Feb 26 22:24:08 2011 +0100 Replace "depends on PLATFORM_LINUX" with "select PLATFORM_LINUX" and commit 5c69ad0ecdc18cf51b312c7c82848f4438fe1c8d Author: Ron Yorston Date: Tue Aug 4 08:24:19 2020 +0100 build system: drop PLATFORM_LINUX but does, hopefully, the right thing. Original complain was that the allnoconfig turns off PLATFORM_LINUX on which all linux-specific applets depends. Instead of setting this config option right for linux and non-linux (initially it was just a regular kconfig symbol, not set depending on the platform), it were turned into something which made little sense (in the first commit), and later dropped completely. So introduce a dynamic kconfig symbol PLATFORM_LINUX with the value actually depending on the target platform, so that it is not affected by all{yes|no|whatever}config. This way, it is possible to depend on it for linux-specific applets without breaking *config anymore. It is done by creating a small kconfig fragment, .platform.in, to define just PLATFORM_LINUX symbol. It is created in Makefile if ${CPP} has __linux__ #defined. And include it in the top-level Config.in. Regenerate default config files with the new symbol. And mark all the applets which were marked as "select PLATFORM_LINUX" before the "build system: drop PLATFORM_LINUX" commit, as "depends on PLATFORM_LINUX". Also mark 2 other applets, tc and dhcprelay, as linux-only too. This way, it is finally possible to build busybox on other platforms without really huge efforts to maintain list of "incompatible" applets externally, and does not put any pressure on the main development, - the only thing needed is to keep the existing "depends on PLATFORM_LINUX" lines. Signed-off-by: Michael Tokarev --- Config.in | 4 ++++ Makefile | 9 ++++++++- configs/TEST_nommu_defconfig | 1 + configs/TEST_noprintf_defconfig | 1 + configs/TEST_rh9_defconfig | 1 + configs/android2_defconfig | 1 + configs/android_502_defconfig | 1 + configs/android_defconfig | 1 + configs/android_ndk_defconfig | 1 + configs/cygwin_defconfig | 1 + configs/freebsd_defconfig | 1 + console-tools/chvt.c | 1 + console-tools/deallocvt.c | 1 + console-tools/dumpkmap.c | 1 + console-tools/fgconsole.c | 1 + console-tools/kbd_mode.c | 1 + console-tools/loadfont.c | 2 ++ console-tools/loadkmap.c | 1 + console-tools/openvt.c | 1 + console-tools/setconsole.c | 1 + console-tools/setkeycodes.c | 1 + console-tools/setlogcons.c | 1 + console-tools/showkey.c | 1 + coreutils/date.c | 1 + coreutils/stat.c | 1 + e2fsprogs/lsattr.c | 1 + klibc-utils/run-init.c | 1 + libbb/Config.src | 2 ++ miscutils/adjtimex.c | 1 + miscutils/beep.c | 1 + miscutils/conspy.c | 1 + miscutils/devfsd.c | 2 ++ miscutils/fbsplash.c | 1 + miscutils/hdparm.c | 1 + miscutils/i2c_tools.c | 5 +++++ miscutils/lsscsi.c | 1 + miscutils/nandwrite.c | 2 ++ miscutils/partprobe.c | 1 + miscutils/raidautorun.c | 1 + miscutils/readahead.c | 1 + miscutils/rfkill.c | 1 + miscutils/rx.c | 1 + miscutils/setserial.c | 1 + miscutils/ubi_tools.c | 6 ++++++ miscutils/ubirename.c | 1 + miscutils/watchdog.c | 1 + modutils/depmod.c | 1 + modutils/insmod.c | 1 + modutils/lsmod.c | 1 + modutils/modinfo.c | 1 + modutils/modprobe.c | 1 + modutils/rmmod.c | 1 + networking/arp.c | 1 + networking/arping.c | 1 + networking/brctl.c | 1 + networking/ether-wake.c | 1 + networking/ifconfig.c | 1 + networking/ifenslave.c | 1 + networking/ifplugd.c | 1 + networking/ip.c | 7 +++++++ networking/nameif.c | 1 + networking/netstat.c | 1 + networking/ntpd.c | 1 + networking/ping.c | 1 + networking/route.c | 1 + networking/slattach.c | 1 + networking/tc.c | 1 + networking/traceroute.c | 1 + networking/tunctl.c | 1 + networking/udhcp/Config.src | 3 +++ networking/vconfig.c | 1 + networking/zcip.c | 1 + procps/free.c | 1 + procps/ps.c | 1 + procps/uptime.c | 1 + sysklogd/klogd.c | 1 + sysklogd/syslogd.c | 1 + util-linux/acpid.c | 1 + util-linux/blkdiscard.c | 1 + util-linux/blkid.c | 1 + util-linux/dmesg.c | 1 + util-linux/eject.c | 1 + util-linux/fatattr.c | 1 + util-linux/fbset.c | 1 + util-linux/fdformat.c | 1 + util-linux/fdisk.c | 1 + util-linux/findfs.c | 1 + util-linux/freeramdisk.c | 2 ++ util-linux/fsfreeze.c | 1 + util-linux/fstrim.c | 1 + util-linux/hwclock.c | 1 + util-linux/ionice.c | 1 + util-linux/ipcs.c | 1 + util-linux/losetup.c | 1 + util-linux/lspci.c | 1 + util-linux/lsusb.c | 1 + util-linux/mdev.c | 1 + util-linux/mkfs_ext2.c | 2 ++ util-linux/mkfs_minix.c | 1 + util-linux/mkfs_reiser.c | 1 + util-linux/mkfs_vfat.c | 2 ++ util-linux/mount.c | 1 + util-linux/nsenter.c | 1 + util-linux/pivot_root.c | 1 + util-linux/readprofile.c | 1 + util-linux/rtcwake.c | 1 + util-linux/setarch.c | 3 +++ util-linux/setpriv.c | 1 + util-linux/swaponoff.c | 2 ++ util-linux/switch_root.c | 1 + util-linux/uevent.c | 1 + util-linux/umount.c | 1 + util-linux/unshare.c | 1 + 113 files changed, 150 insertions(+), 1 deletion(-) diff --git a/Config.in b/Config.in index a98a8b15b..75697e781 100644 --- a/Config.in +++ b/Config.in @@ -9,6 +9,9 @@ config HAVE_DOT_CONFIG bool default y +# include generated CONFIG_PLATFORM_LINUX symbol: +source .platform.in + menu "Settings" config DESKTOP @@ -312,6 +315,7 @@ config BUSYBOX_EXEC_PATH config SELINUX bool "Support NSA Security Enhanced Linux" default n + depends on PLATFORM_LINUX help Enable support for SELinux in applets ls, ps, and id. Also provide the option of compiling in SELinux applets. diff --git a/Makefile b/Makefile index 503475fe9..ad780c261 100644 --- a/Makefile +++ b/Makefile @@ -361,9 +361,16 @@ scripts/basic/%: scripts_basic ; # This target generates Kbuild's and Config.in's from *.c files PHONY += gen_build_files -gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(wildcard $(srctree)/embed/*) +gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(wildcard $(srctree)/embed/*) .platform.in $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) +.platform.in: + $(Q)printf '#ifndef __linux__\nplatform_is_not_linux\n#endif' \ + | $(CPP) - | grep -s platform_is_not_linux \ + && linux=n || linux=y; \ + printf "config PLATFORM_LINUX\n\tbool\n\tdefault $$linux\n" > $@ +MRPROPER_FILES += .platform.in + # bbox: we have helpers in applets/ # we depend on scripts_basic, since scripts/basic/fixdep # must be built before any other host prog diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig index 415f5a802..4048ba9bd 100644 --- a/configs/TEST_nommu_defconfig +++ b/configs/TEST_nommu_defconfig @@ -4,6 +4,7 @@ # Wed Jan 27 21:01:26 2010 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/TEST_noprintf_defconfig b/configs/TEST_noprintf_defconfig index 9b378fd55..064a28955 100644 --- a/configs/TEST_noprintf_defconfig +++ b/configs/TEST_noprintf_defconfig @@ -4,6 +4,7 @@ # Mon Jun 7 13:37:55 2010 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/TEST_rh9_defconfig b/configs/TEST_rh9_defconfig index 4ac62b9da..c81d051d3 100644 --- a/configs/TEST_rh9_defconfig +++ b/configs/TEST_rh9_defconfig @@ -4,6 +4,7 @@ # Fri Apr 16 22:25:22 2010 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/android2_defconfig b/configs/android2_defconfig index d4b8f1616..0eef44a22 100644 --- a/configs/android2_defconfig +++ b/configs/android2_defconfig @@ -4,6 +4,7 @@ # android-ndk-r6/build/tools/make-standalone-toolchain.sh --platform=android-8 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/android_502_defconfig b/configs/android_502_defconfig index 104e70f23..39c2bd6ec 100644 --- a/configs/android_502_defconfig +++ b/configs/android_502_defconfig @@ -74,6 +74,7 @@ # Mon Mar 14 20:43:42 2016 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/android_defconfig b/configs/android_defconfig index 92a66048a..fe5c9a614 100644 --- a/configs/android_defconfig +++ b/configs/android_defconfig @@ -4,6 +4,7 @@ # Sun Nov 6 07:51:38 2011 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig index 425593454..8374ca241 100644 --- a/configs/android_ndk_defconfig +++ b/configs/android_ndk_defconfig @@ -4,6 +4,7 @@ # Fri Sep 18 20:39:29 2015 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/cygwin_defconfig b/configs/cygwin_defconfig index c09bc9281..65e6ce32c 100644 --- a/configs/cygwin_defconfig +++ b/configs/cygwin_defconfig @@ -4,6 +4,7 @@ # Sun Jul 10 12:48:50 2011 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/configs/freebsd_defconfig b/configs/freebsd_defconfig index 6cbd54895..dc8b6409c 100644 --- a/configs/freebsd_defconfig +++ b/configs/freebsd_defconfig @@ -4,6 +4,7 @@ # Tue Dec 21 19:47:40 2010 # CONFIG_HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y # # Busybox Settings diff --git a/console-tools/chvt.c b/console-tools/chvt.c index 7c2814d1c..4ea1bf82a 100644 --- a/console-tools/chvt.c +++ b/console-tools/chvt.c @@ -9,6 +9,7 @@ //config:config CHVT //config: bool "chvt (2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program is used to change to another terminal. //config: Example: chvt 4 (change to terminal /dev/tty4) diff --git a/console-tools/deallocvt.c b/console-tools/deallocvt.c index 6cd54653c..8f3781a33 100644 --- a/console-tools/deallocvt.c +++ b/console-tools/deallocvt.c @@ -10,6 +10,7 @@ //config:config DEALLOCVT //config: bool "deallocvt (1.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program deallocates unused virtual consoles. diff --git a/console-tools/dumpkmap.c b/console-tools/dumpkmap.c index 3d8de6bed..924e86810 100644 --- a/console-tools/dumpkmap.c +++ b/console-tools/dumpkmap.c @@ -9,6 +9,7 @@ //config:config DUMPKMAP //config: bool "dumpkmap (1.6 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program dumps the kernel's keyboard translation table to //config: stdout, in binary format. You can then use loadkmap to load it. diff --git a/console-tools/fgconsole.c b/console-tools/fgconsole.c index 9bfb68017..fa533a051 100644 --- a/console-tools/fgconsole.c +++ b/console-tools/fgconsole.c @@ -9,6 +9,7 @@ //config:config FGCONSOLE //config: bool "fgconsole (1.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program prints active (foreground) console number. diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index b0b963ee0..90e7695f2 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -11,6 +11,7 @@ //config:config KBD_MODE //config: bool "kbd_mode (4.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program reports and sets keyboard mode. diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index 81a0e6aa8..02c6a150f 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c @@ -12,12 +12,14 @@ //config:config LOADFONT //config: bool "loadfont (5.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program loads a console font from standard input. //config: //config:config SETFONT //config: bool "setfont (24 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Allows to load console screen map. Useful for i18n. //config: diff --git a/console-tools/loadkmap.c b/console-tools/loadkmap.c index c038e2d22..0a53b3345 100644 --- a/console-tools/loadkmap.c +++ b/console-tools/loadkmap.c @@ -9,6 +9,7 @@ //config:config LOADKMAP //config: bool "loadkmap (1.8 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program loads a keyboard translation table from //config: standard input. diff --git a/console-tools/openvt.c b/console-tools/openvt.c index db2f073b2..cab6c358b 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -10,6 +10,7 @@ //config:config OPENVT //config: bool "openvt (7.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program is used to start a command on an unused //config: virtual terminal. diff --git a/console-tools/setconsole.c b/console-tools/setconsole.c index 461a98c6a..2d934cd24 100644 --- a/console-tools/setconsole.c +++ b/console-tools/setconsole.c @@ -10,6 +10,7 @@ //config:config SETCONSOLE //config: bool "setconsole (3.6 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Redirect writes to /dev/console to another device, //config: like the current tty while logged in via telnet. diff --git a/console-tools/setkeycodes.c b/console-tools/setkeycodes.c index 5de18b8ea..3ab269320 100644 --- a/console-tools/setkeycodes.c +++ b/console-tools/setkeycodes.c @@ -11,6 +11,7 @@ //config:config SETKEYCODES //config: bool "setkeycodes (2.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program loads entries into the kernel's scancode-to-keycode //config: map, allowing unusual keyboards to generate usable keycodes. diff --git a/console-tools/setlogcons.c b/console-tools/setlogcons.c index e9c2f516e..46f579984 100644 --- a/console-tools/setlogcons.c +++ b/console-tools/setlogcons.c @@ -11,6 +11,7 @@ //config:config SETLOGCONS //config: bool "setlogcons (1.8 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: This program redirects the output console of kernel messages. diff --git a/console-tools/showkey.c b/console-tools/showkey.c index 84eb38a0a..45533dce6 100644 --- a/console-tools/showkey.c +++ b/console-tools/showkey.c @@ -9,6 +9,7 @@ //config:config SHOWKEY //config: bool "showkey (4.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Shows keys pressed. diff --git a/coreutils/date.c b/coreutils/date.c index abcc37c33..2ff84a30d 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -37,6 +37,7 @@ //config: bool "Support %[num]N nanosecond format specifier" //config: default n # stat's nanosecond field is a bit non-portable //config: depends on DATE +//config: depends on PLATFORM_LINUX //config: help //config: Support %[num]N format specifier. Adds ~250 bytes of code. //config: diff --git a/coreutils/stat.c b/coreutils/stat.c index 2c2909e7e..dd4b36fa0 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -31,6 +31,7 @@ //config: bool "Enable display of filesystem status (-f)" //config: default y //config: depends on STAT +//config: depends on PLATFORM_LINUX # statfs() //config: help //config: Without this, stat will not support the '-f' option to display //config: information about filesystem status. diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index c9f353ce5..3ab8b7ff6 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c @@ -12,6 +12,7 @@ //config:config LSATTR //config: bool "lsattr (5.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: lsattr lists the file attributes on a second extended file system. diff --git a/klibc-utils/run-init.c b/klibc-utils/run-init.c index 73c677bab..61e4f66fd 100644 --- a/klibc-utils/run-init.c +++ b/klibc-utils/run-init.c @@ -8,6 +8,7 @@ //config:config RUN_INIT //config: bool "run-init (7.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The run-init utility is used from initramfs to select a new //config: root device. Under initramfs, you have to use this instead of diff --git a/libbb/Config.src b/libbb/Config.src index 66a3ffa23..460e74cb4 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -118,6 +118,7 @@ config FEATURE_VERBOSE_CP_MESSAGE config FEATURE_USE_SENDFILE bool "Use sendfile system call" default y + depends on PLATFORM_LINUX help When enabled, busybox will use the kernel sendfile() function instead of read/write loops to copy data between file descriptors @@ -140,6 +141,7 @@ config FEATURE_COPYBUF_KB config MONOTONIC_SYSCALL bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" default y + depends on PLATFORM_LINUX help Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring time intervals (time, ping, traceroute etc need this). diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c index 209d1d560..b859d817c 100644 --- a/miscutils/adjtimex.c +++ b/miscutils/adjtimex.c @@ -13,6 +13,7 @@ //config:config ADJTIMEX //config: bool "adjtimex (4.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Adjtimex reads and optionally sets adjustment parameters for //config: the Linux clock adjustment algorithm. diff --git a/miscutils/beep.c b/miscutils/beep.c index 7c60aed08..46ac3ebdf 100644 --- a/miscutils/beep.c +++ b/miscutils/beep.c @@ -9,6 +9,7 @@ //config:config BEEP //config: bool "beep (2.4 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The beep applets beeps in a given freq/Hz. //config: diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 21a498d0f..df926cc20 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -12,6 +12,7 @@ //config:config CONSPY //config: bool "conspy (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: A text-mode VNC like program for Linux virtual terminals. //config: example: conspy NUM shared access to console num diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c index 297693f8c..daf3f1cb6 100644 --- a/miscutils/devfsd.c +++ b/miscutils/devfsd.c @@ -56,6 +56,7 @@ //config:config DEVFSD //config: bool "devfsd (obsolete)" //config: default n +//config: depends on PLATFORM_LINUX //config: select FEATURE_SYSLOG //config: help //config: This is deprecated and should NOT be used anymore. @@ -98,6 +99,7 @@ //config:config FEATURE_DEVFS //config: bool "Use devfs names for all devices (obsolete)" //config: default n +//config: depends on PLATFORM_LINUX //config: help //config: This is obsolete and should NOT be used anymore. //config: Use linux >= 2.6 (optionally with hotplug) and mdev instead! diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index 2934d8eb7..a913428d1 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c @@ -23,6 +23,7 @@ //config:config FBSPLASH //config: bool "fbsplash (26 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Shows splash image and progress bar on framebuffer device. //config: Can be used during boot phase of an embedded device. diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c index 83e2f8d53..f72352bd9 100644 --- a/miscutils/hdparm.c +++ b/miscutils/hdparm.c @@ -14,6 +14,7 @@ //config:config HDPARM //config: bool "hdparm (25 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Get/Set hard drive parameters. Primarily intended for ATA //config: drives. diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index da26f5e19..6e645d0cb 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -11,30 +11,35 @@ //config:config I2CGET //config: bool "i2cget (5.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Read from I2C/SMBus chip registers. //config: //config:config I2CSET //config: bool "i2cset (6.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Set I2C registers. //config: //config:config I2CDUMP //config: bool "i2cdump (7.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Examine I2C registers. //config: //config:config I2CDETECT //config: bool "i2cdetect (7.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Detect I2C chips. //config: //config:config I2CTRANSFER //config: bool "i2ctransfer (4.0 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Send user-defined I2C messages in one transfer. //config: diff --git a/miscutils/lsscsi.c b/miscutils/lsscsi.c index 8f7eda761..a9d8c3772 100644 --- a/miscutils/lsscsi.c +++ b/miscutils/lsscsi.c @@ -9,6 +9,7 @@ //config:config LSSCSI //config: bool "lsscsi (2.5 kb)" //config: default y +//config: #depends on PLATFORM_LINUX //config: help //config: lsscsi is a utility for displaying information about SCSI buses in the //config: system and devices connected to them. diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 52bf49434..a3d24c285 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -10,12 +10,14 @@ //config:config NANDWRITE //config: bool "nandwrite (4.8 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Write to the specified MTD device, with bad blocks awareness //config: //config:config NANDDUMP //config: bool "nanddump (5.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Dump the content of raw NAND chip diff --git a/miscutils/partprobe.c b/miscutils/partprobe.c index 0fb1927b7..c1454bb9a 100644 --- a/miscutils/partprobe.c +++ b/miscutils/partprobe.c @@ -7,6 +7,7 @@ //config:config PARTPROBE //config: bool "partprobe (3.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Ask kernel to rescan partition table. diff --git a/miscutils/raidautorun.c b/miscutils/raidautorun.c index 905862cf7..e4fb3cf39 100644 --- a/miscutils/raidautorun.c +++ b/miscutils/raidautorun.c @@ -9,6 +9,7 @@ //config:config RAIDAUTORUN //config: bool "raidautorun (1.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: raidautorun tells the kernel md driver to //config: search and start RAID arrays. diff --git a/miscutils/readahead.c b/miscutils/readahead.c index d2bed2092..c95dc36d8 100644 --- a/miscutils/readahead.c +++ b/miscutils/readahead.c @@ -13,6 +13,7 @@ //config: bool "readahead (1.5 kb)" //config: default y //config: depends on LFS +//config: depends on PLATFORM_LINUX //config: help //config: Preload the files listed on the command line into RAM cache so that //config: subsequent reads on these files will not block on disk I/O. diff --git a/miscutils/rfkill.c b/miscutils/rfkill.c index 9d91ea82f..9d8921b87 100644 --- a/miscutils/rfkill.c +++ b/miscutils/rfkill.c @@ -9,6 +9,7 @@ //config:config RFKILL //config: bool "rfkill (4.4 kb)" //config: default n # doesn't build on Ubuntu 9.04 +//config: depends on PLATFORM_LINUX //config: help //config: Enable/disable wireless devices. //config: diff --git a/miscutils/rx.c b/miscutils/rx.c index d8b041480..88783e637 100644 --- a/miscutils/rx.c +++ b/miscutils/rx.c @@ -17,6 +17,7 @@ //config:config RX //config: bool "rx (2.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Receive files using the Xmodem protocol. diff --git a/miscutils/setserial.c b/miscutils/setserial.c index 2006861e2..737707bc0 100644 --- a/miscutils/setserial.c +++ b/miscutils/setserial.c @@ -10,6 +10,7 @@ //config:config SETSERIAL //config: bool "setserial (6.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Retrieve or set Linux serial port. diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index 6d49f61d9..c169b3d94 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c @@ -6,36 +6,42 @@ //config:config UBIATTACH //config: bool "ubiattach (4.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Attach MTD device to an UBI device. //config: //config:config UBIDETACH //config: bool "ubidetach (4.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Detach MTD device from an UBI device. //config: //config:config UBIMKVOL //config: bool "ubimkvol (5.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Create a UBI volume. //config: //config:config UBIRMVOL //config: bool "ubirmvol (4.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Delete a UBI volume. //config: //config:config UBIRSVOL //config: bool "ubirsvol (4.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Resize a UBI volume. //config: //config:config UBIUPDATEVOL //config: bool "ubiupdatevol (5.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Update a UBI volume. diff --git a/miscutils/ubirename.c b/miscutils/ubirename.c index 06a0adacf..1d4c91fda 100644 --- a/miscutils/ubirename.c +++ b/miscutils/ubirename.c @@ -9,6 +9,7 @@ //config:config UBIRENAME //config: bool "ubirename (2.4 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Utility to rename UBI volumes diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index 9f5a4b849..a27653720 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c @@ -11,6 +11,7 @@ //config:config WATCHDOG //config: bool "watchdog (5.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The watchdog utility is used with hardware or software watchdog //config: device drivers. It opens the specified watchdog device special file diff --git a/modutils/depmod.c b/modutils/depmod.c index bb42bbefe..14dd12a07 100644 --- a/modutils/depmod.c +++ b/modutils/depmod.c @@ -10,6 +10,7 @@ //config:config DEPMOD //config: bool "depmod (27 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: depmod generates modules.dep (and potentially modules.alias //config: and modules.symbols) that contain dependency information diff --git a/modutils/insmod.c b/modutils/insmod.c index 8f7163e25..9b26e27a3 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -9,6 +9,7 @@ //config:config INSMOD //config: bool "insmod (22 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: insmod is used to load specified modules in the running kernel. diff --git a/modutils/lsmod.c b/modutils/lsmod.c index 2beb12362..60aa36404 100644 --- a/modutils/lsmod.c +++ b/modutils/lsmod.c @@ -10,6 +10,7 @@ //config:config LSMOD //config: bool "lsmod (1.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: lsmod is used to display a list of loaded modules. //config: diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 0a86c3296..099f645c1 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c @@ -8,6 +8,7 @@ //config:config MODINFO //config: bool "modinfo (24 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Show information about a Linux Kernel module diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 235706fd5..fbc0ba112 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -10,6 +10,7 @@ //config:config MODPROBE //config: bool "modprobe (28 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Handle the loading of modules, and their dependencies on a high //config: level. diff --git a/modutils/rmmod.c b/modutils/rmmod.c index 2b3c39153..d0117f0f9 100644 --- a/modutils/rmmod.c +++ b/modutils/rmmod.c @@ -10,6 +10,7 @@ //config:config RMMOD //config: bool "rmmod (3.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: rmmod is used to unload specified modules from the kernel. diff --git a/networking/arp.c b/networking/arp.c index 16783ab95..e162af136 100644 --- a/networking/arp.c +++ b/networking/arp.c @@ -15,6 +15,7 @@ //config:config ARP //config: bool "arp (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Manipulate the system ARP cache. diff --git a/networking/arping.c b/networking/arping.c index 86f0221ed..01f7abaa2 100644 --- a/networking/arping.c +++ b/networking/arping.c @@ -8,6 +8,7 @@ //config:config ARPING //config: bool "arping (9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Ping hosts by ARP packets. diff --git a/networking/brctl.c b/networking/brctl.c index 956bd91f3..6b5357709 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -12,6 +12,7 @@ //config:config BRCTL //config: bool "brctl (4.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Manage ethernet bridges. //config: Supports addbr/delbr and addif/delif. diff --git a/networking/ether-wake.c b/networking/ether-wake.c index 36e90acfb..f4e7cba58 100644 --- a/networking/ether-wake.c +++ b/networking/ether-wake.c @@ -66,6 +66,7 @@ //config:config ETHER_WAKE //config: bool "ether-wake (4.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Send a magic packet to wake up sleeping machines. diff --git a/networking/ifconfig.c b/networking/ifconfig.c index 9ee232a66..42a1ac8bc 100644 --- a/networking/ifconfig.c +++ b/networking/ifconfig.c @@ -27,6 +27,7 @@ //config:config IFCONFIG //config: bool "ifconfig (12 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Ifconfig is used to configure the kernel-resident network interfaces. //config: diff --git a/networking/ifenslave.c b/networking/ifenslave.c index bdb9894be..75f395e72 100644 --- a/networking/ifenslave.c +++ b/networking/ifenslave.c @@ -100,6 +100,7 @@ //config:config IFENSLAVE //config: bool "ifenslave (13 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Userspace application to bind several interfaces //config: to a logical interface (use with kernel bonding driver). diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 0b55bf4e5..70b72969d 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c @@ -9,6 +9,7 @@ //config:config IFPLUGD //config: bool "ifplugd (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Network interface plug detection daemon. diff --git a/networking/ip.c b/networking/ip.c index 7c3208699..54ef58d60 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -11,6 +11,7 @@ //config:config IP //config: bool "ip (35 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The "ip" applet is a TCP/IP interface configuration and routing //config: utility. @@ -22,6 +23,7 @@ //config: bool "ipaddr (14 kb)" //config: default y //config: select FEATURE_IP_ADDRESS +//config: depends on PLATFORM_LINUX //config: help //config: Short form of "ip addr" //config: @@ -29,6 +31,7 @@ //config: bool "iplink (17 kb)" //config: default y //config: select FEATURE_IP_LINK +//config: depends on PLATFORM_LINUX //config: help //config: Short form of "ip link" //config: @@ -36,6 +39,7 @@ //config: bool "iproute (15 kb)" //config: default y //config: select FEATURE_IP_ROUTE +//config: depends on PLATFORM_LINUX //config: help //config: Short form of "ip route" //config: @@ -43,6 +47,7 @@ //config: bool "iptunnel (9.6 kb)" //config: default y //config: select FEATURE_IP_TUNNEL +//config: depends on PLATFORM_LINUX //config: help //config: Short form of "ip tunnel" //config: @@ -50,6 +55,7 @@ //config: bool "iprule (10 kb)" //config: default y //config: select FEATURE_IP_RULE +//config: depends on PLATFORM_LINUX //config: help //config: Short form of "ip rule" //config: @@ -57,6 +63,7 @@ //config: bool "ipneigh (8.3 kb)" //config: default y //config: select FEATURE_IP_NEIGH +//config: depends on PLATFORM_LINUX //config: help //config: Short form of "ip neigh" //config: diff --git a/networking/nameif.c b/networking/nameif.c index 66e042688..8b5243df8 100644 --- a/networking/nameif.c +++ b/networking/nameif.c @@ -12,6 +12,7 @@ //config:config NAMEIF //config: bool "nameif (6.6 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: select FEATURE_SYSLOG //config: help //config: nameif is used to rename network interface by its MAC address. diff --git a/networking/netstat.c b/networking/netstat.c index 807800a62..dadc54877 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -16,6 +16,7 @@ //config:config NETSTAT //config: bool "netstat (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: netstat prints information about the Linux networking subsystem. //config: diff --git a/networking/ntpd.c b/networking/ntpd.c index 204e1d7c2..892b69629 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -43,6 +43,7 @@ //config:config NTPD //config: bool "ntpd (22 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The NTP client/server daemon. //config: diff --git a/networking/ping.c b/networking/ping.c index 9805695a1..ddf440aed 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -27,6 +27,7 @@ //config:config PING //config: bool "ping (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to //config: elicit an ICMP ECHO_RESPONSE from a host or gateway. diff --git a/networking/route.c b/networking/route.c index 26146f8e9..2d0f3a667 100644 --- a/networking/route.c +++ b/networking/route.c @@ -27,6 +27,7 @@ //config:config ROUTE //config: bool "route (8.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Route displays or manipulates the kernel's IP routing tables. diff --git a/networking/slattach.c b/networking/slattach.c index 6d2a252fc..93fdf7f51 100644 --- a/networking/slattach.c +++ b/networking/slattach.c @@ -15,6 +15,7 @@ //config:config SLATTACH //config: bool "slattach (6.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: slattach configures serial line as SLIP network interface. diff --git a/networking/tc.c b/networking/tc.c index 43187f7ee..1622a90d2 100644 --- a/networking/tc.c +++ b/networking/tc.c @@ -9,6 +9,7 @@ //config:config TC //config: bool "tc (8.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Show / manipulate traffic control settings //config: diff --git a/networking/traceroute.c b/networking/traceroute.c index 4bbe1ab8e..fb9315db5 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -212,6 +212,7 @@ //config:config TRACEROUTE //config: bool "traceroute (11 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Utility to trace the route of IP packets. //config: diff --git a/networking/tunctl.c b/networking/tunctl.c index 97e6917aa..83b8695ce 100644 --- a/networking/tunctl.c +++ b/networking/tunctl.c @@ -12,6 +12,7 @@ //config:config TUNCTL //config: bool "tunctl (6.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: tunctl creates or deletes tun devices. //config: diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index 8c8c11c26..9ea368ad9 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -6,6 +6,7 @@ config UDHCPD bool "udhcpd (21 kb)" default y + depends on PLATFORM_LINUX help udhcpd is a DHCP server geared primarily toward embedded systems, while striving to be fully functional and RFC compliant. @@ -53,6 +54,7 @@ config DUMPLEASES config DHCPRELAY bool "dhcprelay (5.2 kb)" default y + depends on PLATFORM_LINUX help dhcprelay listens for DHCP requests on one or more interfaces and forwards these requests to a different interface or DHCP @@ -61,6 +63,7 @@ config DHCPRELAY config UDHCPC bool "udhcpc (24 kb)" default y + depends on PLATFORM_LINUX help udhcpc is a DHCP client geared primarily toward embedded systems, while striving to be fully functional and RFC compliant. diff --git a/networking/vconfig.c b/networking/vconfig.c index 7e805be9c..56b1437c3 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c @@ -9,6 +9,7 @@ //config:config VCONFIG //config: bool "vconfig (2.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Creates, removes, and configures VLAN interfaces diff --git a/networking/zcip.c b/networking/zcip.c index 311dfbe4c..e946142cd 100644 --- a/networking/zcip.c +++ b/networking/zcip.c @@ -16,6 +16,7 @@ //config:config ZCIP //config: bool "zcip (8.4 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: select FEATURE_SYSLOG //config: help //config: ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. diff --git a/procps/free.c b/procps/free.c index 0b68e1b88..9545d64f9 100644 --- a/procps/free.c +++ b/procps/free.c @@ -9,6 +9,7 @@ //config:config FREE //config: bool "free (3.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX #sysinfo() //config: help //config: free displays the total amount of free and used physical and swap //config: memory in the system, as well as the buffers used by the kernel. diff --git a/procps/ps.c b/procps/ps.c index 03b9c418c..5813cf854 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -35,6 +35,7 @@ //config: bool "Enable -o time and -o etime specifiers" //config: default y //config: depends on (PS || MINIPS) && DESKTOP +//config: depends on PLATFORM_LINUX //config: //config:config FEATURE_PS_UNUSUAL_SYSTEMS //config: bool "Support Linux prior to 2.4.0 and non-ELF systems" diff --git a/procps/uptime.c b/procps/uptime.c index 4fd0c9d2d..577e16fad 100644 --- a/procps/uptime.c +++ b/procps/uptime.c @@ -14,6 +14,7 @@ //config:config UPTIME //config: bool "uptime (3.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX #sysinfo() //config: help //config: uptime gives a one line display of the current time, how long //config: the system has been running, how many users are currently logged diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c index df0edee0a..540441471 100644 --- a/sysklogd/klogd.c +++ b/sysklogd/klogd.c @@ -33,6 +33,7 @@ //config: bool "Use the klogctl() interface" //config: default y //config: depends on KLOGD +//config: depends on PLATFORM_LINUX //config: help //config: The klogd applet supports two interfaces for reading //config: kernel messages. Linux provides the klogctl() interface diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 6ddfd771a..3583b9600 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -109,6 +109,7 @@ //config: bool "Linux kernel printk buffer support" //config: default y //config: depends on SYSLOGD +//config: depends on PLATFORM_LINUX //config: help //config: When you enable this feature, the syslogd utility will //config: write system log message to the Linux kernel's printk buffer. diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 00613f8e3..60776ea5c 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c @@ -9,6 +9,7 @@ //config:config ACPID //config: bool "acpid (9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: acpid listens to ACPI events coming either in textual form from //config: /proc/acpi/event (though it is marked deprecated it is still widely diff --git a/util-linux/blkdiscard.c b/util-linux/blkdiscard.c index 7ac8045f9..dc844c181 100644 --- a/util-linux/blkdiscard.c +++ b/util-linux/blkdiscard.c @@ -8,6 +8,7 @@ //config:config BLKDISCARD //config: bool "blkdiscard (4.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: blkdiscard discards sectors on a given device. diff --git a/util-linux/blkid.c b/util-linux/blkid.c index 4a820771f..cb96c178b 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c @@ -9,6 +9,7 @@ //config:config BLKID //config: bool "blkid (12 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: select VOLUMEID //config: help //config: Lists labels and UUIDs of all filesystems. diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c index 6670b84de..8cb8d6bd7 100644 --- a/util-linux/dmesg.c +++ b/util-linux/dmesg.c @@ -11,6 +11,7 @@ //config:config DMESG //config: bool "dmesg (3.7 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: dmesg is used to examine or control the kernel ring buffer. When the //config: Linux kernel prints messages to the system log, they are stored in diff --git a/util-linux/eject.c b/util-linux/eject.c index 29b0a86bd..f95d952cc 100644 --- a/util-linux/eject.c +++ b/util-linux/eject.c @@ -15,6 +15,7 @@ //config:config EJECT //config: bool "eject (4 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Used to eject cdroms. (defaults to /dev/cdrom) //config: diff --git a/util-linux/fatattr.c b/util-linux/fatattr.c index afd70c45d..017c808de 100644 --- a/util-linux/fatattr.c +++ b/util-linux/fatattr.c @@ -11,6 +11,7 @@ //config:config FATATTR //config: bool "fatattr (1.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: fatattr lists or changes the file attributes on a fat file system. diff --git a/util-linux/fbset.c b/util-linux/fbset.c index 41cc29f37..c5269ede5 100644 --- a/util-linux/fbset.c +++ b/util-linux/fbset.c @@ -14,6 +14,7 @@ //config:config FBSET //config: bool "fbset (5.9 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: fbset is used to show or change the settings of a Linux frame buffer //config: device. The frame buffer device provides a simple and unique diff --git a/util-linux/fdformat.c b/util-linux/fdformat.c index f0466fdbd..2c72d781c 100644 --- a/util-linux/fdformat.c +++ b/util-linux/fdformat.c @@ -8,6 +8,7 @@ //config:config FDFORMAT //config: bool "fdformat (4.4 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: fdformat is used to low-level format a floppy disk. diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 20e7d56fa..03b5e3bf6 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -10,6 +10,7 @@ //config:config FDISK //config: bool "fdisk (37 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The fdisk utility is used to divide hard disks into one or more //config: logical disks, which are generally called partitions. This utility diff --git a/util-linux/findfs.c b/util-linux/findfs.c index f5621a1fa..dec9290e6 100644 --- a/util-linux/findfs.c +++ b/util-linux/findfs.c @@ -10,6 +10,7 @@ //config:config FINDFS //config: bool "findfs (12 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: select VOLUMEID //config: help //config: Prints the name of a filesystem with given label or UUID. diff --git a/util-linux/freeramdisk.c b/util-linux/freeramdisk.c index 309169d25..b505f4dae 100644 --- a/util-linux/freeramdisk.c +++ b/util-linux/freeramdisk.c @@ -11,6 +11,7 @@ //config:config FDFLUSH //config: bool "fdflush (1.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: fdflush is only needed when changing media on slightly-broken //config: removable media drives. It is used to make Linux believe that a @@ -23,6 +24,7 @@ //config:config FREERAMDISK //config: bool "freeramdisk (1.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Linux allows you to create ramdisks. This utility allows you to //config: delete them and completely free all memory that was used for the diff --git a/util-linux/fsfreeze.c b/util-linux/fsfreeze.c index 6e2ff0a54..673684f49 100644 --- a/util-linux/fsfreeze.c +++ b/util-linux/fsfreeze.c @@ -7,6 +7,7 @@ //config:config FSFREEZE //config: bool "fsfreeze (3.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: select LONG_OPTS //config: help //config: Halt new accesses and flush writes on a mounted filesystem. diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c index 6d673002f..8ed22de10 100644 --- a/util-linux/fstrim.c +++ b/util-linux/fstrim.c @@ -10,6 +10,7 @@ //config:config FSTRIM //config: bool "fstrim (4.4 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Discard unused blocks on a mounted filesystem. diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c index 723b09589..8ffac66ee 100644 --- a/util-linux/hwclock.c +++ b/util-linux/hwclock.c @@ -9,6 +9,7 @@ //config:config HWCLOCK //config: bool "hwclock (5.8 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The hwclock utility is used to read and set the hardware clock //config: on a system. This is primarily used to set the current time on diff --git a/util-linux/ionice.c b/util-linux/ionice.c index 82bd309d1..7228f5a00 100644 --- a/util-linux/ionice.c +++ b/util-linux/ionice.c @@ -9,6 +9,7 @@ //config:config IONICE //config: bool "ionice (3.8 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Set/set program io scheduling class and priority //config: Requires kernel >= 2.6.13 diff --git a/util-linux/ipcs.c b/util-linux/ipcs.c index 5973cbf57..1df6f5906 100644 --- a/util-linux/ipcs.c +++ b/util-linux/ipcs.c @@ -10,6 +10,7 @@ //config:config IPCS //config: bool "ipcs (11 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The ipcs utility is used to provide information on the currently //config: allocated System V interprocess (IPC) objects in the system. diff --git a/util-linux/losetup.c b/util-linux/losetup.c index 24f7a2349..ce3db34d5 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c @@ -9,6 +9,7 @@ //config:config LOSETUP //config: bool "losetup (5.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: losetup is used to associate or detach a loop device with a regular //config: file or block device, and to query the status of a loop device. This diff --git a/util-linux/lspci.c b/util-linux/lspci.c index c22cbcc1e..c37a78ca8 100644 --- a/util-linux/lspci.c +++ b/util-linux/lspci.c @@ -9,6 +9,7 @@ //config:config LSPCI //config: bool "lspci (6.3 kb)" //config: default y +//config: #depends on PLATFORM_LINUX //config: help //config: lspci is a utility for displaying information about PCI buses in the //config: system and devices connected to them. diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c index 9abb748ce..7e232350a 100644 --- a/util-linux/lsusb.c +++ b/util-linux/lsusb.c @@ -9,6 +9,7 @@ //config:config LSUSB //config: bool "lsusb (4.2 kb)" //config: default y +//config: #depends on PLATFORM_LINUX //config: help //config: lsusb is a utility for displaying information about USB buses in the //config: system and devices connected to them. diff --git a/util-linux/mdev.c b/util-linux/mdev.c index ebdc0c254..e8240cb83 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -10,6 +10,7 @@ //config:config MDEV //config: bool "mdev (17 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: mdev is a mini-udev implementation for dynamically creating device //config: nodes in the /dev directory. diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c index fcf374b2d..5b9a39793 100644 --- a/util-linux/mkfs_ext2.c +++ b/util-linux/mkfs_ext2.c @@ -10,12 +10,14 @@ //config:config MKE2FS //config: bool "mke2fs (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Utility to create EXT2 filesystems. //config: //config:config MKFS_EXT2 //config: bool "mkfs.ext2 (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Alias to "mke2fs". diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c index 3c72e5419..0dcacfe79 100644 --- a/util-linux/mkfs_minix.c +++ b/util-linux/mkfs_minix.c @@ -65,6 +65,7 @@ //config:config MKFS_MINIX //config: bool "mkfs.minix (10 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The minix filesystem is a nice, small, compact, read-write filesystem //config: with little overhead. If you wish to be able to create minix diff --git a/util-linux/mkfs_reiser.c b/util-linux/mkfs_reiser.c index 44a743147..22ffcd346 100644 --- a/util-linux/mkfs_reiser.c +++ b/util-linux/mkfs_reiser.c @@ -9,6 +9,7 @@ //config:config MKFS_REISER //config: bool "mkfs_reiser" //config: default n +//config: depends on PLATFORM_LINUX //config: help //config: Utility to create ReiserFS filesystems. //config: Note: this applet needs a lot of testing and polishing. diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c index 821371953..d68edb890 100644 --- a/util-linux/mkfs_vfat.c +++ b/util-linux/mkfs_vfat.c @@ -10,12 +10,14 @@ //config:config MKDOSFS //config: bool "mkdosfs (7.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Utility to create FAT32 filesystems. //config: //config:config MKFS_VFAT //config: bool "mkfs.vfat (7.2 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Alias to "mkdosfs". diff --git a/util-linux/mount.c b/util-linux/mount.c index 4e65b6b46..f70399bbb 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -20,6 +20,7 @@ //config:config MOUNT //config: bool "mount (23 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: All files and filesystems in Unix are arranged into one big directory //config: tree. The 'mount' utility is used to graft a filesystem onto a diff --git a/util-linux/nsenter.c b/util-linux/nsenter.c index 1aa045b35..da4b7ccdd 100644 --- a/util-linux/nsenter.c +++ b/util-linux/nsenter.c @@ -9,6 +9,7 @@ //config:config NSENTER //config: bool "nsenter (6.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Run program with namespaces of other processes. diff --git a/util-linux/pivot_root.c b/util-linux/pivot_root.c index ecc891100..42383c3d3 100644 --- a/util-linux/pivot_root.c +++ b/util-linux/pivot_root.c @@ -11,6 +11,7 @@ //config:config PIVOT_ROOT //config: bool "pivot_root (1.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The pivot_root utility swaps the mount points for the root filesystem //config: with some other mounted filesystem. This allows you to do all sorts diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c index f11c62292..2cf5b3fb8 100644 --- a/util-linux/readprofile.c +++ b/util-linux/readprofile.c @@ -34,6 +34,7 @@ //config:config READPROFILE //config: bool "readprofile (7.1 kb)" //config: default y +//config: #depends on PLATFORM_LINUX //config: help //config: This allows you to parse /proc/profile for basic profiling. diff --git a/util-linux/rtcwake.c b/util-linux/rtcwake.c index eac16077d..a17e82a0b 100644 --- a/util-linux/rtcwake.c +++ b/util-linux/rtcwake.c @@ -25,6 +25,7 @@ //config:config RTCWAKE //config: bool "rtcwake (6.8 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Enter a system sleep state until specified wakeup time. diff --git a/util-linux/setarch.c b/util-linux/setarch.c index cf8ef0064..1ec07b6f2 100644 --- a/util-linux/setarch.c +++ b/util-linux/setarch.c @@ -9,6 +9,7 @@ //config:config SETARCH //config: bool "setarch (3.6 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The linux32 utility is used to create a 32bit environment for the //config: specified program (usually a shell). It only makes sense to have @@ -18,12 +19,14 @@ //config:config LINUX32 //config: bool "linux32 (3.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Alias to "setarch linux32". //config: //config:config LINUX64 //config: bool "linux64 (3.3 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Alias to "setarch linux64". diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c index 6904cf019..60229770d 100644 --- a/util-linux/setpriv.c +++ b/util-linux/setpriv.c @@ -9,6 +9,7 @@ //config:config SETPRIV //config: bool "setpriv (6.6 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: select LONG_OPTS //config: help //config: Run a program with different Linux privilege settings. diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c index e2ff4b5cc..4caa28935 100644 --- a/util-linux/swaponoff.c +++ b/util-linux/swaponoff.c @@ -9,6 +9,7 @@ //config:config SWAPON //config: bool "swapon (15 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: Once you have created some swap space using 'mkswap', you also need //config: to enable your swap space with the 'swapon' utility. The 'swapoff' @@ -35,6 +36,7 @@ //config:config SWAPOFF //config: bool "swapoff (14 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: //config:config FEATURE_SWAPONOFF_LABEL //config: bool "Support specifying devices by label or UUID" diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index 901c0b8db..23de78957 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -9,6 +9,7 @@ //config:config SWITCH_ROOT //config: bool "switch_root (5.5 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: The switch_root utility is used from initramfs to select a new //config: root device. Under initramfs, you have to use this instead of diff --git a/util-linux/uevent.c b/util-linux/uevent.c index db11746d0..abbefbdce 100644 --- a/util-linux/uevent.c +++ b/util-linux/uevent.c @@ -6,6 +6,7 @@ //config:config UEVENT //config: bool "uevent (3.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: uevent is a netlink listener for kernel uevent notifications //config: sent via netlink. It is usually used for dynamic device creation. diff --git a/util-linux/umount.c b/util-linux/umount.c index 23da32868..6924a97e3 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -10,6 +10,7 @@ //config:config UMOUNT //config: bool "umount (5.1 kb)" //config: default y +//config: depends on PLATFORM_LINUX //config: help //config: When you want to remove a mounted filesystem from its current mount //config: point, for example when you are shutting down the system, the diff --git a/util-linux/unshare.c b/util-linux/unshare.c index 06b938074..1fc1d8c43 100644 --- a/util-linux/unshare.c +++ b/util-linux/unshare.c @@ -10,6 +10,7 @@ //config: bool "unshare (7.2 kb)" //config: default y //config: depends on !NOMMU +//config: depends on PLATFORM_LINUX //config: select LONG_OPTS //config: help //config: Run program with some namespaces unshared from parent. -- 2.30.2 From mjt at tls.msk.ru Fri Nov 4 16:49:48 2022 From: mjt at tls.msk.ru (Michael Tokarev) Date: Fri, 4 Nov 2022 19:49:48 +0300 Subject: [PATCH] Fix non-Linux builds Message-ID: <20221104164948.95918-1-mjt@msgid.tls.msk.ru> From: Samuel Thibault Some features are Linux-only. Also, libresolv is used on all GNU platforms, notably GNU/Hurd and GNU/kfreeBSD. --- coreutils/dd.c | 20 ++++++++++++++++++-- networking/traceroute.c | 2 ++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/coreutils/dd.c b/coreutils/dd.c index 06c1b7b9c..3e034eb1e 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c @@ -200,6 +200,7 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) } #if ENABLE_FEATURE_DD_IBS_OBS +# ifdef O_DIRECT static int clear_O_DIRECT(int fd) { if (errno == EINVAL) { @@ -211,6 +212,7 @@ static int clear_O_DIRECT(int fd) } return 0; } +# endif #endif static ssize_t dd_read(void *ibuf, size_t ibs) @@ -225,8 +227,10 @@ static ssize_t dd_read(void *ibuf, size_t ibs) #endif n = safe_read(ifd, ibuf, ibs); #if ENABLE_FEATURE_DD_IBS_OBS +# ifdef O_DIRECT if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd)) goto read_again; +# endif #endif return n; } @@ -239,8 +243,10 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs, IF_FEATURE_DD_IBS_OBS(write_again:) n = full_write(ofd, buf, len); #if ENABLE_FEATURE_DD_IBS_OBS +# ifdef O_DIRECT if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd)) goto write_again; +# endif #endif #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE @@ -501,8 +507,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) if (infile) { int iflag = O_RDONLY; #if ENABLE_FEATURE_DD_IBS_OBS - if (G.flags & FLAG_IDIRECT) + if (G.flags & FLAG_IDIRECT) { +# ifdef O_DIRECT iflag |= O_DIRECT; +# else + bb_error_msg_and_die("O_DIRECT not supported on this platform"); +# endif + } #endif xmove_fd(xopen(infile, iflag), ifd); } else { @@ -516,8 +527,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) if (G.flags & FLAG_APPEND) oflag |= O_APPEND; #if ENABLE_FEATURE_DD_IBS_OBS - if (G.flags & FLAG_ODIRECT) + if (G.flags & FLAG_ODIRECT) { +# ifdef O_DIRECT oflag |= O_DIRECT; +# else + bb_error_msg_and_die("O_DIRECT not supported on this platform"); +# endif + } #endif xmove_fd(xopen(outfile, oflag), ofd); diff --git a/networking/traceroute.c b/networking/traceroute.c index fb9315db5..760ed6d64 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -964,8 +964,10 @@ traceroute_init(int op, char **argv) if (af == AF_INET) { xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); #if ENABLE_FEATURE_TRACEROUTE_VERBOSE +# ifdef IP_PKTINFO /* want recvmsg to report target local address (for -v) */ setsockopt_1(rcvsock, IPPROTO_IP, IP_PKTINFO); +# endif #endif } #if ENABLE_TRACEROUTE6 -- 2.30.2 From mjt at tls.msk.ru Fri Nov 4 17:33:24 2022 From: mjt at tls.msk.ru (Michael Tokarev) Date: Fri, 4 Nov 2022 20:33:24 +0300 Subject: [PATCH] buildsys: resurrect PLATFORM_LINUX and depend on it for linux-specific applets In-Reply-To: <20221104164927.95804-1-mjt@msgid.tls.msk.ru> References: <20221104164927.95804-1-mjt@msgid.tls.msk.ru> Message-ID: <66d37c76-64da-e891-de3b-da9573cf8ae5@msgid.tls.msk.ru> Just a bit of context I failed to add. I'm aware of the previous issues there, http://lists.busybox.net/pipermail/busybox/2011-February/074954.html was the reason it was changed from "depends on linux" to "select linux". It was a wrong thing to do, instead, PLATFORM_LINUX should have been made a non-user-selectable symbol whith automatic value depending on the actual platform in question. This is an attempt to do just that. Thanks, /mjt 04.11.2022 19:49, Michael Tokarev wrote: > This effectively reverts the following two commits: > > commit e3b1a1fd28558f7a1b3c0ec33313bedb675be8a1 > Author: Denys Vlasenko > Date: Sat Feb 26 22:24:08 2011 +0100 > > Replace "depends on PLATFORM_LINUX" with "select PLATFORM_LINUX" > > and > > commit 5c69ad0ecdc18cf51b312c7c82848f4438fe1c8d > Author: Ron Yorston > Date: Tue Aug 4 08:24:19 2020 +0100 > > build system: drop PLATFORM_LINUX > > but does, hopefully, the right thing. > > Original complain was that the allnoconfig turns off PLATFORM_LINUX > on which all linux-specific applets depends. Instead of setting this > config option right for linux and non-linux (initially it was just a > regular kconfig symbol, not set depending on the platform), it were > turned into something which made little sense (in the first commit), > and later dropped completely. > > So introduce a dynamic kconfig symbol PLATFORM_LINUX with the value > actually depending on the target platform, so that it is not affected > by all{yes|no|whatever}config. This way, it is possible to depend on > it for linux-specific applets without breaking *config anymore. > > It is done by creating a small kconfig fragment, .platform.in, to > define just PLATFORM_LINUX symbol. It is created in Makefile if > ${CPP} has __linux__ #defined. And include it in the top-level Config.in. > > Regenerate default config files with the new symbol. > > And mark all the applets which were marked as "select PLATFORM_LINUX" > before the "build system: drop PLATFORM_LINUX" commit, as > "depends on PLATFORM_LINUX". > > Also mark 2 other applets, tc and dhcprelay, as linux-only too. > > This way, it is finally possible to build busybox on other platforms > without really huge efforts to maintain list of "incompatible" applets > externally, and does not put any pressure on the main development, - > the only thing needed is to keep the existing "depends on PLATFORM_LINUX" > lines. > > Signed-off-by: Michael Tokarev > --- ... From mjt at tls.msk.ru Fri Nov 4 17:35:47 2022 From: mjt at tls.msk.ru (Michael Tokarev) Date: Fri, 4 Nov 2022 20:35:47 +0300 Subject: [PATCH] Fix non-Linux builds In-Reply-To: <20221104164948.95918-1-mjt@msgid.tls.msk.ru> References: <20221104164948.95918-1-mjt@msgid.tls.msk.ru> Message-ID: <6bc1763f-7862-78d3-59f7-18ef854bc747@msgid.tls.msk.ru> 04.11.2022 19:49, Michael Tokarev wrote: > From: Samuel Thibault > > Some features are Linux-only. And this is what's left from the patch by Samuel sent in October - only the actual source changes. Maybe some bits could be done in a more compact way, with less ifdeffery. /mjt From explorer09 at gmail.com Mon Nov 7 05:25:06 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Mon, 7 Nov 2022 13:25:06 +0800 Subject: [PATCH] buildsys: resurrect PLATFORM_LINUX and depend on it for linux-specific applets In-Reply-To: <20221104164927.95804-1-mjt@msgid.tls.msk.ru> References: <20221104164927.95804-1-mjt@msgid.tls.msk.ru> Message-ID: On Sat, Nov 5, 2022 at 12:55 AM Michael Tokarev wrote: > diff --git a/Makefile b/Makefile > index 503475fe9..ad780c261 100644 > --- a/Makefile > +++ b/Makefile > @@ -361,9 +361,16 @@ scripts/basic/%: scripts_basic ; > > # This target generates Kbuild's and Config.in's from *.c files > PHONY += gen_build_files > -gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(wildcard $(srctree)/embed/*) > +gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(wildcard $(srctree)/embed/*) .platform.in > $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) > > +.platform.in: > + $(Q)printf '#ifndef __linux__\nplatform_is_not_linux\n#endif' \ > + | $(CPP) - | grep -s platform_is_not_linux \ > + && linux=n || linux=y; \ > + printf "config PLATFORM_LINUX\n\tbool\n\tdefault $$linux\n" > $@ > +MRPROPER_FILES += .platform.in > + > # bbox: we have helpers in applets/ > # we depend on scripts_basic, since scripts/basic/fixdep > # must be built before any other host prog What is the reason for preferring #ifndef check rather than #ifdef? I mean, that would make PLATFORM_LINUX defaults to y if the compiler fails, and I would expect n in that case. And I'm curious. Does Busybox's kconfig system supports macros as described in ? If the system supports macros, we can put this in the Kconfig file and simplify a lot of things: config PLATFORM_LINUX bool default $(shell, { printf '#ifndef __linux__\n#error \n#endif\n' \ | $(CPP) - -o /dev/null; } >/dev/null 2>&1 && echo y || echo n) From mjt at tls.msk.ru Mon Nov 7 05:38:16 2022 From: mjt at tls.msk.ru (Michael Tokarev) Date: Mon, 7 Nov 2022 08:38:16 +0300 Subject: [PATCH] buildsys: resurrect PLATFORM_LINUX and depend on it for linux-specific applets In-Reply-To: References: <20221104164927.95804-1-mjt@msgid.tls.msk.ru> Message-ID: <4d236173-3eed-4341-68a3-7565c428e9d5@msgid.tls.msk.ru> 07.11.2022 08:25, Kang-Che Sung wrote: > On Sat, Nov 5, 2022 at 12:55 AM Michael Tokarev wrote: > >> diff --git a/Makefile b/Makefile >> +.platform.in: >> + $(Q)printf '#ifndef __linux__\nplatform_is_not_linux\n#endif' \ >> + | $(CPP) - | grep -s platform_is_not_linux \ >> + && linux=n || linux=y; \ >> + printf "config PLATFORM_LINUX\n\tbool\n\tdefault $$linux\n" > $@ > What is the reason for preferring #ifndef check rather than #ifdef? > I mean, that would make PLATFORM_LINUX defaults to y if the compiler fails, > and I would expect n in that case. That's exactly the goal, - to make linux the default, that's the reason I changed from ifdef linux to ifndef. The idea is to bring as few burden to the main authors as possible, - if this doesn't work, their favorite platform wont be affected. See the email I referred to in other message - http://lists.busybox.net/pipermail/busybox/2011-February/074954.html - from 11 years ago, - this is when "depends on LINUX" were (mistakenly) changed to "select LINUX" in the first place, making it effectively impossible to build busybox on non-linux. > And I'm curious. Does Busybox's kconfig system supports macros as described in > ? > If the system supports macros, we can put this in the Kconfig file and simplify > a lot of things: > > config PLATFORM_LINUX > bool > default $(shell, { printf '#ifndef __linux__\n#error \n#endif\n' \ > | $(CPP) - -o /dev/null; } >/dev/null 2>&1 && echo y || echo n) No, - busybox's kconfig is much simpler than that, as far as I can see, it is a fork off a much earlier kconfig language. Thanks, /mjt From steffen at sdaoden.eu Mon Nov 7 19:41:34 2022 From: steffen at sdaoden.eu (Steffen Nurpmeso) Date: Mon, 07 Nov 2022 20:41:34 +0100 Subject: FS="\0" differences Message-ID: <20221107194134.i5yN8%steffen@sdaoden.eu> Hello. I do not know how portable / desired, but stumbled upon #?0|kent:src$ printf 'a\0b\0c\0' | gawk 'BEGIN{FS="\0"} {for(i=0; i < NF; ++i) print i, $i}' 0 abc 1 a 2 b 3 c #?0|kent:src$ printf 'a\0b\0c\0' | mawk 'BEGIN{FS="\0"} {for(i=0; i < NF; ++i) print i, $i}' 0 abc 1 a 2 b 3 c #?0|kent:src$ printf 'a\0b\0c\0' | nawk 'BEGIN{FS="\0"} {for(i=0; i < NF; ++i) print i, $i}' 0 a #?0|kent:src$ printf 'a\0b\0c\0' | busybox.static awk 'BEGIN{FS="\0"} {for(i=0; i < NF; ++i) print i, $i}' 0 a 0 b 0 c For nawk this is https://github.com/onetrueawk/awk/issues/165. Ciao, --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt) From steffen at sdaoden.eu Mon Nov 7 20:16:02 2022 From: steffen at sdaoden.eu (Steffen Nurpmeso) Date: Mon, 07 Nov 2022 21:16:02 +0100 Subject: [PATCH v4] shell: exchange Dijkstra $(( )) evaluator.. In-Reply-To: <09f36b9e8c5793662b0f788b3396d02e7f1cb9ed.1661902741.git.steffen@sdaoden.eu> References: <09f36b9e8c5793662b0f788b3396d02e7f1cb9ed.1661902741.git.steffen@sdaoden.eu> Message-ID: <20221107201602.EXBne%steffen@sdaoden.eu> Hey, Steffen Nurpmeso wrote in <09f36b9e8c5793662b0f788b3396d02e7f1cb9ed.1661902741.git.steffen at sdaoden\ .eu>: |The former implementation was not correct regarding whiteouts in |?: conditional branches. The new one also parses a bit better, in |effect on equal level than bash with its recursive descendent parser. I am quite sorry on how this was happening. Anyhow, i stumbled upon a bug that somehow did not trigger for months - su_ALIGNOF(sizeof(*sasp->sas_ops) * 2)) + (su_ALIGNOF(*sasp->sas_ops) * 2)) a_SHEXP_ARITH_ERROR_TRACK( + sizeof(*sasp->sas_error_track) * 2 )) )){ @@ -433,7 +432,7 @@ jenomem: ++i; j = su_ALIGNOF(*sasp->sas_nums) * (i >> 1); - o = su_ALIGNOF(sizeof(*sasp->sas_ops) * i); + o = su_ALIGNOF(*sasp->sas_ops) * i; Two out of four were used falsely, and i did not see it. Does not trigger with my default build of busybox, but did trigger with my MUA upon syntax error (r=(xa ((512 + 511) & ~511) >> 9)). I did then change to "normal alignment directives", saving some alloc space. Anyhow -- i was so shocked i immediately embedded the entire header into math.c, using tabulator indentation and up to ~120 columns, ripping off practically all compat shims. 'Had to remove the >>> unsigned right shift operator to get away with only arith_t, and its support. Not yet ready, 'want to have this running a few days. But geee, i was _so_ thrilled to come back to tabulators after seeing how nice it can be to work with a 120{-140} column screen, and how many bytes that saves! Only did 80 (79) for all my life!! 'Only working with ~<30% of my screen width. I immediately changed two old projects of mine accordingly, and think will turn all to the new era of wide screens. So it is. Ciao! --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt) From steffen at sdaoden.eu Tue Nov 8 21:15:35 2022 From: steffen at sdaoden.eu (Steffen Nurpmeso) Date: Tue, 08 Nov 2022 22:15:35 +0100 Subject: FS="\0" differences In-Reply-To: <20221107194134.i5yN8%steffen@sdaoden.eu> References: <20221107194134.i5yN8%steffen@sdaoden.eu> Message-ID: <20221108211535.sDkE3%steffen@sdaoden.eu> Steffen Nurpmeso wrote in <20221107194134.i5yN8%steffen at sdaoden.eu>: |I do not know how portable / desired, but stumbled upon | | #?0|kent:src$ printf 'a\0b\0c\0' | gawk 'BEGIN{FS="\0"} {for(i=0; \ | i < NF; ++i) print i, $i}' | 0 abc | 1 a | 2 b | 3 c | #?0|kent:src$ printf 'a\0b\0c\0' | mawk 'BEGIN{FS="\0"} {for(i=0; \ | i < NF; ++i) print i, $i}' | 0 abc | 1 a | 2 b | 3 c | #?0|kent:src$ printf 'a\0b\0c\0' | nawk 'BEGIN{FS="\0"} {for(i=0; \ | i < NF; ++i) print i, $i}' | 0 a | #?0|kent:src$ printf 'a\0b\0c\0' | busybox.static awk 'BEGIN{FS="\0"} \ | {for(i=0; i < NF; ++i) print i, $i}' | 0 a | 0 b | 0 c | |For nawk this is https://github.com/onetrueawk/awk/issues/165. They closed it after Arnold "Aharon" Robbins from [gn]awk stated that whereas gawk uses pointer+length to store strings, nawk only uses C-style strings. It would thus require a massive change. (He also pointed out that POSIX states the behaviour is undefined in the case, and that awk was made for text not binary thus NUL is not expected to happen.) For busybox however i still find the behaviour odd, and i would love to see it en par with [gm]awk. --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt) From steffen at sdaoden.eu Tue Nov 8 21:15:58 2022 From: steffen at sdaoden.eu (Steffen Nurpmeso) Date: Tue, 08 Nov 2022 22:15:58 +0100 Subject: [PATCH v5] shell: exchange Dijkstra $(( )) evaluator.. Message-ID: <195379cd4b8e7ea5b0136cbd74a8fb7cb4366c98.1667864866.git.steffen@sdaoden.eu> The former implementation was not correct regarding whiteouts in ?: conditional branches. The new one also parses a bit better, in effect on equal level than bash with its recursive descendent parser. A patch iteration saw bugfixes suggested by Harald van Dijk. function old new delta static.arith__eval - 1852 +1852 arith__op_apply - 1510 +1510 arith__val_eval - 272 +272 arith 14 269 +255 arith_op_toks - 186 +186 strto_arith_t - 156 +156 static.arith__ws_squeeze - 147 +147 .rodata 105081 105163 +82 arith__op_apply_colons - 75 +75 ash_arith 126 123 -3 op_tokens 141 - -141 arith_lookup_val 193 - -193 arith_apply 1044 - -1044 evaluate_string 1146 - -1146 ------------------------------------------------------------------------------ (add/remove: 7/4 grow/shrink: 2/1 up/down: 4535/-2527) Total: 2008 bytes text data bss dec hex filename 1928911 32444 29370 1990725 1e6045 busybox_old 1930919 32444 29370 1992733 1e681d busybox_unstripped --- shell/Config.src | 8 + shell/ash.c | 6 +- shell/ash_test/ash-arith/bigbadbison.right | 873 +++++++++ shell/ash_test/ash-arith/bigbadbison.tests | 907 ++++++++++ shell/hush.c | 23 +- shell/hush_test/hush-arith/bigbadbison.right | 873 +++++++++ shell/hush_test/hush-arith/bigbadbison.tests | 907 ++++++++++ shell/math.c | 1695 +++++++++++------- shell/math.h | 9 +- 9 files changed, 4694 insertions(+), 607 deletions(-) create mode 100644 shell/ash_test/ash-arith/bigbadbison.right create mode 100755 shell/ash_test/ash-arith/bigbadbison.tests create mode 100644 shell/hush_test/hush-arith/bigbadbison.right create mode 100755 shell/hush_test/hush-arith/bigbadbison.tests diff --git a/shell/Config.src b/shell/Config.src index 5efbf99959..32aaab58e8 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -108,6 +108,14 @@ config FEATURE_SH_MATH_BASE default y depends on FEATURE_SH_MATH +config FEATURE_SH_MATH_ERROR_TRACK + bool "Extend POSIX math support with error location tracking" + default y + depends on FEATURE_SH_MATH + help + Enable error location tracking in the shell's math support. + Without it only the type of error will be logged. + config FEATURE_SH_EXTRA_QUIET bool "Hide message on interactive shell startup" default y diff --git a/shell/ash.c b/shell/ash.c index 326f8b2a98..af3db6162e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6034,8 +6034,12 @@ ash_arith(const char *s) INT_OFF; result = arith(&math_state, s); - if (math_state.errmsg) + if (math_state.errmsg) { ash_msg_and_raise_error(math_state.errmsg); +# if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + free(math_state.errmsg); +# endif + } INT_ON; return result; diff --git a/shell/ash_test/ash-arith/bigbadbison.right b/shell/ash_test/ash-arith/bigbadbison.right new file mode 100644 index 0000000000..3f3e95700a --- /dev/null +++ b/shell/ash_test/ash-arith/bigbadbison.right @@ -0,0 +1,873 @@ += BASE +<0> +<0> +<1> +<0> +<0> +<0> +<0> +<1> +<1> +<1> +<0> +<10> +<9191919191919> +<13> +<11> +<1023> +<1295> +<1295> +<9322365> +<16242915> +<10> +<33> +<10> +<33> +<1> +<1> +<1> +<33> +<33> +<33> +<33> += UNA PLUS/MINUS +<0> +<0> +<1> +<1> +<4221> +<16929> +<16242915> +<16242915> +<1> +<1> +<1> +<0> +<0> +<-1> +<-1> +<-4221> +<-16929> +<-16242915> +<-16242915> +<-1> +<-1> +<-1> +<-1> +<1> +<-1> += UNA ! +<1> +<1> +<0> +<0> +<1> +<0> += UNA ~ +<-1> +<-1> +<-2> +<-2> +<-2276> +<0> +<0> +<-1> +<-1> +<-1> +<-1> += BIN + +<0> +<0> +<1> +<1> +<1> +<1> +<2> +<2> +<2> +<-2> +<3333> +<3333> +<33> +<-33> +<-33> +<-1> +<33> +<-33> +<-33> +<1> +<9223372036854775807> +<-9223372036854775807> +<9223372036854775806> +<-9223372036854775808> +<-2> +<0> +<9223372036854775797> +<-9223372036854775797> +<9223372036854775796> +<-9223372036854775798> +<-12> +<10> += BIN - +<0> +<0> +<-1> +<-1> +<1> +<1> +<0> +<0> +<0> +<0> +<-1111> +<1111> +<-1> +<1> +<1> +<129> +<1> +<-1> +<-1> +<129> +<-9223372036854775807> +<9223372036854775807> +<-9223372036854775808> +<9223372036854775806> +<0> +<-2> +<-9223372036854775797> +<9223372036854775797> +<-9223372036854775798> +<9223372036854775796> +<10> +<-12> += BIN * +<0> +<0> +<0> +<0> +<0> +<0> +<1> +<1> +<2468642> +<2468642> +<272> +<272> +<272> +<-4160> +<272> +<272> +<272> +<-4160> +<-9223372036854775808> +<-9223372036854775808> +<-9223372036854775807> +<9223372036854775807> +<1> +<-1> +<-9223372036854775808> +<-9223372036854775808> +<-9223372036854775797> +<9223372036854775797> +<11> +<-11> += BIN / +<0> +<1> +<1> +<0> +<2> +<0> +<0> +<0> +<0> +<1> +<1> +<1> +<-1> +<2> +<3> +<1> +<1> +<0> +<0> +<-9223372036854775808> +<-9223372036854775808> +<-9223372036854775807> +<9223372036854775807> +<1> +<-1> +<838488366986797800> +<-838488366986797800> +<-838488366986797800> +<838488366986797800> +<0> +<0> += BIN % +<0> +<0> +<0> +<1111> +<0> +<16> +<-16> +<-16> +<64> +<1> +<-1> +<-1> +<1> +<0> +<0> +<1> +<0> +<3> +<-1> +<0> +<0> +<0> +<0> +<0> +<0> +<-8> +<-8> +<7> +<7> +<-1> +<-1> += BIN << +<0> +<0> +<0> +<0> +<1> +<1> +<2> +<2> +<78179674781384704> +<18639486976> +<2097152> +<-2251799813685248> +<-2251799813685248> +<0> +<1114112> +<-4785074604081152> +<-4785074604081152> +<65> +<64> +<0> +<0> +<-9223372036854775808> +<-2> +<-9223372036854775808> +<-2> +<0> +<0> +<-9007199254740992> +<-2048> +<-9007199254740992> +<-2048> += BIN >> +<0> +<0> +<0> +<0> +<1> +<1> +<0> +<0> +<0> +<0> +<0> +<-1> +<-1> +<0> +<0> +<-1> +<-1> +<65> +<64> +<-1> +<-4611686018427387904> +<0> +<4611686018427387903> +<-1> +<-1> +<-1024> +<-4503599627370496> +<1023> +<4503599627370495> +<-1> +<-1> += BIN ** +<0> +<2> +<4> +<8> +<16> +<10000> +<10000000000> +<100005> +<10000000000> += LOG OR +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> += LOG AND +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<0> +<0> += BIN BIT_OR +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<3327> +<3327> +<17> +<-1> +<-1> +<-1> +<17> +<-1> +<-1> +<-63> +<1088> +<-1> +<-9223372036854775807> +<-1> +<9223372036854775807> +<-1> +<-1> +<-11> +<-9223372036854775797> +<-1> +<9223372036854775807> +<-1> +<-1> += BIN BIT_XOR +<0> +<0> +<1> +<1> +<1> +<1> +<0> +<0> +<3321> +<3321> +<1> +<31> +<31> +<-1> +<1> +<31> +<31> +<-127> +<1088> +<9223372036854775807> +<-9223372036854775807> +<-9223372036854775808> +<9223372036854775806> +<0> +<-2> +<9223372036854775797> +<-9223372036854775797> +<-9223372036854775798> +<9223372036854775796> +<10> +<-12> += BIN BIT_AND +<0> +<0> +<0> +<0> +<0> +<0> +<1> +<1> +<6> +<6> +<16> +<-32> +<-32> +<0> +<16> +<-32> +<-32> +<64> +<0> +<-9223372036854775808> +<0> +<9223372036854775807> +<1> +<-1> +<1> +<-9223372036854775808> +<0> +<9223372036854775797> +<11> +<-11> +<11> += BIN EQ +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<1> += BIN NE +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<0> += BIN LE +<1> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<0> +<1> += BIN GE +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<1> +<0> += BIN LT +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<0> +<1> += BIN GT +<0> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<1> +<0> += PRECEDENCE I +<6> +<2> +<0> +<2> +<-1> +<1> +<1> +<2> +<8> +<7> +<12> +<5> +<10> +<1> +<72> +<48> +<288> +<1> +<3> +<1> +<4> +<76> +<1> +<1> +<1> +<1> +<2> +<2> += PARENS +<6> +<6> +<-4> +<-4> +<2> +<2> +<0> +<0> +<-3> +<-3> +<0> +<0> +<12> +<12> +<10> +<10> +<12> +<48> +<1> +<1> +<6> +<6> +<9> +<9> +<20> +<20> +<21> +<21> +<36864> +<36864> +<6> +<6> +<9> +<9> +<9> +<9> +<0> +<0> +<38> +<38> +<2> +<2> +<32> +<32> +<0> +<0> +<24> +<24> += ASSIGN I +<3><3> +<3><3> +<3><3> +<11><11> +<9><9> +<10><10> +<20><20> +<10><10> +<5><5> +<0><0> +<0><0> +<10><10> +<100><100> +<100><100> +<11><11> +<11><11> +<10><10> +<2><2> +<5><5> +<20><20> += ASSIGN II +<2><3> +<4><3> +<36><5><7> +<1501><100><15> +<3><3> +<10><1><2><3><10> += POSTFIX +<1><2> +<1><2><1> +<10><2><11> +<10><2><11> +<1><0> +<1><0><1> +<10><0><9> +<10><0><9> += PREFIX +<2><2> +<2><2><2> +<22><2><11> +<10><1><10> +<22><2><11> +<0><0> +<0><0><0> +<9><1><9> +<10><1><10> +<0><0><9> += VAR RECUR +<2><1 + 1> +<2><1 + 1> +<3><3> +<2><3> +<3><1 + 1> +<4><1 + 1 * 2> +<5><(1 + 1) * 2> +<3><3><3 / 2> +<2><2> +<2><2> +<3><3> +<4><4> +<5><5> +<5><5><3 / 2> += COMMA +<2> +<3> +<4> +<4> +<133><133> +<10><10> += COND +<3> +<3> +<2> +<3> +<2> +<2> +<111> +<5> +<7> +<5> +<5> +<7> +<7> +<7> +<7> +<5> +-- COND .2 +<-1> +<0> +<1> +<1> +<32> +<32> +<1> +<1> +<32> +-- COND .3 +<3> +<4> +<3> +<3> +<3> +<4> +<3> +<3> +<3> +<4> +<1> +<4> +<5> +<2> +<10> +<10> +<10> +<10> +<10> +<2> +<10> +<10> +<10> +<10> +<10> +<2> +<5> +<5> +<8> +<8> +<10> +<10> +<10> +<10> +<10> +-- COND .4 +<5> +<6> +<7> +<8> +<9> +<12> +<10> +<12> +<10> +-- COND .5 +<12> +<10> +<12> +<10> +-- COND .6 +<12> +<9> +<-2> +<-1> +<23> +<26> +<24> +<0> +<23> +<23> +<23> +-- COND .7 +<16><2><3><16><5> +<16><2><3><16><5> +<16><2><3><16><5> +<25><2><3><4><25><> +<9><2><9><4><5> +<9><2><9><4><5> +<9><2><9><4><5> +<9><2><9><4><5> +<9><2><9><4><5> +<16><2><3><16><5> +<9><2><9><4><5><> +<4><4><3><4><5><> +-- COND .8 +<10><2> +<20><0> +<10><10> +<20><0> +<10><10> +<20><0> +<20><20> +-- COND .9 +<2><+E+><1+1> +<2><1+1><+E+> +<2><+E+><2> +<1><1><+E+> +<4><+E+><4> +<4><4><+E+> +-- COND .10 +<-1><+E+><+E+><+E+><-1> +<2><1><2><+E+><+E+> +<3><0><+E+><3><+E+> += WILD I +<14> +<1> +<1> +<1> +<3> +<87> +<2097152> +<20><10> +<100><10> +<0><10> += WILD II +<36><11> +<33><11> +<36><12> +<39><12> +<39><12> +<-33><12> +<-27> +<20><10> +<21><11> +<20><10> +<21><11> +<21><11> +<20><10> +<20><10> +<21> +<21> +<21> += WILD RECUR +<20><20><10> +<10><10> +<11><11> +<21><11> +<10><10> +<1><1> +<6><6><6> +<10><10><5> +<12><12> +<12><12> +<10><11> +<10><11> +<10><10><5> +<6><6> +<10><10> +<10><0><10><20> +<10><6><10><20> +<10><10><10><20> +<50><50><10><20> +<50><50><10><20> +<500><500><10><20> diff --git a/shell/ash_test/ash-arith/bigbadbison.tests b/shell/ash_test/ash-arith/bigbadbison.tests new file mode 100755 index 0000000000..0e01c6fe6a --- /dev/null +++ b/shell/ash_test/ash-arith/bigbadbison.tests @@ -0,0 +1,907 @@ +# make this work with (ba)sh \ +command -v shopt && shopt -s expand_aliases;\ +alias p=printf;alias e=echo;alias s=export +s I=10 J=33 +e '= BASE' +e "<$(())>" +e "<$(( ))>" +e "<$((1))>" +e "<$((0))>" +e "<$((0x0))>" +e "<$((0X0))>" +e "<$((000))>" +e "<$((000000000000001))>" +e "<$((2#00000000000000000000000000000000000001))>" +e "<$((0X00000000000000000000000000000000000000000001))>" +e "<$((999999999999999999999999999999999999999999999))>" +e "<$(( 10 ))>" +e "<$((9191919191919))>" +e "<$((0xD))>" +e "<$((013))>" +e "<$((32#VV))>" +e "<$((36#ZZ))>" +e "<$((36#zz))>" +e "<$(( 64#zzZZ ))>" +e "<$((64#ZZzz))>" +e "<$((I))>" +e "<$((J))>" +e "<$(( I ))>" +e "<$(( J ))>" +e "<$(( (1) ))>" +e "<$((((1))))>" +e "<$(((((1)))))>" +e "<$(( (J) ))>" +e "<$((((J))))>" +e "<$(((((J)))))>" +e "<$(( ( ( ( J ) ) ) ))>" +e '= UNA PLUS/MINUS' +e "<$((+0))>" +e "<$(( + 0 ))>" +e "<$(( +1))>" +e "<$((+ 1 ))>" +e "<$(( + 4221 ))>" +e "<$(( +0x4221 ))>" +e "<$(( + 64#ZZzz ))>" +e "<$(( +64#ZZzz ))>" +e "<$((+ (1) ))>" +e "<$((+((1))))>" +e "<$((+(((1)))))>" +e "<$((-0))>" +e "<$(( - 0 ))>" +e "<$(( -1))>" +e "<$((- 1 ))>" +e "<$(( - 4221 ))>" +e "<$(( -0x4221 ))>" +e "<$(( - 64#ZZzz ))>" +e "<$(( -64#ZZzz ))>" +e "<$((- (1) ))>" +e "<$((-((1))))>" +e "<$((-(((1)))))>" +e "<$((+ -(1) ))>" +e "<$((+(-(-1))))>" +e "<$((+(-(-(-1)))))>" +e '= UNA !' +e "<$((!0))>" +e "<$((! 00000000))>" +e "<$((!1))>" +e "<$((! 0x00001))>" +e "<$((! - 0))>" +e "<$((!-1))>" +e '= UNA ~' +e "<$((~0))>" +e "<$((~ 00000000))>" +e "<$((~1))>" +e "<$((~ 0x00001))>" +e "<$((~ 64#zz))>" +e "<$((~-1))>" +e "<$((~ - 1))>" +e "<$((~-0))>" +e "<$((~ - 0))>" +e "<$((~(-0)))>" +e "<$((~((- 0))))>" +e '= BIN +' +e "<$((0+0))>" +e "<$(( 0 + 0 ))>" +e "<$((0+1))>" +e "<$(( 0 + 1 ))>" +e "<$((1+0))>" +e "<$(( 1 + 0 ))>" +e "<$((1+1))>" +e "<$(( 1 + 1 ))>" +e "<$(( (1 + 1) ))>" +e "<$(((((((-1)))) + (((-1))))))>" +e "<$((1111+2222))>" +e "<$((2222+1111))>" +e "<$(( +0x10 + +0x11 ))>" +e "<$(( -0x10 + -0x11 ))>" +e "<$(( -0x10 + -0x11 ))>" +e "<$(( +64#10 + -64#11 ))>" +e "<$(( +0x11 + +0x10 ))>" +e "<$(( -0x11 + -0x10 ))>" +e "<$(( -0x11 + -0x10 ))>" +e "<$(( +64#11 + -64#10 ))>" +e "<$((0x8000000000000000+-1))>" +e "<$((0x8000000000000000+1))>" +e "<$((0x7FFFFFFFFFFFFFFF+-1))>" +e "<$((0x7FFFFFFFFFFFFFFF+1))>" +e "<$((0xFFFFFFFFFFFFFFFF+-1))>" +e "<$((0xFFFFFFFFFFFFFFFF+1))>" +e "<$((0x8000000000000000+-11))>" +e "<$((0x8000000000000000+11))>" +e "<$((0x7FFFFFFFFFFFFFFF+-11))>" +e "<$((0x7FFFFFFFFFFFFFFF+11))>" +e "<$((0xFFFFFFFFFFFFFFFF+-11))>" +e "<$((0xFFFFFFFFFFFFFFFF+11))>" +e '= BIN -' +e "<$((0-0))>" +e "<$(( 0 - 0 ))>" +e "<$((0-1))>" +e "<$(( 0 - 1 ))>" +e "<$((1-0))>" +e "<$(( 1 - 0 ))>" +e "<$((1-1))>" +e "<$(( 1 - 1 ))>" +e "<$(( (1 - 1) ))>" +e "<$(((((((+1)))) - (((+1))))))>" +e "<$((1111-2222))>" +e "<$((2222-1111))>" +e "<$(( +0x10 - +0x11 ))>" +e "<$(( -0x10 - -0x11 ))>" +e "<$(( -0x10 - -0x11 ))>" +e "<$(( +64#10 - -64#11 ))>" +e "<$(( +0x11 - +0x10 ))>" +e "<$(( -0x11 - -0x10 ))>" +e "<$(( -0x11 - -0x10 ))>" +e "<$(( +64#11 - -64#10 ))>" +e "<$((0x8000000000000000--1))>" +e "<$((0x8000000000000000-1))>" +e "<$((0x7FFFFFFFFFFFFFFF--1))>" +e "<$((0x7FFFFFFFFFFFFFFF-1))>" +e "<$((0xFFFFFFFFFFFFFFFF--1))>" +e "<$((0xFFFFFFFFFFFFFFFF-1))>" +e "<$((0x8000000000000000--11))>" +e "<$((0x8000000000000000-11))>" +e "<$((0x7FFFFFFFFFFFFFFF--11))>" +e "<$((0x7FFFFFFFFFFFFFFF-11))>" +e "<$((0xFFFFFFFFFFFFFFFF--11))>" +e "<$((0xFFFFFFFFFFFFFFFF-11))>" +e '= BIN *' +e "<$((0*0))>" +e "<$(( 0 * 0 ))>" +e "<$((0*1))>" +e "<$(( 0 * 1 ))>" +e "<$((1*0))>" +e "<$(( 1 * 0 ))>" +e "<$((1*1))>" +e "<$(( 1 * 1 ))>" +e "<$((1111*2222))>" +e "<$((2222*1111))>" +e "<$(( +0x10 * +0x11 ))>" +e "<$(( -0x10 * -0x11 ))>" +e "<$(( -0x10 * -0x11 ))>" +e "<$(( +64#10 * -64#11 ))>" +e "<$(( +0x11 * +0x10 ))>" +e "<$(( -0x11 * -0x10 ))>" +e "<$(( -0x11 * -0x10 ))>" +e "<$(( +64#11 * -64#10 ))>" +e "<$((0x8000000000000000*-1))>" +e "<$((0x8000000000000000*1))>" +e "<$((0x7FFFFFFFFFFFFFFF*-1))>" +e "<$((0x7FFFFFFFFFFFFFFF*1))>" +e "<$((0xFFFFFFFFFFFFFFFF*-1))>" +e "<$((0xFFFFFFFFFFFFFFFF*1))>" +e "<$((0x8000000000000000*-11))>" +e "<$((0x8000000000000000*11))>" +e "<$((0x7FFFFFFFFFFFFFFF*-11))>" +e "<$((0x7FFFFFFFFFFFFFFF*11))>" +e "<$((0xFFFFFFFFFFFFFFFF*-11))>" +e "<$((0xFFFFFFFFFFFFFFFF*11))>" +e '= BIN /' +e "<$(( 0 / 1 ))>" +e "<$((1/1))>" +e "<$(( 1 / 1 ))>" +e "<$((1111/2222))>" +e "<$((2222/1111))>" +e "<$(( +0x10 / +0x11 ))>" +e "<$(( -0x10 / -0x11 ))>" +e "<$(( -0x10 / -0x11 ))>" +e "<$(( +64#10 / -64#11 ))>" +e "<$(( +0x11 / +0x10 ))>" +e "<$(( -0x11 / -0x10 ))>" +e "<$(( -0x11 / -0x10 ))>" +e "<$(( +64#11 / -64#10 ))>" +e "<$((2/1))>" +e "<$((3/1))>" +e "<$((3/2))>" +e "<$((3/3))>" +e "<$((3/4))>" +e "<$((-1/4))>" +e "<$((0x8000000000000000/-1))>" +e "<$((0x8000000000000000/1))>" +e "<$((0x7FFFFFFFFFFFFFFF/-1))>" +e "<$((0x7FFFFFFFFFFFFFFF/1))>" +e "<$((0xFFFFFFFFFFFFFFFF/-1))>" +e "<$((0xFFFFFFFFFFFFFFFF/1))>" +e "<$((0x8000000000000000/-11))>" +e "<$((0x8000000000000000/11))>" +e "<$((0x7FFFFFFFFFFFFFFF/-11))>" +e "<$((0x7FFFFFFFFFFFFFFF/11))>" +e "<$((0xFFFFFFFFFFFFFFFF/-11))>" +e "<$((0xFFFFFFFFFFFFFFFF/11))>" +e '= BIN %' +e "<$(( 0 % 1 ))>" +e "<$((1%1))>" +e "<$(( 1 % 1 ))>" +e "<$((1111%2222))>" +e "<$((2222%1111))>" +e "<$(( +0x10 % +0x11 ))>" +e "<$(( -0x10 % -0x11 ))>" +e "<$(( -0x10 % -0x11 ))>" +e "<$(( +64#10 % -64#11 ))>" +e "<$(( +0x11 % +0x10 ))>" +e "<$(( -0x11 % -0x10 ))>" +e "<$(( -0x11 % -0x10 ))>" +e "<$(( +64#11 % -64#10 ))>" +e "<$((2%1))>" +e "<$((3%1))>" +e "<$((3%2))>" +e "<$((3%3))>" +e "<$((3%4))>" +e "<$((-1%4))>" +e "<$((0x8000000000000000%-1))>" +e "<$((0x8000000000000000%1))>" +e "<$((0x7FFFFFFFFFFFFFFF%-1))>" +e "<$((0x7FFFFFFFFFFFFFFF%1))>" +e "<$((0xFFFFFFFFFFFFFFFF%-1))>" +e "<$((0xFFFFFFFFFFFFFFFF%1))>" +e "<$((0x8000000000000000%-11))>" +e "<$((0x8000000000000000%11))>" +e "<$((0x7FFFFFFFFFFFFFFF%-11))>" +e "<$((0x7FFFFFFFFFFFFFFF%11))>" +e "<$((0xFFFFFFFFFFFFFFFF%-11))>" +e "<$((0xFFFFFFFFFFFFFFFF%11))>" +e '= BIN <<' +e "<$((0<<0))>" +e "<$(( 0 << 0 ))>" +e "<$((0<<1))>" +e "<$(( 0 << 1 ))>" +e "<$((1<<0))>" +e "<$(( 1 << 0 ))>" +e "<$((1<<1))>" +e "<$(( 1 << 1 ))>" +e "<$((1111<<2222))>" +e "<$((2222<<1111))>" +e "<$(( +0x10 << +0x11 ))>" +e "<$(( -0x10 << -0x11 ))>" +e "<$(( -0x10 << -0x11 ))>" +e "<$(( +64#10 << -64#11 ))>" +e "<$(( +0x11 << +0x10 ))>" +e "<$(( -0x11 << -0x10 ))>" +e "<$(( -0x11 << -0x10 ))>" +e "<$(( +64#11 << -64#10 ))>" +e "<$(( +64 << +1024 ))>" +e "<$((0x8000000000000000<<-1))>" +e "<$((0x8000000000000000<<1))>" +e "<$((0x7FFFFFFFFFFFFFFF<<-1))>" +e "<$((0x7FFFFFFFFFFFFFFF<<1))>" +e "<$((0xFFFFFFFFFFFFFFFF<<-1))>" +e "<$((0xFFFFFFFFFFFFFFFF<<1))>" +e "<$((0x8000000000000000<<-11))>" +e "<$((0x8000000000000000<<11))>" +e "<$((0x7FFFFFFFFFFFFFFF<<-11))>" +e "<$((0x7FFFFFFFFFFFFFFF<<11))>" +e "<$((0xFFFFFFFFFFFFFFFF<<-11))>" +e "<$((0xFFFFFFFFFFFFFFFF<<11))>" +e '= BIN >>' +e "<$((0>>0))>" +e "<$(( 0 >> 0 ))>" +e "<$((0>>1))>" +e "<$(( 0 >> 1 ))>" +e "<$((1>>0))>" +e "<$(( 1 >> 0 ))>" +e "<$((1>>1))>" +e "<$(( 1 >> 1 ))>" +e "<$((1111>>2222))>" +e "<$((2222>>1111))>" +e "<$(( +0x10 >> +0x11 ))>" +e "<$(( -0x10 >> -0x11 ))>" +e "<$(( -0x10 >> -0x11 ))>" +e "<$(( +64#10 >> -64#11 ))>" +e "<$(( +0x11 >> +0x10 ))>" +e "<$(( -0x11 >> -0x10 ))>" +e "<$(( -0x11 >> -0x10 ))>" +e "<$(( +64#11 >> -64#10 ))>" +e "<$(( +64 >> +1024 ))>" +e "<$((0x8000000000000000>>-1))>" +e "<$((0x8000000000000000>>1))>" +e "<$((0x7FFFFFFFFFFFFFFF>>-1))>" +e "<$((0x7FFFFFFFFFFFFFFF>>1))>" +e "<$((0xFFFFFFFFFFFFFFFF>>-1))>" +e "<$((0xFFFFFFFFFFFFFFFF>>1))>" +e "<$((0x8000000000000000>>-11))>" +e "<$((0x8000000000000000>>11))>" +e "<$((0x7FFFFFFFFFFFFFFF>>-11))>" +e "<$((0x7FFFFFFFFFFFFFFF>>11))>" +e "<$((0xFFFFFFFFFFFFFFFF>>-11))>" +e "<$((0xFFFFFFFFFFFFFFFF>>11))>" +e '= BIN **' +e "<$((0**1))>" +e "<$((2**1))>" +e "<$((2**2))>" +e "<$((2**3))>" +e "<$((2**4))>" +e "<$((10**4))>" +e "<$((10**10))>" +e "<$((10**5+5))>" +e "<$((10**(5+5)))>" +e '= LOG OR' +e "<$((0||0))>" +e "<$(( 000 || 0X0 ))>" +e "<$((01 || 64#1))>" +e "<$((01 || 64#1))>" +e "<$((0x1234 || 4660))>" +e "<$((0x1234 || 011064))>" +s I=33 J=33;e "<$((I||J))>" +s I=33 J=33;e "<$(( I || J ))>" +e "<$((0||1))>" +e "<$((0||0000000000000000000000001))>" +e "<$((1||2))>" +e "<$((0x1234 || 04660))>" +e "<$((0x1234 || 0x11064))>" +s I=10 J=33;e "<$((I||J))>" +s I=-10 J=-33;e "<$((I||J))>" +s I=-33 J=-33;e "<$((I||J))>" +s I=0 J=-33;e "<$((I||J))>" +s I=33 J=0;e "<$((I||J))>" +e '= LOG AND' +e "<$((0&&0))>" +e "<$(( 000 && 0X0 ))>" +e "<$((01 && 64#1))>" +e "<$((01 && 64#1))>" +e "<$((0x1234 && 4660))>" +e "<$((0x1234 && 011064))>" +s I=33 J=33;e "<$((I&&J))>" +s I=33 J=33;e "<$(( I && J ))>" +e "<$((0&&1))>" +e "<$((0&&0000000000000000000000001))>" +e "<$((1&&2))>" +e "<$((0x1234 && 04660))>" +e "<$((0x1234 && 0x11064))>" +s I=10 J=33;e "<$((I&&J))>" +s I=-10 J=-33;e "<$((I&&J))>" +s I=-33 J=-33;e "<$((I&&J))>" +s I=0 J=-33;e "<$((I&&J))>" +s I=33 J=0;e "<$((I&&J))>" +e '= BIN BIT_OR' +e "<$((0|0))>" +e "<$(( 0 | 0 ))>" +e "<$((0|1))>" +e "<$(( 0 | 1 ))>" +e "<$((1|0))>" +e "<$(( 1 | 0 ))>" +e "<$((1|1))>" +e "<$(( 1 | 1 ))>" +e "<$((1111|2222))>" +e "<$((2222|1111))>" +e "<$(( +0x10 | +0x11 ))>" +e "<$(( -0x10 | -0x11 ))>" +e "<$(( -0x10 | -0x11 ))>" +e "<$(( +64#10 | -64#11 ))>" +e "<$(( +0x11 | +0x10 ))>" +e "<$(( -0x11 | -0x10 ))>" +e "<$(( -0x11 | -0x10 ))>" +e "<$(( +64#11 | -64#10 ))>" +e "<$(( +64 | +1024 ))>" +e "<$((0x8000000000000000|-1))>" +e "<$((0x8000000000000000|1))>" +e "<$((0x7FFFFFFFFFFFFFFF|-1))>" +e "<$((0x7FFFFFFFFFFFFFFF|1))>" +e "<$((0xFFFFFFFFFFFFFFFF|-1))>" +e "<$((0xFFFFFFFFFFFFFFFF|1))>" +e "<$((0x8000000000000000|-11))>" +e "<$((0x8000000000000000|11))>" +e "<$((0x7FFFFFFFFFFFFFFF|-11))>" +e "<$((0x7FFFFFFFFFFFFFFF|11))>" +e "<$((0xFFFFFFFFFFFFFFFF|-11))>" +e "<$((0xFFFFFFFFFFFFFFFF|11))>" +e '= BIN BIT_XOR' +e "<$((0^0))>" +e "<$(( 0 ^ 0 ))>" +e "<$((0^1))>" +e "<$(( 0 ^ 1 ))>" +e "<$((1^0))>" +e "<$(( 1 ^ 0 ))>" +e "<$((1^1))>" +e "<$(( 1 ^ 1 ))>" +e "<$((1111^2222))>" +e "<$((2222^1111))>" +e "<$(( +0x10 ^ +0x11 ))>" +e "<$(( -0x10 ^ -0x11 ))>" +e "<$(( -0x10 ^ -0x11 ))>" +e "<$(( +64#10 ^ -64#11 ))>" +e "<$(( +0x11 ^ +0x10 ))>" +e "<$(( -0x11 ^ -0x10 ))>" +e "<$(( -0x11 ^ -0x10 ))>" +e "<$(( +64#11 ^ -64#10 ))>" +e "<$(( +64 ^ +1024 ))>" +e "<$((0x8000000000000000^-1))>" +e "<$((0x8000000000000000^1))>" +e "<$((0x7FFFFFFFFFFFFFFF^-1))>" +e "<$((0x7FFFFFFFFFFFFFFF^1))>" +e "<$((0xFFFFFFFFFFFFFFFF^-1))>" +e "<$((0xFFFFFFFFFFFFFFFF^1))>" +e "<$((0x8000000000000000^-11))>" +e "<$((0x8000000000000000^11))>" +e "<$((0x7FFFFFFFFFFFFFFF^-11))>" +e "<$((0x7FFFFFFFFFFFFFFF^11))>" +e "<$((0xFFFFFFFFFFFFFFFF^-11))>" +e "<$((0xFFFFFFFFFFFFFFFF^11))>" +e '= BIN BIT_AND' +e "<$((0&0))>" +e "<$(( 0 & 0 ))>" +e "<$((0&1))>" +e "<$(( 0 & 1 ))>" +e "<$((1&0))>" +e "<$(( 1 & 0 ))>" +e "<$((1&1))>" +e "<$(( 1 & 1 ))>" +e "<$((1111&2222))>" +e "<$((2222&1111))>" +e "<$(( +0x10 & +0x11 ))>" +e "<$(( -0x10 & -0x11 ))>" +e "<$(( -0x10 & -0x11 ))>" +e "<$(( +64#10 & -64#11 ))>" +e "<$(( +0x11 & +0x10 ))>" +e "<$(( -0x11 & -0x10 ))>" +e "<$(( -0x11 & -0x10 ))>" +e "<$(( +64#11 & -64#10 ))>" +e "<$(( +64 & +1024 ))>" +e "<$((0x8000000000000000&-1))>" +e "<$((0x8000000000000000&1))>" +e "<$((0x7FFFFFFFFFFFFFFF&-1))>" +e "<$((0x7FFFFFFFFFFFFFFF&1))>" +e "<$((0xFFFFFFFFFFFFFFFF&-1))>" +e "<$((0xFFFFFFFFFFFFFFFF&1))>" +e "<$((0x8000000000000000&-11))>" +e "<$((0x8000000000000000&11))>" +e "<$((0x7FFFFFFFFFFFFFFF&-11))>" +e "<$((0x7FFFFFFFFFFFFFFF&11))>" +e "<$((0xFFFFFFFFFFFFFFFF&-11))>" +e "<$((0xFFFFFFFFFFFFFFFF&11))>" +e '= BIN EQ' +e "<$((0==0))>" +e "<$(( 000 == 0X0 ))>" +e "<$((01 == 64#1))>" +e "<$((01 == 64#1))>" +e "<$((0x1234 == 4660))>" +e "<$((0x1234 == 011064))>" +s I=33 J=33;e "<$((I==J))>" +s I=33 J=33;e "<$(( I == J ))>" +e "<$((0==1))>" +e "<$((0==0000000000000000000000001))>" +e "<$((1==2))>" +e "<$((0x1234 == 04660))>" +e "<$((0x1234 == 0x11064))>" +s I=10 J=33;e "<$((I==J))>" +s I=-10 J=-33;e "<$((I==J))>" +s I=-33 J=-33;e "<$((I==J))>" +e '= BIN NE' +e "<$((0!=0))>" +e "<$(( 000 != 0X0 ))>" +e "<$((01 != 64#1))>" +e "<$((01 != 64#1))>" +e "<$((0x1234 != 4660))>" +e "<$((0x1234 != 011064))>" +s I=33 J=33;e "<$((I!=J))>" +s I=33 J=33;e "<$(( I != J ))>" +e "<$((0!=1))>" +e "<$((0!=0000000000000000000000001))>" +e "<$((1!=2))>" +e "<$((0x1234 != 04660))>" +e "<$((0x1234 != 0x11064))>" +s I=10 J=33;e "<$((I!=J))>" +s I=-10 J=-33;e "<$((I!=J))>" +s I=-33 J=-33;e "<$((I!=J))>" +e '= BIN LE' +e "<$((0<=0))>" +e "<$(( 000 <= 0X0 ))>" +e "<$((01 <= 64#1))>" +e "<$((01 <= 64#2))>" +e "<$((02 <= 64#1))>" +e "<$((0x1234 <= 4660))>" +e "<$((0x1234 <= 011064))>" +e "<$((0x1233 <= 011064))>" +e "<$((0x1235 <= 011064))>" +s I=33 J=33;e "<$((I<=J))>" +s I=33 J=33;e "<$((I<=J))>" +s I=32 J=33;e "<$((I<=J))>" +s I=34 J=33;e "<$((I<=J))>" +s I=-33 J=-33;e "<$((I<=J))>" +s I=-33 J=-33;e "<$((I<=J))>" +s I=-32 J=-33;e "<$((I<=J))>" +s I=-34 J=-33;e "<$((I<=J))>" +e '= BIN GE' +e "<$((0>=0))>" +e "<$(( 000 >= 0X0 ))>" +e "<$((01 >= 64#1))>" +e "<$((01 >= 64#2))>" +e "<$((02 >= 64#1))>" +e "<$((0x1234 >= 4660))>" +e "<$((0x1234 >= 011064))>" +e "<$((0x1233 >= 011064))>" +e "<$((0x1235 >= 011064))>" +s I=33 J=33;e "<$((I>=J))>" +s I=33 J=33;e "<$((I>=J))>" +s I=32 J=33;e "<$((I>=J))>" +s I=34 J=33;e "<$((I>=J))>" +s I=-33 J=-33;e "<$((I>=J))>" +s I=-33 J=-33;e "<$((I>=J))>" +s I=-32 J=-33;e "<$((I>=J))>" +s I=-34 J=-33;e "<$((I>=J))>" +e '= BIN LT' +e "<$((0<0))>" +e "<$(( 000 < 0X0 ))>" +e "<$((01 < 64#1))>" +e "<$((01 < 64#2))>" +e "<$((02 < 64#1))>" +e "<$((0x1234 < 4660))>" +e "<$((0x1234 < 011064))>" +e "<$((0x1233 < 011064))>" +e "<$((0x1235 < 011064))>" +s I=33 J=33;e "<$((I" +s I=33 J=33;e "<$((I" +s I=32 J=33;e "<$((I" +s I=34 J=33;e "<$((I" +s I=-33 J=-33;e "<$((I" +s I=-33 J=-33;e "<$((I" +s I=-32 J=-33;e "<$((I" +s I=-34 J=-33;e "<$((I" +e '= BIN GT' +e "<$((0>0))>" +e "<$(( 000 > 0X0 ))>" +e "<$((01 > 64#1))>" +e "<$((01 > 64#2))>" +e "<$((02 > 64#1))>" +e "<$((0x1234 > 4660))>" +e "<$((0x1234 > 011064))>" +e "<$((0x1233 > 011064))>" +e "<$((0x1235 > 011064))>" +s I=33 J=33;e "<$((I>J))>" +s I=33 J=33;e "<$((I>J))>" +s I=32 J=33;e "<$((I>J))>" +s I=34 J=33;e "<$((I>J))>" +s I=-33 J=-33;e "<$((I>J))>" +s I=-33 J=-33;e "<$((I>J))>" +s I=-32 J=-33;e "<$((I>J))>" +s I=-34 J=-33;e "<$((I>J))>" +# +# COMMA below +e '= PRECEDENCE I' +e "<$(( 1 + 2 + 3 ))>" +e "<$(( 1 - 2 + 3 ))>" +e "<$(( 3 - 2 - 1 ))>" +e "<$(( 3 - 2 + 1 ))>" +e "<$(( - 2 + 1 ))>" +e "<$(( 2 + -1 ))>" +e "<$(( ! 2 + 1 ))>" +e "<$(( 2 + !1 ))>" +e "<$(( 3 * 2 + 2 ))>" +e "<$(( 3 + 2 * 2 ))>" +e "<$(( 3 * 2 * 2 ))>" +e "<$(( 9 / 3 + 2 ))>" +e "<$(( 9 + 3 / 2 ))>" +e "<$(( 9 / 3 / 2 ))>" +e "<$(( 9 << 1 + 2 ))>" +e "<$(( 9 + 3 << 2 ))>" +e "<$(( 9 << 3 << 2 ))>" +e "<$(( 9 >> 1 + 2 ))>" +e "<$(( 9 + 3 >> 2 ))>" +e "<$(( 19 >> 3 >> 1 ))>" +e "<$(( 19 >> 3 << 1 ))>" +e "<$(( 19 << 3 >> 1 ))>" +e "<$(( 2 + 3 < 3 * 2 ))>" +e "<$(( 2 << 3 >= 3 << 2 ))>" +e "<$(( 0xfD & 0xF == 0xF ))>" +e "<$((0xfD&0xF==0xF))>" +e "<$(( 3 * 7 , 2 << 8 , 9 - 7 ))>" +e "<$((3*7,2<<8,9-7))>" +e '= PARENS' +e "<$(((1 + 2) + 3))>" +e "<$(((1+2)+3))>" +e "<$((1 - (2 + 3)))>" +e "<$((1-(2+3)))>" +e "<$((3 - (2 - 1)))>" +e "<$((3-(2-1)))>" +e "<$((3 - ( 2 + 1 )))>" +e "<$((3-(2+1)))>" +e "<$((- (2 + 1)))>" +e "<$((-(2+1)))>" +e "<$((! (2 + 1)))>" +e "<$((!(2+1)))>" +e "<$((3 * (2 + 2)))>" +e "<$((3*(2+2)))>" +e "<$(((3 + 2) * 2))>" +e "<$(((3+2)*2))>" +e "<$((3 * (2 * 2)))>" +e "<$((3*(2*8)))>" +e "<$((9 / (3 + 2)))>" +e "<$((9/(3+2)))>" +e "<$((( 9 + 3 ) / 2))>" +e "<$(((9+3)/2))>" +e "<$((9 / ( 3 / 2 )))>" +e "<$((9/(3/2)))>" +e "<$((( 9 << 1 ) + 2))>" +e "<$(((9<<1)+2))>" +e "<$((9 + (3 << 2)))>" +e "<$((9+(3<<2)))>" +e "<$((9 << (3 << 2)))>" +e "<$((9<<(3<<2)))>" +e "<$(((9 >> 1) + 2))>" +e "<$(((9>>1)+2))>" +e "<$((9 + (3 >> 2)))>" +e "<$((9+(3>>2)))>" +e "<$((19 >> (3 >> 1)))>" +e "<$((19>>(3>>1)))>" +e "<$((19 >> (3 << 1)))>" +e "<$((19>>(3<<1)))>" +e "<$((19 << (3 >> 1)))>" +e "<$((19<<(3>>1)))>" +e "<$((2 + (3 < 3) * 2))>" +e "<$((2+(3<3)*2))>" +e "<$((2 << ((3 >= 3) << 2)))>" +e "<$((2<<((3>=3)<<2)))>" +e "<$(((0xfD & 0xF) == 0xF))>" +e "<$(((0xfD&0xF)==0xF))>" +e "<$((3 * (7 , 2) << (8 , 9 - 7)))>" +e "<$((3*(7,2)<<(8,9-7)))>" +# +# COND BELOW +e '= ASSIGN I' +unset I;p "<$(( I = 3 ))>";e "<$I>" +unset I;p "<$((I=3))>";e "<$I>" +s I=10;p "<$((I=3))>";e "<$I>" +s I=10;p "<$((I+=1))>";e "<$I>" +s I=10;p "<$((I-=1))>";e "<$I>" +s I=10;p "<$((I*=1))>";e "<$I>" +s I=10;p "<$((I*=2))>";e "<$I>" +s I=10;p "<$((I/=1))>";e "<$I>" +s I=10;p "<$((I/=2))>";e "<$I>" +s I=10;p "<$((I%=1))>";e "<$I>" +s I=10;p "<$((I%=2))>";e "<$I>" +s I=10;p "<$((I**=1))>";e "<$I>" +s I=10;p "<$((I**=2))>";e "<$I>" +s I=10;p "<$((I**=1+1))>";e "<$I>" +s I=10;p "<$((I|=1))>";e "<$I>" +s I=10;p "<$((I^=1))>";e "<$I>";p "<$((I^=1))>";e "<$I>" +s I=10;p "<$((I&=2))>";e "<$I>" +s I=10;p "<$((I>>=1))>";e "<$I>" +s I=10;p "<$((I<<=1))>";e "<$I>" +e '= ASSIGN II' +s I=2;p "<$(((I+=1)-1))>";e "<$I>" +s I=4;p "<$(((I-=1)+1))>";e "<$I>" +s I=0 J=0;p "<$(((I=5)*(J=7)+1))>";e "<$I><$J>" +s I=99 J=17;p "<$(((I+=1)*(J-=2)+1))>";e "<$I><$J>" +s I=10;p "<$((I=2,I|=1))>";e "<$I>" +s I=0 J=0 Y=0 Z=0;p "<$((I=1,J=2,Y=3,Z=4,Z+=I+J+Y))>";e "<$I><$J><$Y><$Z>" +e '= POSTFIX' +s I=1;p "<$((I++))>";e "<$I>" +s I=1 J=0;p "<$((J=I++))>";e "<$I><$J>" +s I=1 J=10;p "<$((J++*I++))>";e "<$I><$J>" +s I=1 J=10;p "<$(((J++)*(I++)))>";e "<$I><$J>" +s I=1;p "<$((I--))>";e "<$I>" +s I=1 J=0;p "<$((J=I--))>";e "<$I><$J>" +s I=1 J=10;p "<$((J--*I--))>";e "<$I><$J>" +s I=1 J=10;p "<$(((J--)*(I--)))>";e "<$I><$J>" +e '= PREFIX' +s I=1;p "<$((++I))>";e "<$I>" +s I=1 J=0;p "<$((J=++I))>";e "<$I><$J>" +s I=1 J=10;p "<$((++J*++I))>";e "<$I><$J>" +s I=1 J=10;p "<$((++(J)*++(I)))>";e "<$I><$J>" +s I=1 J=10;p "<$(((++J)*(++I)))>";e "<$I><$J>" +s I=1;p "<$((--I))>";e "<$I>" +s I=1 J=0;p "<$((J=--I))>";e "<$I><$J>" +s I=2 J=10;p "<$((--J*--I))>";e "<$I><$J>" +s I=1 J=10;p "<$((--(J)*--(I)))>";e "<$I><$J>" +s I=1 J=10;p "<$(((--J)*(--I)))>";e "<$I><$J>" +e '= VAR RECUR' +s I='1 + 1';p "<$((I))>";e "<$I>" +s I='1 + 1';p "<$((+I))>";e "<$I>" +s I='1 + 1';p "<$((++I))>";e "<$I>" +s I='1 + 1';p "<$((I++))>";e "<$I>" +s I='1 + 1';p "<$((1+I))>";e "<$I>" +s I='1 + 1 * 2';p "<$((I+1))>";e "<$I>" +s I='(1 + 1) * 2';p "<$((I+1))>";e "<$I>" +s I='1 + 1' J='3 / 2';p "<$((I=I+J))>";e "<$I><$J>" +s I='1 + 1';p "<$((I=I))>";e "<$I>" +s I='1 + 1';p "<$((I=+I))>";e "<$I>" +s I='1 + 1';p "<$((I=1+I))>";e "<$I>" +s I='1 + 1 * 2';p "<$((I=I+1))>";e "<$I>" +s I='(1 + 1) * 2';p "<$((I=I+1))>";e "<$I>" +s I='1 + 1' J='3 / 2';p "<$((I+=I+J))>";e "<$I><$J>" +e '= COMMA' +e "<$(( 1 , 2 ))>" +e "<$(( 1 , 2 , 3 ))>" +e "<$(( 1 , 2 , 3 , 4 ))>" +e "<$((1,2,3,4))>" +s I='1 + 1';p "<$(( I=10 , I+=I, I=I**2, I/=3 ))>";e "<$I>" +s I1=I2=10 I2=3;p "<$((I1,I2))>";e "<$I1><$I2>" +e '= COND' +e "<$(( +0 ? 2 : 3 ))>" +e "<$((-0?2:3))>" +e "<$(( +1 ? 2 : 3 ))>" +e "<$(( 1-1 ? 2 : 3 ))>" +e "<$(( 1-0 ? 2 : 3 ))>" +e "<$((-1?2:3))>" +e "<$(( 0x1234 ? 111 : 222 ))>" +e "<$((1**2 ? 5 : 7))>" +e "<$((0**2 ? 5 : 7))>" +e "<$((0**2>=0?5:7))>" +e "<$((-1<=0**2?5:7))>" +e "<$((1<=0**2?5:7))>" +e "<$((1>2||1*0?5:7))>" +e "<$((1>2&&1*0?5:7))>" +e "<$((1<2&&1*0?5:7))>" +e "<$((1<2&&1*0+1?5:7))>" +e '-- COND .2' +e "<$(( 1 < 2 ? -1 : 1 > 2 ? 1 : 0 ))>" +e "<$((1 < 1 ? -1 : 1 > 1 ? 1 : 0))>" +e "<$((2<1?-1:2>1?1:0))>" +e "<$((4<5 ? 1 : 32))>" +e "<$((4>5 ? 1 : 32))>" +e "<$((4>(2+3) ? 1 : 32))>" +e "<$((4<(2+3) ? 1 : 32))>" +e "<$(((2+2)<(2+3) ? 1 : 32))>" +e "<$(((2+2)>(2+3) ? 1 : 32))>" +## grouping protects precedence in : parts (syntax error tests below) +e '-- COND .3' +e "<$((1-1 < 1 ? 2,4 : 1,3))>" +e "<$((0<1?2,4:(1,3)))>" +e "<$((0,1,2,0?2,4:1,3))>" +e "<$((0,1,2,1?2,4:1,3))>" +e "<$((0,1,2,0?2,4:(1,3)))>" +e "<$((0,1,2,1?2,4:(1,3)))>" +e "<$((0,1,2,0?(2,4):1,3))>" +e "<$((0,1,2,1?(2,4):1,3))>" +e "<$((0,1,2,0?(2,4):(1,3)))>" +e "<$((0,1,2,1?(2,4):(1,3)))>" +e "<$((0?2:((0,3)?1:4)))>" +e "<$((1?2:3,0?1:4))>" +e "<$((1?2:3,0?1:4?5:6))>" +e "<$((1?2:(3,0)?1:4?5:6))>" +e "<$((1?2:3,0?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,0)?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,0)?(4,5):5,6?7,8:9,10))>" +e "<$((1?2:(3,0)?(4,5):(5,6)?7,8:9,10))>" +e "<$((1?2:(3,0)?(4,5):(5,6)?(7,8):9,10))>" +e "<$((1?2:(3,0)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((1?2:3,1?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,1)?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,1)?(4,5):5,6?7,8:9,10))>" +e "<$((1?2:(3,1)?(4,5):(5,6)?7,8:9,10))>" +e "<$((1?2:(3,1)?(4,5):(5,6)?(7,8):9,10))>" +e "<$((1?2:(3,1)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((0?2:(3,1)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((0?2:(3,1)?4,5:(5,6)?7,8:(9,10)))>" +e "<$((0?2:(3,0)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((0?2:(3,0)?4,5:(5,6)?7,8:(9,10)))>" +e "<$((0?2:(3,0)?(4,5):(5,0)?(7,8):(9,10)))>" +e "<$((0?2:(3,0)?4,5:(5,0)?7,8:(9,10)))>" +e "<$((0?2:3,0?4,5:(5,0)?7,8:(9,10)))>" +e "<$((0?2:(3,0)?4,5:5,0?7,8:(9,10)))>" +e "<$((0?2:(3,0)?4,5:(5,0)?7,8:9,10))>" +e '-- COND .4' +e "<$((1?2?3?4?5:6:7:8:9))>" +e "<$((1?2?3?0?5:6:7:8:9))>" +e "<$((1?2?0?0?5:6:7:8:9))>" +e "<$((1?0?0?0?5:6:7:8:9))>" +e "<$((0?0?0?0?5:6:7:8:9))>" +e "<$((0?3+4?10:11:5+6?12:13))>" +e "<$((1?3+4?10:11:5+6?12:13))>" +e "<$((0?(3+4)?(10):(11):((5+6)?12:13)))>" +e "<$((1?(3+4)?(10):(11):((5+6)?12:13)))>" +e '-- COND .5' +e "<$((0?3+4?10:11?20+1:22*1:5+6?12:13))>" +e "<$((1?3+4?10:11?20+1:22*1:5+6?12:13))>" +e "<$((0?(3+4)?(10):(11)?(20+1):(22*1):((5+6)?12:13)))>" +e "<$((1?(3+4)?(10):(11)?(20+1):(22*1):((5+6)?12:13)))>" +e '-- COND .6' +e "<$((0?3+4?9:11?20+1:22*1:5+6?12:13))>" +e "<$((1?3+4?9:11?20+1:22*1:5+6?12:13))>" +e "<$((0?10+11?20+1?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?0?20+1?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20+1?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?0?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?0?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?0:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?23**1:0:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?23**1:24**1:0?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?23**1:24**1:25/1?0:56>>1:-1:-2))>" +e '-- COND .7' +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? (I2 < I3) ? I3 *= I3 : (I2 *= I2) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? ((I2 < I3) ? I3 *= I3 : (I2 *= I2)) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$((((I1";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1";\ + e "<$I1><$I2><$I3><$I4><$I5>" +# only first +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? (I2 > I3) ? I3 *= I3 : (I2 *= I2) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(((I1I3)?I3*=I3:(I2*=I2):(I1*=I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? ((I2 > I3) ? I3 *= I3 : (I2 *= I2)) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( ((I1 < I2) ? ((I2 > I3) ? (I3 *= I3):(I2 *= I2)):(I1 *= I1))))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1I3)?(I3>I4)?I4*=I4:(I3*=I3):(I2*=I2):(I1*=I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +# last not etc. +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1I4)?I4*=I4:(I3*=I3):(I2*=I2):(I1*=I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1I3)?(I3";\ + e "<$I1><$I2><$I3><$I4><$I5>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1>I2)?(I2";\ + e "<$I1><$I2><$I3><$I4><$I5>" +e '-- COND .8' +s I=0;p "<$((1?I=2:(I=3),8,10))>";e "<$I>" +s I=0;p "<$((1?20:(I+=2)))>";e "<$I>" +s I=0;p "<$((1?I+=10:(I+=2)))>";e "<$I>" +s I=0;p "<$((0?I+=2:20))>";e "<$I>" +s I=0;p "<$((0?I+=2:(I+=10)))>";e "<$I>" +s I=0;p "<$((0?(I+=2):(20)))>";e "<$I>" +s I=0;p "<$((0?(I+=2):(I+=20)))>";e "<$I>" +e '-- COND .9' +s I1=+E+ I2=1+1;p "<$((0?I1:I2))>";e "<$I1><$I2>" +s I1=1+1 I2=+E+;p "<$((1?I1:I2))>";e "<$I1><$I2>" +s I1=+E+ I2=1+1;p "<$((0?I1=1:(I2=2)))>";e "<$I1><$I2>" +s I1=1+1 I2=+E+;p "<$((1?I1=1:(I2=2)))>";e "<$I1><$I2>" +s I1=+E+ I2=1+1;p "<$((0?I1*=I1:(I2*=I2)))>";e "<$I1><$I2>" +s I1=1+1 I2=+E+;p "<$((1?I1*=I1:(I2*=I2)))>";e "<$I1><$I2>" +e '-- COND .10' +s I1=+E+ I2=+E+ I3=+E+ I4=-1;p "<$((0?I1?I2:I3:I4))>";e "<$I1><$I2><$I3><$I4>" +s I1=1 I2=2 I3=+E+ I4=+E+;p "<$((1?I1?I2:I3:I4))>";e "<$I1><$I2><$I3><$I4>" +s I1=0 I2=+E+ I3=3 I4=+E+;p "<$((1?I1?I2:I3:I4))>";e "<$I1><$I2><$I3><$I4>" +e '= WILD I' +e "<$(( 3 + ( 11 ) ))>" +e "<$((1 + (2 - 2)))>" +e "<$((1 + (2 - 2)))>" +e "<$(( (( 3 / 3 )) + ((1*1*1)) - (( 7 % 6 ))))>" +e "<$(( 3+((2 * 2))/6 ))>" +e "<$(( 1 + 1 - 3 * 3 + 99-88 / 17))>" +e "<$(( 1 << 2 % 1+2 * 4 - (2 + 2 + 1) * 6 / 7 + 4 * 2 + (81/9)))>" +s I1=I2=10 I2=3;p "<$((I1 + I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=3;p "<$((I1 * I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=3;p "<$((I1 % I2))>";e "<$I1><$I2>" +e '= WILD II' +s I=10;p "<$((3+(3*(I=11))))>";e "<$I>" +s I=10;p "<$((3+(3*(I++))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,I++))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,++I))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,++++I))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,+++++++++++++++++++++++-+++++I))))>";e "<$I>" +e "<$((3+(3*(+++++++++++++++++++++++-+++++10))))>" +s I=10;p "<$(( +10 + + +I ))>";e "<$I>" +s I=10;p "<$(( +10 + ++I ))>";e "<$I>" +s I=10;p "<$(( +10 ++ +I ))>";e "<$I>" +s I=10;p "<$(( +10 +++ I ))>";e "<$I>" +s I=10;p "<$(( +10+++I ))>";e "<$I>" +s I=10;p "<$((+10++I))>";e "<$I>" +s I=10;p "<$((+10 + + + ++++ +I))>";e "<$I>" +e "<$(( +10 + + + ++++ +11 ))>" +e "<$(( +10 + + + ++++ ++11 ))>" +e "<$((+10++++++++11))>" +e '= WILD RECUR' # (some yet) +s I1=I2=10 I2=5;p "<$((I1+=I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1,I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1+I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I2=0 I2=5 I3=I2+=1;p "<$((I1?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I1=10 I2=5 I3=I2+=1;p "<$((I1=0?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I1=10 I2=5 I3=I2+=1;p "<$((I1=1?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I2='(I2=10)+1' I2=5 I3=I2+=1;p "<$((I1,I3))>";e "<$I1><$I2><$I3>" +s I1=I2='(I2=(I2=10)+1)' I2=5 I3=I2+=1;p "<$((I1,I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1+I3*I1*I3/I1%I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1+I3*I1*I3/I1%I3))>";e "<$I1><$I2><$I3>" +s I1=I2=+E+ I2=5;p "<$((I1=10))>";e "<$I1><$I2>" +s I1=I2=+E+ I2=5;p "<$((0?I1:++I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=5;p "<$((I2,(1?I1:++I2)))>";e "<$I1><$I2>" +s I1=5 I2=10 I3=20;p "<$((I1-=5,1?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1=Ix,1?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1=Ix?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1*=Ix?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((0,I1*=Ix?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1*=Ix?I2:I3,Ix=21,I1*=Ix?I2:I3))>";e "<$I1><$I2><$I3>" diff --git a/shell/hush.c b/shell/hush.c index 051b123e78..be01ed035c 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6475,7 +6475,7 @@ static NOINLINE int encode_then_append_var_plusminus(o_string *output, int n, } #if ENABLE_FEATURE_SH_MATH -static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) +static arith_t expand_and_evaluate_arith(const char *arg, char **errmsg_p) { arith_state_t math_state; arith_t res; @@ -6489,8 +6489,13 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) free(exp_str); if (errmsg_p) *errmsg_p = math_state.errmsg; - if (math_state.errmsg) + if (math_state.errmsg) { msg_and_die_if_script(math_state.errmsg); +# if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + if (errmsg_p == NULL) + free(math_state.errmsg); +# endif + } return res; } #endif @@ -6814,11 +6819,15 @@ static NOINLINE int expand_one_var(o_string *output, int n, */ arith_t beg, len; unsigned vallen; - const char *errmsg; + char *errmsg; beg = expand_and_evaluate_arith(exp_word, &errmsg); - if (errmsg) + if (errmsg) { +# if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + free(errmsg); +# endif goto empty_result; + } debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); *p++ = SPECIAL_VAR_SYMBOL; exp_word = p; @@ -6838,8 +6847,12 @@ static NOINLINE int expand_one_var(o_string *output, int n, goto empty_result; } len = expand_and_evaluate_arith(exp_word, &errmsg); - if (errmsg) + if (errmsg) { +# if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + free(errmsg); +# endif goto empty_result; + } debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); debug_printf_varexp("from val:'%s'\n", val); if (len < 0) { diff --git a/shell/hush_test/hush-arith/bigbadbison.right b/shell/hush_test/hush-arith/bigbadbison.right new file mode 100644 index 0000000000..3f3e95700a --- /dev/null +++ b/shell/hush_test/hush-arith/bigbadbison.right @@ -0,0 +1,873 @@ += BASE +<0> +<0> +<1> +<0> +<0> +<0> +<0> +<1> +<1> +<1> +<0> +<10> +<9191919191919> +<13> +<11> +<1023> +<1295> +<1295> +<9322365> +<16242915> +<10> +<33> +<10> +<33> +<1> +<1> +<1> +<33> +<33> +<33> +<33> += UNA PLUS/MINUS +<0> +<0> +<1> +<1> +<4221> +<16929> +<16242915> +<16242915> +<1> +<1> +<1> +<0> +<0> +<-1> +<-1> +<-4221> +<-16929> +<-16242915> +<-16242915> +<-1> +<-1> +<-1> +<-1> +<1> +<-1> += UNA ! +<1> +<1> +<0> +<0> +<1> +<0> += UNA ~ +<-1> +<-1> +<-2> +<-2> +<-2276> +<0> +<0> +<-1> +<-1> +<-1> +<-1> += BIN + +<0> +<0> +<1> +<1> +<1> +<1> +<2> +<2> +<2> +<-2> +<3333> +<3333> +<33> +<-33> +<-33> +<-1> +<33> +<-33> +<-33> +<1> +<9223372036854775807> +<-9223372036854775807> +<9223372036854775806> +<-9223372036854775808> +<-2> +<0> +<9223372036854775797> +<-9223372036854775797> +<9223372036854775796> +<-9223372036854775798> +<-12> +<10> += BIN - +<0> +<0> +<-1> +<-1> +<1> +<1> +<0> +<0> +<0> +<0> +<-1111> +<1111> +<-1> +<1> +<1> +<129> +<1> +<-1> +<-1> +<129> +<-9223372036854775807> +<9223372036854775807> +<-9223372036854775808> +<9223372036854775806> +<0> +<-2> +<-9223372036854775797> +<9223372036854775797> +<-9223372036854775798> +<9223372036854775796> +<10> +<-12> += BIN * +<0> +<0> +<0> +<0> +<0> +<0> +<1> +<1> +<2468642> +<2468642> +<272> +<272> +<272> +<-4160> +<272> +<272> +<272> +<-4160> +<-9223372036854775808> +<-9223372036854775808> +<-9223372036854775807> +<9223372036854775807> +<1> +<-1> +<-9223372036854775808> +<-9223372036854775808> +<-9223372036854775797> +<9223372036854775797> +<11> +<-11> += BIN / +<0> +<1> +<1> +<0> +<2> +<0> +<0> +<0> +<0> +<1> +<1> +<1> +<-1> +<2> +<3> +<1> +<1> +<0> +<0> +<-9223372036854775808> +<-9223372036854775808> +<-9223372036854775807> +<9223372036854775807> +<1> +<-1> +<838488366986797800> +<-838488366986797800> +<-838488366986797800> +<838488366986797800> +<0> +<0> += BIN % +<0> +<0> +<0> +<1111> +<0> +<16> +<-16> +<-16> +<64> +<1> +<-1> +<-1> +<1> +<0> +<0> +<1> +<0> +<3> +<-1> +<0> +<0> +<0> +<0> +<0> +<0> +<-8> +<-8> +<7> +<7> +<-1> +<-1> += BIN << +<0> +<0> +<0> +<0> +<1> +<1> +<2> +<2> +<78179674781384704> +<18639486976> +<2097152> +<-2251799813685248> +<-2251799813685248> +<0> +<1114112> +<-4785074604081152> +<-4785074604081152> +<65> +<64> +<0> +<0> +<-9223372036854775808> +<-2> +<-9223372036854775808> +<-2> +<0> +<0> +<-9007199254740992> +<-2048> +<-9007199254740992> +<-2048> += BIN >> +<0> +<0> +<0> +<0> +<1> +<1> +<0> +<0> +<0> +<0> +<0> +<-1> +<-1> +<0> +<0> +<-1> +<-1> +<65> +<64> +<-1> +<-4611686018427387904> +<0> +<4611686018427387903> +<-1> +<-1> +<-1024> +<-4503599627370496> +<1023> +<4503599627370495> +<-1> +<-1> += BIN ** +<0> +<2> +<4> +<8> +<16> +<10000> +<10000000000> +<100005> +<10000000000> += LOG OR +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> += LOG AND +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<0> +<0> += BIN BIT_OR +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<3327> +<3327> +<17> +<-1> +<-1> +<-1> +<17> +<-1> +<-1> +<-63> +<1088> +<-1> +<-9223372036854775807> +<-1> +<9223372036854775807> +<-1> +<-1> +<-11> +<-9223372036854775797> +<-1> +<9223372036854775807> +<-1> +<-1> += BIN BIT_XOR +<0> +<0> +<1> +<1> +<1> +<1> +<0> +<0> +<3321> +<3321> +<1> +<31> +<31> +<-1> +<1> +<31> +<31> +<-127> +<1088> +<9223372036854775807> +<-9223372036854775807> +<-9223372036854775808> +<9223372036854775806> +<0> +<-2> +<9223372036854775797> +<-9223372036854775797> +<-9223372036854775798> +<9223372036854775796> +<10> +<-12> += BIN BIT_AND +<0> +<0> +<0> +<0> +<0> +<0> +<1> +<1> +<6> +<6> +<16> +<-32> +<-32> +<0> +<16> +<-32> +<-32> +<64> +<0> +<-9223372036854775808> +<0> +<9223372036854775807> +<1> +<-1> +<1> +<-9223372036854775808> +<0> +<9223372036854775797> +<11> +<-11> +<11> += BIN EQ +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<1> += BIN NE +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<0> +<1> +<1> +<1> +<1> +<1> +<1> +<1> +<0> += BIN LE +<1> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<0> +<1> += BIN GE +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<0> +<1> +<1> +<1> +<1> +<0> += BIN LT +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<0> +<1> += BIN GT +<0> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<0> +<1> +<0> +<0> +<1> +<0> += PRECEDENCE I +<6> +<2> +<0> +<2> +<-1> +<1> +<1> +<2> +<8> +<7> +<12> +<5> +<10> +<1> +<72> +<48> +<288> +<1> +<3> +<1> +<4> +<76> +<1> +<1> +<1> +<1> +<2> +<2> += PARENS +<6> +<6> +<-4> +<-4> +<2> +<2> +<0> +<0> +<-3> +<-3> +<0> +<0> +<12> +<12> +<10> +<10> +<12> +<48> +<1> +<1> +<6> +<6> +<9> +<9> +<20> +<20> +<21> +<21> +<36864> +<36864> +<6> +<6> +<9> +<9> +<9> +<9> +<0> +<0> +<38> +<38> +<2> +<2> +<32> +<32> +<0> +<0> +<24> +<24> += ASSIGN I +<3><3> +<3><3> +<3><3> +<11><11> +<9><9> +<10><10> +<20><20> +<10><10> +<5><5> +<0><0> +<0><0> +<10><10> +<100><100> +<100><100> +<11><11> +<11><11> +<10><10> +<2><2> +<5><5> +<20><20> += ASSIGN II +<2><3> +<4><3> +<36><5><7> +<1501><100><15> +<3><3> +<10><1><2><3><10> += POSTFIX +<1><2> +<1><2><1> +<10><2><11> +<10><2><11> +<1><0> +<1><0><1> +<10><0><9> +<10><0><9> += PREFIX +<2><2> +<2><2><2> +<22><2><11> +<10><1><10> +<22><2><11> +<0><0> +<0><0><0> +<9><1><9> +<10><1><10> +<0><0><9> += VAR RECUR +<2><1 + 1> +<2><1 + 1> +<3><3> +<2><3> +<3><1 + 1> +<4><1 + 1 * 2> +<5><(1 + 1) * 2> +<3><3><3 / 2> +<2><2> +<2><2> +<3><3> +<4><4> +<5><5> +<5><5><3 / 2> += COMMA +<2> +<3> +<4> +<4> +<133><133> +<10><10> += COND +<3> +<3> +<2> +<3> +<2> +<2> +<111> +<5> +<7> +<5> +<5> +<7> +<7> +<7> +<7> +<5> +-- COND .2 +<-1> +<0> +<1> +<1> +<32> +<32> +<1> +<1> +<32> +-- COND .3 +<3> +<4> +<3> +<3> +<3> +<4> +<3> +<3> +<3> +<4> +<1> +<4> +<5> +<2> +<10> +<10> +<10> +<10> +<10> +<2> +<10> +<10> +<10> +<10> +<10> +<2> +<5> +<5> +<8> +<8> +<10> +<10> +<10> +<10> +<10> +-- COND .4 +<5> +<6> +<7> +<8> +<9> +<12> +<10> +<12> +<10> +-- COND .5 +<12> +<10> +<12> +<10> +-- COND .6 +<12> +<9> +<-2> +<-1> +<23> +<26> +<24> +<0> +<23> +<23> +<23> +-- COND .7 +<16><2><3><16><5> +<16><2><3><16><5> +<16><2><3><16><5> +<25><2><3><4><25><> +<9><2><9><4><5> +<9><2><9><4><5> +<9><2><9><4><5> +<9><2><9><4><5> +<9><2><9><4><5> +<16><2><3><16><5> +<9><2><9><4><5><> +<4><4><3><4><5><> +-- COND .8 +<10><2> +<20><0> +<10><10> +<20><0> +<10><10> +<20><0> +<20><20> +-- COND .9 +<2><+E+><1+1> +<2><1+1><+E+> +<2><+E+><2> +<1><1><+E+> +<4><+E+><4> +<4><4><+E+> +-- COND .10 +<-1><+E+><+E+><+E+><-1> +<2><1><2><+E+><+E+> +<3><0><+E+><3><+E+> += WILD I +<14> +<1> +<1> +<1> +<3> +<87> +<2097152> +<20><10> +<100><10> +<0><10> += WILD II +<36><11> +<33><11> +<36><12> +<39><12> +<39><12> +<-33><12> +<-27> +<20><10> +<21><11> +<20><10> +<21><11> +<21><11> +<20><10> +<20><10> +<21> +<21> +<21> += WILD RECUR +<20><20><10> +<10><10> +<11><11> +<21><11> +<10><10> +<1><1> +<6><6><6> +<10><10><5> +<12><12> +<12><12> +<10><11> +<10><11> +<10><10><5> +<6><6> +<10><10> +<10><0><10><20> +<10><6><10><20> +<10><10><10><20> +<50><50><10><20> +<50><50><10><20> +<500><500><10><20> diff --git a/shell/hush_test/hush-arith/bigbadbison.tests b/shell/hush_test/hush-arith/bigbadbison.tests new file mode 100755 index 0000000000..0e01c6fe6a --- /dev/null +++ b/shell/hush_test/hush-arith/bigbadbison.tests @@ -0,0 +1,907 @@ +# make this work with (ba)sh \ +command -v shopt && shopt -s expand_aliases;\ +alias p=printf;alias e=echo;alias s=export +s I=10 J=33 +e '= BASE' +e "<$(())>" +e "<$(( ))>" +e "<$((1))>" +e "<$((0))>" +e "<$((0x0))>" +e "<$((0X0))>" +e "<$((000))>" +e "<$((000000000000001))>" +e "<$((2#00000000000000000000000000000000000001))>" +e "<$((0X00000000000000000000000000000000000000000001))>" +e "<$((999999999999999999999999999999999999999999999))>" +e "<$(( 10 ))>" +e "<$((9191919191919))>" +e "<$((0xD))>" +e "<$((013))>" +e "<$((32#VV))>" +e "<$((36#ZZ))>" +e "<$((36#zz))>" +e "<$(( 64#zzZZ ))>" +e "<$((64#ZZzz))>" +e "<$((I))>" +e "<$((J))>" +e "<$(( I ))>" +e "<$(( J ))>" +e "<$(( (1) ))>" +e "<$((((1))))>" +e "<$(((((1)))))>" +e "<$(( (J) ))>" +e "<$((((J))))>" +e "<$(((((J)))))>" +e "<$(( ( ( ( J ) ) ) ))>" +e '= UNA PLUS/MINUS' +e "<$((+0))>" +e "<$(( + 0 ))>" +e "<$(( +1))>" +e "<$((+ 1 ))>" +e "<$(( + 4221 ))>" +e "<$(( +0x4221 ))>" +e "<$(( + 64#ZZzz ))>" +e "<$(( +64#ZZzz ))>" +e "<$((+ (1) ))>" +e "<$((+((1))))>" +e "<$((+(((1)))))>" +e "<$((-0))>" +e "<$(( - 0 ))>" +e "<$(( -1))>" +e "<$((- 1 ))>" +e "<$(( - 4221 ))>" +e "<$(( -0x4221 ))>" +e "<$(( - 64#ZZzz ))>" +e "<$(( -64#ZZzz ))>" +e "<$((- (1) ))>" +e "<$((-((1))))>" +e "<$((-(((1)))))>" +e "<$((+ -(1) ))>" +e "<$((+(-(-1))))>" +e "<$((+(-(-(-1)))))>" +e '= UNA !' +e "<$((!0))>" +e "<$((! 00000000))>" +e "<$((!1))>" +e "<$((! 0x00001))>" +e "<$((! - 0))>" +e "<$((!-1))>" +e '= UNA ~' +e "<$((~0))>" +e "<$((~ 00000000))>" +e "<$((~1))>" +e "<$((~ 0x00001))>" +e "<$((~ 64#zz))>" +e "<$((~-1))>" +e "<$((~ - 1))>" +e "<$((~-0))>" +e "<$((~ - 0))>" +e "<$((~(-0)))>" +e "<$((~((- 0))))>" +e '= BIN +' +e "<$((0+0))>" +e "<$(( 0 + 0 ))>" +e "<$((0+1))>" +e "<$(( 0 + 1 ))>" +e "<$((1+0))>" +e "<$(( 1 + 0 ))>" +e "<$((1+1))>" +e "<$(( 1 + 1 ))>" +e "<$(( (1 + 1) ))>" +e "<$(((((((-1)))) + (((-1))))))>" +e "<$((1111+2222))>" +e "<$((2222+1111))>" +e "<$(( +0x10 + +0x11 ))>" +e "<$(( -0x10 + -0x11 ))>" +e "<$(( -0x10 + -0x11 ))>" +e "<$(( +64#10 + -64#11 ))>" +e "<$(( +0x11 + +0x10 ))>" +e "<$(( -0x11 + -0x10 ))>" +e "<$(( -0x11 + -0x10 ))>" +e "<$(( +64#11 + -64#10 ))>" +e "<$((0x8000000000000000+-1))>" +e "<$((0x8000000000000000+1))>" +e "<$((0x7FFFFFFFFFFFFFFF+-1))>" +e "<$((0x7FFFFFFFFFFFFFFF+1))>" +e "<$((0xFFFFFFFFFFFFFFFF+-1))>" +e "<$((0xFFFFFFFFFFFFFFFF+1))>" +e "<$((0x8000000000000000+-11))>" +e "<$((0x8000000000000000+11))>" +e "<$((0x7FFFFFFFFFFFFFFF+-11))>" +e "<$((0x7FFFFFFFFFFFFFFF+11))>" +e "<$((0xFFFFFFFFFFFFFFFF+-11))>" +e "<$((0xFFFFFFFFFFFFFFFF+11))>" +e '= BIN -' +e "<$((0-0))>" +e "<$(( 0 - 0 ))>" +e "<$((0-1))>" +e "<$(( 0 - 1 ))>" +e "<$((1-0))>" +e "<$(( 1 - 0 ))>" +e "<$((1-1))>" +e "<$(( 1 - 1 ))>" +e "<$(( (1 - 1) ))>" +e "<$(((((((+1)))) - (((+1))))))>" +e "<$((1111-2222))>" +e "<$((2222-1111))>" +e "<$(( +0x10 - +0x11 ))>" +e "<$(( -0x10 - -0x11 ))>" +e "<$(( -0x10 - -0x11 ))>" +e "<$(( +64#10 - -64#11 ))>" +e "<$(( +0x11 - +0x10 ))>" +e "<$(( -0x11 - -0x10 ))>" +e "<$(( -0x11 - -0x10 ))>" +e "<$(( +64#11 - -64#10 ))>" +e "<$((0x8000000000000000--1))>" +e "<$((0x8000000000000000-1))>" +e "<$((0x7FFFFFFFFFFFFFFF--1))>" +e "<$((0x7FFFFFFFFFFFFFFF-1))>" +e "<$((0xFFFFFFFFFFFFFFFF--1))>" +e "<$((0xFFFFFFFFFFFFFFFF-1))>" +e "<$((0x8000000000000000--11))>" +e "<$((0x8000000000000000-11))>" +e "<$((0x7FFFFFFFFFFFFFFF--11))>" +e "<$((0x7FFFFFFFFFFFFFFF-11))>" +e "<$((0xFFFFFFFFFFFFFFFF--11))>" +e "<$((0xFFFFFFFFFFFFFFFF-11))>" +e '= BIN *' +e "<$((0*0))>" +e "<$(( 0 * 0 ))>" +e "<$((0*1))>" +e "<$(( 0 * 1 ))>" +e "<$((1*0))>" +e "<$(( 1 * 0 ))>" +e "<$((1*1))>" +e "<$(( 1 * 1 ))>" +e "<$((1111*2222))>" +e "<$((2222*1111))>" +e "<$(( +0x10 * +0x11 ))>" +e "<$(( -0x10 * -0x11 ))>" +e "<$(( -0x10 * -0x11 ))>" +e "<$(( +64#10 * -64#11 ))>" +e "<$(( +0x11 * +0x10 ))>" +e "<$(( -0x11 * -0x10 ))>" +e "<$(( -0x11 * -0x10 ))>" +e "<$(( +64#11 * -64#10 ))>" +e "<$((0x8000000000000000*-1))>" +e "<$((0x8000000000000000*1))>" +e "<$((0x7FFFFFFFFFFFFFFF*-1))>" +e "<$((0x7FFFFFFFFFFFFFFF*1))>" +e "<$((0xFFFFFFFFFFFFFFFF*-1))>" +e "<$((0xFFFFFFFFFFFFFFFF*1))>" +e "<$((0x8000000000000000*-11))>" +e "<$((0x8000000000000000*11))>" +e "<$((0x7FFFFFFFFFFFFFFF*-11))>" +e "<$((0x7FFFFFFFFFFFFFFF*11))>" +e "<$((0xFFFFFFFFFFFFFFFF*-11))>" +e "<$((0xFFFFFFFFFFFFFFFF*11))>" +e '= BIN /' +e "<$(( 0 / 1 ))>" +e "<$((1/1))>" +e "<$(( 1 / 1 ))>" +e "<$((1111/2222))>" +e "<$((2222/1111))>" +e "<$(( +0x10 / +0x11 ))>" +e "<$(( -0x10 / -0x11 ))>" +e "<$(( -0x10 / -0x11 ))>" +e "<$(( +64#10 / -64#11 ))>" +e "<$(( +0x11 / +0x10 ))>" +e "<$(( -0x11 / -0x10 ))>" +e "<$(( -0x11 / -0x10 ))>" +e "<$(( +64#11 / -64#10 ))>" +e "<$((2/1))>" +e "<$((3/1))>" +e "<$((3/2))>" +e "<$((3/3))>" +e "<$((3/4))>" +e "<$((-1/4))>" +e "<$((0x8000000000000000/-1))>" +e "<$((0x8000000000000000/1))>" +e "<$((0x7FFFFFFFFFFFFFFF/-1))>" +e "<$((0x7FFFFFFFFFFFFFFF/1))>" +e "<$((0xFFFFFFFFFFFFFFFF/-1))>" +e "<$((0xFFFFFFFFFFFFFFFF/1))>" +e "<$((0x8000000000000000/-11))>" +e "<$((0x8000000000000000/11))>" +e "<$((0x7FFFFFFFFFFFFFFF/-11))>" +e "<$((0x7FFFFFFFFFFFFFFF/11))>" +e "<$((0xFFFFFFFFFFFFFFFF/-11))>" +e "<$((0xFFFFFFFFFFFFFFFF/11))>" +e '= BIN %' +e "<$(( 0 % 1 ))>" +e "<$((1%1))>" +e "<$(( 1 % 1 ))>" +e "<$((1111%2222))>" +e "<$((2222%1111))>" +e "<$(( +0x10 % +0x11 ))>" +e "<$(( -0x10 % -0x11 ))>" +e "<$(( -0x10 % -0x11 ))>" +e "<$(( +64#10 % -64#11 ))>" +e "<$(( +0x11 % +0x10 ))>" +e "<$(( -0x11 % -0x10 ))>" +e "<$(( -0x11 % -0x10 ))>" +e "<$(( +64#11 % -64#10 ))>" +e "<$((2%1))>" +e "<$((3%1))>" +e "<$((3%2))>" +e "<$((3%3))>" +e "<$((3%4))>" +e "<$((-1%4))>" +e "<$((0x8000000000000000%-1))>" +e "<$((0x8000000000000000%1))>" +e "<$((0x7FFFFFFFFFFFFFFF%-1))>" +e "<$((0x7FFFFFFFFFFFFFFF%1))>" +e "<$((0xFFFFFFFFFFFFFFFF%-1))>" +e "<$((0xFFFFFFFFFFFFFFFF%1))>" +e "<$((0x8000000000000000%-11))>" +e "<$((0x8000000000000000%11))>" +e "<$((0x7FFFFFFFFFFFFFFF%-11))>" +e "<$((0x7FFFFFFFFFFFFFFF%11))>" +e "<$((0xFFFFFFFFFFFFFFFF%-11))>" +e "<$((0xFFFFFFFFFFFFFFFF%11))>" +e '= BIN <<' +e "<$((0<<0))>" +e "<$(( 0 << 0 ))>" +e "<$((0<<1))>" +e "<$(( 0 << 1 ))>" +e "<$((1<<0))>" +e "<$(( 1 << 0 ))>" +e "<$((1<<1))>" +e "<$(( 1 << 1 ))>" +e "<$((1111<<2222))>" +e "<$((2222<<1111))>" +e "<$(( +0x10 << +0x11 ))>" +e "<$(( -0x10 << -0x11 ))>" +e "<$(( -0x10 << -0x11 ))>" +e "<$(( +64#10 << -64#11 ))>" +e "<$(( +0x11 << +0x10 ))>" +e "<$(( -0x11 << -0x10 ))>" +e "<$(( -0x11 << -0x10 ))>" +e "<$(( +64#11 << -64#10 ))>" +e "<$(( +64 << +1024 ))>" +e "<$((0x8000000000000000<<-1))>" +e "<$((0x8000000000000000<<1))>" +e "<$((0x7FFFFFFFFFFFFFFF<<-1))>" +e "<$((0x7FFFFFFFFFFFFFFF<<1))>" +e "<$((0xFFFFFFFFFFFFFFFF<<-1))>" +e "<$((0xFFFFFFFFFFFFFFFF<<1))>" +e "<$((0x8000000000000000<<-11))>" +e "<$((0x8000000000000000<<11))>" +e "<$((0x7FFFFFFFFFFFFFFF<<-11))>" +e "<$((0x7FFFFFFFFFFFFFFF<<11))>" +e "<$((0xFFFFFFFFFFFFFFFF<<-11))>" +e "<$((0xFFFFFFFFFFFFFFFF<<11))>" +e '= BIN >>' +e "<$((0>>0))>" +e "<$(( 0 >> 0 ))>" +e "<$((0>>1))>" +e "<$(( 0 >> 1 ))>" +e "<$((1>>0))>" +e "<$(( 1 >> 0 ))>" +e "<$((1>>1))>" +e "<$(( 1 >> 1 ))>" +e "<$((1111>>2222))>" +e "<$((2222>>1111))>" +e "<$(( +0x10 >> +0x11 ))>" +e "<$(( -0x10 >> -0x11 ))>" +e "<$(( -0x10 >> -0x11 ))>" +e "<$(( +64#10 >> -64#11 ))>" +e "<$(( +0x11 >> +0x10 ))>" +e "<$(( -0x11 >> -0x10 ))>" +e "<$(( -0x11 >> -0x10 ))>" +e "<$(( +64#11 >> -64#10 ))>" +e "<$(( +64 >> +1024 ))>" +e "<$((0x8000000000000000>>-1))>" +e "<$((0x8000000000000000>>1))>" +e "<$((0x7FFFFFFFFFFFFFFF>>-1))>" +e "<$((0x7FFFFFFFFFFFFFFF>>1))>" +e "<$((0xFFFFFFFFFFFFFFFF>>-1))>" +e "<$((0xFFFFFFFFFFFFFFFF>>1))>" +e "<$((0x8000000000000000>>-11))>" +e "<$((0x8000000000000000>>11))>" +e "<$((0x7FFFFFFFFFFFFFFF>>-11))>" +e "<$((0x7FFFFFFFFFFFFFFF>>11))>" +e "<$((0xFFFFFFFFFFFFFFFF>>-11))>" +e "<$((0xFFFFFFFFFFFFFFFF>>11))>" +e '= BIN **' +e "<$((0**1))>" +e "<$((2**1))>" +e "<$((2**2))>" +e "<$((2**3))>" +e "<$((2**4))>" +e "<$((10**4))>" +e "<$((10**10))>" +e "<$((10**5+5))>" +e "<$((10**(5+5)))>" +e '= LOG OR' +e "<$((0||0))>" +e "<$(( 000 || 0X0 ))>" +e "<$((01 || 64#1))>" +e "<$((01 || 64#1))>" +e "<$((0x1234 || 4660))>" +e "<$((0x1234 || 011064))>" +s I=33 J=33;e "<$((I||J))>" +s I=33 J=33;e "<$(( I || J ))>" +e "<$((0||1))>" +e "<$((0||0000000000000000000000001))>" +e "<$((1||2))>" +e "<$((0x1234 || 04660))>" +e "<$((0x1234 || 0x11064))>" +s I=10 J=33;e "<$((I||J))>" +s I=-10 J=-33;e "<$((I||J))>" +s I=-33 J=-33;e "<$((I||J))>" +s I=0 J=-33;e "<$((I||J))>" +s I=33 J=0;e "<$((I||J))>" +e '= LOG AND' +e "<$((0&&0))>" +e "<$(( 000 && 0X0 ))>" +e "<$((01 && 64#1))>" +e "<$((01 && 64#1))>" +e "<$((0x1234 && 4660))>" +e "<$((0x1234 && 011064))>" +s I=33 J=33;e "<$((I&&J))>" +s I=33 J=33;e "<$(( I && J ))>" +e "<$((0&&1))>" +e "<$((0&&0000000000000000000000001))>" +e "<$((1&&2))>" +e "<$((0x1234 && 04660))>" +e "<$((0x1234 && 0x11064))>" +s I=10 J=33;e "<$((I&&J))>" +s I=-10 J=-33;e "<$((I&&J))>" +s I=-33 J=-33;e "<$((I&&J))>" +s I=0 J=-33;e "<$((I&&J))>" +s I=33 J=0;e "<$((I&&J))>" +e '= BIN BIT_OR' +e "<$((0|0))>" +e "<$(( 0 | 0 ))>" +e "<$((0|1))>" +e "<$(( 0 | 1 ))>" +e "<$((1|0))>" +e "<$(( 1 | 0 ))>" +e "<$((1|1))>" +e "<$(( 1 | 1 ))>" +e "<$((1111|2222))>" +e "<$((2222|1111))>" +e "<$(( +0x10 | +0x11 ))>" +e "<$(( -0x10 | -0x11 ))>" +e "<$(( -0x10 | -0x11 ))>" +e "<$(( +64#10 | -64#11 ))>" +e "<$(( +0x11 | +0x10 ))>" +e "<$(( -0x11 | -0x10 ))>" +e "<$(( -0x11 | -0x10 ))>" +e "<$(( +64#11 | -64#10 ))>" +e "<$(( +64 | +1024 ))>" +e "<$((0x8000000000000000|-1))>" +e "<$((0x8000000000000000|1))>" +e "<$((0x7FFFFFFFFFFFFFFF|-1))>" +e "<$((0x7FFFFFFFFFFFFFFF|1))>" +e "<$((0xFFFFFFFFFFFFFFFF|-1))>" +e "<$((0xFFFFFFFFFFFFFFFF|1))>" +e "<$((0x8000000000000000|-11))>" +e "<$((0x8000000000000000|11))>" +e "<$((0x7FFFFFFFFFFFFFFF|-11))>" +e "<$((0x7FFFFFFFFFFFFFFF|11))>" +e "<$((0xFFFFFFFFFFFFFFFF|-11))>" +e "<$((0xFFFFFFFFFFFFFFFF|11))>" +e '= BIN BIT_XOR' +e "<$((0^0))>" +e "<$(( 0 ^ 0 ))>" +e "<$((0^1))>" +e "<$(( 0 ^ 1 ))>" +e "<$((1^0))>" +e "<$(( 1 ^ 0 ))>" +e "<$((1^1))>" +e "<$(( 1 ^ 1 ))>" +e "<$((1111^2222))>" +e "<$((2222^1111))>" +e "<$(( +0x10 ^ +0x11 ))>" +e "<$(( -0x10 ^ -0x11 ))>" +e "<$(( -0x10 ^ -0x11 ))>" +e "<$(( +64#10 ^ -64#11 ))>" +e "<$(( +0x11 ^ +0x10 ))>" +e "<$(( -0x11 ^ -0x10 ))>" +e "<$(( -0x11 ^ -0x10 ))>" +e "<$(( +64#11 ^ -64#10 ))>" +e "<$(( +64 ^ +1024 ))>" +e "<$((0x8000000000000000^-1))>" +e "<$((0x8000000000000000^1))>" +e "<$((0x7FFFFFFFFFFFFFFF^-1))>" +e "<$((0x7FFFFFFFFFFFFFFF^1))>" +e "<$((0xFFFFFFFFFFFFFFFF^-1))>" +e "<$((0xFFFFFFFFFFFFFFFF^1))>" +e "<$((0x8000000000000000^-11))>" +e "<$((0x8000000000000000^11))>" +e "<$((0x7FFFFFFFFFFFFFFF^-11))>" +e "<$((0x7FFFFFFFFFFFFFFF^11))>" +e "<$((0xFFFFFFFFFFFFFFFF^-11))>" +e "<$((0xFFFFFFFFFFFFFFFF^11))>" +e '= BIN BIT_AND' +e "<$((0&0))>" +e "<$(( 0 & 0 ))>" +e "<$((0&1))>" +e "<$(( 0 & 1 ))>" +e "<$((1&0))>" +e "<$(( 1 & 0 ))>" +e "<$((1&1))>" +e "<$(( 1 & 1 ))>" +e "<$((1111&2222))>" +e "<$((2222&1111))>" +e "<$(( +0x10 & +0x11 ))>" +e "<$(( -0x10 & -0x11 ))>" +e "<$(( -0x10 & -0x11 ))>" +e "<$(( +64#10 & -64#11 ))>" +e "<$(( +0x11 & +0x10 ))>" +e "<$(( -0x11 & -0x10 ))>" +e "<$(( -0x11 & -0x10 ))>" +e "<$(( +64#11 & -64#10 ))>" +e "<$(( +64 & +1024 ))>" +e "<$((0x8000000000000000&-1))>" +e "<$((0x8000000000000000&1))>" +e "<$((0x7FFFFFFFFFFFFFFF&-1))>" +e "<$((0x7FFFFFFFFFFFFFFF&1))>" +e "<$((0xFFFFFFFFFFFFFFFF&-1))>" +e "<$((0xFFFFFFFFFFFFFFFF&1))>" +e "<$((0x8000000000000000&-11))>" +e "<$((0x8000000000000000&11))>" +e "<$((0x7FFFFFFFFFFFFFFF&-11))>" +e "<$((0x7FFFFFFFFFFFFFFF&11))>" +e "<$((0xFFFFFFFFFFFFFFFF&-11))>" +e "<$((0xFFFFFFFFFFFFFFFF&11))>" +e '= BIN EQ' +e "<$((0==0))>" +e "<$(( 000 == 0X0 ))>" +e "<$((01 == 64#1))>" +e "<$((01 == 64#1))>" +e "<$((0x1234 == 4660))>" +e "<$((0x1234 == 011064))>" +s I=33 J=33;e "<$((I==J))>" +s I=33 J=33;e "<$(( I == J ))>" +e "<$((0==1))>" +e "<$((0==0000000000000000000000001))>" +e "<$((1==2))>" +e "<$((0x1234 == 04660))>" +e "<$((0x1234 == 0x11064))>" +s I=10 J=33;e "<$((I==J))>" +s I=-10 J=-33;e "<$((I==J))>" +s I=-33 J=-33;e "<$((I==J))>" +e '= BIN NE' +e "<$((0!=0))>" +e "<$(( 000 != 0X0 ))>" +e "<$((01 != 64#1))>" +e "<$((01 != 64#1))>" +e "<$((0x1234 != 4660))>" +e "<$((0x1234 != 011064))>" +s I=33 J=33;e "<$((I!=J))>" +s I=33 J=33;e "<$(( I != J ))>" +e "<$((0!=1))>" +e "<$((0!=0000000000000000000000001))>" +e "<$((1!=2))>" +e "<$((0x1234 != 04660))>" +e "<$((0x1234 != 0x11064))>" +s I=10 J=33;e "<$((I!=J))>" +s I=-10 J=-33;e "<$((I!=J))>" +s I=-33 J=-33;e "<$((I!=J))>" +e '= BIN LE' +e "<$((0<=0))>" +e "<$(( 000 <= 0X0 ))>" +e "<$((01 <= 64#1))>" +e "<$((01 <= 64#2))>" +e "<$((02 <= 64#1))>" +e "<$((0x1234 <= 4660))>" +e "<$((0x1234 <= 011064))>" +e "<$((0x1233 <= 011064))>" +e "<$((0x1235 <= 011064))>" +s I=33 J=33;e "<$((I<=J))>" +s I=33 J=33;e "<$((I<=J))>" +s I=32 J=33;e "<$((I<=J))>" +s I=34 J=33;e "<$((I<=J))>" +s I=-33 J=-33;e "<$((I<=J))>" +s I=-33 J=-33;e "<$((I<=J))>" +s I=-32 J=-33;e "<$((I<=J))>" +s I=-34 J=-33;e "<$((I<=J))>" +e '= BIN GE' +e "<$((0>=0))>" +e "<$(( 000 >= 0X0 ))>" +e "<$((01 >= 64#1))>" +e "<$((01 >= 64#2))>" +e "<$((02 >= 64#1))>" +e "<$((0x1234 >= 4660))>" +e "<$((0x1234 >= 011064))>" +e "<$((0x1233 >= 011064))>" +e "<$((0x1235 >= 011064))>" +s I=33 J=33;e "<$((I>=J))>" +s I=33 J=33;e "<$((I>=J))>" +s I=32 J=33;e "<$((I>=J))>" +s I=34 J=33;e "<$((I>=J))>" +s I=-33 J=-33;e "<$((I>=J))>" +s I=-33 J=-33;e "<$((I>=J))>" +s I=-32 J=-33;e "<$((I>=J))>" +s I=-34 J=-33;e "<$((I>=J))>" +e '= BIN LT' +e "<$((0<0))>" +e "<$(( 000 < 0X0 ))>" +e "<$((01 < 64#1))>" +e "<$((01 < 64#2))>" +e "<$((02 < 64#1))>" +e "<$((0x1234 < 4660))>" +e "<$((0x1234 < 011064))>" +e "<$((0x1233 < 011064))>" +e "<$((0x1235 < 011064))>" +s I=33 J=33;e "<$((I" +s I=33 J=33;e "<$((I" +s I=32 J=33;e "<$((I" +s I=34 J=33;e "<$((I" +s I=-33 J=-33;e "<$((I" +s I=-33 J=-33;e "<$((I" +s I=-32 J=-33;e "<$((I" +s I=-34 J=-33;e "<$((I" +e '= BIN GT' +e "<$((0>0))>" +e "<$(( 000 > 0X0 ))>" +e "<$((01 > 64#1))>" +e "<$((01 > 64#2))>" +e "<$((02 > 64#1))>" +e "<$((0x1234 > 4660))>" +e "<$((0x1234 > 011064))>" +e "<$((0x1233 > 011064))>" +e "<$((0x1235 > 011064))>" +s I=33 J=33;e "<$((I>J))>" +s I=33 J=33;e "<$((I>J))>" +s I=32 J=33;e "<$((I>J))>" +s I=34 J=33;e "<$((I>J))>" +s I=-33 J=-33;e "<$((I>J))>" +s I=-33 J=-33;e "<$((I>J))>" +s I=-32 J=-33;e "<$((I>J))>" +s I=-34 J=-33;e "<$((I>J))>" +# +# COMMA below +e '= PRECEDENCE I' +e "<$(( 1 + 2 + 3 ))>" +e "<$(( 1 - 2 + 3 ))>" +e "<$(( 3 - 2 - 1 ))>" +e "<$(( 3 - 2 + 1 ))>" +e "<$(( - 2 + 1 ))>" +e "<$(( 2 + -1 ))>" +e "<$(( ! 2 + 1 ))>" +e "<$(( 2 + !1 ))>" +e "<$(( 3 * 2 + 2 ))>" +e "<$(( 3 + 2 * 2 ))>" +e "<$(( 3 * 2 * 2 ))>" +e "<$(( 9 / 3 + 2 ))>" +e "<$(( 9 + 3 / 2 ))>" +e "<$(( 9 / 3 / 2 ))>" +e "<$(( 9 << 1 + 2 ))>" +e "<$(( 9 + 3 << 2 ))>" +e "<$(( 9 << 3 << 2 ))>" +e "<$(( 9 >> 1 + 2 ))>" +e "<$(( 9 + 3 >> 2 ))>" +e "<$(( 19 >> 3 >> 1 ))>" +e "<$(( 19 >> 3 << 1 ))>" +e "<$(( 19 << 3 >> 1 ))>" +e "<$(( 2 + 3 < 3 * 2 ))>" +e "<$(( 2 << 3 >= 3 << 2 ))>" +e "<$(( 0xfD & 0xF == 0xF ))>" +e "<$((0xfD&0xF==0xF))>" +e "<$(( 3 * 7 , 2 << 8 , 9 - 7 ))>" +e "<$((3*7,2<<8,9-7))>" +e '= PARENS' +e "<$(((1 + 2) + 3))>" +e "<$(((1+2)+3))>" +e "<$((1 - (2 + 3)))>" +e "<$((1-(2+3)))>" +e "<$((3 - (2 - 1)))>" +e "<$((3-(2-1)))>" +e "<$((3 - ( 2 + 1 )))>" +e "<$((3-(2+1)))>" +e "<$((- (2 + 1)))>" +e "<$((-(2+1)))>" +e "<$((! (2 + 1)))>" +e "<$((!(2+1)))>" +e "<$((3 * (2 + 2)))>" +e "<$((3*(2+2)))>" +e "<$(((3 + 2) * 2))>" +e "<$(((3+2)*2))>" +e "<$((3 * (2 * 2)))>" +e "<$((3*(2*8)))>" +e "<$((9 / (3 + 2)))>" +e "<$((9/(3+2)))>" +e "<$((( 9 + 3 ) / 2))>" +e "<$(((9+3)/2))>" +e "<$((9 / ( 3 / 2 )))>" +e "<$((9/(3/2)))>" +e "<$((( 9 << 1 ) + 2))>" +e "<$(((9<<1)+2))>" +e "<$((9 + (3 << 2)))>" +e "<$((9+(3<<2)))>" +e "<$((9 << (3 << 2)))>" +e "<$((9<<(3<<2)))>" +e "<$(((9 >> 1) + 2))>" +e "<$(((9>>1)+2))>" +e "<$((9 + (3 >> 2)))>" +e "<$((9+(3>>2)))>" +e "<$((19 >> (3 >> 1)))>" +e "<$((19>>(3>>1)))>" +e "<$((19 >> (3 << 1)))>" +e "<$((19>>(3<<1)))>" +e "<$((19 << (3 >> 1)))>" +e "<$((19<<(3>>1)))>" +e "<$((2 + (3 < 3) * 2))>" +e "<$((2+(3<3)*2))>" +e "<$((2 << ((3 >= 3) << 2)))>" +e "<$((2<<((3>=3)<<2)))>" +e "<$(((0xfD & 0xF) == 0xF))>" +e "<$(((0xfD&0xF)==0xF))>" +e "<$((3 * (7 , 2) << (8 , 9 - 7)))>" +e "<$((3*(7,2)<<(8,9-7)))>" +# +# COND BELOW +e '= ASSIGN I' +unset I;p "<$(( I = 3 ))>";e "<$I>" +unset I;p "<$((I=3))>";e "<$I>" +s I=10;p "<$((I=3))>";e "<$I>" +s I=10;p "<$((I+=1))>";e "<$I>" +s I=10;p "<$((I-=1))>";e "<$I>" +s I=10;p "<$((I*=1))>";e "<$I>" +s I=10;p "<$((I*=2))>";e "<$I>" +s I=10;p "<$((I/=1))>";e "<$I>" +s I=10;p "<$((I/=2))>";e "<$I>" +s I=10;p "<$((I%=1))>";e "<$I>" +s I=10;p "<$((I%=2))>";e "<$I>" +s I=10;p "<$((I**=1))>";e "<$I>" +s I=10;p "<$((I**=2))>";e "<$I>" +s I=10;p "<$((I**=1+1))>";e "<$I>" +s I=10;p "<$((I|=1))>";e "<$I>" +s I=10;p "<$((I^=1))>";e "<$I>";p "<$((I^=1))>";e "<$I>" +s I=10;p "<$((I&=2))>";e "<$I>" +s I=10;p "<$((I>>=1))>";e "<$I>" +s I=10;p "<$((I<<=1))>";e "<$I>" +e '= ASSIGN II' +s I=2;p "<$(((I+=1)-1))>";e "<$I>" +s I=4;p "<$(((I-=1)+1))>";e "<$I>" +s I=0 J=0;p "<$(((I=5)*(J=7)+1))>";e "<$I><$J>" +s I=99 J=17;p "<$(((I+=1)*(J-=2)+1))>";e "<$I><$J>" +s I=10;p "<$((I=2,I|=1))>";e "<$I>" +s I=0 J=0 Y=0 Z=0;p "<$((I=1,J=2,Y=3,Z=4,Z+=I+J+Y))>";e "<$I><$J><$Y><$Z>" +e '= POSTFIX' +s I=1;p "<$((I++))>";e "<$I>" +s I=1 J=0;p "<$((J=I++))>";e "<$I><$J>" +s I=1 J=10;p "<$((J++*I++))>";e "<$I><$J>" +s I=1 J=10;p "<$(((J++)*(I++)))>";e "<$I><$J>" +s I=1;p "<$((I--))>";e "<$I>" +s I=1 J=0;p "<$((J=I--))>";e "<$I><$J>" +s I=1 J=10;p "<$((J--*I--))>";e "<$I><$J>" +s I=1 J=10;p "<$(((J--)*(I--)))>";e "<$I><$J>" +e '= PREFIX' +s I=1;p "<$((++I))>";e "<$I>" +s I=1 J=0;p "<$((J=++I))>";e "<$I><$J>" +s I=1 J=10;p "<$((++J*++I))>";e "<$I><$J>" +s I=1 J=10;p "<$((++(J)*++(I)))>";e "<$I><$J>" +s I=1 J=10;p "<$(((++J)*(++I)))>";e "<$I><$J>" +s I=1;p "<$((--I))>";e "<$I>" +s I=1 J=0;p "<$((J=--I))>";e "<$I><$J>" +s I=2 J=10;p "<$((--J*--I))>";e "<$I><$J>" +s I=1 J=10;p "<$((--(J)*--(I)))>";e "<$I><$J>" +s I=1 J=10;p "<$(((--J)*(--I)))>";e "<$I><$J>" +e '= VAR RECUR' +s I='1 + 1';p "<$((I))>";e "<$I>" +s I='1 + 1';p "<$((+I))>";e "<$I>" +s I='1 + 1';p "<$((++I))>";e "<$I>" +s I='1 + 1';p "<$((I++))>";e "<$I>" +s I='1 + 1';p "<$((1+I))>";e "<$I>" +s I='1 + 1 * 2';p "<$((I+1))>";e "<$I>" +s I='(1 + 1) * 2';p "<$((I+1))>";e "<$I>" +s I='1 + 1' J='3 / 2';p "<$((I=I+J))>";e "<$I><$J>" +s I='1 + 1';p "<$((I=I))>";e "<$I>" +s I='1 + 1';p "<$((I=+I))>";e "<$I>" +s I='1 + 1';p "<$((I=1+I))>";e "<$I>" +s I='1 + 1 * 2';p "<$((I=I+1))>";e "<$I>" +s I='(1 + 1) * 2';p "<$((I=I+1))>";e "<$I>" +s I='1 + 1' J='3 / 2';p "<$((I+=I+J))>";e "<$I><$J>" +e '= COMMA' +e "<$(( 1 , 2 ))>" +e "<$(( 1 , 2 , 3 ))>" +e "<$(( 1 , 2 , 3 , 4 ))>" +e "<$((1,2,3,4))>" +s I='1 + 1';p "<$(( I=10 , I+=I, I=I**2, I/=3 ))>";e "<$I>" +s I1=I2=10 I2=3;p "<$((I1,I2))>";e "<$I1><$I2>" +e '= COND' +e "<$(( +0 ? 2 : 3 ))>" +e "<$((-0?2:3))>" +e "<$(( +1 ? 2 : 3 ))>" +e "<$(( 1-1 ? 2 : 3 ))>" +e "<$(( 1-0 ? 2 : 3 ))>" +e "<$((-1?2:3))>" +e "<$(( 0x1234 ? 111 : 222 ))>" +e "<$((1**2 ? 5 : 7))>" +e "<$((0**2 ? 5 : 7))>" +e "<$((0**2>=0?5:7))>" +e "<$((-1<=0**2?5:7))>" +e "<$((1<=0**2?5:7))>" +e "<$((1>2||1*0?5:7))>" +e "<$((1>2&&1*0?5:7))>" +e "<$((1<2&&1*0?5:7))>" +e "<$((1<2&&1*0+1?5:7))>" +e '-- COND .2' +e "<$(( 1 < 2 ? -1 : 1 > 2 ? 1 : 0 ))>" +e "<$((1 < 1 ? -1 : 1 > 1 ? 1 : 0))>" +e "<$((2<1?-1:2>1?1:0))>" +e "<$((4<5 ? 1 : 32))>" +e "<$((4>5 ? 1 : 32))>" +e "<$((4>(2+3) ? 1 : 32))>" +e "<$((4<(2+3) ? 1 : 32))>" +e "<$(((2+2)<(2+3) ? 1 : 32))>" +e "<$(((2+2)>(2+3) ? 1 : 32))>" +## grouping protects precedence in : parts (syntax error tests below) +e '-- COND .3' +e "<$((1-1 < 1 ? 2,4 : 1,3))>" +e "<$((0<1?2,4:(1,3)))>" +e "<$((0,1,2,0?2,4:1,3))>" +e "<$((0,1,2,1?2,4:1,3))>" +e "<$((0,1,2,0?2,4:(1,3)))>" +e "<$((0,1,2,1?2,4:(1,3)))>" +e "<$((0,1,2,0?(2,4):1,3))>" +e "<$((0,1,2,1?(2,4):1,3))>" +e "<$((0,1,2,0?(2,4):(1,3)))>" +e "<$((0,1,2,1?(2,4):(1,3)))>" +e "<$((0?2:((0,3)?1:4)))>" +e "<$((1?2:3,0?1:4))>" +e "<$((1?2:3,0?1:4?5:6))>" +e "<$((1?2:(3,0)?1:4?5:6))>" +e "<$((1?2:3,0?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,0)?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,0)?(4,5):5,6?7,8:9,10))>" +e "<$((1?2:(3,0)?(4,5):(5,6)?7,8:9,10))>" +e "<$((1?2:(3,0)?(4,5):(5,6)?(7,8):9,10))>" +e "<$((1?2:(3,0)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((1?2:3,1?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,1)?4,5:5,6?7,8:9,10))>" +e "<$((1?2:(3,1)?(4,5):5,6?7,8:9,10))>" +e "<$((1?2:(3,1)?(4,5):(5,6)?7,8:9,10))>" +e "<$((1?2:(3,1)?(4,5):(5,6)?(7,8):9,10))>" +e "<$((1?2:(3,1)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((0?2:(3,1)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((0?2:(3,1)?4,5:(5,6)?7,8:(9,10)))>" +e "<$((0?2:(3,0)?(4,5):(5,6)?(7,8):(9,10)))>" +e "<$((0?2:(3,0)?4,5:(5,6)?7,8:(9,10)))>" +e "<$((0?2:(3,0)?(4,5):(5,0)?(7,8):(9,10)))>" +e "<$((0?2:(3,0)?4,5:(5,0)?7,8:(9,10)))>" +e "<$((0?2:3,0?4,5:(5,0)?7,8:(9,10)))>" +e "<$((0?2:(3,0)?4,5:5,0?7,8:(9,10)))>" +e "<$((0?2:(3,0)?4,5:(5,0)?7,8:9,10))>" +e '-- COND .4' +e "<$((1?2?3?4?5:6:7:8:9))>" +e "<$((1?2?3?0?5:6:7:8:9))>" +e "<$((1?2?0?0?5:6:7:8:9))>" +e "<$((1?0?0?0?5:6:7:8:9))>" +e "<$((0?0?0?0?5:6:7:8:9))>" +e "<$((0?3+4?10:11:5+6?12:13))>" +e "<$((1?3+4?10:11:5+6?12:13))>" +e "<$((0?(3+4)?(10):(11):((5+6)?12:13)))>" +e "<$((1?(3+4)?(10):(11):((5+6)?12:13)))>" +e '-- COND .5' +e "<$((0?3+4?10:11?20+1:22*1:5+6?12:13))>" +e "<$((1?3+4?10:11?20+1:22*1:5+6?12:13))>" +e "<$((0?(3+4)?(10):(11)?(20+1):(22*1):((5+6)?12:13)))>" +e "<$((1?(3+4)?(10):(11)?(20+1):(22*1):((5+6)?12:13)))>" +e '-- COND .6' +e "<$((0?3+4?9:11?20+1:22*1:5+6?12:13))>" +e "<$((1?3+4?9:11?20+1:22*1:5+6?12:13))>" +e "<$((0?10+11?20+1?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?0?20+1?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20+1?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?0?22*1?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?0?23**1:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?0:24**1:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?23**1:0:25/1?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?23**1:24**1:0?26%27:56>>1:-1:-2))>" +e "<$((1?10?20?22*1?23**1:24**1:25/1?0:56>>1:-1:-2))>" +e '-- COND .7' +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? (I2 < I3) ? I3 *= I3 : (I2 *= I2) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? ((I2 < I3) ? I3 *= I3 : (I2 *= I2)) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$((((I1";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1";\ + e "<$I1><$I2><$I3><$I4><$I5>" +# only first +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? (I2 > I3) ? I3 *= I3 : (I2 *= I2) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(((I1I3)?I3*=I3:(I2*=I2):(I1*=I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( (I1 < I2) ? ((I2 > I3) ? I3 *= I3 : (I2 *= I2)) : (I1 *= I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ + p "<$(( ((I1 < I2) ? ((I2 > I3) ? (I3 *= I3):(I2 *= I2)):(I1 *= I1))))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1I3)?(I3>I4)?I4*=I4:(I3*=I3):(I2*=I2):(I1*=I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +# last not etc. +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1I4)?I4*=I4:(I3*=I3):(I2*=I2):(I1*=I1)))>";\ + e "<$I1><$I2><$I3><$I4>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1I3)?(I3";\ + e "<$I1><$I2><$I3><$I4><$I5>" +s I1=2 I2=3 I3=4 I4=5;\ +p "<$(((I1>I2)?(I2";\ + e "<$I1><$I2><$I3><$I4><$I5>" +e '-- COND .8' +s I=0;p "<$((1?I=2:(I=3),8,10))>";e "<$I>" +s I=0;p "<$((1?20:(I+=2)))>";e "<$I>" +s I=0;p "<$((1?I+=10:(I+=2)))>";e "<$I>" +s I=0;p "<$((0?I+=2:20))>";e "<$I>" +s I=0;p "<$((0?I+=2:(I+=10)))>";e "<$I>" +s I=0;p "<$((0?(I+=2):(20)))>";e "<$I>" +s I=0;p "<$((0?(I+=2):(I+=20)))>";e "<$I>" +e '-- COND .9' +s I1=+E+ I2=1+1;p "<$((0?I1:I2))>";e "<$I1><$I2>" +s I1=1+1 I2=+E+;p "<$((1?I1:I2))>";e "<$I1><$I2>" +s I1=+E+ I2=1+1;p "<$((0?I1=1:(I2=2)))>";e "<$I1><$I2>" +s I1=1+1 I2=+E+;p "<$((1?I1=1:(I2=2)))>";e "<$I1><$I2>" +s I1=+E+ I2=1+1;p "<$((0?I1*=I1:(I2*=I2)))>";e "<$I1><$I2>" +s I1=1+1 I2=+E+;p "<$((1?I1*=I1:(I2*=I2)))>";e "<$I1><$I2>" +e '-- COND .10' +s I1=+E+ I2=+E+ I3=+E+ I4=-1;p "<$((0?I1?I2:I3:I4))>";e "<$I1><$I2><$I3><$I4>" +s I1=1 I2=2 I3=+E+ I4=+E+;p "<$((1?I1?I2:I3:I4))>";e "<$I1><$I2><$I3><$I4>" +s I1=0 I2=+E+ I3=3 I4=+E+;p "<$((1?I1?I2:I3:I4))>";e "<$I1><$I2><$I3><$I4>" +e '= WILD I' +e "<$(( 3 + ( 11 ) ))>" +e "<$((1 + (2 - 2)))>" +e "<$((1 + (2 - 2)))>" +e "<$(( (( 3 / 3 )) + ((1*1*1)) - (( 7 % 6 ))))>" +e "<$(( 3+((2 * 2))/6 ))>" +e "<$(( 1 + 1 - 3 * 3 + 99-88 / 17))>" +e "<$(( 1 << 2 % 1+2 * 4 - (2 + 2 + 1) * 6 / 7 + 4 * 2 + (81/9)))>" +s I1=I2=10 I2=3;p "<$((I1 + I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=3;p "<$((I1 * I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=3;p "<$((I1 % I2))>";e "<$I1><$I2>" +e '= WILD II' +s I=10;p "<$((3+(3*(I=11))))>";e "<$I>" +s I=10;p "<$((3+(3*(I++))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,I++))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,++I))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,++++I))))>";e "<$I>" +s I=10;p "<$((3+(3*(I=11,+++++++++++++++++++++++-+++++I))))>";e "<$I>" +e "<$((3+(3*(+++++++++++++++++++++++-+++++10))))>" +s I=10;p "<$(( +10 + + +I ))>";e "<$I>" +s I=10;p "<$(( +10 + ++I ))>";e "<$I>" +s I=10;p "<$(( +10 ++ +I ))>";e "<$I>" +s I=10;p "<$(( +10 +++ I ))>";e "<$I>" +s I=10;p "<$(( +10+++I ))>";e "<$I>" +s I=10;p "<$((+10++I))>";e "<$I>" +s I=10;p "<$((+10 + + + ++++ +I))>";e "<$I>" +e "<$(( +10 + + + ++++ +11 ))>" +e "<$(( +10 + + + ++++ ++11 ))>" +e "<$((+10++++++++11))>" +e '= WILD RECUR' # (some yet) +s I1=I2=10 I2=5;p "<$((I1+=I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1,I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1+I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I2=0 I2=5 I3=I2+=1;p "<$((I1?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I1=10 I2=5 I3=I2+=1;p "<$((I1=0?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I1=10 I2=5 I3=I2+=1;p "<$((I1=1?I1:I3))>";e "<$I1><$I2><$I3>" +s I1=I2='(I2=10)+1' I2=5 I3=I2+=1;p "<$((I1,I3))>";e "<$I1><$I2><$I3>" +s I1=I2='(I2=(I2=10)+1)' I2=5 I3=I2+=1;p "<$((I1,I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1+I3*I1*I3/I1%I3))>";e "<$I1><$I2><$I3>" +s I1=I2=10 I2=5 I3=I2+=1;p "<$((I1+I3*I1*I3/I1%I3))>";e "<$I1><$I2><$I3>" +s I1=I2=+E+ I2=5;p "<$((I1=10))>";e "<$I1><$I2>" +s I1=I2=+E+ I2=5;p "<$((0?I1:++I2))>";e "<$I1><$I2>" +s I1=I2=10 I2=5;p "<$((I2,(1?I1:++I2)))>";e "<$I1><$I2>" +s I1=5 I2=10 I3=20;p "<$((I1-=5,1?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1=Ix,1?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1=Ix?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1*=Ix?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((0,I1*=Ix?I2:I3))>";e "<$I1><$I2><$I3>" +s I1=5 Ix=6 I2=10 I3=20;p "<$((I1*=Ix?I2:I3,Ix=21,I1*=Ix?I2:I3))>";e "<$I1><$I2><$I3>" diff --git a/shell/math.c b/shell/math.c index 76d22c9bd5..b38fc0ce69 100644 --- a/shell/math.c +++ b/shell/math.c @@ -113,401 +113,24 @@ * - protect $((num num)) as true zero expr (Manuel's error) * - always use special isspace(), see comment from bash ;-) */ +/* Copyright (c) 2022 Steffen Nurpmeso . + * SPDX-License-Identifier: ISC + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include "libbb.h" #include "math.h" -typedef unsigned char operator; - -/* An operator's token id is a bit of a bitfield. The lower 5 bits are the - * precedence, and 3 high bits are an ID unique across operators of that - * precedence. The ID portion is so that multiple operators can have the - * same precedence, ensuring that the leftmost one is evaluated first. - * Consider * and / - */ -#define tok_decl(prec,id) (((id)<<5) | (prec)) -#define PREC(op) ((op) & 0x1F) - -#define TOK_LPAREN tok_decl(0,0) - -#define TOK_COMMA tok_decl(1,0) - -/* All assignments are right associative and have the same precedence, - * but there are 11 of them, which doesn't fit into 3 bits for unique id. - * Abusing another precedence level: - */ -#define TOK_ASSIGN tok_decl(2,0) -#define TOK_AND_ASSIGN tok_decl(2,1) -#define TOK_OR_ASSIGN tok_decl(2,2) -#define TOK_XOR_ASSIGN tok_decl(2,3) -#define TOK_PLUS_ASSIGN tok_decl(2,4) -#define TOK_MINUS_ASSIGN tok_decl(2,5) -#define TOK_LSHIFT_ASSIGN tok_decl(2,6) -#define TOK_RSHIFT_ASSIGN tok_decl(2,7) - -#define TOK_MUL_ASSIGN tok_decl(3,0) -#define TOK_DIV_ASSIGN tok_decl(3,1) -#define TOK_REM_ASSIGN tok_decl(3,2) - -#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0) - -/* Ternary conditional operator is right associative too */ -#define TOK_CONDITIONAL tok_decl(4,0) -#define TOK_CONDITIONAL_SEP tok_decl(4,1) - -#define TOK_OR tok_decl(5,0) - -#define TOK_AND tok_decl(6,0) - -#define TOK_BOR tok_decl(7,0) - -#define TOK_BXOR tok_decl(8,0) - -#define TOK_BAND tok_decl(9,0) - -#define TOK_EQ tok_decl(10,0) -#define TOK_NE tok_decl(10,1) - -#define TOK_LT tok_decl(11,0) -#define TOK_GT tok_decl(11,1) -#define TOK_GE tok_decl(11,2) -#define TOK_LE tok_decl(11,3) - -#define TOK_LSHIFT tok_decl(12,0) -#define TOK_RSHIFT tok_decl(12,1) - -#define TOK_ADD tok_decl(13,0) -#define TOK_SUB tok_decl(13,1) - -#define TOK_MUL tok_decl(14,0) -#define TOK_DIV tok_decl(14,1) -#define TOK_REM tok_decl(14,2) - -/* Exponent is right associative */ -#define TOK_EXPONENT tok_decl(15,1) - -/* Unary operators */ -#define UNARYPREC 16 -#define TOK_BNOT tok_decl(UNARYPREC,0) -#define TOK_NOT tok_decl(UNARYPREC,1) - -#define TOK_UMINUS tok_decl(UNARYPREC+1,0) -#define TOK_UPLUS tok_decl(UNARYPREC+1,1) - -#define PREC_PRE (UNARYPREC+2) - -#define TOK_PRE_INC tok_decl(PREC_PRE, 0) -#define TOK_PRE_DEC tok_decl(PREC_PRE, 1) - -#define PREC_POST (UNARYPREC+3) - -#define TOK_POST_INC tok_decl(PREC_POST, 0) -#define TOK_POST_DEC tok_decl(PREC_POST, 1) - -#define SPEC_PREC (UNARYPREC+4) - -#define TOK_NUM tok_decl(SPEC_PREC, 0) -#define TOK_RPAREN tok_decl(SPEC_PREC, 1) - -static int -is_assign_op(operator op) -{ - operator prec = PREC(op); - fix_assignment_prec(prec); - return prec == PREC(TOK_ASSIGN) - || prec == PREC_PRE - || prec == PREC_POST; -} - -static int -is_right_associative(operator prec) -{ - return prec == PREC(TOK_ASSIGN) - || prec == PREC(TOK_EXPONENT) - || prec == PREC(TOK_CONDITIONAL); -} - - -typedef struct { - arith_t val; - /* We acquire second_val only when "expr1 : expr2" part - * of ternary ?: op is evaluated. - * We treat ?: as two binary ops: (expr ? (expr1 : expr2)). - * ':' produces a new value which has two parts, val and second_val; - * then '?' selects one of them based on its left side. - */ - arith_t second_val; - char second_val_present; - /* If NULL then it's just a number, else it's a named variable */ - char *var; -} var_or_num_t; - -typedef struct remembered_name { - struct remembered_name *next; - const char *var; -} remembered_name; - - -static arith_t -evaluate_string(arith_state_t *math_state, const char *expr); - -static const char* -arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) -{ - if (t->var) { - const char *p = math_state->lookupvar(t->var); - if (p) { - remembered_name *cur; - remembered_name cur_save; - - /* did we already see this name? - * testcase: a=b; b=a; echo $((a)) - */ - for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) { - if (strcmp(cur->var, t->var) == 0) { - /* Yes */ - return "expression recursion loop detected"; - } - } - - /* push current var name */ - cur = math_state->list_of_recursed_names; - cur_save.var = t->var; - cur_save.next = cur; - math_state->list_of_recursed_names = &cur_save; - - /* recursively evaluate p as expression */ - t->val = evaluate_string(math_state, p); - - /* pop current var name */ - math_state->list_of_recursed_names = cur; - - return math_state->errmsg; - } - /* treat undefined var as 0 */ - t->val = 0; - } - return 0; -} - -/* "Applying" a token means performing it on the top elements on the integer - * stack. For an unary operator it will only change the top element, but a - * binary operator will pop two arguments and push the result */ -static NOINLINE const char* -arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_or_num_t **numstackptr) -{ -#define NUMPTR (*numstackptr) - - var_or_num_t *top_of_stack; - arith_t rez; - const char *err; - - /* There is no operator that can work without arguments */ - if (NUMPTR == numstack) - goto err; - - top_of_stack = NUMPTR - 1; - - /* Resolve name to value, if needed */ - err = arith_lookup_val(math_state, top_of_stack); - if (err) - return err; - - rez = top_of_stack->val; - if (op == TOK_UMINUS) - rez = -rez; - else if (op == TOK_NOT) - rez = !rez; - else if (op == TOK_BNOT) - rez = ~rez; - else if (op == TOK_POST_INC || op == TOK_PRE_INC) - rez++; - else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) - rez--; - else if (op != TOK_UPLUS) { - /* Binary operators */ - arith_t right_side_val; - char bad_second_val; - - /* Binary operators need two arguments */ - if (top_of_stack == numstack) - goto err; - /* ...and they pop one */ - NUMPTR = top_of_stack; /* this decrements NUMPTR */ - - bad_second_val = top_of_stack->second_val_present; - if (op == TOK_CONDITIONAL) { /* ? operation */ - /* Make next if (...) protect against - * $((expr1 ? expr2)) - that is, missing ": expr" */ - bad_second_val = !bad_second_val; - } - if (bad_second_val) { - /* Protect against $((expr expr1 : expr2)) */ - return "malformed ?: operator"; - } - - top_of_stack--; /* now points to left side */ - - if (op != TOK_ASSIGN) { - /* Resolve left side value (unless the op is '=') */ - err = arith_lookup_val(math_state, top_of_stack); - if (err) - return err; - } - - right_side_val = rez; - rez = top_of_stack->val; - if (op == TOK_CONDITIONAL) /* ? operation */ - rez = (rez ? right_side_val : top_of_stack[1].second_val); - else if (op == TOK_CONDITIONAL_SEP) { /* : operation */ - if (top_of_stack == numstack) { - /* Protect against $((expr : expr)) */ - return "malformed ?: operator"; - } - top_of_stack->second_val_present = op; - top_of_stack->second_val = right_side_val; - } - else if (op == TOK_BOR || op == TOK_OR_ASSIGN) - rez |= right_side_val; - else if (op == TOK_OR) - rez = right_side_val || rez; - else if (op == TOK_BAND || op == TOK_AND_ASSIGN) - rez &= right_side_val; - else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) - rez ^= right_side_val; - else if (op == TOK_AND) - rez = rez && right_side_val; - else if (op == TOK_EQ) - rez = (rez == right_side_val); - else if (op == TOK_NE) - rez = (rez != right_side_val); - else if (op == TOK_GE) - rez = (rez >= right_side_val); - else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) - rez >>= right_side_val; - else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) - rez <<= right_side_val; - else if (op == TOK_GT) - rez = (rez > right_side_val); - else if (op == TOK_LT) - rez = (rez < right_side_val); - else if (op == TOK_LE) - rez = (rez <= right_side_val); - else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) - rez *= right_side_val; - else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) - rez += right_side_val; - else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) - rez -= right_side_val; - else if (op == TOK_ASSIGN || op == TOK_COMMA) - rez = right_side_val; - else if (op == TOK_EXPONENT) { - arith_t c; - if (right_side_val < 0) - return "exponent less than 0"; - c = 1; - while (--right_side_val >= 0) - c *= rez; - rez = c; - } - else if (right_side_val == 0) - return "divide by zero"; - else if (op == TOK_DIV || op == TOK_DIV_ASSIGN - || op == TOK_REM || op == TOK_REM_ASSIGN) { - /* - * bash 4.2.45 x86 64bit: SEGV on 'echo $((2**63 / -1))' - * - * MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1 - * and thus is not representable. - * Some CPUs segfault trying such op. - * Others overflow MAX_POSITIVE_INT+1 to - * MAX_NEGATIVE_INT (0x7fff+1 = 0x8000). - * Make sure to at least not SEGV here: - */ - if (right_side_val == -1 - && rez << 1 == 0 /* MAX_NEGATIVE_INT or 0 */ - ) { - right_side_val = 1; - } - if (op == TOK_DIV || op == TOK_DIV_ASSIGN) - rez /= right_side_val; - else { - rez %= right_side_val; - } - } - } - - if (is_assign_op(op)) { - char buf[sizeof(arith_t)*3 + 2]; - - if (top_of_stack->var == NULL) { - /* Hmm, 1=2 ? */ - goto err; - } - /* Save to shell variable */ - sprintf(buf, ARITH_FMT, rez); - math_state->setvar(top_of_stack->var, buf); - /* After saving, make previous value for v++ or v-- */ - if (op == TOK_POST_INC) - rez--; - if (op == TOK_POST_DEC) - rez++; - } - - top_of_stack->val = rez; - /* Erase var name, it is just a number now */ - top_of_stack->var = NULL; - return NULL; - err: - return "arithmetic syntax error"; -#undef NUMPTR -} - -/* longest must be first */ -static const char op_tokens[] ALIGN1 = { - '<','<','=',0, TOK_LSHIFT_ASSIGN, - '>','>','=',0, TOK_RSHIFT_ASSIGN, - '<','<', 0, TOK_LSHIFT, - '>','>', 0, TOK_RSHIFT, - '|','|', 0, TOK_OR, - '&','&', 0, TOK_AND, - '!','=', 0, TOK_NE, - '<','=', 0, TOK_LE, - '>','=', 0, TOK_GE, - '=','=', 0, TOK_EQ, - '|','=', 0, TOK_OR_ASSIGN, - '&','=', 0, TOK_AND_ASSIGN, - '*','=', 0, TOK_MUL_ASSIGN, - '/','=', 0, TOK_DIV_ASSIGN, - '%','=', 0, TOK_REM_ASSIGN, - '+','=', 0, TOK_PLUS_ASSIGN, - '-','=', 0, TOK_MINUS_ASSIGN, - '-','-', 0, TOK_POST_DEC, - '^','=', 0, TOK_XOR_ASSIGN, - '+','+', 0, TOK_POST_INC, - '*','*', 0, TOK_EXPONENT, - '!', 0, TOK_NOT, - '<', 0, TOK_LT, - '>', 0, TOK_GT, - '=', 0, TOK_ASSIGN, - '|', 0, TOK_BOR, - '&', 0, TOK_BAND, - '*', 0, TOK_MUL, - '/', 0, TOK_DIV, - '%', 0, TOK_REM, - '+', 0, TOK_ADD, - '-', 0, TOK_SUB, - '^', 0, TOK_BXOR, - /* uniq */ - '~', 0, TOK_BNOT, - ',', 0, TOK_COMMA, - '?', 0, TOK_CONDITIONAL, - ':', 0, TOK_CONDITIONAL_SEP, - ')', 0, TOK_RPAREN, - '(', 0, TOK_LPAREN, - 0 -}; -#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) - #if ENABLE_FEATURE_SH_MATH_BASE static arith_t strto_arith_t(const char *nptr, char **endptr) { @@ -577,250 +200,1124 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) # endif #endif -static arith_t -evaluate_string(arith_state_t *math_state, const char *expr) -{ - operator lasttok; - const char *errmsg; - const char *start_expr = expr = skip_whitespace(expr); - unsigned expr_len = strlen(expr) + 2; - /* Stack of integers */ - /* The proof that there can be no more than strlen(startbuf)/2+1 - * integers in any given correct or incorrect expression - * is left as an exercise to the reader. */ - var_or_num_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0])); - var_or_num_t *numstackptr = numstack; - /* Stack of operator tokens */ - operator *const stack = alloca(expr_len * sizeof(stack[0])); - operator *stackptr = stack; +#if 1 +# define ARITH_DBG 0 +# define ARITH_L(X) +#else +# define ARITH_DBG 1 +# define ARITH_L(X) arith_log X +#endif + +/* Tracking of error location in input */ +#if ENABLE_FEATURE_SH_MATH_ERROR_TRACK +# undef ARITH_ERROR_TRACK +# define ARITH_ERROR_TRACK(X) X +#else +# define ARITH_ERROR_TRACK(X) +#endif + +#define ALIGN_Z(X) (((X) + 7) & ~7) +#define SYM_COMMA , +#define CONCAT(S1,S2) arith__CONCAT_1(S1, S2) +#define arith__CONCAT_1(S1,S2) arith__CONCAT_2(S1, S2) +#define arith__CONCAT_2(S1,S2) S1 ## S2 +#define S(X,Y) ((X)(Y)) +#define C(X,Y) ((X)(Y)) + +#define ARITH_ISVARC(C) ((C) == '_' || isalnum(S(unsigned char,C))) +#define ARITH_ISVARC_BAD1ST(C) isdigit(S(unsigned char,C)) + +#define ARITH_IDEC_ERROR (1u<<0) +#define ARITH_IDEC_CONSUMED (1u<<1) + +enum arith_error{ + ARITH_ERR_NONE, + ARITH_ERR_NOMEM, /* Out of memory */ + ARITH_ERR_SYNTAX, /* General syntax error */ + ARITH_ERR_ASSIGN_NO_VAR, /* Assignment without variable */ + ARITH_ERR_DIV_BY_ZERO, + ARITH_ERR_EXP_INVALID, /* Invalid exponent */ + ARITH_ERR_NO_OP, /* Expected an argument here */ + ARITH_ERR_COND_NO_COLON, /* Incomplete ?: condition */ + ARITH_ERR_COND_PREC_INVALID, /* 1 ? VAR1 : VAR2 = 3 */ + ARITH_ERR_NAME_LOOP, /* Variable self-reference loop */ + ARITH_ERR_OP_INVALID /* Unknown operator */ +}; + +/* Operators and precedences in increasing precedence order. + * (The operator stack as such is uint16_t: [OP_FLAGS |] (OP<<8) | PREC.) */ +enum arith_ops{ +#undef a_X +#define a_X(N,P,O) \ + CONCAT(ARITH_PREC_,N) = CONCAT(P,u),\ + CONCAT(ARITH_OP_,N) = (CONCAT(O,u) << 8) | CONCAT(ARITH_PREC_,N) + + a_X(PAREN_LEFT, 0, 0), + + a_X(COMMA, 1, 0), + + a_X(ASSIGN, 2, 0), + a_X(ASSIGN_BIT_OR, 2, 1), + a_X(ASSIGN_BIT_XOR, 2, 2), + a_X(ASSIGN_BIT_AND, 2, 3), + a_X(ASSIGN_SHIFT_LEFT, 2, 4), a_X(ASSIGN_SHIFT_RIGHT, 2, 5), + a_X(ASSIGN_ADD, 2, 7), a_X(ASSIGN_SUB, 2, 8), + a_X(ASSIGN_MUL, 2, 9), a_X(ASSIGN_DIV, 2, 10), a_X(ASSIGN_MOD, 2, 11), + a_X(ASSIGN_EXP, 2, 12), + + a_X(COND, 3, 0), + a_X(COND_COLON, 3, 1), + + a_X(OR, 4, 0), + a_X(AND, 5, 0), + a_X(BIT_OR, 6, 0), + a_X(BIT_XOR, 7, 0), + a_X(BIT_AND, 8, 0), + a_X(EQ, 9, 0), a_X(NE, 9, 1), + a_X(LE, 10, 0), a_X(GE, 10, 1), a_X(LT, 10, 2), a_X(GT, 10, 3), + a_X(SHIFT_LEFT, 11, 0), a_X(SHIFT_RIGHT, 11, 1), + a_X(ADD, 12, 0), a_X(SUB, 12, 1), + a_X(MUL, 13, 0), a_X(DIV, 13, 1), a_X(MOD, 13, 2), + a_X(EXP, 14, 0), + + /* Further operators are unary, pre- or postfix */ + ARITH_PREC_UNARY = 15, + ARITH_PREC_PREFIX = 16, + ARITH_PREC_POSTFIX = 18, + + a_X(UNARY_NOT, 15, 0), a_X(UNARY_BIT_NOT, 15, 1), + a_X(PREFIX_INC, 16, 0), a_X(PREFIX_DEC, 16, 1), + a_X(UNARY_PLUS, 17, 1), a_X(UNARY_MINUS, 17, 0), + a_X(POSTFIX_INC, 18, 0), a_X(POSTFIX_DEC, 18, 1), + + /* Beyond operator profanity; the first "is a number" */ + ARITH_PREC_SKY = 19, + a_X(NUM, 19, 0), a_X(PAREN_RIGHT, 19, 1), + +#undef a_X +}; + +enum arith_op_flags{ + /* Mask off operator and precision */ + ARITH_OP_MASK = 0x1FFF, + ARITH_OP_FLAG_COND_SAW_COLON = 1u<<13, + ARITH_OP_FLAG_OUTER_WHITEOUT = 1u<<14, + ARITH_OP_FLAG_WHITEOUT = 1u<<15, + ARITH_OP_FLAG_WHITE_MASK = ARITH_OP_FLAG_OUTER_WHITEOUT | + ARITH_OP_FLAG_WHITEOUT, + ARITH_OP_FLAG_MASK = ARITH_OP_FLAG_COND_SAW_COLON | + ARITH_OP_FLAG_WHITE_MASK +}; + +struct arith_name_stack{ + struct arith_name_stack *sans_last; + char const *sans_var; +}; + +struct arith_val{ + arith_t sav_val; + char *sav_var; /* Named variable or NULL */ +}; + +struct arith_stack{ + struct arith_val *sas_nums; + struct arith_val *sas_nums_top; + uint16_t *sas_ops; + uint16_t *sas_ops_top; + ARITH_ERROR_TRACK( + char **sas_error_track; + char **sas_error_track_top; + ) +}; + +struct arith_ctx{ + uint32_t sac_error; + int8_t sac_have_error_track; + uint8_t sac__pad[3]; + arith_t sac_rv; + struct arith_stack *sac_stack; + struct arith_name_stack *sac_name_stack; + ARITH_ERROR_TRACK( char **sac_error_track_or_nil; ) + arith_state_t *sac_cookie; +}; + +/* Sort by ~expected usage -- however, longest first if ambiguous! + * Follow busybox, save space by compressing data in char[] not struct[]! */ +static char const arith_op_toks[] = { +#undef a_X +#define a_X(X) \ + S(char,(CONCAT(ARITH_OP_,X) & 0xFF00u) >> 8), S(char,CONCAT(ARITH_PREC_,X)) + + '+','+','\0', a_X(POSTFIX_INC), + '+','=','\0', a_X(ASSIGN_ADD), + '+','\0', a_X(ADD), + '-','-','\0', a_X(POSTFIX_DEC), + '-','=','\0', a_X(ASSIGN_SUB), + '-','\0', a_X(SUB), + '*','*','=','\0', a_X(ASSIGN_EXP), + '*','*','\0', a_X(EXP), + '*','=','\0', a_X(ASSIGN_MUL), + '*','\0', a_X(MUL), + '/','=','\0', a_X(ASSIGN_DIV), + '/','\0', a_X(DIV), + '%','=','\0', a_X(ASSIGN_MOD), + '%','\0', a_X(MOD), + '|','|','\0', a_X(OR), + '|','=','\0', a_X(ASSIGN_BIT_OR), + '|','\0', a_X(BIT_OR), + '^','=','\0', a_X(ASSIGN_BIT_XOR), + '^','\0', a_X(BIT_XOR), + '&','&','\0', a_X(AND), + '&','=','\0', a_X(ASSIGN_BIT_AND), + '&','\0', a_X(BIT_AND), + '<','<','=',0, a_X(ASSIGN_SHIFT_LEFT), + '<','<','\0', a_X(SHIFT_LEFT), + '>','>','=',0, a_X(ASSIGN_SHIFT_RIGHT), + '>','>','\0', a_X(SHIFT_RIGHT), + + '~','\0', a_X(UNARY_BIT_NOT), + '!','=','\0', a_X(NE), + '!','\0', a_X(UNARY_NOT), + + ')','\0', a_X(PAREN_RIGHT), + '(','\0', a_X(PAREN_LEFT), + ',','\0', a_X(COMMA), + + '<','=','\0', a_X(LE), + '>','=','\0', a_X(GE), + '=','=','\0', a_X(EQ), + '<','\0', a_X(LT), + '>','\0', a_X(GT), + '=','\0', a_X(ASSIGN), + + '?','\0', a_X(COND), + ':','\0', a_X(COND_COLON), + + '\0' +#undef a_X +}; + +/* Wrapper around strto_arith_t() */ +static inline uint32_t arith_idec(void *resp, char const *cbuf, char const **endptr_or_nil); + +/* Our "public" entry point. + * exp_buf can be NULL if exp_len is 0, it need not be NUL terminated (stop for NUL or out of length). + * Upon error *error_track_or_nil is set to a "newly allocated" string that points to where parse stopped, + * or NULL upon initial setup failure */ +static enum arith_error arith_eval(arith_state_t *cookie, arith_t *resp, char const *exp_buf, size_t exp_len + ARITH_ERROR_TRACK( SYM_COMMA char **error_track_or_nil )); + +static void arith__eval(struct arith_ctx *self, char const *exp_buf, size_t exp_len); + +/* Count non-WS as well as normalized WS ([:"space":]+ -> ' ') in exp_buf, return count. + * If store!=NULL, also copy normalization. + * An all-WS exp_buf returns 0 */ +static size_t arith__ws_squeeze(struct arith_ctx *self, char const *exp_buf, size_t exp_len, char *store_or_nil); + +/* Resolve and evaluate the "self-contained string" savp->sav_var. + * Take care to avoid name lookuintptr_t loops */ +static bool arith__val_eval(struct arith_ctx *self, struct arith_val *savp); + +/* Work top of the stack, which may pop & push etc */ +static bool arith__op_apply(struct arith_ctx *self); + +static bool arith__op_apply_colons(struct arith_ctx *self); + +#if ARITH_DBG +static void arith_log(char const *fmt, ...); +#endif + +static inline uint32_t arith_idec(void *resp, char const *cbuf, char const **endptr_or_nil){ + uint32_t rv; + arith_t res; + char const *eptr; + + if(endptr_or_nil == NULL) + endptr_or_nil = &eptr; + + errno = 0; + res = strto_arith_t(cbuf, C(char**,endptr_or_nil)); + rv = 0; + if(errno == 0){ + if(**endptr_or_nil == '\0') + rv = ARITH_IDEC_CONSUMED; + }else{ + rv = ARITH_IDEC_ERROR; + res = 0; + } + + *S(arith_t*,resp) = res; + return rv; +} + +static enum arith_error +arith_eval(arith_state_t *cookie, arith_t *resp, char const *exp_buf, size_t exp_len + ARITH_ERROR_TRACK( SYM_COMMA char **error_track_or_nil )){ + struct arith_stack sas_stack; + struct arith_ctx self; + + ARITH_L(("> arith_eval %zu <%.*s>\n", + exp_len, S(int,exp_len != SIZE_MAX ? exp_len : strlen(exp_buf)), exp_buf)); + + ARITH_ERROR_TRACK( + if(error_track_or_nil != NULL) + *error_track_or_nil = NULL; + ); + + memset(&self, 0, sizeof(struct arith_ctx)); + self.sac_cookie = cookie; + ARITH_ERROR_TRACK( + if((self.sac_error_track_or_nil = error_track_or_nil) != NULL) + self.sac_have_error_track = true; + ) + + self.sac_stack = &sas_stack; + arith__eval(&self, exp_buf, exp_len); + *resp = self.sac_rv; + + ARITH_L(("< arith_eval %zu <%.*s> -> <%lld> ERR<%u>\n", + exp_len, S(int,exp_len != SIZE_MAX ? exp_len : strlen(exp_buf)), + exp_buf, self.sac_rv, self.sac_error)); + + return S(enum arith_error,self.sac_error); +} + +static void +arith__eval(struct arith_ctx *self, char const *exp_buf, size_t exp_len){ + char *ep, *varp, *cp, c; + uint16_t lop; + struct arith_stack *sasp; + void *mem_p; + + ARITH_L((" > _arith_eval %zu <%.*s>\n", + exp_len, S(int,exp_len != SIZE_MAX ? exp_len : strlen(exp_buf)), exp_buf)); + + mem_p = NULL; + sasp = self->sac_stack; + + /* Create a single continuous allocation for anything */ + /* C99 */{ + union {void *v; char *c;} p; + size_t i, j, o, a; + + /* Done for empty expression */ + if((i = arith__ws_squeeze(self, exp_buf, exp_len, NULL)) == 0) + goto jleave; + + /* Overflow check: since arithmetic expressions are rarely long enough + * to come near this limit, xxx laxe & fuzz, not exact; max INT_MAX! */ + if(i++ >= S(size_t,INT_MAX)) + goto jenomem; + if(i >= ((SIZE_MAX - (i ARITH_ERROR_TRACK( * 2 ))) / + ((ALIGN_Z(sizeof(*sasp->sas_nums)) + + ALIGN_Z(sizeof(*sasp->sas_ops) * 2)) + ARITH_ERROR_TRACK( + sizeof(*sasp->sas_error_track) * 2 )) + )){ +jenomem: + self->sac_error = ARITH_ERR_NOMEM; + goto jleave; + } + + ++i; + j = ALIGN_Z(sizeof(*sasp->sas_nums) * (i >> 1)); + o = ALIGN_Z(sizeof(*sasp->sas_ops) * i); + a = j + o + ARITH_ERROR_TRACK( (sizeof(*sasp->sas_error_track) * i) + ) + 1 + (i ARITH_ERROR_TRACK( * 2 )); + mem_p = p.v = alloca(a); + sasp->sas_nums = sasp->sas_nums_top = S(struct arith_val*,p.v); + p.c += j; + sasp->sas_ops = sasp->sas_ops_top = S(uint16_t*,p.v); + p.c += o; + ARITH_ERROR_TRACK( + sasp->sas_error_track_top = sasp->sas_error_track = S(char**,p.v); + p.c += sizeof(*sasp->sas_error_track) * i; + ) + + ep = ++p.c; /* ++ to copy varnames in !_ARITH_ERROR cases */ + i = arith__ws_squeeze(self, exp_buf, exp_len, ep); + varp = &ep[ +#if 0 ARITH_ERROR_TRACK( + 1 ) + i + 1 +#else + -1 +#endif + ]; + + ARITH_L((" ! _arith_eval ALLOC <%lu> nums=%p (%lu) ops=%p varp=%p %lu <%s>\n", + S(unsigned long,a), sasp->sas_nums, S(unsigned long,j / sizeof(*sasp->sas_nums)), + sasp->sas_ops, varp, S(unsigned long,i - 1), ep)); + } /* Start with a left paren */ - *stackptr++ = lasttok = TOK_LPAREN; - errmsg = NULL; - - while (1) { - const char *p; - operator op; - operator prec; - - expr = skip_whitespace(expr); - if (*expr == '\0') { - if (expr == start_expr) { - /* Null expression */ - numstack->val = 0; - goto ret; + ARITH_ERROR_TRACK( *sasp->sas_error_track_top++ = ep; ) + *sasp->sas_ops_top++ = lop = ARITH_OP_PAREN_LEFT; + + for(;;) Jouter:{ + uint16_t op; + + ARITH_L((" = _arith_eval TICK LOP <0x%02X %u> nums=%lu ops=%lu DATA %lu <%s>\n", + lop, lop & 0xFF, S(unsigned long,sasp->sas_nums_top - sasp->sas_nums), + S(unsigned long,sasp->sas_ops_top - sasp->sas_ops), + S(unsigned long,strlen(ep)), ep)); + + if(*ep == '\0'){ + /* At the end of the expression pop anything left. Assume we have read PAREN_RIGHT */ + if(exp_buf != NULL){ + exp_buf = NULL; + op = ARITH_OP_PAREN_RIGHT; + /* Can only be a syntax error! */ + if(sasp->sas_ops_top == sasp->sas_ops){ + self->sac_error = ARITH_ERR_SYNTAX; + break; + } + goto jtok_go; } - /* This is only reached after all tokens have been extracted from the - * input stream. If there are still tokens on the operator stack, they - * are to be applied in order. At the end, there should be a final - * result on the integer stack */ - - if (expr != ptr_to_rparen + 1) { - /* If we haven't done so already, - * append a closing right paren - * and let the loop process it */ - expr = ptr_to_rparen; -//bb_error_msg("expr=')'"); - continue; - } - /* At this point, we're done with the expression */ - if (numstackptr != numstack + 1) { - /* ...but if there isn't, it's bad */ - goto err; - } - goto ret; + /* After PAREN_RIGHT, we must be finished */ + if(sasp->sas_nums_top != &sasp->sas_nums[1]) + self->sac_error = ARITH_ERR_SYNTAX; + break; } - p = endofname(expr); - if (p != expr) { - /* Name */ - size_t var_name_size = (p - expr) + 1; /* +1 for NUL */ - numstackptr->var = alloca(var_name_size); - safe_strncpy(numstackptr->var, expr, var_name_size); -//bb_error_msg("var:'%s'", numstackptr->var); - expr = p; - num: - numstackptr->second_val_present = 0; - numstackptr++; - lasttok = TOK_NUM; + /* Skip (normalized) WS now */ + if(*ep == ' ') + ++ep; + + /* A number? */ + if(isdigit(S(unsigned char,*ep))){ + if(arith_idec(&sasp->sas_nums_top->sav_val, ep, S(char const**,&ep)) & ARITH_IDEC_ERROR) + sasp->sas_nums_top->sav_val = 0; + sasp->sas_nums_top->sav_var = NULL; + + ++sasp->sas_nums_top; + lop = ARITH_OP_NUM; + ARITH_L((" + _arith_eval NUM <%lld>\n", sasp->sas_nums_top[-1].sav_val)); continue; } - if (isdigit(*expr)) { - /* Number */ - numstackptr->var = NULL; - errno = 0; - numstackptr->val = strto_arith_t(expr, (char**) &expr); -//bb_error_msg("val:%lld", numstackptr->val); - if (errno) - numstackptr->val = 0; /* bash compat */ - goto num; + /* Is it a variable name? */ + for(cp = ep; (c = *cp, ARITH_ISVARC(c)); ++cp) + if(cp == ep && ARITH_ISVARC_BAD1ST(c)) + break; + + if(cp != ep){ + /* Copy over to pre-allocated var storage */ + /* C99 */{ + size_t i; + + i = S(size_t,cp - ep); + /* (move not copy for !_ARITH_ERROR cases (says ISO C?)) */ + memmove(sasp->sas_nums_top->sav_var = varp, ep, i); + varp += i; + *varp++ = '\0'; + } + ep = cp; + + ++sasp->sas_nums_top; + lop = ARITH_OP_NUM; + + ARITH_L((" + _arith_eval VAR <%s>\n", sasp->sas_nums_top[-1].sav_var)); + continue; } - /* Should be an operator */ - - /* Special case: XYZ--, XYZ++, --XYZ, ++XYZ are recognized - * only if XYZ is a variable name, not a number or EXPR. IOW: - * "a+++v" is a++ + v. - * "(a)+++7" is ( a ) + + + 7. - * "7+++v" is 7 + ++v, not 7++ + v. - * "--7" is - - 7, not --7. - * "++++a" is + + ++a, not ++ ++a. - */ - if ((expr[0] == '+' || expr[0] == '-') - && (expr[1] == expr[0]) - ) { - if (numstackptr == numstack || !numstackptr[-1].var) { /* not a VAR++ */ - char next = skip_whitespace(expr + 2)[0]; - if (!(isalpha(next) || next == '_')) { /* not a ++VAR */ - //bb_error_msg("special %c%c", expr[0], expr[0]); - op = (expr[0] == '+' ? TOK_ADD : TOK_SUB); - expr++; - goto tok_found1; + /* An operator. We turn prefix operators to multiple unary plus/minus if + * not pre- or post-attached to a variable name (++10 -> + + 10). + * (We adjust postfix to prefix below) */ + if((ep[0] == '+' || ep[0] == '-') && (ep[1] == ep[0])){ + if(sasp->sas_nums_top == sasp->sas_nums || sasp->sas_nums_top[-1].sav_var == NULL){ + if((c = ep[2]) == ' ') + c = ep[3]; + + if(c != '\0' && (!ARITH_ISVARC(c) || ARITH_ISVARC_BAD1ST(c))){ + op = (ep[0] == '+') ? ARITH_OP_ADD : ARITH_OP_SUB; + ++ep; + ARITH_L((" + _arith_eval OP PREFIX INC/DEC SPLIT <%c%c> -> <%c>\n", + ep[0], ep[0], ep[0])); + goto jtok_go; } } } - p = op_tokens; - while (1) { - /* Compare expr to current op_tokens[] element */ - const char *e = expr; - while (1) { - if (*p == '\0') { - /* Match: operator is found */ - expr = e; - goto tok_found; + /* Operator search */ + /* C99 */{ + char const *tokp; + + /* 3=NUL+OP+PREC */ + for(tokp = arith_op_toks; *tokp != '\0'; tokp += 3){ + for(cp = ep;; ++tokp, ++cp){ + if(*tokp == '\0'){ + ep = cp; + op = (S(uint16_t,tokp[1]) << 8) | S(uint8_t,tokp[2]); + goto jtok_go; + }else if(*tokp != *cp) + break; } - if (*p != *e) - break; - p++; - e++; - } - /* No match, go to next element of op_tokens[] */ - while (*p) - p++; - p += 2; /* skip NUL and TOK_foo bytes */ - if (*p == '\0') { - /* No next element, operator not found */ - //math_state->syntax_error_at = expr; - goto err; + + while(*tokp != '\0') + ++tokp; } + self->sac_error = ARITH_ERR_OP_INVALID; + goto jleave; } - tok_found: - op = p[1]; /* fetch TOK_foo value */ - tok_found1: - /* NB: expr now points past the operator */ - - /* post grammar: a++ reduce to num */ - if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) - lasttok = TOK_NUM; - - /* Plus and minus are binary (not unary) _only_ if the last - * token was a number, or a right paren (which pretends to be - * a number, since it evaluates to one). Think about it. - * It makes sense. */ - if (lasttok != TOK_NUM) { - switch (op) { - case TOK_ADD: - op = TOK_UPLUS; - break; - case TOK_SUB: - op = TOK_UMINUS; - break; - case TOK_POST_INC: - op = TOK_PRE_INC; - break; - case TOK_POST_DEC: - op = TOK_PRE_DEC; + +jtok_go:/* C99 */{ + uint8_t prec; + + prec = op & 0xFF; + ARITH_L((" + _arith_eval OP <0x%02X %u> LOP <0x%02X %u> nums=%lu ops=%lu %lu <%s>\n", + op, prec, lop, lop & 0xFF, + S(unsigned long,sasp->sas_nums_top - sasp->sas_nums), + S(unsigned long,sasp->sas_ops_top - sasp->sas_ops), + S(unsigned long,strlen(ep)), ep)); + + if(op == ARITH_OP_UNARY_PLUS){ + ARITH_L((" + _arith_eval IGNORE UNARY PLUS\n")); + continue; + } + + /* Correct our understanding of what there is. Post grammar: VAR++ reduces to num */ + if((lop & 0xFF) == ARITH_PREC_POSTFIX){ + lop = ARITH_OP_NUM; + ARITH_L((" + _arith_eval LOP POSTFIX REDUCED to NUM\n")); + } + /* Adjust some binary/postfix operators to make them flow */ + else if(lop != ARITH_OP_NUM){ + switch(op){ + case ARITH_OP_ADD: + ARITH_L((" + _arith_eval OP ADJUST: IGNORE UNARY PLUS\n")); + continue; + case ARITH_OP_SUB: + op = ARITH_OP_UNARY_MINUS; + goto junapre; + case ARITH_OP_POSTFIX_INC: + op = ARITH_OP_PREFIX_INC; + goto junapre; + case ARITH_OP_POSTFIX_DEC: + op = ARITH_OP_PREFIX_DEC; +junapre: + prec = ARITH_PREC_PREFIX; + ARITH_L((" + _arith_eval OP ADJUST TO UNARY/PREFIX\n")); break; } } - /* We don't want an unary operator to cause recursive descent on the - * stack, because there can be many in a row and it could cause an - * operator to be evaluated before its argument is pushed onto the - * integer stack. - * But for binary operators, "apply" everything on the operator - * stack until we find an operator with a lesser priority than the - * one we have just extracted. If op is right-associative, - * then stop "applying" on the equal priority too. - * Left paren is given the lowest priority so it will never be - * "applied" in this way. - */ - prec = PREC(op); -//bb_error_msg("prec:%02x", prec); - if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { - /* not left paren or unary */ - if (lasttok != TOK_NUM) { - /* binary op must be preceded by a num */ - goto err; + /* Special: +10++VAR -> +10 + +VAR. (Since we do handle +10++11 correctly via "prefix split", + * we should also handle this) */ + else if(prec == ARITH_PREC_POSTFIX){ + if((c = ep[0]) == ' ') + c = ep[1]; + if(c != '\0' && (ARITH_ISVARC(c) && !ARITH_ISVARC_BAD1ST(c))){ + c = *--ep; + op = (c == '+') ? ARITH_OP_ADD : ARITH_OP_SUB; + prec = op & 0xFF; + ARITH_L((" + _arith_eval OP POSTFIX INC/DEC SPLIT <%c%c> -> <%c>\n", c, c, c)); } - /* The algorithm employed here is simple: while we don't - * hit an open paren nor the bottom of the stack, pop - * tokens and apply them */ - while (stackptr != stack) { - operator prev_op = *--stackptr; - if (op == TOK_RPAREN) { -//bb_error_msg("op == TOK_RPAREN"); - if (prev_op == TOK_LPAREN) { -//bb_error_msg("prev_op == TOK_LPAREN"); -//bb_error_msg(" %p %p numstackptr[-1].var:'%s'", numstack, numstackptr-1, numstackptr[-1].var); - if (numstackptr[-1].var) { - /* Expression is (var), lookup now */ - errmsg = arith_lookup_val(math_state, &numstackptr[-1]); - if (errmsg) - goto err_with_custom_msg; - /* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */ - numstackptr[-1].var = NULL; + } + + /* Check whether we can work it a bit */ + if((prec > ARITH_PREC_PAREN_LEFT && prec < ARITH_PREC_UNARY) || prec >= ARITH_PREC_SKY){ + if(lop != ARITH_OP_NUM){ + self->sac_error = ARITH_ERR_NO_OP; + goto jleave; + } + + /* Pop as much as possible */ + while(sasp->sas_ops_top != sasp->sas_ops){ + ARITH_ERROR_TRACK( --sasp->sas_error_track_top; ) + lop = *--sasp->sas_ops_top & ARITH_OP_MASK; + + ARITH_L((" + _arith_eval TRY POP - OP <0x%02X %u>, NEW LOP <0x%02X %u 0x%X> nums=%lu ops=%lu\n", + op, op & 0xFF, lop, lop & 0xFF, + (*sasp->sas_ops_top & ARITH_OP_FLAG_MASK), + S(unsigned long,sasp->sas_nums_top - sasp->sas_nums), + S(unsigned long,sasp->sas_ops_top - sasp->sas_ops))); + + /* Special-case parenthesis groups */ + if(op == ARITH_OP_PAREN_RIGHT){ + if(lop == ARITH_OP_PAREN_LEFT){ + /* Resolve VAR to NUM */ + if(sasp->sas_nums_top[-1].sav_var != NULL){ + if(!arith__val_eval(self, &sasp->sas_nums_top[-1])) + goto jleave; } - /* Any operator directly after a - * close paren should consider itself binary */ - lasttok = TOK_NUM; - goto next; + sasp->sas_nums_top[-1].sav_var = NULL; + ARITH_L((" + _arith_eval OP () RESOLVED <%lld>\n", + sasp->sas_nums_top[-1].sav_val)); + lop = ARITH_OP_NUM; + goto Jouter; } -//bb_error_msg("prev_op != TOK_LPAREN"); - } else { - operator prev_prec = PREC(prev_op); -//bb_error_msg("op != TOK_RPAREN"); - fix_assignment_prec(prec); - fix_assignment_prec(prev_prec); - if (prev_prec < prec - || (prev_prec == prec && is_right_associative(prec)) - ) { - stackptr++; + }else{ + uint8_t lprec; + + lprec = lop & 0xFF; + + if(op == ARITH_OP_COND){ + uint16_t x; + + x = *sasp->sas_ops_top & ARITH_OP_FLAG_MASK; + if(x & ARITH_OP_FLAG_WHITEOUT){ + x ^= ARITH_OP_FLAG_WHITEOUT; + x |= ARITH_OP_FLAG_OUTER_WHITEOUT; + } + op |= x; + + /* Resolve as resolve can, need to assert our condition! */ + while(lprec > ARITH_PREC_COND){ + if(!arith__op_apply(self)) + goto jleave; + ARITH_ERROR_TRACK( --sasp->sas_error_track_top; ) + lop = *--sasp->sas_ops_top & ARITH_OP_MASK; + lprec = lop & 0xFF; + } + + /* Evaluate condition assertion */ + --sasp->sas_nums_top; + + if(sasp->sas_nums_top->sav_var != NULL){ + if(!(op & ARITH_OP_FLAG_WHITE_MASK) && + !arith__val_eval(self, sasp->sas_nums_top)) + goto jleave; + sasp->sas_nums_top->sav_var = NULL; + } + + if(sasp->sas_nums_top->sav_val == 0) + op |= ARITH_OP_FLAG_WHITEOUT; + op |= *sasp->sas_ops_top & ARITH_OP_FLAG_MASK; + + /* Delay ternary: this ? op will last until we can resolve + * the entire condition, its number stack position is used + * as storage for the actual condition result */ + ARITH_ERROR_TRACK( ++sasp->sas_error_track_top; ) + ++sasp->sas_ops_top; + break; + }else if(op == ARITH_OP_COND_COLON){ + size_t recur; + uint16_t *opsp, x; + bool delay; + + delay = true; + + /* Find our counterpart ? so we can toggle whiteout */ + opsp = sasp->sas_ops_top; + for(recur = 1;; --opsp){ + if(opsp == sasp->sas_ops){ + self->sac_error = ARITH_ERR_SYNTAX; + goto jleave; + } + + x = *opsp & ARITH_OP_MASK; + if(x == ARITH_OP_COND_COLON) + ++recur; + else if(x == ARITH_OP_COND && --recur == 0){ + *opsp |= ARITH_OP_FLAG_COND_SAW_COLON; + break; + } + } + op |= *opsp & ARITH_OP_FLAG_MASK; + op ^= ARITH_OP_FLAG_WHITEOUT; + + /* Resolve innermost condition asap. + * In "1?0?5:6:3", resolve innermost upon :3 */ + while(lprec > ARITH_PREC_PAREN_LEFT && lprec != ARITH_PREC_COND){ + if(!arith__op_apply(self)) + goto jleave; + ARITH_ERROR_TRACK( --sasp->sas_error_track_top; ) + lop = *--sasp->sas_ops_top & ARITH_OP_MASK; + lprec = lop & 0xFF; + } + + /* If at a COLON we have to resolve further, otherwise syntax + * error would happen for 1?2?3:6:7 (due to how Dijkstra's + * algorithm applies, and our squeezing of ?: constructs) */ + if(lop == ARITH_OP_COND_COLON){ + delay = false; + if(!arith__op_apply_colons(self)) + goto jleave; + lop = *sasp->sas_ops_top & ARITH_OP_MASK; + } + + if(lop != ARITH_OP_COND){ + self->sac_error = ARITH_ERR_SYNTAX; + goto jleave; + } + + if(delay){ + ARITH_ERROR_TRACK( ++sasp->sas_error_track_top; ) + ++sasp->sas_ops_top; + } + ARITH_L((" + _arith_eval %sTERNARY ?:%s\n", + (delay ? "DELAY " : ""), + ((op & ARITH_OP_FLAG_WHITE_MASK) ? " WHITEOUT" : ""))); break; } + /* Is this a right-associative operation? */ + else{ + bool doit; + + doit = false; + if(lprec < prec){ + doit = true; + ARITH_L((" + _arith_eval DELAY PRECEDENCE\n")); + }else if(lprec == prec && prec == ARITH_PREC_ASSIGN){ + doit = true; + ARITH_L((" + _arith_eval DELAY RIGHT ASSOC\n")); + }else if(lprec == ARITH_PREC_COND){ + if(lop == ARITH_OP_COND){ + doit = true; + ARITH_L((" + _arith_eval DELAY CONDITION\n")); + } + /* Without massive rewrite this is the location to detect + * in-whiteout precedence bugs as in + * $((0?I1=10:(1?I3:I2=12))) + * which would be parsed like (1?I3:I2)=12 without error + * (different to 0?I3:I2=12) otherwise */ + else if(op != ARITH_OP_COMMA){ + self->sac_error = ARITH_ERR_COND_PREC_INVALID; + goto jleave; + } + } + + if(doit){ + /* If we are about to delay and LHV is a VAR, expand that + * immediately to expand in correct order things like + * I1=I2=10 I2=3; echo $((I1,I2)) + * I1=I2=10 I2=3; echo $((I1+=I2)) */ + if(sasp->sas_nums_top[-1].sav_var != NULL){ + if(op != ARITH_OP_ASSIGN && + !(*sasp->sas_ops_top & ARITH_OP_FLAG_WHITE_MASK) && + !arith__val_eval(self, &sasp->sas_nums_top[-1])) + goto jleave; + if(prec != ARITH_PREC_ASSIGN) + sasp->sas_nums_top[-1].sav_var = NULL; + } + + ARITH_ERROR_TRACK( ++sasp->sas_error_track_top; ) + ++sasp->sas_ops_top; + break; + } + } + } + + /* */ + if(!arith__op_apply(self)) + goto jleave; + + if(lop == ARITH_OP_COND_COLON){ + ARITH_ERROR_TRACK( --sasp->sas_error_track_top; ) + --sasp->sas_ops_top; } -//bb_error_msg("arith_apply(prev_op:%02x)", prev_op); - errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); - if (errmsg) - goto err_with_custom_msg; } - if (op == TOK_RPAREN) - goto err; } /* Push this operator to the stack and remember it */ -//bb_error_msg("push op:%02x", op); - *stackptr++ = lasttok = op; - next: ; - } /* while (1) */ - - err: - errmsg = "arithmetic syntax error"; - err_with_custom_msg: - numstack->val = -1; - ret: - math_state->errmsg = errmsg; - return numstack->val; + ARITH_ERROR_TRACK( *sasp->sas_error_track_top++ = ep; ) + if(sasp->sas_ops_top > sasp->sas_ops && (op & 0xFF) != ARITH_PREC_COND) + op |= sasp->sas_ops_top[-1] & ARITH_OP_FLAG_MASK; + *sasp->sas_ops_top++ = op; + lop = op & ARITH_OP_MASK; + ARITH_L((" + _arith_eval OP PUSH <0x%02X %u> nums=%lu ops=%lu\n", + op, (op & 0xFF), S(unsigned long,sasp->sas_nums_top - sasp->sas_nums), + S(unsigned long,sasp->sas_ops_top - sasp->sas_ops))); + } + } + + self->sac_rv = sasp->sas_nums->sav_val; + +jleave: +#if 0 ARITH_ERROR_TRACK( + 1 ) + if(self->sac_error != ARITH_ERR_NONE && mem_p != NULL && self->sac_have_error_track){ + if(sasp->sas_error_track_top > sasp->sas_error_track) + --sasp->sas_error_track_top; + *self->sac_error_track_or_nil = xstrdup(*sasp->sas_error_track_top); + } +#endif + + ARITH_L((" < _arith_eval <%lld> ERR<%d>\n", self->sac_rv, self->sac_error)); } +static size_t +arith__ws_squeeze(struct arith_ctx *self, char const *exp_buf, size_t exp_len, char *store_or_nil){ + char c; + bool last_ws, ws; + size_t rv; + (void)self; + + rv = 0; + + for(;; ++exp_buf, --exp_len){ + if(exp_len == 0 || (c = *exp_buf) == '\0') + goto jleave; + if(!isspace(S(unsigned char,c))) + break; + } + + for(last_ws = false;; ++exp_buf, --exp_len){ + if(exp_len == 0 || (c = *exp_buf) == '\0') + break; + + ws = !!isspace(S(unsigned char,c)); + if(ws){ + if(last_ws) + continue; + c = ' '; + } + last_ws = ws; + + ++rv; + if(store_or_nil != NULL) + *store_or_nil++ = c; + } + + if(last_ws){ + --rv; + if(store_or_nil != NULL) + --store_or_nil; + } + +jleave: + if(store_or_nil != NULL) + *store_or_nil = '\0'; + + return rv; +} + +static bool +arith__val_eval(struct arith_ctx *self, struct arith_val *savp){ + struct arith_name_stack sans_stack, *sansp; + struct arith_stack sas_stack, *sasp; + char const *cp; + + ARITH_L(("> _arith_val_eval %p <%s>\n", savp, savp->sav_var)); + + savp->sav_val = 0; + + cp = (*self->sac_cookie->lookupvar)(savp->sav_var); + if(cp == NULL) + goto jleave; + + for(sansp = self->sac_name_stack; sansp != NULL; sansp = sansp->sans_last){ + if(!strcmp(sansp->sans_var, savp->sav_var)){ + self->sac_error = ARITH_ERR_NAME_LOOP; + goto jleave; + } + } + + /* cp must be a self-contained expression. + * However, in most cases it solely consists of an integer, shortcut that */ + if(arith_idec(&savp->sav_val, cp, NULL) & ARITH_IDEC_CONSUMED){ + ARITH_L((" + _arith_val_eval NUM DIRECT <%lld>\n", savp->sav_val)); + }else{ + sasp = self->sac_stack; + self->sac_stack = &sas_stack; + + sans_stack.sans_last = sansp = self->sac_name_stack; + sans_stack.sans_var = savp->sav_var; + self->sac_name_stack = &sans_stack; + + arith__eval(self, cp, SIZE_MAX); + savp->sav_val = self->sac_rv; + /* .sav_var may be needed further on for updating purposes */ + + self->sac_stack = sasp; + self->sac_name_stack = sansp; + } + + cp = NULL; +jleave: + ARITH_L(("< _arith_val_eval %p <%s> <%lld> -> OK <%d>\n", + savp, savp->sav_var, savp->sav_val, (cp == NULL && self->sac_error == ARITH_ERR_NONE))); + + return (cp == NULL && self->sac_error == ARITH_ERR_NONE); +} + +static bool +arith__op_apply(struct arith_ctx *self){ + struct arith_val *nums_top; + uint8_t prec; + uint16_t op; + struct arith_stack *sasp; + arith_t val; + bool rv, ign; + + rv = false; + val = 0; + sasp = self->sac_stack; + op = *sasp->sas_ops_top & ARITH_OP_MASK; + ign = ((*sasp->sas_ops_top & ARITH_OP_FLAG_WHITE_MASK) != 0); + + ARITH_L((" > _arith_op_apply %s<0x%02X %u> nums_top=%p (%lu) ops_top=%p (%lu)\n", + (ign ? "WHITEOUT " : ""), op, (op & 0xFF), sasp->sas_nums_top, + S(unsigned long,sasp->sas_nums_top - sasp->sas_nums), + sasp->sas_ops_top, S(unsigned long,sasp->sas_ops_top - sasp->sas_ops))); + + /* At least one argument is always needed */ + if((nums_top = sasp->sas_nums_top) == sasp->sas_nums){ + self->sac_error = ARITH_ERR_NO_OP; + goto jleave; + } + --nums_top; + + /* Resolve name ([R]VAL) to value as necessary */ + if(!ign && nums_top->sav_var != NULL && !arith__val_eval(self, nums_top)) + goto jleave; + + val = nums_top->sav_val; + prec = op & 0xFF; + + /* Not a binary operator? */ + if(prec >= ARITH_PREC_UNARY && prec < ARITH_PREC_SKY){ + if(ign) + goto jquick; + + switch(op){ + default: break; + case ARITH_OP_UNARY_NOT: val = !val; break; + case ARITH_OP_UNARY_BIT_NOT: val = ~val; break; + case ARITH_OP_UNARY_MINUS: val = -val; break; + case ARITH_OP_PREFIX_INC: /* FALLTHROUGH */ + case ARITH_OP_POSTFIX_INC: ++val; break; + case ARITH_OP_PREFIX_DEC: /* FALLTHROUGH */ + case ARITH_OP_POSTFIX_DEC: --val; break; + } + }else if(op == ARITH_OP_COND){ + if(!(*sasp->sas_ops_top & ARITH_OP_FLAG_COND_SAW_COLON)){ + self->sac_error = ARITH_ERR_COND_NO_COLON; + goto jleave; + } + goto jquick; + }else if(op == ARITH_OP_COND_COLON){ + if(!ign){ + /* Move the ternary value over to LHV where we find it as a result, + * and ensure LHV's name is forgotten so not to evaluate it (for example in 0?I1:I2 + * I1 would be evaluated when resolving the virtual outer group, + * because it still exists on number stack) */ + nums_top[-1].sav_val = nums_top[0].sav_val; + nums_top[-1].sav_var = NULL; + } + + sasp->sas_nums_top = nums_top; + + if((sasp->sas_ops_top[-1] & ARITH_OP_MASK) == ARITH_OP_COND_COLON){ + ARITH_ERROR_TRACK( --sasp->sas_error_track_top; ) + --sasp->sas_ops_top; + if(!arith__op_apply_colons(self)) + goto jleave; + if(!ign) + sasp->sas_nums_top[-1].sav_val = val; + } + }else{ + /* Binaries need two numbers: one is popped, the other replaced */ + arith_t rval; + + if(nums_top == sasp->sas_nums){ + self->sac_error = ARITH_ERR_NO_OP; + goto jleave; + } + sasp->sas_nums_top = nums_top--; + + if(ign) + goto jquick; + + /* Resolve LHV as necessary */ + if(op != ARITH_OP_ASSIGN && nums_top->sav_var != NULL && !arith__val_eval(self, nums_top)) + goto jleave; + + rval = val; + val = nums_top->sav_val; /* (may be bogus for assign, fixed soon) */ + + /* In precedence order (excluding assignments) */ + switch(op){ + default: break; + case ARITH_OP_COMMA: /* FALLTHROUGH */ + + case ARITH_OP_ASSIGN: val = rval; break; + + case ARITH_OP_OR: val = (val != 0 || rval != 0); break; + case ARITH_OP_AND: val = (val != 0 && rval != 0); break; + + case ARITH_OP_BIT_OR: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_BIT_OR: val |= rval; break; + case ARITH_OP_BIT_XOR: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_BIT_XOR: val ^= rval; break; + case ARITH_OP_BIT_AND: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_BIT_AND: val &= rval; break; + + case ARITH_OP_EQ: val = (val == rval); break; + case ARITH_OP_NE: val = (val != rval); break; + + case ARITH_OP_LE: val = (val <= rval); break; + case ARITH_OP_GE: val = (val >= rval); break; + case ARITH_OP_LT: val = (val < rval); break; + case ARITH_OP_GT: val = (val > rval); break; + + case ARITH_OP_SHIFT_LEFT: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_SHIFT_LEFT: val <<= rval; break; + + case ARITH_OP_SHIFT_RIGHT: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_SHIFT_RIGHT: val >>= rval; break; + + case ARITH_OP_ADD: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_ADD: val += rval; break; + case ARITH_OP_SUB: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_SUB: val -= rval; break; + + case ARITH_OP_MUL: /* FALLTROUGH */ + case ARITH_OP_ASSIGN_MUL: val *= rval; break; + /* For /,%, avoid lvh=ARITH_MIN, rhv=-1: + * CHANGES, bash 4.3 [ac50fbac377e32b98d2de396f016ea81e8ee9961]: + * Fixed a bug that caused floating-point exceptions and overflow errors for the / and % + * arithmetic operators when using INTMAX_MIN and -1. */ + case ARITH_OP_DIV: /* FALLTRHOUGH */ + case ARITH_OP_ASSIGN_DIV: + if(rval == 0){ + self->sac_error = ARITH_ERR_DIV_BY_ZERO; + goto jleave; + }else if(val != ARITH_MIN || rval != -1) + val /= rval; + break; + case ARITH_OP_MOD: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_MOD: + if(rval == 0){ + self->sac_error = ARITH_ERR_DIV_BY_ZERO; + goto jleave; + }else if(val == ARITH_MIN && rval == -1) + val = 0; + else + val %= rval; + break; + + case ARITH_OP_EXP: /* FALLTHROUGH */ + case ARITH_OP_ASSIGN_EXP: + if(rval < 0){ + self->sac_error = ARITH_ERR_EXP_INVALID; + goto jleave; + }else{ + arith_t i; + + for(i = 1; rval > 0; --rval) + i *= val; + val = i; + } + break; + } + } + + /* Assignment updates a variable, which must exist. For prefix and postfix operators, too: we already turned + * them into multiple unary plus/minus unless we had seen a variable name */ +jquick: + if(prec == ARITH_PREC_ASSIGN || prec == ARITH_PREC_PREFIX || prec == ARITH_PREC_POSTFIX){ + char buf[80u], *bp; + + if(nums_top->sav_var == NULL){ + self->sac_error = ARITH_ERR_ASSIGN_NO_VAR; + goto jleave; + } + + if(!ign){ + snprintf(bp = buf, sizeof(buf), ARITH_FMT, val); + (*self->sac_cookie->setvar)(nums_top->sav_var, bp); + } + + /* And restore the stack value again for postfix operators */ + if(op == ARITH_OP_POSTFIX_INC) + --val; + else if(op == ARITH_OP_POSTFIX_DEC) + ++val; + + if(!ign){ + ARITH_L((" + _arith_op_apply VAR <%s> SET <%s> VAL <%lld>\n", nums_top->sav_var, bp, val)); + } + } + + nums_top->sav_val = val; + nums_top->sav_var = NULL; + + rv = true; +jleave: + ARITH_L((" < _arith_op_apply RV %d <0x%02X %u> RES<%lld> ERR<%d> nums=%lu ops=%lu\n", + rv, op, op & 0xFF, val, self->sac_error, + S(unsigned long,sasp->sas_nums_top - sasp->sas_nums), + S(unsigned long,sasp->sas_ops_top - sasp->sas_ops))); + + return rv; +} + +static bool +arith__op_apply_colons(struct arith_ctx *self){ + uint16_t lop, lprec; + bool next_stop; + + for(next_stop = false;;){ + if(!arith__op_apply(self)){ + next_stop = false; + break; + } + if(next_stop) + break; + ARITH_ERROR_TRACK( --self->sac_stack->sas_error_track_top; ) + lop = *--self->sac_stack->sas_ops_top & ARITH_OP_MASK; + lprec = lop & 0xFF; + next_stop = (lprec == ARITH_PREC_PAREN_LEFT || lop == ARITH_OP_COND); + } + + return next_stop; +} + +#if ARITH_DBG +static void +arith_log(char const *fmt, ...){ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +#endif + arith_t FAST_FUNC arith(arith_state_t *math_state, const char *expr) { +#if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + char *err_rest; +#endif + char const *emsg; + arith_t res; + math_state->errmsg = NULL; - math_state->list_of_recursed_names = NULL; - return evaluate_string(math_state, expr); + + switch(arith_eval(math_state, &res, expr, SIZE_MAX +#if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + , &err_rest +#endif + )){ + default: + return res; +#undef a_X +#define a_X(X,N) case CONCAT(ARITH_ERR_,X): emsg = N; break + a_X(NOMEM, "out of memory"); + a_X(SYNTAX, "syntax error"); + a_X(ASSIGN_NO_VAR, "assignment without variable"); + a_X(DIV_BY_ZERO, "division by zero"); + a_X(EXP_INVALID, "invalid exponent"); + a_X(NO_OP, "syntax error, expected operand"); + a_X(COND_NO_COLON, "syntax error, incomplete ?: condition"); + a_X(COND_PREC_INVALID, "?: condition, invalid precedence (1:v2:v3=3)"); + a_X(NAME_LOOP, "recursive variable name reference"); + a_X(OP_INVALID, "unknown operator"); + } +#undef a_X + + math_state->errmsg = +#if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + xasprintf("%s (rest: %s)", emsg, err_rest); +#else + emsg +#endif + ; +#if ENABLE_FEATURE_SH_MATH_ERROR_TRACK + free(err_rest); +#endif + + return -1; } /* diff --git a/shell/math.h b/shell/math.h index 41ef6e8dfa..8ef6019de8 100644 --- a/shell/math.h +++ b/shell/math.h @@ -65,9 +65,11 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN #if ENABLE_FEATURE_SH_MATH_64 typedef long long arith_t; +# define ARITH_MIN LLONG_MIN # define ARITH_FMT "%lld" #else typedef long arith_t; +# define ARITH_MIN LONG_MIN # define ARITH_FMT "%ld" #endif @@ -76,11 +78,14 @@ typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *v //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); typedef struct arith_state_t { - const char *errmsg; + /* ENABLE_FEATURE_SH_MATH_ERROR_TRACK: must be free(3)d if !NULL */ +#if !ENABLE_FEATURE_SH_MATH_ERROR_TRACK + const +#endif + char *errmsg; arith_var_lookup_t lookupvar; arith_var_set_t setvar; // arith_var_endofname_t endofname; - void *list_of_recursed_names; } arith_state_t; arith_t FAST_FUNC arith(arith_state_t *state, const char *expr); -- 2.38.1 --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt) From steffen at sdaoden.eu Tue Nov 8 21:22:43 2022 From: steffen at sdaoden.eu (Steffen Nurpmeso) Date: Tue, 08 Nov 2022 22:22:43 +0100 Subject: [PATCH v5] shell: exchange Dijkstra $(( )) evaluator.. In-Reply-To: <195379cd4b8e7ea5b0136cbd74a8fb7cb4366c98.1667864866.git.steffen@sdaoden.eu> References: <195379cd4b8e7ea5b0136cbd74a8fb7cb4366c98.1667864866.git.steffen@sdaoden.eu> Message-ID: <20221108212243.HaOMV%steffen@sdaoden.eu> (P.S.: not tested with hush, actually.) --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt) From magnus.armholt at gmail.com Mon Nov 14 10:13:55 2022 From: magnus.armholt at gmail.com (Magnus Armholt) Date: Mon, 14 Nov 2022 12:13:55 +0200 Subject: [PATCH 0/1] Make same named group deletion configurable Message-ID: <20221114101356.510282-1-magnus.armholt@fi.abb.com> Deleting a user will automatically delete a group with the same name (as user) if group deletion is enabled, no matter if other users are part of that group. Make it possible to disable the functionality in the configuration, but leave it on by default so that the default behaviour stays the same as in previous releases. Magnus Armholt (1): Add config option to delete group with same name loginutils/deluser.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) -- 2.34.1 From magnus.armholt at gmail.com Mon Nov 14 10:13:56 2022 From: magnus.armholt at gmail.com (Magnus Armholt) Date: Mon, 14 Nov 2022 12:13:56 +0200 Subject: [PATCH 1/1] Add config option to delete group with same name In-Reply-To: <20221114101356.510282-1-magnus.armholt@fi.abb.com> References: <20221114101356.510282-1-magnus.armholt@fi.abb.com> Message-ID: <20221114101356.510282-2-magnus.armholt@fi.abb.com> Add config option to control the functionality to delete a group with the same name as a user being deleted. --- loginutils/deluser.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 8e7df737c..a089eafa3 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -27,6 +27,15 @@ //config: help //config: If called with two non-option arguments, deluser //config: or delgroup will remove an user from a specified group. +//config: +//config:config FEATURE_DEL_SAMENAMED_GROUP +//config: bool "Support removing group with same name as user" +//config: default y +//config: depends on DELGROUP +//config: help +//config: If enabled, deluser will delete a group with same name as the user +//config: when the user is deleted (no matter if other users are part of the group). + // APPLET_NOEXEC:name main location suid_type help //applet:IF_DELUSER( APPLET_NOEXEC(deluser, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, deluser)) @@ -149,7 +158,7 @@ int deluser_main(int argc, char **argv) if (update_passwd(bb_path_group_file, NULL, NULL, name) == -1) return EXIT_FAILURE; - if (ENABLE_DELGROUP) { + if (ENABLE_DELGROUP && ENABLE_FEATURE_DEL_SAMENAMED_GROUP) { /* "deluser USER" also should try to delete * same-named group. IOW: do "delgroup USER" */ -- 2.34.1 From farmatito at tiscali.it Mon Nov 14 13:16:05 2022 From: farmatito at tiscali.it (tito) Date: Mon, 14 Nov 2022 14:16:05 +0100 Subject: [PATCH 0/1] Make same named group deletion configurable In-Reply-To: <20221114101356.510282-1-magnus.armholt@fi.abb.com> References: <20221114101356.510282-1-magnus.armholt@fi.abb.com> Message-ID: <20221114141605.4cdcd3f9@devuan> On Mon, 14 Nov 2022 12:13:55 +0200 Magnus Armholt wrote: > Deleting a user will automatically delete a group with the same > name (as user) if group deletion is enabled, no matter if other > users are part of that group. Make it possible to disable the > functionality in the configuration, but leave it on by default > so that the default behaviour stays the same as in previous releases. > > Magnus Armholt (1): > Add config option to delete group with same name > > loginutils/deluser.c | 11 ++++++++++- > 1 file changed, 10 insertions(+), 1 deletion(-) > Hi, man deluser/delgroup on devuan says: Remove a group If deluser is called with the --group option, or delgroup is called, a group will be removed. Warning: The primary group of an existing user cannot be removed. If the option --only-if-empty is given, the group won't be removed if it has any members left. So it seems to me that the default is to remove a group even if there are still users in it. It should not be difficult to add the --only-if-empy option, check for gr->mem != NULL and exit with an error. Ciao, Tito From magnus.armholt at gmail.com Tue Nov 15 10:49:25 2022 From: magnus.armholt at gmail.com (Magnus Armholt) Date: Tue, 15 Nov 2022 12:49:25 +0200 Subject: [PATCH 0/1] Make same named group deletion configurable In-Reply-To: <20221114141605.4cdcd3f9@devuan> References: <20221114101356.510282-1-magnus.armholt@fi.abb.com> <20221114141605.4cdcd3f9@devuan> Message-ID: Hi, Thanks for the input. I will drop this patch and instead send in a new one implementing the --only-if-empty functionality BR, Magnus -------------- next part -------------- An HTML attachment was scrubbed... URL: From magnus.armholt at gmail.com Tue Nov 15 10:59:13 2022 From: magnus.armholt at gmail.com (Magnus Armholt) Date: Tue, 15 Nov 2022 12:59:13 +0200 Subject: [PATCH 0/1] delgroup: Add --only-if-empty flag Message-ID: <20221115105914.925851-1-magnus.armholt@fi.abb.com> Add --only-if-empty flag to delgroup implementation. When given, and error will be returned if the group is not empty. The flag can also be given to deluser. When given, deluser will not delete the same name group, unless it is empty. Magnus Armholt (1): delgroup: Add --only-if-empty argument option loginutils/deluser.c | 50 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) -- 2.34.1 From magnus.armholt at gmail.com Tue Nov 15 10:59:14 2022 From: magnus.armholt at gmail.com (Magnus Armholt) Date: Tue, 15 Nov 2022 12:59:14 +0200 Subject: [PATCH 1/1] delgroup: Add --only-if-empty argument option In-Reply-To: <20221115105914.925851-1-magnus.armholt@fi.abb.com> References: <20221115105914.925851-1-magnus.armholt@fi.abb.com> Message-ID: <20221115105914.925851-2-magnus.armholt@fi.abb.com> Add option to only remove group if it is empty. The option can also be given to deluser, if delgroup is enabled. When --only-if-empty flag is given to deluser, it will not return failure when removing same named group fails due to being non-empty. --- loginutils/deluser.c | 50 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 8e7df737c..689adc7db 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -36,16 +36,23 @@ //kbuild:lib-$(CONFIG_DELGROUP) += deluser.o //usage:#define deluser_trivial_usage -//usage: IF_LONG_OPTS("[--remove-home] ") "USER" +//usage: IF_LONG_OPTS("[--remove-home] ") +//usage: IF_DELGROUP(IF_LONG_OPTS("[--only-if-empty] ")) "USER" //usage:#define deluser_full_usage "\n\n" //usage: "Delete USER from the system" -// --remove-home is self-explanatory enough to put it in --help +//usage: "\n --remove-home Remove also home folder of user USER" +//usage: "\n --only-if-empty Only remove group, with same name as user USER," +//usage: "\n from the system if it is empty" + //usage:#define delgroup_trivial_usage -//usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" +//usage: IF_LONG_OPTS("[--only-if-empty] ") +//usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" //usage:#define delgroup_full_usage "\n\n" //usage: "Delete group GROUP from the system" //usage: IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") +//usage: "\n --only-if-empty Only remove group GROUP from the system" +//usage: "\n if it is empty" #include "libbb.h" @@ -65,13 +72,34 @@ int deluser_main(int argc, char **argv) #if !ENABLE_LONG_OPTS const int opt_delhome = 0; + const int opt_delgroup_onlyifempty = 0; #else + int opt_delgroup_onlyifempty = 0; int opt_delhome = 0; if (do_deluser) { - opt_delhome = getopt32long(argv, "", - "remove-home\0" No_argument "\xff"); - argv += opt_delhome; - argc -= opt_delhome; + int num_opts = 0; + int opts = getopt32long(argv, "", + "remove-home\0" No_argument "\xef" + "only-if-empty\0" No_argument "\xff"); + if (opts & 1 << 0) + { + opt_delhome = 1; + num_opts++; + } + if (opts & 1 << 1) + { + opt_delgroup_onlyifempty = 1; + num_opts++; + } + + argv += num_opts; + argc -= num_opts; + + } else { + opt_delgroup_onlyifempty = getopt32long(argv, "", + "only-if-empty\0" No_argument "\xff"); + argv += opt_delgroup_onlyifempty; + argc -= opt_delgroup_onlyifempty; } #endif @@ -114,10 +142,16 @@ int deluser_main(int argc, char **argv) if (do_deluser < 0) { /* delgroup after deluser? */ gr = getgrnam(name); if (!gr) - return EXIT_SUCCESS; + return EXIT_SUCCESS; } else { gr = xgetgrnam(name); /* bail out if GROUP is wrong */ } + if (opt_delgroup_onlyifempty && gr->gr_mem != NULL) { + if (do_deluser < 0) { /* delgroup after deluser? */ + return EXIT_SUCCESS; + } + bb_error_msg_and_die("'%s' is not empty", name); + } if (!member) { /* "delgroup GROUP" */ struct passwd *pw; -- 2.34.1 From asmadeus at codewreck.org Wed Nov 16 02:52:44 2022 From: asmadeus at codewreck.org (Dominique Martinet) Date: Wed, 16 Nov 2022 11:52:44 +0900 Subject: [PATCH] sed: check errors writing file with sed -i Message-ID: <20221116025244.29213-1-asmadeus@codewreck.org> From: Dominique Martinet sed would currently not error if write failed when modifying a file. This can be reproduced with the following 'script': $ sudo mount -t tmpfs tmpfs -o size=1M /tmp/m $ sudo chmod 777 /tmp/m $ echo foo > /tmp/m/foo $ dd if=/dev/zero of=/tmp/m/fill bs=4k dd: error writing '/tmp/m/fill': No space left on device 256+0 records in 255+0 records out 1044480 bytes (1.0 MB, 1020 KiB) copied, 0.00234567 s, 445 MB/s $ busybox sed -i -e 's/.*/bar/' /tmp/m/foo $ echo $? 0 $ cat /tmp/m/foo new behaviour: $ echo foo > /tmp/m/foo $ ./busybox sed -i -e 's/.*/bar/' /tmp/m/foo sed: write error $ echo $? 4 $ cat /tmp/m/foo foo function old new delta sed_main 765 788 +23 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 23/0) Total: 23 bytes text data bss dec hex filename 793709 14340 1976 810025 c5c29 busybox_old 793732 14340 1976 810048 c5c40 busybox_unstripped Signed-off-by: Dominique Martinet --- There are other places where we're not checking return codes when I think we should, but that fixes my immediate problem. Resend from my personal mail address as mails are only allowed from subscribers on the list... Sorry for double mail Denys. editors/sed.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/editors/sed.c b/editors/sed.c index 32a4b61f6d4c..31ade17477ca 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -1639,7 +1639,10 @@ int sed_main(int argc UNUSED_PARAM, char **argv) fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); process_files(); - fclose(G.nonstdout); + if (fclose(G.nonstdout)) { + xfunc_error_retval = 4; /* It's what gnu sed exits with... */ + bb_simple_error_msg_and_die(bb_msg_write_error); + } G.nonstdout = stdout; if (opt_i) { -- 2.35.1 From David.Laight at ACULAB.COM Wed Nov 16 09:51:50 2022 From: David.Laight at ACULAB.COM (David Laight) Date: Wed, 16 Nov 2022 09:51:50 +0000 Subject: [PATCH] sed: check errors writing file with sed -i In-Reply-To: <20221116025244.29213-1-asmadeus@codewreck.org> References: <20221116025244.29213-1-asmadeus@codewreck.org> Message-ID: From: busybox Dominique Martinet > Sent: 16 November 2022 02:53 > > From: Dominique Martinet > > sed would currently not error if write failed when modifying a file. .... > diff --git a/editors/sed.c b/editors/sed.c > index 32a4b61f6d4c..31ade17477ca 100644 > --- a/editors/sed.c > +++ b/editors/sed.c > @@ -1639,7 +1639,10 @@ int sed_main(int argc UNUSED_PARAM, char **argv) > fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); > > process_files(); > -fclose(G.nonstdout); > +if (fclose(G.nonstdout)) { > +xfunc_error_retval = 4; /* It's what gnu sed exits with... */ > +bb_simple_error_msg_and_die(bb_msg_write_error); > +} > G.nonstdout = stdout; Does that report an error if there is nothing currently buffered? I think the best sequence is: fflush(G.nonstdout); if (ferror(G.nonstdout)) { xfunc_error_retval = 4; /* It's what gnu sed exits with... */ bb_simple_error_msg_and_die(bb_msg_write_error); } fclose(G.nonstdout); G.nonstdout = stdout; David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales) From asmadeus at codewreck.org Wed Nov 16 10:10:25 2022 From: asmadeus at codewreck.org ('Dominique Martinet') Date: Wed, 16 Nov 2022 19:10:25 +0900 Subject: [PATCH] sed: check errors writing file with sed -i In-Reply-To: References: <20221116025244.29213-1-asmadeus@codewreck.org> Message-ID: David Laight wrote on Wed, Nov 16, 2022 at 09:51:50AM +0000: > > +if (fclose(G.nonstdout)) { > > +xfunc_error_retval = 4; /* It's what gnu sed exits with... */ > > +bb_simple_error_msg_and_die(bb_msg_write_error); > > +} > > G.nonstdout = stdout; > > Does that report an error if there is nothing currently buffered? hmm, I never use the file interface so not quite sure, looking a bit I guess that's libc dependant? On glibc it looks like fclose will catch any error flag, but on musl from what I'm following the fflush implied in fclose will only catch the error if there haven't been another error before (because wpos=wbase=0 already so it won't try to write), and the close call itself doesn't care so it just happened to work because there was data buffered as you've pointed out. > I think the best sequence is: > > fflush(G.nonstdout); > if (ferror(G.nonstdout)) { > xfunc_error_retval = 4; /* It's what gnu sed exits with... */ > bb_simple_error_msg_and_die(bb_msg_write_error); > } > fclose(G.nonstdout); > G.nonstdout = stdout; This looked safe to me, yes. I'll send a v2 with this in a minute. -- Dominique From asmadeus at codewreck.org Wed Nov 16 10:18:59 2022 From: asmadeus at codewreck.org (Dominique Martinet) Date: Wed, 16 Nov 2022 19:18:59 +0900 Subject: [PATCH v2] sed: check errors writing file with sed -i Message-ID: <20221116101859.33414-1-asmadeus@codewreck.org> From: Dominique Martinet sed would currently not error if write failed when modifying a file. This can be reproduced with the following 'script': $ sudo mount -t tmpfs tmpfs -o size=1M /tmp/m $ sudo chmod 777 /tmp/m $ echo foo > /tmp/m/foo $ dd if=/dev/zero of=/tmp/m/fill bs=4k dd: error writing '/tmp/m/fill': No space left on device 256+0 records in 255+0 records out 1044480 bytes (1.0 MB, 1020 KiB) copied, 0.00234567 s, 445 MB/s $ busybox sed -i -e 's/.*/bar/' /tmp/m/foo $ echo $? 0 $ cat /tmp/m/foo new behaviour: $ echo foo > /tmp/m/foo $ ./busybox sed -i -e 's/.*/bar/' /tmp/m/foo sed: write error $ echo $? 4 $ cat /tmp/m/foo foo function old new delta sed_main 754 801 +47 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 47/0) Total: 47 bytes text data bss dec hex filename 66957 2398 1552 70907 114fb busybox_old 67004 2398 1552 70954 1152a busybox_unstripped Signed-off-by: Dominique Martinet --- v2: - use ferror as suggested I've checked this works with my simple case on both glibc and musl editors/sed.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/editors/sed.c b/editors/sed.c index 32a4b61f6d4c..be709eef3a9c 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -1639,6 +1639,11 @@ int sed_main(int argc UNUSED_PARAM, char **argv) fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); process_files(); + fflush(G.nonstdout); + if (ferror(G.nonstdout)) { + xfunc_error_retval = 4; /* It's what gnu sed exits with... */ + bb_simple_error_msg_and_die(bb_msg_write_error); + } fclose(G.nonstdout); G.nonstdout = stdout; -- 2.35.1 From vda.linux at googlemail.com Wed Nov 16 12:22:33 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Wed, 16 Nov 2022 13:22:33 +0100 Subject: [PATCH] loop: fix a race when a free loop device is snatched In-Reply-To: <20221021070132.40939-1-nixiaoming@huawei.com> References: <20221021070132.40939-1-nixiaoming@huawei.com> Message-ID: Applied, thank you On Fri, Oct 21, 2022 at 8:58 AM Xiaoming Ni wrote: > > When /dev/loop-control exists and *device is empty, the mounting fails > due to concurrent contention. > Code Execution Flow: > try = xasprintf(LOOP_FORMAT, i); > for (i = 0; i <= 0xfffff; i++) { // The value of "try" is not changed. > ... > lfd = rc = open(try, mode); > ... > rc = repeat_on_eagain(ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo)); > // Because of race, the value of "rc" is 0. and the value of "try" is not changed > ... > close(lfd); > } > > add/remove: 0/0 grow/shrink: 1/0 up/down: 5/0 (5) > Function old new delta > set_loop 773 778 +5 > > Fixes: 4bc59a4cf ("mount: fix a race when a free loop device is snatched > under us by another mount") > Fiexe: 3b69ba799 ("mount,losetup: use /dev/loop-control is it exists") > > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index cb8fa2442..845565d7b 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -218,8 +218,13 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > /* failure, undo LOOP_SET_FD */ > ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > + } else { > + if (rc == 0 && *device == NULL && try != dev) { > + free(try); > + close(lfd); > + goto get_free_loopN; > + } > } > - /* else: device is not free (rc == 0) or error other than ENXIO */ > close_and_try_next_loopN: > close(lfd); > try_next_loopN: > -- > 2.27.0 > From nixiaoming at huawei.com Fri Nov 18 01:01:49 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:49 +0800 Subject: [PATCH 0/9] loop: Micro-refactoring set_loop() and add LOOP_CONFIGURE Message-ID: <20221118010158.60271-1-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 To facilitate the addition of new functions, the code of set_loop() is micro-refactored. LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0): function old new delta set_loop 760 626 -134 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-134) Total: -134 bytes else function old new delta set_loop 760 703 -57 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-57) Total: -57 bytes ---- Xiaoming Ni (9): loop:refactor: extract subfunction open_file() loop:refactor: extract subfunction get_next_free_loop() loop:refactor: del close_and_try_next_loopN loop:refactor: extract subfunction set_loop_info() loop:refactor: extract subfunction set_loop_configure() loop:refactor: Use a structure to reduce parameters loop:refactor: Extract subfunction do_stat_and_mknod() loop:refactor: extract subfunction set_loop_dev() loop: Add LOOP_CONFIGURE ioctl libbb/loop.c | 275 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 170 insertions(+), 105 deletions(-) -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:55 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:55 +0800 Subject: [PATCH 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-7-nixiaoming@huawei.com> Step 6 of micro-refactoring the set_loop(): Use structs to avoid transferring a large number of parameters in set_loop_configure() and set_loop_info() function old new delta set_loop 708 720 +12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0) Total: 12 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 54 +++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 914af57b2..2200ccb9a 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,32 +126,21 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info loopinfo2; /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { return -1; } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); + if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + memcpy(&loopinfo2, loopinfo, sizeof(*loopinfo)); /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); } if (rc == 0) { return lfd; @@ -161,21 +150,36 @@ static int set_loop_configure(int ffd, int lfd, const char *file, return -1; } -static int set_loop_info(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info tmp; - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &tmp); /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); + return set_loop_configure(ffd, lfd, loopinfo); } return -1; } +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + memset(loopinfo, 0, sizeof(*loopinfo)); + safe_strncpy((char *)loopinfo->lo_file_name, file, LO_NAME_SIZE); + loopinfo->lo_offset = offset; + loopinfo->lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -187,12 +191,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse char *try; struct stat statbuf; int i, lfd, ffd, mode, rc; + bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); if (ffd < 0) { return -errno; } + init_bb_loop_info(&loopinfo, file, offset, sizelimit, flags); try = *device; if (!try) { try = dev; @@ -239,7 +245,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + rc = set_loop_info(ffd, lfd, &loopinfo); if (rc == lfd) { /* SUCCESS! */ if (!*device) -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:53 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:53 +0800 Subject: [PATCH 4/9] loop:refactor: extract subfunction set_loop_info() In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-5-nixiaoming@huawei.com> Step 4 of micro-refactoring the set_loop(): Extract subfunction set_loop_info() from set_loop() function old new delta set_loop 734 700 -34 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 91 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 91c3a45c4..89adc4f94 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,47 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_info(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + + /* If device is free, try to claim it */ + if (rc && errno == ENXIO) { + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + } + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -135,7 +176,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - bb_loop_info loopinfo; struct stat statbuf; int i, lfd, ffd, mode, rc; @@ -190,49 +230,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); - - /* If device is free, try to claim it */ - if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - close(lfd); - /* Ouch. Are we racing with other mount? */ - if (!*device) { -//TODO: add "if (--failcount != 0) ..."? - continue; - } else { - break; - } - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - /* SUCCESS! */ - if (!*device) /* was looping in search of free "/dev/loopN"? */ - *device = xstrdup(dev); - rc = lfd; /* return this */ - break; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + if (rc == lfd) { + /* SUCCESS! */ + if (!*device) + *device = xstrdup(dev); + break; } close(lfd); try_next_loopN: -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:51 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:51 +0800 Subject: [PATCH 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-3-nixiaoming@huawei.com> Step 2 of micro-refactoring the set_loop function () Extract subfunction get_next_free_loop() from set_loop() Also fix miss free(try) when stat(try) and mknod fail function old new delta set_loop 758 734 -24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") Signed-off-by: Xiaoming Ni --- libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c517ceb13..71fd8c1bc 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int get_next_free_loop(char *dev, int id) +{ + int i = get_free_loop(); + if (i >= 0) { + sprintf(dev, LOOP_FORMAT, i); + return 1; /* use /dev/loop-control */ + } else if (i == -2) { + sprintf(dev, LOOP_FORMAT, id); + return 2; + } else { + return -1; /* no free loop devices */ + } +} + static int open_file(const char *file, unsigned flags, int *mode) { int ffd; @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse try = *device; if (!try) { - get_free_loopN: - i = get_free_loop(); - if (i == -1) { - close(ffd); - return -1; /* no free loop devices */ - } - if (i >= 0) { - try = xasprintf(LOOP_FORMAT, i); - goto open_lfd; - } - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ try = dev; } /* Find a loop device */ /* 0xfffff is a max possible minor number in Linux circa 2010 */ for (i = 0; i <= 0xfffff; i++) { - sprintf(dev, LOOP_FORMAT, i); + if (!*device) { + rc = get_next_free_loop(dev, i); + if (rc == -1) { + break; /* no free loop devices */ + } else if (rc == 1) { + goto open_lfd; + } + } IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { if (ENABLE_FEATURE_MOUNT_LOOP_CREATE && errno == ENOENT - && try == dev + && (!*device) ) { /* Node doesn't exist, try to create it */ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { /* Ouch. Are we racing with other mount? */ - if (!*device /* yes */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); + if (!*device) { close(lfd); //TODO: add "if (--failcount != 0) ..."? - goto get_free_loopN; + continue; } goto close_and_try_next_loopN; } @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } if (rc == 0) { /* SUCCESS! */ - if (try != dev) /* tried a kernel-offered free loopN? */ - *device = try; /* malloced */ if (!*device) /* was looping in search of free "/dev/loopN"? */ *device = xstrdup(dev); rc = lfd; /* return this */ @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary - } else { - /* device is not free (rc == 0), or error other than ENXIO */ - if (rc == 0 /* device is not free? */ - && !*device /* racing with other mount? */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); - close(lfd); - goto get_free_loopN; - } } close_and_try_next_loopN: close(lfd); -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:54 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:54 +0800 Subject: [PATCH 5/9] loop:refactor: extract subfunction set_loop_configure() In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-6-nixiaoming@huawei.com> Step 5 of micro-refactoring the set_loop(): Extract subfunction set_loop_configure() function old new delta set_loop 700 708 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 89adc4f94..914af57b2 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,41 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_configure(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return -1; +} + static int set_loop_info(int ffd, int lfd, const char *file, unsigned long long offset, unsigned long long sizelimit, unsigned flags) { @@ -136,33 +171,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - return -1; - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - return lfd; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); } return -1; } -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:56 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:56 +0800 Subject: [PATCH 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-8-nixiaoming@huawei.com> Step 7 of micro-refactoring the set_loop(): Extract subfunction do_stat_and_mknod() function old new delta set_loop 720 700 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 2200ccb9a..67e16ddb0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -180,6 +180,28 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); } +static int do_stat_and_mknod(const char *dev, const char *device, int i) +{ + struct stat statbuf; + + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) + if (stat(dev, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE + && errno == ENOENT + && (!device) + ) { + /* Node doesn't exist, try to create it */ + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { + return 0; + } + } + /* Ran out of block devices, return failure */ + return -1; + } + return 0; +} + + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -189,7 +211,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - struct stat statbuf; int i, lfd, ffd, mode, rc; bb_loop_info loopinfo; @@ -216,18 +237,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } } - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) - if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE - && errno == ENOENT - && (!*device) - ) { - /* Node doesn't exist, try to create it */ - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) - goto open_lfd; - } - /* Ran out of block devices, return failure */ - rc = -1; + rc = do_stat_and_mknod(try, *device, i); + if (rc == -1) { break; } open_lfd: @@ -249,7 +260,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc == lfd) { /* SUCCESS! */ if (!*device) - *device = xstrdup(dev); + *device = xstrdup(try); break; } close(lfd); -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:52 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:52 +0800 Subject: [PATCH 3/9] loop:refactor: del close_and_try_next_loopN In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-4-nixiaoming@huawei.com> Step 3 of micro-refactoring the set_loop() function: Delete close_and_try_next_loopN. (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 71fd8c1bc..91c3a45c4 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -197,13 +197,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc && errno == ENXIO) { /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { + close(lfd); /* Ouch. Are we racing with other mount? */ if (!*device) { - close(lfd); //TODO: add "if (--failcount != 0) ..."? continue; + } else { + break; } - goto close_and_try_next_loopN; } memset(&loopinfo, 0, sizeof(loopinfo)); safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); @@ -233,7 +234,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary } - close_and_try_next_loopN: close(lfd); try_next_loopN: rc = -1; -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:58 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:58 +0800 Subject: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-10-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0): function old new delta set_loop 703 626 -77 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-77) Total: -77 bytes else: add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0 (0) Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/libbb/loop.c b/libbb/loop.c index 9a7ca666d..d4f4906b0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,30 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) + +/* + * loop: Add LOOP_CONFIGURE ioctl + * https://lwn.net/Articles/820408/ + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 + */ +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) +{ + int rc; + struct loop_config config; + + memset(&config, 0, sizeof(config)); + config.fd = ffd; + memcpy(&config.info, loopinfo, sizeof(config.info)); + + rc = ioctl(lfd, LOOP_CONFIGURE, &config); + if (rc == 0) { + return lfd; + } + return -1; +} + +#else static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; @@ -149,6 +173,7 @@ static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary return -1; } +#endif static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:50 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:50 +0800 Subject: [PATCH 1/9] loop:refactor: extract subfunction open_file() In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-2-nixiaoming@huawei.com> Step 1 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop() function old new delta set_loop 760 758 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-2) Total: -2 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 750642ade..c517ceb13 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,22 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int open_file(const char *file, unsigned flags, int *mode) +{ + int ffd; + /* open the file. barf if this doesn't work. */ + *mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; + retry_open_ffd: + ffd = open(file, *mode); + if (ffd < 0) { + if (*mode != O_RDONLY) { + *mode = O_RDONLY; + goto retry_open_ffd; + } + } + return ffd; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -109,15 +125,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse struct stat statbuf; int i, lfd, ffd, mode, rc; - /* Open the file. Barf if this doesn't work. */ - mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; - open_ffd: - ffd = open(file, mode); + ffd = open_file(file, flags, &mode); if (ffd < 0) { - if (mode != O_RDONLY) { - mode = O_RDONLY; - goto open_ffd; - } return -errno; } -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 01:01:57 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 09:01:57 +0800 Subject: [PATCH 8/9] loop:refactor: extract subfunction set_loop_dev() In-Reply-To: <20221118010158.60271-1-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> Message-ID: <20221118010158.60271-9-nixiaoming@huawei.com> Step 8 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop_dev() function old new delta set_loop 700 703 +3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 3/0) Total: 3 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 67e16ddb0..9a7ca666d 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -201,6 +201,26 @@ static int do_stat_and_mknod(const char *dev, const char *device, int i) return 0; } +static int set_loop_dev(const char *dev, int *mode, int ffd, bb_loop_info *loopinfo) +{ + int rc; + /* Open the sucker and check its loopiness */ + int lfd = open(dev, *mode); + if (lfd < 0 && errno == EROFS) { + *mode = O_RDONLY; + lfd = open(dev, *mode); + } + if (lfd < 0) { + return lfd; + } + rc = set_loop_info(ffd, lfd, loopinfo); + if (rc == lfd) { + return lfd; + } + close(lfd); + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to @@ -211,7 +231,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - int i, lfd, ffd, mode, rc; + int i, ffd, mode, rc; bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); @@ -242,32 +262,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse break; } open_lfd: - /* Open the sucker and check its loopiness */ - lfd = rc = open(try, mode); - if (lfd < 0 && errno == EROFS) { - mode = O_RDONLY; - lfd = rc = open(try, mode); - } - if (lfd < 0) { + rc = set_loop_dev(try, &mode, ffd, &loopinfo); + if (rc == -1) { if (errno == ENXIO) { /* Happens if loop module is not loaded */ /* rc is -1; */ break; } - goto try_next_loopN; - } - rc = set_loop_info(ffd, lfd, &loopinfo); - if (rc == lfd) { + } else { /* SUCCESS! */ if (!*device) *device = xstrdup(try); break; } - close(lfd); - try_next_loopN: - rc = -1; - if (*device) /* was looking for a particular "/dev/loopN"? */ - break; /* yes, do not try other names */ } /* for() */ close(ffd); -- 2.27.0 From cand at gmx.com Fri Nov 18 06:34:05 2022 From: cand at gmx.com (Lauri Kasanen) Date: Fri, 18 Nov 2022 08:34:05 +0200 Subject: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221118010158.60271-10-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> <20221118010158.60271-10-nixiaoming@huawei.com> Message-ID: <20221118083405.bece747d422801e7a46ae060@gmx.com> On Fri, 18 Nov 2022 09:01:58 +0800 Xiaoming Ni wrote: > LOOP_CONFIGURE is added to Linux 5.8 ... > diff --git a/libbb/loop.c b/libbb/loop.c > index 9a7ca666d..d4f4906b0 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -126,6 +126,30 @@ static int open_file(const char *file, unsigned flags, int *mode) > return ffd; > } > > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) > +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > +#else This assumes compile-time matches runtime. Ie, if you build on a 5.8 system, but run on an earlier kernel, the resulting busybox would be unable to mount loops at all. Please put it backward runtime compatibility, probably by having the new-kernel code in the same func. - Lauri From nixiaoming at huawei.com Fri Nov 18 09:11:17 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 17:11:17 +0800 Subject: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221118083405.bece747d422801e7a46ae060@gmx.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> <20221118010158.60271-10-nixiaoming@huawei.com> <20221118083405.bece747d422801e7a46ae060@gmx.com> Message-ID: <5379e99d-e556-9c06-1c17-64d2e3f7fe2a@huawei.com> On 2022/11/18 14:34, Lauri Kasanen wrote: > On Fri, 18 Nov 2022 09:01:58 +0800 > Xiaoming Ni wrote: > >> LOOP_CONFIGURE is added to Linux 5.8 > ... >> diff --git a/libbb/loop.c b/libbb/loop.c >> index 9a7ca666d..d4f4906b0 100644 >> --- a/libbb/loop.c >> +++ b/libbb/loop.c >> @@ -126,6 +126,30 @@ static int open_file(const char *file, unsigned flags, int *mode) >> return ffd; >> } >> >> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) >> +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) >> +#else > > This assumes compile-time matches runtime. Ie, if you build on a 5.8 > system, but run on an earlier kernel, the resulting busybox would be > unable to mount loops at all. > > Please put it backward runtime compatibility, probably by having the > new-kernel code in the same func. > + rc = ioctl(lfd, LOOP_CONFIGURE, &config); + if (rc == 0) { + return lfd; + } + if (rc == -1 && errno == EINVAL) /* The system may not support RING_CONFIGURE. */ + return set_loop_configure_old(ffd, lfd, loopinfo); + return -1; Is this ok? > - Lauri > > . > From explorer09 at gmail.com Fri Nov 18 09:13:26 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Fri, 18 Nov 2022 17:13:26 +0800 Subject: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221118010158.60271-10-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> <20221118010158.60271-10-nixiaoming@huawei.com> Message-ID: On Fri, Nov 18, 2022 at 9:04 AM Xiaoming Ni wrote: > > LOOP_CONFIGURE is added to Linux 5.8 > > This allows userspace to completely setup a loop device with a single > ioctl, removing the in-between state where the device can be partially > configured - eg the loop device has a backing file associated with it, > but is reading from the wrong offset. > > https://lwn.net/Articles/820408/ > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 > Hello. 1. Are the patches 1 to 8 you proposed in this set _not_ relevant to the new LOOP_CONFIGURE ioctl? I.e. They are general code structure improvements to the busybox loop device code and do not add any feature? Note that according to the bloat-o-meter results you included in the patches, some of them increase code size, and you should explain why the code size increases there, and why you think it is okay for the patch to increase code size. 2. I think LOOP_CONFIGURE support can be made into a config option, so that builders can have choice on which algorithm should be built into their busybox binary. * Always use LOOP_CONFIGURE ioctl, or * Support LOOP_CONFIGURE, but keep the old code for runtime fallback, or * Not support LOOP_CONFIGURE at all (always use the old code) From nixiaoming at huawei.com Fri Nov 18 09:27:23 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 17:27:23 +0800 Subject: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: References: <20221118010158.60271-1-nixiaoming@huawei.com> <20221118010158.60271-10-nixiaoming@huawei.com> Message-ID: <18fea0d9-9ddc-7733-ed24-41b39f510539@huawei.com> On 2022/11/18 17:13, Kang-Che Sung wrote: > On Fri, Nov 18, 2022 at 9:04 AM Xiaoming Ni wrote: >> >> LOOP_CONFIGURE is added to Linux 5.8 >> >> This allows userspace to completely setup a loop device with a single >> ioctl, removing the in-between state where the device can be partially >> configured - eg the loop device has a backing file associated with it, >> but is reading from the wrong offset. >> >> https://lwn.net/Articles/820408/ >> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 >> > > Hello. > > 1. Are the patches 1 to 8 you proposed in this set _not_ relevant to > the new LOOP_CONFIGURE ioctl? > I.e. They are general code structure improvements to the busybox loop > device code and do not add any feature? Patches 1-8 are micro-refactoring, not new features. > Note that according to the bloat-o-meter results you included in the > patches, some of them increase code size, and you should explain why > the code size increases there, and why you think it is okay for the > patch to increase code size. In patches 1-8, each patch increases or decreases the code size, but the end result is a reduction in the code size. see [PATCH 0/9] loop: Micro-refactoring set_loop() and add LOOP_CONFIGURE > 2. I think LOOP_CONFIGURE support can be made into a config option, so > that builders can have choice on which algorithm should be built into > their busybox binary. > * Always use LOOP_CONFIGURE ioctl, or > * Support LOOP_CONFIGURE, but keep the old code for runtime fallback, or > * Not support LOOP_CONFIGURE at all (always use the old code) > . > Thanks, I will add the switch control in the v2 patch. From cand at gmx.com Fri Nov 18 09:56:21 2022 From: cand at gmx.com (Lauri Kasanen) Date: Fri, 18 Nov 2022 11:56:21 +0200 Subject: [PATCH 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <5379e99d-e556-9c06-1c17-64d2e3f7fe2a@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com> <20221118010158.60271-10-nixiaoming@huawei.com> <20221118083405.bece747d422801e7a46ae060@gmx.com> <5379e99d-e556-9c06-1c17-64d2e3f7fe2a@huawei.com> Message-ID: <20221118115621.9530c100fdb77395c6c5aaad@gmx.com> On Fri, 18 Nov 2022 17:11:17 +0800 Xiaoming Ni wrote: > >> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0) > >> +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > >> +#else > > > > This assumes compile-time matches runtime. Ie, if you build on a 5.8 > > system, but run on an earlier kernel, the resulting busybox would be > > unable to mount loops at all. > > > > Please put it backward runtime compatibility, probably by having the > > new-kernel code in the same func. > > > > + rc = ioctl(lfd, LOOP_CONFIGURE, &config); > + if (rc == 0) { > + return lfd; > + } > + if (rc == -1 && errno == EINVAL) /* The system may not support > RING_CONFIGURE. */ > + return set_loop_configure_old(ffd, lfd, loopinfo); > + return -1; > > Is this ok? Probably, if it works (I don't remember what errno an invalid ioctl returns). Also wrong comment (RING_CONFIGURE) - Lauri From nixiaoming at huawei.com Fri Nov 18 12:14:40 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:40 +0800 Subject: [PATCH v2 1/9] loop:refactor: extract subfunction open_file() In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-2-nixiaoming@huawei.com> Step 1 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop() function old new delta set_loop 760 758 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-2) Total: -2 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 750642ade..c517ceb13 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,22 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int open_file(const char *file, unsigned flags, int *mode) +{ + int ffd; + /* open the file. barf if this doesn't work. */ + *mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; + retry_open_ffd: + ffd = open(file, *mode); + if (ffd < 0) { + if (*mode != O_RDONLY) { + *mode = O_RDONLY; + goto retry_open_ffd; + } + } + return ffd; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -109,15 +125,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse struct stat statbuf; int i, lfd, ffd, mode, rc; - /* Open the file. Barf if this doesn't work. */ - mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; - open_ffd: - ffd = open(file, mode); + ffd = open_file(file, flags, &mode); if (ffd < 0) { - if (mode != O_RDONLY) { - mode = O_RDONLY; - goto open_ffd; - } return -errno; } -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:47 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:47 +0800 Subject: [PATCH v2 8/9] loop:refactor: extract subfunction set_loop_dev() In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-9-nixiaoming@huawei.com> Step 8 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop_dev() function old new delta set_loop 700 716 +16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 16/0) Total: 16 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 67e16ddb0..ddb92fce3 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -201,6 +201,26 @@ static int do_stat_and_mknod(const char *dev, const char *device, int i) return 0; } +static int set_loop_dev(const char *dev, int *mode, int ffd, bb_loop_info *loopinfo) +{ + int rc; + /* Open the sucker and check its loopiness */ + int lfd = open(dev, *mode); + if (lfd < 0 && errno == EROFS) { + *mode = O_RDONLY; + lfd = open(dev, *mode); + } + if (lfd < 0) { + return lfd; + } + rc = set_loop_info(ffd, lfd, loopinfo); + if (rc == lfd) { + return lfd; + } + close(lfd); + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to @@ -211,7 +231,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - int i, lfd, ffd, mode, rc; + int i, ffd, mode, rc; bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); @@ -242,30 +262,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse break; } open_lfd: - /* Open the sucker and check its loopiness */ - lfd = rc = open(try, mode); - if (lfd < 0 && errno == EROFS) { - mode = O_RDONLY; - lfd = rc = open(try, mode); - } - if (lfd < 0) { + rc = set_loop_dev(try, &mode, ffd, &loopinfo); + if (rc == -1) { if (errno == ENXIO) { /* Happens if loop module is not loaded */ /* rc is -1; */ break; } - goto try_next_loopN; - } - rc = set_loop_info(ffd, lfd, &loopinfo); - if (rc == lfd) { + } else { /* SUCCESS! */ if (!*device) *device = xstrdup(try); break; } - close(lfd); - try_next_loopN: - rc = -1; if (*device) /* was looking for a particular "/dev/loopN"? */ break; /* yes, do not try other names */ } /* for() */ -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:48 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:48 +0800 Subject: [PATCH v2 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-10-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 kernel version >= 5.8, choice CONFIG_LOOP_CONFIGURE function old new delta set_loop 716 832 +116 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 116/0) Total: 116 bytes kernel version < 5.8, choice CONFIG_NO_LOOP_CONFIGURE function old new delta set_loop 760 716 -44 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-44) Total: -44 bytes kernel version is unknown, choice CONFIG_TRY_LOOP_CONFIGURE function old new delta ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Xiaoming Ni --- libbb/Config.src | 22 ++++++++++++++++++++++ libbb/loop.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/libbb/Config.src b/libbb/Config.src index 66a3ffa23..b7f9ddab4 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN For example, this means that entering 'l', 's', ' ', 0xff, [Enter] at shell prompt will list file named 0xff (single char name with char value 255), not file named '?'. + +choice + prompt "LOOP_CONFIGURE or LOOP_SET_FD + LOOP_SET_STATUS" + default TRY_LOOP_CONFIGURE + help + LOOP_CONFIGURE is added to Linux 5.8 + https://lwn.net/Articles/820408/ + This allows userspace to completely setup a loop device with a single + ioctl, removing the in-between state where the device can be partially + configured - eg the loop device has a backing file associated with it, + but is reading from the wrong offset. + +config LOOP_CONFIGURE + bool "always uses LOOP_CONFIGURE, kernel version >= 5.8" + +config NO_LOOP_CONFIGURE + bool "never uses LOOP_CONFIGURE, kernel version < 5.8" + +config TRY_LOOP_CONFIGURE + bool "try LOOP_CONFIGURE, kernel version is unknown" + +endchoice diff --git a/libbb/loop.c b/libbb/loop.c index ddb92fce3..be592bc4b 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,7 +126,8 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) +#ifndef CONFIG_LOOP_CONFIGURE +static int set_loop_configure_old(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; bb_loop_info loopinfo2; @@ -149,6 +150,46 @@ static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary return -1; } +#endif + +#ifndef CONFIG_NO_LOOP_CONFIGURE + +#ifndef LOOP_CONFIGURE +#define LOOP_CONFIGURE 0x4C0A +struct loop_config { + uint32_t fd; + uint32_t block_size; + struct loop_info64 info; + uint64_t __reserved[8]; +}; +#endif + +/* + * linux v5.8.0 + * loop: Add LOOP_CONFIGURE ioctl + * https://lwn.net/Articles/820408/ + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 + */ +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) +{ + int rc; + struct loop_config config; + + memset(&config, 0, sizeof(config)); + config.fd = ffd; + memcpy(&config.info, loopinfo, sizeof(config.info)); + + rc = ioctl(lfd, LOOP_CONFIGURE, &config); + if (rc == 0) { + return lfd; + } +#ifdef CONFIG_TRY_LOOP_CONFIGURE + if (rc == -1 && errno == EINVAL) /* The system may not support LOOP_CONFIGURE. */ + return set_loop_configure_old(ffd, lfd, loopinfo); +#endif + return -1; +} +#endif static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { @@ -159,7 +200,11 @@ static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) /* If device is free, try to claim it */ if (rc && errno == ENXIO) { +#ifdef CONFIG_NO_LOOP_CONFIGURE + return set_loop_configure_old(ffd, lfd, loopinfo); +#else return set_loop_configure(ffd, lfd, loopinfo); +#endif } return -1; } -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:42 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:42 +0800 Subject: [PATCH v2 3/9] loop:refactor: del close_and_try_next_loopN In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-4-nixiaoming@huawei.com> Step 3 of micro-refactoring the set_loop() function: Delete close_and_try_next_loopN. (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 71fd8c1bc..91c3a45c4 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -197,13 +197,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc && errno == ENXIO) { /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { + close(lfd); /* Ouch. Are we racing with other mount? */ if (!*device) { - close(lfd); //TODO: add "if (--failcount != 0) ..."? continue; + } else { + break; } - goto close_and_try_next_loopN; } memset(&loopinfo, 0, sizeof(loopinfo)); safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); @@ -233,7 +234,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary } - close_and_try_next_loopN: close(lfd); try_next_loopN: rc = -1; -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:44 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:44 +0800 Subject: [PATCH v2 5/9] loop:refactor: extract subfunction set_loop_configure() In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-6-nixiaoming@huawei.com> Step 5 of micro-refactoring the set_loop(): Extract subfunction set_loop_configure() function old new delta set_loop 700 708 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 89adc4f94..914af57b2 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,41 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_configure(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return -1; +} + static int set_loop_info(int ffd, int lfd, const char *file, unsigned long long offset, unsigned long long sizelimit, unsigned flags) { @@ -136,33 +171,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - return -1; - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - return lfd; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); } return -1; } -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:46 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:46 +0800 Subject: [PATCH v2 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-8-nixiaoming@huawei.com> Step 7 of micro-refactoring the set_loop(): Extract subfunction do_stat_and_mknod() function old new delta set_loop 720 700 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 2200ccb9a..67e16ddb0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -180,6 +180,28 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); } +static int do_stat_and_mknod(const char *dev, const char *device, int i) +{ + struct stat statbuf; + + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) + if (stat(dev, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE + && errno == ENOENT + && (!device) + ) { + /* Node doesn't exist, try to create it */ + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { + return 0; + } + } + /* Ran out of block devices, return failure */ + return -1; + } + return 0; +} + + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -189,7 +211,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - struct stat statbuf; int i, lfd, ffd, mode, rc; bb_loop_info loopinfo; @@ -216,18 +237,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } } - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) - if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE - && errno == ENOENT - && (!*device) - ) { - /* Node doesn't exist, try to create it */ - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) - goto open_lfd; - } - /* Ran out of block devices, return failure */ - rc = -1; + rc = do_stat_and_mknod(try, *device, i); + if (rc == -1) { break; } open_lfd: @@ -249,7 +260,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc == lfd) { /* SUCCESS! */ if (!*device) - *device = xstrdup(dev); + *device = xstrdup(try); break; } close(lfd); -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:39 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:39 +0800 Subject: [PATCH v2 0/9] loop: Micro-refactoring set_loop() and add LOOP_CONFIGURE Message-ID: <20221118121448.109475-1-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 patch 1-8: To facilitate the addition of new functions, the code of set_loop() is micro-refactored. function old new delta set_loop 760 703 -57 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-57) Total: -57 bytes patch 9: add LOOP_CONFIGURE Builders can use config to choose which algorithm to build into their busybox binary --- v2: add config for builder to select v1: http://lists.busybox.net/pipermail/busybox/2022-November/089969.html --- Xiaoming Ni (9): loop:refactor: extract subfunction open_file() loop:refactor: extract subfunction get_next_free_loop() loop:refactor: del close_and_try_next_loopN loop:refactor: extract subfunction set_loop_info() loop:refactor: extract subfunction set_loop_configure() loop:refactor: Use a structure to reduce parameters loop:refactor: Extract subfunction do_stat_and_mknod() loop:refactor: extract subfunction set_loop_dev() loop: Add LOOP_CONFIGURE ioctl libbb/Config.src | 22 ++++ libbb/loop.c | 293 ++++++++++++++++++++++++++++++----------------- 2 files changed, 212 insertions(+), 103 deletions(-) -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:41 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:41 +0800 Subject: [PATCH v2 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-3-nixiaoming@huawei.com> Step 2 of micro-refactoring the set_loop function () Extract subfunction get_next_free_loop() from set_loop() Also fix miss free(try) when stat(try) and mknod fail function old new delta set_loop 758 734 -24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") Signed-off-by: Xiaoming Ni --- libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c517ceb13..71fd8c1bc 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int get_next_free_loop(char *dev, int id) +{ + int i = get_free_loop(); + if (i >= 0) { + sprintf(dev, LOOP_FORMAT, i); + return 1; /* use /dev/loop-control */ + } else if (i == -2) { + sprintf(dev, LOOP_FORMAT, id); + return 2; + } else { + return -1; /* no free loop devices */ + } +} + static int open_file(const char *file, unsigned flags, int *mode) { int ffd; @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse try = *device; if (!try) { - get_free_loopN: - i = get_free_loop(); - if (i == -1) { - close(ffd); - return -1; /* no free loop devices */ - } - if (i >= 0) { - try = xasprintf(LOOP_FORMAT, i); - goto open_lfd; - } - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ try = dev; } /* Find a loop device */ /* 0xfffff is a max possible minor number in Linux circa 2010 */ for (i = 0; i <= 0xfffff; i++) { - sprintf(dev, LOOP_FORMAT, i); + if (!*device) { + rc = get_next_free_loop(dev, i); + if (rc == -1) { + break; /* no free loop devices */ + } else if (rc == 1) { + goto open_lfd; + } + } IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { if (ENABLE_FEATURE_MOUNT_LOOP_CREATE && errno == ENOENT - && try == dev + && (!*device) ) { /* Node doesn't exist, try to create it */ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { /* Ouch. Are we racing with other mount? */ - if (!*device /* yes */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); + if (!*device) { close(lfd); //TODO: add "if (--failcount != 0) ..."? - goto get_free_loopN; + continue; } goto close_and_try_next_loopN; } @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } if (rc == 0) { /* SUCCESS! */ - if (try != dev) /* tried a kernel-offered free loopN? */ - *device = try; /* malloced */ if (!*device) /* was looping in search of free "/dev/loopN"? */ *device = xstrdup(dev); rc = lfd; /* return this */ @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary - } else { - /* device is not free (rc == 0), or error other than ENXIO */ - if (rc == 0 /* device is not free? */ - && !*device /* racing with other mount? */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); - close(lfd); - goto get_free_loopN; - } } close_and_try_next_loopN: close(lfd); -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:45 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:45 +0800 Subject: [PATCH v2 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-7-nixiaoming@huawei.com> Step 6 of micro-refactoring the set_loop(): Use structs to avoid transferring a large number of parameters in set_loop_configure() and set_loop_info() function old new delta set_loop 708 720 +12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0) Total: 12 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 54 +++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 914af57b2..2200ccb9a 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,32 +126,21 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info loopinfo2; /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { return -1; } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); + if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + memcpy(&loopinfo2, loopinfo, sizeof(*loopinfo)); /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); } if (rc == 0) { return lfd; @@ -161,21 +150,36 @@ static int set_loop_configure(int ffd, int lfd, const char *file, return -1; } -static int set_loop_info(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info tmp; - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &tmp); /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); + return set_loop_configure(ffd, lfd, loopinfo); } return -1; } +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + memset(loopinfo, 0, sizeof(*loopinfo)); + safe_strncpy((char *)loopinfo->lo_file_name, file, LO_NAME_SIZE); + loopinfo->lo_offset = offset; + loopinfo->lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -187,12 +191,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse char *try; struct stat statbuf; int i, lfd, ffd, mode, rc; + bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); if (ffd < 0) { return -errno; } + init_bb_loop_info(&loopinfo, file, offset, sizelimit, flags); try = *device; if (!try) { try = dev; @@ -239,7 +245,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + rc = set_loop_info(ffd, lfd, &loopinfo); if (rc == lfd) { /* SUCCESS! */ if (!*device) -- 2.27.0 From nixiaoming at huawei.com Fri Nov 18 12:14:43 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:14:43 +0800 Subject: [PATCH v2 4/9] loop:refactor: extract subfunction set_loop_info() In-Reply-To: <20221118121448.109475-1-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> Message-ID: <20221118121448.109475-5-nixiaoming@huawei.com> Step 4 of micro-refactoring the set_loop(): Extract subfunction set_loop_info() from set_loop() function old new delta set_loop 734 700 -34 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 91 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 91c3a45c4..89adc4f94 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,47 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_info(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + + /* If device is free, try to claim it */ + if (rc && errno == ENXIO) { + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + } + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -135,7 +176,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - bb_loop_info loopinfo; struct stat statbuf; int i, lfd, ffd, mode, rc; @@ -190,49 +230,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); - - /* If device is free, try to claim it */ - if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - close(lfd); - /* Ouch. Are we racing with other mount? */ - if (!*device) { -//TODO: add "if (--failcount != 0) ..."? - continue; - } else { - break; - } - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - /* SUCCESS! */ - if (!*device) /* was looping in search of free "/dev/loopN"? */ - *device = xstrdup(dev); - rc = lfd; /* return this */ - break; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + if (rc == lfd) { + /* SUCCESS! */ + if (!*device) + *device = xstrdup(dev); + break; } close(lfd); try_next_loopN: -- 2.27.0 From wharms at bfs.de Fri Nov 18 12:20:04 2022 From: wharms at bfs.de (Walter Harms) Date: Fri, 18 Nov 2022 12:20:04 +0000 Subject: AW: [PATCH 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: <20221118010158.60271-3-nixiaoming@huawei.com> References: <20221118010158.60271-1-nixiaoming@huawei.com>, <20221118010158.60271-3-nixiaoming@huawei.com> Message-ID: hi, just a minor comment. do not use i as name for return value, most ppl use it as loop counter, triggers the wrong circuits in the brain. (rule of least surprise). just name it err or what you like, and please untangle the if() if (err>=0) return if (err==-2) return return -1 just my 2 cents ... ________________________________________ Von: busybox im Auftrag von Xiaoming Ni Gesendet: Freitag, 18. November 2022 02:01:51 An: busybox at busybox.net; vda.linux at googlemail.com Cc: wangle6 at huawei.com Betreff: [PATCH 2/9] loop:refactor: extract subfunction get_next_free_loop() Step 2 of micro-refactoring the set_loop function () Extract subfunction get_next_free_loop() from set_loop() Also fix miss free(try) when stat(try) and mknod fail function old new delta set_loop 758 734 -24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") Signed-off-by: Xiaoming Ni --- libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c517ceb13..71fd8c1bc 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int get_next_free_loop(char *dev, int id) +{ + int i = get_free_loop(); + if (i >= 0) { + sprintf(dev, LOOP_FORMAT, i); + return 1; /* use /dev/loop-control */ + } else if (i == -2) { + sprintf(dev, LOOP_FORMAT, id); + return 2; + } else { + return -1; /* no free loop devices */ + } +} + static int open_file(const char *file, unsigned flags, int *mode) { int ffd; @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse try = *device; if (!try) { - get_free_loopN: - i = get_free_loop(); - if (i == -1) { - close(ffd); - return -1; /* no free loop devices */ - } - if (i >= 0) { - try = xasprintf(LOOP_FORMAT, i); - goto open_lfd; - } - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ try = dev; } /* Find a loop device */ /* 0xfffff is a max possible minor number in Linux circa 2010 */ for (i = 0; i <= 0xfffff; i++) { - sprintf(dev, LOOP_FORMAT, i); + if (!*device) { + rc = get_next_free_loop(dev, i); + if (rc == -1) { + break; /* no free loop devices */ + } else if (rc == 1) { + goto open_lfd; + } + } IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { if (ENABLE_FEATURE_MOUNT_LOOP_CREATE && errno == ENOENT - && try == dev + && (!*device) ) { /* Node doesn't exist, try to create it */ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { /* Ouch. Are we racing with other mount? */ - if (!*device /* yes */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); + if (!*device) { close(lfd); //TODO: add "if (--failcount != 0) ..."? - goto get_free_loopN; + continue; } goto close_and_try_next_loopN; } @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } if (rc == 0) { /* SUCCESS! */ - if (try != dev) /* tried a kernel-offered free loopN? */ - *device = try; /* malloced */ if (!*device) /* was looping in search of free "/dev/loopN"? */ *device = xstrdup(dev); rc = lfd; /* return this */ @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary - } else { - /* device is not free (rc == 0), or error other than ENXIO */ - if (rc == 0 /* device is not free? */ - && !*device /* racing with other mount? */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); - close(lfd); - goto get_free_loopN; - } } close_and_try_next_loopN: close(lfd); -- 2.27.0 _______________________________________________ busybox mailing list busybox at busybox.net http://lists.busybox.net/mailman/listinfo/busybox From wharms at bfs.de Fri Nov 18 12:27:30 2022 From: wharms at bfs.de (Walter Harms) Date: Fri, 18 Nov 2022 12:27:30 +0000 Subject: AW: [PATCH v2 4/9] loop:refactor: extract subfunction set_loop_info() In-Reply-To: <20221118121448.109475-5-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com>, <20221118121448.109475-5-nixiaoming@huawei.com> Message-ID: <03cf95f60dbf4813a201329ae96f3278@bfs.de> on other minor if (rc && errno == ENXIO) turn it on its head safes one indent level if ( !rc || errno != ENXIO ) return -1; // failed to get loopinfo jm2c ________________________________________ Von: busybox im Auftrag von Xiaoming Ni Gesendet: Freitag, 18. November 2022 13:14:43 An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com Cc: wangle6 at huawei.com Betreff: [PATCH v2 4/9] loop:refactor: extract subfunction set_loop_info() Step 4 of micro-refactoring the set_loop(): Extract subfunction set_loop_info() from set_loop() function old new delta set_loop 734 700 -34 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 91 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 91c3a45c4..89adc4f94 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,47 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_info(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + + /* If device is free, try to claim it */ + if (rc && errno == ENXIO) { + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + } + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -135,7 +176,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - bb_loop_info loopinfo; struct stat statbuf; int i, lfd, ffd, mode, rc; @@ -190,49 +230,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); - - /* If device is free, try to claim it */ - if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - close(lfd); - /* Ouch. Are we racing with other mount? */ - if (!*device) { -//TODO: add "if (--failcount != 0) ..."? - continue; - } else { - break; - } - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - /* SUCCESS! */ - if (!*device) /* was looping in search of free "/dev/loopN"? */ - *device = xstrdup(dev); - rc = lfd; /* return this */ - break; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + if (rc == lfd) { + /* SUCCESS! */ + if (!*device) + *device = xstrdup(dev); + break; } close(lfd); try_next_loopN: -- 2.27.0 _______________________________________________ busybox mailing list busybox at busybox.net http://lists.busybox.net/mailman/listinfo/busybox From wharms at bfs.de Fri Nov 18 12:36:08 2022 From: wharms at bfs.de (Walter Harms) Date: Fri, 18 Nov 2022 12:36:08 +0000 Subject: AW: [PATCH v2 5/9] loop:refactor: extract subfunction set_loop_configure() In-Reply-To: <20221118121448.109475-6-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com>, <20221118121448.109475-6-nixiaoming@huawei.com> Message-ID: A little tweak make it more readable (i hope) putting if (rc) direkt behind rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); if (rc == 0) return lfd; // no need to check rc again if ( (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { // try again without BB_LO_FLAGS_AUTOCLEAR // does it realy work that way ? no ~ ? loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); } if (rc == 0) return lfd; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } ________________________________________ Von: busybox im Auftrag von Xiaoming Ni Gesendet: Freitag, 18. November 2022 13:14:44 An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com Cc: wangle6 at huawei.com Betreff: [PATCH v2 5/9] loop:refactor: extract subfunction set_loop_configure() Step 5 of micro-refactoring the set_loop(): Extract subfunction set_loop_configure() function old new delta set_loop 700 708 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 89adc4f94..914af57b2 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,41 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_configure(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return -1; +} + static int set_loop_info(int ffd, int lfd, const char *file, unsigned long long offset, unsigned long long sizelimit, unsigned flags) { @@ -136,33 +171,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - return -1; - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - return lfd; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); } return -1; } -- 2.27.0 _______________________________________________ busybox mailing list busybox at busybox.net http://lists.busybox.net/mailman/listinfo/busybox From nixiaoming at huawei.com Fri Nov 18 12:36:34 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:36:34 +0800 Subject: AW: [PATCH 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: References: <20221118010158.60271-1-nixiaoming@huawei.com> <20221118010158.60271-3-nixiaoming@huawei.com> Message-ID: <673b00a2-5623-d538-ef3a-a232b6b67e37@huawei.com> On 2022/11/18 20:20, Walter Harms wrote: > hi, > just a minor comment. > > do not use i as name for return value, > most ppl use it as loop counter, triggers the > wrong circuits in the brain. (rule of least surprise). > just name it err or what you like, > > and please untangle the if() > > if (err>=0) > return > if (err==-2) > return > > return -1 > > just my 2 cents ... > Thanks, I'll send a v3 patch later to replace "i" with "loopdevno", refer to the variable name of get_free_loop(). Also, I made a mistake in patch9's commit msg. The log of the code size change is misposted. I will send patch v3 later Thanks > > ________________________________________ > Von: busybox im Auftrag von Xiaoming Ni > Gesendet: Freitag, 18. November 2022 02:01:51 > An: busybox at busybox.net; vda.linux at googlemail.com > Cc: wangle6 at huawei.com > Betreff: [PATCH 2/9] loop:refactor: extract subfunction get_next_free_loop() > > Step 2 of micro-refactoring the set_loop function () > Extract subfunction get_next_free_loop() from set_loop() > > Also fix miss free(try) when stat(try) and mknod fail > > function old new delta > set_loop 758 734 -24 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes > > Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- > 1 file changed, 25 insertions(+), 30 deletions(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index c517ceb13..71fd8c1bc 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) > return loopdevno; /* can be -1 if error */ > } > > +static int get_next_free_loop(char *dev, int id) > +{ > + int i = get_free_loop(); > + if (i >= 0) { > + sprintf(dev, LOOP_FORMAT, i); > + return 1; /* use /dev/loop-control */ > + } else if (i == -2) { > + sprintf(dev, LOOP_FORMAT, id); > + return 2; > + } else { > + return -1; /* no free loop devices */ > + } > +} > + > static int open_file(const char *file, unsigned flags, int *mode) > { > int ffd; > @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > > try = *device; > if (!try) { > - get_free_loopN: > - i = get_free_loop(); > - if (i == -1) { > - close(ffd); > - return -1; /* no free loop devices */ > - } > - if (i >= 0) { > - try = xasprintf(LOOP_FORMAT, i); > - goto open_lfd; > - } > - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ > try = dev; > } > > /* Find a loop device */ > /* 0xfffff is a max possible minor number in Linux circa 2010 */ > for (i = 0; i <= 0xfffff; i++) { > - sprintf(dev, LOOP_FORMAT, i); > + if (!*device) { > + rc = get_next_free_loop(dev, i); > + if (rc == -1) { > + break; /* no free loop devices */ > + } else if (rc == 1) { > + goto open_lfd; > + } > + } > > IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) > if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { > if (ENABLE_FEATURE_MOUNT_LOOP_CREATE > && errno == ENOENT > - && try == dev > + && (!*device) > ) { > /* Node doesn't exist, try to create it */ > if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) > @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > /* Associate free loop device with file */ > if (ioctl(lfd, LOOP_SET_FD, ffd)) { > /* Ouch. Are we racing with other mount? */ > - if (!*device /* yes */ > - && try != dev /* tried a _kernel-offered_ loopN? */ > - ) { > - free(try); > + if (!*device) { > close(lfd); > //TODO: add "if (--failcount != 0) ..."? > - goto get_free_loopN; > + continue; > } > goto close_and_try_next_loopN; > } > @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > if (rc == 0) { > /* SUCCESS! */ > - if (try != dev) /* tried a kernel-offered free loopN? */ > - *device = try; /* malloced */ > if (!*device) /* was looping in search of free "/dev/loopN"? */ > *device = xstrdup(dev); > rc = lfd; /* return this */ > @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > /* failure, undo LOOP_SET_FD */ > ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > - } else { > - /* device is not free (rc == 0), or error other than ENXIO */ > - if (rc == 0 /* device is not free? */ > - && !*device /* racing with other mount? */ > - && try != dev /* tried a _kernel-offered_ loopN? */ > - ) { > - free(try); > - close(lfd); > - goto get_free_loopN; > - } > } > close_and_try_next_loopN: > close(lfd); > -- > 2.27.0 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox > . > From wharms at bfs.de Fri Nov 18 12:39:23 2022 From: wharms at bfs.de (Walter Harms) Date: Fri, 18 Nov 2022 12:39:23 +0000 Subject: AW: [PATCH v2 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() In-Reply-To: <20221118121448.109475-8-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com>, <20221118121448.109475-8-nixiaoming@huawei.com> Message-ID: <469de3e96f8e4a5da456df2a92c5492a@bfs.de> again try to safe indent level if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) return 0; jm2c ________________________________________ Von: busybox im Auftrag von Xiaoming Ni Gesendet: Freitag, 18. November 2022 13:14:46 An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com Cc: wangle6 at huawei.com Betreff: [PATCH v2 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() Step 7 of micro-refactoring the set_loop(): Extract subfunction do_stat_and_mknod() function old new delta set_loop 720 700 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 2200ccb9a..67e16ddb0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -180,6 +180,28 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); } +static int do_stat_and_mknod(const char *dev, const char *device, int i) +{ + struct stat statbuf; + + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) + if (stat(dev, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE + && errno == ENOENT + && (!device) + ) { + /* Node doesn't exist, try to create it */ + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { + return 0; + } + } + /* Ran out of block devices, return failure */ + return -1; + } + return 0; +} + + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -189,7 +211,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - struct stat statbuf; int i, lfd, ffd, mode, rc; bb_loop_info loopinfo; @@ -216,18 +237,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } } - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) - if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE - && errno == ENOENT - && (!*device) - ) { - /* Node doesn't exist, try to create it */ - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) - goto open_lfd; - } - /* Ran out of block devices, return failure */ - rc = -1; + rc = do_stat_and_mknod(try, *device, i); + if (rc == -1) { break; } open_lfd: @@ -249,7 +260,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc == lfd) { /* SUCCESS! */ if (!*device) - *device = xstrdup(dev); + *device = xstrdup(try); break; } close(lfd); -- 2.27.0 _______________________________________________ busybox mailing list busybox at busybox.net http://lists.busybox.net/mailman/listinfo/busybox From nixiaoming at huawei.com Fri Nov 18 12:47:25 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:47:25 +0800 Subject: AW: [PATCH v2 4/9] loop:refactor: extract subfunction set_loop_info() In-Reply-To: <03cf95f60dbf4813a201329ae96f3278@bfs.de> References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-5-nixiaoming@huawei.com> <03cf95f60dbf4813a201329ae96f3278@bfs.de> Message-ID: <30a1c2a5-21f4-3db1-188a-29b828f775a0@huawei.com> On 2022/11/18 20:27, Walter Harms wrote: > on other minor > > if (rc && errno == ENXIO) > > turn it on its head safes one indent level > > if ( !rc || errno != ENXIO ) > return -1; // failed to get loopinfo > > jm2c Here's for copy-paste consistency Simplification has been implemented in patch 5 by extracting functions > ________________________________________ > Von: busybox im Auftrag von Xiaoming Ni > Gesendet: Freitag, 18. November 2022 13:14:43 > An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com > Cc: wangle6 at huawei.com > Betreff: [PATCH v2 4/9] loop:refactor: extract subfunction set_loop_info() > > Step 4 of micro-refactoring the set_loop(): > Extract subfunction set_loop_info() from set_loop() > > function old new delta > set_loop 734 700 -34 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes > > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 91 +++++++++++++++++++++++++++------------------------- > 1 file changed, 47 insertions(+), 44 deletions(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index 91c3a45c4..89adc4f94 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -126,6 +126,47 @@ static int open_file(const char *file, unsigned flags, int *mode) > return ffd; > } > > +static int set_loop_info(int ffd, int lfd, const char *file, > + unsigned long long offset, unsigned long long sizelimit, unsigned flags) > +{ > + int rc; > + bb_loop_info loopinfo; > + > + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); > + > + /* If device is free, try to claim it */ > + if (rc && errno == ENXIO) { > + /* Associate free loop device with file */ > + if (ioctl(lfd, LOOP_SET_FD, ffd)) { > + return -1; > + } > + memset(&loopinfo, 0, sizeof(loopinfo)); > + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); > + loopinfo.lo_offset = offset; > + loopinfo.lo_sizelimit = sizelimit; > + /* > + * Used by mount to set LO_FLAGS_AUTOCLEAR. > + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. > + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount > + * is wrong (would free the loop device!) > + */ > + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > + /* (this code path is not tested) */ > + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + } > + if (rc == 0) { > + return lfd; > + } > + /* failure, undo LOOP_SET_FD */ > + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > + } > + return -1; > +} > + > /* Returns opened fd to the loop device, <0 on error. > * *device is loop device to use, or if *device==NULL finds a loop device to > * mount it on and sets *device to a strdup of that loop device name. > @@ -135,7 +176,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > { > char dev[LOOP_NAMESIZE]; > char *try; > - bb_loop_info loopinfo; > struct stat statbuf; > int i, lfd, ffd, mode, rc; > > @@ -190,49 +230,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > goto try_next_loopN; > } > - > - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); > - > - /* If device is free, try to claim it */ > - if (rc && errno == ENXIO) { > - /* Associate free loop device with file */ > - if (ioctl(lfd, LOOP_SET_FD, ffd)) { > - close(lfd); > - /* Ouch. Are we racing with other mount? */ > - if (!*device) { > -//TODO: add "if (--failcount != 0) ..."? > - continue; > - } else { > - break; > - } > - } > - memset(&loopinfo, 0, sizeof(loopinfo)); > - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); > - loopinfo.lo_offset = offset; > - loopinfo.lo_sizelimit = sizelimit; > - /* > - * Used by mount to set LO_FLAGS_AUTOCLEAR. > - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. > - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount > - * is wrong (would free the loop device!) > - */ > - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > - /* (this code path is not tested) */ > - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > - } > - if (rc == 0) { > - /* SUCCESS! */ > - if (!*device) /* was looping in search of free "/dev/loopN"? */ > - *device = xstrdup(dev); > - rc = lfd; /* return this */ > - break; > - } > - /* failure, undo LOOP_SET_FD */ > - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > + rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); > + if (rc == lfd) { > + /* SUCCESS! */ > + if (!*device) > + *device = xstrdup(dev); > + break; > } > close(lfd); > try_next_loopN: > -- > 2.27.0 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox > . > From wharms at bfs.de Fri Nov 18 12:48:00 2022 From: wharms at bfs.de (Walter Harms) Date: Fri, 18 Nov 2022 12:48:00 +0000 Subject: AW: [PATCH v2 8/9] loop:refactor: extract subfunction set_loop_dev() In-Reply-To: <20221118121448.109475-9-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com>, <20221118121448.109475-9-nixiaoming@huawei.com> Message-ID: i am wondering, maybe question for the maintainer. would it hurt to open it O_RDONLY in the first place ? cm2c ________________________________________ Von: busybox im Auftrag von Xiaoming Ni Gesendet: Freitag, 18. November 2022 13:14:47 An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com Cc: wangle6 at huawei.com Betreff: [PATCH v2 8/9] loop:refactor: extract subfunction set_loop_dev() Step 8 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop_dev() function old new delta set_loop 700 716 +16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 16/0) Total: 16 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 67e16ddb0..ddb92fce3 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -201,6 +201,26 @@ static int do_stat_and_mknod(const char *dev, const char *device, int i) return 0; } +static int set_loop_dev(const char *dev, int *mode, int ffd, bb_loop_info *loopinfo) +{ + int rc; + /* Open the sucker and check its loopiness */ + int lfd = open(dev, *mode); + if (lfd < 0 && errno == EROFS) { + *mode = O_RDONLY; + lfd = open(dev, *mode); + } + if (lfd < 0) { + return lfd; + } + rc = set_loop_info(ffd, lfd, loopinfo); + if (rc == lfd) { + return lfd; + } + close(lfd); + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to @@ -211,7 +231,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - int i, lfd, ffd, mode, rc; + int i, ffd, mode, rc; bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); @@ -242,30 +262,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse break; } open_lfd: - /* Open the sucker and check its loopiness */ - lfd = rc = open(try, mode); - if (lfd < 0 && errno == EROFS) { - mode = O_RDONLY; - lfd = rc = open(try, mode); - } - if (lfd < 0) { + rc = set_loop_dev(try, &mode, ffd, &loopinfo); + if (rc == -1) { if (errno == ENXIO) { /* Happens if loop module is not loaded */ /* rc is -1; */ break; } - goto try_next_loopN; - } - rc = set_loop_info(ffd, lfd, &loopinfo); - if (rc == lfd) { + } else { /* SUCCESS! */ if (!*device) *device = xstrdup(try); break; } - close(lfd); - try_next_loopN: - rc = -1; if (*device) /* was looking for a particular "/dev/loopN"? */ break; /* yes, do not try other names */ } /* for() */ -- 2.27.0 _______________________________________________ busybox mailing list busybox at busybox.net http://lists.busybox.net/mailman/listinfo/busybox From nixiaoming at huawei.com Fri Nov 18 12:49:05 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Fri, 18 Nov 2022 20:49:05 +0800 Subject: AW: [PATCH v2 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() In-Reply-To: <469de3e96f8e4a5da456df2a92c5492a@bfs.de> References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-8-nixiaoming@huawei.com> <469de3e96f8e4a5da456df2a92c5492a@bfs.de> Message-ID: <48e34c32-9867-e994-a9c9-729faf1922ad@huawei.com> On 2022/11/18 20:39, Walter Harms wrote: > again try to safe indent level > > if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) > return 0; > > jm2c Thanks, will be modified in v3 > ________________________________________ > Von: busybox im Auftrag von Xiaoming Ni > Gesendet: Freitag, 18. November 2022 13:14:46 > An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com > Cc: wangle6 at huawei.com > Betreff: [PATCH v2 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() > > Step 7 of micro-refactoring the set_loop(): > Extract subfunction do_stat_and_mknod() > > function old new delta > set_loop 720 700 -20 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes > > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 39 +++++++++++++++++++++++++-------------- > 1 file changed, 25 insertions(+), 14 deletions(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index 2200ccb9a..67e16ddb0 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -180,6 +180,28 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, > loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > } > > +static int do_stat_and_mknod(const char *dev, const char *device, int i) > +{ > + struct stat statbuf; > + > + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) > + if (stat(dev, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { > + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE > + && errno == ENOENT > + && (!device) > + ) { > + /* Node doesn't exist, try to create it */ > + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { > + return 0; > + } > + } > + /* Ran out of block devices, return failure */ > + return -1; > + } > + return 0; > +} > + > + > /* Returns opened fd to the loop device, <0 on error. > * *device is loop device to use, or if *device==NULL finds a loop device to > * mount it on and sets *device to a strdup of that loop device name. > @@ -189,7 +211,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > { > char dev[LOOP_NAMESIZE]; > char *try; > - struct stat statbuf; > int i, lfd, ffd, mode, rc; > bb_loop_info loopinfo; > > @@ -216,18 +237,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > } > > - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) > - if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { > - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE > - && errno == ENOENT > - && (!*device) > - ) { > - /* Node doesn't exist, try to create it */ > - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) > - goto open_lfd; > - } > - /* Ran out of block devices, return failure */ > - rc = -1; > + rc = do_stat_and_mknod(try, *device, i); > + if (rc == -1) { > break; > } > open_lfd: > @@ -249,7 +260,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > if (rc == lfd) { > /* SUCCESS! */ > if (!*device) > - *device = xstrdup(dev); > + *device = xstrdup(try); > break; > } > close(lfd); > -- > 2.27.0 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox > . > From explorer09 at gmail.com Fri Nov 18 17:40:22 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Sat, 19 Nov 2022 01:40:22 +0800 Subject: [PATCH v2 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: <20221118121448.109475-3-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-3-nixiaoming@huawei.com> Message-ID: On Friday, November 18, 2022, Xiaoming Ni wrote: > Step 2 of micro-refactoring the set_loop function () > Extract subfunction get_next_free_loop() from set_loop() > > Also fix miss free(try) when stat(try) and mknod fail > > function old new delta > set_loop 758 734 -24 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes > > Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- > 1 file changed, 25 insertions(+), 30 deletions(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index c517ceb13..71fd8c1bc 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) > return loopdevno; /* can be -1 if error */ > } > > +static int get_next_free_loop(char *dev, int id) > +{ > + int i = get_free_loop(); > + if (i >= 0) { > + sprintf(dev, LOOP_FORMAT, i); > + return 1; /* use /dev/loop-control */ > + } else if (i == -2) { > + sprintf(dev, LOOP_FORMAT, id); > + return 2; > + } else { > + return -1; /* no free loop devices */ > + } > +} I'm a little nervous when the buffer length of `dev` is not passed into this function. Yes I know the buffer is large enough for the loop device path that would be printed. But I just wish there would be an assertion in this function, so that if the function is reused somewhere else, the developer would know what he is doing. > + > static int open_file(const char *file, unsigned flags, int *mode) > { > int ffd; > @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > > try = *device; > if (!try) { > - get_free_loopN: > - i = get_free_loop(); > - if (i == -1) { > - close(ffd); > - return -1; /* no free loop devices */ > - } > - if (i >= 0) { > - try = xasprintf(LOOP_FORMAT, i); > - goto open_lfd; > - } > - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ > try = dev; > } > > /* Find a loop device */ > /* 0xfffff is a max possible minor number in Linux circa 2010 */ > for (i = 0; i <= 0xfffff; i++) { > - sprintf(dev, LOOP_FORMAT, i); > + if (!*device) { > + rc = get_next_free_loop(dev, i); > + if (rc == -1) { > + break; /* no free loop devices */ > + } else if (rc == 1) { > + goto open_lfd; > + } > + } > > IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) > if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { > if (ENABLE_FEATURE_MOUNT_LOOP_CREATE > && errno == ENOENT > - && try == dev > + && (!*device) > ) { > /* Node doesn't exist, try to create it */ > if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) > @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > /* Associate free loop device with file */ > if (ioctl(lfd, LOOP_SET_FD, ffd)) { > /* Ouch. Are we racing with other mount? */ > - if (!*device /* yes */ > - && try != dev /* tried a _kernel-offered_ loopN? */ > - ) { > - free(try); > + if (!*device) { > close(lfd); > //TODO: add "if (--failcount != 0) ..."? > - goto get_free_loopN; > + continue; > } > goto close_and_try_next_loopN; > } > @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > if (rc == 0) { > /* SUCCESS! */ > - if (try != dev) /* tried a kernel-offered free loopN? */ > - *device = try; /* malloced */ > if (!*device) /* was looping in search of free "/dev/loopN"? */ > *device = xstrdup(dev); > rc = lfd; /* return this */ > @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > /* failure, undo LOOP_SET_FD */ > ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > - } else { > - /* device is not free (rc == 0), or error other than ENXIO */ > - if (rc == 0 /* device is not free? */ > - && !*device /* racing with other mount? */ > - && try != dev /* tried a _kernel-offered_ loopN? */ > - ) { > - free(try); > - close(lfd); > - goto get_free_loopN; > - } > } > close_and_try_next_loopN: > close(lfd); > -- > 2.27.0 > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From explorer09 at gmail.com Fri Nov 18 18:06:28 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Sat, 19 Nov 2022 02:06:28 +0800 Subject: [PATCH v2 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: <20221118121448.109475-7-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-7-nixiaoming@huawei.com> Message-ID: On Friday, November 18, 2022, Xiaoming Ni wrote: > Step 6 of micro-refactoring the set_loop(): > Use structs to avoid transferring a large number of parameters > in set_loop_configure() and set_loop_info() > > function old new delta > set_loop 708 720 +12 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0) Total: 12 bytes > > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 54 +++++++++++++++++++++++++++++----------------------- > 1 file changed, 30 insertions(+), 24 deletions(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index 914af57b2..2200ccb9a 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -126,32 +126,21 @@ static int open_file(const char *file, unsigned flags, int *mode) > return ffd; > } > > -static int set_loop_configure(int ffd, int lfd, const char *file, > - unsigned long long offset, unsigned long long sizelimit, unsigned flags) > +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > { > int rc; > - bb_loop_info loopinfo; > + bb_loop_info loopinfo2; > /* Associate free loop device with file */ > if (ioctl(lfd, LOOP_SET_FD, ffd)) { > return -1; > } > - memset(&loopinfo, 0, sizeof(loopinfo)); > - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); > - loopinfo.lo_offset = offset; > - loopinfo.lo_sizelimit = sizelimit; > - /* > - * Used by mount to set LO_FLAGS_AUTOCLEAR. > - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. > - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount > - * is wrong (would free the loop device!) > - */ > - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); > + if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > + memcpy(&loopinfo2, loopinfo, sizeof(*loopinfo)); Just use `loopinfo2 = loopinfo;` Also, it is unclear why there is the need to clone the loopinfo buffer. > /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > /* (this code path is not tested) */ > - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); > } > if (rc == 0) { > return lfd; > @@ -161,21 +150,36 @@ static int set_loop_configure(int ffd, int lfd, const char *file, > return -1; > } > > -static int set_loop_info(int ffd, int lfd, const char *file, > - unsigned long long offset, unsigned long long sizelimit, unsigned flags) > +static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) > { > int rc; > - bb_loop_info loopinfo; > + bb_loop_info tmp; > > - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); > + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &tmp); > > /* If device is free, try to claim it */ > if (rc && errno == ENXIO) { > - return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); > + return set_loop_configure(ffd, lfd, loopinfo); > } > return -1; > } > > +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, > + unsigned long long offset, unsigned long long sizelimit, unsigned flags) > +{ > + memset(loopinfo, 0, sizeof(*loopinfo)); Would it reduce code size by doing the initialization like this? ``` bb_loop_info empty = {0}; loopinfo = empty; ``` > + safe_strncpy((char *)loopinfo->lo_file_name, file, LO_NAME_SIZE); > + loopinfo->lo_offset = offset; > + loopinfo->lo_sizelimit = sizelimit; > + /* > + * Used by mount to set LO_FLAGS_AUTOCLEAR. > + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. > + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount > + * is wrong (would free the loop device!) > + */ > + loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > +} > + > /* Returns opened fd to the loop device, <0 on error. > * *device is loop device to use, or if *device==NULL finds a loop device to > * mount it on and sets *device to a strdup of that loop device name. > @@ -187,12 +191,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > char *try; > struct stat statbuf; > int i, lfd, ffd, mode, rc; > + bb_loop_info loopinfo; > > ffd = open_file(file, flags, &mode); > if (ffd < 0) { > return -errno; > } > > + init_bb_loop_info(&loopinfo, file, offset, sizelimit, flags); > try = *device; > if (!try) { > try = dev; > @@ -239,7 +245,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse > } > goto try_next_loopN; > } > - rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); > + rc = set_loop_info(ffd, lfd, &loopinfo); > if (rc == lfd) { > /* SUCCESS! */ > if (!*device) > -- > 2.27.0 > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From explorer09 at gmail.com Fri Nov 18 18:22:31 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Sat, 19 Nov 2022 02:22:31 +0800 Subject: [PATCH v2 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221118121448.109475-10-nixiaoming@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-10-nixiaoming@huawei.com> Message-ID: On Friday, November 18, 2022, Xiaoming Ni wrote: > LOOP_CONFIGURE is added to Linux 5.8 > > This allows userspace to completely setup a loop device with a single > ioctl, removing the in-between state where the device can be partially > configured - eg the loop device has a backing file associated with it, > but is reading from the wrong offset. > > https://lwn.net/Articles/820408/ > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 > > kernel version >= 5.8, choice CONFIG_LOOP_CONFIGURE > function old new delta > set_loop 716 832 +116 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 1/0 up/down: 116/0) Total: 116 bytes > kernel version < 5.8, choice CONFIG_NO_LOOP_CONFIGURE > function old new delta > set_loop 760 716 -44 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-44) Total: -44 bytes > kernel version is unknown, choice CONFIG_TRY_LOOP_CONFIGURE > function old new delta > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes > > Signed-off-by: Xiaoming Ni > --- > libbb/Config.src | 22 ++++++++++++++++++++++ > libbb/loop.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- > 2 files changed, 68 insertions(+), 1 deletion(-) > > diff --git a/libbb/Config.src b/libbb/Config.src > index 66a3ffa23..b7f9ddab4 100644 > --- a/libbb/Config.src > +++ b/libbb/Config.src > @@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN > For example, this means that entering 'l', 's', ' ', 0xff, [Enter] > at shell prompt will list file named 0xff (single char name > with char value 255), not file named '?'. > + > +choice > + prompt "LOOP_CONFIGURE or LOOP_SET_FD + LOOP_SET_STATUS" > + default TRY_LOOP_CONFIGURE > + help > + LOOP_CONFIGURE is added to Linux 5.8 > + https://lwn.net/Articles/820408/ > + This allows userspace to completely setup a loop device with a single > + ioctl, removing the in-between state where the device can be partially > + configured - eg the loop device has a backing file associated with it, > + but is reading from the wrong offset. > + > +config LOOP_CONFIGURE > + bool "always uses LOOP_CONFIGURE, kernel version >= 5.8" > + > +config NO_LOOP_CONFIGURE > + bool "never uses LOOP_CONFIGURE, kernel version < 5.8" > + > +config TRY_LOOP_CONFIGURE > + bool "try LOOP_CONFIGURE, kernel version is unknown" > + > +endchoice > diff --git a/libbb/loop.c b/libbb/loop.c > index ddb92fce3..be592bc4b 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -126,7 +126,8 @@ static int open_file(const char *file, unsigned flags, int *mode) > return ffd; > } > > -static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > +#ifndef CONFIG_LOOP_CONFIGURE > +static int set_loop_configure_old(int ffd, int lfd, bb_loop_info *loopinfo) > { > int rc; > bb_loop_info loopinfo2; > @@ -149,6 +150,46 @@ static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > return -1; > } > +#endif > + > +#ifndef CONFIG_NO_LOOP_CONFIGURE > + > +#ifndef LOOP_CONFIGURE > +#define LOOP_CONFIGURE 0x4C0A > +struct loop_config { > + uint32_t fd; > + uint32_t block_size; > + struct loop_info64 info; > + uint64_t __reserved[8]; > +}; > +#endif > + > +/* > + * linux v5.8.0 > + * loop: Add LOOP_CONFIGURE ioctl > + * https://lwn.net/Articles/820408/ > + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 > + */ > +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > +{ > + int rc; > + struct loop_config config; > + > + memset(&config, 0, sizeof(config)); > + config.fd = ffd; > + memcpy(&config.info, loopinfo, sizeof(config.info)); > + > + rc = ioctl(lfd, LOOP_CONFIGURE, &config); > + if (rc == 0) { > + return lfd; > + } > +#ifdef CONFIG_TRY_LOOP_CONFIGURE > + if (rc == -1 && errno == EINVAL) /* The system may not support LOOP_CONFIGURE. */ > + return set_loop_configure_old(ffd, lfd, loopinfo); > +#endif How about putting the new code into a function named try_loop_configure_ioctl(), and let the original set_loop_configure() call it? This way you won't rename the function to set_loop_configure_old, the name I personally think is ugly. > + return -1; > +} > +#endif > > static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) > { > @@ -159,7 +200,11 @@ static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) > > /* If device is free, try to claim it */ > if (rc && errno == ENXIO) { > +#ifdef CONFIG_NO_LOOP_CONFIGURE > + return set_loop_configure_old(ffd, lfd, loopinfo); > +#else > return set_loop_configure(ffd, lfd, loopinfo); > +#endif > } > return -1; > } > -- > 2.27.0 > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nixiaoming at huawei.com Mon Nov 21 01:19:13 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 09:19:13 +0800 Subject: [PATCH v2 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-3-nixiaoming@huawei.com> Message-ID: On 2022/11/19 1:40, Kang-Che Sung wrote: > > > On Friday, November 18, 2022, Xiaoming Ni > wrote: > > Step 2 of micro-refactoring the set_loop function () > > ? ? ? ? Extract subfunction get_next_free_loop() from set_loop() > > > > Also fix miss free(try) when stat(try) and mknod fail > > > > function? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?old? ? ?new? ?delta > > set_loop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?758? ? ?734? ? ?-24 > > > ------------------------------------------------------------------------------ > > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24)? ? ? ? ? ? ?Total: > -24 bytes > > > > Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") > > Signed-off-by: Xiaoming Ni > > > --- > > ?libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- > > ?1 file changed, 25 insertions(+), 30 deletions(-) > > > > diff --git a/libbb/loop.c b/libbb/loop.c > > index c517ceb13..71fd8c1bc 100644 > > --- a/libbb/loop.c > > +++ b/libbb/loop.c > > @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) > > ? ? ? ? return loopdevno; /* can be -1 if error */ > > ?} > > > > +static int get_next_free_loop(char *dev, int id) > > +{ > > +? ? ? ?int i = get_free_loop(); > > +? ? ? ?if (i >= 0) { > > +? ? ? ? ? ? ? ?sprintf(dev, LOOP_FORMAT, i); > > +? ? ? ? ? ? ? ?return 1; /* use /dev/loop-control */ > > +? ? ? ?} else if (i == -2) { > > +? ? ? ? ? ? ? ?sprintf(dev, LOOP_FORMAT, id); > > +? ? ? ? ? ? ? ?return 2; > > +? ? ? ?} else { > > +? ? ? ? ? ? ? ?return -1; /* no free loop devices */ > > +? ? ? ?} > > +} > > I'm a little nervous when the buffer length of `dev` is not passed into > this function. Yes I know the buffer is large enough for the loop device > path that would be printed. But I just wish there would be an assertion > in this function, so that if the function is reused somewhere else, the > developer would know what he is doing. > static int get_next_free_loop(char *dev, size_t dev_size, int id) { int loopdevno = get_free_loop(); if (loopdevno >= 0) { snprintf(dev, dev_size, LOOP_FORMAT, loopdevno); return 1; /* use /dev/loop-control */ } if (loopdevno == -2) { snprintf(dev, dev_size, LOOP_FORMAT, id); return 2; } return -1; /* no free loop devices */ } If the dev_size parameter is added to get_next_free_loop(), the code size increases, Is it worth? function old new delta set_loop 734 744 +10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 10/0) Total: 10 bytes Thanks Xiaoming Ni From nixiaoming at huawei.com Mon Nov 21 01:31:15 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 09:31:15 +0800 Subject: [PATCH v2 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-7-nixiaoming@huawei.com> Message-ID: <88656fed-1f35-44a5-88d3-5d1692ae92e5@huawei.com> On 2022/11/19 2:06, Kang-Che Sung wrote: > > > On Friday, November 18, 2022, Xiaoming Ni > wrote: > > Step 6 of micro-refactoring the set_loop(): > > ? ? ? ? Use structs to avoid transferring a large number of parameters > > ? ? ? ? in set_loop_configure() and set_loop_info() > > > > function? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?old? ? ?new? ?delta > > set_loop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?708? ? ?720? ? ?+12 > > > ------------------------------------------------------------------------------ > > (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0)? ? ? ? ? ? ? ?Total: > 12 bytes > > > > Signed-off-by: Xiaoming Ni > > > --- > > ?libbb/loop.c | 54 +++++++++++++++++++++++++++++----------------------- > > ?1 file changed, 30 insertions(+), 24 deletions(-) > > ... > > -? ? ? ? */ > > -? ? ? ?loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > > -? ? ? ?rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > > -? ? ? ?if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > > +? ? ? ?rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); > > +? ? ? ?if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > > +? ? ? ? ? ? ? ?memcpy(&loopinfo2, loopinfo, sizeof(*loopinfo)); > > Just use `loopinfo2 = loopinfo;` Tested on my PC, there was no difference in code size between your modified scheme and my current scheme. function old new delta ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes > Also, it is unclear why there is the need to clone the loopinfo buffer. > > > ? ? ? ? ? ? ? ? /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > > ? ? ? ? ? ? ? ? /* (this code path is not tested) */ > > -? ? ? ? ? ? ? ?loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > > -? ? ? ? ? ? ? ?rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > > +? ? ? ? ? ? ? ?loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > > +? ? ? ? ? ? ? ?rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); > > ? ? ? ? } > > ? ? ? ? if (rc == 0) { > > ? ? ? ? ? ? ? ? return lfd; ... > > > > +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, > > +? ? ? ? ? ? ? ?unsigned long long offset, unsigned long long > sizelimit, unsigned flags) > > +{ > > +? ? ? ?memset(loopinfo, 0, sizeof(*loopinfo)); > > Would it reduce code size by doing the initialization like this? > > ``` > ? ? ? ?bb_loop_info empty = {0}; > ? ? ? ?loopinfo = empty; > ``` > Tested on my PC, there was no difference in code size between your modified scheme and my current scheme. function old new delta ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Thanks Xiaoming Ni From nixiaoming at huawei.com Mon Nov 21 01:49:06 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 09:49:06 +0800 Subject: [PATCH v2 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-10-nixiaoming@huawei.com> Message-ID: On 2022/11/19 2:22, Kang-Che Sung wrote: > > > On Friday, November 18, 2022, Xiaoming Ni > wrote: > > LOOP_CONFIGURE is added to Linux 5.8 > > > > This allows userspace to completely setup a loop device with a single > > ioctl, removing the in-between state where the device can be partially > > configured - eg the loop device has a backing file associated with it, > > but is reading from the wrong offset. > > > > https://lwn.net/Articles/820408/ > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 > > > > > kernel version >= 5.8, choice CONFIG_LOOP_CONFIGURE > > ? ? ? ? function? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?old > ?new? ?delta > > ? ? ? ? set_loop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?716 > ?832? ? +116 > > > ------------------------------------------------------------------------------ > > ? ? ? ? (add/remove: 0/0 grow/shrink: 1/0 up/down: 116/0) > ?Total: 116 bytes > > kernel version < 5.8, choice CONFIG_NO_LOOP_CONFIGURE > > ? ? ? ? function? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?old > ?new? ?delta > > ? ? ? ? set_loop? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?760 > ?716? ? ?-44 > > > ------------------------------------------------------------------------------ > > ? ? ? ? (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-44) > ?Total: -44 bytes > > kernel version is unknown, choice CONFIG_TRY_LOOP_CONFIGURE > > ? ? ? ? function? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?old > ?new? ?delta > > > ------------------------------------------------------------------------------ > > ? ? ? ? (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) > ? ?Total: 0 bytes > > > > Signed-off-by: Xiaoming Ni > > > --- > > ?libbb/Config.src | 22 ++++++++++++++++++++++ > > ?libbb/loop.c? ? ?| 47 ++++++++++++++++++++++++++++++++++++++++++++++- > > ?2 files changed, 68 insertions(+), 1 deletion(-) > > > > diff --git a/libbb/Config.src b/libbb/Config.src > > index 66a3ffa23..b7f9ddab4 100644 > > --- a/libbb/Config.src > > +++ b/libbb/Config.src > > @@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN > > ? ? ? ? For example, this means that entering 'l', 's', ' ', 0xff, > [Enter] > > ? ? ? ? at shell prompt will list file named 0xff (single char name > > ? ? ? ? with char value 255), not file named '?'. > > + > > +choice > > +? ? ? ?prompt "LOOP_CONFIGURE or LOOP_SET_FD + LOOP_SET_STATUS" > > +? ? ? ?default TRY_LOOP_CONFIGURE > > +? ? ? ?help > > +? ? ? ?LOOP_CONFIGURE is added to Linux 5.8 > > + https://lwn.net/Articles/820408/ > > +? ? ? ?This allows userspace to completely setup a loop device with > a single > > +? ? ? ?ioctl, removing the in-between state where the device can be > partially > > +? ? ? ?configured - eg the loop device has a backing file associated > with it, > > +? ? ? ?but is reading from the wrong offset. > > + > > +config LOOP_CONFIGURE > > +? ? ? ?bool "always uses LOOP_CONFIGURE, kernel version >= 5.8" > > + > > +config NO_LOOP_CONFIGURE > > +? ? ? ?bool "never uses LOOP_CONFIGURE, kernel version < 5.8" > > + > > +config TRY_LOOP_CONFIGURE > > +? ? ? ?bool "try LOOP_CONFIGURE, kernel version is unknown" > > + > > +endchoice > > diff --git a/libbb/loop.c b/libbb/loop.c > > index ddb92fce3..be592bc4b 100644 > > --- a/libbb/loop.c > > +++ b/libbb/loop.c > > @@ -126,7 +126,8 @@ static int open_file(const char *file, unsigned > flags, int *mode) > > ? ? ? ? return ffd; > > ?} > > > > -static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > > +#ifndef CONFIG_LOOP_CONFIGURE > > +static int set_loop_configure_old(int ffd, int lfd, bb_loop_info > *loopinfo) > > ?{ > > ? ? ? ? int rc; > > ? ? ? ? bb_loop_info loopinfo2; > > @@ -149,6 +150,46 @@ static int set_loop_configure(int ffd, int lfd, > bb_loop_info *loopinfo) > > ? ? ? ? ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > > ? ? ? ? return -1; > > ?} > > +#endif > > + > > +#ifndef CONFIG_NO_LOOP_CONFIGURE > > + > > +#ifndef LOOP_CONFIGURE > > +#define LOOP_CONFIGURE 0x4C0A > > +struct loop_config { > > +? ? ? ?uint32_t fd; > > +? ? ? ?uint32_t block_size; > > +? ? ? ?struct loop_info64 info; > > +? ? ? ?uint64_t __reserved[8]; > > +}; > > +#endif > > + > > +/* > > + * linux v5.8.0 > > + * loop: Add LOOP_CONFIGURE ioctl > > + * https://lwn.net/Articles/820408/ > > + * > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 > > > + */ > > +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) > > +{ > > +? ? ? ?int rc; > > +? ? ? ?struct loop_config config; > > + > > +? ? ? ?memset(&config, 0, sizeof(config)); > > +? ? ? ?config.fd = ffd; > > +? ? ? ?memcpy(&config.info , loopinfo, > sizeof(config.info )); > > + > > +? ? ? ?rc = ioctl(lfd, LOOP_CONFIGURE, &config); > > +? ? ? ?if (rc == 0) { > > +? ? ? ? ? ? ? ?return lfd; > > +? ? ? ?} > > +#ifdef CONFIG_TRY_LOOP_CONFIGURE > > +? ? ? ?if (rc == -1 && errno == EINVAL) /* The system may not > support LOOP_CONFIGURE. */ > > +? ? ? ? ? ? ? ?return set_loop_configure_old(ffd, lfd, loopinfo); > > +#endif > > How about putting the new code into a function named > try_loop_configure_ioctl(), and let the original set_loop_configure() > call it? > This way you won't rename the function to set_loop_configure_old, the > name I personally think is ugly. > new name: set_loop_fd_and_status #ifdef CONFIG_TRY_LOOP_CONFIGURE if (rc == -1 && errno == EINVAL) /* The system may not support LOOP_CONFIGURE. */ return set_loop_fd_and_status(ffd, lfd, loopinfo); #endif return -1; } #endif static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; bb_loop_info tmp; rc = ioctl(lfd, BB_LOOP_GET_STATUS, &tmp); /* If device is free, try to claim it */ if (rc && errno == ENXIO) { #ifdef CONFIG_NO_LOOP_CONFIGURE return set_loop_fd_and_status(ffd, lfd, loopinfo); #else return set_loop_configure(ffd, lfd, loopinfo); #endif } Thanks Xiaoming Ni > > > > +? ? ? ?return -1; > > +} > > +#endif > > > > ?static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) > > ?{ > > @@ -159,7 +200,11 @@ static int set_loop_info(int ffd, int lfd, > bb_loop_info *loopinfo) > > > > ? ? ? ? /* If device is free, try to claim it */ > > ? ? ? ? if (rc && errno == ENXIO) { > > +#ifdef CONFIG_NO_LOOP_CONFIGURE > > +? ? ? ? ? ? ? ?return set_loop_configure_old(ffd, lfd, loopinfo); > > +#else > > ? ? ? ? ? ? ? ? return set_loop_configure(ffd, lfd, loopinfo); > > +#endif > > ? ? ? ? } > > ? ? ? ? return -1; > > ?} > > -- > > 2.27.0 > > > > From nixiaoming at huawei.com Mon Nov 21 01:53:28 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 09:53:28 +0800 Subject: AW: [PATCH v2 5/9] loop:refactor: extract subfunction set_loop_configure() In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-6-nixiaoming@huawei.com> Message-ID: <25569756-4a0e-1cd6-f376-0ee6c6db28ff@huawei.com> On 2022/11/18 20:36, Walter Harms wrote: > A little tweak make it more readable (i hope) > putting if (rc) direkt behind > > rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > if (rc == 0) > return lfd; > > // no need to check rc again > if ( (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > // try again without BB_LO_FLAGS_AUTOCLEAR > // does it realy work that way ? no ~ ? > loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > } > if (rc == 0) > return lfd; > > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > + /* (this code path is not tested) */ > + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + } > + if (rc == 0) { > + return lfd; > + } In this case, duplicate "if(rc==0)" occurs. Is that worse? Thanks Xiaoming Ni > ________________________________________ > Von: busybox im Auftrag von Xiaoming Ni > Gesendet: Freitag, 18. November 2022 13:14:44 > An: busybox at busybox.net; vda.linux at googlemail.com; cand at gmx.com; explorer09 at gmail.com > Cc: wangle6 at huawei.com > Betreff: [PATCH v2 5/9] loop:refactor: extract subfunction set_loop_configure() > > Step 5 of micro-refactoring the set_loop(): > Extract subfunction set_loop_configure() > > function old new delta > set_loop 700 708 +8 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes > > Signed-off-by: Xiaoming Ni > --- > libbb/loop.c | 63 ++++++++++++++++++++++++++++++---------------------- > 1 file changed, 36 insertions(+), 27 deletions(-) > > diff --git a/libbb/loop.c b/libbb/loop.c > index 89adc4f94..914af57b2 100644 > --- a/libbb/loop.c > +++ b/libbb/loop.c > @@ -126,6 +126,41 @@ static int open_file(const char *file, unsigned flags, int *mode) > return ffd; > } > > +static int set_loop_configure(int ffd, int lfd, const char *file, > + unsigned long long offset, unsigned long long sizelimit, unsigned flags) > +{ > + int rc; > + bb_loop_info loopinfo; > + /* Associate free loop device with file */ > + if (ioctl(lfd, LOOP_SET_FD, ffd)) { > + return -1; > + } > + memset(&loopinfo, 0, sizeof(loopinfo)); > + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); > + loopinfo.lo_offset = offset; > + loopinfo.lo_sizelimit = sizelimit; > + /* > + * Used by mount to set LO_FLAGS_AUTOCLEAR. > + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. > + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount > + * is wrong (would free the loop device!) > + */ > + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > + /* (this code path is not tested) */ > + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > + } > + if (rc == 0) { > + return lfd; > + } > + /* failure, undo LOOP_SET_FD */ > + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > + return -1; > +} > + > static int set_loop_info(int ffd, int lfd, const char *file, > unsigned long long offset, unsigned long long sizelimit, unsigned flags) > { > @@ -136,33 +171,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, > > /* If device is free, try to claim it */ > if (rc && errno == ENXIO) { > - /* Associate free loop device with file */ > - if (ioctl(lfd, LOOP_SET_FD, ffd)) { > - return -1; > - } > - memset(&loopinfo, 0, sizeof(loopinfo)); > - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); > - loopinfo.lo_offset = offset; > - loopinfo.lo_sizelimit = sizelimit; > - /* > - * Used by mount to set LO_FLAGS_AUTOCLEAR. > - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. > - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount > - * is wrong (would free the loop device!) > - */ > - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { > - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > - /* (this code path is not tested) */ > - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > - } > - if (rc == 0) { > - return lfd; > - } > - /* failure, undo LOOP_SET_FD */ > - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary > + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); > } > return -1; > } > -- > 2.27.0 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox > . > From nixiaoming at huawei.com Mon Nov 21 02:46:30 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:30 +0800 Subject: [PATCH v3 0/9] loop: Micro-refactoring set_loop() and add LOOP_CONFIGURE Message-ID: <20221121024639.92549-1-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 patch 1-8: To facilitate the addition of new functions, the code of set_loop() is micro-refactored. function old new delta set_loop 760 716 -44 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-44) Total: -44 bytes patch 9: add LOOP_CONFIGURE Builders can use config to choose which algorithm to build into their busybox binary --- v3: Fine-tuned based on review comments patch2: Rename local variables, use "loopdevno" instead of "i" in get_next_free_loop(). patch7: Reduce indentation using guard statements in do_stat_and_mknod(). patch9: Rename set_loop_configure_old() to set_loop_fd_and_status() v2: http://lists.busybox.net/pipermail/busybox/2022-November/089990.html changes in patch9: add config for builder to select v1: http://lists.busybox.net/pipermail/busybox/2022-November/089969.html --- *** BLURB HERE *** Xiaoming Ni (9): loop:refactor: extract subfunction open_file() loop:refactor: extract subfunction get_next_free_loop() loop:refactor: del close_and_try_next_loopN loop:refactor: extract subfunction set_loop_info() loop:refactor: extract subfunction set_loop_configure() loop:refactor: Use a structure to reduce parameters loop:refactor: Extract subfunction do_stat_and_mknod() loop:refactor: extract subfunction set_loop_dev() loop: Add LOOP_CONFIGURE ioctl libbb/Config.src | 22 ++++ libbb/loop.c | 292 ++++++++++++++++++++++++++++++----------------- 2 files changed, 211 insertions(+), 103 deletions(-) -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:31 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:31 +0800 Subject: [PATCH v3 1/9] loop:refactor: extract subfunction open_file() In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-2-nixiaoming@huawei.com> Step 1 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop() function old new delta set_loop 760 758 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-2) Total: -2 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 750642ade..c517ceb13 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,22 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int open_file(const char *file, unsigned flags, int *mode) +{ + int ffd; + /* open the file. barf if this doesn't work. */ + *mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; + retry_open_ffd: + ffd = open(file, *mode); + if (ffd < 0) { + if (*mode != O_RDONLY) { + *mode = O_RDONLY; + goto retry_open_ffd; + } + } + return ffd; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -109,15 +125,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse struct stat statbuf; int i, lfd, ffd, mode, rc; - /* Open the file. Barf if this doesn't work. */ - mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; - open_ffd: - ffd = open(file, mode); + ffd = open_file(file, flags, &mode); if (ffd < 0) { - if (mode != O_RDONLY) { - mode = O_RDONLY; - goto open_ffd; - } return -errno; } -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:33 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:33 +0800 Subject: [PATCH v3 3/9] loop:refactor: del close_and_try_next_loopN In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-4-nixiaoming@huawei.com> Step 3 of micro-refactoring the set_loop() function: Delete close_and_try_next_loopN. (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index baa02dabb..147597ab9 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -197,13 +197,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc && errno == ENXIO) { /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { + close(lfd); /* Ouch. Are we racing with other mount? */ if (!*device) { - close(lfd); //TODO: add "if (--failcount != 0) ..."? continue; + } else { + break; } - goto close_and_try_next_loopN; } memset(&loopinfo, 0, sizeof(loopinfo)); safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); @@ -233,7 +234,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary } - close_and_try_next_loopN: close(lfd); try_next_loopN: rc = -1; -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:37 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:37 +0800 Subject: [PATCH v3 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-8-nixiaoming@huawei.com> Step 7 of micro-refactoring the set_loop(): Extract subfunction do_stat_and_mknod() function old new delta set_loop 720 700 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 0b1336a02..8b207b929 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -180,6 +180,27 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); } +static int do_stat_and_mknod(const char *dev, const char *device, int i) +{ + struct stat statbuf; + + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) + if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) + return 0; + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE + && errno == ENOENT + && (!device) + ) { + /* Node doesn't exist, try to create it */ + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { + return 0; + } + } + /* Ran out of block devices, return failure */ + return -1; +} + + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -189,7 +210,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - struct stat statbuf; int i, lfd, ffd, mode, rc; bb_loop_info loopinfo; @@ -216,18 +236,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } } - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) - if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE - && errno == ENOENT - && (!*device) - ) { - /* Node doesn't exist, try to create it */ - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) - goto open_lfd; - } - /* Ran out of block devices, return failure */ - rc = -1; + rc = do_stat_and_mknod(try, *device, i); + if (rc == -1) { break; } open_lfd: @@ -249,7 +259,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc == lfd) { /* SUCCESS! */ if (!*device) - *device = xstrdup(dev); + *device = xstrdup(try); break; } close(lfd); -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:35 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:35 +0800 Subject: [PATCH v3 5/9] loop:refactor: extract subfunction set_loop_configure() In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-6-nixiaoming@huawei.com> Step 5 of micro-refactoring the set_loop(): Extract subfunction set_loop_configure() function old new delta set_loop 700 708 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 34e2dce7a..dc8ecc9a8 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,41 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_configure(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return -1; +} + static int set_loop_info(int ffd, int lfd, const char *file, unsigned long long offset, unsigned long long sizelimit, unsigned flags) { @@ -136,33 +171,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - return -1; - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - return lfd; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); } return -1; } -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:34 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:34 +0800 Subject: [PATCH v3 4/9] loop:refactor: extract subfunction set_loop_info() In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-5-nixiaoming@huawei.com> Step 4 of micro-refactoring the set_loop(): Extract subfunction set_loop_info() from set_loop() function old new delta set_loop 734 700 -34 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 91 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 147597ab9..34e2dce7a 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,6 +126,47 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_info(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + + /* If device is free, try to claim it */ + if (rc && errno == ENXIO) { + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + } + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -135,7 +176,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - bb_loop_info loopinfo; struct stat statbuf; int i, lfd, ffd, mode, rc; @@ -190,49 +230,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); - - /* If device is free, try to claim it */ - if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - close(lfd); - /* Ouch. Are we racing with other mount? */ - if (!*device) { -//TODO: add "if (--failcount != 0) ..."? - continue; - } else { - break; - } - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - /* SUCCESS! */ - if (!*device) /* was looping in search of free "/dev/loopN"? */ - *device = xstrdup(dev); - rc = lfd; /* return this */ - break; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + if (rc == lfd) { + /* SUCCESS! */ + if (!*device) + *device = xstrdup(dev); + break; } close(lfd); try_next_loopN: -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:32 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:32 +0800 Subject: [PATCH v3 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-3-nixiaoming@huawei.com> Step 2 of micro-refactoring the set_loop function () Extract subfunction get_next_free_loop() from set_loop() Also fix miss free(try) when stat(try) and mknod fail function old new delta set_loop 758 734 -24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") Signed-off-by: Xiaoming Ni --- libbb/loop.c | 55 ++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c517ceb13..baa02dabb 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,20 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int get_next_free_loop(char *dev, int id) +{ + int loopdevno = get_free_loop(); + if (loopdevno >= 0) { + sprintf(dev, LOOP_FORMAT, loopdevno); + return 1; /* use /dev/loop-control */ + } + if (loopdevno == -2) { + sprintf(dev, LOOP_FORMAT, id); + return 2; + } + return -1; /* no free loop devices */ +} + static int open_file(const char *file, unsigned flags, int *mode) { int ffd; @@ -132,30 +146,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse try = *device; if (!try) { - get_free_loopN: - i = get_free_loop(); - if (i == -1) { - close(ffd); - return -1; /* no free loop devices */ - } - if (i >= 0) { - try = xasprintf(LOOP_FORMAT, i); - goto open_lfd; - } - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ try = dev; } /* Find a loop device */ /* 0xfffff is a max possible minor number in Linux circa 2010 */ for (i = 0; i <= 0xfffff; i++) { - sprintf(dev, LOOP_FORMAT, i); + if (!*device) { + rc = get_next_free_loop(dev, i); + if (rc == -1) { + break; /* no free loop devices */ + } else if (rc == 1) { + goto open_lfd; + } + } IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { if (ENABLE_FEATURE_MOUNT_LOOP_CREATE && errno == ENOENT - && try == dev + && (!*device) ) { /* Node doesn't exist, try to create it */ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) @@ -188,13 +198,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { /* Ouch. Are we racing with other mount? */ - if (!*device /* yes */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); + if (!*device) { close(lfd); //TODO: add "if (--failcount != 0) ..."? - goto get_free_loopN; + continue; } goto close_and_try_next_loopN; } @@ -218,8 +225,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } if (rc == 0) { /* SUCCESS! */ - if (try != dev) /* tried a kernel-offered free loopN? */ - *device = try; /* malloced */ if (!*device) /* was looping in search of free "/dev/loopN"? */ *device = xstrdup(dev); rc = lfd; /* return this */ @@ -227,16 +232,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary - } else { - /* device is not free (rc == 0), or error other than ENXIO */ - if (rc == 0 /* device is not free? */ - && !*device /* racing with other mount? */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); - close(lfd); - goto get_free_loopN; - } } close_and_try_next_loopN: close(lfd); -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:39 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:39 +0800 Subject: [PATCH v3 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-10-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 Builders can use config to choose which algorithm to build into their busybox binary kernel version >= 5.8, choice CONFIG_LOOP_CONFIGURE function old new delta set_loop 716 639 -77 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-77) Total: -77 bytes kernel version < 5.8, choice CONFIG_NO_LOOP_CONFIGURE function old new delta ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes kernel version is unknown, choice CONFIG_TRY_LOOP_CONFIGURE function old new delta set_loop 716 832 +116 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 116/0) Total: 116 bytes Signed-off-by: Xiaoming Ni --- libbb/Config.src | 22 ++++++++++++++++++++++ libbb/loop.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/libbb/Config.src b/libbb/Config.src index 66a3ffa23..b7f9ddab4 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN For example, this means that entering 'l', 's', ' ', 0xff, [Enter] at shell prompt will list file named 0xff (single char name with char value 255), not file named '?'. + +choice + prompt "LOOP_CONFIGURE or LOOP_SET_FD + LOOP_SET_STATUS" + default TRY_LOOP_CONFIGURE + help + LOOP_CONFIGURE is added to Linux 5.8 + https://lwn.net/Articles/820408/ + This allows userspace to completely setup a loop device with a single + ioctl, removing the in-between state where the device can be partially + configured - eg the loop device has a backing file associated with it, + but is reading from the wrong offset. + +config LOOP_CONFIGURE + bool "always uses LOOP_CONFIGURE, kernel version >= 5.8" + +config NO_LOOP_CONFIGURE + bool "never uses LOOP_CONFIGURE, kernel version < 5.8" + +config TRY_LOOP_CONFIGURE + bool "try LOOP_CONFIGURE, kernel version is unknown" + +endchoice diff --git a/libbb/loop.c b/libbb/loop.c index 799936765..14919b318 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,7 +126,8 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) +#ifndef CONFIG_LOOP_CONFIGURE +static int set_loop_fd_and_status(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; bb_loop_info loopinfo2; @@ -149,6 +150,46 @@ static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary return -1; } +#endif + +#ifndef CONFIG_NO_LOOP_CONFIGURE + +#ifndef LOOP_CONFIGURE +#define LOOP_CONFIGURE 0x4C0A +struct loop_config { + uint32_t fd; + uint32_t block_size; + struct loop_info64 info; + uint64_t __reserved[8]; +}; +#endif + +/* + * linux v5.8.0 + * loop: Add LOOP_CONFIGURE ioctl + * https://lwn.net/Articles/820408/ + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 + */ +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) +{ + int rc; + struct loop_config config; + + memset(&config, 0, sizeof(config)); + config.fd = ffd; + memcpy(&config.info, loopinfo, sizeof(config.info)); + + rc = ioctl(lfd, LOOP_CONFIGURE, &config); + if (rc == 0) { + return lfd; + } +#ifdef CONFIG_TRY_LOOP_CONFIGURE + if (rc == -1 && errno == EINVAL) /* The system may not support LOOP_CONFIGURE. */ + return set_loop_fd_and_status(ffd, lfd, loopinfo); +#endif + return -1; +} +#endif static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { @@ -159,7 +200,11 @@ static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) /* If device is free, try to claim it */ if (rc && errno == ENXIO) { +#ifdef CONFIG_NO_LOOP_CONFIGURE + return set_loop_fd_and_status(ffd, lfd, loopinfo); +#else return set_loop_configure(ffd, lfd, loopinfo); +#endif } return -1; } -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:38 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:38 +0800 Subject: [PATCH v3 8/9] loop:refactor: extract subfunction set_loop_dev() In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-9-nixiaoming@huawei.com> Step 8 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop_dev() function old new delta set_loop 700 716 +16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 16/0) Total: 16 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 8b207b929..799936765 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -200,6 +200,26 @@ static int do_stat_and_mknod(const char *dev, const char *device, int i) return -1; } +static int set_loop_dev(const char *dev, int *mode, int ffd, bb_loop_info *loopinfo) +{ + int rc; + /* Open the sucker and check its loopiness */ + int lfd = open(dev, *mode); + if (lfd < 0 && errno == EROFS) { + *mode = O_RDONLY; + lfd = open(dev, *mode); + } + if (lfd < 0) { + return lfd; + } + rc = set_loop_info(ffd, lfd, loopinfo); + if (rc == lfd) { + return lfd; + } + close(lfd); + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to @@ -210,7 +230,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - int i, lfd, ffd, mode, rc; + int i, ffd, mode, rc; bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); @@ -241,30 +261,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse break; } open_lfd: - /* Open the sucker and check its loopiness */ - lfd = rc = open(try, mode); - if (lfd < 0 && errno == EROFS) { - mode = O_RDONLY; - lfd = rc = open(try, mode); - } - if (lfd < 0) { + rc = set_loop_dev(try, &mode, ffd, &loopinfo); + if (rc == -1) { if (errno == ENXIO) { /* Happens if loop module is not loaded */ /* rc is -1; */ break; } - goto try_next_loopN; - } - rc = set_loop_info(ffd, lfd, &loopinfo); - if (rc == lfd) { + } else { /* SUCCESS! */ if (!*device) *device = xstrdup(try); break; } - close(lfd); - try_next_loopN: - rc = -1; if (*device) /* was looking for a particular "/dev/loopN"? */ break; /* yes, do not try other names */ } /* for() */ -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 02:46:36 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 10:46:36 +0800 Subject: [PATCH v3 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: <20221121024639.92549-1-nixiaoming@huawei.com> References: <20221121024639.92549-1-nixiaoming@huawei.com> Message-ID: <20221121024639.92549-7-nixiaoming@huawei.com> Step 6 of micro-refactoring the set_loop(): Use structs to avoid transferring a large number of parameters in set_loop_configure() and set_loop_info() function old new delta set_loop 708 720 +12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0) Total: 12 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 54 +++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index dc8ecc9a8..0b1336a02 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -126,32 +126,21 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_configure(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info loopinfo2; /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { return -1; } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); + if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + memcpy(&loopinfo2, loopinfo, sizeof(*loopinfo)); /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); } if (rc == 0) { return lfd; @@ -161,21 +150,36 @@ static int set_loop_configure(int ffd, int lfd, const char *file, return -1; } -static int set_loop_info(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_info(int ffd, int lfd, bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info tmp; - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &tmp); /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); + return set_loop_configure(ffd, lfd, loopinfo); } return -1; } +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + memset(loopinfo, 0, sizeof(*loopinfo)); + safe_strncpy((char *)loopinfo->lo_file_name, file, LO_NAME_SIZE); + loopinfo->lo_offset = offset; + loopinfo->lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -187,12 +191,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse char *try; struct stat statbuf; int i, lfd, ffd, mode, rc; + bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); if (ffd < 0) { return -errno; } + init_bb_loop_info(&loopinfo, file, offset, sizelimit, flags); try = *device; if (!try) { try = dev; @@ -239,7 +245,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + rc = set_loop_info(ffd, lfd, &loopinfo); if (rc == lfd) { /* SUCCESS! */ if (!*device) -- 2.27.0 From explorer09 at gmail.com Mon Nov 21 04:28:29 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Mon, 21 Nov 2022 12:28:29 +0800 Subject: [PATCH v2 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: <88656fed-1f35-44a5-88d3-5d1692ae92e5@huawei.com> References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-7-nixiaoming@huawei.com> <88656fed-1f35-44a5-88d3-5d1692ae92e5@huawei.com> Message-ID: On Mon, Nov 21, 2022 at 9:31 AM Xiaoming Ni wrote: > > Also, it is unclear why there is the need to clone the loopinfo buffer. > > > > > /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ > > > /* (this code path is not tested) */ > > > - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > > > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); > > > + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; > > > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); > > > } > > > if (rc == 0) { > > > return lfd; > ... > Pardon for my ignorance, but does the LOOP_SET_STATUS64 ioctl modify the `loopinfo` object internally? If the answer is yes, then it might not be a good idea to pass the `loopinfo` structure to set_loop_configure(). I think it might be better to create the object on the fly (i.e. drop this patch). Otherwise, let set_loop_configure pass in a `const bb_loop_info *` object, when we are sure it would never be modified internally. From nixiaoming at huawei.com Mon Nov 21 07:27:06 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 15:27:06 +0800 Subject: [PATCH v2 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-7-nixiaoming@huawei.com> <88656fed-1f35-44a5-88d3-5d1692ae92e5@huawei.com> Message-ID: On 2022/11/21 12:28, Kang-Che Sung wrote: > On Mon, Nov 21, 2022 at 9:31 AM Xiaoming Ni wrote: >>> Also, it is unclear why there is the need to clone the loopinfo buffer. >>> >>> > /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ >>> > /* (this code path is not tested) */ >>> > - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; >>> > - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); >>> > + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; >>> > + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); >>> > } >>> > if (rc == 0) { >>> > return lfd; >> ... >> > > Pardon for my ignorance, but does the LOOP_SET_STATUS64 ioctl modify > the `loopinfo` object internally? in linux kernel, drivers/block/loop.c: static int loop_set_status(struct loop_device *lo, const struct loop_info64 *info) static int loop_set_status64(struct loop_device *lo, const struct loop_info64 __user *arg) > If the answer is yes, then it might not be a good idea to pass the > `loopinfo` structure to set_loop_configure(). > I think it might be better to create the object on the fly (i.e. drop > this patch). > Otherwise, let set_loop_configure pass in a `const bb_loop_info *` > object, when we are sure it would never be modified internally. thanks I'll add const modifiers in the next version. Thanks From explorer09 at gmail.com Mon Nov 21 07:50:43 2022 From: explorer09 at gmail.com (Kang-Che Sung) Date: Mon, 21 Nov 2022 15:50:43 +0800 Subject: [PATCH v2 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-3-nixiaoming@huawei.com> Message-ID: On Mon, Nov 21, 2022 at 9:19 AM Xiaoming Ni wrote: > static int get_next_free_loop(char *dev, size_t dev_size, int id) > { > int loopdevno = get_free_loop(); > if (loopdevno >= 0) { > snprintf(dev, dev_size, LOOP_FORMAT, loopdevno); > return 1; /* use /dev/loop-control */ > } > if (loopdevno == -2) { > snprintf(dev, dev_size, LOOP_FORMAT, id); > return 2; > } > return -1; /* no free loop devices */ > } > > If the dev_size parameter is added to get_next_free_loop(), the code > size increases, Is it worth? > > function old new delta > set_loop 734 744 +10 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 1/0 up/down: 10/0) Total: 10 > bytes No, that isn't what I mean. sprintf() is faster than snprintf() when we are sure the string buffer would never overflow. Just keep using sprintf() here but add a statement before it: `assert(dev_size >= LOOP_NAMESIZE);` From ncopa at alpinelinux.org Mon Nov 21 13:09:57 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Mon, 21 Nov 2022 14:09:57 +0100 Subject: [PATCH] more: accept and ignore -e Message-ID: <20221121130957.8794-1-ncopa@alpinelinux.org> Accept and ignore -e which is specified in POSIX. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html --- util-linux/more.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util-linux/more.c b/util-linux/more.c index eea69da06..a830dcbc1 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -84,11 +84,12 @@ int more_main(int argc UNUSED_PARAM, char **argv) /* Parse options */ /* Accepted but ignored: */ /* -d Display help instead of ringing bell */ + /* -e Exit immediately after writing the last line */ /* -f Count logical lines (IOW: long lines are not folded) */ /* -l Do not pause after any line containing a ^L (form feed) */ /* -s Squeeze blank lines into one */ /* -u Suppress underlining */ - getopt32(argv, "dflsu"); + getopt32(argv, "deflsu"); argv += optind; /* Another popular pager, most, detects when stdout -- 2.38.1 From nixiaoming at huawei.com Mon Nov 21 13:48:45 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:48:45 +0800 Subject: [PATCH v2 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: References: <20221118121448.109475-1-nixiaoming@huawei.com> <20221118121448.109475-3-nixiaoming@huawei.com> Message-ID: <600c6400-5e80-013f-0b6b-0522baf201e1@huawei.com> On 2022/11/21 15:50, Kang-Che Sung wrote: > On Mon, Nov 21, 2022 at 9:19 AM Xiaoming Ni wrote: >> static int get_next_free_loop(char *dev, size_t dev_size, int id) >> { >> int loopdevno = get_free_loop(); >> if (loopdevno >= 0) { >> snprintf(dev, dev_size, LOOP_FORMAT, loopdevno); >> return 1; /* use /dev/loop-control */ >> } >> if (loopdevno == -2) { >> snprintf(dev, dev_size, LOOP_FORMAT, id); >> return 2; >> } >> return -1; /* no free loop devices */ >> } >> >> If the dev_size parameter is added to get_next_free_loop(), the code >> size increases, Is it worth? >> >> function old new delta >> set_loop 734 744 +10 >> ------------------------------------------------------------------------------ >> (add/remove: 0/0 grow/shrink: 1/0 up/down: 10/0) Total: 10 >> bytes > > No, that isn't what I mean. sprintf() is faster than snprintf() when > we are sure the string buffer would never overflow. > Just keep using sprintf() here but add a statement before it: > `assert(dev_size >= LOOP_NAMESIZE);` > . > thanks I'll add const modifiers in the next version. Thanks From nixiaoming at huawei.com Mon Nov 21 13:58:13 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:13 +0800 Subject: [PATCH v4 3/9] loop:refactor: del close_and_try_next_loopN In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-4-nixiaoming@huawei.com> Step 3 of micro-refactoring the set_loop() function: Delete close_and_try_next_loopN. (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 6c28e683a..c7687052b 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -200,13 +200,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc && errno == ENXIO) { /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { + close(lfd); /* Ouch. Are we racing with other mount? */ if (!*device) { - close(lfd); //TODO: add "if (--failcount != 0) ..."? continue; + } else { + break; } - goto close_and_try_next_loopN; } memset(&loopinfo, 0, sizeof(loopinfo)); safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); @@ -236,7 +237,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary } - close_and_try_next_loopN: close(lfd); try_next_loopN: rc = -1; -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:11 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:11 +0800 Subject: [PATCH v4 1/9] loop:refactor: extract subfunction open_file() In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-2-nixiaoming@huawei.com> Step 1 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop() function old new delta set_loop 760 758 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-2) Total: -2 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 750642ade..c517ceb13 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -96,6 +96,22 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int open_file(const char *file, unsigned flags, int *mode) +{ + int ffd; + /* open the file. barf if this doesn't work. */ + *mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; + retry_open_ffd: + ffd = open(file, *mode); + if (ffd < 0) { + if (*mode != O_RDONLY) { + *mode = O_RDONLY; + goto retry_open_ffd; + } + } + return ffd; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -109,15 +125,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse struct stat statbuf; int i, lfd, ffd, mode, rc; - /* Open the file. Barf if this doesn't work. */ - mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; - open_ffd: - ffd = open(file, mode); + ffd = open_file(file, flags, &mode); if (ffd < 0) { - if (mode != O_RDONLY) { - mode = O_RDONLY; - goto open_ffd; - } return -errno; } -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:10 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:10 +0800 Subject: [PATCH v4 0/9] loop: Micro-refactoring set_loop() and add LOOP_CONFIGURE Message-ID: <20221121135819.413-1-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 patch 1-8: To facilitate the addition of new functions, the code of set_loop() is micro-refactored. function old new delta set_loop 760 716 -44 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-44) Total: -44 bytes patch 9: add LOOP_CONFIGURE Builders can use config to choose which algorithm to build into their busybox binary --- v4: Fine-tuned based on review comments patch2: add assert(dev_size >= LOOP_NAMESIZE) in get_next_free_loop(). patch6,8,9: The const modifier is added to the "bb_loop_info *loopinfo" parameter. v3: http://lists.busybox.net/pipermail/busybox/2022-November/090009.html Fine-tuned based on review comments patch2: Rename local variables, use "loopdevno" instead of "i" in get_next_free_loop(). patch7: Reduce indentation using guard statements in do_stat_and_mknod(). patch9: Rename set_loop_configure_old() to set_loop_fd_and_status() v2: http://lists.busybox.net/pipermail/busybox/2022-November/089990.html changes in patch9: add config for builder to select v1: http://lists.busybox.net/pipermail/busybox/2022-November/089969.html --- Xiaoming Ni (9): loop:refactor: extract subfunction open_file() loop:refactor: extract subfunction get_next_free_loop() loop:refactor: del close_and_try_next_loopN loop:refactor: extract subfunction set_loop_info() loop:refactor: extract subfunction set_loop_configure() loop:refactor: Use a structure to reduce parameters loop:refactor: Extract subfunction do_stat_and_mknod() loop:refactor: extract subfunction set_loop_dev() loop: Add LOOP_CONFIGURE ioctl libbb/Config.src | 22 ++++ libbb/loop.c | 295 ++++++++++++++++++++++++++++++----------------- 2 files changed, 214 insertions(+), 103 deletions(-) -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:14 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:14 +0800 Subject: [PATCH v4 4/9] loop:refactor: extract subfunction set_loop_info() In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-5-nixiaoming@huawei.com> Step 4 of micro-refactoring the set_loop(): Extract subfunction set_loop_info() from set_loop() function old new delta set_loop 734 700 -34 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-34) Total: -34 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 91 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c7687052b..5dd4d4e59 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -129,6 +129,47 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_info(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + + /* If device is free, try to claim it */ + if (rc && errno == ENXIO) { + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + } + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -138,7 +179,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - bb_loop_info loopinfo; struct stat statbuf; int i, lfd, ffd, mode, rc; @@ -193,49 +233,12 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); - - /* If device is free, try to claim it */ - if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - close(lfd); - /* Ouch. Are we racing with other mount? */ - if (!*device) { -//TODO: add "if (--failcount != 0) ..."? - continue; - } else { - break; - } - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - /* SUCCESS! */ - if (!*device) /* was looping in search of free "/dev/loopN"? */ - *device = xstrdup(dev); - rc = lfd; /* return this */ - break; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + if (rc == lfd) { + /* SUCCESS! */ + if (!*device) + *device = xstrdup(dev); + break; } close(lfd); try_next_loopN: -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:18 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:18 +0800 Subject: [PATCH v4 8/9] loop:refactor: extract subfunction set_loop_dev() In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-9-nixiaoming@huawei.com> Step 8 of micro-refactoring the set_loop(): Extract subfunction open_file() from set_loop_dev() function old new delta set_loop 700 716 +16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 16/0) Total: 16 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index ec4fcf883..03b73e658 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -203,6 +203,26 @@ static int do_stat_and_mknod(const char *dev, const char *device, int i) return -1; } +static int set_loop_dev(const char *dev, int *mode, int ffd, const bb_loop_info *loopinfo) +{ + int rc; + /* Open the sucker and check its loopiness */ + int lfd = open(dev, *mode); + if (lfd < 0 && errno == EROFS) { + *mode = O_RDONLY; + lfd = open(dev, *mode); + } + if (lfd < 0) { + return lfd; + } + rc = set_loop_info(ffd, lfd, loopinfo); + if (rc == lfd) { + return lfd; + } + close(lfd); + return -1; +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to @@ -213,7 +233,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - int i, lfd, ffd, mode, rc; + int i, ffd, mode, rc; bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); @@ -244,30 +264,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse break; } open_lfd: - /* Open the sucker and check its loopiness */ - lfd = rc = open(try, mode); - if (lfd < 0 && errno == EROFS) { - mode = O_RDONLY; - lfd = rc = open(try, mode); - } - if (lfd < 0) { + rc = set_loop_dev(try, &mode, ffd, &loopinfo); + if (rc == -1) { if (errno == ENXIO) { /* Happens if loop module is not loaded */ /* rc is -1; */ break; } - goto try_next_loopN; - } - rc = set_loop_info(ffd, lfd, &loopinfo); - if (rc == lfd) { + } else { /* SUCCESS! */ if (!*device) *device = xstrdup(try); break; } - close(lfd); - try_next_loopN: - rc = -1; if (*device) /* was looking for a particular "/dev/loopN"? */ break; /* yes, do not try other names */ } /* for() */ -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:12 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:12 +0800 Subject: [PATCH v4 2/9] loop:refactor: extract subfunction get_next_free_loop() In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-3-nixiaoming@huawei.com> Step 2 of micro-refactoring the set_loop function () Extract subfunction get_next_free_loop() from set_loop() Also fix miss free(try) when stat(try) and mknod fail function old new delta set_loop 758 734 -24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24) Total: -24 bytes Fixes: 3448914e8cc5 ("mount,losetup: use /dev/loop-control is it exists") Signed-off-by: Xiaoming Ni --- libbb/loop.c | 58 +++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index c517ceb13..6c28e683a 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -9,6 +9,7 @@ */ #include "libbb.h" #include +#include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) @@ -96,6 +97,22 @@ int FAST_FUNC get_free_loop(void) return loopdevno; /* can be -1 if error */ } +static int get_next_free_loop(char *dev, __attribute__((unused)) size_t dev_size, int id) +{ + int loopdevno; + assert(dev_size >= LOOP_NAMESIZE); + loopdevno = get_free_loop(); + if (loopdevno >= 0) { + sprintf(dev, LOOP_FORMAT, loopdevno); + return 1; /* use /dev/loop-control */ + } + if (loopdevno == -2) { + sprintf(dev, LOOP_FORMAT, id); + return 2; + } + return -1; /* no free loop devices */ +} + static int open_file(const char *file, unsigned flags, int *mode) { int ffd; @@ -132,30 +149,26 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse try = *device; if (!try) { - get_free_loopN: - i = get_free_loop(); - if (i == -1) { - close(ffd); - return -1; /* no free loop devices */ - } - if (i >= 0) { - try = xasprintf(LOOP_FORMAT, i); - goto open_lfd; - } - /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ try = dev; } /* Find a loop device */ /* 0xfffff is a max possible minor number in Linux circa 2010 */ for (i = 0; i <= 0xfffff; i++) { - sprintf(dev, LOOP_FORMAT, i); + if (!*device) { + rc = get_next_free_loop(dev, sizeof(dev), i); + if (rc == -1) { + break; /* no free loop devices */ + } else if (rc == 1) { + goto open_lfd; + } + } IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { if (ENABLE_FEATURE_MOUNT_LOOP_CREATE && errno == ENOENT - && try == dev + && (!*device) ) { /* Node doesn't exist, try to create it */ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) @@ -188,13 +201,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { /* Ouch. Are we racing with other mount? */ - if (!*device /* yes */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); + if (!*device) { close(lfd); //TODO: add "if (--failcount != 0) ..."? - goto get_free_loopN; + continue; } goto close_and_try_next_loopN; } @@ -218,8 +228,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } if (rc == 0) { /* SUCCESS! */ - if (try != dev) /* tried a kernel-offered free loopN? */ - *device = try; /* malloced */ if (!*device) /* was looping in search of free "/dev/loopN"? */ *device = xstrdup(dev); rc = lfd; /* return this */ @@ -227,16 +235,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* failure, undo LOOP_SET_FD */ ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary - } else { - /* device is not free (rc == 0), or error other than ENXIO */ - if (rc == 0 /* device is not free? */ - && !*device /* racing with other mount? */ - && try != dev /* tried a _kernel-offered_ loopN? */ - ) { - free(try); - close(lfd); - goto get_free_loopN; - } } close_and_try_next_loopN: close(lfd); -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:16 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:16 +0800 Subject: [PATCH v4 6/9] loop:refactor: Use a structure to reduce parameters In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-7-nixiaoming@huawei.com> Step 6 of micro-refactoring the set_loop(): Use structs to avoid transferring a large number of parameters in set_loop_configure() and set_loop_info() function old new delta set_loop 708 720 +12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 12/0) Total: 12 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 54 +++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 0d4d0398c..5f0db4b18 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -129,32 +129,21 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } -static int set_loop_configure(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_fd_and_status(int ffd, int lfd, const bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info loopinfo2; /* Associate free loop device with file */ if (ioctl(lfd, LOOP_SET_FD, ffd)) { return -1; } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + rc = ioctl(lfd, BB_LOOP_SET_STATUS, loopinfo); + if (rc != 0 && (loopinfo->lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + memcpy(&loopinfo2, loopinfo, sizeof(*loopinfo)); /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + loopinfo2.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo2); } if (rc == 0) { return lfd; @@ -164,21 +153,36 @@ static int set_loop_configure(int ffd, int lfd, const char *file, return -1; } -static int set_loop_info(int ffd, int lfd, const char *file, - unsigned long long offset, unsigned long long sizelimit, unsigned flags) +static int set_loop_info(int ffd, int lfd, const bb_loop_info *loopinfo) { int rc; - bb_loop_info loopinfo; + bb_loop_info tmp; - rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); + rc = ioctl(lfd, BB_LOOP_GET_STATUS, &tmp); /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); + return set_loop_fd_and_status(ffd, lfd, loopinfo); } return -1; } +static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + memset(loopinfo, 0, sizeof(*loopinfo)); + safe_strncpy((char *)loopinfo->lo_file_name, file, LO_NAME_SIZE); + loopinfo->lo_offset = offset; + loopinfo->lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); +} + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -190,12 +194,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse char *try; struct stat statbuf; int i, lfd, ffd, mode, rc; + bb_loop_info loopinfo; ffd = open_file(file, flags, &mode); if (ffd < 0) { return -errno; } + init_bb_loop_info(&loopinfo, file, offset, sizelimit, flags); try = *device; if (!try) { try = dev; @@ -242,7 +248,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } goto try_next_loopN; } - rc = set_loop_info(ffd, lfd, file, offset, sizelimit, flags); + rc = set_loop_info(ffd, lfd, &loopinfo); if (rc == lfd) { /* SUCCESS! */ if (!*device) -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:15 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:15 +0800 Subject: [PATCH v4 5/9] loop:refactor: extract subfunction set_loop_configure() In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-6-nixiaoming@huawei.com> Step 5 of micro-refactoring the set_loop(): Extract subfunction set_loop_configure() function old new delta set_loop 700 708 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 5dd4d4e59..0d4d0398c 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -129,6 +129,41 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +static int set_loop_configure(int ffd, int lfd, const char *file, + unsigned long long offset, unsigned long long sizelimit, unsigned flags) +{ + int rc; + bb_loop_info loopinfo; + /* Associate free loop device with file */ + if (ioctl(lfd, LOOP_SET_FD, ffd)) { + return -1; + } + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); + loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; + /* + * Used by mount to set LO_FLAGS_AUTOCLEAR. + * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. + * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount + * is wrong (would free the loop device!) + */ + loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { + /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ + /* (this code path is not tested) */ + loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; + rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); + } + if (rc == 0) { + return lfd; + } + /* failure, undo LOOP_SET_FD */ + ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return -1; +} + static int set_loop_info(int ffd, int lfd, const char *file, unsigned long long offset, unsigned long long sizelimit, unsigned flags) { @@ -139,33 +174,7 @@ static int set_loop_info(int ffd, int lfd, const char *file, /* If device is free, try to claim it */ if (rc && errno == ENXIO) { - /* Associate free loop device with file */ - if (ioctl(lfd, LOOP_SET_FD, ffd)) { - return -1; - } - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); - loopinfo.lo_offset = offset; - loopinfo.lo_sizelimit = sizelimit; - /* - * Used by mount to set LO_FLAGS_AUTOCLEAR. - * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. - * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount - * is wrong (would free the loop device!) - */ - loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { - /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ - /* (this code path is not tested) */ - loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; - rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); - } - if (rc == 0) { - return lfd; - } - /* failure, undo LOOP_SET_FD */ - ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary + return set_loop_configure(ffd, lfd, file, offset, sizelimit, flags); } return -1; } -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:17 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:17 +0800 Subject: [PATCH v4 7/9] loop:refactor: Extract subfunction do_stat_and_mknod() In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-8-nixiaoming@huawei.com> Step 7 of micro-refactoring the set_loop(): Extract subfunction do_stat_and_mknod() function old new delta set_loop 720 700 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes Signed-off-by: Xiaoming Ni --- libbb/loop.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/libbb/loop.c b/libbb/loop.c index 5f0db4b18..ec4fcf883 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -183,6 +183,27 @@ static void init_bb_loop_info(bb_loop_info *loopinfo, const char *file, loopinfo->lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); } +static int do_stat_and_mknod(const char *dev, const char *device, int i) +{ + struct stat statbuf; + + IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) + if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) + return 0; + if (ENABLE_FEATURE_MOUNT_LOOP_CREATE + && errno == ENOENT + && (!device) + ) { + /* Node doesn't exist, try to create it */ + if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) { + return 0; + } + } + /* Ran out of block devices, return failure */ + return -1; +} + + /* Returns opened fd to the loop device, <0 on error. * *device is loop device to use, or if *device==NULL finds a loop device to * mount it on and sets *device to a strdup of that loop device name. @@ -192,7 +213,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse { char dev[LOOP_NAMESIZE]; char *try; - struct stat statbuf; int i, lfd, ffd, mode, rc; bb_loop_info loopinfo; @@ -219,18 +239,8 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } } - IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) - if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { - if (ENABLE_FEATURE_MOUNT_LOOP_CREATE - && errno == ENOENT - && (!*device) - ) { - /* Node doesn't exist, try to create it */ - if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) - goto open_lfd; - } - /* Ran out of block devices, return failure */ - rc = -1; + rc = do_stat_and_mknod(try, *device, i); + if (rc == -1) { break; } open_lfd: @@ -252,7 +262,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse if (rc == lfd) { /* SUCCESS! */ if (!*device) - *device = xstrdup(dev); + *device = xstrdup(try); break; } close(lfd); -- 2.27.0 From nixiaoming at huawei.com Mon Nov 21 13:58:19 2022 From: nixiaoming at huawei.com (Xiaoming Ni) Date: Mon, 21 Nov 2022 21:58:19 +0800 Subject: [PATCH v4 9/9] loop: Add LOOP_CONFIGURE ioctl In-Reply-To: <20221121135819.413-1-nixiaoming@huawei.com> References: <20221121135819.413-1-nixiaoming@huawei.com> Message-ID: <20221121135819.413-10-nixiaoming@huawei.com> LOOP_CONFIGURE is added to Linux 5.8 This allows userspace to completely setup a loop device with a single ioctl, removing the in-between state where the device can be partially configured - eg the loop device has a backing file associated with it, but is reading from the wrong offset. https://lwn.net/Articles/820408/ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 Builders can use config to choose which algorithm to build into their busybox binary kernel version >= 5.8, choice CONFIG_LOOP_CONFIGURE function old new delta set_loop 716 639 -77 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-77) Total: -77 bytes kernel version < 5.8, choice CONFIG_NO_LOOP_CONFIGURE function old new delta ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0) Total: 0 bytes kernel version is unknown, choice CONFIG_TRY_LOOP_CONFIGURE function old new delta set_loop 716 832 +116 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 116/0) Total: 116 bytes Signed-off-by: Xiaoming Ni --- libbb/Config.src | 22 ++++++++++++++++++++++ libbb/loop.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/libbb/Config.src b/libbb/Config.src index 66a3ffa23..b7f9ddab4 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN For example, this means that entering 'l', 's', ' ', 0xff, [Enter] at shell prompt will list file named 0xff (single char name with char value 255), not file named '?'. + +choice + prompt "LOOP_CONFIGURE or LOOP_SET_FD + LOOP_SET_STATUS" + default TRY_LOOP_CONFIGURE + help + LOOP_CONFIGURE is added to Linux 5.8 + https://lwn.net/Articles/820408/ + This allows userspace to completely setup a loop device with a single + ioctl, removing the in-between state where the device can be partially + configured - eg the loop device has a backing file associated with it, + but is reading from the wrong offset. + +config LOOP_CONFIGURE + bool "always uses LOOP_CONFIGURE, kernel version >= 5.8" + +config NO_LOOP_CONFIGURE + bool "never uses LOOP_CONFIGURE, kernel version < 5.8" + +config TRY_LOOP_CONFIGURE + bool "try LOOP_CONFIGURE, kernel version is unknown" + +endchoice diff --git a/libbb/loop.c b/libbb/loop.c index 03b73e658..9316c6b44 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -129,6 +129,7 @@ static int open_file(const char *file, unsigned flags, int *mode) return ffd; } +#ifndef CONFIG_LOOP_CONFIGURE static int set_loop_fd_and_status(int ffd, int lfd, const bb_loop_info *loopinfo) { int rc; @@ -152,6 +153,46 @@ static int set_loop_fd_and_status(int ffd, int lfd, const bb_loop_info *loopinfo ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary return -1; } +#endif + +#ifndef CONFIG_NO_LOOP_CONFIGURE + +#ifndef LOOP_CONFIGURE +#define LOOP_CONFIGURE 0x4C0A +struct loop_config { + uint32_t fd; + uint32_t block_size; + struct loop_info64 info; + uint64_t __reserved[8]; +}; +#endif + +/* + * linux v5.8.0 + * loop: Add LOOP_CONFIGURE ioctl + * https://lwn.net/Articles/820408/ + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3448914e8cc5 + */ +static int set_loop_configure(int ffd, int lfd, const bb_loop_info *loopinfo) +{ + int rc; + struct loop_config config; + + memset(&config, 0, sizeof(config)); + config.fd = ffd; + memcpy(&config.info, loopinfo, sizeof(config.info)); + + rc = ioctl(lfd, LOOP_CONFIGURE, &config); + if (rc == 0) { + return lfd; + } +#ifdef CONFIG_TRY_LOOP_CONFIGURE + if (rc == -1 && errno == EINVAL) /* The system may not support LOOP_CONFIGURE. */ + return set_loop_fd_and_status(ffd, lfd, loopinfo); +#endif + return -1; +} +#endif static int set_loop_info(int ffd, int lfd, const bb_loop_info *loopinfo) { @@ -162,7 +203,11 @@ static int set_loop_info(int ffd, int lfd, const bb_loop_info *loopinfo) /* If device is free, try to claim it */ if (rc && errno == ENXIO) { +#ifdef CONFIG_NO_LOOP_CONFIGURE return set_loop_fd_and_status(ffd, lfd, loopinfo); +#else + return set_loop_configure(ffd, lfd, loopinfo); +#endif } return -1; } -- 2.27.0 From boubaker.bassem.1991 at gmail.com Mon Nov 21 13:50:42 2022 From: boubaker.bassem.1991 at gmail.com (bboubaker) Date: Mon, 21 Nov 2022 14:50:42 +0100 Subject: [PATCH] getty: prevent getty from changing tty lines protections and ownership Message-ID: <20221121135042.3336052-1-bboubaker@sierrawireless.com> There are dedicated linux sub-systems such as udev/mdev to handle tty lines ownership and permissions getty should be only capable of using it and not do an override. Signed-off-by: bboubaker --- loginutils/getty.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index cd6378d80..af580dd61 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -219,10 +219,6 @@ static void open_tty(void) debug("open(2)\n"); close(0); xopen(G.tty_name, O_RDWR | O_NONBLOCK); /* uses fd 0 */ - - /* Set proper protections and ownership */ - fchown(0, 0, 0); /* 0:0 */ - fchmod(0, 0620); /* crw--w---- */ } else { char *n; /* -- 2.25.1 From troglobit at gmail.com Wed Nov 23 12:38:46 2022 From: troglobit at gmail.com (Joachim Wiberg) Date: Wed, 23 Nov 2022 13:38:46 +0100 Subject: [PATCH 1/1] logger: add '-i' flag for optional PID to syslog messages Message-ID: <20221123123846.4121655-1-troglobit@gmail.com> The -i flag in the util-linux, and upstream sysklogd, projects add PID to syslog messages, using the LOG_PID flag. Signed-off-by: Joachim Wiberg --- sysklogd/logger.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sysklogd/logger.c b/sysklogd/logger.c index 04b2c8e3b..8424ae206 100644 --- a/sysklogd/logger.c +++ b/sysklogd/logger.c @@ -21,9 +21,10 @@ //kbuild:lib-$(CONFIG_LOGGER) += syslogd_and_logger.o //usage:#define logger_trivial_usage -//usage: "[-s] [-t TAG] [-p PRIO] [MESSAGE]" +//usage: "[-i] [-s] [-t TAG] [-p PRIO] [MESSAGE]" //usage:#define logger_full_usage "\n\n" //usage: "Write MESSAGE (or stdin) to syslog\n" +//usage: "\n -i Log PID of logger to system log" //usage: "\n -s Log to stderr as well as the system log" //usage: "\n -t TAG Log using the specified tag (defaults to user name)" //usage: "\n -p PRIO Priority (number or FACILITY.LEVEL pair)" @@ -105,10 +106,12 @@ int logger_main(int argc UNUSED_PARAM, char **argv) str_t = uid2uname_utoa(geteuid()); /* Parse any options */ - opt = getopt32(argv, "p:st:", &str_p, &str_t); + opt = getopt32(argv, "p:st:i", &str_p, &str_t); if (opt & 0x2) /* -s */ i |= LOG_PERROR; + if (opt & 0x8) /* -i */ + i |= LOG_PID; //if (opt & 0x4) /* -t */ openlog(str_t, i, 0); i = LOG_USER | LOG_NOTICE; -- 2.34.1 From harald at gigawatt.nl Wed Nov 23 23:25:09 2022 From: harald at gigawatt.nl (Harald van Dijk) Date: Wed, 23 Nov 2022 23:25:09 +0000 Subject: busybox ash segfault on invalid substitutions Message-ID: <9be97a87-ad69-9ca7-f48b-9178e8ae2617@gigawatt.nl> Hi, Over on the dash mailing list, Christoph Anton Mitterer reported a segfault in dash when dealing with invalid substitutions: busybox ash being based on dash, despite the segmentation fault not triggering there with the original script, it can be triggered in busybox ash with a different script as well. I am reporting this here as requested in that thread. The below is with a build with 'make defconfig', except CONFIG_DEBUG=y and CONFIG_DEBUG_PESSIMIZE=y. $ gdb --args ./busybox_unstripped sh -c 'f() { echo ${PWD-${PWD!}}; }; f' GNU gdb (GDB) 12.1 Copyright (C) 2022 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./busybox_unstripped... (gdb) run Starting program: /home/harald/busybox/busybox_unstripped sh -c f\(\)\ \{\ echo\ \$\{PWD-\$\{PWD\!\}\}\;\ \}\;\ f [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Program received signal SIGSEGV, Segmentation fault. 0x00348eab in argstr (p=0x1 , flag=1089) at shell/ash.c:6819 6819 if (*p == '~') (gdb) This happens because invalid substitutions (${PWD!}) are encoded using a null byte, but function definitions treat node text as C-style strings terminated by the first null byte, so we end up accessing the duplicated node text past the end of the buffer: (gdb) b shell/ash.c:9148 Breakpoint 1 at 0x34ca03: file shell/ash.c, line 9148. (gdb) run Starting program: /home/harald/busybox/busybox_unstripped sh -c f\(\)\ \{\ echo\ \$\{PWD-\$\{PWD\!\}\}\;\ \}\;\ f [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, copynode (n=0x3923ec) at shell/ash.c:9148 9148 new->narg.text = nodeckstrdup(n->narg.text); (gdb) cont Continuing. Breakpoint 1, copynode (n=0x39240c) at shell/ash.c:9148 9148 new->narg.text = nodeckstrdup(n->narg.text); (gdb) p n->narg.text $1 = 0x3923fc "\202\002PWD=\202" (gdb) step nodeckstrdup (s=0xffffd1c8 "") at shell/ash.c:9059 9059 { (gdb) next 9060 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); (gdb) 9061 return strcpy(funcstring_end, s); (gdb) 9062 } Here, \202 is CTLVAR. We can see that n->narg.text ends in CTLVAR followed by a null byte, and it is copied using strlen() and strcpy(), so any bytes after that null byte will be left out. There are two possible ways of fixing this, depending on the intended behaviour. Nothing has yet been said on the list to definitively know what the dash intended behaviour here is, but regardless, busybox may choose to act now. 1: If the intended behaviour is to raise an error: --- a/shell/ash.c +++ b/shell/ash.c @@ -7465,9 +7465,6 @@ varvalue(char *name, int varflags, int flags, int quoted) int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD); if (!subtype) { - if (discard) - return -1; - ifsfree(); raise_error_syntax("bad substitution"); } This preserves the copynode() behaviour of cutting off the word, but it is okay as now a null byte is guaranteed to terminate the expansion. 2: If the intended behaviour is to ignore the invalid substitution as long as it is skipped: --- a/shell/ash.c +++ b/shell/ash.c @@ -12981,6 +12981,8 @@ parsesub: { synstack->dblquote = newsyn != BASESYNTAX; } + if (subtype == 0) + subtype = VSNUL; ((unsigned char *)stackblock())[typeloc] = subtype; if (subtype != VSNORMAL) { synstack->varnest++; This encodes invalid substitutions using VSNUL, which when masked with VSTYPE will result in 0 like before, but does not result in all bits zero, so does not terminate the string. I know my mail client will have mangled the formatting. Apologies for that. I am not expecting either of these patches to be applied as is anyway, at this point I am more interested in getting the busybox views on whether either fix is wanted now already (before dash acts), and if so, which one. Especially the second one will likely have opportunities to clean up and reduce code size by making sure subtype is already set to VSNUL at this point, rather than 0, meaning it does not need to be patched up here. Cheers, Harald van Dijk From vda.linux at googlemail.com Tue Nov 29 13:10:45 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Tue, 29 Nov 2022 14:10:45 +0100 Subject: [PATCH] Fix non-Linux builds In-Reply-To: <20221016000459.5itbhtqlkkozgdnp@begin> References: <20221016000459.5itbhtqlkkozgdnp@begin> Message-ID: applied, thank you. On Sun, Oct 16, 2022 at 2:05 AM Samuel Thibault wrote: > > Various tools are Linuxish and should thus only attempted to build on > Linux only. Some features are also Linux-only. > > Also, libresolv is used on all GNU platforms, notably GNU/Hurd and > GNU/kfreeBSD. > > diff --git a/Makefile.flags b/Makefile.flags > index 84cb00a75..50137a78e 100644 > --- a/Makefile.flags > +++ b/Makefile.flags > @@ -184,7 +184,7 @@ LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=% > endif > > ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y) > -ifneq (,$(findstring linux,$(shell $(CC) $(CFLAGS) -dumpmachine))) > +ifneq (,$(findstring gnu,$(shell $(CC) $(CFLAGS) -dumpmachine))) > LDLIBS += resolv > endif > endif > diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c > index 81a0e6aa8..3f36cabe0 100644 > --- a/console-tools/loadfont.c > +++ b/console-tools/loadfont.c > @@ -12,6 +12,7 @@ > //config:config LOADFONT > //config: bool "loadfont (5.2 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: This program loads a console font from standard input. > //config: > diff --git a/console-tools/openvt.c b/console-tools/openvt.c > index db2f073b2..9e6cffecc 100644 > --- a/console-tools/openvt.c > +++ b/console-tools/openvt.c > @@ -10,6 +10,7 @@ > //config:config OPENVT > //config: bool "openvt (7.2 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: This program is used to start a command on an unused > //config: virtual terminal. > diff --git a/coreutils/dd.c b/coreutils/dd.c > index 06c1b7b9c..3e034eb1e 100644 > --- a/coreutils/dd.c > +++ b/coreutils/dd.c > @@ -200,6 +200,7 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) > } > > #if ENABLE_FEATURE_DD_IBS_OBS > +# ifdef O_DIRECT > static int clear_O_DIRECT(int fd) > { > if (errno == EINVAL) { > @@ -211,6 +212,7 @@ static int clear_O_DIRECT(int fd) > } > return 0; > } > +# endif > #endif > > static ssize_t dd_read(void *ibuf, size_t ibs) > @@ -225,8 +227,10 @@ static ssize_t dd_read(void *ibuf, size_t ibs) > #endif > n = safe_read(ifd, ibuf, ibs); > #if ENABLE_FEATURE_DD_IBS_OBS > +# ifdef O_DIRECT > if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd)) > goto read_again; > +# endif > #endif > return n; > } > @@ -239,8 +243,10 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs, > IF_FEATURE_DD_IBS_OBS(write_again:) > n = full_write(ofd, buf, len); > #if ENABLE_FEATURE_DD_IBS_OBS > +# ifdef O_DIRECT > if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd)) > goto write_again; > +# endif > #endif > > #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE > @@ -501,8 +507,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) > if (infile) { > int iflag = O_RDONLY; > #if ENABLE_FEATURE_DD_IBS_OBS > - if (G.flags & FLAG_IDIRECT) > + if (G.flags & FLAG_IDIRECT) { > +# ifdef O_DIRECT > iflag |= O_DIRECT; > +# else > + bb_error_msg_and_die("O_DIRECT not supported on this platform"); > +# endif > + } > #endif > xmove_fd(xopen(infile, iflag), ifd); > } else { > @@ -516,8 +527,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) > if (G.flags & FLAG_APPEND) > oflag |= O_APPEND; > #if ENABLE_FEATURE_DD_IBS_OBS > - if (G.flags & FLAG_ODIRECT) > + if (G.flags & FLAG_ODIRECT) { > +# ifdef O_DIRECT > oflag |= O_DIRECT; > +# else > + bb_error_msg_and_die("O_DIRECT not supported on this platform"); > +# endif > + } > #endif > xmove_fd(xopen(outfile, oflag), ofd); > > diff --git a/klibc-utils/run-init.c b/klibc-utils/run-init.c > index 73c677bab..77fc0e60c 100644 > --- a/klibc-utils/run-init.c > +++ b/klibc-utils/run-init.c > @@ -8,6 +8,7 @@ > //config:config RUN_INIT > //config: bool "run-init (7.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The run-init utility is used from initramfs to select a new > //config: root device. Under initramfs, you have to use this instead of > diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c > index 209d1d560..c289245c0 100644 > --- a/miscutils/adjtimex.c > +++ b/miscutils/adjtimex.c > @@ -13,6 +13,7 @@ > //config:config ADJTIMEX > //config: bool "adjtimex (4.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Adjtimex reads and optionally sets adjustment parameters for > //config: the Linux clock adjustment algorithm. > diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c > index da26f5e19..46749fb9c 100644 > --- a/miscutils/i2c_tools.c > +++ b/miscutils/i2c_tools.c > @@ -11,30 +11,35 @@ > //config:config I2CGET > //config: bool "i2cget (5.5 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Read from I2C/SMBus chip registers. > //config: > //config:config I2CSET > //config: bool "i2cset (6.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Set I2C registers. > //config: > //config:config I2CDUMP > //config: bool "i2cdump (7.1 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Examine I2C registers. > //config: > //config:config I2CDETECT > //config: bool "i2cdetect (7.1 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Detect I2C chips. > //config: > //config:config I2CTRANSFER > //config: bool "i2ctransfer (4.0 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Send user-defined I2C messages in one transfer. > //config: > diff --git a/miscutils/partprobe.c b/miscutils/partprobe.c > index 0fb1927b7..0abed6ff1 100644 > --- a/miscutils/partprobe.c > +++ b/miscutils/partprobe.c > @@ -7,6 +7,7 @@ > //config:config PARTPROBE > //config: bool "partprobe (3.5 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Ask kernel to rescan partition table. > > diff --git a/miscutils/ubirename.c b/miscutils/ubirename.c > index 06a0adacf..e7c56640c 100644 > --- a/miscutils/ubirename.c > +++ b/miscutils/ubirename.c > @@ -9,6 +9,7 @@ > //config:config UBIRENAME > //config: bool "ubirename (2.4 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Utility to rename UBI volumes > > diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c > index 9f5a4b849..91a20239d 100644 > --- a/miscutils/watchdog.c > +++ b/miscutils/watchdog.c > @@ -11,6 +11,7 @@ > //config:config WATCHDOG > //config: bool "watchdog (5.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The watchdog utility is used with hardware or software watchdog > //config: device drivers. It opens the specified watchdog device special file > diff --git a/modutils/Config.src b/modutils/Config.src > index 188296814..b8ba3b7b6 100644 > --- a/modutils/Config.src > +++ b/modutils/Config.src > @@ -8,6 +8,7 @@ menu "Linux Module Utilities" > config MODPROBE_SMALL > bool "Simplified modutils" > default y > + select PLATFORM_LINUX > help > Build smaller (~1.5 kbytes), simplified module tools. > > diff --git a/modutils/depmod.c b/modutils/depmod.c > index bb42bbefe..9e39481c5 100644 > --- a/modutils/depmod.c > +++ b/modutils/depmod.c > @@ -10,6 +10,7 @@ > //config:config DEPMOD > //config: bool "depmod (27 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: depmod generates modules.dep (and potentially modules.alias > //config: and modules.symbols) that contain dependency information > diff --git a/modutils/insmod.c b/modutils/insmod.c > index 8f7163e25..85b46cdd6 100644 > --- a/modutils/insmod.c > +++ b/modutils/insmod.c > @@ -9,6 +9,7 @@ > //config:config INSMOD > //config: bool "insmod (22 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: insmod is used to load specified modules in the running kernel. > > diff --git a/modutils/lsmod.c b/modutils/lsmod.c > index 2beb12362..39dc8e6b7 100644 > --- a/modutils/lsmod.c > +++ b/modutils/lsmod.c > @@ -10,6 +10,7 @@ > //config:config LSMOD > //config: bool "lsmod (1.9 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: lsmod is used to display a list of loaded modules. > //config: > diff --git a/modutils/modinfo.c b/modutils/modinfo.c > index 0a86c3296..5d01179a0 100644 > --- a/modutils/modinfo.c > +++ b/modutils/modinfo.c > @@ -8,6 +8,7 @@ > //config:config MODINFO > //config: bool "modinfo (24 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Show information about a Linux Kernel module > > diff --git a/modutils/modprobe.c b/modutils/modprobe.c > index 235706fd5..77c4bb74d 100644 > --- a/modutils/modprobe.c > +++ b/modutils/modprobe.c > @@ -10,6 +10,7 @@ > //config:config MODPROBE > //config: bool "modprobe (28 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Handle the loading of modules, and their dependencies on a high > //config: level. > diff --git a/modutils/rmmod.c b/modutils/rmmod.c > index 2b3c39153..8d4639f50 100644 > --- a/modutils/rmmod.c > +++ b/modutils/rmmod.c > @@ -10,6 +10,7 @@ > //config:config RMMOD > //config: bool "rmmod (3.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: rmmod is used to unload specified modules from the kernel. > > diff --git a/networking/arp.c b/networking/arp.c > index 16783ab95..6519f8156 100644 > --- a/networking/arp.c > +++ b/networking/arp.c > @@ -15,6 +15,7 @@ > //config:config ARP > //config: bool "arp (10 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Manipulate the system ARP cache. > > diff --git a/networking/arping.c b/networking/arping.c > index 86f0221ed..fd0e1b276 100644 > --- a/networking/arping.c > +++ b/networking/arping.c > @@ -8,6 +8,7 @@ > //config:config ARPING > //config: bool "arping (9 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Ping hosts by ARP packets. > > diff --git a/networking/brctl.c b/networking/brctl.c > index 956bd91f3..b353210d7 100644 > --- a/networking/brctl.c > +++ b/networking/brctl.c > @@ -12,6 +12,7 @@ > //config:config BRCTL > //config: bool "brctl (4.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Manage ethernet bridges. > //config: Supports addbr/delbr and addif/delif. > diff --git a/networking/ifconfig.c b/networking/ifconfig.c > index 9ee232a66..4090959b8 100644 > --- a/networking/ifconfig.c > +++ b/networking/ifconfig.c > @@ -27,6 +27,7 @@ > //config:config IFCONFIG > //config: bool "ifconfig (12 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Ifconfig is used to configure the kernel-resident network interfaces. > //config: > diff --git a/networking/ifplugd.c b/networking/ifplugd.c > index 0b55bf4e5..bc4303ef0 100644 > --- a/networking/ifplugd.c > +++ b/networking/ifplugd.c > @@ -9,6 +9,7 @@ > //config:config IFPLUGD > //config: bool "ifplugd (10 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Network interface plug detection daemon. > > diff --git a/networking/ip.c b/networking/ip.c > index 7c3208699..23ee7d24b 100644 > --- a/networking/ip.c > +++ b/networking/ip.c > @@ -11,6 +11,7 @@ > //config:config IP > //config: bool "ip (35 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The "ip" applet is a TCP/IP interface configuration and routing > //config: utility. > @@ -21,6 +22,7 @@ > //config:config IPADDR > //config: bool "ipaddr (14 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select FEATURE_IP_ADDRESS > //config: help > //config: Short form of "ip addr" > @@ -28,6 +30,7 @@ > //config:config IPLINK > //config: bool "iplink (17 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select FEATURE_IP_LINK > //config: help > //config: Short form of "ip link" > @@ -35,6 +38,7 @@ > //config:config IPROUTE > //config: bool "iproute (15 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select FEATURE_IP_ROUTE > //config: help > //config: Short form of "ip route" > @@ -49,6 +53,7 @@ > //config:config IPRULE > //config: bool "iprule (10 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select FEATURE_IP_RULE > //config: help > //config: Short form of "ip rule" > @@ -56,6 +61,7 @@ > //config:config IPNEIGH > //config: bool "ipneigh (8.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select FEATURE_IP_NEIGH > //config: help > //config: Short form of "ip neigh" > diff --git a/networking/nameif.c b/networking/nameif.c > index 66e042688..3ccd935b8 100644 > --- a/networking/nameif.c > +++ b/networking/nameif.c > @@ -12,6 +12,7 @@ > //config:config NAMEIF > //config: bool "nameif (6.6 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select FEATURE_SYSLOG > //config: help > //config: nameif is used to rename network interface by its MAC address. > diff --git a/networking/route.c b/networking/route.c > index 26146f8e9..616572814 100644 > --- a/networking/route.c > +++ b/networking/route.c > @@ -27,6 +27,7 @@ > //config:config ROUTE > //config: bool "route (8.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Route displays or manipulates the kernel's IP routing tables. > > diff --git a/networking/tc.c b/networking/tc.c > index 43187f7ee..1f4bcce2b 100644 > --- a/networking/tc.c > +++ b/networking/tc.c > @@ -9,6 +9,7 @@ > //config:config TC > //config: bool "tc (8.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Show / manipulate traffic control settings > //config: > diff --git a/networking/traceroute.c b/networking/traceroute.c > index 4bbe1ab8e..2ba990fd0 100644 > --- a/networking/traceroute.c > +++ b/networking/traceroute.c > @@ -963,8 +963,10 @@ traceroute_init(int op, char **argv) > if (af == AF_INET) { > xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); > #if ENABLE_FEATURE_TRACEROUTE_VERBOSE > +# ifdef IP_PKTINFO > /* want recvmsg to report target local address (for -v) */ > setsockopt_1(rcvsock, IPPROTO_IP, IP_PKTINFO); > +# endif > #endif > } > #if ENABLE_TRACEROUTE6 > diff --git a/networking/tunctl.c b/networking/tunctl.c > index 97e6917aa..59cae331c 100644 > --- a/networking/tunctl.c > +++ b/networking/tunctl.c > @@ -12,6 +12,7 @@ > //config:config TUNCTL > //config: bool "tunctl (6.2 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: tunctl creates or deletes tun devices. > //config: > diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src > index 8c8c11c26..23e2b40d8 100644 > --- a/networking/udhcp/Config.src > +++ b/networking/udhcp/Config.src > @@ -6,6 +6,7 @@ > config UDHCPD > bool "udhcpd (21 kb)" > default y > + select PLATFORM_LINUX > help > udhcpd is a DHCP server geared primarily toward embedded systems, > while striving to be fully functional and RFC compliant. > @@ -53,6 +54,7 @@ config DUMPLEASES > config DHCPRELAY > bool "dhcprelay (5.2 kb)" > default y > + select PLATFORM_LINUX > help > dhcprelay listens for DHCP requests on one or more interfaces > and forwards these requests to a different interface or DHCP > @@ -61,6 +63,7 @@ config DHCPRELAY > config UDHCPC > bool "udhcpc (24 kb)" > default y > + select PLATFORM_LINUX > help > udhcpc is a DHCP client geared primarily toward embedded systems, > while striving to be fully functional and RFC compliant. > diff --git a/procps/free.c b/procps/free.c > index 0b68e1b88..c734f757d 100644 > --- a/procps/free.c > +++ b/procps/free.c > @@ -9,6 +9,7 @@ > //config:config FREE > //config: bool "free (3.1 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: free displays the total amount of free and used physical and swap > //config: memory in the system, as well as the buffers used by the kernel. > diff --git a/procps/uptime.c b/procps/uptime.c > index 4fd0c9d2d..4992c263e 100644 > --- a/procps/uptime.c > +++ b/procps/uptime.c > @@ -14,6 +14,7 @@ > //config:config UPTIME > //config: bool "uptime (3.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: uptime gives a one line display of the current time, how long > //config: the system has been running, how many users are currently logged > diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c > index df0edee0a..ddf50071d 100644 > --- a/sysklogd/klogd.c > +++ b/sysklogd/klogd.c > @@ -19,6 +19,7 @@ > //config:config KLOGD > //config: bool "klogd (5.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: klogd is a utility which intercepts and logs all > //config: messages from the Linux kernel and sends the messages > diff --git a/util-linux/acpid.c b/util-linux/acpid.c > index 00613f8e3..7bce8abea 100644 > --- a/util-linux/acpid.c > +++ b/util-linux/acpid.c > @@ -9,6 +9,7 @@ > //config:config ACPID > //config: bool "acpid (9 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: acpid listens to ACPI events coming either in textual form from > //config: /proc/acpi/event (though it is marked deprecated it is still widely > diff --git a/util-linux/blkdiscard.c b/util-linux/blkdiscard.c > index 7ac8045f9..2291eec21 100644 > --- a/util-linux/blkdiscard.c > +++ b/util-linux/blkdiscard.c > @@ -8,6 +8,7 @@ > //config:config BLKDISCARD > //config: bool "blkdiscard (4.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: blkdiscard discards sectors on a given device. > > diff --git a/util-linux/blkid.c b/util-linux/blkid.c > index 4a820771f..008ae5d9e 100644 > --- a/util-linux/blkid.c > +++ b/util-linux/blkid.c > @@ -9,6 +9,7 @@ > //config:config BLKID > //config: bool "blkid (12 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select VOLUMEID > //config: help > //config: Lists labels and UUIDs of all filesystems. > diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c > index 6670b84de..5da887f0e 100644 > --- a/util-linux/dmesg.c > +++ b/util-linux/dmesg.c > @@ -11,6 +11,7 @@ > //config:config DMESG > //config: bool "dmesg (3.7 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: dmesg is used to examine or control the kernel ring buffer. When the > //config: Linux kernel prints messages to the system log, they are stored in > diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c > index 20e7d56fa..e9ebbd5d4 100644 > --- a/util-linux/fdisk.c > +++ b/util-linux/fdisk.c > @@ -10,6 +10,7 @@ > //config:config FDISK > //config: bool "fdisk (37 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The fdisk utility is used to divide hard disks into one or more > //config: logical disks, which are generally called partitions. This utility > diff --git a/util-linux/findfs.c b/util-linux/findfs.c > index f5621a1fa..7ca9dc96b 100644 > --- a/util-linux/findfs.c > +++ b/util-linux/findfs.c > @@ -10,6 +10,7 @@ > //config:config FINDFS > //config: bool "findfs (12 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select VOLUMEID > //config: help > //config: Prints the name of a filesystem with given label or UUID. > diff --git a/util-linux/freeramdisk.c b/util-linux/freeramdisk.c > index 309169d25..d27113d97 100644 > --- a/util-linux/freeramdisk.c > +++ b/util-linux/freeramdisk.c > @@ -11,6 +11,7 @@ > //config:config FDFLUSH > //config: bool "fdflush (1.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: fdflush is only needed when changing media on slightly-broken > //config: removable media drives. It is used to make Linux believe that a > @@ -23,6 +24,7 @@ > //config:config FREERAMDISK > //config: bool "freeramdisk (1.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Linux allows you to create ramdisks. This utility allows you to > //config: delete them and completely free all memory that was used for the > diff --git a/util-linux/fsfreeze.c b/util-linux/fsfreeze.c > index 6e2ff0a54..fb0b3c4bd 100644 > --- a/util-linux/fsfreeze.c > +++ b/util-linux/fsfreeze.c > @@ -7,6 +7,7 @@ > //config:config FSFREEZE > //config: bool "fsfreeze (3.5 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select LONG_OPTS > //config: help > //config: Halt new accesses and flush writes on a mounted filesystem. > diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c > index 6d673002f..12bab40d1 100644 > --- a/util-linux/fstrim.c > +++ b/util-linux/fstrim.c > @@ -10,6 +10,7 @@ > //config:config FSTRIM > //config: bool "fstrim (4.4 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Discard unused blocks on a mounted filesystem. > > diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c > index 723b09589..2edadfa4d 100644 > --- a/util-linux/hwclock.c > +++ b/util-linux/hwclock.c > @@ -9,6 +9,7 @@ > //config:config HWCLOCK > //config: bool "hwclock (5.8 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The hwclock utility is used to read and set the hardware clock > //config: on a system. This is primarily used to set the current time on > diff --git a/util-linux/ionice.c b/util-linux/ionice.c > index 82bd309d1..b30d5f78d 100644 > --- a/util-linux/ionice.c > +++ b/util-linux/ionice.c > @@ -9,6 +9,7 @@ > //config:config IONICE > //config: bool "ionice (3.8 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Set/set program io scheduling class and priority > //config: Requires kernel >= 2.6.13 > diff --git a/util-linux/losetup.c b/util-linux/losetup.c > index 24f7a2349..ec0cf04e4 100644 > --- a/util-linux/losetup.c > +++ b/util-linux/losetup.c > @@ -9,6 +9,7 @@ > //config:config LOSETUP > //config: bool "losetup (5.5 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: losetup is used to associate or detach a loop device with a regular > //config: file or block device, and to query the status of a loop device. This > diff --git a/util-linux/mdev.c b/util-linux/mdev.c > index ebdc0c254..f6de7ad2a 100644 > --- a/util-linux/mdev.c > +++ b/util-linux/mdev.c > @@ -10,6 +10,7 @@ > //config:config MDEV > //config: bool "mdev (17 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: mdev is a mini-udev implementation for dynamically creating device > //config: nodes in the /dev directory. > diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c > index fcf374b2d..892b0867a 100644 > --- a/util-linux/mkfs_ext2.c > +++ b/util-linux/mkfs_ext2.c > @@ -10,6 +10,7 @@ > //config:config MKE2FS > //config: bool "mke2fs (10 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Utility to create EXT2 filesystems. > //config: > diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c > index 821371953..5136446eb 100644 > --- a/util-linux/mkfs_vfat.c > +++ b/util-linux/mkfs_vfat.c > @@ -10,6 +10,7 @@ > //config:config MKDOSFS > //config: bool "mkdosfs (7.2 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Utility to create FAT32 filesystems. > //config: > diff --git a/util-linux/mount.c b/util-linux/mount.c > index 4e65b6b46..e3aeda666 100644 > --- a/util-linux/mount.c > +++ b/util-linux/mount.c > @@ -20,6 +20,7 @@ > //config:config MOUNT > //config: bool "mount (23 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: All files and filesystems in Unix are arranged into one big directory > //config: tree. The 'mount' utility is used to graft a filesystem onto a > diff --git a/util-linux/nsenter.c b/util-linux/nsenter.c > index 1aa045b35..8652e803a 100644 > --- a/util-linux/nsenter.c > +++ b/util-linux/nsenter.c > @@ -9,6 +9,7 @@ > //config:config NSENTER > //config: bool "nsenter (6.5 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Run program with namespaces of other processes. > > diff --git a/util-linux/pivot_root.c b/util-linux/pivot_root.c > index ecc891100..41f29da32 100644 > --- a/util-linux/pivot_root.c > +++ b/util-linux/pivot_root.c > @@ -11,6 +11,7 @@ > //config:config PIVOT_ROOT > //config: bool "pivot_root (1.1 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The pivot_root utility swaps the mount points for the root filesystem > //config: with some other mounted filesystem. This allows you to do all sorts > diff --git a/util-linux/setarch.c b/util-linux/setarch.c > index cf8ef0064..57051a683 100644 > --- a/util-linux/setarch.c > +++ b/util-linux/setarch.c > @@ -9,6 +9,7 @@ > //config:config SETARCH > //config: bool "setarch (3.6 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The linux32 utility is used to create a 32bit environment for the > //config: specified program (usually a shell). It only makes sense to have > @@ -18,12 +19,14 @@ > //config:config LINUX32 > //config: bool "linux32 (3.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Alias to "setarch linux32". > //config: > //config:config LINUX64 > //config: bool "linux64 (3.3 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Alias to "setarch linux64". > > diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c > index 6904cf019..bfe2c7a7a 100644 > --- a/util-linux/setpriv.c > +++ b/util-linux/setpriv.c > @@ -9,6 +9,7 @@ > //config:config SETPRIV > //config: bool "setpriv (6.6 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: select LONG_OPTS > //config: help > //config: Run a program with different Linux privilege settings. > diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c > index e2ff4b5cc..567869cc7 100644 > --- a/util-linux/swaponoff.c > +++ b/util-linux/swaponoff.c > @@ -9,6 +9,7 @@ > //config:config SWAPON > //config: bool "swapon (15 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: Once you have created some swap space using 'mkswap', you also need > //config: to enable your swap space with the 'swapon' utility. The 'swapoff' > @@ -35,6 +36,7 @@ > //config:config SWAPOFF > //config: bool "swapoff (14 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: > //config:config FEATURE_SWAPONOFF_LABEL > //config: bool "Support specifying devices by label or UUID" > diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c > index 901c0b8db..f61002236 100644 > --- a/util-linux/switch_root.c > +++ b/util-linux/switch_root.c > @@ -9,6 +9,7 @@ > //config:config SWITCH_ROOT > //config: bool "switch_root (5.5 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: The switch_root utility is used from initramfs to select a new > //config: root device. Under initramfs, you have to use this instead of > diff --git a/util-linux/uevent.c b/util-linux/uevent.c > index db11746d0..bd39c3acd 100644 > --- a/util-linux/uevent.c > +++ b/util-linux/uevent.c > @@ -6,6 +6,7 @@ > //config:config UEVENT > //config: bool "uevent (3.1 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: help > //config: uevent is a netlink listener for kernel uevent notifications > //config: sent via netlink. It is usually used for dynamic device creation. > diff --git a/util-linux/unshare.c b/util-linux/unshare.c > index 06b938074..156a96d94 100644 > --- a/util-linux/unshare.c > +++ b/util-linux/unshare.c > @@ -9,6 +9,7 @@ > //config:config UNSHARE > //config: bool "unshare (7.2 kb)" > //config: default y > +//config: select PLATFORM_LINUX > //config: depends on !NOMMU > //config: select LONG_OPTS > //config: help > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From vda.linux at googlemail.com Tue Nov 29 13:45:03 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Tue, 29 Nov 2022 14:45:03 +0100 Subject: [PATCH] unzip -l: add missed big-endian conversions date and time In-Reply-To: <1666699008-29866-1-git-send-email-peter.kaestle@nokia.com> References: <1666699008-29866-1-git-send-email-peter.kaestle@nokia.com> Message-ID: Applied, thank you On Tue, Oct 25, 2022 at 1:57 PM Peter Kaestle wrote: > > When calling unzip -l the date and time output was missing big-endian > conversions. > > Signed-off-by: Peter K?stle > --- > archival/unzip.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/archival/unzip.c b/archival/unzip.c > index fc92ac661..b27dd2187 100644 > --- a/archival/unzip.c > +++ b/archival/unzip.c > @@ -118,6 +118,8 @@ typedef union { > #define FIX_ENDIANNESS_ZIP(zip) \ > do { if (BB_BIG_ENDIAN) { \ > (zip).fmt.method = SWAP_LE16((zip).fmt.method ); \ > + (zip).fmt.modtime = SWAP_LE16((zip).fmt.modtime ); \ > + (zip).fmt.moddate = SWAP_LE16((zip).fmt.moddate ); \ > (zip).fmt.crc32 = SWAP_LE32((zip).fmt.crc32 ); \ > (zip).fmt.cmpsize = SWAP_LE32((zip).fmt.cmpsize ); \ > (zip).fmt.ucmpsize = SWAP_LE32((zip).fmt.ucmpsize ); \ > -- > 2.38.0 > From vda.linux at googlemail.com Tue Nov 29 14:03:54 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Tue, 29 Nov 2022 15:03:54 +0100 Subject: busybox init returns fails with error code -1 (0x00007f00) In-Reply-To: References: Message-ID: On Tue, Oct 25, 2022 at 10:56 PM samuel ammonius wrote: > Hello, > > I have a simple ISO filesystem set up with busybox and grub.These are the commands I use in GRUB2 to start the system: > > grub> set root=(cd) > grub> linux /boot/bzImage root=/dev/sda1 > grub> initrd /boot/initrd > grub> boot > > I don't know how to get the full kernel error log, but the final error is "kernel panic: attempted to kill init! error code: 0x00007f00". I tried building a static "Hello, world!" program as the FAQ said, and it worked. What could be causing the error? Error code 0x00007f00 means that init exited with exit code 127 (0x7f). IOW: it did not crash with a signal, it called exit(127). Did it print any error message? From sfammonius at gmail.com Tue Nov 29 20:37:36 2022 From: sfammonius at gmail.com (samuel ammonius) Date: Tue, 29 Nov 2022 17:07:36 -0330 Subject: busybox init returns fails with error code -1 (0x00007f00) In-Reply-To: References: Message-ID: Sorry about not responding. I've been using another address for some time. I don't know anything about initrd. I selected some packages, and added an overlay filesystem where inittab was configured to have my application run on start. Could the error code be from the application rather than busybox itself? On Tue, Nov 29, 2022 at 10:34 AM Denys Vlasenko wrote: > On Tue, Oct 25, 2022 at 10:56 PM samuel ammonius > wrote: > > Hello, > > > > I have a simple ISO filesystem set up with busybox and grub.These are > the commands I use in GRUB2 to start the system: > > > > grub> set root=(cd) > > grub> linux /boot/bzImage root=/dev/sda1 > > grub> initrd /boot/initrd > > grub> boot > > > > I don't know how to get the full kernel error log, but the final error > is "kernel panic: attempted to kill init! error code: 0x00007f00". I tried > building a static "Hello, world!" program as the FAQ said, and it worked. > What could be causing the error? > > Error code 0x00007f00 means that init exited with exit code 127 (0x7f). > IOW: it did not crash with a signal, it called exit(127). > Did it print any error message? > -------------- next part -------------- An HTML attachment was scrubbed... URL: