From abefc3c276ac2450f756c5232745a145bd14dbdf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 30 Sep 2020 22:22:04 +0200 Subject: libbb: fold common64_hash() into its only user Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 75 ++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 47 deletions(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 9db79ea8b..d8f210173 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -38,35 +38,6 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n) return (x << n) | (x >> (64 - n)); } -/* Feed data through a temporary buffer. - * The internal buffer remembers previous data until it has 64 - * bytes worth to pass on. - */ -static void FAST_FUNC common64_hash(md5_ctx_t *ctx, const void *buffer, size_t len) -{ - unsigned bufpos = ctx->total64 & 63; - - ctx->total64 += len; - - while (1) { - unsigned remaining = 64 - bufpos; - if (remaining > len) - remaining = len; - /* Copy data into aligned buffer */ - memcpy(ctx->wbuffer + bufpos, buffer, remaining); - len -= remaining; - buffer = (const char *)buffer + remaining; - bufpos += remaining; - /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ - bufpos -= 64; - if (bufpos != 0) - break; - /* Buffer is filled up, process it */ - ctx->process_block(ctx); - /*bufpos = 0; - already is */ - } -} - /* Process the remaining bytes in the buffer */ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) { @@ -449,7 +420,29 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx) /* Used also for sha1 and sha256 */ void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) { - common64_hash(ctx, buffer, len); + unsigned bufpos = ctx->total64 & 63; + + ctx->total64 += len; + + while (1) { + unsigned remaining = 64 - bufpos; + if (remaining > len) + remaining = len; + /* Copy data into aligned buffer */ + memcpy(ctx->wbuffer + bufpos, buffer, remaining); + len -= remaining; + buffer = (const char *)buffer + remaining; + bufpos += remaining; + + /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ + bufpos -= 64; + if (bufpos != 0) + break; + + /* Buffer is filled up, process it */ + ctx->process_block(ctx); + /*bufpos = 0; - already is */ + } } /* Process the remaining bytes in the buffer and put result from CTX @@ -816,7 +809,7 @@ void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) int i; /* Two extra iterations zero out ctx->total64[2] */ uint64_t *tp = ctx->total64; - for (i = 0; i < 2+8; i++) + for (i = 0; i < 8 + 2; i++) tp[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ } @@ -832,22 +825,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) ctx->total64[0] += len; if (ctx->total64[0] < len) ctx->total64[1]++; -# if 0 - remaining = 128 - bufpos; - /* Hash whole blocks */ - while (len >= remaining) { - memcpy(ctx->wbuffer + bufpos, buffer, remaining); - buffer = (const char *)buffer + remaining; - len -= remaining; - remaining = 128; - bufpos = 0; - sha512_process_block128(ctx); - } - - /* Save last, partial blosk */ - memcpy(ctx->wbuffer + bufpos, buffer, len); -# else while (1) { remaining = 128 - bufpos; if (remaining > len) @@ -857,15 +835,16 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) len -= remaining; buffer = (const char *)buffer + remaining; bufpos += remaining; + /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ bufpos -= 128; if (bufpos != 0) break; + /* Buffer is filled up, process it */ sha512_process_block128(ctx); /*bufpos = 0; - already is */ } -# endif } #endif /* NEED_SHA512 */ @@ -1398,10 +1377,12 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) bufpos++; remaining--; } + /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ bufpos -= ctx->input_block_bytes; if (bufpos != 0) break; + /* Buffer is filled up, process it */ sha3_process_block72(ctx->state); /*bufpos = 0; - already is */ -- cgit v1.2.3-55-g6feb From 6561e07460acc5b38af99aa5e80283dc04953eca Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Wed, 29 Jul 2020 10:43:53 +0200 Subject: mount: support the sizelimit and offset option for loop devices Starting with linux kernel v5.4 squashfs has a more strict parameter checking implemented. Unlike util-linux mount, busybox never supported the sizelimit option but simply forwards it to the kernel. Since v5.4 mounting will fail with squashfs: Unknown parameter 'sizelimit' Support the sizelimit parameter by setting it in the LOOP_SET_STATUS64 structure before handing it to the kernel. While at it also add support for the offset option, which currently will always be set to 0. function old new delta cut_out_ull_opt - 167 +167 singlemount 1230 1266 +36 set_loop 834 862 +28 losetup_main 479 483 +4 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 235/0) Total: 235 bytes Signed-off-by: Steffen Trumtrar Signed-off-by: Denys Vlasenko --- include/libbb.h | 3 ++- libbb/loop.c | 4 +++- util-linux/losetup.c | 2 +- util-linux/mount.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 4 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 8c7978456..83ecca47f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1515,7 +1515,8 @@ int del_loop(const char *device) FAST_FUNC; * malloc and return it in *devname. * return value is the opened fd to the loop device, or < on error */ -int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC; +int set_loop(char **devname, const char *file, unsigned long long offset, + unsigned long long sizelimit, unsigned flags) FAST_FUNC; /* These constants match linux/loop.h (without BB_ prefix): */ #define BB_LO_FLAGS_READ_ONLY 1 #define BB_LO_FLAGS_AUTOCLEAR 4 diff --git a/libbb/loop.c b/libbb/loop.c index ada0c7638..85b2724e5 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -102,7 +102,8 @@ int FAST_FUNC get_free_loop(void) * search will re-use an existing loop device already bound to that * file/offset if it finds one. */ -int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, unsigned flags) +int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, + unsigned long long sizelimit, unsigned flags) { char dev[LOOP_NAMESIZE]; char *try; @@ -185,6 +186,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse memset(&loopinfo, 0, sizeof(loopinfo)); safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); loopinfo.lo_offset = offset; + loopinfo.lo_sizelimit = sizelimit; /* * Used by mount to set LO_FLAGS_AUTOCLEAR. * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. diff --git a/util-linux/losetup.c b/util-linux/losetup.c index ac8b79502..24f7a2349 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c @@ -150,7 +150,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_P) { flags |= BB_LO_FLAGS_PARTSCAN; } - if (set_loop(&d, argv[0], offset, flags) < 0) + if (set_loop(&d, argv[0], offset, 0, flags) < 0) bb_simple_perror_msg_and_die(argv[0]); return EXIT_SUCCESS; } diff --git a/util-linux/mount.c b/util-linux/mount.c index b92e2c297..19ac13930 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1886,6 +1886,58 @@ static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts) #endif // !ENABLE_FEATURE_MOUNT_NFS +// Find "...,NAME=NUM,..." in the option string, remove "NAME=NUM" option +// and return NUM. +// Return 0 if not found. +// All instances must be parsed and removed (for example, since kernel 5.4 +// squashfs: Unknown parameter 'sizelimit' +// will result if loopback mount option "sizelimit=NNN" is not removed +// and squashfs sees it in option string). +static unsigned long long cut_out_ull_opt(char *opts, const char *name_eq) +{ + unsigned long long ret = 0; + + if (!opts) // allow NULL opts (simplifies callers' work) + return ret; + + for (;;) { + char *end; + char *opt; + + // Find comma-delimited "NAME=" + for (;;) { + opt = strstr(opts, name_eq); + if (!opt) + return ret; + if (opt == opts) + break; // found it (it's first opt) + if (opt[-1] == ',') { + opts = opt - 1; + break; // found it (it's not a first opt) + } + // False positive like "VNAME=", we are at "N". + // - skip it, loop back to searching + opts = opt + 1; + } + + ret = bb_strtoull(opt + strlen(name_eq), &end, 0); + if (errno && errno != EINVAL) { + err: + bb_error_msg_and_die("bad option '%s'", opt); + } + if (*end == '\0') { + // It is "[,]NAME=NUM\0" - truncate it and return + *opts = '\0'; + return ret; + } + if (*end != ',') + goto err; + // We are at trailing comma + // Remove "NAME=NUM," and loop back to check for duplicate opts + overlapping_strcpy(opt, end + 1); + } +} + // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem // type detection. Returns 0 for success, nonzero for failure. // NB: mp->xxx fields may be trashed on exit @@ -2029,9 +2081,16 @@ static int singlemount(struct mntent *mp, int ignore_busy) ) { // Do we need to allocate a loopback device for it? if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { + unsigned long long offset; + unsigned long long sizelimit; + loopFile = bb_simplify_path(mp->mnt_fsname); mp->mnt_fsname = NULL; // will receive malloced loop dev name + // Parse and remove loopback options + offset = cut_out_ull_opt(filteropts, "offset="); + sizelimit = cut_out_ull_opt(filteropts, "sizelimit="); + // mount always creates AUTOCLEARed loopdevs, so that umounting // drops them without any code in the userspace. // This happens since circa linux-2.6.25: @@ -2040,7 +2099,8 @@ static int singlemount(struct mntent *mp, int ignore_busy) // Subject: Allow auto-destruction of loop devices loopfd = set_loop(&mp->mnt_fsname, loopFile, - 0, + offset, + sizelimit, ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0) | BB_LO_FLAGS_AUTOCLEAR ); -- cgit v1.2.3-55-g6feb From b1c7a66ca6ff913afba17cfe6f16a78a66915c07 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Oct 2020 00:34:44 +0200 Subject: libbb: extend "errno pointer" trick to other than __GLIBC__ Savings on musl: function old new delta resume_main 582 614 +32 lbb_prepare - 20 +20 seq_main 432 449 +17 fgetsetversion 74 88 +14 ... script_main 1207 1180 -27 close_silently 28 - -28 shell_builtin_ulimit 655 626 -29 lineedit_read_key 280 247 -33 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 25/123 up/down: 182/-882) Total: -700 bytes text data bss dec hex filename 1005858 551 5676 1012085 f7175 busybox_old 1005136 551 5680 1011367 f6ea7 busybox_unstripped Signed-off-by: Denys Vlasenko --- include/libbb.h | 7 ++++--- libbb/appletlib.c | 2 +- libbb/ptr_to_globals.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 83ecca47f..df7e45404 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -339,12 +339,13 @@ struct BUG_off_t_size_is_misdetected { #endif #endif -#if defined(__GLIBC__) -/* glibc uses __errno_location() to get a ptr to errno */ -/* We can just memorize it once - no multithreading in busybox :) */ +#if defined(errno) +/* If errno is a define, assume it's "define errno (*__errno_location())" + * and we will cache it's result in this variable */ extern int *const bb_errno; #undef errno #define errno (*bb_errno) +#define bb_cached_errno_ptr 1 #endif #if !(ULONG_MAX > 0xffffffff) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index a515c3fe3..717c63649 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -303,7 +303,7 @@ void lbb_prepare(const char *applet void lbb_prepare(const char *applet IF_FEATURE_INDIVIDUAL(, char **argv)) { -#ifdef __GLIBC__ +#ifdef bb_cached_errno_ptr (*(int **)not_const_pp(&bb_errno)) = __errno_location(); barrier(); #endif diff --git a/libbb/ptr_to_globals.c b/libbb/ptr_to_globals.c index 8ba9cd154..2232c6864 100644 --- a/libbb/ptr_to_globals.c +++ b/libbb/ptr_to_globals.c @@ -14,7 +14,7 @@ struct globals; * but here we make it live in R/W memory */ struct globals *ptr_to_globals; -#ifdef __GLIBC__ +#ifdef errno int *bb_errno; #endif @@ -27,7 +27,7 @@ int *bb_errno; * on weird architectures, compilers, linkers and so on */ struct globals *const ptr_to_globals __attribute__ ((section (".data"))); -#ifdef __GLIBC__ +#ifdef errno int *const bb_errno __attribute__ ((section (".data"))); #endif -- cgit v1.2.3-55-g6feb From aaa0709e7b39d0dc22ac92443a86c84eaff58679 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Oct 2020 01:44:26 +0200 Subject: libbb: do not open-code __errno_location() call Thanks dalias! Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 717c63649..5f59f1273 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -25,6 +25,11 @@ * * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :( */ + +/* Define this accessor before we #define "errno" our way */ +#include +static inline int *get_perrno(void) { return &errno; } + #include "busybox.h" #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ @@ -304,7 +309,7 @@ void lbb_prepare(const char *applet IF_FEATURE_INDIVIDUAL(, char **argv)) { #ifdef bb_cached_errno_ptr - (*(int **)not_const_pp(&bb_errno)) = __errno_location(); + (*(int **)not_const_pp(&bb_errno)) = get_perrno(); barrier(); #endif applet_name = applet; -- cgit v1.2.3-55-g6feb From 4a0eb0370c4df8ee01973b50bb460560532b79f1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Oct 2020 03:07:22 +0200 Subject: gcc-9.x warning fixes Signed-off-by: Denys Vlasenko --- archival/tar.c | 3 ++- include/libbb.h | 2 +- libbb/inet_cksum.c | 4 +++- networking/ping.c | 4 ++-- networking/traceroute.c | 2 +- networking/udhcp/d6_dhcpc.c | 2 +- networking/udhcp/d6_packet.c | 2 +- networking/udhcp/dhcpc.c | 4 ++-- networking/udhcp/packet.c | 4 ++-- 9 files changed, 15 insertions(+), 12 deletions(-) (limited to 'libbb') diff --git a/archival/tar.c b/archival/tar.c index 4ab38db29..4f2564813 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -297,7 +297,8 @@ static void writeLongname(int fd, int type, const char *name, int dir) header.typeflag = type; strcpy(header.name, "././@LongLink"); /* This sets mode/uid/gid/mtime to "00...00" strings */ - memset(header.mode, '0', sizeof(struct prefilled)); + memset((char*)&header + offsetof(struct tar_header_t, mode), /* make gcc-9.x happy */ + '0', sizeof(struct prefilled)); header.mode [sizeof(header.mode ) - 1] = '\0'; header.uid [sizeof(header.uid ) - 1] = '\0'; header.gid [sizeof(header.gid ) - 1] = '\0'; diff --git a/include/libbb.h b/include/libbb.h index df7e45404..3e23b5bbd 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -818,7 +818,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, struct sockaddr *to, socklen_t sa_size) FAST_FUNC; -uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; +uint16_t inet_cksum(const void *addr, int len) FAST_FUNC; int parse_pasv_epsv(char *buf) FAST_FUNC; /* 0 if argv[0] is NULL: */ diff --git a/libbb/inet_cksum.c b/libbb/inet_cksum.c index 3d5dc3adf..fee8648f3 100644 --- a/libbb/inet_cksum.c +++ b/libbb/inet_cksum.c @@ -6,8 +6,10 @@ #include "libbb.h" -uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft) +uint16_t FAST_FUNC inet_cksum(const void *ptr, int nleft) { + const uint16_t *addr = ptr; + /* * Our algorithm is simple, using a 32 bit accumulator, * we add sequential 16 bit words to it, and at the end, fold diff --git a/networking/ping.c b/networking/ping.c index 47b6ab1b2..5f7e5b9b5 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -217,7 +217,7 @@ static void ping4(len_and_sockaddr *lsa) /*memset(pkt, 0, sizeof(G.packet)); already is */ pkt->icmp_type = ICMP_ECHO; pkt->icmp_id = G.myid; - pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); + pkt->icmp_cksum = inet_cksum(pkt, sizeof(G.packet)); xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); @@ -529,7 +529,7 @@ static void sendping4(int junk UNUSED_PARAM) /* No hton: we'll read it back on the same machine */ *(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us(); - pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); + pkt->icmp_cksum = inet_cksum(pkt, datalen + ICMP_MINLEN); sendping_tail(sendping4, ICMP_MINLEN); } diff --git a/networking/traceroute.c b/networking/traceroute.c index 5068f654b..1c4dc3e4a 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -468,7 +468,7 @@ send_probe(int seq, int ttl) /* Always calculate checksum for icmp packets */ outicmp->icmp_cksum = 0; outicmp->icmp_cksum = inet_cksum( - (uint16_t *)outicmp, + outicmp, ((char*)outip + packlen) - (char*)outicmp ); if (outicmp->icmp_cksum == 0) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index fc2d672b7..ac8af91d3 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -947,7 +947,7 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_pac // packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ // check = packet.udp.check; // packet.udp.check = 0; -// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { +// if (check && check != inet_cksum(&packet, bytes)) { // log1("packet with bad UDP checksum received, ignoring"); // return -2; // } diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 446497e15..167a813e3 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c @@ -103,7 +103,7 @@ int FAST_FUNC d6_send_raw_packet( */ packet.ip6.ip6_hlim = IPPROTO_UDP; packet.udp.check = inet_cksum( - (uint16_t *)&packet + 2, + (uint8_t *)&packet + 4, offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size ); /* fix 'hop limit' and 'next header' after UDP checksumming */ diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index e13eb3f9f..66aa38c20 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -935,7 +935,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) /* verify IP checksum */ check = packet.ip.check; packet.ip.check = 0; - if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { + if (check != inet_cksum(&packet.ip, sizeof(packet.ip))) { log1s("bad IP header checksum, ignoring"); return -2; } @@ -960,7 +960,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ check = packet.udp.check; packet.udp.check = 0; - if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { + if (check && check != inet_cksum(&packet, bytes)) { log1s("packet with bad UDP checksum received, ignoring"); return -2; } diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 6d4375237..51374646d 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -164,14 +164,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, packet.udp.len = htons(UDP_DHCP_SIZE - padding); /* for UDP checksumming, ip.len is set to UDP packet len */ packet.ip.tot_len = packet.udp.len; - packet.udp.check = inet_cksum((uint16_t *)&packet, + packet.udp.check = inet_cksum(&packet, IP_UDP_DHCP_SIZE - padding); /* but for sending, it is set to IP packet len */ packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); packet.ip.ihl = sizeof(packet.ip) >> 2; packet.ip.version = IPVERSION; packet.ip.ttl = IPDEFTTL; - packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip)); + packet.ip.check = inet_cksum(&packet.ip, sizeof(packet.ip)); udhcp_dump_packet(dhcp_pkt); result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, -- cgit v1.2.3-55-g6feb From 689d0650ab63425adaea26afe347015a204958ee Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Oct 2020 21:52:16 +0200 Subject: libbb: shrink recursive_action() by reducing memory pressure function old new delta recursive_action1 - 316 +316 file_action_grep 161 164 +3 add_to_prg_cache_if_socket 202 205 +3 depmod_main 509 511 +2 writeFileToTarball 488 489 +1 parse_module 281 282 +1 fileAction 207 208 +1 act 189 190 +1 add_to_dirlist 65 64 -1 writeTarFile 196 194 -2 uuidcache_init 47 45 -2 uuidcache_check_device 109 107 -2 true_action 8 6 -2 run_parts_main 310 308 -2 netstat_main 534 532 -2 lsusb_main 29 27 -2 lspci_main 45 43 -2 initial_scan 138 136 -2 grep_main 845 843 -2 find_main 482 480 -2 config_file_action 437 435 -2 chmod_main 142 140 -2 dirAction 14 10 -4 diff_main 1544 1540 -4 chown_main 154 148 -6 skip_dir 136 129 -7 dir_act 191 184 -7 recursive_action 453 69 -384 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 7/20 up/down: 328/-439) Total: -111 bytes Signed-off-by: Denys Vlasenko --- archival/tar.c | 9 ++--- coreutils/chmod.c | 13 +++---- coreutils/chown.c | 9 +++-- debianutils/run_parts.c | 10 +++--- editors/diff.c | 22 ++++++------ findutils/find.c | 17 +++++---- findutils/grep.c | 13 ++++--- include/libbb.h | 16 ++++++--- libbb/recursive_action.c | 72 +++++++++++++++++++++++--------------- modutils/depmod.c | 12 ++++--- modutils/modprobe-small.c | 3 +- modutils/modprobe.c | 14 ++++---- networking/netstat.c | 28 +++++++-------- selinux/chcon.c | 8 ++--- selinux/setfiles.c | 8 ++--- util-linux/lspci.c | 11 +++--- util-linux/lsusb.c | 10 +++--- util-linux/mdev.c | 20 +++++------ util-linux/volume_id/get_devname.c | 14 ++++---- 19 files changed, 159 insertions(+), 150 deletions(-) (limited to 'libbb') diff --git a/archival/tar.c b/archival/tar.c index 4f2564813..93184cc2a 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -491,10 +491,11 @@ static int exclude_file(const llist_t *excluded_files, const char *file) # define exclude_file(excluded_files, file) 0 # endif -static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf, - void *userData, int depth UNUSED_PARAM) +static int FAST_FUNC writeFileToTarball(struct recursive_state *state, + const char *fileName, + struct stat *statbuf) { - struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData; + struct TarBallInfo *tbInfo = (struct TarBallInfo *) state->userData; const char *header_name; int inputFileFd = -1; @@ -700,7 +701,7 @@ static NOINLINE int writeTarFile( /* Read the directory/files and iterate over them one at a time */ while (filelist) { if (!recursive_action(filelist->data, recurseFlags, - writeFileToTarball, writeFileToTarball, tbInfo, 0) + writeFileToTarball, writeFileToTarball, tbInfo) ) { errorFlag = TRUE; } diff --git a/coreutils/chmod.c b/coreutils/chmod.c index 27e9b6b86..d2988c490 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c @@ -65,12 +65,14 @@ * symbolic links encountered during recursive directory traversals. */ -static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void* param, int depth) +static int FAST_FUNC fileAction(struct recursive_state *state, + const char *fileName, + struct stat *statbuf) { mode_t newmode; /* match coreutils behavior */ - if (depth == 0) { + if (state->depth == 0) { /* statbuf holds lstat result, but we need stat (follow link) */ if (stat(fileName, statbuf)) goto err; @@ -79,9 +81,9 @@ static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void return TRUE; } - newmode = bb_parse_mode((char *)param, statbuf->st_mode); + newmode = bb_parse_mode((char *)state->userData, statbuf->st_mode); if (newmode == (mode_t)-1) - bb_error_msg_and_die("invalid mode '%s'", (char *)param); + bb_error_msg_and_die("invalid mode '%s'", (char *)state->userData); if (chmod(fileName, newmode) == 0) { if (OPT_VERBOSE @@ -136,8 +138,7 @@ int chmod_main(int argc UNUSED_PARAM, char **argv) OPT_RECURSE, // recurse fileAction, // file action fileAction, // dir action - smode, // user data - 0) // depth + smode) // user data ) { retval = EXIT_FAILURE; } diff --git a/coreutils/chown.c b/coreutils/chown.c index a1c5c0224..ffccc6cce 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c @@ -97,10 +97,10 @@ struct param_t { chown_fptr chown_func; }; -static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, - void *vparam, int depth UNUSED_PARAM) +static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, + const char *fileName, struct stat *statbuf) { -#define param (*(struct param_t*)vparam) +#define param (*(struct param_t*)state->userData) #define opt option_mask32 uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid; gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid; @@ -159,8 +159,7 @@ int chown_main(int argc UNUSED_PARAM, char **argv) flags, /* flags */ fileAction, /* file action */ fileAction, /* dir action */ - ¶m, /* user data */ - 0) /* depth */ + ¶m) /* user data */ ) { retval = EXIT_FAILURE; } diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index 196e0640d..585a4b58f 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -131,12 +131,13 @@ static int bb_alphasort(const void *p1, const void *p2) return (option_mask32 & OPT_r) ? -r : r; } -static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUSED_PARAM, int depth) +static int FAST_FUNC act(struct recursive_state *state, + const char *file, struct stat *statbuf) { - if (depth == 0) + if (state->depth == 0) return TRUE; - if (depth == 1 + if (state->depth == 1 && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) || invalid_name(file) || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) @@ -199,8 +200,7 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) ACTION_RECURSE|ACTION_FOLLOWLINKS, act, /* file action */ act, /* dir action */ - NULL, /* user data */ - 0 /* depth */ + NULL /* user data */ ); if (!names) diff --git a/editors/diff.c b/editors/diff.c index dc40ab4f1..280091756 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -803,11 +803,11 @@ struct dlist { }; /* This function adds a filename to dl, the directory listing. */ -static int FAST_FUNC add_to_dirlist(const char *filename, - struct stat *sb UNUSED_PARAM, - void *userdata, int depth UNUSED_PARAM) +static int FAST_FUNC add_to_dirlist(struct recursive_state *state, + const char *filename, + struct stat *sb UNUSED_PARAM) { - struct dlist *const l = userdata; + struct dlist *const l = state->userData; const char *file = filename + l->len; while (*file == '/') file++; @@ -820,12 +820,12 @@ static int FAST_FUNC add_to_dirlist(const char *filename, /* If recursion is not set, this function adds the directory * to the list and prevents recursive_action from recursing into it. */ -static int FAST_FUNC skip_dir(const char *filename, - struct stat *sb, void *userdata, - int depth) +static int FAST_FUNC skip_dir(struct recursive_state *state, + const char *filename, + struct stat *sb) { - if (!(option_mask32 & FLAG(r)) && depth) { - add_to_dirlist(filename, sb, userdata, depth); + if (!(option_mask32 & FLAG(r)) && state->depth) { + add_to_dirlist(state, filename, sb); return SKIP; } if (!(option_mask32 & FLAG(N))) { @@ -833,7 +833,7 @@ static int FAST_FUNC skip_dir(const char *filename, * which do not exist on the "other side". * Testcase: diff -r /tmp / * (it would recurse deep into /proc without this code) */ - struct dlist *const l = userdata; + struct dlist *const l = state->userData; filename += l->len; if (filename[0]) { struct stat osb; @@ -868,7 +868,7 @@ static void diffdir(char *p[2], const char *s_start) * add_to_dirlist will remove it. */ list[i].len = strlen(p[i]); recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS, - add_to_dirlist, skip_dir, &list[i], 0); + add_to_dirlist, skip_dir, &list[i]); /* Sort dl alphabetically. * GNU diff does this ignoring any number of trailing dots. * We don't, so for us dotted files almost always are diff --git a/findutils/find.c b/findutils/find.c index 9a2c61b75..e2947afb4 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -889,10 +889,10 @@ ACTF(links) } #endif -static int FAST_FUNC fileAction(const char *fileName, - struct stat *statbuf, - void *userData UNUSED_PARAM, - int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) +static int FAST_FUNC fileAction( + struct recursive_state *state IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), + const char *fileName, + struct stat *statbuf) { int r; int same_fs = 1; @@ -911,12 +911,12 @@ static int FAST_FUNC fileAction(const char *fileName, #endif #if ENABLE_FEATURE_FIND_MAXDEPTH - if (depth < G.minmaxdepth[0]) { + if (state->depth < G.minmaxdepth[0]) { if (same_fs) return TRUE; /* skip this, continue recursing */ return SKIP; /* stop recursing */ } - if (depth > G.minmaxdepth[1]) + if (state->depth > G.minmaxdepth[1]) return SKIP; /* stop recursing */ #endif @@ -927,7 +927,7 @@ static int FAST_FUNC fileAction(const char *fileName, #if ENABLE_FEATURE_FIND_MAXDEPTH if (S_ISDIR(statbuf->st_mode)) { - if (depth == G.minmaxdepth[1]) + if (state->depth == G.minmaxdepth[1]) return SKIP; } #endif @@ -1570,8 +1570,7 @@ int find_main(int argc UNUSED_PARAM, char **argv) G.recurse_flags,/* flags */ fileAction, /* file action */ fileAction, /* dir action */ - NULL, /* user data */ - 0) /* depth */ + NULL) /* user data */ ) { G.exitstatus |= EXIT_FAILURE; } diff --git a/findutils/grep.c b/findutils/grep.c index 0892a713a..10cca83e7 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -656,10 +656,9 @@ static void load_pattern_list(llist_t **lst, char *pattern) llist_add_to(lst, new_grep_list_data(p, 0)); } -static int FAST_FUNC file_action_grep(const char *filename, - struct stat *statbuf, - void* matched, - int depth UNUSED_PARAM) +static int FAST_FUNC file_action_grep(struct recursive_state *state UNUSED_PARAM, + const char *filename, + struct stat *statbuf) { FILE *file; @@ -686,7 +685,7 @@ static int FAST_FUNC file_action_grep(const char *filename, return 0; } cur_file = filename; - *(int*)matched |= grep_file(file); + *(int*)state->userData |= grep_file(file); fclose(file); return 1; } @@ -702,8 +701,8 @@ static int grep_dir(const char *dir) | 0, /* fileAction= */ file_action_grep, /* dirAction= */ NULL, - /* userData= */ &matched, - 0); + /* userData= */ &matched + ); return matched; } diff --git a/include/libbb.h b/include/libbb.h index 8b84d13a0..1b7c0b83a 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -441,10 +441,18 @@ enum { ACTION_DANGLING_OK = (1 << 5), }; typedef uint8_t recurse_flags_t; -extern int recursive_action(const char *fileName, unsigned flags, - int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), - int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), - void* userData, unsigned depth) FAST_FUNC; +typedef struct recursive_state { + unsigned flags; + unsigned depth; + void *userData; + int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf); + int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf); +} recursive_state_t; +int recursive_action(const char *fileName, unsigned flags, + int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), + int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), + void *userData +) FAST_FUNC; extern int device_open(const char *device, int mode) FAST_FUNC; enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */ diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 0831ecc3a..b1c4bfad7 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c @@ -21,10 +21,9 @@ * is so stinking huge. */ -static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, - struct stat *statbuf UNUSED_PARAM, - void* userData UNUSED_PARAM, - int depth UNUSED_PARAM) +static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM, + const char *fileName UNUSED_PARAM, + struct stat *statbuf UNUSED_PARAM) { return TRUE; } @@ -65,12 +64,7 @@ static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. */ -int FAST_FUNC recursive_action(const char *fileName, - unsigned flags, - int FAST_FUNC (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), - int FAST_FUNC (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), - void* userData, - unsigned depth) +static int recursive_action1(recursive_state_t *state, const char *fileName) { struct stat statbuf; unsigned follow; @@ -78,24 +72,21 @@ int FAST_FUNC recursive_action(const char *fileName, DIR *dir; struct dirent *next; - if (!fileAction) fileAction = true_action; - if (!dirAction) dirAction = true_action; - follow = ACTION_FOLLOWLINKS; - if (depth == 0) + if (state->depth == 0) follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; - follow &= flags; + follow &= state->flags; status = (follow ? stat : lstat)(fileName, &statbuf); if (status < 0) { #ifdef DEBUG_RECURS_ACTION - bb_error_msg("status=%d flags=%x", status, flags); + bb_error_msg("status=%d flags=%x", status, state->flags); #endif - if ((flags & ACTION_DANGLING_OK) + if ((state->flags & ACTION_DANGLING_OK) && errno == ENOENT && lstat(fileName, &statbuf) == 0 ) { /* Dangling link */ - return fileAction(fileName, &statbuf, userData, depth); + return state->fileAction(state, fileName, &statbuf); } goto done_nak_warn; } @@ -103,20 +94,20 @@ int FAST_FUNC recursive_action(const char *fileName, /* If S_ISLNK(m), then we know that !S_ISDIR(m). * Then we can skip checking first part: if it is true, then * (!dir) is also true! */ - if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */ + if ( /* (!(state->flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */ !S_ISDIR(statbuf.st_mode) ) { - return fileAction(fileName, &statbuf, userData, depth); + return state->fileAction(state, fileName, &statbuf); } /* It's a directory (or a link to one, and followLinks is set) */ - if (!(flags & ACTION_RECURSE)) { - return dirAction(fileName, &statbuf, userData, depth); + if (!(state->flags & ACTION_RECURSE)) { + return state->dirAction(state, fileName, &statbuf); } - if (!(flags & ACTION_DEPTHFIRST)) { - status = dirAction(fileName, &statbuf, userData, depth); + if (!(state->flags & ACTION_DEPTHFIRST)) { + status = state->dirAction(state, fileName, &statbuf); if (status == FALSE) goto done_nak_warn; if (status == SKIP) @@ -140,11 +131,13 @@ int FAST_FUNC recursive_action(const char *fileName, continue; /* process every file (NB: ACTION_RECURSE is set in flags) */ - s = recursive_action(nextFile, flags, fileAction, dirAction, - userData, depth + 1); + state->depth++; + s = recursive_action1(state, nextFile); if (s == FALSE) status = FALSE; free(nextFile); + state->depth--; + //#define RECURSE_RESULT_ABORT -1 // if (s == RECURSE_RESULT_ABORT) { // closedir(dir); @@ -153,15 +146,36 @@ int FAST_FUNC recursive_action(const char *fileName, } closedir(dir); - if (flags & ACTION_DEPTHFIRST) { - if (!dirAction(fileName, &statbuf, userData, depth)) + if (state->flags & ACTION_DEPTHFIRST) { + if (!state->dirAction(state, fileName, &statbuf)) goto done_nak_warn; } return status; done_nak_warn: - if (!(flags & ACTION_QUIET)) + if (!(state->flags & ACTION_QUIET)) bb_simple_perror_msg(fileName); return FALSE; } + +int FAST_FUNC recursive_action(const char *fileName, + unsigned flags, + int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), + int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf), + void *userData) +{ + /* Keeping a part of variables of recusive descent in a "state structure" + * instead of passing ALL of them down as parameters of recursive_action1() + * relieves register pressure, both in recursive_action1() + * and in every file/dirAction(). + */ + recursive_state_t state; + state.flags = flags; + state.depth = 0; + state.userData = userData; + state.fileAction = fileAction ? fileAction : true_action; + state.dirAction = dirAction ? dirAction : true_action; + + return recursive_action1(&state, fileName); +} diff --git a/modutils/depmod.c b/modutils/depmod.c index 318e7cdc7..bb42bbefe 100644 --- a/modutils/depmod.c +++ b/modutils/depmod.c @@ -32,10 +32,11 @@ * for each depends, look through our list of full paths and emit if found */ -static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, - void *data, int depth UNUSED_PARAM) +static int FAST_FUNC parse_module(struct recursive_state *state, + const char *fname, + struct stat *sb UNUSED_PARAM) { - module_db *modules = data; + module_db *modules = state->userData; char *image, *ptr; module_entry *e; @@ -201,11 +202,12 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) memset(&modules, 0, sizeof(modules)); if (*argv) { do { - parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0); + recursive_action(*argv, 0 /* no ACTION_RECURSE! */, + parse_module, NULL, &modules); } while (*++argv); } else { recursive_action(".", ACTION_RECURSE, - parse_module, NULL, &modules, 0); + parse_module, NULL, &modules); } /* Generate dependency and alias files */ diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index a94b0b9a6..18cfac481 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c @@ -751,8 +751,7 @@ static int process_module(char *name, const char *cmdline_options) ACTION_RECURSE, /* flags */ fileAction, /* file action */ NULL, /* dir action */ - name, /* user data */ - 0 /* depth */ + name /* user data */ ); dbg1_error_msg("dirscan complete"); /* Module was not found, or load failed, or is_remove */ diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 70c45903a..eeeff7609 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -235,10 +235,9 @@ static void add_probe(const char *name) } } -static int FAST_FUNC config_file_action(const char *filename, - struct stat *statbuf UNUSED_PARAM, - void *userdata UNUSED_PARAM, - int depth) +static int FAST_FUNC config_file_action(struct recursive_state *state, + const char *filename, + struct stat *statbuf UNUSED_PARAM) { char *tokens[3]; parser_t *p; @@ -255,7 +254,7 @@ static int FAST_FUNC config_file_action(const char *filename, * that we shouldn't recurse into /etc/modprobe.d/dir/ * _subdirectories_: */ - if (depth > 1) + if (state->depth > 1) return SKIP; /* stop recursing */ //TODO: instead, can use dirAction in recursive_action() to SKIP dirs //on depth == 1 level. But that's more code... @@ -264,7 +263,7 @@ static int FAST_FUNC config_file_action(const char *filename, * depth==0: read_config("modules.{symbols,alias}") must work, * "include FILE_NOT_ENDING_IN_CONF" must work too. */ - if (depth != 0) { + if (state->depth != 0) { if (!is_suffixed_with(base, ".conf")) goto error; } @@ -329,8 +328,7 @@ static int FAST_FUNC config_file_action(const char *filename, static int read_config(const char *path) { return recursive_action(path, ACTION_RECURSE | ACTION_QUIET, - config_file_action, NULL, NULL, - /*depth:*/ 0); + config_file_action, NULL, NULL); } static const char *humanly_readable_name(struct module_entry *m) diff --git a/networking/netstat.c b/networking/netstat.c index 936610f89..3ab7b0d21 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -272,10 +272,9 @@ static long extract_socket_inode(const char *lname) return inode; } -static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, - struct stat *statbuf UNUSED_PARAM, - void *pid_slash_progname, - int depth UNUSED_PARAM) +static int FAST_FUNC add_to_prg_cache_if_socket(struct recursive_state *state, + const char *fileName, + struct stat *statbuf UNUSED_PARAM) { char *linkname; long inode; @@ -284,16 +283,17 @@ static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, if (linkname != NULL) { inode = extract_socket_inode(linkname); free(linkname); - if (inode >= 0) - prg_cache_add(inode, (char *)pid_slash_progname); + if (inode >= 0) { + char *pid_slash_progname = state->userData; + prg_cache_add(inode, pid_slash_progname); + } } return TRUE; } -static int FAST_FUNC dir_act(const char *fileName, - struct stat *statbuf UNUSED_PARAM, - void *userData UNUSED_PARAM, - int depth) +static int FAST_FUNC dir_act(struct recursive_state *state, + const char *fileName, + struct stat *statbuf UNUSED_PARAM) { const char *pid; char *pid_slash_progname; @@ -301,7 +301,7 @@ static int FAST_FUNC dir_act(const char *fileName, char cmdline_buf[512]; int n, len; - if (depth == 0) /* "/proc" itself */ + if (state->depth == 0) /* "/proc" itself */ return TRUE; /* continue looking one level below /proc */ pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ @@ -321,8 +321,8 @@ static int FAST_FUNC dir_act(const char *fileName, ACTION_RECURSE | ACTION_QUIET, add_to_prg_cache_if_socket, NULL, - (void *)pid_slash_progname, - 0); + (void *)pid_slash_progname + ); free(pid_slash_progname); if (!n) @@ -337,7 +337,7 @@ static void prg_cache_load(void) prg_cache_loaded = 1; load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET, - NULL, dir_act, NULL, 0); + NULL, dir_act, NULL); if (load_ok) return; diff --git a/selinux/chcon.c b/selinux/chcon.c index afe7f713d..9b13679b8 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c @@ -62,11 +62,9 @@ static char *type = NULL; static char *range = NULL; static char *specified_context = NULL; -static int FAST_FUNC change_filedir_context( +static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED_PARAM, const char *fname, - struct stat *stbuf UNUSED_PARAM, - void *userData UNUSED_PARAM, - int depth UNUSED_PARAM) + struct stat *stbuf UNUSED_PARAM) { context_t context = NULL; security_context_t file_context = NULL; @@ -207,7 +205,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0), change_filedir_context, change_filedir_context, - NULL, 0) != TRUE) + NULL) != TRUE) errors = 1; } return errors; diff --git a/selinux/setfiles.c b/selinux/setfiles.c index 55bfb4d02..a617b95d8 100644 --- a/selinux/setfiles.c +++ b/selinux/setfiles.c @@ -463,11 +463,9 @@ static int restore(const char *file) * This function is called by recursive_action on each file during * the directory traversal. */ -static int FAST_FUNC apply_spec( +static int FAST_FUNC apply_spec(struct recursive_state *state UNUSED_PARAM, const char *file, - struct stat *sb, - void *userData UNUSED_PARAM, - int depth UNUSED_PARAM) + struct stat *sb) { if (!follow_mounts) { /* setfiles does not process across different mount points */ @@ -535,7 +533,7 @@ static int process_one(char *name) ACTION_RECURSE, apply_spec, apply_spec, - NULL, 0) != TRUE + NULL) != TRUE ) { bb_error_msg("error while labeling %s", name); goto err; diff --git a/util-linux/lspci.c b/util-linux/lspci.c index 2f0b5fab9..c22cbcc1e 100644 --- a/util-linux/lspci.c +++ b/util-linux/lspci.c @@ -37,11 +37,9 @@ enum { /* * PCI_SLOT_NAME PCI_CLASS: PCI_VID:PCI_DID [PCI_SUBSYS_VID:PCI_SUBSYS_DID] [DRIVER] */ -static int FAST_FUNC fileAction( +static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, const char *fileName, - struct stat *statbuf UNUSED_PARAM, - void *userData UNUSED_PARAM, - int depth UNUSED_PARAM) + struct stat *statbuf UNUSED_PARAM) { parser_t *parser; char *tokens[3]; @@ -117,8 +115,7 @@ int lspci_main(int argc UNUSED_PARAM, char **argv) ACTION_RECURSE, fileAction, NULL, /* dirAction */ - NULL, /* userData */ - 0 /* depth */); - + NULL /* userData */ + ); return EXIT_SUCCESS; } diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c index 64a00eee2..9abb748ce 100644 --- a/util-linux/lsusb.c +++ b/util-linux/lsusb.c @@ -24,11 +24,9 @@ #include "libbb.h" -static int FAST_FUNC fileAction( +static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, const char *fileName, - struct stat *statbuf UNUSED_PARAM, - void *userData UNUSED_PARAM, - int depth UNUSED_PARAM) + struct stat *statbuf UNUSED_PARAM) { parser_t *parser; char *tokens[4]; @@ -80,8 +78,8 @@ int lsusb_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) ACTION_RECURSE, fileAction, NULL, /* dirAction */ - NULL, /* userData */ - 0 /* depth */); + NULL /* userData */ + ); return EXIT_SUCCESS; } diff --git a/util-linux/mdev.c b/util-linux/mdev.c index f42bebc20..59dbcf0cd 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -845,13 +845,12 @@ static ssize_t readlink2(char *buf, size_t bufsize) /* File callback for /sys/ traversal. * We act only on "/sys/.../dev" (pseudo)file */ -static int FAST_FUNC fileAction(const char *fileName, - struct stat *statbuf UNUSED_PARAM, - void *userData, - int depth UNUSED_PARAM) +static int FAST_FUNC fileAction(struct recursive_state *state, + const char *fileName, + struct stat *statbuf UNUSED_PARAM) { size_t len = strlen(fileName) - 4; /* can't underflow */ - char *path = userData; /* char array[PATH_MAX + SCRATCH_SIZE] */ + char *path = state->userData; /* char array[PATH_MAX + SCRATCH_SIZE] */ char subsys[PATH_MAX]; int res; @@ -888,12 +887,11 @@ static int FAST_FUNC fileAction(const char *fileName, } /* Directory callback for /sys/ traversal */ -static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, - struct stat *statbuf UNUSED_PARAM, - void *userData UNUSED_PARAM, - int depth) +static int FAST_FUNC dirAction(struct recursive_state *state, + const char *fileName UNUSED_PARAM, + struct stat *statbuf UNUSED_PARAM) { - return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); + return (state->depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); } /* For the full gory details, see linux/Documentation/firmware_class/README @@ -1149,7 +1147,7 @@ static void initial_scan(char *temp) /* Create all devices from /sys/dev hierarchy */ recursive_action("/sys/dev", ACTION_RECURSE | ACTION_FOLLOWLINKS, - fileAction, dirAction, temp, 0); + fileAction, dirAction, temp); } #if ENABLE_FEATURE_MDEV_DAEMON diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index 34f5d119f..00cfb2826 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c @@ -102,10 +102,9 @@ uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uu * add a cache entry for this device. * If device node does not exist, it will be temporarily created. */ static int FAST_FUNC -uuidcache_check_device(const char *device, - struct stat *statbuf, - void *userData UNUSED_PARAM, - int depth UNUSED_PARAM) +uuidcache_check_device(struct recursive_state *state UNUSED_PARAM, + const char *device, + struct stat *statbuf) { /* note: this check rejects links to devices, among other nodes */ if (!S_ISBLK(statbuf->st_mode) @@ -145,12 +144,13 @@ uuidcache_init(int scan_devices) * This is unacceptably complex. Let's just scan /dev. * (Maybe add scanning of /sys/block/XXX/dev for devices * somehow not having their /dev/XXX entries created?) */ - if (scan_devices) + if (scan_devices) { recursive_action("/dev", ACTION_RECURSE, uuidcache_check_device, /* file_action */ NULL, /* dir_action */ - NULL, /* userData */ - 0 /* depth */); + NULL /* userData */ + ); + } return uuidCache; } -- cgit v1.2.3-55-g6feb From 2496616b0a8d1c80cd1416b73a4847b59b9f969a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Oct 2020 02:36:47 +0200 Subject: avoid using strok - eliminates use of hidden global variable function old new delta udhcp_str2optset 616 650 +34 setpriv_main 950 975 +25 switch_root_main 688 706 +18 parse 958 970 +12 getopt_main 622 628 +6 parse_resolvconf 302 306 +4 mpstat_main 1139 1142 +3 static.p 4 - -4 cdcmd 717 702 -15 strtok 148 - -148 ------------------------------------------------------------------------------ (add/remove: 0/3 grow/shrink: 7/1 up/down: 102/-167) Total: -65 bytes Signed-off-by: Denys Vlasenko --- libbb/kernel_version.c | 20 +++++++++++--------- libbb/update_passwd.c | 15 +++++++++------ mailutils/reformime.c | 5 +++-- networking/nslookup.c | 5 +++-- networking/udhcp/common.c | 10 +++++----- procps/mpstat.c | 2 +- shell/ash.c | 4 ++-- util-linux/getopt.c | 5 +++-- util-linux/mount.c | 3 ++- util-linux/setpriv.c | 9 +++++---- util-linux/switch_root.c | 4 ++-- 11 files changed, 46 insertions(+), 36 deletions(-) (limited to 'libbb') diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c index 7769a091b..6bb32ce5f 100644 --- a/libbb/kernel_version.c +++ b/libbb/kernel_version.c @@ -19,15 +19,17 @@ int FAST_FUNC get_linux_version_code(void) { struct utsname name; char *t; - int i, r; + int r; uname(&name); /* never fails */ - t = name.release; - r = 0; - for (i = 0; i < 3; i++) { - t = strtok(t, "."); - r = r * 256 + (t ? atoi(t) : 0); - t = NULL; - } - return r; + t = name.release - 1; + r = 1; + do { + r <<= 8; + if (t) { + r += atoi(++t); + t = strchr(t, '.'); + } + } while (r < 0x1000000); + return r - 0x1000000; } diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c index c605c4c64..7b67f30cd 100644 --- a/libbb/update_passwd.c +++ b/libbb/update_passwd.c @@ -18,17 +18,20 @@ #if ENABLE_SELINUX static void check_selinux_update_passwd(const char *username) { - security_context_t context; - char *seuser; + security_context_t seuser; + char *p; if (getuid() != (uid_t)0 || is_selinux_enabled() == 0) return; /* No need to check */ - if (getprevcon_raw(&context) < 0) + if (getprevcon_raw(&seuser) < 0) bb_simple_perror_msg_and_die("getprevcon failed"); - seuser = strtok(context, ":"); - if (!seuser) - bb_error_msg_and_die("invalid context '%s'", context); + + p = strchr(seuser, ':'); + if (!p) + bb_error_msg_and_die("invalid context '%s'", seuser); + *p = '\0'; + if (strcmp(seuser, username) != 0) { security_class_t tclass; access_vector_t av; diff --git a/mailutils/reformime.c b/mailutils/reformime.c index 321729e0a..307656a15 100644 --- a/mailutils/reformime.c +++ b/mailutils/reformime.c @@ -115,6 +115,7 @@ static int parse(const char *boundary, char **argv) /* Split to tokens */ { char *s, *p; + char *tokstate; unsigned ntokens; const char *delims = ";=\" \t\n"; @@ -127,13 +128,13 @@ static int parse(const char *boundary, char **argv) } dbg_error_msg("L:'%s'", p); ntokens = 0; - s = strtok(s, delims); + s = strtok_r(s, delims, &tokstate); while (s) { tokens[ntokens] = s; if (ntokens < ARRAY_SIZE(tokens) - 1) ntokens++; dbg_error_msg("L[%d]='%s'", ntokens, s); - s = strtok(NULL, delims); + s = strtok_r(NULL, delims, &tokstate); } tokens[ntokens] = NULL; dbg_error_msg("EMPTYLINE, ntokens:%d", ntokens); diff --git a/networking/nslookup.c b/networking/nslookup.c index c43e60558..759de5c83 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c @@ -703,12 +703,13 @@ static void parse_resolvconf(void) while (fgets(line, sizeof(line), resolv)) { char *p, *arg; + char *tokstate; - p = strtok(line, " \t\n"); + p = strtok_r(line, " \t\n", &tokstate); if (!p) continue; dbg("resolv_key:'%s'\n", p); - arg = strtok(NULL, "\n"); + arg = strtok_r(NULL, "\n", &tokstate); dbg("resolv_arg:'%s'\n", arg); if (!arg) continue; diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 20d843bab..4bc719001 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -526,7 +526,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, /* Cheat, the only *const* str possible is "" */ str = (char *) const_str; - opt = strtok(str, " \t=:"); + opt = strtok_r(str, " \t=:", &str); if (!opt) return 0; @@ -550,10 +550,10 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, char *val; if (optflag->flags == OPTION_BIN) { - val = strtok(NULL, ""); /* do not split "'q w e'" */ + val = strtok_r(NULL, "", &str); /* do not split "'q w e'" */ if (val) trim(val); } else - val = strtok(NULL, ", \t"); + val = strtok_r(NULL, ", \t", &str); if (!val) break; @@ -567,7 +567,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, break; case OPTION_IP_PAIR: retval = udhcp_str2nip(val, buffer); - val = strtok(NULL, ", \t/-"); + val = strtok_r(NULL, ", \t/-", &str); if (!val) retval = 0; if (retval) @@ -631,7 +631,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, *slash = '\0'; retval = udhcp_str2nip(val, buffer + 1); buffer[0] = mask = bb_strtou(slash + 1, NULL, 10); - val = strtok(NULL, ", \t/-"); + val = strtok_r(NULL, ", \t/-", &str); if (!val || mask > 32 || errno) retval = 0; if (retval) { diff --git a/procps/mpstat.c b/procps/mpstat.c index 52a436a55..c78c1f0a0 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c @@ -923,7 +923,7 @@ int mpstat_main(int argc UNUSED_PARAM, char **argv) char *t; G.p_option = 1; - for (t = strtok(opt_set_cpu, ","); t; t = strtok(NULL, ",")) { + for (t = strtok_r(opt_set_cpu, ",", &opt_set_cpu); t; t = strtok_r(NULL, ",", &opt_set_cpu)) { if (strcmp(t, "ALL") == 0) { /* Select every CPU */ memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len); diff --git a/shell/ash.c b/shell/ash.c index 07aa2da2e..58da0a2a0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2770,7 +2770,7 @@ updatepwd(const char *dir) lim++; } } - p = strtok(cdcomppath, "/"); + p = strtok_r(cdcomppath, "/", &cdcomppath); while (p) { switch (*p) { case '.': @@ -2789,7 +2789,7 @@ updatepwd(const char *dir) new = stack_putstr(p, new); USTPUTC('/', new); } - p = strtok(NULL, "/"); + p = strtok_r(NULL, "/", &cdcomppath); } if (new > lim) STUNPUTC(new); diff --git a/util-linux/getopt.c b/util-linux/getopt.c index db7db6ff8..1fa402429 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c @@ -289,12 +289,13 @@ static struct option *add_long_options(struct option *long_options, char *option { int long_nr = 0; int arg_opt, tlen; - char *tokptr = strtok(options, ", \t\n"); + char *tokptr; if (long_options) while (long_options[long_nr].name) long_nr++; + tokptr = strtok_r(options, ", \t\n", &options); while (tokptr) { arg_opt = no_argument; tlen = strlen(tokptr); @@ -318,7 +319,7 @@ static struct option *add_long_options(struct option *long_options, char *option long_nr++; /*memset(&long_options[long_nr], 0, sizeof(long_options[0])); - xrealloc_vector did it */ } - tokptr = strtok(NULL, ", \t\n"); + tokptr = strtok_r(NULL, ", \t\n", &options); } return long_options; } diff --git a/util-linux/mount.c b/util-linux/mount.c index 19ac13930..fc5161d7f 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1230,6 +1230,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi * then data pointer is interpreted as a string. */ struct nfs_mount_data data; char *opt; + char *tokstate; struct hostent *hp; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; @@ -1348,7 +1349,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi nfsvers = 0; /* parse options */ - if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { + if (filteropts) for (opt = strtok_r(filteropts, ",", &tokstate); opt; opt = strtok_r(NULL, ",", &tokstate)) { char *opteq = strchr(opt, '='); if (opteq) { int val, idx; diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c index 37e8821a1..1e4b201ed 100644 --- a/util-linux/setpriv.c +++ b/util-linux/setpriv.c @@ -144,10 +144,11 @@ static unsigned parse_cap(const char *cap) static void set_inh_caps(char *capstring) { struct caps caps; + char *string; getcaps(&caps); - capstring = strtok(capstring, ","); + capstring = strtok_r(capstring, ",", &string); while (capstring) { unsigned cap; @@ -159,7 +160,7 @@ static void set_inh_caps(char *capstring) caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); else caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap); - capstring = strtok(NULL, ","); + capstring = strtok_r(NULL, ",", &string); } if (capset(&caps.header, caps.data) != 0) @@ -170,7 +171,7 @@ static void set_ambient_caps(char *string) { char *cap; - cap = strtok(string, ","); + cap = strtok_r(string, ",", &string); while (cap) { unsigned idx; @@ -182,7 +183,7 @@ static void set_ambient_caps(char *string) if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, idx, 0, 0) < 0) bb_simple_perror_msg("cap_ambient_lower"); } - cap = strtok(NULL, ","); + cap = strtok_r(NULL, ",", &string); } } #endif /* FEATURE_SETPRIV_CAPABILITIES */ diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index c65096c27..f2674b5ac 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -164,7 +164,7 @@ static void drop_capabilities(char *string) { char *cap; - cap = strtok(string, ","); + cap = strtok_r(string, ",", &string); while (cap) { unsigned cap_idx; @@ -174,7 +174,7 @@ static void drop_capabilities(char *string) drop_bounding_set(cap_idx); drop_capset(cap_idx); bb_error_msg("dropped capability: %s", cap); - cap = strtok(NULL, ","); + cap = strtok_r(NULL, ",", &string); } } #endif -- cgit v1.2.3-55-g6feb From dac5b8314236338963877903cba3d7edfbfc9c58 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Oct 2020 18:54:36 +0200 Subject: xxd: fix printing of trailing spaces function old new delta bb_dump_dump 1497 1523 +26 xxd_main 459 466 +7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 33/0) Total: 33 bytes Signed-off-by: Denys Vlasenko --- include/dump.h | 39 ++------------------ libbb/dump.c | 93 ++++++++++++++++++++++++++++++++++++------------ testsuite/xxd.tests | 34 ++++++++++++++++++ util-linux/hexdump_xxd.c | 1 + 4 files changed, 108 insertions(+), 59 deletions(-) create mode 100755 testsuite/xxd.tests (limited to 'libbb') diff --git a/include/dump.h b/include/dump.h index 4c237ef05..f4759c193 100644 --- a/include/dump.h +++ b/include/dump.h @@ -2,50 +2,15 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -#define F_IGNORE 0x01 /* %_A */ -#define F_SETREP 0x02 /* rep count set, not default */ -#define F_ADDRESS 0x001 /* print offset */ -#define F_BPAD 0x002 /* blank pad */ -#define F_C 0x004 /* %_c */ -#define F_CHAR 0x008 /* %c */ -#define F_DBL 0x010 /* %[EefGf] */ -#define F_INT 0x020 /* %[di] */ -#define F_P 0x040 /* %_p */ -#define F_STR 0x080 /* %s */ -#define F_U 0x100 /* %_u */ -#define F_UINT 0x200 /* %[ouXx] */ -#define F_TEXT 0x400 /* no conversions */ - enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ -typedef struct PR { - struct PR *nextpr; /* next print unit */ - unsigned flags; /* flag values */ - int bcnt; /* byte count */ - char *cchar; /* conversion character */ - char *fmt; /* printf format */ - char *nospace; /* no whitespace version */ -} PR; - -typedef struct FU { - struct FU *nextfu; /* next format unit */ - struct PR *nextpr; /* next print unit */ - unsigned flags; /* flag values */ - int reps; /* repetition count */ - int bcnt; /* byte count */ - char *fmt; /* format string */ -} FU; - -typedef struct FS { /* format strings */ - struct FS *nextfs; /* linked list of format strings */ - struct FU *nextfu; /* linked list of format units */ - int bcnt; -} FS; +typedef struct FS FS; typedef struct dumper_t { off_t dump_skip; /* bytes to skip */ int dump_length; /* max bytes to read */ smallint dump_vflag; /*enum dump_vflag_t*/ + const char *eofstring; FS *fshead; } dumper_t; diff --git a/libbb/dump.c b/libbb/dump.c index 8029cca0e..920f003ef 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -13,13 +13,43 @@ #include "libbb.h" #include "dump.h" -static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; - -static const char size_conv_str[] ALIGN1 = -"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; - -static const char int_convs[] ALIGN1 = "diouxX"; - +#define F_IGNORE 0x01 /* %_A */ +#define F_SETREP 0x02 /* rep count set, not default */ +#define F_ADDRESS 0x001 /* print offset */ +#define F_BPAD 0x002 /* blank pad */ +#define F_C 0x004 /* %_c */ +#define F_CHAR 0x008 /* %c */ +#define F_DBL 0x010 /* %[EefGf] */ +#define F_INT 0x020 /* %[di] */ +#define F_P 0x040 /* %_p */ +#define F_STR 0x080 /* %s */ +#define F_U 0x100 /* %_u */ +#define F_UINT 0x200 /* %[ouXx] */ +#define F_TEXT 0x400 /* no conversions */ + +typedef struct PR { + struct PR *nextpr; /* next print unit */ + unsigned flags; /* flag values */ + int bcnt; /* byte count */ + char *cchar; /* conversion character */ + char *fmt; /* printf format */ + char *nospace; /* no whitespace version */ +} PR; + +typedef struct FU { + struct FU *nextfu; /* next format unit */ + struct PR *nextpr; /* next print unit */ + unsigned flags; /* flag values */ + int reps; /* repetition count */ + int bcnt; /* byte count */ + char *fmt; /* format string */ +} FU; + +typedef struct FS { /* format strings */ + struct FS *nextfs; /* linked list of format strings */ + struct FU *nextfu; /* linked list of format units */ + int bcnt; +} FS; typedef struct priv_dumper_t { dumper_t pub; @@ -39,6 +69,13 @@ typedef struct priv_dumper_t { unsigned char *get__savp; } priv_dumper_t; +static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; + +static const char size_conv_str[] ALIGN1 = +"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; + +static const char int_convs[] ALIGN1 = "diouxX"; + dumper_t* FAST_FUNC alloc_dumper(void) { priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); @@ -48,7 +85,6 @@ dumper_t* FAST_FUNC alloc_dumper(void) return &dumper->pub; } - static NOINLINE int bb_dump_size(FS *fs) { FU *fu; @@ -284,7 +320,9 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * repeat it as necessary. * * if rep count is greater than 1, no trailing whitespace - * gets output from the last iteration of the format unit. + * gets output from the last iteration of the format unit: + * 2/1 "%02x " prints "XX XX", not "XX XX " + * 2/1 "%02x\n" prints "XX\nXX", not "XX\nXX\n" */ for (fu = fs->nextfu; fu; fu = fu->nextfu) { if (!fu->nextfu @@ -453,7 +491,7 @@ static void bpad(PR *pr) for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1) if (pr->nospace) pr->nospace--; - while ((*p2++ = *p1++) != 0) + while ((*p2++ = *p1++) != '\0') continue; } @@ -520,36 +558,43 @@ static void conv_u(PR *pr, unsigned char *p) static void display(priv_dumper_t* dumper) { - FS *fs; - FU *fu; - PR *pr; - int cnt; - unsigned char *bp, *savebp; - off_t saveaddress; + unsigned char *bp; unsigned char savech = '\0'; while ((bp = get(dumper)) != NULL) { + FS *fs; + unsigned char *savebp; + off_t saveaddress; + fs = dumper->pub.fshead; savebp = bp; saveaddress = dumper->address; for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { + FU *fu; for (fu = fs->nextfu; fu; fu = fu->nextfu) { + int cnt; if (fu->flags & F_IGNORE) { break; } for (cnt = fu->reps; cnt; --cnt) { + PR *pr; for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, bp += pr->bcnt, pr = pr->nextpr) { - if (dumper->eaddress && dumper->address >= dumper->eaddress - && !(pr->flags & (F_TEXT | F_BPAD)) + if (dumper->eaddress + && dumper->address >= dumper->eaddress ) { - bpad(pr); + if (dumper->pub.eofstring) { + /* xxd support: requested to not pad incomplete blocks */ + fputs(dumper->pub.eofstring, stdout); + return; + } + if (!(pr->flags & (F_TEXT | F_BPAD))) + bpad(pr); } if (cnt == 1 && pr->nospace) { savech = *pr->nospace; *pr->nospace = '\0'; } -/* PRINT; */ switch (pr->flags) { case F_ADDRESS: printf(pr->fmt, (unsigned) dumper->address); @@ -638,7 +683,9 @@ static void display(priv_dumper_t* dumper) } } } + if (dumper->endfu) { + PR *pr; /* * if eaddress not set, error or file size was multiple * of blocksize, and no partial block ever found. @@ -695,8 +742,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) { const char *p; FS *tfs; - FU *tfu, **nextfupp; - const char *savep; + FU **nextfupp; /* start new linked list of format units */ tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */ @@ -713,6 +759,9 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* take the format string and break it up into format units */ p = fmt; for (;;) { + FU *tfu; + const char *savep; + p = skip_whitespace(p); if (*p == '\0') { break; diff --git a/testsuite/xxd.tests b/testsuite/xxd.tests new file mode 100755 index 000000000..2e80be5fe --- /dev/null +++ b/testsuite/xxd.tests @@ -0,0 +1,34 @@ +#!/bin/sh + +# Copyright 2020 by Denys Vlasenko +# Licensed under GPLv2, see file LICENSE in this source tree. + +. ./testing.sh + +# testing "description" "command" "result" "infile" "stdin" +testing 'xxd -p with one NUL' \ + 'xxd -p' \ + "\ +00 +" \ + '' \ + '\0' + +testing 'xxd -p with 30 NULs' \ + 'xxd -p' \ + "\ +000000000000000000000000000000000000000000000000000000000000 +" \ + '' \ + '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' + +testing 'xxd -p with 31 NULs' \ + 'xxd -p' \ + "\ +000000000000000000000000000000000000000000000000000000000000 +00 +" \ + '' \ + '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' + +exit $FAILCOUNT diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 6cf6d0297..f2d1ecb2c 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c @@ -141,6 +141,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) bb_dump_add(dumper, buf); } else { bb_dump_add(dumper, "\"\n\""); + dumper->eofstring = "\n"; } return bb_dump_dump(dumper, argv); -- cgit v1.2.3-55-g6feb From 079487b48724d936b31a6696ae0f929b0251eaa3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Oct 2020 19:26:52 +0200 Subject: hexdump: fix dup block comparison function old new delta bb_dump_dump 1523 1520 -3 Signed-off-by: Denys Vlasenko --- libbb/dump.c | 1 - testsuite/hexdump.tests | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/dump.c b/libbb/dump.c index 920f003ef..7a07d6605 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -432,7 +432,6 @@ static unsigned char *get(priv_dumper_t *dumper) if (dumper->pub.dump_vflag != DUP) { puts("*"); } - return NULL; } memset(dumper->get__curp + nread, 0, need); dumper->eaddress = dumper->address + nread; diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests index 45a0c1300..cfb20187e 100755 --- a/testsuite/hexdump.tests +++ b/testsuite/hexdump.tests @@ -15,4 +15,23 @@ testing 'hexdump -C with four NULs' \ '' \ '\0\0\0\0' +testing "hexdump does not think last padded block matches any full block" \ + "hexdump -e '1/1 \"%02x|\"1/1 \"%02x!\\n\"'" \ + "\ +00|00! +* +00| ! +" \ + '' \ + '\0\0\0\0\0\0\0\0\0\0\0' + +testing "hexdump thinks last full block can match" \ + "hexdump -e '1/1 \"%02x|\"1/1 \"%02x!\\n\"'" \ + "\ +00|00! +* +" \ + '' \ + '\0\0\0\0\0\0\0\0\0\0\0\0' + exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 112453acf24520b4655f9f36da41d8ac591b1a60 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 25 Oct 2020 23:44:22 +0100 Subject: od: unbreak it Signed-off-by: Denys Vlasenko --- include/dump.h | 24 +++++++++++++++++++++++- libbb/dump.c | 24 ------------------------ 2 files changed, 23 insertions(+), 25 deletions(-) (limited to 'libbb') diff --git a/include/dump.h b/include/dump.h index f4759c193..9193a6925 100644 --- a/include/dump.h +++ b/include/dump.h @@ -4,7 +4,29 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ -typedef struct FS FS; +typedef struct PR { + struct PR *nextpr; /* next print unit */ + unsigned flags; /* flag values */ + int bcnt; /* byte count */ + char *cchar; /* conversion character */ + char *fmt; /* printf format */ + char *nospace; /* no whitespace version */ +} PR; + +typedef struct FU { + struct FU *nextfu; /* next format unit */ + struct PR *nextpr; /* next print unit */ + unsigned flags; /* flag values */ + int reps; /* repetition count */ + int bcnt; /* byte count */ + char *fmt; /* format string */ +} FU; + +typedef struct FS { /* format strings */ + struct FS *nextfs; /* linked list of format strings */ + struct FU *nextfu; /* linked list of format units */ + int bcnt; +} FS; typedef struct dumper_t { off_t dump_skip; /* bytes to skip */ diff --git a/libbb/dump.c b/libbb/dump.c index 7a07d6605..1ba1132b3 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -27,30 +27,6 @@ #define F_UINT 0x200 /* %[ouXx] */ #define F_TEXT 0x400 /* no conversions */ -typedef struct PR { - struct PR *nextpr; /* next print unit */ - unsigned flags; /* flag values */ - int bcnt; /* byte count */ - char *cchar; /* conversion character */ - char *fmt; /* printf format */ - char *nospace; /* no whitespace version */ -} PR; - -typedef struct FU { - struct FU *nextfu; /* next format unit */ - struct PR *nextpr; /* next print unit */ - unsigned flags; /* flag values */ - int reps; /* repetition count */ - int bcnt; /* byte count */ - char *fmt; /* format string */ -} FU; - -typedef struct FS { /* format strings */ - struct FS *nextfs; /* linked list of format strings */ - struct FU *nextfu; /* linked list of format units */ - int bcnt; -} FS; - typedef struct priv_dumper_t { dumper_t pub; -- cgit v1.2.3-55-g6feb