From dario.binacchi at amarulasolutions.com Sat Aug 5 09:36:48 2023 From: dario.binacchi at amarulasolutions.com (Dario Binacchi) Date: Sat, 5 Aug 2023 11:36:48 +0200 Subject: [RESEND PATCH] ip link: support for the CAN netlink Message-ID: <20230805093648.3988937-1-dario.binacchi@amarulasolutions.com> I developed this application to test the Linux kernel series [1]. As described in the cover letter I could not use the iproute2 package since the microcontroller is without MMU. cc: Marc Kleine-Budde [1] https://marc.info/?l=linux-netdev&m=167999323611710&w=2 Signed-off-by: Dario Binacchi --- configs/TEST_nommu_defconfig | 1 + networking/ip.c | 84 ++++++++++ networking/libiproute/iplink.c | 298 ++++++++++++++++++++++++++++++++- 3 files changed, 374 insertions(+), 9 deletions(-) diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig index 415f5a8027f9..fa3e9632622a 100644 --- a/configs/TEST_nommu_defconfig +++ b/configs/TEST_nommu_defconfig @@ -703,6 +703,7 @@ CONFIG_FEATURE_INETD_RPC=y CONFIG_IP=y CONFIG_FEATURE_IP_ADDRESS=y CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_LINK_CAN=y CONFIG_FEATURE_IP_ROUTE=y CONFIG_FEATURE_IP_TUNNEL=y CONFIG_FEATURE_IP_RULE=y diff --git a/networking/ip.c b/networking/ip.c index 36126b74738c..e5b704df5b85 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -32,6 +32,14 @@ //config: help //config: Short form of "ip link" //config: +//config:config IPLINK_CAN +//config: bool "iplink for CAN (4.6 kb)" +//config: default n +//config: depends on IPLINK +//config: select FEATURE_IP_LINK_CAN +//config: help +//config: Short form of "ip link" for CAN +//config: //config:config IPROUTE //config: bool "iproute (15 kb)" //config: default y @@ -74,6 +82,13 @@ //config: help //config: Configure network devices with "ip". //config: +//config:config FEATURE_IP_LINK_CAN +//config: bool "ip link can" +//config: default n +//config: depends on IP_LINK_CAN +//config: help +//config: Configure CAN devices with "ip". +//config: //config:config FEATURE_IP_ROUTE //config: bool "ip route" //config: default y @@ -122,6 +137,7 @@ //applet:IF_IP( APPLET_NOEXEC(ip , ip , BB_DIR_SBIN, BB_SUID_DROP, ip )) //applet:IF_IPADDR( APPLET_NOEXEC(ipaddr , ipaddr , BB_DIR_SBIN, BB_SUID_DROP, ipaddr )) //applet:IF_IPLINK( APPLET_NOEXEC(iplink , iplink , BB_DIR_SBIN, BB_SUID_DROP, iplink )) +//applet:IF_IPLINK_CAN(APPLET_NOEXEC(iplinkcan , iplinkcan , BB_DIR_SBIN, BB_SUID_DROP, iplinkcan)) //applet:IF_IPROUTE( APPLET_NOEXEC(iproute , iproute , BB_DIR_SBIN, BB_SUID_DROP, iproute )) //applet:IF_IPRULE( APPLET_NOEXEC(iprule , iprule , BB_DIR_SBIN, BB_SUID_DROP, iprule )) //applet:IF_IPTUNNEL(APPLET_NOEXEC(iptunnel, iptunnel, BB_DIR_SBIN, BB_SUID_DROP, iptunnel)) @@ -130,6 +146,7 @@ //kbuild:lib-$(CONFIG_IP) += ip.o //kbuild:lib-$(CONFIG_IPADDR) += ip.o //kbuild:lib-$(CONFIG_IPLINK) += ip.o +//kbuild:lib-$(CONFIG_IPLINK_CAN) += ip.o //kbuild:lib-$(CONFIG_IPROUTE) += ip.o //kbuild:lib-$(CONFIG_IPRULE) += ip.o //kbuild:lib-$(CONFIG_IPTUNNEL) += ip.o @@ -149,10 +166,16 @@ //usage: "ipaddr show|flush [dev IFACE] [scope SCOPE] [to PREFIX] [label PATTERN]" //usage: //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 +//usage:#if ENABLE_FEATURE_IP_LINK_CAN +//usage:#define iplink_type_usage "\n [type TYPE ARGS]" +//usage:#else +//usage:#define iplink_type_usage "" +//usage:#endif //usage:#define iplink_trivial_usage //usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" //usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" //usage: " [master IFACE | nomaster] [netns PID]" +//usage: IF_FEATURE_IP_LINK(iplink_type_usage) // * short help shows only "set" command, long help continues (with just one "\n") // * and shows all other commands: //usage:#define iplink_full_usage "\n" @@ -207,6 +230,59 @@ // bond_slave | ipvlan | geneve | bridge_slave | vrf } //usage: //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 +//usage:#define iplinkcan_trivial_usage +//usage: /*Usage:iplinkcan*/"set DEVICE type can" +//usage:#define iplinkcan_full_usage "\n\n" +//usage: " [bitrate BITRATE [sample-point SAMPLE-POINT]] |\n" +//usage: " [tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n" +//usage: " phase-seg2 PHASE-SEG2 [sjw SJW]]\n" +//usage: "\n" +//usage: " [dbitrate BITRATE [dsample-point SAMPLE-POINT]] |\n" +//usage: " [dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n" +//usage: " dphase-seg2 PHASE-SEG2 [dsjw SJW]]\n" +//usage: "\n" +//usage: " [loopback on|off] [listen-only on|off] [triple-sampling on|off]\n" +//usage: " [one-shot on|off] [berr-reporting on|off]\n" +//usage: " [fd on|off] [fd-non-iso on|off] [presume-ack on|off]\n" +//usage: "\n" +//usage: " [restart-ms TIME-MS] [restart]\n" +//usage: "\n" +//usage: " [termination 0..65535]\n" +//usage: +//upstream man ip-link-can: +//Usage: ip link set DEVICE type can +// [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | +// [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 +// phase-seg2 PHASE-SEG2 [ sjw SJW ] ] +// +// [ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] | +// [ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1 +// dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ] +// +// [ loopback { on | off } ] +// [ listen-only { on | off } ] +// [ triple-sampling { on | off } ] +// [ one-shot { on | off } ] +// [ berr-reporting { on | off } ] +// [ fd { on | off } ] +// [ fd-non-iso { on | off } ] +// [ presume-ack { on | off } ] +// +// [ restart-ms TIME-MS ] +// [ restart ] +// +// [ termination { 0..65535 } ] +// +// Where: BITRATE := { 1..1000000 } +// SAMPLE-POINT := { 0.000..0.999 } +// TQ := { NUMBER } +// PROP-SEG := { 1..8 } +// PHASE-SEG1 := { 1..8 } +// PHASE-SEG2 := { 1..8 } +// SJW := { 1..4 } +// RESTART-MS := { 0 | NUMBER } +//usage: +//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 //usage:#define iproute_trivial_usage //usage: "list|flush|add|del|change|append|replace|test ROUTE" //usage:#define iproute_full_usage "\n\n" @@ -327,6 +403,7 @@ typedef int FAST_FUNC (*ip_func_ptr_t)(char**); #if ENABLE_IPADDR \ || ENABLE_IPLINK \ + || ENABLE_IPLINK_CAN \ || ENABLE_IPROUTE \ || ENABLE_IPRULE \ || ENABLE_IPTUNNEL \ @@ -352,6 +429,13 @@ int iplink_main(int argc UNUSED_PARAM, char **argv) return ip_do(do_iplink, argv); } #endif +#if ENABLE_IPLINK_CAN +int iplinkcan_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int iplinkcan_main(int argc UNUSED_PARAM, char **argv) +{ + return ip_do(do_iplink, argv); +} +#endif #if ENABLE_IPROUTE int iproute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int iproute_main(int argc UNUSED_PARAM, char **argv) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 9eb0b4f5f118..c3be54f841dd 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -11,10 +11,17 @@ #include #include +#include #include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" #include "utils.h" +#if ENABLE_FEATURE_IP_LINK_CAN +#define ENABLE_FEATURE_IP_LINK_IFACE 1 +#else +#define ENABLE_FEATURE_IP_LINK_IFACE 0 +#endif + #undef ETH_P_8021AD #define ETH_P_8021AD 0x88A8 #undef VLAN_FLAG_REORDER_HDR @@ -28,6 +35,11 @@ #undef IFLA_VLAN_PROTOCOL #define IFLA_VLAN_PROTOCOL 5 +#ifndef NLMSG_TAIL +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#endif + #ifndef IFLA_LINKINFO # define IFLA_LINKINFO 18 # define IFLA_INFO_KIND 1 @@ -55,6 +67,13 @@ struct ifla_vlan_flags { #define str_on_off "on\0""off\0" +enum { + PARM_on = 0, + PARM_off +}; + +typedef void FAST_FUNC(*ip_type_set_func_ptr_t)(char*, char**); + /* Exits on error */ static int get_ctl_fd(void) { @@ -241,10 +260,261 @@ static void die_must_be_on_off(const char *msg) bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg); } +#if ENABLE_FEATURE_IP_LINK_CAN +static float FAST_FUNC get_float(char *arg, const char *errmsg) +{ + float ret; + char *ptr; + + if (!arg || !*arg) + invarg_1_to_2(arg, errmsg); /* does not return */ + + ret = strtof(arg, &ptr); + if (!ptr || ptr == arg || *ptr) + invarg_1_to_2(arg, errmsg); /* does not return */ + + return ret; +} + +static void do_set_can(char *dev, char **argv) +{ + struct can_bittiming bt = {}, dbt = {}; + struct can_ctrlmode cm = {}; + char *keyword; + static const char keywords[] ALIGN1 = + "bitrate\0""sample-point\0""tq\0" + "prop-seg\0""phase-seg1\0""phase-seg2\0""sjw\0" + "dbitrate\0""dsample-point\0""dtq\0" + "dprop-seg\0""dphase-seg1\0""dphase-seg2\0""dsjw\0" + "loopback\0""listen-only\0""triple-sampling\0" + "one-shot\0""berr-reporting\0" + "fd\0""fd-non-iso\0""presume-ack\0" + "cc-len8-dlc\0""restart\0""restart-ms\0" + "termination\0"; + enum { ARG_bitrate = 0, ARG_sample_point, ARG_tq, + ARG_prop_seg, ARG_phase_seg1, ARG_phase_seg2, ARG_sjw, + ARG_dbitrate, ARG_dsample_point, ARG_dtq, + ARG_dprop_seg, ARG_dphase_seg1, ARG_dphase_seg2, ARG_dsjw, + ARG_loopback, ARG_listen_only, ARG_triple_sampling, + ARG_one_shot, ARG_berr_reporting, + ARG_fd, ARG_fd_non_iso, ARG_presume_ack, + ARG_cc_len8_dlc, ARG_restart, ARG_restart_ms, + ARG_termination }; + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + size_t dev_len; + struct rtattr *linkinfo, *data; + smalluint key, param; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = preferred_family; + xrtnl_open(&rth); + req.i.ifi_index = xll_name_to_index(dev); + dev_len = strlen(dev); + if (dev_len < 2 || dev_len > IFNAMSIZ) + invarg_1_to_2(dev, "dev"); + + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, dev_len); + linkinfo = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)"can", + strlen("can")); + data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + while (*argv) { + key = index_in_substrings(keywords, *argv); + keyword = *argv; + //printf("%s: key: %d, *argv: %s\n", __func__, key, *argv); + switch (key) { + case ARG_bitrate: + case ARG_tq: + case ARG_prop_seg: + case ARG_phase_seg1: + case ARG_phase_seg2: + case ARG_sjw: { + __u32 *val; + + NEXT_ARG(); + if (key == ARG_bitrate) + val = &bt.bitrate; + else if (key == ARG_tq) + val = &bt.tq; + else if (key == ARG_prop_seg) + val = &bt.prop_seg; + else if (key == ARG_phase_seg1) + val = &bt.phase_seg1; + else if (key == ARG_phase_seg2) + val = &bt.phase_seg2; + else + val = &bt.sjw; + + *val = get_u32(*argv, keyword); + break; + } + case ARG_sample_point: { + float sp; + + NEXT_ARG(); + sp = get_float(*argv, keyword); + bt.sample_point = (__u32)(sp * 1000); + break; + } + case ARG_dbitrate: + case ARG_dtq: + case ARG_dprop_seg: + case ARG_dphase_seg1: + case ARG_dphase_seg2: + case ARG_dsjw: { + __u32 *val; + + NEXT_ARG(); + if (key == ARG_dbitrate) + val = &dbt.bitrate; + else if (key == ARG_dtq) + val = &dbt.tq; + else if (key == ARG_dprop_seg) + val = &dbt.prop_seg; + else if (key == ARG_dphase_seg1) + val = &dbt.phase_seg1; + else if (key == ARG_dphase_seg2) + val = &dbt.phase_seg2; + else + val = &dbt.sjw; + + *val = get_u32(*argv, keyword); + break; + } + case ARG_dsample_point: { + float sp; + + NEXT_ARG(); + sp = get_float(*argv, keyword); + dbt.sample_point = (__u32)(sp * 1000); + break; + } + case ARG_loopback: + case ARG_listen_only: + case ARG_triple_sampling: + case ARG_one_shot: + case ARG_berr_reporting: + case ARG_fd: + case ARG_fd_non_iso: + case ARG_presume_ack: + case ARG_cc_len8_dlc: { + __u32 flag = 0; + + NEXT_ARG(); + param = index_in_strings(str_on_off, *argv); + if (param < 0) + die_must_be_on_off(keyword); + + if (key == ARG_loopback) + flag = CAN_CTRLMODE_LOOPBACK; + else if (key == ARG_listen_only) + flag = CAN_CTRLMODE_LISTENONLY; + else if (key == ARG_triple_sampling) + flag = CAN_CTRLMODE_3_SAMPLES; + else if (key == ARG_one_shot) + flag = CAN_CTRLMODE_ONE_SHOT; + else if (key == ARG_berr_reporting) + flag = CAN_CTRLMODE_BERR_REPORTING; + else if (key == ARG_fd) + flag = CAN_CTRLMODE_FD; + else if (key == ARG_fd_non_iso) + flag = CAN_CTRLMODE_FD_NON_ISO; + else if (key == ARG_presume_ack) + flag = CAN_CTRLMODE_PRESUME_ACK; + else +#if defined(CAN_CTRLMODE_CC_LEN8_DLC) + flag = CAN_CTRLMODE_CC_LEN8_DLC; +#else + die_must_be_on_off(keyword); +#endif + cm.mask |= flag; + if (param == PARM_on) + cm.flags |= flag; + + break; + } + case ARG_restart: { + __u32 val = 1; + + NEXT_ARG(); + addattr_l(&req.n, sizeof(req), IFLA_CAN_RESTART, &val, sizeof(val)); + break; + } + case ARG_restart_ms: { + __u32 val; + + NEXT_ARG(); + val = get_u32(*argv, keyword); + addattr_l(&req.n, sizeof(req), IFLA_CAN_RESTART_MS, &val, sizeof(val)); + break; + } + case ARG_termination: { + __u16 val; + + NEXT_ARG(); + val = get_u16(*argv, keyword); + addattr_l(&req.n, sizeof(req), IFLA_CAN_TERMINATION, &val, sizeof(val)); + break; + } + default: + break; + } + + argv++; + } + + if (bt.bitrate || bt.tq) + addattr_l(&req.n, sizeof(req), IFLA_CAN_BITTIMING, &bt, sizeof(bt)); + + if (cm.mask) + addattr_l(&req.n, sizeof(req), IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + xfunc_die(); +} +#endif + +#if ENABLE_FEATURE_IP_LINK_IFACE +static void do_set_iface(char *type, char *dev, char **argv) +{ + static const char keywords[] ALIGN1 = "" + IF_FEATURE_IP_LINK_CAN("can\0") + ; + static const ip_type_set_func_ptr_t funcs[] ALIGN_PTR = { + IF_FEATURE_IP_LINK_CAN(do_set_can,) + }; + ip_type_set_func_ptr_t func; + int key; + + key = index_in_substrings(keywords, type); + if (key < 0) + return; + func = funcs[key]; + func(dev, argv); +} +#endif + /* Return value becomes exitcode. It's okay to not return at all */ static int do_set(char **argv) { char *dev = NULL; +#if ENABLE_FEATURE_IP_LINK_IFACE + char *type = NULL; +#endif uint32_t mask = 0; uint32_t flags = 0; int qlen = -1; @@ -261,18 +531,24 @@ static int do_set(char **argv) "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" "arp\0""promisc\0""address\0""netns\0" "master\0""nomaster\0" +#if ENABLE_FEATURE_IP_LINK_IFACE + "type\0" +#endif "dev\0" /* must be last */; enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast, ARG_arp, ARG_promisc, ARG_addr, ARG_netns, ARG_master, ARG_nomaster, +#if ENABLE_FEATURE_IP_LINK_IFACE + ARG_type, +#endif ARG_dev }; - enum { PARM_on = 0, PARM_off }; smalluint key; while (*argv) { /* substring search ensures that e.g. "addr" and "address" * are both accepted */ key = index_in_substrings(keywords, *argv); + //printf("%s: key: %d, *argv: %s\n", __func__, key, *argv); if (key == ARG_up) { mask |= IFF_UP; flags |= IFF_UP; @@ -304,6 +580,13 @@ static int do_set(char **argv) } else if (key == ARG_netns) { NEXT_ARG(); netns = get_unsigned(*argv, "netns"); +#if ENABLE_FEATURE_IP_LINK_IFACE + } else if (key == ARG_type) { + NEXT_ARG(); + type = *argv; + argv++; + break; +#endif } else if (key >= ARG_dev) { /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */ if (key == ARG_dev) { @@ -311,6 +594,7 @@ static int do_set(char **argv) } if (dev) duparg2("dev", *argv); + dev = *argv; } else { /* "on|off" options */ @@ -496,6 +780,10 @@ static int do_set(char **argv) } if (mask) do_chflags(dev, flags, mask); +#if ENABLE_FEATURE_IP_LINK_IFACE + if (type) + do_set_iface(type, dev, argv); +#endif return 0; } @@ -531,10 +819,6 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) PROTO_8021Q = 0, PROTO_8021AD, }; - enum { - PARM_on = 0, - PARM_off - }; int arg; uint16_t id, proto; struct ifla_vlan_flags flags = {}; @@ -610,10 +894,6 @@ static void vrf_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table)); } -#ifndef NLMSG_TAIL -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) -#endif /* Return value becomes exitcode. It's okay to not return at all */ static int do_add_or_delete(char **argv, const unsigned rtm) { -- 2.34.1 From ross.burton at arm.com Tue Aug 8 18:02:09 2023 From: ross.burton at arm.com (ross.burton at arm.com) Date: Tue, 8 Aug 2023 19:02:09 +0100 Subject: [PATCH] testsuite: handle /bin/false being busybox in the start-stop-daemon tests Message-ID: <20230808180209.2912321-1-ross.burton@arm.com> From: Ross Burton It's known that the final start-stop-daemon test fails if /bin/false is actually a busybox symlink. Instead of failing, check if false is busybox and adapt the expected output to match. Signed-off-by: Ross Burton --- testsuite/start-stop-daemon.tests | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests index 0757b1288..a699c3ca1 100755 --- a/testsuite/start-stop-daemon.tests +++ b/testsuite/start-stop-daemon.tests @@ -26,11 +26,20 @@ testing "start-stop-daemon without -x and -a" \ # Unfortunately, this does not actually check argv[0] correctness, # but at least it checks that pathname to exec() is correct # -# NB: this fails if /bin/false is a busybox symlink: -# busybox looks at argv[0] and says "qwerty: applet not found" +# Note that if /bin/false is busybox the expected output needs to +# be different, as busybox looks at argv[0] and says +# "qwerty: applet not found". +case $(readlink /bin/false) in + *busybox*) + EXPECTED="qwerty: applet not found\n127\n" + ;; + *) + EXPECTED="1\n" + ;; +esac + testing "start-stop-daemon with both -x and -a" \ 'start-stop-daemon -S -x /bin/false -a qwerty false 2>&1; echo $?' \ - "1\n" \ - "" "" + "$EXPECTED" "" "" exit $FAILCOUNT -- 2.34.1 From roberto.foglietta at gmail.com Wed Aug 9 21:42:38 2023 From: roberto.foglietta at gmail.com (Roberto A. Foglietta) Date: Wed, 9 Aug 2023 23:42:38 +0200 Subject: udhcpd wait for interface has an ip Message-ID: Hi all, I am dealing with busybox udhcpd and I discovered that there is not an option that makes this daemon - especially in combination with -f option - wait until the interface receives an IP. Something like -w, for example. At the moment, I solved in this way: ExecStartPre=/bin/sh -c "while ! /usr/sbin/ip -4 a | /bin/grep -q rndis0:; do /bin/sleep 1; done" However, this implies to use --no-block with systemctl re/start and it is a potentially critical shortcoming because this option is not the default. udhcpd: is interface rndis0 up and configured?: Cannot assign requested address I am puzzled because I think that it is not an uncommon issue waiting for an interface that will come up soon or later. Moreover, at first glance, it would not a pain to add that option in networking/udhcp/dhcpd.c:958 == untested and uncompiled code, just for example == again: if (udhcp_read_interface(server_data.interface, &server_data.ifindex, (server_data.server_nip == 0 ? &server_data.server_nip : NULL), server_data.server_mac) ) { if(wait_for_interface) { sleep(1); goto again; } retval = 1; goto ret; } Possibly, I have overlooked something. Otherwise, I can implement this feature. Just let me know. From roberto.foglietta at gmail.com Thu Aug 10 04:20:32 2023 From: roberto.foglietta at gmail.com (Roberto A. Foglietta) Date: Thu, 10 Aug 2023 06:20:32 +0200 Subject: update "exit with stopped jobs" patch Message-ID: Hi, I am checking the status of applying these patches in the 1.36.1 version: -> https://github.com/robang74/tinycore-editor/tree/main/busybox/patches In particular, I found this one where the first trunk has been applied but not the second one. Even if the second one has been evaluated. * https://github.com/robang74/tinycore-editor/blob/main/busybox/patches/busybox-1.33.1-exit-with-stopped-jobs.patch In fact, the busybox code reports: static int FAST_FUNC exitcmd(int argc UNUSED_PARAM, char **argv) { if (stoppedjobs()) return 0; if (argv[1]) savestatus = number(argv[1]); //TODO: this script // trap 'echo trap:$FUNCNAME' EXIT // f() { exit; } // f //prints "trap:f" in bash. We can call exitshell() here to achieve this. //For now, keeping dash code: raise_exception(EXEXIT); /* NOTREACHED */ } Someone can update me on this part of the code, please? IMHO, the question behind it is quite interesting because it relies on the hope that in the future, dash and busybox ash source code will merge in some way and keep aligned. However, this will not happen if the two teams do not merge. First people, then source code. Under this PoV dash could be a single applet busybox executable. I think that the two projects have quite different goals: busybox aims for minimizing size rather than speed, while dash aims for speed. Unfortunately, this dilemma cannot be solved by simply choosing -Os rather than -O3 compilation flags. However, in some cases, a #define set from .config can decide to privilege speed versus size. Best regards, R- From roberto.foglietta at gmail.com Thu Aug 10 04:26:27 2023 From: roberto.foglietta at gmail.com (Roberto A. Foglietta) Date: Thu, 10 Aug 2023 06:26:27 +0200 Subject: update "exit with stopped jobs" patch In-Reply-To: References: Message-ID: On Thu, 10 Aug 2023 at 06:20, Roberto A. Foglietta wrote: > Someone can update me on this part of the code, please? By the way, there is another place in which the same choice has been taken: -> https://github.com/robang74/tinycore-editor/blob/main/busybox/patches/busybox-1.34.0-do-not-cache-value-of-eflag-in-evaltree.patch The second last trunk of the above patch: --- src/shell/ash.c 2021-09-07 05:03:11.231348468 +0200 +++ src/shell/ash.c 2021-09-07 05:02:04.710203902 +0200 @@ -9316,10 +9313,12 @@ evaltree(union node *n, int flags) } } if (eflag) - exitshell(); + goto exexit; } - if (flags & EV_EXIT) + if (flags & EV_EXIT) { +exexit: exitshell(); + } popstackmark(&smark); TRACE(("leaving evaltree (no interrupts)\n")); Which has been applied but with raise_exception(EXEND); instead of exitshell(); - and I suppose for the same reason even if no comment highlights it. Best regards, R- From roberto.foglietta at gmail.com Thu Aug 10 05:17:04 2023 From: roberto.foglietta at gmail.com (Roberto A. Foglietta) Date: Thu, 10 Aug 2023 07:17:04 +0200 Subject: update "exit with stopped jobs" patch In-Reply-To: References: Message-ID: On Thu, 10 Aug 2023 at 06:20, Roberto A. Foglietta wrote: > Unfortunately, this dilemma cannot be solved by simply choosing -Os > rather than -O3 compilation flags. However, in some cases, a #define > set from .config can decide to privilege speed versus size. About this above, I wish to point out that busybox source code can be divided mainly into three categories: 1. the ash, which in the embedded system is supposed to be the default shell and the only one, therefore, it is always running in interactive mode or as a shell interpreter; 2. the lib busybox (libbb), which is a shared source code among many applets as much as possible, a group of functions that are frequently called and put in run; 3. everything else Under this PoV, parts #1 and #2 can be compiled with -O2 or -O3 while for the rest, -Os could be fine as well. In fact, if ifconfig takes a little longer to execute from the perspective of an interactive user, there is no difference. Some other applets are most involved in scripting, like grep, sed and awk or cat and dd. However, {grep, sed, awk, etc.} performances depend on how fast they can handle strings, while {dd, cat, etc.} how fast they can handle I/O and, in general, data transfer. Therefore, each applet has its own specific profile of optimization that can have a little to do with -O3 versus -Os (e.g. a log(n) or N^2 algorithm will not change because of compilation flags). I do not think that it will be difficult to put in `make menuconfig` an option for implementing this division among {1,2} and {3}. What do you think about it? Best regards, R- From j.neuschaefer at gmx.net Mon Aug 14 15:56:58 2023 From: j.neuschaefer at gmx.net (=?UTF-8?q?J=2E=20Neusch=C3=A4fer?=) Date: Mon, 14 Aug 2023 17:56:58 +0200 Subject: [PATCH v2] vi: Remove obsolete comment about regex search Message-ID: <20230814155658.1682148-1-j.neuschaefer@gmx.net> From: Jonathan Neusch?fer On glibc systems (and potentially others), busybox vi supports regex search if FEATURE_VI_REGEX_SEARCH is enabled. Signed-off-by: Jonathan Neusch?fer --- v2: Rebased on 1.36.0 v1: previous version, submitted in 2018 --- editors/vi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index 3cc3d2a0b..3dc23b08e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -8,7 +8,6 @@ // //Things To Do: // ./.exrc -// add magic to search /foo.*bar // add :help command // :map macros // if mark[] values were line numbers rather than pointers -- 2.40.1 From gavinli at thegavinli.com Mon Aug 21 19:17:29 2023 From: gavinli at thegavinli.com (Gavin Li) Date: Mon, 21 Aug 2023 15:17:29 -0400 Subject: [PATCH v1] tar: add --occurrence[=NUM] option Message-ID: <20230821191729.178535-1-gavinli@thegavinli.com> Enable GNU tar's --occurrence option when FEATURE_TAR_LONG_OPTIONS is enabled. Signed-off-by: Gavin Li --- archival/ar.c | 6 +- archival/cpio.c | 2 +- archival/dpkg.c | 38 ++++++------ archival/dpkg_deb.c | 24 ++++---- archival/libarchive/Kbuild.src | 2 + archival/libarchive/accept_add_to.c | 15 +++++ archival/libarchive/accept_add_to_end.c | 15 +++++ archival/libarchive/filter_accept_list.c | 2 +- .../libarchive/filter_accept_list_reassign.c | 2 +- .../libarchive/filter_accept_reject_list.c | 18 +++++- archival/libarchive/get_header_tar.c | 7 +++ archival/tar.c | 59 ++++++++++++++----- include/bb_archive.h | 14 ++++- testsuite/tar/tar-handles-occurrence | 18 ++++++ 14 files changed, 168 insertions(+), 54 deletions(-) create mode 100644 archival/libarchive/accept_add_to.c create mode 100644 archival/libarchive/accept_add_to_end.c create mode 100644 testsuite/tar/tar-handles-occurrence diff --git a/archival/ar.c b/archival/ar.c index 320cbae72..f1df21e95 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -56,7 +56,7 @@ /* filter out entries with same names as specified on the command line */ static char FAST_FUNC filter_replaceable(archive_handle_t *handle) { - if (find_list_entry(handle->accept, handle->file_header->name)) + if (find_list_entry((llist_t *)handle->accept, handle->file_header->name)) return EXIT_FAILURE; return EXIT_SUCCESS; @@ -124,7 +124,7 @@ static int write_ar_header(archive_handle_t *handle) struct stat st; int fd; - fn = llist_pop(&handle->accept); + fn = llist_pop((llist_t **)&handle->accept); if (!fn) return -1; @@ -287,7 +287,7 @@ int ar_main(int argc UNUSED_PARAM, char **argv) if (*argv) archive_handle->filter = filter_accept_list; while (*argv) { - llist_add_to_end(&archive_handle->accept, *argv++); + accept_add_to_end(&archive_handle->accept, *argv++); } #if ENABLE_FEATURE_AR_CREATE diff --git a/archival/cpio.c b/archival/cpio.c index f0d990048..4950d6ead 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -559,7 +559,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) while (*argv) { archive_handle->filter = filter_accept_list; - llist_add_to(&archive_handle->accept, *argv); + accept_add_to(&archive_handle->accept, *argv); argv++; } diff --git a/archival/dpkg.c b/archival/dpkg.c index 8031956e9..23e46e062 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -1495,15 +1495,15 @@ static void init_archive_deb_control(archive_handle_t *ar_handle) tar_handle->src_fd = ar_handle->src_fd; /* We don't care about data.tar.* or debian-binary, just control.tar.* */ - llist_add_to(&(ar_handle->accept), (char*)"control.tar"); + accept_add_to(&(ar_handle->accept), (char*)"control.tar"); #if ENABLE_FEATURE_SEAMLESS_GZ - llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); + accept_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); #endif #if ENABLE_FEATURE_SEAMLESS_BZ2 - llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); + accept_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); #endif #if ENABLE_FEATURE_SEAMLESS_XZ - llist_add_to(&(ar_handle->accept), (char*)"control.tar.xz"); + accept_add_to(&(ar_handle->accept), (char*)"control.tar.xz"); #endif /* Assign the tar handle as a subarchive of the ar handle */ @@ -1519,18 +1519,18 @@ static void init_archive_deb_data(archive_handle_t *ar_handle) tar_handle->src_fd = ar_handle->src_fd; /* We don't care about control.tar.* or debian-binary, just data.tar.* */ - llist_add_to(&(ar_handle->accept), (char*)"data.tar"); + accept_add_to(&(ar_handle->accept), (char*)"data.tar"); #if ENABLE_FEATURE_SEAMLESS_GZ - llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); + accept_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); #endif #if ENABLE_FEATURE_SEAMLESS_BZ2 - llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); + accept_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); #endif #if ENABLE_FEATURE_SEAMLESS_LZMA - llist_add_to(&(ar_handle->accept), (char*)"data.tar.lzma"); + accept_add_to(&(ar_handle->accept), (char*)"data.tar.lzma"); #endif #if ENABLE_FEATURE_SEAMLESS_XZ - llist_add_to(&(ar_handle->accept), (char*)"data.tar.xz"); + accept_add_to(&(ar_handle->accept), (char*)"data.tar.xz"); #endif /* Assign the tar handle as a subarchive of the ar handle */ @@ -1545,7 +1545,7 @@ static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle) xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size); } -static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) +static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, accept_llist_t *myaccept) { ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer; ar_handle->dpkg__sub_archive->accept = myaccept; @@ -1557,7 +1557,7 @@ static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, lli return ar_handle->dpkg__sub_archive->dpkg__buffer; } -static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll) +static void append_control_file_to_llist(const char *package_name, const char *control_name, accept_llist_t **ll) { FILE *fp; char *filename, *line; @@ -1567,7 +1567,7 @@ static void append_control_file_to_llist(const char *package_name, const char *c free(filename); if (fp != NULL) { while ((line = xmalloc_fgetline(fp)) != NULL) - llist_add_to(ll, line); + accept_add_to(ll, line); fclose(fp); } } @@ -1578,7 +1578,7 @@ static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle) char *name_ptr = archive_handle->file_header->name + 1; /* Is this file marked as config file? */ - if (!find_list_entry(archive_handle->accept, name_ptr)) + if (!find_list_entry((llist_t *)archive_handle->accept, name_ptr)) return EXIT_SUCCESS; /* no */ fd = open(name_ptr, O_RDONLY); @@ -1600,7 +1600,7 @@ static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle) free(buf); /* Is it changed after install? */ - if (find_list_entry(archive_handle->accept, md5line) == NULL) { + if (find_list_entry((llist_t *)archive_handle->accept, md5line) == NULL) { printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr); archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name); } @@ -1660,8 +1660,8 @@ static void unpack_package(deb_file_t *deb_file) char *list_filename; archive_handle_t *archive_handle; FILE *out_stream; - llist_t *accept_list; - llist_t *conffile_list; + accept_llist_t *accept_list; + accept_llist_t *conffile_list; int i; /* If existing version, remove it first */ @@ -1690,7 +1690,7 @@ static void unpack_package(deb_file_t *deb_file) i = 0; while (i < ARRAY_SIZE(all_control_files)) { char *c = xasprintf("./%s", all_control_files[i]); - llist_add_to(&accept_list, c); + accept_add_to(&accept_list, c); i++; } archive_handle->dpkg__sub_archive->accept = accept_list; @@ -1831,10 +1831,10 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) if (opt & (OPT_install | OPT_unpack)) { /* -i/-u: require filename */ archive_handle_t *archive_handle; - llist_t *control_list = NULL; + accept_llist_t *control_list = NULL; /* Extract the control file */ - llist_add_to(&control_list, (char*)"./control"); + accept_add_to(&control_list, (char*)"./control"); archive_handle = init_archive_deb_ar(argv[0]); init_archive_deb_control(archive_handle); deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c index dda931169..988c6bcad 100644 --- a/archival/dpkg_deb.c +++ b/archival/dpkg_deb.c @@ -47,7 +47,7 @@ int dpkg_deb_main(int argc UNUSED_PARAM, char **argv) { archive_handle_t *ar_archive; archive_handle_t *tar_archive; - llist_t *control_tar_llist = NULL; + accept_llist_t *control_tar_llist = NULL; unsigned opt; const char *extract_dir; @@ -59,23 +59,23 @@ int dpkg_deb_main(int argc UNUSED_PARAM, char **argv) ar_archive->dpkg__sub_archive = tar_archive; ar_archive->filter = filter_accept_list_reassign; - llist_add_to(&ar_archive->accept, (char*)"data.tar"); - llist_add_to(&control_tar_llist, (char*)"control.tar"); + accept_add_to(&ar_archive->accept, (char*)"data.tar"); + accept_add_to(&control_tar_llist, (char*)"control.tar"); #if ENABLE_FEATURE_SEAMLESS_GZ - llist_add_to(&ar_archive->accept, (char*)"data.tar.gz"); - llist_add_to(&control_tar_llist, (char*)"control.tar.gz"); + accept_add_to(&ar_archive->accept, (char*)"data.tar.gz"); + accept_add_to(&control_tar_llist, (char*)"control.tar.gz"); #endif #if ENABLE_FEATURE_SEAMLESS_BZ2 - llist_add_to(&ar_archive->accept, (char*)"data.tar.bz2"); - llist_add_to(&control_tar_llist, (char*)"control.tar.bz2"); + accept_add_to(&ar_archive->accept, (char*)"data.tar.bz2"); + accept_add_to(&control_tar_llist, (char*)"control.tar.bz2"); #endif #if ENABLE_FEATURE_SEAMLESS_LZMA - llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma"); - llist_add_to(&control_tar_llist, (char*)"control.tar.lzma"); + accept_add_to(&ar_archive->accept, (char*)"data.tar.lzma"); + accept_add_to(&control_tar_llist, (char*)"control.tar.lzma"); #endif #if ENABLE_FEATURE_SEAMLESS_XZ - llist_add_to(&ar_archive->accept, (char*)"data.tar.xz"); - llist_add_to(&control_tar_llist, (char*)"control.tar.xz"); + accept_add_to(&ar_archive->accept, (char*)"data.tar.xz"); + accept_add_to(&control_tar_llist, (char*)"control.tar.xz"); #endif /* Must have 1 or 2 args */ @@ -95,7 +95,7 @@ int dpkg_deb_main(int argc UNUSED_PARAM, char **argv) /* Print the entire control file */ //TODO: standard tool accepts an optional list of fields to print ar_archive->accept = control_tar_llist; - llist_add_to(&(tar_archive->accept), (char*)"./control"); + accept_add_to(&(tar_archive->accept), (char*)"./control"); tar_archive->filter = filter_accept_list; tar_archive->action_data = data_extract_to_stdout; if (extract_dir) diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src index d2f284b08..ccc83a9f0 100644 --- a/archival/libarchive/Kbuild.src +++ b/archival/libarchive/Kbuild.src @@ -7,6 +7,8 @@ lib-y:= common.o COMMON_FILES:= \ + accept_add_to.o \ + accept_add_to_end.o \ \ data_skip.o \ data_extract_all.o \ diff --git a/archival/libarchive/accept_add_to.c b/archival/libarchive/accept_add_to.c new file mode 100644 index 000000000..36310ba9d --- /dev/null +++ b/archival/libarchive/accept_add_to.c @@ -0,0 +1,15 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC accept_add_to(accept_llist_t **old_head, char *data) +{ + accept_llist_t *new_head = xzalloc(sizeof(accept_llist_t)); + + new_head->data = data; + new_head->link = *old_head; + *old_head = new_head; +} diff --git a/archival/libarchive/accept_add_to_end.c b/archival/libarchive/accept_add_to_end.c new file mode 100644 index 000000000..8260ea23e --- /dev/null +++ b/archival/libarchive/accept_add_to_end.c @@ -0,0 +1,15 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC accept_add_to_end(accept_llist_t **list_head, char *data) +{ + while (*list_head) + list_head = &(*list_head)->link; + *list_head = xzalloc(sizeof(accept_llist_t)); + (*list_head)->data = data; + /*(*list_head)->link = NULL;*/ +} diff --git a/archival/libarchive/filter_accept_list.c b/archival/libarchive/filter_accept_list.c index 32f806574..0319ff927 100644 --- a/archival/libarchive/filter_accept_list.c +++ b/archival/libarchive/filter_accept_list.c @@ -12,7 +12,7 @@ */ char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle) { - if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) + if (find_list_entry((llist_t *)archive_handle->accept, archive_handle->file_header->name)) return EXIT_SUCCESS; return EXIT_FAILURE; } diff --git a/archival/libarchive/filter_accept_list_reassign.c b/archival/libarchive/filter_accept_list_reassign.c index 826c5c29d..c6428f9c3 100644 --- a/archival/libarchive/filter_accept_list_reassign.c +++ b/archival/libarchive/filter_accept_list_reassign.c @@ -17,7 +17,7 @@ char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle) { /* Check the file entry is in the accept list */ - if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) { + if (find_list_entry((llist_t *)archive_handle->accept, archive_handle->file_header->name)) { const char *name_ptr; /* Find extension */ diff --git a/archival/libarchive/filter_accept_reject_list.c b/archival/libarchive/filter_accept_reject_list.c index 939e626fa..935e60c29 100644 --- a/archival/libarchive/filter_accept_reject_list.c +++ b/archival/libarchive/filter_accept_reject_list.c @@ -14,7 +14,7 @@ char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle) { const char *key; const llist_t *reject_entry; - const llist_t *accept_entry; + accept_llist_t *accept_entry; key = archive_handle->file_header->name; @@ -26,10 +26,24 @@ char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle) /* Fail if an accept list was specified and the key wasnt in there */ if (archive_handle->accept) { - accept_entry = find_list_entry2(archive_handle->accept, key); + accept_entry = (accept_llist_t *)find_list_entry2((llist_t *)archive_handle->accept, key); if (!accept_entry) { return EXIT_FAILURE; } + + /* Mark the file as seen */ + accept_entry->tar__seen_count++; + +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + /* Support tar --occurrence */ + if (archive_handle->tar__occurrence) { + if (accept_entry->tar__seen_count == archive_handle->tar__occurrence) { + archive_handle->tar__occurrence_remaining--; + } else { + return EXIT_FAILURE; + } + } +#endif } /* Accepted */ diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index cc6f3f0ad..9ae190609 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -176,6 +176,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) # define p_linkname 0 #endif +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + if (archive_handle->tar__occurrence && archive_handle->tar__occurrence_remaining == 0) { + /* We've found all of the occurrences we were looking for, signal end of archive */ + return EXIT_FAILURE; + } +#endif + #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX again: #endif diff --git a/archival/tar.c b/archival/tar.c index d6ca6c1e0..7aa393dc2 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -655,7 +655,7 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) static NOINLINE int writeTarFile( struct TarBallInfo *tbInfo, int recurseFlags, - const llist_t *filelist, + const accept_llist_t *filelist, const char *gzip) { int errorFlag = FALSE; @@ -715,9 +715,9 @@ static NOINLINE int writeTarFile( #endif /* FEATURE_TAR_CREATE */ #if ENABLE_FEATURE_TAR_FROM -static llist_t *append_file_list_to_list(llist_t *list) +static accept_llist_t *append_file_list_to_list(llist_t *list) { - llist_t *newlist = NULL; + accept_llist_t *newlist = NULL; while (list) { FILE *src_stream; @@ -729,7 +729,7 @@ static llist_t *append_file_list_to_list(llist_t *list) char *cp = last_char_is(line, '/'); if (cp > line) *cp = '\0'; - llist_add_to_end(&newlist, line); + accept_add_to_end(&newlist, line); } fclose(src_stream); } @@ -799,6 +799,7 @@ static llist_t *append_file_list_to_list(llist_t *list) //usage: ) //usage: ) //usage: IF_FEATURE_TAR_LONG_OPTIONS( +//usage: "\n --occurrence [NUM] Exit after NUM (default 1) occurrences" //usage: "\n --overwrite Replace existing files" //usage: "\n --strip-components NUM NUM of leading components to strip" //usage: "\n --no-recursion Don't descend in directories" @@ -826,6 +827,7 @@ enum { OPTBIT_AUTOCOMPRESS_BY_EXT, IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) #if ENABLE_FEATURE_TAR_LONG_OPTIONS + OPTBIT_OCCURRENCE, OPTBIT_STRIP_COMPONENTS, IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,) OPTBIT_NORECURSION, @@ -853,6 +855,7 @@ enum { OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z OPT_AUTOCOMPRESS_BY_EXT = 1 << OPTBIT_AUTOCOMPRESS_BY_EXT, // a OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m + OPT_OCCURRENCE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OCCURRENCE )) + 0, // occurrence OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0, // strip-components OPT_LZMA = IF_FEATURE_TAR_LONG_OPTIONS(IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA))) + 0, // lzma OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0, // no-recursion @@ -901,6 +904,7 @@ static const char tar_longopts[] ALIGN1 = # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME "touch\0" No_argument "m" # endif + "occurrence\0" Optional_argument "\xf7" "strip-components\0" Required_argument "\xf8" # if ENABLE_FEATURE_SEAMLESS_LZMA "lzma\0" No_argument "\xf9" @@ -936,6 +940,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) const char *tar_filename = "-"; unsigned opt; int verboseFlag = 0; +#if ENABLE_FEATURE_TAR_FROM + llist_t *accept = NULL, *reject = NULL; +#endif #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM llist_t *excludes = NULL; #endif @@ -999,6 +1006,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_SEAMLESS_Z( "Z" ) "a" IF_FEATURE_TAR_NOPRESERVE_TIME("m") + IF_FEATURE_TAR_LONG_OPTIONS("\xf7:") // --occurrence IF_FEATURE_TAR_LONG_OPTIONS("\xf8:") // --strip-components "\0" "tt:vv:" // count -t,-v @@ -1009,14 +1017,16 @@ int tar_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive #if ENABLE_FEATURE_TAR_LONG_OPTIONS + ":\xf7+" // --occurrence[=NUM] ":\xf8+" // --strip-components=NUM #endif LONGOPTS , &base_dir // -C dir , &tar_filename // -f filename - IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T - IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X + IF_FEATURE_TAR_FROM(, &accept) // T + IF_FEATURE_TAR_FROM(, &reject) // X #if ENABLE_FEATURE_TAR_LONG_OPTIONS + , &tar_handle->tar__occurrence // --occurrence , &tar_handle->tar__strip_components // --strip-components #endif IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command @@ -1061,6 +1071,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) bb_error_msg("verboseFlag:%d", verboseFlag); bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command); bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components); + bb_error_msg("tar_handle->tar__occurrence:%u", tar_handle->tar__occurrence); return 0; # undef showopt #endif @@ -1106,7 +1117,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_TAR_FROM /* Convert each -X EXCLFILE to list of to-be-rejected glob patterns */ - tar_handle->reject = append_file_list_to_list(tar_handle->reject); + tar_handle->reject = (llist_t *)append_file_list_to_list(reject); # if ENABLE_FEATURE_TAR_LONG_OPTIONS /* Append --exclude=GLOBPATTERNs to reject */ if (excludes) { @@ -1116,7 +1127,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) *p2next = excludes; } # endif - tar_handle->accept = append_file_list_to_list(tar_handle->accept); + tar_handle->accept = append_file_list_to_list(accept); #endif /* Setup an array of filenames to work with */ @@ -1126,13 +1137,26 @@ int tar_main(int argc UNUSED_PARAM, char **argv) char *cp = last_char_is(*argv, '/'); if (cp > *argv) *cp = '\0'; - llist_add_to_end(&tar_handle->accept, *argv); + accept_add_to_end(&tar_handle->accept, *argv); argv++; } if (tar_handle->accept || tar_handle->reject) tar_handle->filter = filter_accept_reject_list; +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + if (tar_handle->tar__occurrence) { + accept_llist_t *a = tar_handle->accept; + + if (opt & OPT_CREATE) + bb_simple_error_msg_and_die("--occurrence cannot be used with -c"); + if (!a) + bb_simple_error_msg_and_die("--occurrence requires a file list"); + for (; a; a = a->link) + tar_handle->tar__occurrence_remaining++; + } +#endif + /* Open the tar file */ { int tar_fd = STDIN_FILENO; @@ -1265,14 +1289,21 @@ int tar_main(int argc UNUSED_PARAM, char **argv) create_links_from_list(tar_handle->link_placeholders); /* Check that every file that should have been extracted was */ - while (tar_handle->accept) { - if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) - && !find_list_entry(tar_handle->passed, tar_handle->accept->data) - ) { + for (; tar_handle->accept; tar_handle->accept = tar_handle->accept->link) { + if (find_list_entry(tar_handle->reject, tar_handle->accept->data)) { + continue; + } + if (tar_handle->accept->tar__seen_count == 0) { bb_error_msg_and_die("%s: not found in archive", tar_handle->accept->data); } - tar_handle->accept = tar_handle->accept->link; +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + if (tar_handle->tar__occurrence + && tar_handle->accept->tar__seen_count < tar_handle->tar__occurrence) { + bb_error_msg_and_die("%s: required occurrence not found in archive", + tar_handle->accept->data); + } +#endif } if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) close(tar_handle->src_fd); diff --git a/include/bb_archive.h b/include/bb_archive.h index e0ef8fc4e..74b55236f 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -43,6 +43,13 @@ typedef struct file_header_t { dev_t device; } file_header_t; +typedef struct accept_llist_t { + /* link/data must be first: this struct needs to be llist-compatible */ + struct accept_llist_t *link; + char *data; + unsigned tar__seen_count; +} accept_llist_t; + struct hardlinks_t; typedef struct archive_handle_t { @@ -55,7 +62,7 @@ typedef struct archive_handle_t { /* Define if the header and data component should be processed */ char FAST_FUNC (*filter)(struct archive_handle_t *); /* List of files that have been accepted */ - llist_t *accept; + accept_llist_t *accept; /* List of files that have been rejected */ llist_t *reject; /* List of files that have successfully been worked on */ @@ -82,6 +89,8 @@ typedef struct archive_handle_t { /* Archiver specific. Can make it a union if it ever gets big */ #if ENABLE_FEATURE_TAR_LONG_OPTIONS unsigned tar__strip_components; + unsigned tar__occurrence; + unsigned tar__occurrence_remaining; #endif #define PAX_NEXT_FILE 0 #define PAX_GLOBAL 1 @@ -175,6 +184,9 @@ extern const char cpio_TRAILER[]; archive_handle_t *init_handle(void) FAST_FUNC; +void accept_add_to(accept_llist_t **old_head, char *data) FAST_FUNC; +void accept_add_to_end(accept_llist_t **list_head, char *data) FAST_FUNC; + char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; char filter_accept_list(archive_handle_t *archive_handle) FAST_FUNC; char filter_accept_list_reassign(archive_handle_t *archive_handle) FAST_FUNC; diff --git a/testsuite/tar/tar-handles-occurrence b/testsuite/tar/tar-handles-occurrence new file mode 100644 index 000000000..4d7a8c5db --- /dev/null +++ b/testsuite/tar/tar-handles-occurrence @@ -0,0 +1,18 @@ +# FEATURE: CONFIG_FEATURE_TAR_LONG_OPTIONS + +echo one > test.txt +busybox tar -cf one.tar test.txt + +echo two > test.txt +busybox tar -cf two.tar test.txt + +(head -c 1024 one.tar; head -c 1024 two.tar) > combined.tar + +data=$(busybox tar -xO --occurrence=1 test.txt < combined.tar) +test "$data" = "one" + +data=$(busybox tar -xO --occurrence=2 test.txt < combined.tar) +test "$data" = "two" + +data=$(busybox tar -xO --occurrence=3 test.txt < combined.tar) && exit 1 +test "$data" = "" -- 2.39.2 From rmy at pobox.com Tue Aug 22 08:38:03 2023 From: rmy at pobox.com (Ron Yorston) Date: Tue, 22 Aug 2023 09:38:03 +0100 Subject: [PATCH] tsort: avoid use-after-free Message-ID: <64e473eb.+Y49z45YOIk3o/lO%rmy@pobox.com> When the input data contained a cycle it was possible for tsort to attempt to access freed nodes. This sometimes resulted in the test case 'echo a b b a | tsort' crashing. Don't free nodes when they're removed from the graph. function old new delta tsort_main 621 596 -25 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-25) Total: -25 bytes Signed-off-by: Ron Yorston --- coreutils/tsort.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/coreutils/tsort.c b/coreutils/tsort.c index a451ed2ff..3e7aa48f4 100644 --- a/coreutils/tsort.c +++ b/coreutils/tsort.c @@ -101,6 +101,10 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) ssize_t len; struct node *a; int cycles; + unsigned i; +#if ENABLE_FEATURE_CLEAN_UP + unsigned max_len; +#endif INIT_G(); @@ -152,9 +156,11 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) * - if any nodes are left, they form cycles. */ cycles = 0; +#if ENABLE_FEATURE_CLEAN_UP + max_len = G.nodes_len; +#endif while (G.nodes_len) { struct node *n; - unsigned i; /* Search for first node with no incoming edges */ for (i = 0; i < G.nodes_len; i++) { @@ -173,16 +179,24 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) /* Remove the node (need no longer maintain sort) */ n = G.nodes[i]; G.nodes[i] = G.nodes[--G.nodes_len]; +#if ENABLE_FEATURE_CLEAN_UP + /* Keep reference to removed node so it can be freed */ + G.nodes[G.nodes_len] = n; +#endif /* And remove its outgoing edges */ for (i = 0; i < n->out_count; i++) n->out[i]->in_count--; - free(n->out); puts(n->name); - free(n); + } +#if ENABLE_FEATURE_CLEAN_UP + for (i = 0; i < max_len; i++) + free(G.nodes[i].out); + free(G.nodes[i]); } free(G.nodes); +#endif fflush_stdout_and_exit(cycles ? 1 : 0); } -- 2.41.0 From radoslav.kolev at suse.com Mon Aug 28 13:06:26 2023 From: radoslav.kolev at suse.com (Radoslav Kolev) Date: Mon, 28 Aug 2023 16:06:26 +0300 Subject: [PATCH] shell: avoid segfault on ${0::0/0~09J}. Closes 15216 In-Reply-To: <63ad9a0f.MQrBKX7zM8Pqj639%rmy@pobox.com> References: <63ad9a0f.MQrBKX7zM8Pqj639%rmy@pobox.com> Message-ID: On 12/29/22 3:45 PM, Ron Yorston wrote: > Both ash and hush segfault when asked to evaluate ${0::0/0~09J}. > > The stack for integer values in the arithmetic code was too small: > '09J' results in three integers. The leading zero starts an octal > number but '9' isn't an octal digit so '0', '9' and the variable > 'Z' are placed on the stack. > > Signed-off-by: Ron Yorston Hello, is there some problem with this patch or another reason it's not applied yet? Or it just slipped trough the cracks? If so please consider applying it. Thank you! Rado From rmy at pobox.com Mon Aug 28 13:27:36 2023 From: rmy at pobox.com (Ron Yorston) Date: Mon, 28 Aug 2023 14:27:36 +0100 Subject: [PATCH] shell: avoid segfault on ${0::0/0~09J}. Closes 15216 In-Reply-To: References: <63ad9a0f.MQrBKX7zM8Pqj639%rmy@pobox.com> Message-ID: <64eca0c8.Ole12aJkuPoZmuPM%rmy@pobox.com> Radoslav Kolev wrote: >On 12/29/22 3:45 PM, Ron Yorston wrote: >> Both ash and hush segfault when asked to evaluate ${0::0/0~09J}. > >is there some problem with this patch or another reason it's not applied >yet? Or it just slipped trough the cracks? If so please consider >applying it. Denys applied a different fix in commit d417193cf. Cheers, Ron From zhuyan34 at huawei.com Tue Aug 29 12:50:32 2023 From: zhuyan34 at huawei.com (Yan Zhu) Date: Tue, 29 Aug 2023 20:50:32 +0800 Subject: [PATCH] ash: initialize basepf.buf in ash Message-ID: <20230829125032.238011-1-zhuyan34@huawei.com> From: zhuyan When I planned to print the command in read_line_input, I found that after the system started, the command printed for the first time was always garbled. After analysis, it is found that in the init() function of ash, the variable basepf.buf is not initialized after applying for memory, resulting in garbled initial data. Then assign it to the global variable g_parsefile->buf in ash.c, and then pass g_parsefile->buf to the parameter command of the function read_line_input in the function preadfd(), and finally cause it to be garbled when the command is printed by read_line_input. The call stack is as follows: #0 read_line_input (st=0xb6fff220, prompt=0xb6ffc910 "\\[\\033[32m\\]\\h \\w\\[\\033[m\\] \\$ ", command=command at entry=0xb6ffc230 "P\325\377\266P\325\377\266", maxsize=maxsize at entry=1024) at libbb/lineedit.c:2461 #1 0x0043ef8c in preadfd () at shell/ash.c:10812 #2 preadbuffer () at shell/ash.c:10914 #3 pgetc () at shell/ash.c:10997 #4 0x00440c20 in pgetc_eatbnl () at shell/ash.c:11039 #5 0x00440cbc in xxreadtoken () at shell/ash.c:13157 #6 0x00440f40 in readtoken () at shell/ash.c:13268 #7 0x00441234 in list (nlflag=nlflag at entry=1) at shell/ash.c:11782 #8 0x004420e8 in parsecmd (interact=) at shell/ash.c:13344 #9 0x00442c34 in cmdloop (top=top at entry=1) at shell/ash.c:13549 #10 0x00444e4c in ash_main (argc=, argv=0x444e4c ) at shell/ash.c:14747 #11 0x00407954 in run_applet_no_and_exit (applet_no=9, name=, argv=0xbefffd34) at libbb/appletlib.c:1024 #12 0x00407b68 in run_applet_and_exit (name=0xbefffe56 "ash", argv=0x9) at libbb/appletlib.c:1047 #13 0x00407f88 in main (argc=, argv=0xbefffd34) at libbb/appletlib.c:1181 Fixes: 82dd14a510ca ("ash: use CONFIG_FEATURE_EDITING_MAX_LEN") Signed-off-by: zhuyan --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index e1d93da73..771fc8bf9 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -14484,7 +14484,7 @@ static NOINLINE void init(void) { /* we will never free this */ - basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); + basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); basepf.linno = 1; sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ -- 2.12.3 From vda.linux at googlemail.com Thu Aug 31 01:25:16 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Thu, 31 Aug 2023 03:25:16 +0200 Subject: [PATCH] ash: initialize basepf.buf in ash In-Reply-To: <20230829125032.238011-1-zhuyan34@huawei.com> References: <20230829125032.238011-1-zhuyan34@huawei.com> Message-ID: Applied, thank you On Tue, Aug 29, 2023 at 2:49?PM Yan Zhu wrote: > > From: zhuyan > > When I planned to print the command in read_line_input, I found that after > the system started, the command printed for the first time was always > garbled. > > After analysis, it is found that in the init() function of ash, the > variable basepf.buf is not initialized after applying for memory, resulting > in garbled initial data. Then assign it to the global variable > g_parsefile->buf in ash.c, and then pass g_parsefile->buf to the parameter > command of the function read_line_input in the function preadfd(), and > finally cause it to be garbled when the command is printed by > read_line_input. > > The call stack is as follows: > #0 read_line_input (st=0xb6fff220, prompt=0xb6ffc910 "\\[\\033[32m\\]\\h \\w\\[\\033[m\\] \\$ ", command=command at entry=0xb6ffc230 "P\325\377\266P\325\377\266", maxsize=maxsize at entry=1024) at libbb/lineedit.c:2461 > #1 0x0043ef8c in preadfd () at shell/ash.c:10812 > #2 preadbuffer () at shell/ash.c:10914 > #3 pgetc () at shell/ash.c:10997 > #4 0x00440c20 in pgetc_eatbnl () at shell/ash.c:11039 > #5 0x00440cbc in xxreadtoken () at shell/ash.c:13157 > #6 0x00440f40 in readtoken () at shell/ash.c:13268 > #7 0x00441234 in list (nlflag=nlflag at entry=1) at shell/ash.c:11782 > #8 0x004420e8 in parsecmd (interact=) at shell/ash.c:13344 > #9 0x00442c34 in cmdloop (top=top at entry=1) at shell/ash.c:13549 > #10 0x00444e4c in ash_main (argc=, argv=0x444e4c ) at shell/ash.c:14747 > #11 0x00407954 in run_applet_no_and_exit (applet_no=9, name=, argv=0xbefffd34) at libbb/appletlib.c:1024 > #12 0x00407b68 in run_applet_and_exit (name=0xbefffe56 "ash", argv=0x9) at libbb/appletlib.c:1047 > #13 0x00407f88 in main (argc=, argv=0xbefffd34) at libbb/appletlib.c:1181 > > Fixes: 82dd14a510ca ("ash: use CONFIG_FEATURE_EDITING_MAX_LEN") > > Signed-off-by: zhuyan > --- > shell/ash.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/shell/ash.c b/shell/ash.c > index e1d93da73..771fc8bf9 100644 > --- a/shell/ash.c > +++ b/shell/ash.c > @@ -14484,7 +14484,7 @@ static NOINLINE void > init(void) > { > /* we will never free this */ > - basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); > + basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ); > basepf.linno = 1; > > sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ > -- > 2.12.3 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From vda.linux at googlemail.com Thu Aug 31 07:48:14 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Thu, 31 Aug 2023 09:48:14 +0200 Subject: [PATCH] tsort: avoid use-after-free In-Reply-To: <64e473eb.+Y49z45YOIk3o/lO%rmy@pobox.com> References: <64e473eb.+Y49z45YOIk3o/lO%rmy@pobox.com> Message-ID: Applied, thank you. On Tue, Aug 22, 2023 at 10:38?AM Ron Yorston wrote: > > When the input data contained a cycle it was possible for tsort to > attempt to access freed nodes. This sometimes resulted in the > test case 'echo a b b a | tsort' crashing. > > Don't free nodes when they're removed from the graph. > > function old new delta > tsort_main 621 596 -25 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-25) Total: -25 bytes > > Signed-off-by: Ron Yorston > --- > coreutils/tsort.c | 20 +++++++++++++++++--- > 1 file changed, 17 insertions(+), 3 deletions(-) > > diff --git a/coreutils/tsort.c b/coreutils/tsort.c > index a451ed2ff..3e7aa48f4 100644 > --- a/coreutils/tsort.c > +++ b/coreutils/tsort.c > @@ -101,6 +101,10 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) > ssize_t len; > struct node *a; > int cycles; > + unsigned i; > +#if ENABLE_FEATURE_CLEAN_UP > + unsigned max_len; > +#endif > > INIT_G(); > > @@ -152,9 +156,11 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) > * - if any nodes are left, they form cycles. > */ > cycles = 0; > +#if ENABLE_FEATURE_CLEAN_UP > + max_len = G.nodes_len; > +#endif > while (G.nodes_len) { > struct node *n; > - unsigned i; > > /* Search for first node with no incoming edges */ > for (i = 0; i < G.nodes_len; i++) { > @@ -173,16 +179,24 @@ int tsort_main(int argc UNUSED_PARAM, char **argv) > /* Remove the node (need no longer maintain sort) */ > n = G.nodes[i]; > G.nodes[i] = G.nodes[--G.nodes_len]; > +#if ENABLE_FEATURE_CLEAN_UP > + /* Keep reference to removed node so it can be freed */ > + G.nodes[G.nodes_len] = n; > +#endif > > /* And remove its outgoing edges */ > for (i = 0; i < n->out_count; i++) > n->out[i]->in_count--; > - free(n->out); > > puts(n->name); > - free(n); > + } > +#if ENABLE_FEATURE_CLEAN_UP > + for (i = 0; i < max_len; i++) > + free(G.nodes[i].out); > + free(G.nodes[i]); > } > free(G.nodes); > +#endif > > fflush_stdout_and_exit(cycles ? 1 : 0); > } > -- > 2.41.0 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From rob at landley.net Thu Aug 31 09:04:28 2023 From: rob at landley.net (Rob Landley) Date: Thu, 31 Aug 2023 04:04:28 -0500 Subject: Add *sum -b (brief, hash only) option. Message-ID: <9e11c315-f934-3395-6a7f-3ee31bea1a5d@landley.net> Something toybox has had for years, thought you guys might be interested. A way to get these things to output ONLY the hash, so it's more easily scriptable. In the gnu/dammit version -b says not to strip DOS newlines, which we already ignored as a NOP in at least some cases... Rob -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-Add-sum-b-brief.patch Type: text/x-patch Size: 4697 bytes Desc: not available URL: From vda.linux at googlemail.com Thu Aug 31 14:32:47 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Thu, 31 Aug 2023 16:32:47 +0200 Subject: Add *sum -b (brief, hash only) option. In-Reply-To: <9e11c315-f934-3395-6a7f-3ee31bea1a5d@landley.net> References: <9e11c315-f934-3395-6a7f-3ee31bea1a5d@landley.net> Message-ID: On Thu, Aug 31, 2023 at 11:02?AM Rob Landley wrote: > Something toybox has had for years, thought you guys might be interested. A way > to get these things to output ONLY the hash, so it's more easily scriptable. > > In the gnu/dammit version -b says not to strip DOS newlines, which we already > ignored as a NOP in at least some cases... Did you ask GNU coreutils to also have such an option? I prefer to not create another case of several incompatible options for the same functionality, invented independently. From rob at landley.net Thu Aug 31 20:51:05 2023 From: rob at landley.net (Rob Landley) Date: Thu, 31 Aug 2023 15:51:05 -0500 Subject: Add *sum -b (brief, hash only) option. In-Reply-To: References: <9e11c315-f934-3395-6a7f-3ee31bea1a5d@landley.net> Message-ID: <0f374ab4-c394-afce-7e5b-e6dc93b69541@landley.net> On 8/31/23 09:32, Denys Vlasenko wrote: > On Thu, Aug 31, 2023 at 11:02?AM Rob Landley wrote: >> Something toybox has had for years, thought you guys might be interested. A way >> to get these things to output ONLY the hash, so it's more easily scriptable. >> >> In the gnu/dammit version -b says not to strip DOS newlines, which we already >> ignored as a NOP in at least some cases... > > Did you ask GNU coreutils to also have such an option? Not yet, I'm still waiting for the resolution of: https://lists.gnu.org/archive/html/coreutils/2023-08/msg00009.html https://lists.gnu.org/archive/html/coreutils/2023-08/msg00100.html You have a lot more gnu/faith than I do. (I'm agnustic at best.) > I prefer to not create another case of several incompatible options > for the same functionality, invented independently. It's been in toybox for 9 years, which predates Android's adoption: https://github.com/landley/toybox/commit/2682551a4b19 *shrug* Your call, of course. Just thought I'd offer a patch... Rob