logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 92efecb5fe4e6cad6b7c34e2e46e6f90d215e220
parent 47364622bed691918f9ad10aaf65de7410847ea4
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Mon, 28 Jul 2025 07:43:05 +0200

cmd/strings: use fwrite for resulting string

Which is still more efficient than a direct write(2)/writev(2)
call due to real binaries having lots of short strings so buffering helps.

Also insert delim at the end so writes can more easily be 4K aligned
and save some syscalls.

Prior version:
    $ strace -cw strings /bin/node >/dev/null
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     58.73    0.166938          11     14510           read
     41.19    0.117061           6     16789           writev
      0.06    0.000163         163         1           execve
      0.01    0.000020          20         1           open
      0.00    0.000014          13         1           set_tid_address
      0.00    0.000012          11         1         1 ioctl
      0.00    0.000010           9         1           close
      0.00    0.000008           7         1           arch_prctl
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.284226           9     31305         1 total
    $ /bin/time strings /bin/node >/dev/null
    real 0.240000
    user 0.155336
    sys 0.084182

With direct writev(2):
    $ strace -cw ./cmd/strings /bin/node >/dev/null
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     94.49    2.924822           6    436496           writev
      5.50    0.170349          11     14510           read
      0.01    0.000171         171         1           execve
      0.00    0.000016          15         1           open
      0.00    0.000010          10         1           close
      0.00    0.000008           7         1           arch_prctl
      0.00    0.000007           7         1           set_tid_address
    ------ ----------- ----------- --------- --------- ----------------
    100.00    3.095384           6    451011           total
    $ time ./cmd/strings /bin/node >/dev/null
    0m00.33s real     0m00.15s user     0m00.18s system

With this commit:
    $ strace -cw ./cmd/strings /bin/node >/dev/null
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     59.17    0.159342          10     14510           read
     40.76    0.109777           6     16417           writev
      0.06    0.000151         150         1           execve
      0.01    0.000016          15         1           open
      0.00    0.000008           8         1           close
      0.00    0.000008           7         1         1 ioctl
      0.00    0.000007           7         1           arch_prctl
      0.00    0.000007           7         1           set_tid_address
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.269316           8     30933         1 total
    $ /bin/time ./cmd/strings /bin/node >/dev/null
    real 0.170000
    user 0.105422
    sys 0.066265

Diffstat:

Mcmd/strings.c42++++++++++++++++++++----------------------
1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/cmd/strings.c b/cmd/strings.c @@ -20,29 +20,23 @@ const char *opt_offset_format = NULL; char delim = '\n'; static int -print_string(char *buffer, size_t offset) +print_string(char *buffer, size_t buflen, size_t offset) { int ret = 0; + int wrote = 0; - if(opt_offset_format == NULL) + if(opt_offset_format) { - ret = printf("%s%c", buffer, delim); - } - else - { - ret = printf(opt_offset_format, offset, buffer, delim); + ret = printf(opt_offset_format, offset); + if(ret < 0) return ret; + wrote += ret; } - if(ret < 0) - { - fprintf(stderr, "strings: error: Failed writing: %s\n", strerror(errno)); - errno = 0; - return 1; - } - else - { - return 0; - } + ret = fwrite(buffer, buflen, 1, stdout); + if(ret < 0) return ret; + wrote += ret; + + return wrote; } static int @@ -71,8 +65,12 @@ concat(int fd, const char *fdname) if(write_pos >= opt_min_strlen) { - write_buf[write_pos] = '\0'; - if(print_string(write_buf, offset) != 0) return 1; + write_buf[write_pos] = delim; + if(print_string(write_buf, write_pos+1, offset) < 0) + { + fprintf(stderr, "strings: error: Failed writing resulting string: %s\n", strerror(errno)); + return 1; + } } offset += write_pos; @@ -145,13 +143,13 @@ main(int argc, char *argv[]) switch(optarg[0]) { case 'o': - opt_offset_format = "%zo %s%c"; + opt_offset_format = "%zo "; break; case 'x': - opt_offset_format = "%zx %s%c"; + opt_offset_format = "%zx "; break; case 'd': - opt_offset_format = "%zd %s%c"; + opt_offset_format = "%zd "; break; default: fprintf(stderr, "strings: error: Unknown format: %s\n", optarg);