From dario.binacchi at amarulasolutions.com Fri Jun 2 10:04:48 2023 From: dario.binacchi at amarulasolutions.com (Dario Binacchi) Date: Fri, 2 Jun 2023 12:04:48 +0200 Subject: [RESEND, RFC PATCH] ip link: support for the CAN netlink Message-ID: <20230602100448.3342902-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 7c320869958a..4959e9f25288 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 68d1990445fe..f97169714d0f 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.32.0 From deweloper at wp.pl Fri Jun 2 18:04:15 2023 From: deweloper at wp.pl (Aleksander Mazur) Date: Fri, 2 Jun 2023 20:04:15 +0200 Subject: ftpd: support SITE CHMOD 0777 /path/to/file Message-ID: <20230602200415.254c5c3f@mocarz> Hi, This patch allows changing file permissions via ftp. Mode is limited to octal values (no a+rwx etc.) and just access permissions (0777, no suid), like in vsftpd. Verified with following FTP clients: Midnight Commander, ncftp (in the latter case explicit chmod command is needed). Without this patch the executable bit is lost and you have to recover permissions of uploaded files on your own. function old new delta ftpd_main 2061 2280 +219 .rodata 33114 33120 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 225/0) Total: 225 bytes text data bss dec hex filename 300584 1331 1212 303127 4a017 busybox_old 300809 1331 1212 303352 4a0f8 busybox_unstripped -------------- next part -------------- A non-text attachment was scrubbed... Name: 012-ftpd-site_chmod.patch Type: text/x-patch Size: 2134 bytes Desc: not available URL: From deweloper at wp.pl Sun Jun 4 11:22:27 2023 From: deweloper at wp.pl (Aleksander Mazur) Date: Sun, 4 Jun 2023 13:22:27 +0200 Subject: hush: BUG in varexp2 when doing a=${a:+$a }a Message-ID: <20230604132227.7e61d58c@mocarz> Hi, hush aborts when doing mentioned parameter substitution. (Fortunately it works fine when double-quoted.) $ ./hush BusyBox v1.37.0.git (2023-06-04 12:42:18 CEST) hush - the humble shell Enter 'help' for a list of built-in commands. /tmp $ a=${a:+$a }a /tmp $ echo $a a /tmp $ a=${a:+$a }a hush: BUG in varexp2 -------------- next part -------------- A non-text attachment was scrubbed... Name: hush-vars-var_subst.tests.fail Type: application/octet-stream Size: 159 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: var_subst.right Type: application/octet-stream Size: 10 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: var_subst.tests Type: application/octet-stream Size: 46 bytes Desc: not available URL: From andrej.picej at norik.com Mon Jun 5 08:57:45 2023 From: andrej.picej at norik.com (Andrej Picej) Date: Mon, 5 Jun 2023 10:57:45 +0200 Subject: [PATCH] hwclock: add get/set parameters option Message-ID: <20230605085745.1974591-1-andrej.picej@norik.com> In kernel 5.16 special ioctls were introduced to get/set RTC parameters. Add option to get/set parameters into busybox version of hwclock. Implementation is similar to the one already used in linux-utils hwclock tool. Example of parameter get use: $ hwclock -g 2 The RTC parameter 0x2 is set to 0x2. $ hwclock --param-get bsm The RTC parameter 0x2 is set to 0x2. Example of parameter set use: $ hwclock -p 2=1 The RTC parameter 0x2 will be set to 0x1. $ hwclock -p bsm=2 The RTC parameter 0x2 will be set to 0x2. Signed-off-by: Andrej Picej --- include/rtc_.h | 23 +++++++++ util-linux/hwclock.c | 119 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 137 insertions(+), 5 deletions(-) diff --git a/include/rtc_.h b/include/rtc_.h index 24ff536..4b8d9fc 100644 --- a/include/rtc_.h +++ b/include/rtc_.h @@ -22,6 +22,11 @@ int rtc_xopen(const char **default_rtc, int flags) FAST_FUNC; void rtc_read_tm(struct tm *ptm, int fd) FAST_FUNC; time_t rtc_tm2time(struct tm *ptm, int utc) FAST_FUNC; +struct hwclock_param { + int id; + const char *name; + const char *help; +}; /* * Everything below this point has been copied from linux/rtc.h @@ -46,6 +51,17 @@ struct linux_rtc_wkalrm { struct linux_rtc_time time; /* time the alarm is set to */ }; +struct rtc_param { + __u64 param; + union { + __u64 uvalue; + __s64 svalue; + __u64 ptr; + }; + __u32 index; + __u32 __pad; +}; + /* * ioctl calls that are permitted to the /dev/rtc interface, if * any of the RTC drivers are enabled. @@ -71,12 +87,19 @@ struct linux_rtc_wkalrm { #define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ #define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ +#define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param) /* Get parameter */ +#define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param) /* Set parameter */ + /* interrupt flags */ #define RTC_IRQF 0x80 /* any of the following is active */ #define RTC_PF 0x40 #define RTC_AF 0x20 #define RTC_UF 0x10 +# define RTC_PARAM_FEATURES 0 +# define RTC_PARAM_CORRECTION 1 +# define RTC_PARAM_BACKUP_SWITCH_MODE 2 + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c index 723b095..0a49671 100644 --- a/util-linux/hwclock.c +++ b/util-linux/hwclock.c @@ -48,6 +48,19 @@ # define LIBC_IS_MUSL 0 #endif +static const struct hwclock_param hwclock_params[] = +{ + { RTC_PARAM_FEATURES, "features", "supported features" }, + { RTC_PARAM_CORRECTION, "correction", "time correction" }, + { RTC_PARAM_BACKUP_SWITCH_MODE, "bsm", "backup switch mode" }, + { } +}; + +const struct hwclock_param *get_hwclock_params(void) +{ + return hwclock_params; +} + /* diff code is disabled: it's not sys/hw clock diff, it's some useless * "time between hwclock was started and we saw CMOS tick" quantity. @@ -320,6 +333,89 @@ static void from_sys_clock(const char **pp_rtcname, int utc) close(rtc); } +static int resolve_rtc_param_alias(const char *alias, __u64 *value) +{ + const struct hwclock_param *param = &hwclock_params[0]; + + while (param->name) { + if (!strcmp(alias, param->name)) { + *value = param->id; + return 0; + } + param++; + } + + return 1; +} + +static void get_rtc_param(const char **pp_rtcname, const char *rtc_param) +{ + int rtc; + struct rtc_param param = { .param = 0 }; + + if (resolve_rtc_param_alias(rtc_param, ¶m.param) != 0) { + param.param = bb_strtoull(rtc_param, NULL, 0); + if (errno) + bb_error_msg_and_die("could not convert parameter name: '%s' to number", rtc_param); + } + + rtc = rtc_xopen(pp_rtcname, O_RDONLY); + + xioctl(rtc, RTC_PARAM_GET, ¶m); + + printf("The RTC parameter 0x%jx is set to 0x%jx.\n", + (uintmax_t) param.param, (uintmax_t) param.uvalue); + + if (ENABLE_FEATURE_CLEAN_UP) + close(rtc); +} + +static void set_rtc_param(const char **pp_rtcname, const char *rtc_param) +{ + int rtc; + int ret = 1; + struct rtc_param param = { .param = 0 }; + char *tok, *opt = xstrdup(rtc_param); + + /* handle param name */ + tok = strtok(opt, "="); + if (resolve_rtc_param_alias(tok, ¶m.param) != 0) { + param.param = bb_strtoull(tok, NULL, 0); + if (errno) { + bb_error_msg("could not convert parameter name: '%s' to number", tok); + goto done; + } + } + + /* handle param value */ + tok = strtok(NULL, "="); + if (!tok) { + bb_error_msg("expected ="); + goto done; + } + param.uvalue = bb_strtoull(tok, NULL, 0); + if (errno) { + bb_error_msg("could not convert parameter value to number"); + goto done; + } + + rtc = rtc_xopen(pp_rtcname, O_WRONLY); + + printf("The RTC parameter 0x%jx will be set to 0x%jx.\n", + (uintmax_t) param.param, (uintmax_t) param.uvalue); + + xioctl(rtc, RTC_PARAM_SET, ¶m); + + if (ENABLE_FEATURE_CLEAN_UP) + close(rtc); + + ret = 0; +done: + free(opt); + if (ret) + bb_error_msg_and_die("error: %d", ret); +} + // hwclock from util-linux 2.36.1 // hwclock [function] [option...] //Functions: @@ -346,10 +442,10 @@ static void from_sys_clock(const char **pp_rtcname, int utc) //usage:#define hwclock_trivial_usage //usage: IF_LONG_OPTS( -//usage: "[-swul] [--systz] [-f DEV]" +//usage: "[-swul] [--systz] [--param-get PARAM] [--param-set PARAM=VAL] [-f DEV]" //usage: ) //usage: IF_NOT_LONG_OPTS( -//usage: "[-swult] [-f DEV]" +//usage: "[-swult] [-g PARAM] [-p PARAM=VAL] [-f DEV]" //usage: ) //usage:#define hwclock_full_usage "\n\n" //usage: "Show or set hardware clock (RTC)\n" @@ -360,6 +456,8 @@ static void from_sys_clock(const char **pp_rtcname, int utc) //usage: IF_LONG_OPTS( //usage: "\n --systz Set in-kernel timezone, correct system time" //usage: "\n if RTC is kept in local time" +//usage: "\n --param-get PARAM Get RTC parameter" +//usage: "\n --param-set PARAM=VAL Set RTC parameter" //usage: ) //usage: "\n -f DEV Use specified device (e.g. /dev/rtc2)" //usage: "\n -u Assume RTC is kept in UTC" @@ -375,11 +473,14 @@ static void from_sys_clock(const char **pp_rtcname, int utc) #define HWCLOCK_OPT_SYSTOHC 0x10 #define HWCLOCK_OPT_SYSTZ 0x20 #define HWCLOCK_OPT_RTCFILE 0x40 +#define HWCLOCK_OPT_PARAM_GET 0x80 +#define HWCLOCK_OPT_PARAM_SET 0x100 int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int hwclock_main(int argc UNUSED_PARAM, char **argv) { const char *rtcname = NULL; + const char *param = NULL; unsigned opt; int utc; #if ENABLE_LONG_OPTS @@ -391,14 +492,18 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv) "systohc\0" No_argument "w" "systz\0" No_argument "t" /* short opt is non-standard */ "rtc\0" Required_argument "f" + "param-get\0" Required_argument "g" /* short opt is non-standard */ + "param-set\0" Required_argument "p" /* short opt is non-standard */ ; #endif opt = getopt32long(argv, - "^""lurswtf:v" /* -v is accepted and ignored */ + "^""lurswtf:g:p:v" /* -v is accepted and ignored */ "\0" - "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l", + "r--wstgp:w--rstgp:s--wrtgp:t--rswgp:g--rswtp:p--rswtg:l--u:u--l", hwclock_longopts, - &rtcname + &rtcname, + ¶m, + ¶m ); /* If -u or -l wasn't given, check if we are using utc */ @@ -413,6 +518,10 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv) from_sys_clock(&rtcname, utc); else if (opt & HWCLOCK_OPT_SYSTZ) set_kernel_timezone_and_clock(utc, NULL); + else if (opt & HWCLOCK_OPT_PARAM_GET) + get_rtc_param(&rtcname, param); + else if (opt & HWCLOCK_OPT_PARAM_SET) + set_rtc_param(&rtcname, param); else /* default HWCLOCK_OPT_SHOW */ show_clock(&rtcname, utc); -- 2.25.1 From felix.schladt at gmail.com Mon Jun 5 17:46:02 2023 From: felix.schladt at gmail.com (Felix Schladt) Date: Mon, 5 Jun 2023 19:46:02 +0200 Subject: set icmp_code always to 0 even when -p option is used Message-ID: <20230605174626.65187-1-felix.schladt@gmail.com> Introduced with commit b34266b42b5f6f78b7346c9ca90caebcd59db345 the icmp_code field is no longer set to 0 due to the introduction of a memset of the whole struct to 0. But with commit 6ff055115798166e172039284448be758b04e195 the "-p" option was introduced, which allows to fill empty bytes of the package with an arbitrary byte. Since then the memset sets the whole struct to this byte and then fills in the individual fields, but the icmp_code field is never set to 0 as this line is commented out. Kind regards, Felix Schladt From felix.schladt at gmail.com Mon Jun 5 17:46:03 2023 From: felix.schladt at gmail.com (Felix Schladt) Date: Mon, 5 Jun 2023 19:46:03 +0200 Subject: [PATCH] set icmp_code always to 0 even when -p option is used In-Reply-To: <20230605174626.65187-1-felix.schladt@gmail.com> References: <20230605174626.65187-1-felix.schladt@gmail.com> Message-ID: <20230605174626.65187-2-felix.schladt@gmail.com> --- networking/ping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index 9805695a1..71640eb27 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -563,7 +563,7 @@ static void sendping4(int junk UNUSED_PARAM) memset(pkt, G.pattern, datalen + ICMP_MINLEN + 4); pkt->icmp_type = ICMP_ECHO; - /*pkt->icmp_code = 0;*/ + pkt->icmp_code = 0; pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ pkt->icmp_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp_id = myid; @@ -586,7 +586,7 @@ static void sendping6(int junk UNUSED_PARAM) memset(pkt, G.pattern, datalen + sizeof(struct icmp6_hdr) + 4); pkt->icmp6_type = ICMP6_ECHO_REQUEST; - /*pkt->icmp6_code = 0;*/ + *pkt->icmp6_code = 0; /*pkt->icmp6_cksum = 0;*/ pkt->icmp6_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp6_id = myid; -- 2.41.0 From felix.schladt at gmail.com Mon Jun 5 18:03:37 2023 From: felix.schladt at gmail.com (Felix Schladt) Date: Mon, 5 Jun 2023 20:03:37 +0200 Subject: [PATCH] set icmp_code always to 0 even when -p option is used Message-ID: <20230605180337.6041-1-felix.schladt@gmail.com> --- networking/ping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index 9805695a1..1c387353f 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -563,7 +563,7 @@ static void sendping4(int junk UNUSED_PARAM) memset(pkt, G.pattern, datalen + ICMP_MINLEN + 4); pkt->icmp_type = ICMP_ECHO; - /*pkt->icmp_code = 0;*/ + pkt->icmp_code = 0; pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ pkt->icmp_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp_id = myid; @@ -586,7 +586,7 @@ static void sendping6(int junk UNUSED_PARAM) memset(pkt, G.pattern, datalen + sizeof(struct icmp6_hdr) + 4); pkt->icmp6_type = ICMP6_ECHO_REQUEST; - /*pkt->icmp6_code = 0;*/ + pkt->icmp6_code = 0; /*pkt->icmp6_cksum = 0;*/ pkt->icmp6_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp6_id = myid; -- 2.41.0 From zhousiqi5 at huawei.com Thu Jun 8 02:44:18 2023 From: zhousiqi5 at huawei.com (zhousiqi (A)) Date: Thu, 8 Jun 2023 02:44:18 +0000 Subject: [Patch] Enable udhcpc6 in the busybox to obtain the SNTP server. Message-ID: <8c3428fb78b348c3818ec93533becd0b@huawei.com> Dear BusyBox maintainers, I am writing to propose a patch for udhcpc6 that adds support for retrieving SNTP (Simple Network Time Protocol) servers. Currently, udhcpc6 does not support this function, which limits its usefulness in certain environments. My patch extends the existing -O option in udhcpc6 to include a new option, -O sntpsrv. When the -O sntpsrv option is used, udhcpc6 will request SNTP servers from the DHCPv6 server, and will configure the system's time accordingly. I have tested this patch on my own system, and have verified that it works as expected. I believe that this patch will be useful to other users who need to retrieve SNTP servers using udhcpc6. Thank you for your time and consideration. Best regards, Zhou >From 57e404b2a227e40fffe4d56045885939fa0e00d6 Mon Sep 17 00:00:00 2001 From: Zhou Siqi Date: Tue, 6 Jun 2023 15:46:36 +0800 Subject: [PATCH] The sntp server helps synchronize clock signals between the client and the server. Most DHCP software in the industry supports this function.Currently, udhcpc6 does not support the function of obtaining the SNTP server.This modification enables udhcpc6 to support this function. Signed-off-by: Zhou Siqi --- examples/var_service/dhcp_if/convert2sntpconf | 30 +++++++++++++ networking/udhcp/Config.src | 8 ++++ networking/udhcp/d6_common.h | 3 ++ networking/udhcp/d6_dhcpc.c | 61 +++++++++++++++++---------- 4 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 examples/var_service/dhcp_if/convert2sntpconf diff --git a/examples/var_service/dhcp_if/convert2sntpconf b/examples/var_service/dhcp_if/convert2sntpconf new file mode 100644 index 0000000..c23e914 --- /dev/null +++ b/examples/var_service/dhcp_if/convert2sntpconf @@ -0,0 +1,30 @@ +#!/bin/sh +# This example shows how to obtain the SNTP server information from the configuration information obtained by the client. +# convert: +# (Client configuration information) +# dhcptype=5 +# lease=97200 +# interface=eth0 +# ip=2000:192:168::64:84/64 +# mask=64 +# dns=fec0:70:4000::22:33:40 fec0:70:4000::22:33:41 +fec0:70:4000::22:33:42 # domain=lab.example.com example.com # +sntpsrv=fec0:0:0:23::43 fec0:0:0:23::44 + +# into: + +#let cfg=cfg+1 +#sntpip[$cfg]=... + +exec >/dev/null +exec 2>&1 + +test "$interface" || exit 1 +test "$ip" || exit 1 + +{ +for n in $sntpsrv; do + echo "let cfg=cfg+1" + echo "sntpip[\$cfg]='$n'" +done +} >"$1" diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index 8c8c11c..574c33c 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -171,3 +171,11 @@ config FEATURE_UDHCP_8021Q help If selected, both client and server will support passing of VLAN ID and priority via options 132 and 133 as per 802.1Q. + +config FEATURE_UDHCPC6_RFC4075 + bool "Support udhcpc6 obtain the SNTP servers." + default y + depends on UDHCPC6 + help + If selected, the IPv6 client udhcpc6 can obtain the SNTP servers. + diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h index 9dfde77..49e1b5b 100644 --- a/networking/udhcp/d6_common.h +++ b/networking/udhcp/d6_common.h @@ -87,6 +87,9 @@ struct d6_option { #define D6_OPT_IA_PD 25 #define D6_OPT_IAPREFIX 26 +/* Adapted from dhcp */ +#define D6_OPT_SNTP_SERVERS 31 + /* RFC 4704 "The DHCPv6 Client FQDN Option" * uint16 option-code OPTION_CLIENT_FQDN (39) * uint16 option-len 1 + length of domain name diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 8d11a75..8707da1 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -81,6 +81,9 @@ static const struct dhcp_optflag d6_optflags[] = { { OPTION_STRING, D6_OPT_BOOT_URL }, { OPTION_STRING, D6_OPT_BOOT_PARAM }, #endif +#if ENABLE_FEATURE_UDHCPC6_RFC4075 + { OPTION_6RD | OPTION_LIST | OPTION_REQ, D6_OPT_SNTP_SERVERS }, +#endif { OPTION_STRING, 0xd1 }, /* DHCP_PXE_CONF_FILE */ { OPTION_STRING, 0xd2 }, /* DHCP_PXE_PATH_PREFIX */ { 0, 0 } @@ -102,6 +105,9 @@ static const char d6_option_strings[] ALIGN1 = "bootfile_url" "\0" /* D6_OPT_BOOT_URL */ "bootfile_param" "\0" /* D6_OPT_BOOT_PARAM */ #endif +#if ENABLE_FEATURE_UDHCPC6_RFC4075 + "sntpsrv" "\0" /* D6_OPT_SNTP_SERVERS */ +#endif "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */ "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */ "\0"; @@ -243,10 +249,34 @@ static char *string_option_to_env(const uint8_t *option, return xasprintf("%s=%.*s", name, val_len, (char*)option + 4); } +static void handle_server_info(char *dev_key, const uint8_t *option, +int addrs, int option_offset) { + char *dlist; + + /* Make sure payload-size is a multiple of 16 */ + if ((option[3] & 0x0f) != 0) + return; + + /* Get the number of addresses on the option */ + addrs = option[3] >> 4; + + /* Setup environment variable */ + *new_env() = dlist = xmalloc(strlen(dev_key) + addrs * 40 - 1); + dlist = stpcpy(dlist, dev_key); + option_offset = 0; + + while (addrs--) { + dlist += sprint_nip6(dlist, option + 4 + option_offset); + option_offset += 16; + if (addrs) + *dlist++ = ' '; + } +} + /* put all the parameters into the environment */ static void option_to_env(const uint8_t *option, const uint8_t *option_end) { -#if ENABLE_FEATURE_UDHCPC6_RFC3646 +#if ENABLE_FEATURE_UDHCPC6_RFC3646 || ENABLE_FEATURE_UDHCPC6_RFC4075 int addrs, option_offset; #endif /* "length minus 4" */ @@ -339,28 +369,7 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end) break; #if ENABLE_FEATURE_UDHCPC6_RFC3646 case D6_OPT_DNS_SERVERS: { - char *dlist; - - /* Make sure payload-size is a multiple of 16 */ - if ((option[3] & 0x0f) != 0) - break; - - /* Get the number of addresses on the option */ - addrs = option[3] >> 4; - - /* Setup environment variable */ - *new_env() = dlist = xmalloc(4 + addrs * 40 - 1); - dlist = stpcpy(dlist, "dns="); - option_offset = 0; - - while (addrs--) { - sprint_nip6(dlist, option + 4 + option_offset); - dlist += 39; - option_offset += 16; - if (addrs) - *dlist++ = ' '; - } - + handle_server_info("dns=",option,addrs,option_offset); break; } case D6_OPT_DOMAIN_LIST: { @@ -406,6 +415,12 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end) *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4); break; #endif +#if ENABLE_FEATURE_UDHCPC6_RFC4075 + case D6_OPT_SNTP_SERVERS: { + handle_server_info("sntpsrv=",option,addrs,option_offset); + break; + } +#endif case D6_OPT_BOOT_URL: case D6_OPT_BOOT_PARAM: case 0xd1: /* DHCP_PXE_CONF_FILE */ -- 2.12.3 From zhousiqi5 at huawei.com Thu Jun 8 02:51:38 2023 From: zhousiqi5 at huawei.com (zhousiqi (A)) Date: Thu, 8 Jun 2023 02:51:38 +0000 Subject: [PATCH] Simplify display of IPv6 addresses based on international standard Message-ID: <847942ea3b8840f08e9537c9875937b4@huawei.com> Dear BusyBox maintainers, I am writing to propose a patch for dhcpc6 that simplifies the display of IPv6 addresses based on the international standard. Currently, when dhcpc6 obtains an IPv6 address, it displays the address in a full format, which can be difficult to read and compare. With this patch, the address will be displayed in a simplified format that is easier to read and understand. I have tested this patch on my own system and have not encountered any issues. However, I welcome any feedback or suggestions from the community. Thank you for considering my proposal. Best regards, Zhou >From 757b2901fd397399f6b050a015767d2355a6f36e Mon Sep 17 00:00:00 2001 From: Zhou Siqi Date: Tue, 6 Jun 2023 15:49:59 +0800 Subject: [PATCH] Currently, udhcpc6 does not support simplified IPv6 address based on standards. This modification enables udhcpc6 to support this function. Signed-off-by: Zhou Siqi --- networking/udhcp/Config.src | 7 +++++++ networking/udhcp/common.c | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index 574c33c..c4bb89f 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -179,3 +179,10 @@ config FEATURE_UDHCPC6_RFC4075 help If selected, the IPv6 client udhcpc6 can obtain the SNTP servers. +config FEATURE_UDHCPC6_SIMPLIFY + bool "Support udhcpc6 simplified ipv6 address" + default y + depends on UDHCPC6 + help + If selected, the IPv6 client udhcpc6 can simplify IPv6 addresses + based on international standards. diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 31e525c..e457734 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -5,6 +5,9 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "common.h" +#if ENABLE_FEATURE_UDHCPC6_SIMPLIFY +#include +#endif #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 unsigned dhcp_verbose; @@ -704,8 +707,12 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) { char hexstrbuf[16 * 2]; +#if ENABLE_FEATURE_UDHCPC6_SIMPLIFY + struct in6_addr addr; + char compressed_address[INET6_ADDRSTRLEN]; +#endif bin2hex(hexstrbuf, (void*)ip, 16); - return sprintf(dest, /* "%s" */ + sprintf(dest, /* "%s" */ "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", /* pre, */ hexstrbuf + 0 * 4, @@ -717,4 +724,14 @@ int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) hexstrbuf + 6 * 4, hexstrbuf + 7 * 4 ); +#if ENABLE_FEATURE_UDHCPC6_SIMPLIFY + inet_pton(AF_INET6, dest, &addr); + inet_ntop(AF_INET6, &addr, compressed_address, INET6_ADDRSTRLEN); + /* If dest is different from compressed_address, the simplified address is valid. + * In this case, assign the simplified address to dest. + */ + if (strcmp(dest, compressed_address) != 0) + strcpy(dest,compressed_address); +#endif + return strlen(dest); } -- 2.12.3 From mjt at tls.msk.ru Tue Jun 6 14:08:18 2023 From: mjt at tls.msk.ru (Michael Tokarev) Date: Tue, 6 Jun 2023 17:08:18 +0300 Subject: [PATCH] syslogd: fork after init on a regular system, not before Message-ID: <1686213830.992290.841889.nullmailer@tls.msk.ru> Current syslogd performs all init after daemonizing, meanwhile main process exits successfully. This means any errors during init will not be even shown up because at this time the process has its stderr redirected to /dev/null already. On a MMU system, delay daemonizing to after init. On non-MMU system, keep current code. Signed-off-by: Michael Tokarev --- This is a generic problem with many busybox daemons, I think its root is within the no-MMU system support (where we can't fork). I think this should be solved in a more generic way too, but this is just an example of how this can be fixed in principle. The prob with syslogd is real, any error and it doesn't start but does not show error messages and reports success, - this is hardly acceptable behavour. sysklogd/syslogd.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 6ddfd771a..2f9a727cd 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -1025,7 +1025,6 @@ static void do_syslogd(void) signal(SIGALRM, do_mark); alarm(G.markInterval); #endif - xmove_fd(create_socket(), STDIN_FILENO); if (option_mask32 & OPT_circularlog) ipcsyslog_init(); @@ -1033,6 +1032,16 @@ static void do_syslogd(void) if (option_mask32 & OPT_kmsg) kmsg_init(); + { + int fd = create_socket(); +#if BB_MMU + if (!(option_mask32 & OPT_nofork)) { + bb_daemonize(DAEMON_CHDIR_ROOT); + } +#endif + xmove_fd(fd, STDIN_FILENO); + } + timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER); write_pidfile_std_path_and_ext("syslogd"); @@ -1179,9 +1188,11 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv) G.hostname = safe_gethostname(); *strchrnul(G.hostname, '.') = '\0'; +#if !BB_MMU if (!(opts & OPT_nofork)) { bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); } +#endif do_syslogd(); /* return EXIT_SUCCESS; */ From vda.linux at googlemail.com Mon Jun 12 11:23:59 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Mon, 12 Jun 2023 13:23:59 +0200 Subject: [PATCH] udhcpd: Serve BOOTP clients In-Reply-To: <20230529012951.GA21491@iguana.lan> References: <20230529012951.GA21491@iguana.lan> Message-ID: On Mon, May 29, 2023 at 3:39?AM Adam Goldman wrote: > This patch makes udhcpd respond correctly to queries from BOOTP clients. > > It contains the following changes: > > The end field, or DHCP_END option, is required in DHCP requests but > optional in BOOTP requests. Only complain about missing end fields if > there are DHCP options in the packet. However, we still send an end > field in all replies, because some BOOTP clients expect one in replies > even if they didn't send one in the request. > > Requests without a DHCP_MESSAGE_TYPE are recognized as BOOTP requests > and handled appropriately, instead of being discarded. We still require > an RFC 1048 options field, but we allow it to be empty. > > Since a BOOTP client will keep using the assigned IP forever, we only > send a BOOTP reply if a static lease exists for that client. > > BOOTP replies shouldn't contain DHCP_* options, so we omit them if there > was no DHCP_MESSAGE_TYPE in the request. Options other than DHCP_* > options are still sent. > > The options field of a BOOTP reply must be exactly 64 bytes. If we > construct a reply with more than 64 bytes of options, we give up and log > an error instead of sending it. udhcp_send_raw_packet already pads the > options field to 64 bytes if it is too short. > > This implementation has been tested against an HP PA-RISC client. > > > --- networking/udhcp/common.c.orig 2023-05-22 18:41:39.000000000 -0700 > +++ networking/udhcp/common.c 2023-05-21 19:18:15.000000000 -0700 > @@ -234,6 +234,7 @@ > void FAST_FUNC init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) > { > scan_state->overload = 0; > + scan_state->is_dhcp = 0; > scan_state->rem = sizeof(packet->options); > scan_state->optionptr = packet->options; > } > @@ -251,12 +252,17 @@ > > /* option bytes: [code][len][data1][data2]..[dataLEN] */ > while (1) { > + if (scan_state->rem == 0 && !scan_state->is_dhcp) > + break; /* BOOTP packet without end field */ > if (scan_state->rem <= 0) { > complain: > bb_simple_error_msg("bad packet, malformed option field"); > return NULL; > } > > + if (scan_state->optionptr[OPT_CODE] >= DHCP_REQUESTED_IP && scan_state->optionptr[OPT_CODE] <= DHCP_CLIENT_ID) > + scan_state->is_dhcp = 1; > + scan_state->is_dhcp is not particularly useful. I'm dropping it. > +++ networking/udhcp/packet.c 2023-05-23 00:22:45.000000000 -0700 > @@ -18,6 +18,7 @@ > memset(packet, 0, sizeof(*packet)); > packet->op = BOOTREQUEST; /* if client to a server */ > switch (type) { > + case 0: A symbolic name is better here. > - init_packet(&packet, oldpacket, DHCPOFFER); > + if (!udhcp_get_option(oldpacket, DHCP_MESSAGE_TYPE)) > + message_type = 0; > + init_packet(&packet, oldpacket, message_type); > > /* If it is a static lease, use its IP */ > packet.yiaddr = static_lease_nip; > @@ -785,8 +789,13 @@ > } > > lease_time_sec = select_lease_time(oldpacket); > - udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); > + if (udhcp_get_option(oldpacket, DHCP_MESSAGE_TYPE)) > + udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); > add_server_options(&packet); > + if (!udhcp_get_option(oldpacket, DHCP_MESSAGE_TYPE) && udhcp_end_option(packet.options) > 63) { > + bb_simple_error_msg("BOOTP BOOTREPLY would be too large, not sending"); > + return; > + } Let's just pass the known result of udhcp_get_option(DHCP_MESSAGE_TYPE) down to here, rather than calling it three times. Applied with some changes. Thank you. From vda.linux at googlemail.com Mon Jun 12 14:42:15 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Mon, 12 Jun 2023 16:42:15 +0200 Subject: hush: BUG in varexp2 when doing a=${a:+$a }a In-Reply-To: <20230604132227.7e61d58c@mocarz> References: <20230604132227.7e61d58c@mocarz> Message-ID: Fixed in git. Thank you. On Sun, Jun 4, 2023 at 1:23?PM Aleksander Mazur wrote: > > Hi, > > hush aborts when doing mentioned parameter substitution. > (Fortunately it works fine when double-quoted.) > > $ ./hush > > > BusyBox v1.37.0.git (2023-06-04 12:42:18 CEST) hush - the humble shell > Enter 'help' for a list of built-in commands. > > /tmp $ a=${a:+$a }a > /tmp $ echo $a > a > /tmp $ a=${a:+$a }a > hush: BUG in varexp2 > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From vda.linux at googlemail.com Mon Jun 12 15:54:11 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Mon, 12 Jun 2023 17:54:11 +0200 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: Sorry for missing your fix for so long. I would like to avoid having numstack[] too large, so I'm adding some code to bail out early if we see a number immediately followed by a number or a name, which is never valid. Thus, the current allocation will not be overflowed. Please try current git. On Thu, Dec 29, 2022 at 2:53?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 > --- > shell/math.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/shell/math.c b/shell/math.c > index 76d22c9bd..83ef85c0c 100644 > --- a/shell/math.c > +++ b/shell/math.c > @@ -588,7 +588,8 @@ evaluate_string(arith_state_t *math_state, const char *expr) > /* 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])); > + /* Counterexample: 09J results in three integers. */ > + 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])); > -- > 2.38.1 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From vda.linux at googlemail.com Tue Jun 13 14:30:17 2023 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Tue, 13 Jun 2023 16:30:17 +0200 Subject: [PATCH] syslogd: fork after init on a regular system, not before In-Reply-To: <1686213830.992290.841889.nullmailer@tls.msk.ru> References: <1686213830.992290.841889.nullmailer@tls.msk.ru> Message-ID: I think we can delay daemonizing in both cases. Please try current git. On Thu, Jun 8, 2023 at 10:44?AM Michael Tokarev wrote: > > Current syslogd performs all init after daemonizing, meanwhile > main process exits successfully. This means any errors during init > will not be even shown up because at this time the process has its > stderr redirected to /dev/null already. > > On a MMU system, delay daemonizing to after init. > On non-MMU system, keep current code. > > Signed-off-by: Michael Tokarev > --- > This is a generic problem with many busybox daemons, I think its > root is within the no-MMU system support (where we can't fork). > I think this should be solved in a more generic way too, but this > is just an example of how this can be fixed in principle. The > prob with syslogd is real, any error and it doesn't start but > does not show error messages and reports success, - this is hardly > acceptable behavour. > > sysklogd/syslogd.c | 13 ++++++++++++- > 1 file changed, 12 insertions(+), 1 deletion(-) > > diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c > index 6ddfd771a..2f9a727cd 100644 > --- a/sysklogd/syslogd.c > +++ b/sysklogd/syslogd.c > @@ -1025,7 +1025,6 @@ static void do_syslogd(void) > signal(SIGALRM, do_mark); > alarm(G.markInterval); > #endif > - xmove_fd(create_socket(), STDIN_FILENO); > > if (option_mask32 & OPT_circularlog) > ipcsyslog_init(); > @@ -1033,6 +1032,16 @@ static void do_syslogd(void) > if (option_mask32 & OPT_kmsg) > kmsg_init(); > > + { > + int fd = create_socket(); > +#if BB_MMU > + if (!(option_mask32 & OPT_nofork)) { > + bb_daemonize(DAEMON_CHDIR_ROOT); > + } > +#endif > + xmove_fd(fd, STDIN_FILENO); > + } > + > timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER); > write_pidfile_std_path_and_ext("syslogd"); > > @@ -1179,9 +1188,11 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv) > G.hostname = safe_gethostname(); > *strchrnul(G.hostname, '.') = '\0'; > > +#if !BB_MMU > if (!(opts & OPT_nofork)) { > bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); > } > +#endif > > do_syslogd(); > /* return EXIT_SUCCESS; */ > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From oss-lists at triops.cz Wed Jun 14 14:35:06 2023 From: oss-lists at triops.cz (Ladislav Michl) Date: Wed, 14 Jun 2023 16:35:06 +0200 Subject: [PATCH] date: return failure exit code on set time error Message-ID: From: Ladislav Michl Signed-off-by: Ladislav Michl --- coreutils/date.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/date.c b/coreutils/date.c index abcc37c33..0fca89369 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -289,7 +289,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) /* if setting time, set it */ if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { - bb_simple_perror_msg("can't set date"); + bb_perror_msg_and_die("can't set date"); } } -- 2.39.2 From mjt at tls.msk.ru Wed Jun 14 20:30:37 2023 From: mjt at tls.msk.ru (Michael Tokarev) Date: Wed, 14 Jun 2023 23:30:37 +0300 Subject: [PATCH] syslogd: fork after init on a regular system, not before In-Reply-To: References: <1686213830.992290.841889.nullmailer@tls.msk.ru> Message-ID: <9dd00d60-2bb3-9bb5-1639-5274bcd3ccd9@tls.msk.ru> 13.06.2023 17:30, Denys Vlasenko wrote: > I think we can delay daemonizing in both cases. > > Please try current git. Yes, your version is better, it is definitely cleaner, especially after the preparational patch. But does it work for non-MMU case? Or will it just open /dev/log twice and everything will be ok? I'm not sure how important the non-MMU case is these days, to begin with. The prob there is that you open stuff in parent and check for errors, that's okay. But now you repeat the same open again in a new process after exec, and you can only _hope_ things will work the same way one more time, because you just did that a moment before. This is still a bit dirty at least, I think. But "generally" will work. Either way, this version definitely works ok on a regular system with MMU. The same problem exists in klogd as well. Thank you! /mjt From mjt at tls.msk.ru Wed Jun 14 20:52:34 2023 From: mjt at tls.msk.ru (Michael Tokarev) Date: Wed, 14 Jun 2023 23:52:34 +0300 Subject: [PATCH] syslogd: fork after init on a regular system, not before In-Reply-To: <9dd00d60-2bb3-9bb5-1639-5274bcd3ccd9@tls.msk.ru> References: <1686213830.992290.841889.nullmailer@tls.msk.ru> <9dd00d60-2bb3-9bb5-1639-5274bcd3ccd9@tls.msk.ru> Message-ID: <1e45f338-fdb2-3c0f-2237-9f7812e8a50a@tls.msk.ru> 14.06.2023 23:30, Michael Tokarev ?????: > 13.06.2023 17:30, Denys Vlasenko wrote: >> I think we can delay daemonizing in both cases. >> >> Please try current git. > > Yes, your version is better, it is definitely cleaner, especially > after the preparational patch. > > But does it work for non-MMU case? > Or will it just open /dev/log twice and everything will be ok? Actually it doesn't work on regular system too, the fd#0 is redirected from /dev/null somewhere down the line and enters a tight loop: 44138 readlink("/dev/log", "/run/systemd/journal/dev-log", 80) = 28 44138 readlink("/run/systemd/journal/dev-log", 0x5611c6c26ee0, 80) = -1 EINVAL (Invalid argument) 44138 unlink("/run/systemd/journal/dev-log") = 0 44138 socket(AF_UNIX, SOCK_DGRAM, 0) = 3 44138 bind(3, {sa_family=AF_UNIX, sun_path="/run/systemd/journal/dev-log"}, 110) = 0 44138 chmod("/dev/log", 0666) = 0 44138 dup2(3, 0) = 0 44138 close(3) = 0 44138 chdir("/") = 0 44138 openat(AT_FDCWD, "/dev/null", O_RDWR) = 3 44138 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fb6bc72fa10) = 44139 44138 exit_group(0) = ? 44138 +++ exited with 0 +++ 44139 set_robust_list(0x7fb6bc72fa20, 24) = 0 44139 setsid() = 44139 44139 dup2(3, 0) = 0 44139 dup2(3, 1) = 1 44139 dup2(3, 2) = 2 44139 close(3) = 0 It is done in bb_daemonize_or_rexec(). Which, it seems, can be optimized too, to avoid duplicate dup(0,1,2) case. This is why I used extra variable 'int fd = .. xmove_fd(fd)'. (btw, should it chmod the result of readlink, not /dev/log? - probably doesn't matter). Thanks, /mjt /mjt From mjt at tls.msk.ru Wed Jun 14 20:58:06 2023 From: mjt at tls.msk.ru (Michael Tokarev) Date: Wed, 14 Jun 2023 23:58:06 +0300 Subject: [PATCH] syslogd: fork after init on a regular system, not before In-Reply-To: <1e45f338-fdb2-3c0f-2237-9f7812e8a50a@tls.msk.ru> References: <1686213830.992290.841889.nullmailer@tls.msk.ru> <9dd00d60-2bb3-9bb5-1639-5274bcd3ccd9@tls.msk.ru> <1e45f338-fdb2-3c0f-2237-9f7812e8a50a@tls.msk.ru> Message-ID: 14.06.2023 23:52, Michael Tokarev wrote: > Actually it doesn't work on regular system too, the fd#0 is redirected > from /dev/null somewhere down the line and enters a tight loop Attached is the fix. Not touching daemonize_or_reexec(). Signed-off-by: Michael Tokarev -------------- next part -------------- A non-text attachment was scrubbed... Name: syslogd-avoid-nulling-devlog.patch Type: text/x-patch Size: 875 bytes Desc: not available URL: From iam at valdikss.org.ru Thu Jun 15 20:34:42 2023 From: iam at valdikss.org.ru (ValdikSS) Date: Thu, 15 Jun 2023 23:34:42 +0300 Subject: cut: transforms 0x00 to 0x0a and incorrect length Message-ID: <477abda2-a068-2197-adf3-1b0a88f0b482@valdikss.org.ru> Hi there, Just sending the bug to the mail list in case it got lost in the bug tracker. Cut utility incorrectly replaces null-byte (0x00) with \n (0x0a). Tested with Busybox 1.36.0 and Busybox 1.20.0 ("Busybox in VM" link on the website). Busybox: $ echo -ne "\x00\x01\x02\x03\x04\x05\x06" | ./busybox cut -b 1-3 | hexdump -C 00000000 0a 01 02 03 0a |.....| 00000005 GNU coreutils: $ echo -ne "\x00\x01\x02\x03\x04\x05\x06" | cut -b 1-3 | hexdump -C 00000000 00 01 02 0a |....| 00000004 https://bugs.busybox.net/show_bug.cgi?id=15276 -------------- next part -------------- A non-text attachment was scrubbed... Name: OpenPGP_signature Type: application/pgp-signature Size: 840 bytes Desc: OpenPGP digital signature URL: From mjt at tls.msk.ru Sun Jun 18 07:24:42 2023 From: mjt at tls.msk.ru (Michael Tokarev) Date: Sun, 18 Jun 2023 10:24:42 +0300 Subject: [PATCH] syslogd: fork after init on a regular system, not before In-Reply-To: References: <1686213830.992290.841889.nullmailer@tls.msk.ru> <9dd00d60-2bb3-9bb5-1639-5274bcd3ccd9@tls.msk.ru> <1e45f338-fdb2-3c0f-2237-9f7812e8a50a@tls.msk.ru> Message-ID: <10d0860e-f526-e218-5ae4-e69e84df2a8d@tls.msk.ru> 14.06.2023 23:58, Michael Tokarev wrote: > 14.06.2023 23:52, Michael Tokarev wrote: >> Actually it doesn't work on regular system too, the fd#0 is redirected >> from /dev/null somewhere down the line and enters a tight loop > > Attached is the fix. Not touching daemonize_or_reexec(). > > Signed-off-by: Michael Tokarev Ping? syslogd is completely broken in master now. Thanks, /mjt From lovesykun at gmail.com Sun Jun 18 08:55:49 2023 From: lovesykun at gmail.com (LoveSy) Date: Sun, 18 Jun 2023 16:55:49 +0800 Subject: [PATCH] getfattr: new applet Message-ID: <20230618085549.83293-1-lovesykun@gmail.com> function old new delta getfattr_main - 380 +380 print_attr - 204 +204 list_attr - 152 +152 .rodata 95358 95401 +43 applet_names 2766 2775 +9 e843419 at 0048_000003ed_14 - 8 +8 e843419 at 0047_000003d1_550 - 8 +8 applet_main 3216 3224 +8 packed_usage 34560 34567 +7 applet_install_loc 201 202 +1 ------------------------------------------------------------------------------ (add/remove: 6/0 grow/shrink: 5/0 up/down: 820/0) Total: 820 bytes text data bss dec hex filename 1127717 16889 1736 1146342 117de6 busybox_old 1141124 16937 1736 1159797 11b275 busybox_unstripped Signed-off-by: LoveSy --- miscutils/getfattr.c | 122 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 miscutils/getfattr.c diff --git a/miscutils/getfattr.c b/miscutils/getfattr.c new file mode 100644 index 000000000..4d4eacb5f --- /dev/null +++ b/miscutils/getfattr.c @@ -0,0 +1,122 @@ +/* + * getfattr - get extended attributes of filesystem objects. + * + * Copyright (C) 2023 by LoveSy + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config GETFATTR +//config: bool "getfattr (12.3 kb)" +//config: default y +//config: help +//config: Get extended attributes on files + +//applet:IF_GETFATTR(APPLET_NOEXEC(getfattr, getfattr, BB_DIR_USR_BIN, BB_SUID_DROP, getfattr)) + +//kbuild:lib-$(CONFIG_GETFATTR) += getfattr.o + +#include +#include +#include "libbb.h" + +//usage:#define getfattr_trivial_usage +//usage: "[-h] -n|-d ATTR FILE..." +//usage:#define getfattr_full_usage "\n\n" +//usage: "Get extended attributes" +//usage: "\n" +//usage: "\n -h Do not follow symlinks" +//usage: "\n -d Dump all attributes" +//usage: "\n -n ATTR Get attribute ATTR" +int getfattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; + +int print_attr(const char *file, const char *name, int follow, char **buf, size_t *buflen) +{ + ssize_t vallen, gotlen; + vallen = (follow ? getxattr: lgetxattr)(file, name, NULL, 0); + if (vallen == -1) { + return -1; + } + vallen += 1; + if (*buflen < vallen) { + *buf = (char *)xrealloc(*buf, vallen); + *buflen = vallen; + } + vallen = (follow ? getxattr : lgetxattr)(file, name, *buf, vallen); + if (vallen == -1) { + return -1; + } + (*buf)[vallen] = '\0'; + printf("%s=\"%s\"\n", name, *buf); + return 0; +} + +ssize_t list_attr(const char *file, int follow, char **list, size_t *listlen) +{ + ssize_t len; + len = (follow ? listxattr : llistxattr)(file, NULL, 0); + if (len == -1) { + return -1; + } + if (*listlen < len) { + *list = (char *)xrealloc(*list, len); + *listlen = len; + } + len = (follow ? listxattr : llistxattr)(file, *list, len); + if (len == -1) { + return -1; + } + return len; +} + +int getfattr_main(int argc UNUSED_PARAM, char **argv) +{ + const char *name = NULL; + int status; + int opt; + char *buf = NULL; + size_t buflen = 0; + char *list = NULL; + size_t listlen = 0; + enum { + OPT_h = (1 << 0), + OPT_d = (1 << 1), + }; + + opt = getopt32(argv, "^" + "hdn:" + /* Min one arg, either -x or -n is a must, -d does not allow -n */ + "\0" "-1:dn:n--d:d--n" + , &name + ); + argv += optind; + status = EXIT_SUCCESS; + + do { + int r = 0; + printf("# file: %s\n", *argv); + if (opt & OPT_d) { + ssize_t len = list_attr(*argv, !(opt & OPT_h), &list, &listlen); + ssize_t keylen; + char *key = list; + while (len > 0 && !r) { + r = print_attr(*argv, key, !(opt & OPT_h), &buf, &buflen); + keylen = strlen(key) + 1; + key += keylen; + len -= keylen; + } + } + else { + r = print_attr(*argv, name, !(opt & OPT_h), &buf, &buflen); + } + printf("\n"); + + if (r) { + bb_simple_perror_msg(*argv); + status = EXIT_FAILURE; + } + } while (*++argv); + + free(buf); + + return status; +} -- 2.34.1 From lovesykun at gmail.com Sun Jun 18 09:18:20 2023 From: lovesykun at gmail.com (LoveSy) Date: Sun, 18 Jun 2023 17:18:20 +0800 Subject: [PATCH] getfattr: new applet Message-ID: <20230618091820.87553-1-lovesykun@gmail.com> function old new delta getfattr_main - 388 +388 print_attr - 204 +204 list_attr - 152 +152 .rodata 95358 95401 +43 applet_names 2766 2775 +9 e843419 at 0048_000003ed_14 - 8 +8 e843419 at 0047_000003d1_550 - 8 +8 applet_main 3216 3224 +8 packed_usage 34560 34567 +7 applet_install_loc 201 202 +1 ------------------------------------------------------------------------------ (add/remove: 6/0 grow/shrink: 5/0 up/down: 828/0) Total: 828 bytes text data bss dec hex filename 1127717 16889 1736 1146342 117de6 busybox_old 1157516 16937 1736 1176189 11f27d busybox_unstripped Signed-off-by: LoveSy --- Sorry for my duplicate emails. Please ignore my previous email with the same title, as I accidentially sent it without discription. I raise the patch because I notice there's setfattr in busybox but there's no getfattr. This patch adds the missing getfattr counterpart for setfattr. Note that this is a very simple implementation. miscutils/getfattr.c | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 miscutils/getfattr.c diff --git a/miscutils/getfattr.c b/miscutils/getfattr.c new file mode 100644 index 000000000..556241fb5 --- /dev/null +++ b/miscutils/getfattr.c @@ -0,0 +1,120 @@ +/* + * getfattr - get extended attributes of filesystem objects. + * + * Copyright (C) 2023 by LoveSy + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config GETFATTR +//config: bool "getfattr (12.3 kb)" +//config: default y +//config: help +//config: Get extended attributes on files + +//applet:IF_GETFATTR(APPLET_NOEXEC(getfattr, getfattr, BB_DIR_USR_BIN, BB_SUID_DROP, getfattr)) + +//kbuild:lib-$(CONFIG_GETFATTR) += getfattr.o + +#include +#include +#include "libbb.h" + +//usage:#define getfattr_trivial_usage +//usage: "[-h] -n|-d ATTR FILE..." +//usage:#define getfattr_full_usage "\n\n" +//usage: "Get extended attributes" +//usage: "\n" +//usage: "\n -h Do not follow symlinks" +//usage: "\n -d Dump all attributes" +//usage: "\n -n ATTR Get attribute ATTR" +int getfattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; + +int print_attr(const char *file, const char *name, int follow, char **buf, size_t *buflen) +{ + ssize_t vallen, gotlen; + vallen = (follow ? getxattr: lgetxattr)(file, name, NULL, 0); + if (vallen == -1) { + return -1; + } + vallen += 1; + if (*buflen < vallen) { + *buf = (char *)xrealloc(*buf, vallen); + *buflen = vallen; + } + vallen = (follow ? getxattr : lgetxattr)(file, name, *buf, vallen); + if (vallen == -1) { + return -1; + } + (*buf)[vallen] = '\0'; + printf("%s=\"%s\"\n", name, *buf); + return 0; +} + +ssize_t list_attr(const char *file, int follow, char **list, size_t *listlen) +{ + ssize_t len; + len = (follow ? listxattr : llistxattr)(file, NULL, 0); + if (len == -1) { + return -1; + } + if (*listlen < len) { + *list = (char *)xrealloc(*list, len); + *listlen = len; + } + len = (follow ? listxattr : llistxattr)(file, *list, len); + return len; +} + +int getfattr_main(int argc UNUSED_PARAM, char **argv) +{ + const char *name = NULL; + int status; + int opt; + char *buf = NULL; + size_t buflen = 0; + char *list = NULL; + size_t listlen = 0; + enum { + OPT_h = (1 << 0), + OPT_d = (1 << 1), + }; + + opt = getopt32(argv, "^" + "hdn:" + /* Min one arg, either -x or -n is a must, -d does not allow -n */ + "\0" "-1:dn:n--d:d--n" + , &name + ); + argv += optind; + status = EXIT_SUCCESS; + + do { + int r = 0; + printf("# file: %s\n", *argv); + if (opt & OPT_d) { + ssize_t len = list_attr(*argv, !(opt & OPT_h), &list, &listlen); + ssize_t keylen; + char *key = list; + while (len > 0 && !r) { + r = print_attr(*argv, key, !(opt & OPT_h), &buf, &buflen); + keylen = strlen(key) + 1; + key += keylen; + len -= keylen; + } + } + else { + r = print_attr(*argv, name, !(opt & OPT_h), &buf, &buflen); + } + printf("\n"); + + if (r) { + bb_simple_perror_msg(*argv); + status = EXIT_FAILURE; + } + } while (*++argv); + + free(buf); + free(list); + + return status; +} -- 2.34.1 From jan at kloetzke.net Sun Jun 18 09:15:31 2023 From: jan at kloetzke.net (=?UTF-8?q?Jan=20Kl=C3=B6tzke?=) Date: Sun, 18 Jun 2023 11:15:31 +0200 Subject: [PATCH] dmesg: do not truncate output Message-ID: <20230618091531.176121-1-jan@kloetzke.net> The kernel log buffer can be configured to be bigger than 16 MiB. As the user expects to see all available logs, do not arbitrarily constrain the buffer size. Signed-off-by: Jan Kl?tzke --- util-linux/dmesg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c index 6670b84de..9b2fba22d 100644 --- a/util-linux/dmesg.c +++ b/util-linux/dmesg.c @@ -81,8 +81,6 @@ int dmesg_main(int argc UNUSED_PARAM, char **argv) len = klogctl(10, NULL, 0); /* read ring buffer size */ if (len < 16*1024) len = 16*1024; - if (len > 16*1024*1024) - len = 16*1024*1024; buf = xmalloc(len); len = klogctl(3 + (opts & OPT_c), buf, len); /* read ring buffer */ -- 2.39.2 From peron.clem at gmail.com Sun Jun 18 17:25:32 2023 From: peron.clem at gmail.com (=?UTF-8?B?Q2zDqW1lbnQgUMOpcm9u?=) Date: Sun, 18 Jun 2023 19:25:32 +0200 Subject: [PATCH v3] udhcpc(6): add -K option to set kernel packet priority In-Reply-To: <168138762754.1656295.12624125235575222643@mail.pacien.net> References: <20230413104812.1648285-1-dzfkct.busyboxml@pacien.net> <168138762754.1656295.12624125235575222643@mail.pacien.net> Message-ID: Hi, On Thu, 13 Apr 2023 at 14:07, Pacien TRAN-GIRARD wrote: > > Quoting Cl?ment P?ron (2023-04-13 13:13:41) > > > +#if ENABLE_FEATURE_UDHCPC_SK_PRIO > > > + if (setsockopt_SOL_SOCKET_int(fd, SO_PRIORITY, sk_prio) < 0) { > > > > One difference is that it will call setsockopt even when sk_prio is > > not set and default to '0'. > > > > I don't know if this can have an impact, or maybe we should default > > sk_prio to -1 and only call setsockopt_SOL_SOCKET_int() when it's >= 0 > > I omitted the check here since the default kernel packet priority is 0, > so setting it again to 0 by default should not do any harm. Gentle up on this patch. I don't think it has been picked up yet Regards, From adamg at pobox.com Sat Jun 24 23:23:14 2023 From: adamg at pobox.com (Adam Goldman) Date: Sat, 24 Jun 2023 16:23:14 -0700 Subject: [PATCH] udhcpd: Per-client boot_file Message-ID: <20230624232313.GA7814@iguana.lan> This patch adds the ability to specify a different boot_file for each client. This is useful if clients have different CPU architectures or if some clients are legacy BIOS and some are EFI. It adds a config file option of the form "for xx:xx:xx:xx:xx:xx boot_file foo" which sets the boot_file to "foo" for the client with the MAC address xx:xx:xx:xx:xx:xx. If no such line exists, the global boot_file will be used. The syntax of the option is intended so that in the future, per-client options other than boot_file could be added. --- networking/udhcp/dhcpd.h.orig 2023-01-03 06:17:01.000000000 -0800 +++ networking/udhcp/dhcpd.h 2023-04-16 00:56:09.000000000 -0700 @@ -16,6 +16,7 @@ struct static_lease; +struct boot_file_override; struct server_data_t { char *interface; /* interface to use */ @@ -51,6 +52,7 @@ char *sname; /* bootp server name */ char *boot_file; /* bootp boot file option */ struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */ + struct boot_file_override *boot_file_overrides; /* Boot files for specific clients */ } FIX_ALIASING; #define server_data (*(struct server_data_t*)bb_common_bufsiz1) --- networking/udhcp/dhcpd.c.orig 2023-01-03 06:17:01.000000000 -0800 +++ networking/udhcp/dhcpd.c 2023-05-28 17:13:51.000000000 -0700 @@ -63,6 +63,12 @@ uint8_t opt[1]; }; +struct boot_file_override { + struct boot_file_override *next; + char *boot_file; + uint8_t mac[6]; +}; + /* Takes the address of the pointer to the static_leases linked list, * address to a 6 byte mac address, * 4 byte IP address */ @@ -105,6 +111,33 @@ #endif } +static void add_boot_file_override(struct boot_file_override **bfo_pp, + uint8_t *mac, + const char *boot_file) +{ + struct boot_file_override *bfo; + + /* Find the tail of the list */ + while ((bfo = *bfo_pp) != NULL) { + bfo_pp = &bfo->next; + } + + /* Add new node */ + *bfo_pp = bfo = xzalloc(sizeof(*bfo)); + memcpy(bfo->mac, mac, 6); + bfo->boot_file = strdup(boot_file); + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 + if (dhcp_verbose >= 2) { + bb_info_msg("boot file override: mac:%02x:%02x:%02x:%02x:%02x:%02x boot_file:%s", + bfo->mac[0], bfo->mac[1], bfo->mac[2], + bfo->mac[3], bfo->mac[4], bfo->mac[5], + bfo->boot_file + ); + } +#endif +} + /* Find static lease IP by mac */ static uint32_t get_static_nip_by_mac(void *mac) { @@ -380,6 +413,33 @@ return 1; } +static int FAST_FUNC read_bfo(const char *const_line, void *arg) +{ + char *line; + char *mac_string; + char *specifier; + struct ether_addr mac_bytes; + char *boot_file; + + /* Read mac */ + line = (char *) const_line; + mac_string = strtok_r(line, " \t", &line); + if (!mac_string || !ether_aton_r(mac_string, &mac_bytes)) + return 0; + + specifier = strtok_r(NULL, " \t", &line); + if (!specifier || strcasecmp(specifier, "boot_file")!=0) + return 0; + + boot_file = strtok_r(NULL, " \t", &line); + if (!boot_file) + return 0; + + add_boot_file_override(arg, (uint8_t*) &mac_bytes, boot_file); + + return 1; +} + static int FAST_FUNC read_optset(const char *line, void *arg) { return udhcp_str2optset(line, arg, @@ -420,6 +480,7 @@ {"sname" , read_str , OFS(sname ), NULL}, {"boot_file" , read_str , OFS(boot_file ), NULL}, {"static_lease" , read_staticlease, OFS(static_leases), ""}, + {"for" , read_bfo , OFS(boot_file_overrides), ""}, }; enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; @@ -659,6 +720,7 @@ { struct option_set *config_opts; uint8_t *client_hostname_opt; + char *boot_file; client_hostname_opt = NULL; if (packet->yiaddr) { /* if we aren't from send_inform()... */ @@ -704,8 +766,21 @@ if (server_data.sname) strncpy((char*)packet->sname, server_data.sname, sizeof(packet->sname) - 1); - if (server_data.boot_file) - strncpy((char*)packet->file, server_data.boot_file, sizeof(packet->file) - 1); + + boot_file = server_data.boot_file; + if (packet->yiaddr) { /* if we aren't from send_inform()... */ + struct boot_file_override *bfo = server_data.boot_file_overrides; + while (bfo) { + if (memcmp(bfo->mac, packet->chaddr, 6) == 0) { + boot_file = bfo->boot_file; + break; + } + bfo = bfo->next; + } + } + + if (boot_file) + strncpy((char*)packet->file, boot_file, sizeof(packet->file) - 1); } static uint32_t select_lease_time(struct dhcp_packet *packet) --- examples/udhcp/udhcpd.conf.orig 2023-05-28 17:17:10.000000000 -0700 +++ examples/udhcp/udhcpd.conf 2023-05-28 17:30:19.000000000 -0700 @@ -61,6 +61,11 @@ #static_lease 00:60:08:11:CE:4E 192.168.0.54 #static_lease 00:60:08:11:CE:3E 192.168.0.44 optional_hostname +# The boot_file can be specified on a client-by-client basis. If there is +# no matching "for" line for a client, the global boot_file will be used. +#for 12:34:56:78:90:00 boot_file syslinux32.efi +#for 98:76:54:32:10:00 boot_file syslinux64.efi + # The remainder of options are DHCP options and can be specified with the # keyword 'opt' or 'option'. If an option can take multiple items, such # as the dns option, they can be listed on the same line, or multiple From mjt at tls.msk.ru Sun Jun 25 05:57:47 2023 From: mjt at tls.msk.ru (Michael Tokarev) Date: Sun, 25 Jun 2023 08:57:47 +0300 Subject: [PATCH] udhcpd: Per-client boot_file In-Reply-To: <20230624232313.GA7814@iguana.lan> References: <20230624232313.GA7814@iguana.lan> Message-ID: <02e6ae3c-774f-10ea-95ca-088c7222d9f8@tls.msk.ru> 25.06.2023 02:23, Adam Goldman wrote: > This patch adds the ability to specify a different boot_file for each > client. This is useful if clients have different CPU architectures or if > some clients are legacy BIOS and some are EFI. > > It adds a config file option of the form > "for xx:xx:xx:xx:xx:xx boot_file foo" which sets the boot_file to "foo" > for the client with the MAC address xx:xx:xx:xx:xx:xx. If no such line > exists, the global boot_file will be used. The syntax of the option is > intended so that in the future, per-client options other than boot_file > could be added. I don't think this scales. Instead of per-client, it needs to be per group of clients based on some criteria (such as CPU architecture). See for example how dnsmasq does this (and maybe it is better suited for your usage). /mjt From lucas.larson at gmail.com Sun Jun 25 14:19:03 2023 From: lucas.larson at gmail.com (Lucas Larson) Date: Sun, 25 Jun 2023 10:19:03 -0400 Subject: `sleep` fails if called with an end-of-options delimiter `--` Message-ID: package: busybox version: 1.36.1 Bug description: When using the `sleep` command with the end-of-options delimiter `--` (that is, `sleep -- 1` or `busybox sleep -- 1`), the command fails to execute properly. However, both `sleep 1` and `busybox sleep 1` commands work as expected. According to the POSIX standard, both constructions should be permitted. Minimal steps to reproduce: $ docker pull alpine $ docker run -it alpine $ busybox --help | head -1 BusyBox v1.36.1 (2023-06-02 00:42:02 UTC) multi-call binary. $ cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.18.2 PRETTY_NAME="Alpine Linux v3.18" HOME_URL="https://alpinelinux.org/" BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues" $ *sleep 1* # sleeps for a second $ *sleep -- 1* sh: invalid number '--' # and container exits $ busybox sleep 1 # sleeps for a second $ *busybox sleep -- 1* *sleep: invalid number '--'* # container does not exit $ apk add coreutils # install coreutils on Alpine Linux $ *coreutils --coreutils-prog=sleep 1* # sleeps for a second $ *coreutils --coreutils-prog=sleep -- 1* # also sleeps for a second Thank you, Lucas Larson -------------- next part -------------- An HTML attachment was scrubbed... URL: From David.Laight at ACULAB.COM Sun Jun 25 15:13:23 2023 From: David.Laight at ACULAB.COM (David Laight) Date: Sun, 25 Jun 2023 15:13:23 +0000 Subject: [PATCH] udhcpd: Per-client boot_file In-Reply-To: <02e6ae3c-774f-10ea-95ca-088c7222d9f8@tls.msk.ru> References: <20230624232313.GA7814@iguana.lan> <02e6ae3c-774f-10ea-95ca-088c7222d9f8@tls.msk.ru> Message-ID: From: busybox On Behalf Of Michael Tokarev > Sent: 25 June 2023 06:58 > > 25.06.2023 02:23, Adam Goldman wrote: > > This patch adds the ability to specify a different boot_file for each > > client. This is useful if clients have different CPU architectures or if > > some clients are legacy BIOS and some are EFI. > > > > It adds a config file option of the form > > "for xx:xx:xx:xx:xx:xx boot_file foo" which sets the boot_file to "foo" > > for the client with the MAC address xx:xx:xx:xx:xx:xx. If no such line > > exists, the global boot_file will be used. The syntax of the option is > > intended so that in the future, per-client options other than boot_file > > could be added. > > I don't think this scales. Instead of per-client, it needs to be per > group of clients based on some criteria (such as CPU architecture). > See for example how dnsmasq does this (and maybe it is better suited > for your usage). Isn't there are historic precedence for this to do with booting diskless clients (eg NetBSD) where there are also options for supplying different first and second level 'boot' files. A separate (but maybe interesting) case it to use different address pools for different MAC OUI. In particular this would allow the crappy Cisco phones that never renew addresses be given addresses in a different range from everything else. (Although since 'dayjob' insist on using the M$ DNS server we just have to live with the fact that it is completely broken.) David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales) From adamg at pobox.com Sun Jun 25 22:27:34 2023 From: adamg at pobox.com (Adam Goldman) Date: Sun, 25 Jun 2023 15:27:34 -0700 Subject: [PATCH] udhcpd: Per-client boot_file In-Reply-To: <02e6ae3c-774f-10ea-95ca-088c7222d9f8@tls.msk.ru> References: <20230624232313.GA7814@iguana.lan> <02e6ae3c-774f-10ea-95ca-088c7222d9f8@tls.msk.ru> Message-ID: <20230625222733.GA9402@iguana.lan> On Sun, Jun 25, 2023 at 08:57:47AM +0300, Michael Tokarev wrote: > I don't think this scales. Instead of per-client, it needs to be per > group of clients based on some criteria (such as CPU architecture). "Needs" might be too strong a word. I've been running this with success for two months. However, I'm sure that there are use cases where instead selecting the boot_file based on vendor class identifier would be helpful. -- Adam From dario.binacchi at amarulasolutions.com Mon Jun 26 13:36:46 2023 From: dario.binacchi at amarulasolutions.com (Dario Binacchi) Date: Mon, 26 Jun 2023 15:36:46 +0200 Subject: [RESEND, RFC PATCH] ip link: support for the CAN netlink Message-ID: <20230626133646.36614-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 7c320869958a..4959e9f25288 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 68d1990445fe..f97169714d0f 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.32.0 From oss-lists at triops.cz Tue Jun 27 14:11:12 2023 From: oss-lists at triops.cz (Ladislav Michl) Date: Tue, 27 Jun 2023 16:11:12 +0200 Subject: [PATCH] date: return failure exit code on set time error In-Reply-To: References: Message-ID: Gentle ping... Not possible to do any reasonable scripting as date claims to be successfull all the time. Coreutils-8.32 date does: if (set_date) { /* Set the system clock to the specified date, then regardless of the success of that operation, format and print that date. */ if (settime (&when) != 0) { error (0, errno, _("cannot set date")); ok = false; } } [snip] return ok ? EXIT_SUCCESS : EXIT_FAILURE; On Wed, Jun 14, 2023 at 04:35:06PM +0200, Ladislav Michl wrote: > From: Ladislav Michl > > Signed-off-by: Ladislav Michl > --- > coreutils/date.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/coreutils/date.c b/coreutils/date.c > index abcc37c33..0fca89369 100644 > --- a/coreutils/date.c > +++ b/coreutils/date.c > @@ -289,7 +289,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) > > /* if setting time, set it */ > if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { > - bb_simple_perror_msg("can't set date"); > + bb_perror_msg_and_die("can't set date"); > } > } > > -- > 2.39.2 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox