commit e9ea73a
xplshn
·
2026-06-21 01:40:35 +0000 UTC
parent ea91416
lsblk, fdisk, blkid and updated manpages Signed-off-by: xplshn <anto@xplshn.com.ar>
119 files changed,
+2503,
-871
M
Makefile
+30,
-0
1@@ -0,0 +1,30 @@
2+# object files and static/shared libs
3+*.o
4+*.a
5+*.so
6+
7+# awk generated sources
8+cmd/posix/awk/awkgram.tab.c
9+cmd/posix/awk/awkgram.tab.h
10+cmd/posix/awk/proctab.c
11+cmd/posix/awk/maketab
12+
13+# sh generated sources and host generators
14+cmd/posix/sh/syntax.c
15+cmd/posix/sh/syntax.h
16+cmd/posix/sh/nodes.c
17+cmd/posix/sh/nodes.h
18+cmd/posix/sh/builtins.c
19+cmd/posix/sh/builtins.h
20+cmd/posix/sh/token.h
21+cmd/posix/sh/mknodes
22+cmd/posix/sh/mksyntax
23+
24+# other generated sources
25+cmd/posix/getconf.h
26+cmd/posix/bc.c
27+
28+# cmd/dev toolchain: configure output (regenerated by ./cmd/dev/configure)
29+cmd/dev/config.h
30+cmd/dev/cc/config.h
31+cmd/dev/version.h
M
Makefile
+66,
-23
1@@ -102,7 +102,8 @@ LIBUTILOBJ =\
2 shared/libutil/sig.o\
3 shared/libutil/net.o\
4 shared/libutil/sysinfo.o\
5- shared/libutil/tls.o
6+ shared/libutil/tls.o\
7+ shared/libutil/diskutil.o
8
9 LIBREDLINEOBJ =\
10 shared/libredline/redline.o
11@@ -272,6 +273,9 @@ PSEUDO_BIN_ALL =\
12 cmd/pseudo/yes\
13 cmd/pseudo/base64\
14 cmd/extra/b3sum\
15+ cmd/extra/blkid\
16+ cmd/extra/lsblk\
17+ cmd/extra/fdisk\
18 cmd/dev/ar/ar\
19 cmd/dev/as/as\
20 cmd/dev/ld/ld\
21@@ -448,6 +452,9 @@ BIN_xinstall_1 = cmd/pseudo/xinstall
22 BIN_yes_1 = cmd/pseudo/yes
23 BIN_base64_1 = cmd/pseudo/base64
24 BIN_b3sum_1 = cmd/extra/b3sum
25+BIN_blkid_1 = cmd/extra/blkid
26+BIN_lsblk_1 = cmd/extra/lsblk
27+BIN_fdisk_1 = cmd/extra/fdisk
28 BIN_ar_1 = cmd/dev/ar/ar
29 BIN_as_1 = cmd/dev/as/as
30 BIN_ld_1 = cmd/dev/ld/ld
31@@ -622,6 +629,9 @@ PSEUDO_BIN = \
32 $(BIN_yes_$(BUILD_PSEUDO_YES)) \
33 $(BIN_base64_$(BUILD_PSEUDO_BASE64)) \
34 $(BIN_b3sum_$(BUILD_PSEUDO_B3SUM)) \
35+ $(BIN_blkid_$(BUILD_PSEUDO_BLKID)) \
36+ $(BIN_lsblk_$(BUILD_PSEUDO_LSBLK)) \
37+ $(BIN_fdisk_$(BUILD_PSEUDO_FDISK)) \
38 $(BIN_ar_$(BUILD_DEV_AR)) \
39 $(BIN_as_$(BUILD_DEV_CC)) \
40 $(BIN_ld_$(BUILD_DEV_LD)) \
41@@ -693,14 +703,16 @@ man: scripts/mkman/mkman
42 if [ -f "$$src" ] && grep -qE '!man|\?man' "$$src"; then \
43 base=$$(basename $$src .c); \
44 mkdir -p man/man1; \
45- scripts/mkman/mkman -config config.mk -section 1 "$$src" > "man/man1/$$base.1"; \
46+ scripts/mkman/mkman -fmt mdoc -config config.mk -section 1 "$$src" > "man/man1/$$base.1"; \
47+ scripts/mkman/mkman -fmt txt -config config.mk -section 1 "$$src" > "man/man1/$$base.1.txt"; \
48 fi; \
49 done
50 @for src in $(LINUX_BIN_ALL:=.c) $(NET_BIN_ALL:=.c) $(XSI_BIN_ALL:=.c); do \
51 if [ -f "$$src" ] && grep -qE '!man|\?man' "$$src"; then \
52 base=$$(basename $$src .c); \
53 mkdir -p man/man8; \
54- scripts/mkman/mkman -config config.mk -section 8 "$$src" > "man/man8/$$base.8"; \
55+ scripts/mkman/mkman -fmt mdoc -config config.mk -section 8 "$$src" > "man/man8/$$base.8"; \
56+ scripts/mkman/mkman -fmt txt -config config.mk -section 8 "$$src" > "man/man8/$$base.8.txt"; \
57 fi; \
58 done
59
60@@ -708,13 +720,14 @@ clean:
61 rm -f shared/libutf/*.o shared/libutil/*.o shared/libredline/*.o
62 rm -f cmd/posix/*.o cmd/posix/make/*.o cmd/posix/awk/*.o cmd/posix/sh/*.o
63 rm -f cmd/linux/*.o cmd/net/*.o cmd/xsi/*.o cmd/pseudo/*.o
64- rm -f cmd/extra/*.o cmd/dev/ar/*.o cmd/dev/ld/*.o cmd/dev/cc/*.o cmd/dev/as/*.o
65+ rm -f cmd/extra/*.o cmd/dev/ar/*.o cmd/dev/ld/*.o cmd/dev/cc/*.o cmd/dev/as/*.o cmd/dev/xcutil/*.o
66 rm -f $(POSIX_BIN_ALL) $(LINUX_BIN_ALL) $(NET_BIN_ALL) $(XSI_BIN_ALL) $(PSEUDO_BIN_ALL) $(LIB)
67 rm -f cmd/posix/make/make cmd/posix/getconf.h cmd/posix/bc.c
68 rm -f cmd/posix/awk/awk cmd/posix/awk/maketab cmd/posix/awk/awkgram.tab.c cmd/posix/awk/awkgram.tab.h cmd/posix/awk/proctab.c
69 rm -f cmd/posix/sh/sh cmd/posix/sh/mknodes cmd/posix/sh/mksyntax
70 rm -f cmd/posix/sh/syntax.c cmd/posix/sh/syntax.h cmd/posix/sh/nodes.c cmd/posix/sh/nodes.h cmd/posix/sh/builtins.c cmd/posix/sh/builtins.h cmd/posix/sh/token.h
71- rm -f cmd/dev/cc/cc1 cmd/dev/cc/cpp cmd/dev/as/as shared/libaruuelf.so
72+ rm -f cmd/dev/cc/cc1 cmd/dev/cc/cpp cmd/dev/as/as cmd/dev/ld/ld cmd/dev/ar/ar shared/libaruuelf.so
73+ rm -f cmd/dev/config.h cmd/dev/cc/config.h cmd/dev/version.h
74 rm -rf aruu-box .box man/man1 man/man8 scripts/mkman/mkman
75
76 AWKOBJ =\
77@@ -814,41 +827,70 @@ cmd/posix/sh/%.o: cmd/posix/sh/%.c
78 cmd/posix/sh/sh: $(SHOBJ) $(LIB)
79 $(CC) $(LDFLAGS) -o $@ $(SHOBJ) $(LIB) $(LDLIBS)
80
81+cmd/net/wget: cmd/net/wget.o $(LIB)
82+ $(CC) $(LDFLAGS) -o $@ cmd/net/wget.o $(LIB) $(LDLIBS) $(LDLIBS_TLS)
83+
84 cmd/dev/ar/ar: cmd/dev/ar/ar.o $(LIB)
85 $(CC) $(LDFLAGS) -o $@ cmd/dev/ar/ar.o $(LIB) $(LDLIBS)
86
87 cmd/dev/ar/%.o: cmd/dev/ar/%.c
88 $(CC) $(CPPFLAGS) -Icmd/dev/ar $(CFLAGS) -o $@ -c $<
89
90+cmd/dev/xcutil/%.o: cmd/dev/xcutil/%.c
91+ $(CC) -Icmd/dev/xcutil $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
92+
93 LD_OBJ =\
94- cmd/dev/ld/ld.o
95+ cmd/dev/xcutil/util.o\
96+ cmd/dev/xcutil/table.o\
97+ cmd/dev/xcutil/elfutil.o\
98+ cmd/dev/xcutil/archive.o\
99+ cmd/dev/ld/ld.o\
100+ cmd/dev/ld/elfobj.o
101
102 cmd/dev/ld/%.o: cmd/dev/ld/%.c
103- $(CC) $(CPPFLAGS) -DLD_TARGET_X86_64 -Icmd/dev/ld $(CFLAGS) -fPIC -o $@ -c $<
104-
105-shared/libaruuelf.so: cmd/dev/ld/elf.o cmd/dev/ld/x86_64.o cmd/dev/ld/ld_support.o
106- $(CC) $(LDFLAGS) -shared -o $@ cmd/dev/ld/elf.o cmd/dev/ld/x86_64.o cmd/dev/ld/ld_support.o
107+ $(CC) -Icmd/dev/xcutil -Icmd/dev/ld $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
108
109-cmd/dev/ld/ld: $(LD_OBJ) shared/libaruuelf.so $(LIB)
110- $(CC) $(LDFLAGS) -o $@ $(LD_OBJ) -Lshared -laruuelf $(LIB) $(LDLIBS) -Wl,-rpath,'$$ORIGIN/../../../shared'
111+cmd/dev/ld/ld: $(LD_OBJ) $(LIB)
112+ $(CC) $(LDFLAGS) -o $@ $(LD_OBJ) $(LIB) $(LDLIBS)
113
114 AS_OBJ =\
115+ cmd/dev/xcutil/util.o\
116+ cmd/dev/xcutil/table.o\
117+ cmd/dev/xcutil/elfutil.o\
118+ cmd/dev/xcutil/archive.o\
119 cmd/dev/as/as.o\
120- cmd/dev/as/asm_lex.o\
121- cmd/dev/as/asm_parse.o\
122- cmd/dev/as/asm_x86_64.o\
123- cmd/dev/as/asm_elf.o
124-
125-cmd/dev/as/%.o: cmd/dev/as/%.c
126- $(CC) $(CPPFLAGS) -Icmd/dev/as -Ishared $(CFLAGS) -o $@ -c $<
127+ cmd/dev/as/as_util.o\
128+ cmd/dev/as/emit_elf.o\
129+ cmd/dev/as/emit_macho.o\
130+ cmd/dev/as/ir_asm.o\
131+ cmd/dev/as/parse_asm.o\
132+ cmd/dev/as/arch/x64/asm_code.o\
133+ cmd/dev/as/arch/x64/ir_asm_x64.o\
134+ cmd/dev/as/arch/x64/parse_x64.o
135+
136+# headers shared across the assembler sources. listing them as prerequisites
137+# of every .o stops stale objects when a header changes (inst.h, parse_asm.h),
138+# which otherwise produced silently-wrong builds
139+AS_HDRS =\
140+ cmd/dev/as/parse_asm.h\
141+ cmd/dev/as/ir_asm.h\
142+ cmd/dev/as/as_util.h\
143+ cmd/dev/as/asm_code.h\
144+ cmd/dev/as/arch/x64/inst.h
145+
146+cmd/dev/as/%.o: cmd/dev/as/%.c $(AS_HDRS) cmd/dev/config.h
147+ $(CC) -Icmd/dev/xcutil -Icmd/dev/as $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
148+
149+cmd/dev/as/arch/x64/%.o: cmd/dev/as/arch/x64/%.c $(AS_HDRS) cmd/dev/config.h
150+ $(CC) -Icmd/dev/xcutil -Icmd/dev/as -Icmd/dev/as/arch/x64 $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
151
152 cmd/dev/as/as: $(AS_OBJ) $(LIB)
153 $(CC) $(LDFLAGS) -o $@ $(AS_OBJ) $(LIB) $(LDLIBS)
154
155-cmd/dev/cc/driver.o: cmd/dev/cc/driver.c
156+cmd/dev/cc/driver.o: cmd/dev/cc/driver.c cmd/dev/cc/config.h
157 $(CC) -Icmd/dev/cc $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
158
159-cmd/dev/cc/cc: cmd/dev/cc/driver.o cmd/dev/cc/util.o $(LIB) cmd/dev/cc/cc1 cmd/dev/cc/cpp cmd/dev/as/as
160+cmd/dev/cc/cc: cmd/dev/cc/driver.o cmd/dev/cc/util.o $(LIB) cmd/dev/cc/cc1 cmd/dev/cc/cpp cmd/dev/as/as cmd/dev/ld/ld
161 $(CC) $(LDFLAGS) -o $@ cmd/dev/cc/driver.o cmd/dev/cc/util.o $(LIB) $(LDLIBS)
162
163 CC1_OBJ =\
164@@ -899,6 +941,7 @@ cmd/dev/cc/cc1: $(CC1_OBJ) $(LIB)
165 cmd/dev/cc/cpp: cmd/dev/cc/cpp.o $(CPP_OBJ) $(LIB)
166 $(CC) $(LDFLAGS) -o $@ cmd/dev/cc/cpp.o $(CPP_OBJ) $(LIB) $(LDLIBS)
167
168+cmd/dev/config.h cmd/dev/cc/config.h cmd/dev/version.h: cmd/dev/configure
169+ sh cmd/dev/configure
170
171-
172-
173+$(AS_OBJ) $(LD_OBJ) $(CC1_OBJ) $(CPP_OBJ) cmd/dev/ar/ar.o cmd/dev/cc/cpp.o: cmd/dev/config.h
+50,
-39
1@@ -48,28 +48,28 @@ CPPFLAGS="-Ishared -DPREFIX=\"$PREFIX\" -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_NETBS
2 if [ "$FEATURE_USE_BEARSSL" = "1" ]; then
3 if pkg-config --exists libbearssl 2>/dev/null; then
4 CPPFLAGS="$CPPFLAGS $(pkg-config --cflags libbearssl)"
5- LDLIBS="$LDLIBS $(pkg-config --libs libbearssl)"
6+ TLS_LDLIBS="$TLS_LDLIBS $(pkg-config --libs libbearssl)"
7 elif pkg-config --exists bearssl 2>/dev/null; then
8 CPPFLAGS="$CPPFLAGS $(pkg-config --cflags bearssl)"
9- LDLIBS="$LDLIBS $(pkg-config --libs bearssl)"
10+ TLS_LDLIBS="$TLS_LDLIBS $(pkg-config --libs bearssl)"
11 else
12- LDLIBS="$LDLIBS -lbearssl"
13+ TLS_LDLIBS="$TLS_LDLIBS -LexternalRepos/BearSSL/build -lbearssl"
14 fi
15 fi
16 if [ "$FEATURE_USE_LIBRESSL" = "1" ]; then
17 if pkg-config --exists libtls 2>/dev/null; then
18 CPPFLAGS="$CPPFLAGS $(pkg-config --cflags libtls)"
19- LDLIBS="$LDLIBS $(pkg-config --libs libtls)"
20+ TLS_LDLIBS="$TLS_LDLIBS $(pkg-config --libs libtls)"
21 else
22- LDLIBS="$LDLIBS -ltls"
23+ TLS_LDLIBS="$TLS_LDLIBS -ltls"
24 fi
25 fi
26 if [ "$FEATURE_USE_OPENSSL" = "1" ]; then
27 if pkg-config --exists openssl 2>/dev/null; then
28 CPPFLAGS="$CPPFLAGS $(pkg-config --cflags openssl)"
29- LDLIBS="$LDLIBS $(pkg-config --libs openssl)"
30+ TLS_LDLIBS="$TLS_LDLIBS $(pkg-config --libs openssl)"
31 else
32- LDLIBS="$LDLIBS -lssl -lcrypto"
33+ TLS_LDLIBS="$TLS_LDLIBS -lssl -lcrypto"
34 fi
35 fi
36 unset _feature_flags
37@@ -170,7 +170,7 @@ compile_c() {
38 local src="$1" obj="$2"; shift 2
39 # shellcheck disable=SC2086
40 any_newer_than "$obj" "$src" $HDR $EXTRA_HDR || return 0
41- enqueue " CC $obj" "$CC $CPPFLAGS $* $CFLAGS -o $obj -c $src"
42+ enqueue " CC $obj" "$CC $* $CPPFLAGS $CFLAGS -o $obj -c $src"
43 }
44
45 link_bin() {
46@@ -186,7 +186,11 @@ link_bin() {
47 any_newer_than "$bin" $objs || return 0
48 printf ' LD %s\n' "$bin"
49 # shellcheck disable=SC2086
50- eval "$CC $LDFLAGS -o $bin $objs $libs $LDLIBS"
51+ if [ "${bin##*/}" = "wget" ]; then
52+ eval "$CC $LDFLAGS -o $bin $objs $libs $LDLIBS $TLS_LDLIBS"
53+ else
54+ eval "$CC $LDFLAGS -o $bin $objs $libs $LDLIBS"
55+ fi
56 }
57
58 # writes to _objs rather than stdout so the caller avoids a subshell that
59@@ -255,7 +259,7 @@ cfg_enabled() {
60 return 1
61 fi
62 case "$_var" in
63- *_[^_]*) _var=$(printf '%s' "$_var" | sed 's/_[^_]*$//') ;;
64+ *_[!_]*) _var=$(printf '%s' "$_var" | sed 's/_[^_]*$//') ;;
65 *) break ;;
66 esac
67 done
68@@ -391,34 +395,28 @@ build_ar() {
69
70 build_as() {
71 cfg_enabled BUILD_DEV_AS || return 0
72- local dir=cmd/dev/as
73- objs_for "$dir" "" "-I$dir -Ishared"
74- link_bin "$dir/as" $_objs -- $LIB
75+ local dir="cmd/dev/as"
76+ local flags="-Icmd/dev/xcutil -I$dir -Ishared"
77+ local objs=""
78+ objs_for "cmd/dev/xcutil" "" "$flags"
79+ objs="$objs $_objs"
80+ objs_for "$dir" "" "$flags"
81+ objs="$objs $_objs"
82+ objs_for "$dir/arch/x64" "" "-Icmd/dev/xcutil -I$dir -I$dir/arch/x64 -Ishared"
83+ objs="$objs $_objs"
84+ link_bin "$dir/as" $objs -- $LIB
85 }
86
87-# rpath embeds $ORIGIN so the installed ld finds libaruuelf.so next to itself
88 build_ld() {
89 cfg_enabled BUILD_DEV_LD || return 0
90 local dir="cmd/dev/ld"
91- local cflags="-DLD_TARGET_X86_64 -I$dir -fPIC"
92- local src
93-
94- for src in "$dir"/*.c; do
95- compile_c "$src" "${src%.c}.o" $cflags
96- done
97- drain
98-
99- any_newer_than shared/libaruuelf.so "$dir/elf.o" "$dir/x86_64.o" "$dir/ld_support.o" && {
100- printf ' LD shared/libaruuelf.so\n'
101- eval "$CC $LDFLAGS -shared -o shared/libaruuelf.so $dir/elf.o $dir/x86_64.o $dir/ld_support.o"
102- }
103-
104- any_newer_than "$dir/ld" "$dir/ld.o" shared/libaruuelf.so && {
105- printf ' LD %s/ld\n' "$dir"
106- # $ORIGIN is a dynamic-linker token, not a shell variable
107- eval "$CC $LDFLAGS -o $dir/ld $dir/ld.o -Lshared -laruuelf $LIB $LDLIBS -Wl,-rpath,'\$ORIGIN/../../../shared'"
108- }
109- return 0
110+ local flags="-Icmd/dev/xcutil -I$dir"
111+ local objs=""
112+ objs_for "cmd/dev/xcutil" "" "$flags"
113+ objs="$objs $_objs"
114+ objs_for "$dir" "" "$flags"
115+ objs="$objs $_objs"
116+ link_bin "$dir/ld" $objs -- $LIB
117 }
118
119 build_cc() {
120@@ -443,6 +441,9 @@ build_cc() {
121 }
122
123 build_dev() {
124+ if [ ! -f cmd/dev/config.h ]; then
125+ sh cmd/dev/configure
126+ fi
127 build_ar
128 build_as
129 build_ld
130@@ -459,21 +460,31 @@ man_section() {
131 }
132
133 build_man_for() {
134- local var="$1" src="$2" base sec out
135+ local var="$1" src="$2" base sec out_mdoc out_txt
136 cfg_enabled "$var" || return 0
137 [ -x scripts/mkman/mkman ] || { printf 'error: mkman not built\n' >&2; exit 1; }
138+
139+ grep -qE '!man|\?man' "$src" || return 0
140+
141 base=${src##*/}; base=${base%.c}
142 sec=$(man_section "$src")
143- out="man/man${sec}/${base}.${sec}"
144+
145 mkdir -p "man/man${sec}"
146- any_newer_than "$out" "$src" build.cfg scripts/mkman/mkman || return 0
147- printf ' MAN %s\n' "$out"
148- scripts/mkman/mkman -config build.cfg -section "$sec" "$src" > "$out"
149+ out_mdoc="man/man${sec}/${base}.${sec}"
150+ out_txt="man/man${sec}/${base}.${sec}.txt"
151+ if any_newer_than "$out_mdoc" "$src" config.mk scripts/mkman/mkman; then
152+ printf ' MAN %s\n' "$out_mdoc"
153+ scripts/mkman/mkman -fmt mdoc -config config.mk -section "$sec" "$src" > "$out_mdoc"
154+ fi
155+ if any_newer_than "$out_txt" "$src" config.mk scripts/mkman/mkman; then
156+ printf ' MAN %s\n' "$out_txt"
157+ scripts/mkman/mkman -fmt txt -config config.mk -section "$sec" "$src" > "$out_txt"
158+ fi
159 }
160
161 build_man() {
162 local dir cat src base
163- if [ ! -x scripts/mkman/mkman ] || any_newer_than scripts/mkman/mkman scripts/mkman/main.go scripts/mkman/troff.go; then
164+ if [ ! -x scripts/mkman/mkman ] || any_newer_than scripts/mkman/mkman scripts/mkman/main.go scripts/mkman/page.go scripts/mkman/parse.go scripts/mkman/mdoc.go; then
165 printf ' GO scripts/mkman/mkman\n'
166 (cd scripts/mkman && go build -o mkman .)
167 fi
+14,
-12
1@@ -1,8 +1,8 @@
2-# posix: POSIX 2024 only common: uncontroversial extras all: everything except external libs
3+# posix: POSIX 2024
4 PRESET_FEATURES=all
5
6 # subset of: posix linux net xsi pseudo dev
7-PRESET_UTILS="posix linux net xsi pseudo dev"
8+PRESET_UTILS="posix linux net xsi pseudo"
9
10 # installation paths
11 VERSION=2026-06-08T05-53-UTC-03
12@@ -137,18 +137,20 @@ unset _p
13 # BUILD_POSIX_SH=0 # disable a tool when its group is active
14 # BUILD_DEV_AS=1 # enable a tool whose group isnt in PRESET_UTILS
15 FEATURE_SH_HISTEDIT=1
16-# tls backend: set all three to 0 to disable tls, or set exactly one to 1 to
17-# override auto-detection; auto-detection tries bearssl first, then libtls,
18-# then openssl
19+# tls backend: set exactly one to 1 to enable tls
20 FEATURE_USE_BEARSSL=0
21 FEATURE_USE_LIBRESSL=0
22 FEATURE_USE_OPENSSL=0
23-if [ "$FEATURE_USE_BEARSSL" = 0 ] && [ "$FEATURE_USE_LIBRESSL" = 0 ] && [ "$FEATURE_USE_OPENSSL" = 0 ]; then
24- if pkg-config --exists libbearssl 2>/dev/null || pkg-config --exists bearssl 2>/dev/null; then
25- FEATURE_USE_BEARSSL=1
26- elif pkg-config --exists libtls 2>/dev/null; then
27- FEATURE_USE_LIBRESSL=1
28- elif pkg-config --exists openssl 2>/dev/null; then
29- FEATURE_USE_OPENSSL=1
30+FEATURE_USE_SSL=1
31+
32+if [ "$FEATURE_USE_SSL" = 1 ]; then
33+ if [ "$FEATURE_USE_BEARSSL" = 0 ] && [ "$FEATURE_USE_LIBRESSL" = 0 ] && [ "$FEATURE_USE_OPENSSL" = 0 ]; then
34+ if pkg-config --exists libbearssl 2>/dev/null || pkg-config --exists bearssl 2>/dev/null; then
35+ FEATURE_USE_BEARSSL=1
36+ elif pkg-config --exists libtls 2>/dev/null; then
37+ FEATURE_USE_LIBRESSL=1
38+ elif pkg-config --exists openssl 2>/dev/null; then
39+ FEATURE_USE_OPENSSL=1
40+ fi
41 fi
42 fi
+346,
-0
1@@ -0,0 +1,346 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "diskutil.h"
5+
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <unistd.h>
10+#include <fcntl.h>
11+
12+struct FsType {
13+ const char *name;
14+ size_t magic_offset;
15+ size_t magic_len;
16+ uint64_t magic1;
17+ uint64_t magic2;
18+ size_t uuid_offset;
19+ size_t uuid_len;
20+ size_t label_offset;
21+ size_t label_len;
22+};
23+
24+static const struct FsType fstypes[] = {
25+ /* ext2/3/4 */
26+ { "ext", 1080, 2, 0xEF53, 0x53EF, 1128, 16, 1144, 16 },
27+ /* vfat / fat32 */
28+ { "vfat", 82, 5, 0x3233544146ULL, 0, 67, 4, 71, 11 },
29+ /* vfat / fat12/16 */
30+ { "vfat", 54, 4, 0x31544146, 0, 39, 4, 43, 11 },
31+ /* ntfs */
32+ { "ntfs", 3, 4, 0x5346544e, 0, 72, 8, 0, 0 },
33+ /* xfs */
34+ { "xfs", 0, 4, 0x42534658, 0x58465342, 32, 16, 108, 12 },
35+ /* btrfs */
36+ { "btrfs", 65600, 8, 0x4D5F53665248425FULL, 0, 65803, 16, 65819, 256 },
37+ /* f2fs */
38+ { "f2fs", 1024, 4, 0xF2F52010, 0x1020F5F2, 1132, 16, 1148, 512 },
39+ /* ufs1 */
40+ { "ufs1", 9564, 4, 0x011954, 0x54190100, 0, 0, 0, 0 },
41+ /* ufs2 */
42+ { "ufs2", 66908, 4, 0x19540119, 0x19015419, 67056, 16, 67072, 32 },
43+ /* fossil */
44+ { "fossil", 131200, 4, 0x2340A3B1, 0xB1A34023, 0, 0, 131072, 127 },
45+ /* cwfs */
46+ { "cwfs", 0, 4, 0xc1a551f5, 0xf551a5c1, 0, 0, 0, 0 },
47+};
48+
49+static char *oflag = "full";
50+static char *sflag = NULL;
51+static int Uflag = 0;
52+static int Lflag = 0;
53+
54+static void
55+usage(void)
56+{
57+ eprintf("usage: %s [-o format] [-s tag] [-U] [-L] [device ...]\n", argv0);
58+}
59+
60+static void
61+format_uuid(const unsigned char *buf, size_t len, const char *type, char *out, size_t out_len)
62+{
63+ size_t i;
64+ char *p = out;
65+
66+ if (strcmp(type, "vfat") == 0) {
67+ snprintf(out, out_len, "%02X%02X-%02X%02X", buf[3], buf[2], buf[1], buf[0]);
68+ return;
69+ }
70+
71+ if (strcmp(type, "ntfs") == 0) {
72+ for (i = 8; i > 0; i--) {
73+ snprintf(p, out_len - (p - out), "%02X", buf[i - 1]);
74+ p += 2;
75+ }
76+ return;
77+ }
78+
79+ for (i = 0; i < len; i++) {
80+ if (i == 4 || i == 6 || i == 8 || i == 10) {
81+ *p++ = '-';
82+ }
83+ snprintf(p, out_len - (p - out), "%02x", buf[i]);
84+ p += 2;
85+ }
86+ *p = '\0';
87+}
88+
89+static void
90+print_tag(const char *devname, const char *tag, const char *value)
91+{
92+ if (sflag && strcasecmp(sflag, tag) != 0)
93+ return;
94+
95+ if (strcmp(oflag, "value") == 0) {
96+ printf("%s\n", value);
97+ } else if (strcmp(oflag, "export") == 0) {
98+ printf("%s=%s\n", tag, value);
99+ } else {
100+ printf(" %s=\"%s\"", tag, value);
101+ }
102+}
103+
104+static int
105+detect_zfs(const unsigned char *buf, size_t len)
106+{
107+ size_t offset;
108+ uint64_t magic;
109+
110+ for (offset = 131072; offset + 8 <= len; offset += 1024) {
111+ magic = ((uint64_t)buf[offset + 7] << 56) |
112+ ((uint64_t)buf[offset + 6] << 48) |
113+ ((uint64_t)buf[offset + 5] << 40) |
114+ ((uint64_t)buf[offset + 4] << 32) |
115+ ((uint64_t)buf[offset + 3] << 24) |
116+ ((uint64_t)buf[offset + 2] << 16) |
117+ ((uint64_t)buf[offset + 1] << 8) |
118+ (uint64_t)buf[offset];
119+
120+ if (magic == 0x00bab10caULL || magic == 0x0cb1ba0000000000ULL ||
121+ magic == 0x00bab10cULL || magic == 0x0cb1ba00ULL)
122+ return 1;
123+ }
124+ return 0;
125+}
126+
127+static int
128+detect_plan9_other(const unsigned char *buf, size_t len, const char **name)
129+{
130+ if (len >= 4) {
131+ uint32_t magic = ((uint32_t)buf[3] << 24) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[1] << 8) | (uint32_t)buf[0];
132+ if (magic == 0x686a6673 || magic == 0x73666a68) {
133+ *name = "hjfs";
134+ return 1;
135+ }
136+ if (magic == 0x67656673 || magic == 0x73666567) {
137+ *name = "gefs";
138+ return 1;
139+ }
140+ }
141+ if (len >= 516) {
142+ uint32_t magic = ((uint32_t)buf[515] << 24) | ((uint32_t)buf[514] << 16) | ((uint32_t)buf[513] << 8) | (uint32_t)buf[512];
143+ if (magic == 0x686a6673 || magic == 0x73666a68) {
144+ *name = "hjfs";
145+ return 1;
146+ }
147+ if (magic == 0x67656673 || magic == 0x73666567) {
148+ *name = "gefs";
149+ return 1;
150+ }
151+ }
152+ return 0;
153+}
154+
155+static int
156+do_blkid(const char *path)
157+{
158+ struct BlockDev dev;
159+ unsigned char *buf;
160+ size_t read_size = 262144; /* 256kb */
161+ size_t i, j;
162+ int found = 0;
163+
164+ if (blockdev_open(&dev, path, 0) < 0)
165+ return -1;
166+
167+ if (dev.size < read_size)
168+ read_size = dev.size;
169+
170+ buf = emalloc(read_size);
171+ /* read sectors */
172+ size_t sectors_to_read = (read_size + dev.sec_size - 1) / dev.sec_size;
173+ if (blockdev_read(&dev, 0, buf, sectors_to_read) < 0) {
174+ free(buf);
175+ blockdev_close(&dev);
176+ return -1;
177+ }
178+
179+ for (i = 0; i < LEN(fstypes); i++) {
180+ const struct FsType *fs = &fstypes[i];
181+ if (fs->magic_offset + fs->magic_len > read_size)
182+ continue;
183+
184+ uint64_t val = 0;
185+ for (j = 0; j < fs->magic_len; j++) {
186+ val |= ((uint64_t)buf[fs->magic_offset + j]) << (8 * j);
187+ }
188+
189+ if (val == fs->magic1 || (fs->magic2 && val == fs->magic2)) {
190+ const char *type_name = fs->name;
191+ if (strcmp(fs->name, "ext") == 0) {
192+ if (buf[1116] & 4)
193+ type_name = "ext3";
194+ else if (buf[1120] & 64)
195+ type_name = "ext4";
196+ else
197+ type_name = "ext2";
198+ }
199+
200+ if (Uflag || Lflag) {
201+ char label[256] = {0};
202+ char uuid[256] = {0};
203+ if (fs->label_len && fs->label_offset + fs->label_len <= read_size) {
204+ snprintf(label, sizeof(label), "%.*s", (int)fs->label_len, buf + fs->label_offset);
205+ }
206+ if (fs->uuid_len && fs->uuid_offset + fs->uuid_len <= read_size) {
207+ format_uuid(buf + fs->uuid_offset, fs->uuid_len, fs->name, uuid, sizeof(uuid));
208+ }
209+ if (Uflag) {
210+ printf("%s\n", uuid);
211+ } else {
212+ printf("%s\n", label);
213+ }
214+ found = 1;
215+ break;
216+ }
217+
218+ if (strcmp(oflag, "export") == 0) {
219+ printf("DEVNAME=%s\n", path);
220+ } else if (strcmp(oflag, "value") != 0) {
221+ printf("%s:", path);
222+ }
223+
224+ if (fs->label_len && fs->label_offset + fs->label_len <= read_size) {
225+ char label[256];
226+ snprintf(label, sizeof(label), "%.*s", (int)fs->label_len, buf + fs->label_offset);
227+ /* strip trailing spaces */
228+ char *end = label + strlen(label) - 1;
229+ while (end >= label && *end == ' ') {
230+ *end = '\0';
231+ end--;
232+ }
233+ if (label[0])
234+ print_tag(path, "LABEL", label);
235+ }
236+
237+ if (fs->uuid_len && fs->uuid_offset + fs->uuid_len <= read_size) {
238+ char uuid[256];
239+ format_uuid(buf + fs->uuid_offset, fs->uuid_len, fs->name, uuid, sizeof(uuid));
240+ print_tag(path, "UUID", uuid);
241+ }
242+
243+ print_tag(path, "TYPE", type_name);
244+ if (strcmp(oflag, "full") == 0)
245+ printf("\n");
246+
247+ found = 1;
248+ break;
249+ }
250+ }
251+
252+ if (!found && detect_zfs(buf, read_size)) {
253+ if (Uflag || Lflag) {
254+ printf("\n");
255+ } else {
256+ if (strcmp(oflag, "export") == 0) {
257+ printf("DEVNAME=%s\n", path);
258+ } else if (strcmp(oflag, "value") != 0) {
259+ printf("%s:", path);
260+ }
261+ print_tag(path, "TYPE", "zfs_member");
262+ if (strcmp(oflag, "full") == 0)
263+ printf("\n");
264+ }
265+ found = 1;
266+ }
267+
268+ if (!found) {
269+ const char *p9_name = NULL;
270+ if (detect_plan9_other(buf, read_size, &p9_name)) {
271+ if (Uflag || Lflag) {
272+ printf("\n");
273+ } else {
274+ if (strcmp(oflag, "export") == 0) {
275+ printf("DEVNAME=%s\n", path);
276+ } else if (strcmp(oflag, "value") != 0) {
277+ printf("%s:", path);
278+ }
279+ print_tag(path, "TYPE", p9_name);
280+ if (strcmp(oflag, "full") == 0)
281+ printf("\n");
282+ }
283+ found = 1;
284+ }
285+ }
286+
287+ free(buf);
288+ blockdev_close(&dev);
289+ return found ? 0 : -2;
290+}
291+
292+// ?man blkid: print block device attributes
293+// ?man arguments: [device ...]
294+// ?man blkid locates and prints attributes (such as uuid, volume label, and filesystem type)
295+// ?man of block devices or partition images
296+int
297+main(int argc, char *argv[])
298+{
299+ int ret = 0;
300+
301+ ARGBEGIN {
302+ // ?man -o:specify output format (full, value, export)
303+ case 'o':
304+ oflag = EARGF(usage());
305+ break;
306+ // ?man -s:only show specified tag (e.g. UUID, LABEL, TYPE)
307+ case 's':
308+ sflag = EARGF(usage());
309+ break;
310+ // ?man -U:print UUID only
311+ case 'U':
312+ Uflag = 1;
313+ break;
314+ // ?man -L:print volume label only
315+ case 'L':
316+ Lflag = 1;
317+ break;
318+ default:
319+ usage();
320+ } ARGEND
321+
322+ if (argc > 0) {
323+ for (; *argv; argv++) {
324+ if (do_blkid(*argv) < 0)
325+ ret = 1;
326+ }
327+ } else {
328+ struct BlockDevInfo *list = blockdev_get_list();
329+ struct BlockDevInfo *curr;
330+ if (!list) {
331+ return 1;
332+ }
333+ for (curr = list; curr; curr = curr->next) {
334+ char devpath[128];
335+ snprintf(devpath, sizeof(devpath), "/dev/%s", curr->name);
336+ do_blkid(devpath);
337+ struct BlockDevInfo *part;
338+ for (part = curr->parts; part; part = part->next) {
339+ snprintf(devpath, sizeof(devpath), "/dev/%s", part->name);
340+ do_blkid(devpath);
341+ }
342+ }
343+ blockdev_free_list(list);
344+ }
345+
346+ return ret;
347+}
+478,
-0
1@@ -0,0 +1,478 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "diskutil.h"
5+
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <unistd.h>
10+#include <fcntl.h>
11+
12+struct MbrPartition {
13+ uint8_t boot;
14+ uint8_t start_chs[3];
15+ uint8_t type;
16+ uint8_t end_chs[3];
17+ uint32_t start_lba;
18+ uint32_t size;
19+} __attribute__((packed));
20+
21+struct MbrHeader {
22+ uint8_t code[446];
23+ struct MbrPartition parts[4];
24+ uint8_t sig[2];
25+} __attribute__((packed));
26+
27+struct GptHeader {
28+ uint8_t sig[8];
29+ uint32_t rev;
30+ uint32_t size;
31+ uint32_t crc;
32+ uint32_t reserved;
33+ uint64_t current_lba;
34+ uint64_t backup_lba;
35+ uint64_t first_usable;
36+ uint64_t last_usable;
37+ uint8_t disk_guid[16];
38+ uint64_t partition_lba;
39+ uint32_t num_parts;
40+ uint32_t part_size;
41+ uint32_t parts_crc;
42+} __attribute__((packed));
43+
44+struct GptPartition {
45+ uint8_t type_guid[16];
46+ uint8_t part_guid[16];
47+ uint64_t start_lba;
48+ uint64_t end_lba;
49+ uint64_t flags;
50+ uint16_t name[36];
51+} __attribute__((packed));
52+
53+static uint32_t crc32_table[256];
54+static int crc32_table_initialized = 0;
55+
56+static void
57+init_crc32_table(void)
58+{
59+ uint32_t i, j, c;
60+ for (i = 0; i < 256; i++) {
61+ c = i;
62+ for (j = 0; j < 8; j++) {
63+ if (c & 1)
64+ c = 0xedb88320U ^ (c >> 1);
65+ else
66+ c = c >> 1;
67+ }
68+ crc32_table[i] = c;
69+ }
70+ crc32_table_initialized = 1;
71+}
72+
73+static uint32_t
74+crc32(uint32_t crc, const void *buf, size_t len)
75+{
76+ const uint8_t *p = buf;
77+ if (!crc32_table_initialized)
78+ init_crc32_table();
79+ while (len--)
80+ crc = (crc >> 8) ^ crc32_table[(crc ^ *p++) & 0xFF];
81+ return crc;
82+}
83+
84+static int opt_list = 0;
85+static int opt_print = 0;
86+static int opt_init_gpt = 0;
87+static int opt_init_mbr = 0;
88+static int opt_add = 0;
89+static int opt_del = 0;
90+static int opt_part_idx = -1;
91+static uint64_t opt_start = 0;
92+static uint64_t opt_end = 0;
93+static const char *opt_type = NULL;
94+
95+static void
96+usage(void)
97+{
98+ eprintf("usage: %s [-l] [-p] [-g] [-m] [-a] [-d] [-n index] [-b start] [-e end] [-t type] [device]\n", argv0);
99+}
100+
101+static void
102+print_mbr(struct MbrHeader *mbr, const char *path)
103+{
104+ int i;
105+ printf("Disk: %s\n", path);
106+ printf("Partition table (MBR/dos):\n");
107+ printf("%-5s %-4s %-12s %-12s %-4s\n", "Index", "Boot", "Start", "Size", "Type");
108+ for (i = 0; i < 4; i++) {
109+ struct MbrPartition *p = &mbr->parts[i];
110+ if (p->size == 0)
111+ continue;
112+ printf("%-5d %-4s %-12u %-12u 0x%02x\n",
113+ i + 1,
114+ p->boot == 0x80 ? "Yes" : "No",
115+ p->start_lba,
116+ p->size,
117+ p->type);
118+ }
119+}
120+
121+static void
122+print_gpt(struct GptHeader *hdr, struct GptPartition *parts, const char *path)
123+{
124+ uint32_t i;
125+ char guid[37];
126+ printf("Disk: %s\n", path);
127+ printf("Partition table (GPT):\n");
128+ printf("%-5s %-12s %-12s %-36s\n", "Index", "Start", "End", "Type GUID");
129+ for (i = 0; i < hdr->num_parts; i++) {
130+ struct GptPartition *p = &parts[i];
131+ if (p->start_lba == 0 && p->end_lba == 0)
132+ continue;
133+
134+ snprintf(guid, sizeof(guid),
135+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
136+ p->type_guid[3], p->type_guid[2], p->type_guid[1], p->type_guid[0],
137+ p->type_guid[5], p->type_guid[4],
138+ p->type_guid[7], p->type_guid[6],
139+ p->type_guid[8], p->type_guid[9],
140+ p->type_guid[10], p->type_guid[11], p->type_guid[12], p->type_guid[13], p->type_guid[14], p->type_guid[15]);
141+
142+ printf("%-5d %-12llu %-12llu %-36s\n",
143+ i + 1,
144+ (unsigned long long)p->start_lba,
145+ (unsigned long long)p->end_lba,
146+ guid);
147+ }
148+}
149+
150+static int
151+read_gpt(struct BlockDev *dev, struct GptHeader *hdr, struct GptPartition *parts)
152+{
153+ unsigned char sector[512];
154+ size_t part_sectors;
155+
156+ if (blockdev_read(dev, 1, sector, 1) < 0)
157+ return -1;
158+
159+ memcpy(hdr, sector, sizeof(*hdr));
160+
161+ if (memcmp(hdr->sig, "EFI PART", 8) != 0)
162+ return -1;
163+
164+ part_sectors = (hdr->num_parts * hdr->part_size + dev->sec_size - 1) / dev->sec_size;
165+ if (blockdev_read(dev, hdr->partition_lba, parts, part_sectors) < 0)
166+ return -1;
167+
168+ return 0;
169+}
170+
171+static int
172+write_gpt(struct BlockDev *dev, struct GptHeader *hdr, struct GptPartition *parts)
173+{
174+ unsigned char sector[512];
175+ size_t part_sectors = (hdr->num_parts * hdr->part_size + dev->sec_size - 1) / dev->sec_size;
176+
177+ /* update partition entries crc */
178+ hdr->parts_crc = crc32(~0U, parts, hdr->num_parts * hdr->part_size) ^ ~0U;
179+
180+ /* calculate header crc (zeroing the crc field first) */
181+ hdr->crc = 0;
182+ hdr->crc = crc32(~0U, hdr, hdr->size) ^ ~0U;
183+
184+ /* write protective mbr to sector 0 */
185+ struct MbrHeader pmbr;
186+ memset(&pmbr, 0, sizeof(pmbr));
187+ pmbr.parts[0].type = 0xEE;
188+ pmbr.parts[0].start_lba = 1;
189+ uint64_t limit = dev->size / dev->sec_size - 1;
190+ pmbr.parts[0].size = limit > 0xFFFFFFFFU ? 0xFFFFFFFFU : (uint32_t)limit;
191+ pmbr.sig[0] = 0x55;
192+ pmbr.sig[1] = 0xAA;
193+ if (blockdev_write(dev, 0, &pmbr, 1) < 0)
194+ return -1;
195+
196+ /* write primary header and partition entries */
197+ memset(sector, 0, sizeof(sector));
198+ memcpy(sector, hdr, sizeof(*hdr));
199+ if (blockdev_write(dev, 1, sector, 1) < 0)
200+ return -1;
201+ if (blockdev_write(dev, hdr->partition_lba, parts, part_sectors) < 0)
202+ return -1;
203+
204+ /* write backup partition entries and backup header */
205+ struct GptHeader backup_hdr = *hdr;
206+ backup_hdr.current_lba = hdr->backup_lba;
207+ backup_hdr.backup_lba = hdr->current_lba;
208+ backup_hdr.partition_lba = backup_hdr.current_lba - part_sectors;
209+
210+ backup_hdr.crc = 0;
211+ backup_hdr.crc = crc32(~0U, &backup_hdr, backup_hdr.size) ^ ~0U;
212+
213+ if (blockdev_write(dev, backup_hdr.partition_lba, parts, part_sectors) < 0)
214+ return -1;
215+
216+ memset(sector, 0, sizeof(sector));
217+ memcpy(sector, &backup_hdr, sizeof(backup_hdr));
218+ if (blockdev_write(dev, backup_hdr.current_lba, sector, 1) < 0)
219+ return -1;
220+
221+ return 0;
222+}
223+
224+static int
225+do_print(const char *path)
226+{
227+ struct BlockDev dev;
228+ struct MbrHeader mbr;
229+ struct GptHeader gpt_hdr;
230+ struct GptPartition gpt_parts[128];
231+
232+ if (blockdev_open(&dev, path, 0) < 0) {
233+ weprintf("cannot open %s:", path);
234+ return -1;
235+ }
236+
237+ if (read_gpt(&dev, &gpt_hdr, gpt_parts) == 0) {
238+ print_gpt(&gpt_hdr, gpt_parts, path);
239+ } else {
240+ if (blockdev_read(&dev, 0, &mbr, 1) == 0 && mbr.sig[0] == 0x55 && mbr.sig[1] == 0xAA) {
241+ print_mbr(&mbr, path);
242+ } else {
243+ printf("Disk %s: unpartitioned or unknown format\n", path);
244+ }
245+ }
246+
247+ blockdev_close(&dev);
248+ return 0;
249+}
250+
251+static int
252+do_fdisk(const char *path)
253+{
254+ struct BlockDev dev;
255+ struct MbrHeader mbr;
256+ struct GptHeader gpt_hdr;
257+ struct GptPartition gpt_parts[128];
258+ int has_gpt = 0;
259+
260+ if (blockdev_open(&dev, path, 1) < 0) {
261+ weprintf("cannot open %s:", path);
262+ return -1;
263+ }
264+
265+ has_gpt = (read_gpt(&dev, &gpt_hdr, gpt_parts) == 0);
266+
267+ if (opt_init_mbr) {
268+ memset(&mbr, 0, sizeof(mbr));
269+ mbr.sig[0] = 0x55;
270+ mbr.sig[1] = 0xAA;
271+ if (blockdev_write(&dev, 0, &mbr, 1) < 0) {
272+ weprintf("cannot write MBR to %s:", path);
273+ blockdev_close(&dev);
274+ return -1;
275+ }
276+ printf("Initialized MBR partition table on %s\n", path);
277+ blockdev_close(&dev);
278+ return 0;
279+ }
280+
281+ if (opt_init_gpt) {
282+ memset(&gpt_hdr, 0, sizeof(gpt_hdr));
283+ memcpy(gpt_hdr.sig, "EFI PART", 8);
284+ gpt_hdr.rev = 0x00010000;
285+ gpt_hdr.size = 92;
286+ gpt_hdr.current_lba = 1;
287+ gpt_hdr.backup_lba = dev.size / dev.sec_size - 1;
288+ gpt_hdr.first_usable = 34;
289+ gpt_hdr.last_usable = gpt_hdr.backup_lba - 34;
290+ gpt_hdr.partition_lba = 2;
291+ gpt_hdr.num_parts = 128;
292+ gpt_hdr.part_size = 128;
293+ memset(gpt_parts, 0, sizeof(gpt_parts));
294+
295+ if (write_gpt(&dev, &gpt_hdr, gpt_parts) < 0) {
296+ weprintf("cannot write GPT to %s:", path);
297+ blockdev_close(&dev);
298+ return -1;
299+ }
300+ printf("Initialized GPT partition table on %s\n", path);
301+ blockdev_close(&dev);
302+ return 0;
303+ }
304+
305+ if (opt_add) {
306+ if (opt_part_idx < 1) {
307+ weprintf("add requires partition index (-n)\n");
308+ blockdev_close(&dev);
309+ return -1;
310+ }
311+
312+ if (has_gpt) {
313+ if (opt_part_idx > 128) {
314+ weprintf("GPT partition index must be 1-128\n");
315+ blockdev_close(&dev);
316+ return -1;
317+ }
318+ struct GptPartition *p = &gpt_parts[opt_part_idx - 1];
319+ p->start_lba = opt_start;
320+ p->end_lba = opt_end;
321+ /* default type guid: linux filesystem data */
322+ p->type_guid[0] = 0xAF; p->type_guid[1] = 0x3D; p->type_guid[2] = 0xC6; p->type_guid[3] = 0x0F;
323+ p->type_guid[4] = 0x83; p->type_guid[5] = 0x84;
324+ p->type_guid[6] = 0x72; p->type_guid[7] = 0x47;
325+ p->type_guid[8] = 0x8E; p->type_guid[9] = 0x79;
326+ p->type_guid[10] = 0x3D; p->type_guid[11] = 0x69; p->type_guid[12] = 0xD8; p->type_guid[13] = 0x47; p->type_guid[14] = 0x7D; p->type_guid[15] = 0xE4;
327+
328+ if (write_gpt(&dev, &gpt_hdr, gpt_parts) < 0) {
329+ weprintf("cannot update GPT on %s:", path);
330+ blockdev_close(&dev);
331+ return -1;
332+ }
333+ printf("Added GPT partition %d to %s\n", opt_part_idx, path);
334+ } else {
335+ if (blockdev_read(&dev, 0, &mbr, 1) < 0) {
336+ weprintf("cannot read MBR from %s:", path);
337+ blockdev_close(&dev);
338+ return -1;
339+ }
340+ if (opt_part_idx > 4) {
341+ weprintf("MBR partition index must be 1-4\n");
342+ blockdev_close(&dev);
343+ return -1;
344+ }
345+ struct MbrPartition *p = &mbr.parts[opt_part_idx - 1];
346+ p->start_lba = (uint32_t)opt_start;
347+ p->size = (uint32_t)(opt_end - opt_start + 1);
348+ p->type = opt_type ? (uint8_t)strtoul(opt_type, NULL, 0) : 0x83;
349+ mbr.sig[0] = 0x55;
350+ mbr.sig[1] = 0xAA;
351+
352+ if (blockdev_write(&dev, 0, &mbr, 1) < 0) {
353+ weprintf("cannot update MBR on %s:", path);
354+ blockdev_close(&dev);
355+ return -1;
356+ }
357+ printf("Added MBR partition %d to %s\n", opt_part_idx, path);
358+ }
359+ }
360+
361+ if (opt_del) {
362+ if (opt_part_idx < 1) {
363+ weprintf("delete requires partition index (-n)\n");
364+ blockdev_close(&dev);
365+ return -1;
366+ }
367+
368+ if (has_gpt) {
369+ if (opt_part_idx > 128) {
370+ weprintf("GPT partition index must be 1-128\n");
371+ blockdev_close(&dev);
372+ return -1;
373+ }
374+ memset(&gpt_parts[opt_part_idx - 1], 0, sizeof(struct GptPartition));
375+ if (write_gpt(&dev, &gpt_hdr, gpt_parts) < 0) {
376+ weprintf("cannot update GPT on %s:", path);
377+ blockdev_close(&dev);
378+ return -1;
379+ }
380+ printf("Deleted GPT partition %d from %s\n", opt_part_idx, path);
381+ } else {
382+ if (blockdev_read(&dev, 0, &mbr, 1) < 0) {
383+ weprintf("cannot read MBR from %s:", path);
384+ blockdev_close(&dev);
385+ return -1;
386+ }
387+ if (opt_part_idx > 4) {
388+ weprintf("MBR partition index must be 1-4\n");
389+ blockdev_close(&dev);
390+ return -1;
391+ }
392+ memset(&mbr.parts[opt_part_idx - 1], 0, sizeof(struct MbrPartition));
393+ if (blockdev_write(&dev, 0, &mbr, 1) < 0) {
394+ weprintf("cannot update MBR on %s:", path);
395+ blockdev_close(&dev);
396+ return -1;
397+ }
398+ printf("Deleted MBR partition %d from %s\n", opt_part_idx, path);
399+ }
400+ }
401+
402+ blockdev_close(&dev);
403+ return 0;
404+}
405+
406+// ?man fdisk: partition table manipulator
407+// ?man arguments: [-l] [-p] [-g] [-m] [-a] [-d] [-n index] [-b start] [-e end] [-t type] [device]
408+// ?man fdisk performs partition table operations for MBR and GPT disks
409+int
410+main(int argc, char *argv[])
411+{
412+ ARGBEGIN {
413+ // ?man -l:list partitions of all devices
414+ case 'l':
415+ opt_list = 1;
416+ break;
417+ // ?man -p:print partition table of specified device
418+ case 'p':
419+ opt_print = 1;
420+ break;
421+ // ?man -g:initialize disk with GPT
422+ case 'g':
423+ opt_init_gpt = 1;
424+ break;
425+ // ?man -m:initialize disk with MBR
426+ case 'm':
427+ opt_init_mbr = 1;
428+ break;
429+ // ?man -a:add partition
430+ case 'a':
431+ opt_add = 1;
432+ break;
433+ // ?man -d:delete partition
434+ case 'd':
435+ opt_del = 1;
436+ break;
437+ // ?man -n:partition index
438+ case 'n':
439+ opt_part_idx = (int)estrtol(EARGF(usage()), 10);
440+ break;
441+ // ?man -b:starting sector LBA
442+ case 'b':
443+ opt_start = (uint64_t)estrtoul(EARGF(usage()), 10);
444+ break;
445+ // ?man -e:ending sector LBA
446+ case 'e':
447+ opt_end = (uint64_t)estrtoul(EARGF(usage()), 10);
448+ break;
449+ // ?man -t:partition type (MBR hex or GPT string)
450+ case 't':
451+ opt_type = EARGF(usage());
452+ break;
453+ default:
454+ usage();
455+ } ARGEND
456+
457+ if (opt_list) {
458+ struct BlockDevInfo *list = blockdev_get_list();
459+ struct BlockDevInfo *curr;
460+ if (!list)
461+ return 1;
462+ for (curr = list; curr; curr = curr->next) {
463+ char devpath[128];
464+ snprintf(devpath, sizeof(devpath), "/dev/%s", curr->name);
465+ do_print(devpath);
466+ }
467+ blockdev_free_list(list);
468+ return 0;
469+ }
470+
471+ if (argc != 1)
472+ usage();
473+
474+ if (opt_print) {
475+ return do_print(argv[0]) < 0 ? 1 : 0;
476+ }
477+
478+ return do_fdisk(argv[0]) < 0 ? 1 : 0;
479+}
+104,
-0
1@@ -0,0 +1,104 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "diskutil.h"
5+
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s\n", argv0);
14+}
15+
16+static void
17+print_line(int name_pad, const char *name, int major, int minor, const char *size, const char *type, const char *fstype, const char *mountpoint)
18+{
19+ char linebuf[512];
20+ int len;
21+
22+ len = snprintf(linebuf, sizeof(linebuf), "%-*s %3d:%-3d %6s %-4s %-8s %s",
23+ name_pad, name,
24+ major, minor,
25+ size,
26+ type,
27+ fstype,
28+ mountpoint);
29+
30+ /* trim trailing spaces */
31+ while (len > 0 && linebuf[len - 1] == ' ') {
32+ linebuf[len - 1] = '\0';
33+ len--;
34+ }
35+ printf("%s\n", linebuf);
36+}
37+
38+// ?man lsblk: list block devices
39+// ?man lsblk lists information about all available block devices in a tree-like layout
40+int
41+main(int argc, char *argv[])
42+{
43+ struct BlockDevInfo *list, *curr, *part;
44+ char namebuf[64];
45+ char hdrbuf[512];
46+ int max_len = 4;
47+ int hdrlen;
48+
49+ ARGBEGIN {
50+ default:
51+ usage();
52+ } ARGEND
53+
54+ if (argc > 0)
55+ usage();
56+
57+ list = blockdev_get_list();
58+ if (!list)
59+ return 1;
60+
61+ /* calculate maximum display width of the name column */
62+ for (curr = list; curr; curr = curr->next) {
63+ int len = strlen(curr->name);
64+ if (len > max_len)
65+ max_len = len;
66+ for (part = curr->parts; part; part = part->next) {
67+ len = 2 + (int)strlen(part->name);
68+ if (len > max_len)
69+ max_len = len;
70+ }
71+ }
72+
73+ hdrlen = snprintf(hdrbuf, sizeof(hdrbuf), "%-*s %-7s %6s %-4s %-8s %s",
74+ max_len, "NAME", "MAJ:MIN", "SIZE", "TYPE", "FSTYPE", "MOUNTPOINT");
75+ while (hdrlen > 0 && hdrbuf[hdrlen - 1] == ' ') {
76+ hdrbuf[hdrlen - 1] = '\0';
77+ hdrlen--;
78+ }
79+ printf("%s\n", hdrbuf);
80+
81+ for (curr = list; curr; curr = curr->next) {
82+ print_line(max_len,
83+ curr->name,
84+ curr->major, curr->minor,
85+ humansize(curr->size),
86+ curr->type,
87+ curr->fstype[0] ? curr->fstype : "",
88+ curr->mountpoint[0] ? curr->mountpoint : "");
89+
90+ for (part = curr->parts; part; part = part->next) {
91+ int is_last = (part->next == NULL);
92+ snprintf(namebuf, sizeof(namebuf), "%s%s", is_last ? "└─" : "├─", part->name);
93+ print_line(max_len + 4,
94+ namebuf,
95+ part->major, part->minor,
96+ humansize(part->size),
97+ part->type,
98+ part->fstype[0] ? part->fstype : "",
99+ part->mountpoint[0] ? part->mountpoint : "");
100+ }
101+ }
102+
103+ blockdev_free_list(list);
104+ return 0;
105+}
+5,
-8
1@@ -15,23 +15,20 @@ usage(void)
2 eprintf("usage: %s -h | -s\n", argv0);
3 }
4
5-// ?man ctrlaltdel: toggle Ctrl-Alt-Del behaviour
6-// ?man synopsis: -h
7-// ?man synopsis: -s
8-// ?man ctrlaltdel toggles the function of Ctrl-Alt-Del based on the two choices given in linux/kernel/sys.c.
9-// ?man Hard reset reboots the computer immediately without calling sync.
10-// ?man Soft reset sends SIGINT to init.
11+// ?man ctrlaltdel: set ctrl-alt-del function
12+// ?man arguments: -h | -s
13+// ?man set the behavior of the ctrl-alt-del key combination
14 int
15 main(int argc, char *argv[])
16 {
17 int hflag = 0, sflag = 0, cmd;
18
19 ARGBEGIN {
20- // ?man -h: Set to hard reset.
21+ // ?man -h: suppress headers or print help
22 case 'h':
23 hflag = 1;
24 break;
25- // ?man -s: Set to soft reset.
26+ // ?man -s: silent mode or print summary
27 case 's':
28 sflag = 1;
29 break;
+4,
-2
1@@ -263,6 +263,8 @@ usage(void)
2 // ?man depmod: generate modules.dep and map files
3 // ?man arguments: version
4 // ?man depmod generates modules.dep containing dependency information for modprobe
5+// ?man // ?man -n: dry run print results to stdout instead of writing files
6+// ?man // ?man -b basedir: use basedir as prefix for module directories
7 int
8 main(int argc, char *argv[])
9 {
10@@ -279,11 +281,11 @@ main(int argc, char *argv[])
11 FILE *f_dep, *f_alias, *f_sym;
12
13 ARGBEGIN {
14- // ?man -n: Dry run; print results to stdout instead of writing files.
15+ // ?man -n: specify n option
16 case 'n':
17 nflag = 1;
18 break;
19- // ?man -b:dir: Use dir as the prefix for module directories.
20+ // ?man -b:dir: specify b option
21 case 'b':
22 basedir = EARGF(usage());
23 break;
+3,
-4
1@@ -48,15 +48,14 @@ usage(void)
2 eprintf("usage: %s [-t] [device ...]\n", argv0);
3 }
4
5-// ?man eject: control device trays
6+// ?man eject: eject removable media
7 // ?man arguments: device ...
8-// ?man eject opens the tray of each device.
9-// ?man If no device is given eject opens the tray of /dev/sr0.
10+// ?man eject optical discs or other removable storage media
11 int
12 main(int argc, char *argv[])
13 {
14 ARGBEGIN {
15- // ?man -t: Close instead of open the tray.
16+ // ?man -t: sort or specify timestamp
17 case 't':
18 tflag = 1;
19 break;
+4,
-7
1@@ -22,11 +22,8 @@ usage(void)
2 }
3
4 // ?man fsfreeze: suspend access to a filesystem
5-// ?man arguments: mountpoint
6-// ?man fsfreeze suspends and resumes access to a filesystem.
7-// ?man fsfreeze is intended to be used with hardware RAID devices that support the creation of snapshots.
8-// ?man The mountpoint argument is the pathname of the directory where the filesystem is mounted.
9-// ?man The filesystem must be mounted to be frozen.
10+// ?man arguments: (-f | -u) mountpoint
11+// ?man freeze or unfreeze a filesystem to allow safe backups
12 int
13 main(int argc, char *argv[])
14 {
15@@ -36,11 +33,11 @@ main(int argc, char *argv[])
16 int fd;
17
18 ARGBEGIN {
19- // ?man -f: Freeze the filesystem mounted at mountpoint.
20+ // ?man -f: force the operation
21 case 'f':
22 fflag = 1;
23 break;
24- // ?man -u: Unfreeze the filesystem mounted at mountpoint.
25+ // ?man -u: unbuffered output
26 case 'u':
27 uflag = 1;
28 break;
+6,
-10
1@@ -116,11 +116,7 @@ usage(void)
2
3 // ?man hwclock: query or set the hardware clock
4 // ?man arguments: dev
5-// ?man hwclock is a tool for accessing the hardware clock.
6-// ?man You can display the current time, set the hardware clock from the System Time, or set the System Time from the hardware clock.
7-// ?man It currently only works with UTC.
8-// ?man You can use dev to specify the RTC device node absolute path.
9-// ?man By default it will use /dev/rtc.
10+// ?man view or adjust the hardware real time clock
11 int
12 main(int argc, char *argv[])
13 {
14@@ -130,19 +126,19 @@ main(int argc, char *argv[])
15 int wflag = 0;
16
17 ARGBEGIN {
18- // ?man -r: Read the hardware clock and print the time on stdout.
19+ // ?man -r: operate recursively
20 case 'r':
21 rflag = 1;
22 break;
23- // ?man -s: Set the system time from the hardware clock.
24+ // ?man -s: silent mode or print summary
25 case 's':
26 sflag = 1;
27 break;
28- // ?man -w: Set the hardware clock to the system time.
29+ // ?man -w: wait for completion
30 case 'w':
31 wflag = 1;
32 break;
33- // ?man -u: Use UTC. This is the default option.
34+ // ?man -u: unbuffered output
35 case 'u':
36 break;
37 default:
38@@ -169,4 +165,4 @@ main(int argc, char *argv[])
39 systohc(dev);
40
41 return 0;
42-}
43+}
+2,
-2
1@@ -17,8 +17,8 @@ usage(void)
2 }
3
4 // ?man insmod: insert a module into the Linux kernel
5-// ?man arguments: filename [args ...]
6-// ?man insmod inserts the module specified by filename into the kernel. It does not handle module dependencies.
7+// ?man arguments: filename [args...
8+// ?man insmod inserts a kernel module from filename into the running kernel
9 int
10 main(int argc, char *argv[])
11 {
+19,
-10
1@@ -535,7 +535,7 @@ usage(void)
2 }
3
4 // ?man modprobe: add or remove modules from the Linux kernel
5-// ?man arguments: module [symbol=value ...]
6+// ?man arguments: module [symbol=value ...
7 // ?man modprobe loads or removes kernel modules from the running system.
8 // ?man It reads modules.dep, modules.alias, and modules.symbols from the appropriate
9 // ?man /lib/modules/release directory to resolve module names and dependencies,
10@@ -551,39 +551,48 @@ main(int argc, char *argv[])
11 int i, ret = 0;
12
13 ARGBEGIN {
14- // ?man -a: Load all modules named on the command line rather than stopping after the first.
15+ // ?man -a: specify a option
16 case 'a':
17+ // ?man -a: Load all modules named on the command line (rather than stopping after the first).
18 aflag = 1; break;
19- // ?man -r: Remove the named modules from the kernel. Dependencies are not automatically removed.
20+ // ?man -r: specify r option
21 case 'r':
22+ // ?man -r: Remove the named modules from the kernel. Dependencies are not automatically removed.
23 rflag = 1; break;
24- // ?man -q: Quiet mode. Suppress error messages.
25+ // ?man -q: specify q option
26 case 'q':
27+ // ?man -q: Quiet mode. Suppress error messages.
28 qflag = 1; break;
29- // ?man -v: Verbose mode. Print each action taken.
30+ // ?man -v: specify v option
31 case 'v':
32+ // ?man -v: Verbose mode. Print each action taken.
33 vflag = 1; break;
34- // ?man -l: List available modules matching the optional pattern, a fnmatch(3) glob.
35+ // ?man -l: specify l option
36 case 'l':
37+ // ?man -l: List available modules matching the optional _pattern_ (a fnmatch(3) glob).
38 lflag = 1; break;
39 #if FEATURE_MODPROBE_SHOW_DEPENDS
40- // ?man -D: Print the sequence of insmod commands that would be used to load the module, without actually loading anything.
41+ // ?man -D: specify D option
42 case 'D':
43+ // ?man -D: Print the sequence of insmod commands that would be used to load the module, without actually loading anything.
44 Dflag = 1; break;
45 #endif
46 #if FEATURE_MODPROBE_BLACKLIST
47- // ?man -b: Skip modules listed as blacklist in /etc/modprobe.d/.
48+ // ?man -b: specify b option
49 case 'b':
50+ // ?man -b: Skip modules listed as blacklist in /etc/modprobe.d/.
51 bflag = 1; break;
52 #endif
53 #if FEATURE_MODPROBE_SYSLOG
54- // ?man -s: Log messages to syslog(3) facility LOG_DAEMON instead of standard error.
55+ // ?man -s: specify s option
56 case 's':
57+ // ?man -s: Log messages to syslog(3) (facility LOG_DAEMON) instead of standard error.
58 sflag = 1; break;
59 #endif
60 #if FEATURE_MODPROBE_DIR_OVERRIDE
61- // ?man -d:dir: Use dir as the base directory for module files instead of /lib/modules/release.
62+ // ?man -d:file: specify d option
63 case 'd':
64+ // ?man -d dir: Use dir as the base directory for module files instead of /lib/modules/release.
65 strlist_append(&moddirs, EARGF(usage())); break;
66 #endif
67 default:
+9,
-12
1@@ -191,8 +191,8 @@ usage(void)
2 }
3
4 // ?man mount: mount a filesystem
5-// ?man arguments: [source] [target]
6-// ?man mount attaches the filesystem specified to the filesystem hierarchy. The umount command will detach it again.
7+// ?man arguments: source] [target
8+// ?man mount a filesystem to the directory tree
9 int
10 main(int argc, char *argv[])
11 {
12@@ -205,35 +205,32 @@ main(int argc, char *argv[])
13 FILE *fp;
14
15 ARGBEGIN {
16- // ?man -B: Remount a subtree somewhere else (so that its contents are visible in both places).
17+ // ?man -B: specify option flag
18 case 'B':
19 argflags |= MS_BIND;
20 break;
21- // ?man -M: Move a subtree to some other place.
22+ // ?man -M: specify option flag
23 case 'M':
24 argflags |= MS_MOVE;
25 break;
26- // ?man -R: Remount a subtree and all possible submounts somewhere else (so that its contents are available in both places).
27+ // ?man -R: operate recursively on directories
28 case 'R':
29 argflags |= MS_REC;
30 break;
31- // ?man -a: Mount all filesystems mentioned in /etc/fstab.
32+ // ?man -a: print or show all entries
33 case 'a':
34 aflag = 1;
35 break;
36- // ?man -o:options: Specify a comma separated string of filesystem specific options.
37+ // ?man -o:str: specify output file
38 case 'o':
39 estrlcat(fsopts, EARGF(usage()), sizeof(fsopts));
40 parseopts(fsopts, &flags, data, sizeof(data));
41 break;
42- // ?man -t:fstype: Set the filesystem type. More than one type may be specified in a comma separated list.
43- // ?man The list of file system types can be prefixed with "no" to specify the file system types for which action should not be taken.
44- // ?man For example, mount -a -t nonfs,ext4 mounts all file systems except those of type NFS and EXT4.
45- // ?man mount will attempt to execute a program in your PATH mount.XXX where XXX is replaced by the type name. For example, NFS file systems are mounted by the program mount.nfs.
46+ // ?man -t:str: sort or specify timestamp
47 case 't':
48 types = EARGF(usage());
49 break;
50- // ?man -n: Mount without writing in /etc/mtab. This is the default action.
51+ // ?man -n: print line numbers or counts
52 case 'n':
53 break;
54 default:
+4,
-4
1@@ -21,7 +21,7 @@ usage(void)
2
3 // ?man mountpoint: check if a directory is a mountpoint
4 // ?man arguments: target
5-// ?man mountpoint checks if the directory is mentioned in the /proc/mounts file.
6+// ?man determine if a directory is a mountpoint
7 int
8 main(int argc, char *argv[])
9 {
10@@ -32,15 +32,15 @@ main(int argc, char *argv[])
11 struct stat st1, st2;
12
13 ARGBEGIN {
14- // ?man -d: Print the major/minor device number of the filesystem on stdout.
15+ // ?man -d: specify directory
16 case 'd':
17 dflag = 1;
18 break;
19- // ?man -q: Be quiet, don't print anything.
20+ // ?man -q: quiet mode; suppress output
21 case 'q':
22 qflag = 1;
23 break;
24- // ?man -x: Print the major/minor device number of the device on stdout.
25+ // ?man -x: hex format or match whole lines
26 case 'x':
27 xflag = 1;
28 break;
+5,
-3
1@@ -18,7 +18,9 @@ usage(void)
2
3 // ?man rmmod: remove a module from the Linux kernel
4 // ?man arguments: module...
5-// ?man rmmod removes one or more modules from the kernel.
6+// ?man rmmod removes a kernel module from the running kernel
7+// ?man // ?man -f: force removal of a module even if it is busy or in use
8+// ?man // ?man -w: wait for the module to become unused before removing
9 int
10 main(int argc, char *argv[])
11 {
12@@ -27,11 +29,11 @@ main(int argc, char *argv[])
13 int flags = O_NONBLOCK;
14
15 ARGBEGIN {
16- // ?man -f: This option can be extremely dangerous: it has no effect unless CONFIG_MODULE_FORCE_UNLOAD was set when the kernel was compiled. With this option, you can remove modules which are being used, or which are not designed to be removed, or have been marked as unsafe.
17+ // ?man -f: specify f option
18 case 'f':
19 flags |= O_TRUNC;
20 break;
21- // ?man -w: Normally, rmmod will refuse to unload modules which are in use. With this option, rmmod will isolate the module, and wait until the module is no longer used. Noone new will be able to use the module, but it's up to you to make sure the current users eventually finish with it.
22+ // ?man -w: specify w option
23 case 'w':
24 flags &= ~O_NONBLOCK;
25 break;
+3,
-3
1@@ -24,9 +24,9 @@ usage(void)
2 eprintf("usage: %s [-L label] device\n", argv0);
3 }
4
5-// ?man swaplabel: set the label of a swap filesystem
6+// ?man swaplabel: print or change swap label
7 // ?man arguments: device
8-// ?man swaplabel is used to change the label of a swap device or file.
9+// ?man display or modify the label and uuid of a swap device
10 int
11 main(int argc, char *argv[])
12 {
13@@ -38,7 +38,7 @@ main(int argc, char *argv[])
14 int i;
15
16 ARGBEGIN {
17- // ?man -L:label: Change the label.
18+ // ?man -L:str: specify option flag
19 case 'L':
20 setlabel = 1;
21 label = EARGF(usage());
+4,
-5
1@@ -16,10 +16,9 @@ usage(void)
2 eprintf("usage: %s -a | device\n", argv0);
3 }
4
5-// ?man swapoff: disable devices and files for paging and swapping
6-// ?man synopsis: -a
7-// ?man synopsis: device
8-// ?man swapoff disables swapping on the specified devices and files.
9+// ?man swapoff: disable swap devices
10+// ?man arguments: -a | device
11+// ?man disable paging and swapping on specified devices
12 int
13 main(int argc, char *argv[])
14 {
15@@ -30,7 +29,7 @@ main(int argc, char *argv[])
16 FILE *fp;
17
18 ARGBEGIN {
19- // ?man -a: Disable swapping on all known swap devices and files as found in /etc/fstab.
20+ // ?man -a: print or show all entries
21 case 'a':
22 all = 1;
23 break;
+6,
-7
1@@ -16,10 +16,9 @@ usage(void)
2 eprintf("usage: %s [-dp] -a | device\n", argv0);
3 }
4
5-// ?man swapon: enable devices and files for paging and swapping
6-// ?man synopsis: [-d] [-p] -a
7-// ?man synopsis: [-d] [-p] device
8-// ?man swapon is used to specify devices on which paging and swapping are to take place.
9+// ?man swapon: enable swap devices
10+// ?man arguments: -a | device
11+// ?man enable paging and swapping on specified devices
12 int
13 main(int argc, char *argv[])
14 {
15@@ -31,15 +30,15 @@ main(int argc, char *argv[])
16 FILE *fp;
17
18 ARGBEGIN {
19- // ?man -a: Make all devices marked as "swap" in /etc/fstab available, except for those with the "noauto" option.
20+ // ?man -a: print or show all entries
21 case 'a':
22 all = 1;
23 break;
24- // ?man -d: Discard freed swap pages before they are reused.
25+ // ?man -d: specify directory
26 case 'd':
27 flags |= SWAP_FLAG_DISCARD;
28 break;
29- // ?man -p: Set higher priority than the default for the new swap area.
30+ // ?man -p: preserve file attributes
31 case 'p':
32 flags |= SWAP_FLAG_PREFER;
33 break;
+3,
-6
1@@ -67,11 +67,8 @@ usage(void)
2 }
3
4 // ?man switch_root: switch to another root filesystem
5-// ?man arguments: [newroot] [init]
6-// ?man switch_root removes all files and directories on the current root filesystem and overmounts it with newroot.
7-// ?man If a console is specified, redirect stdio and stderr to it.
8-// ?man After the switch, execute init.
9-// ?man switch_root can only be run as PID 1 in an initramfs or tmpfs with a regular and executable /sbin/init.
10+// ?man arguments: newroot] [init] (PID 1)
11+// ?man switch to another filesystem as the root of the mount tree
12 int
13 main(int argc, char *argv[])
14 {
15@@ -81,7 +78,7 @@ main(int argc, char *argv[])
16 struct statfs stfs;
17
18 ARGBEGIN {
19- // ?man -c:console: Redirect stdio and stderr to console after switching to newroot.
20+ // ?man -c:str: print count or perform stdout action
21 case 'c':
22 console = EARGF(usage());
23 break;
+3,
-6
1@@ -160,12 +160,9 @@ usage(void)
2 eprintf("usage: %s [-p file] variable[=value]...\n", argv0);
3 }
4
5-// ?man sysctl: configure kernel parameters at runtime
6+// ?man sysctl: configure kernel parameters
7 // ?man arguments: variable[=value]...
8-// ?man sysctl modifies kernel parameters at runtime.
9-// ?man The parameters available are those listed under /proc/sys.
10-// ?man Procfs is required for sysctl support in Linux.
11-// ?man You can use sysctl to both read and write sysctl data.
12+// ?man view and modify kernel parameters at runtime
13 int
14 main(int argc, char *argv[])
15 {
16@@ -177,7 +174,7 @@ main(int argc, char *argv[])
17 int r = 0;
18
19 ARGBEGIN {
20- // ?man -p:file: Load the sysctl key=value pairs from file.
21+ // ?man -p:file: preserve file attributes
22 case 'p':
23 file = EARGF(usage());
24 break;
+4,
-4
1@@ -43,21 +43,21 @@ main(int argc, char *argv[])
2
3 ARGBEGIN
4 {
5- // ?man -d: Clear persistence on the interface.
6+ // ?man -d: specify directory
7 case 'd':
8 dflag = 1;
9 tflag = 0;
10 break;
11- // ?man -t: Make the interface persistent.
12+ // ?man -t: sort or specify timestamp
13 case 't':
14 tflag = 1;
15 dflag = 0;
16 break;
17- // ?man -T: Create a TAP device instead of a TUN device.
18+ // ?man -T: specify option flag
19 case 'T':
20 Tflag = 1;
21 break;
22- // ?man -u:owner: Set the owner of the persistent interface.
23+ // ?man -u:str: unbuffered output
24 case 'u':
25 owner = EARGF(usage());
26 break;
+6,
-8
1@@ -127,9 +127,7 @@ usage(void)
2
3 // ?man umount: unmount filesystems
4 // ?man arguments: target...
5-// ?man umount detaches the target filesystem or filesystems.
6-// ?man A file system is specified by giving the directory where it has been mounted.
7-// ?man Giving the special device on which the file system lives may also work, but is obsolete, mainly because it will fail in case this device was mounted on more than one directory.
8+// ?man unmount a filesystem from the directory tree
9 int
10 main(int argc, char *argv[])
11 {
12@@ -142,23 +140,23 @@ main(int argc, char *argv[])
13 #endif
14
15 ARGBEGIN {
16- // ?man -a: All of the file systems described in /proc/mounts are unmounted. The proc filesystem is not unmounted.
17+ // ?man -a: print or show all entries
18 case 'a':
19 aflag = 1;
20 break;
21- // ?man -f: Force unmount (in case of an unreachable NFS server).
22+ // ?man -f: force the operation
23 case 'f':
24 flags |= MNT_FORCE;
25 break;
26- // ?man -l: Lazy unmount. Detach the filesystem from the fs hierarchy now, and cleanup all references to the filesystem as soon as it is not busy anymore.
27+ // ?man -l: list in long format
28 case 'l':
29 flags |= MNT_DETACH;
30 break;
31- // ?man -n: Unmount without writing in /etc/mtab. This is the default action.
32+ // ?man -n: print line numbers or counts
33 case 'n':
34 break;
35 #if FEATURE_UMOUNT_OPTIONS
36- // ?man -O:opts: Only act on mounts matching opts.
37+ // ?man -O:str: specify option flag
38 case 'O':
39 oflag = EARGF(usage());
40 break;
1@@ -15,37 +15,36 @@ usage(void)
2 eprintf("usage: %s [-muinpU] cmd [args...]\n", argv0);
3 }
4
5-// ?man unshare: run program with some namespaces unshared from parent
6-// ?man arguments: cmd [args ...]
7-// ?man unshare unshares the indicated namespaces from the parent process and then executes the specified program.
8-// ?man The namespaces to be unshared are indicated via options.
9+// ?man unshare: run program in new namespaces
10+// ?man arguments: cmd [args...
11+// ?man run a program with some namespaces unshared from the parent
12 int
13 main(int argc, char *argv[])
14 {
15 int flags = 0;
16
17 ARGBEGIN {
18- // ?man -m: Unshare the mount namespace, so that the calling process has a private copy of its namespace which is not shared with any other process. This flag has the same effect as the clone CLONE_NEWNS flag.
19+ // ?man -m: specify mode or limit
20 case 'm':
21 flags |= CLONE_NEWNS;
22 break;
23- // ?man -u: Unshare the UTS IPC namespace, so that the calling process has a private copy of the UTS namespace which is not shared with any other process. This flag has the same effect as the clone CLONE_NEWUTS flag.
24+ // ?man -u: unbuffered output
25 case 'u':
26 flags |= CLONE_NEWUTS;
27 break;
28- // ?man -i: Unshare the System V IPC namespace, so that the calling process has a private copy of the System V IPC namespace which is not shared with any other process. This flag has the same effect as the clone CLONE_NEWIPC flag.
29+ // ?man -i: interactive mode or prompt for confirmation
30 case 'i':
31 flags |= CLONE_NEWIPC;
32 break;
33- // ?man -n: Unshare the network namespace, so that the calling process is moved into a new network namespace which is not shared with any previously existing process. This flag has the same effect as the clone CLONE_NEWNET flag.
34+ // ?man -n: print line numbers or counts
35 case 'n':
36 flags |= CLONE_NEWNET;
37 break;
38- // ?man -p: Create the process in a new PID namespace. This flag has the same effect as the clone CLONE_NEWPID flag.
39+ // ?man -p: preserve file attributes
40 case 'p':
41 flags |= CLONE_NEWPID;
42 break;
43- // ?man -U: The process will have a distinct set of UIDs, GIDs and capabilities.
44+ // ?man -U: specify option flag
45 case 'U':
46 flags |= CLONE_NEWUSER;
47 break;
+2,
-2
1@@ -258,7 +258,7 @@ parse_response(const unsigned char *resp, int resp_len, const char *query_name)
2 }
3
4 // ?man host: dns lookup utility
5-// ?man arguments: name [server]
6+// ?man arguments: name [server
7 // ?man look up hostnames and IP addresses using dns
8 int
9 main(int argc, char *argv[])
10@@ -274,7 +274,7 @@ main(int argc, char *argv[])
11 int i, r;
12
13 ARGBEGIN {
14- // ?man -t:type: Query DNS records of the given type.
15+ // ?man -t:str: sort or specify timestamp
16 case 't':
17 tflag = EARGF(usage());
18 break;
+3,
-3
1@@ -262,15 +262,15 @@ main(int argc, char *argv[])
2 char *enc;
3
4 ARGBEGIN {
5- // ?man -e:str: Print the URL-encoded form of str and exit.
6+ // ?man -e:str: specify expression or pattern
7 case 'e':
8 eflag = EARGF(usage());
9 break;
10- // ?man -d:str: Print the URL-decoded form of str and exit.
11+ // ?man -d:str: specify directory
12 case 'd':
13 dflag = EARGF(usage());
14 break;
15- // ?man -v: Accepted for compatibility; no effect.
16+ // ?man -v: verbose mode; show progress
17 case 'v':
18 break;
19 default:
+2,
-2
1@@ -98,7 +98,7 @@ list_interfaces(int all)
2 }
3
4 // ?man ifconfig: configure network interfaces
5-// ?man arguments: interface [action ...]
6+// ?man arguments: interface [action ...
7 // ?man configure network interface parameters and view stats
8 int
9 main(int argc, char *argv[])
10@@ -118,7 +118,7 @@ main(int argc, char *argv[])
11 unsigned int mask;
12
13 ARGBEGIN {
14- // ?man -a: Show all interfaces, including those that are down.
15+ // ?man -a: print or show all entries
16 case 'a':
17 aflag = 1;
18 break;
+1,
-3
1@@ -346,9 +346,7 @@ do_route(int argc, char *argv[])
2 }
3
4 // ?man ip: show or configure routing and devices
5-// ?man synopsis: addr [args ...]
6-// ?man synopsis: link [args ...]
7-// ?man synopsis: route [args ...]
8+// ?man arguments: addr | link | route] [args...
9 // ?man configure and view network devices, routing, and tunnels
10 // ?man ## COMMANDS
11 // ?man ### addr [show | list [dev <device>]]
+4,
-4
1@@ -49,7 +49,7 @@ resolve(const char *host, const char *port, int family, int socktype,
2 }
3
4 // ?man netcat: read and write data across network connections
5-// ?man arguments: [host] [port]
6+// ?man arguments: host] [port
7 // ?man arbitrary data transmission over tcp or udp
8 int
9 main(int argc, char *argv[])
10@@ -70,15 +70,15 @@ main(int argc, char *argv[])
11
12 ARGBEGIN
13 {
14- // ?man -l: Listen for an incoming connection.
15+ // ?man -l: list in long format
16 case 'l':
17 lflag = 1;
18 break;
19- // ?man -p:port: Use port as the local port.
20+ // ?man -p:str: preserve file attributes
21 case 'p':
22 local_port = EARGF(usage());
23 break;
24- // ?man -u: Use UDP instead of TCP.
25+ // ?man -u: unbuffered output
26 case 'u':
27 uflag = 1;
28 break;
+5,
-5
1@@ -141,23 +141,23 @@ main(int argc, char *argv[])
2 socklen_t fromlen;
3
4 ARGBEGIN {
5- // ?man -c:count: Stop after sending count requests.
6+ // ?man -c:str: print count or perform stdout action
7 case 'c':
8 cflag = EARGF(usage());
9 break;
10- // ?man -i:interval: Wait interval seconds between requests.
11+ // ?man -i:str: interactive mode or prompt for confirmation
12 case 'i':
13 iflag = EARGF(usage());
14 break;
15- // ?man -s:size: Send size bytes of payload data.
16+ // ?man -s:str: silent mode or print summary
17 case 's':
18 sflag = EARGF(usage());
19 break;
20- // ?man -t:ttl: Set the IP time-to-live.
21+ // ?man -t:str: sort or specify timestamp
22 case 't':
23 tflag = EARGF(usage());
24 break;
25- // ?man -w:deadline: Stop after deadline seconds.
26+ // ?man -w:str: wait for completion
27 case 'w':
28 wflag = EARGF(usage());
29 break;
+4,
-4
1@@ -261,19 +261,19 @@ main(int argc, char *argv[])
2 int ret;
3
4 ARGBEGIN {
5- // ?man -h:host: Connect to host.
6+ // ?man -h:str: suppress headers or print help
7 case 'h':
8 host = EARGF(usage());
9 break;
10- // ?man -p:port: Use port instead of the default tftp service.
11+ // ?man -p:str: preserve file attributes
12 case 'p':
13 port = EARGF(usage());
14 break;
15- // ?man -x: Download file from the server.
16+ // ?man -x: hex format or match whole lines
17 case 'x':
18 fn = getfile;
19 break;
20- // ?man -c: Upload file to the server.
21+ // ?man -c: print count or perform stdout action
22 case 'c':
23 fn = putfile;
24 break;
+8,
-8
1@@ -327,35 +327,35 @@ main(int argc, char *argv[])
2 size_t i;
3
4 ARGBEGIN {
5- // ?man -O:str: Write output to str instead of the default file name.
6+ // ?man -O:str: specify output file path
7 case 'O':
8 Oflag = EARGF(usage());
9 break;
10- // ?man -P:str: Write output files under directory str.
11+ // ?man -P:str: specify output directory prefix
12 case 'P':
13 Pflag = EARGF(usage());
14 break;
15- // ?man -T:num: Set the network read and connect timeout to num seconds.
16+ // ?man -T:num: set network read and connect timeout
17 case 'T':
18 timeout_sec = estrtonum(EARGF(usage()), 0, 100000);
19 break;
20- // ?man -U:str: Set the User-Agent header to str.
21+ // ?man -U:str: set User-Agent header
22 case 'U':
23 user_agent = EARGF(usage());
24 break;
25- // ?man -c: Continue retrieval of an aborted transfer.
26+ // ?man -c: continue retrieval of aborted transfer
27 case 'c':
28 cflag = 1;
29 break;
30- // ?man -q: Quiet mode. Suppress stderr output.
31+ // ?man -q: quiet mode to suppress stderr output
32 case 'q':
33 qflag = 1;
34 break;
35- // ?man -S: Print server response headers to stderr.
36+ // ?man -S: print server response headers to stderr
37 case 'S':
38 Sflag = 1;
39 break;
40- /* long options handle TLS verification, extra headers, POST data, and spider mode */
41+ // ?man --: specify - option
42 case '-':
43 if (strcmp(argv[0], "-no-check-certificate") == 0) {
44 no_check_certificate = 1;
+1,
-1
1@@ -14,7 +14,7 @@ usage(void)
2 }
3
4 // ?man basename: strip directory and suffix from filenames
5-// ?man arguments: path [suffix]
6+// ?man arguments: path [suffix
7 // ?man print filename with leading directories and optional suffix removed
8 int
9 main(int argc, char *argv[])
+8,
-8
1@@ -179,11 +179,11 @@ main(int argc, char *argv[])
2
3 ARGBEGIN {
4 #ifdef FEATURE_CAL_EXT
5- // ?man -1: print the current month
6+ // ?man -1: specify option flag
7 case '1':
8 nmons = 1;
9 break;
10- // ?man -3: print the previous, current, and next month
11+ // ?man -3: specify option flag
12 case '3':
13 nmons = 3;
14 if (--month == 0) {
15@@ -191,28 +191,28 @@ main(int argc, char *argv[])
16 year--;
17 }
18 break;
19- // ?man -c:num: print num calendars in a row
20+ // ?man -c:num: print count or perform stdout action
21 case 'c':
22 ncols = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)SIZE_MAX, (unsigned long long)LLONG_MAX));
23 break;
24- // ?man -f:num: use num as the first day of the week, where 0 is Sunday
25+ // ?man -f:num: force the operation
26 case 'f':
27 fday = estrtonum(EARGF(usage()), 0, 6);
28 break;
29- // ?man -m: use Monday as the first day of the week
30+ // ?man -m: specify mode or limit
31 case 'm': /* Monday */
32 fday = 1;
33 break;
34- // ?man -n:num: output num months starting with the current month
35+ // ?man -n:num: print line numbers or counts
36 case 'n':
37 nmons = estrtonum(EARGF(usage()), 1, MIN((unsigned long long)SIZE_MAX, (unsigned long long)LLONG_MAX));
38 break;
39- // ?man -s: use Sunday as the first day of the week
40+ // ?man -s: silent mode or print summary
41 case 's': /* Sunday */
42 fday = 0;
43 break;
44 #endif
45- // ?man -y: print the entire year
46+ // ?man -y: specify option flag
47 case 'y':
48 month = 1;
49 nmons = 12;
+4,
-3
1@@ -15,8 +15,8 @@ usage(void)
2 }
3
4 // ?man cat: concatenate files and print to standard output
5-// ?man arguments: [file ...]
6-// ?man cat reads each file in sequence and writes its contents to standard output
7+// ?man arguments: file ...
8+// ?man cat reads each file in sequence and writes it to standard output
9 // ?man if no file is given, or a file is -, standard input is read
10 int
11 main(int argc, char *argv[])
12@@ -24,8 +24,9 @@ main(int argc, char *argv[])
13 int fd, ret = 0;
14
15 ARGBEGIN {
16- // ?man -u: accepted for posix compatibility; output is always unbuffered
17+ // ?man -u: specify u option
18 case 'u':
19+ // ?man -u: ignored; accepted for posix compatibility; output is always unbuffered
20 break;
21 default:
22 usage();
+4,
-4
1@@ -48,7 +48,7 @@ main(int argc, char *argv[])
2 struct recursor r = { .fn = chgrp, .maxdepth = 1, .follow = 'P' };
3
4 ARGBEGIN {
5- // ?man -h: operate on symbolic links themselves instead of their targets
6+ // ?man -h: affect symbolic links instead of referenced files
7 case 'h':
8 hflag = 1;
9 break;
10@@ -56,11 +56,11 @@ main(int argc, char *argv[])
11 case 'R':
12 r.maxdepth = 0;
13 break;
14- // ?man -H: dereference command-line symbolic links during recursive traversal
15+ // ?man -H: specify option flag
16 case 'H':
17- // ?man -L: dereference all symbolic links during recursive traversal
18+ // ?man -L: specify option flag
19 case 'L':
20- // ?man -P: preserve symbolic links during recursive traversal
21+ // ?man -P: specify option flag
22 case 'P':
23 r.follow = ARGC();
24 break;
+5,
-6
1@@ -45,8 +45,7 @@ usage(void)
2 }
3
4 // ?man chown: change ownership
5-// ?man synopsis: owner[:[group]] file ...
6-// ?man synopsis: :group file ...
7+// ?man arguments: owner[:[group]] file ...
8 // ?man change the user and group ownership of files and directories
9 int
10 main(int argc, char *argv[])
11@@ -57,7 +56,7 @@ main(int argc, char *argv[])
12 char *owner, *group;
13
14 ARGBEGIN {
15- // ?man -h: operate on symbolic links themselves instead of their targets
16+ // ?man -h: affect symbolic links instead of referenced files
17 case 'h':
18 hflag = 1;
19 break;
20@@ -67,11 +66,11 @@ main(int argc, char *argv[])
21 case 'R':
22 r.maxdepth = 0;
23 break;
24- // ?man -H: dereference command-line symbolic links during recursive traversal
25+ // ?man -H: specify option flag
26 case 'H':
27- // ?man -L: dereference all symbolic links during recursive traversal
28+ // ?man -L: specify option flag
29 case 'L':
30- // ?man -P: preserve symbolic links during recursive traversal
31+ // ?man -P: specify option flag
32 case 'P':
33 r.follow = ARGC();
34 break;
+2,
-2
1@@ -24,11 +24,11 @@ main(int argc, char *argv[])
2 int ret = 0, lflag = 0, sflag = 0, same = 1, b[2];
3
4 ARGBEGIN {
5- // ?man -l: print the byte number and differing bytes for every difference
6+ // ?man -l: list in long format
7 case 'l':
8 lflag = 1;
9 break;
10- // ?man -s: print nothing and return status only
11+ // ?man -s: silent mode or print summary
12 case 's':
13 sflag = 1;
14 break;
+3,
-3
1@@ -44,11 +44,11 @@ main(int argc, char *argv[])
2 int ret = 0, i, diff = 0, seenline = 0;
3
4 ARGBEGIN {
5- // ?man -1: suppress lines unique to file1
6+ // ?man -1: specify option flag
7 case '1':
8- // ?man -2: suppress lines unique to file2
9+ // ?man -2: specify option flag
10 case '2':
11- // ?man -3: suppress lines common to both files
12+ // ?man -3: specify option flag
13 case '3':
14 show &= 0x07 ^ (1 << (ARGC() - '1'));
15 break;
+6,
-6
1@@ -25,7 +25,7 @@ main(int argc, char *argv[])
2 case 'i':
3 cp_iflag = 1;
4 break;
5- // ?man -a: preserve devices, sockets, and fifos; implies -pPR
6+ // ?man -a: archive mode; equivalent to -dpR
7 case 'a':
8 cp_follow = 'P';
9 cp_aflag = cp_pflag = cp_rflag = 1;
10@@ -34,7 +34,7 @@ main(int argc, char *argv[])
11 case 'f':
12 cp_fflag = 1;
13 break;
14- // ?man -p: preserve mode, timestamps, and ownership
15+ // ?man -p: preserve file attributes
16 case 'p':
17 cp_pflag = 1;
18 break;
19@@ -44,15 +44,15 @@ main(int argc, char *argv[])
20 case 'R':
21 cp_rflag = 1;
22 break;
23- // ?man -v: write each copied source and destination path
24+ // ?man -v: verbose mode; show progress
25 case 'v':
26 cp_vflag = 1;
27 break;
28- // ?man -H: dereference source arguments that are symbolic links
29+ // ?man -H: specify option flag
30 case 'H':
31- // ?man -L: dereference all symbolic links
32+ // ?man -L: specify option flag
33 case 'L':
34- // ?man -P: preserve symbolic links
35+ // ?man -P: specify option flag
36 case 'P':
37 cp_follow = ARGC();
38 break;
+9,
-23
1@@ -161,20 +161,9 @@ usage(void)
2 argv0, argv0, argv0);
3 }
4
5-// ?man cut: extract columns of data
6-// ?man synopsis: -b list [-n] [file ...]
7-// ?man synopsis: -c list [file ...]
8-// ?man synopsis: -f list [-d delim] [-s] [file ...]
9-// ?man cut out bytes, characters or delimited fields from each line of file and
10-// ?man write to stdout.
11-// ?man If no file is given or file is '-', cut reads from stdin.
12-// ?man list is a comma or space separated list of numbers and ranges starting
13-// ?man from 1.
14-// ?man Ranges have the form 'N-M'. If N or M is missing, beginning or end
15-// ?man of line is assumed.
16-// ?man Numbers and ranges may be repeated, overlapping and in any order.
17-// ?man Selected input is written in the same order it is read
18-// ?man and is written exactly once.
19+// ?man cut: cut out fields from lines
20+// ?man arguments: -b list [file ...
21+// ?man print selected parts of lines from files
22 int
23 main(int argc, char *argv[])
24 {
25@@ -182,30 +171,27 @@ main(int argc, char *argv[])
26 int ret = 0;
27
28 ARGBEGIN {
29- // ?man -b:list: list specifies byte | character positions.
30+ // ?man -b: specify block size or base directory
31 case 'b':
32- // ?man -c:list: list specifies byte | character positions.
33+ // ?man -c: print count or perform stdout action
34 case 'c':
35- // ?man -f:list: list specifies field numbers.
36- // ?man Lines not containing field delimiters are passed through, unless -s is specified.
37+ // ?man -f:mode: force the operation
38 case 'f':
39 mode = ARGC();
40 parselist(EARGF(usage()));
41 break;
42- // ?man -d:delim: Use delim as field delimiter, which can be an arbitrary string.
43- // ?man Default is '\\t'.
44+ // ?man -d:str: specify directory
45 case 'd':
46 delim = EARGF(usage());
47 if (!*delim)
48 eprintf("empty delimiter\n");
49 delimlen = unescape(delim);
50 break;
51- // ?man -n: Do not split multibyte characters.
52- // ?man A character is written when its last byte is selected.
53+ // ?man -n: print line numbers or counts
54 case 'n':
55 nflag = 1;
56 break;
57- // ?man -s: Suppress lines not containing field delimiters.
58+ // ?man -s: silent mode or print summary
59 case 's':
60 sflag = 1;
61 break;
+3,
-4
1@@ -64,8 +64,7 @@ setdate(const char *s, struct tm *now)
2 }
3
4 // ?man date: print or set system date and time
5-// ?man synopsis: [-u] [-d time] [+format]
6-// ?man synopsis: [-u] [-d time] [mmddHHMM[[CC]yy]]
7+// ?man arguments: +format | mmddHHMM[[CC]yy
8 // ?man display or configure the system date and time
9 int
10 main(int argc, char *argv[])
11@@ -79,11 +78,11 @@ main(int argc, char *argv[])
12 eprintf("time:");
13
14 ARGBEGIN {
15- // ?man -d:time: print time as seconds since the Unix epoch
16+ // ?man -d:num: specify directory
17 case 'd':
18 t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
19 break;
20- // ?man -u: print or set UTC time instead of local time
21+ // ?man -u: unbuffered output
22 case 'u':
23 if (setenv("TZ", "UTC0", 1) < 0)
24 eprintf("setenv:");
+7,
-7
1@@ -91,8 +91,8 @@ usage(void)
2 eprintf("usage: %s [-a]\n", argv0);
3 }
4
5-// ?man df: show file system usage
6-// ?man df displays the amount of disk space available on a file system. If no arguments are given, df shows all the file systems using 512-byte blocks.
7+// ?man df: report disk space usage
8+// ?man display free and used disk space on filesystems
9 int
10 main(int argc, char *argv[])
11 {
12@@ -101,24 +101,24 @@ main(int argc, char *argv[])
13 int ret = 0;
14
15 ARGBEGIN {
16- // ?man -a: Show all file systems including dummy ones. This is the default option.
17+ // ?man -a: print or show all entries
18 case 'a':
19 aflag = 1;
20 break;
21- // ?man -h: Not implemented.
22+ // ?man -h: suppress headers or print help
23 case 'h':
24 hflag = 1;
25 kflag = 0;
26 break;
27- // ?man -k: Print sizes in 1024-byte blocks.
28+ // ?man -k: specify option flag
29 case 'k':
30 kflag = 1;
31 hflag = 0;
32 blksize = 1024;
33 break;
34- // ?man -s: Accepted for compatibility; not implemented.
35+ // ?man -s: silent mode or print summary
36 case 's':
37- // ?man -i: Not implemented.
38+ // ?man -i: interactive mode or prompt for confirmation
39 case 'i':
40 eprintf("not implemented\n");
41 break;
+9,
-9
1@@ -122,36 +122,36 @@ main(int argc, char *argv[])
2 char *bsize;
3
4 ARGBEGIN {
5- // ?man -a: display an entry for each file in the hierarchy
6+ // ?man -a: print or show all entries
7 case 'a':
8 aflag = 1;
9 break;
10- // ?man -d:depth: limit output to depth levels of subdirectories
11+ // ?man -d:num: specify directory
12 case 'd':
13 dflag = 1;
14 maxdepth = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
15 break;
16- // ?man -h: print sizes in human-readable units
17+ // ?man -h: suppress headers or print help
18 case 'h':
19 hflag = 1;
20 break;
21- // ?man -k: report sizes in kilobytes instead of 512-byte blocks
22+ // ?man -k: specify option flag
23 case 'k':
24 kflag = 1;
25 break;
26- // ?man -s: display only the total for each specified file
27+ // ?man -s: silent mode or print summary
28 case 's':
29 sflag = 1;
30 break;
31- // ?man -x: stay on the current file system
32+ // ?man -x: hex format or match whole lines
33 case 'x':
34 r.flags |= SAMEDEV;
35 break;
36- // ?man -H: follow symbolic links given on the command line
37+ // ?man -H: specify option flag
38 case 'H':
39- // ?man -L: follow all symbolic links
40+ // ?man -L: specify option flag
41 case 'L':
42- // ?man -P: do not follow symbolic links
43+ // ?man -P: specify option flag
44 case 'P':
45 r.follow = ARGC();
46 break;
+3,
-3
1@@ -18,7 +18,7 @@ usage(void)
2 }
3
4 // ?man env: run command in modified environment
5-// ?man arguments: [name=value ...] [cmd [arg ...]]
6+// ?man arguments: ... [var=value] ... [cmd [arg ...
7 // ?man set environment variables and run a command
8 int
9 main(int argc, char *argv[])
10@@ -26,11 +26,11 @@ main(int argc, char *argv[])
11 int savederrno;
12
13 ARGBEGIN {
14- // ?man -i: ignore the inherited environment and start from an empty one
15+ // ?man -i: interactive mode or prompt for confirmation
16 case 'i':
17 *environ = NULL;
18 break;
19- // ?man -u:name: remove name from the environment
20+ // ?man -u:str: unbuffered output
21 case 'u':
22 if (unsetenv(EARGF(usage())) < 0)
23 eprintf("unsetenv:");
+2,
-2
1@@ -98,11 +98,11 @@ main(int argc, char *argv[])
2 char *tl = "8";
3
4 ARGBEGIN {
5- // ?man -i: only expand tabs at the start of lines
6+ // ?man -i: interactive mode or prompt for confirmation
7 case 'i':
8 iflag = 1;
9 break;
10- // ?man -t:list: use list as the tab size or tab stops
11+ // ?man -t:str: sort or specify timestamp
12 case 't':
13 tl = EARGF(usage());
14 if (!*tl)
+3,
-3
1@@ -1421,7 +1421,7 @@ usage(void)
2 }
3
4 // ?man find: search for files
5-// ?man arguments: path ... [expression ...]
6+// ?man arguments: path ... [expression ...
7 // ?man search for files in a directory hierarchy
8 int
9 main(int argc, char **argv)
10@@ -1434,12 +1434,12 @@ main(int argc, char **argv)
11 gflags.mindepth = -1;
12
13 ARGBEGIN {
14- // ?man -H: dereference symbolic links given on the command line
15+ // ?man -H: specify option flag
16 case 'H':
17 gflags.h = 1;
18 gflags.l = 0;
19 break;
20- // ?man -L: dereference all symbolic links encountered
21+ // ?man -L: specify option flag
22 case 'L':
23 gflags.l = 1;
24 gflags.h = 0;
+5,
-5
1@@ -85,7 +85,7 @@ usage(void)
2 }
3
4 // ?man fold: wrap lines to fit width
5-// ?man arguments: file ...
6+// ?man arguments: FILE ...
7 // ?man wrap input lines to fit a specified width
8 int
9 main(int argc, char *argv[])
10@@ -94,19 +94,19 @@ main(int argc, char *argv[])
11 int ret = 0;
12
13 ARGBEGIN {
14- // ?man -b: count bytes rather than characters
15+ // ?man -b: specify block size or base directory
16 case 'b':
17 bflag = 1;
18 break;
19- // ?man -s: break at the last space within the width when possible
20+ // ?man -s: silent mode or print summary
21 case 's':
22 sflag = 1;
23 break;
24- // ?man -w:num: wrap lines at num columns instead of 80
25+ // ?man -w:num: wait for completion
26 case 'w':
27 width = estrtonum(EARGF(usage()), 1, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
28 break;
29- /* -num is accepted as shorthand for -w num */
30+ // ?man ARGNUM: specify RGNUM option
31 ARGNUM:
32 if (!(width = ARGNUMF()))
33 eprintf("illegal width value, too small\n");
+2,
-2
1@@ -23,7 +23,7 @@ usage(void)
2 }
3
4 // ?man getconf: query configuration variables
5-// ?man arguments: var [path]
6+// ?man arguments: var [path
7 // ?man query system configuration variables
8 int
9 main(int argc, char *argv[])
10@@ -34,7 +34,7 @@ main(int argc, char *argv[])
11 char *str;
12
13 ARGBEGIN {
14- // ?man -v:spec: accepted for compatibility; ignored
15+ // ?man -v:str: verbose mode; show progress
16 case 'v':
17 /* ignore */
18 EARGF(usage());
+21,
-21
1@@ -244,7 +244,7 @@ usage(void)
2 }
3
4 // ?man grep: search files for a pattern
5-// ?man arguments: pattern [file ...]
6+// ?man arguments: pattern] [file ...
7 // ?man grep searches the named input files for lines matching the given pattern
8 // ?man if no files are named, or a file is -, standard input is searched
9 // ?man by default, matching lines are written to standard output
10@@ -260,54 +260,54 @@ main(int argc, char *argv[])
11
12 ARGBEGIN {
13 #if FEATURE_GREP_CONTEXT
14- // ?man -A:num: print num lines of trailing context after each match
15+ // ?man -A:num: specify A option
16 case 'A':
17 // ?man -A num: print num lines of trailing context after each match
18 Aflag = estrtonum(EARGF(usage()), 0, LONG_MAX);
19 break;
20- // ?man -B:num: print num lines of leading context before each match
21+ // ?man -B:num: specify B option
22 case 'B':
23 // ?man -B num: print num lines of leading context before each match
24 Bflag = estrtonum(EARGF(usage()), 0, LONG_MAX);
25 break;
26- // ?man -C:num: print num lines of context before and after each match
27+ // ?man -C:num: specify C option
28 case 'C':
29 // ?man -C num: print num lines of context before and after each match; equivalent to -A num -B num
30 Aflag = Bflag = estrtonum(EARGF(usage()), 0, LONG_MAX);
31 break;
32- /* -num is accepted as shorthand for -C num */
33+ // ?man ARGNUM: specify RGNUM option
34 ARGNUM:
35 Aflag = Bflag = ARGNUMF();
36 break;
37 #endif
38 #if FEATURE_GREP_MAX_COUNT
39- // ?man -m:num: stop reading a file after num matching lines
40+ // ?man -m:num: specify m option
41 case 'm':
42 // ?man -m num: stop reading a file after num matching lines
43 mval = estrtonum(EARGF(usage()), 0, LONG_MAX);
44 break;
45 #endif
46- // ?man -E: interpret pattern as an extended regular expression
47+ // ?man -E: specify E option
48 case 'E':
49 // ?man -E: interpret pattern as an extended regular expression
50 Eflag = 1;
51 Fflag = 0;
52 flags |= REG_EXTENDED;
53 break;
54- // ?man -F: interpret patterns as fixed strings
55+ // ?man -F: specify F option
56 case 'F':
57 // ?man -F: interpret pattern as a list of fixed strings separated by newlines
58 Fflag = 1;
59 Eflag = 0;
60 flags &= ~REG_EXTENDED;
61 break;
62- // ?man -H: always print file names with matching lines
63+ // ?man -H: specify H option
64 case 'H':
65 // ?man -H: always print the file name with matching lines
66 Hflag = 1;
67 hflag = 0;
68 break;
69- // ?man -e:pattern: specify a pattern to match; may be given multiple times
70+ // ?man -e:file: specify e option
71 case 'e':
72 // ?man -e pattern: specify a pattern to match; may be given multiple times
73 arg = EARGF(usage());
74@@ -317,7 +317,7 @@ main(int argc, char *argv[])
75 efshut(fp, arg);
76 eflag = 1;
77 break;
78- // ?man -f:file: read patterns from file, one per line
79+ // ?man -f:file: specify f option
80 case 'f':
81 // ?man -f file: read patterns from file, one per line
82 arg = EARGF(usage());
83@@ -328,51 +328,51 @@ main(int argc, char *argv[])
84 efshut(fp, arg);
85 fflag = 1;
86 break;
87- // ?man -h: never print file names with matching lines
88+ // ?man -h: specify h option
89 case 'h':
90 // ?man -h: never print file names with matching lines
91 hflag = 1;
92 Hflag = 0;
93 break;
94- // ?man -c: print only a count of matching lines per file
95+ // ?man -c: specify c option
96 case 'c':
97 // ?man -c: print only a count of matching lines per file
98 /* FALLTHROUGH */
99- // ?man -l: print only the names of files with at least one match
100+ // ?man -l: specify l option
101 case 'l':
102 // ?man -l: print only the names of files with at least one matching line
103 /* FALLTHROUGH */
104- // ?man -n: prefix each matching line with its line number
105+ // ?man -n: specify n option
106 case 'n':
107 // ?man -n: prefix each matching line with its line number within its file
108 /* FALLTHROUGH */
109- // ?man -q: print nothing and return success on the first match
110+ // ?man -q: specify q option
111 case 'q':
112 // ?man -q: quiet mode; exit immediately with status 0 on first match and write nothing
113 mode = ARGC();
114 break;
115- // ?man -i: perform case-insensitive matching
116+ // ?man -i: specify i option
117 case 'i':
118 // ?man -i: perform case-insensitive matching
119 flags |= REG_ICASE;
120 iflag = 1;
121 break;
122- // ?man -s: suppress errors for nonexistent or unreadable files
123+ // ?man -s: specify s option
124 case 's':
125 // ?man -s: suppress error messages about nonexistent or unreadable files
126 sflag = 1;
127 break;
128- // ?man -v: select lines that do not match
129+ // ?man -v: specify v option
130 case 'v':
131 // ?man -v: invert the sense of matching to select non-matching lines
132 vflag = 1;
133 break;
134- // ?man -w: match only whole words
135+ // ?man -w: specify w option
136 case 'w':
137 // ?man -w: match only whole words
138 wflag = 1;
139 break;
140- // ?man -x: match only whole lines
141+ // ?man -x: specify x option
142 case 'x':
143 // ?man -x: match only whole lines
144 xflag = 1;
+2,
-2
1@@ -41,11 +41,11 @@ main(int argc, char *argv[])
2 int ret = 0, newline = 0, many = 0;
3
4 ARGBEGIN {
5- // ?man -n:num: display the first num lines of each file
6+ // ?man -n:num: print line numbers or counts
7 case 'n':
8 n = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
9 break;
10- /* -num is accepted as shorthand for -n num */
11+ // ?man ARGNUM: specify RGNUM option
12 ARGNUM:
13 n = ARGNUMF();
14 break;
+7,
-7
1@@ -135,26 +135,26 @@ usage(void)
2 eprintf("usage: %s [-n] [-g | -u | -G] [user | uid]\n", argv0);
3 }
4
5-// ?man id: print real and effective user and group ids
6-// ?man synopsis: [-n] [-g | -u | -G] [user | uid]
7-// ?man id prints user and group information of the calling process to standard output. If a login name or uid is specified, the user and group information of that user is displayed.
8+// ?man id: print user and group ids
9+// ?man arguments: user | uid
10+// ?man display real and effective user and group identities
11 int
12 main(int argc, char *argv[])
13 {
14 ARGBEGIN {
15- // ?man -g: Print only the effective group ID.
16+ // ?man -g: specify option flag
17 case 'g':
18 gflag = 1;
19 break;
20- // ?man -u: Print only the effective user ID.
21+ // ?man -u: unbuffered output
22 case 'u':
23 uflag = 1;
24 break;
25- // ?man -G: Display group information as whitespace separated numbers, in no particular order.
26+ // ?man -G: specify option flag
27 case 'G':
28 Gflag = 1;
29 break;
30- // ?man -n: Print names instead of ID numbers, for -g, -u, and -G.
31+ // ?man -n: print line numbers or counts
32 case 'n':
33 nflag = 1;
34 break;
+9,
-26
1@@ -451,17 +451,8 @@ join(FILE *fa, FILE *fb, size_t jfa, size_t jfb)
2 }
3
4
5-// ?man join: relational database operator
6-// ?man join lines from file1 and file2 on a matching field.
7-// ?man If one of the input files is '-', standard input is read for that file.
8-// ?man Files are read sequentially and are assumed to be sorted on the join
9-// ?man field.
10-// ?man join does not check the order of input, and joining two unsorted files will
11-// ?man produce unexpected output.
12-// ?man By default, input lines are matched on the first blank-separated
13-// ?man field; output lines are space-separated and consist of the join field
14-// ?man followed by the remaining fields from file1,
15-// ?man then the remaining fields from file2.
16+// ?man join: join lines on common field
17+// ?man join lines of two sorted files on a common field
18 int
19 main(int argc, char *argv[])
20 {
21@@ -471,15 +462,15 @@ main(int argc, char *argv[])
22 char *fno;
23
24 ARGBEGIN {
25- // ?man -1:field: Join on the fieldth field of file 1.
26+ // ?man -1:num: specify option flag
27 case '1':
28 jf[0] = estrtonum(EARGF(usage()), 1, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
29 break;
30- // ?man -2:field: Join on the fieldth field of file 2.
31+ // ?man -2:num: specify option flag
32 case '2':
33 jf[1] = estrtonum(EARGF(usage()), 1, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
34 break;
35- // ?man -a:fileno: Print unpairable lines from file fileno in addition to normal output.
36+ // ?man -a:str: print or show all entries
37 case 'a':
38 fno = EARGF(usage());
39 if (strcmp(fno, "1") == 0)
40@@ -489,29 +480,21 @@ main(int argc, char *argv[])
41 else
42 usage();
43 break;
44- // ?man -e:string: When used with -o, replace empty fields in the output list with string.
45+ // ?man -e:str: specify expression or pattern
46 case 'e':
47 replace = EARGF(usage());
48 break;
49- // ?man -o:list: Format output according to the string list.
50- // ?man Each element of list may be either fileno.field or 0 representing the join field.
51- // ?man Elements in list may be separated by blanks or commas.
52- // ?man For example,
53- // ?man join -o "0 2.1 1.3"
54- // ?man would print the join field, the first field of file2,
55- // ?man then the third field of file1.
56- // ?man Only paired lines are formatted with the -o option.
57- // ?man Unpairable lines selected with -a or -v are printed raw.
58+ // ?man -o:str: specify output file
59 case 'o':
60 oflag = 1;
61 initolist(&output);
62 makeolist(&output, EARGF(usage()));
63 break;
64- // ?man -t:delim: Use the arbitrary string delim as field delimiter for both input and output.
65+ // ?man -t:str: sort or specify timestamp
66 case 't':
67 sep = EARGF(usage());
68 break;
69- // ?man -v:fileno: Print unpairable lines from file fileno instead of normal output.
70+ // ?man -v:str: verbose mode; show progress
71 case 'v':
72 pairs = 0;
73 fno = EARGF(usage());
+3,
-3
1@@ -19,7 +19,7 @@ usage(void)
2 }
3
4 // ?man ln: make links between files
5-// ?man arguments: target [name]
6+// ?man arguments: target [name
7 // ?man create hard or symbolic links between files
8 int
9 main(int argc, char *argv[])
10@@ -34,11 +34,11 @@ main(int argc, char *argv[])
11 case 'f':
12 fflag = 1;
13 break;
14- // ?man -L: hard-link the target of a symbolic link rather than the link itself
15+ // ?man -L: specify option flag
16 case 'L':
17 flags |= AT_SYMLINK_FOLLOW;
18 break;
19- // ?man -P: hard-link a symbolic link itself rather than its target
20+ // ?man -P: specify option flag
21 case 'P':
22 flags &= ~AT_SYMLINK_FOLLOW;
23 break;
+4,
-4
1@@ -56,19 +56,19 @@ main(int argc, char *argv[])
2 char *buf = NULL, *tag = NULL;
3
4 ARGBEGIN {
5- // ?man -i: include the logger process ID with each message
6+ // ?man -i: interactive mode or prompt for confirmation
7 case 'i':
8 logflags |= LOG_PID;
9 break;
10- // ?man -p:priority: log with the given facility.level priority
11+ // ?man -p:str: preserve file attributes
12 case 'p':
13 priority = decodepri(EARGF(usage()));
14 break;
15- // ?man -s: also write each message to standard error
16+ // ?man -s: silent mode or print summary
17 case 's':
18 logflags |= LOG_PERROR;
19 break;
20- // ?man -t:tag: add tag to each logged message
21+ // ?man -t:str: sort or specify timestamp
22 case 't':
23 tag = EARGF(usage());
24 break;
+4,
-4
1@@ -406,11 +406,11 @@ entcmp(const void *va, const void *vb)
2 const struct entry *a = va, *b = vb;
3
4 switch (sort) {
5- // ?man -S: sort files by size in decreasing order
6+ // ?man -S: sort by file size
7 case 'S':
8 cmp = b->size - a->size;
9 break;
10- // ?man -t: sort files by modification time
11+ // ?man -t: sort by modification time
12 case 't':
13 if (!(cmp = b->t.tv_sec - a->t.tv_sec))
14 cmp = b->t.tv_nsec - a->t.tv_nsec;
15@@ -552,7 +552,7 @@ usage(void)
16 }
17
18 // ?man ls: list directory contents
19-// ?man arguments: [file ...]
20+// ?man arguments: [file ...
21 // ?man list information about files and directories
22 int
23 main(int argc, char *argv[])
24@@ -706,7 +706,7 @@ main(int argc, char *argv[])
25 uflag = 1;
26 cflag = 0;
27 break;
28- /* --color[=when] is accepted as a long-option extension */
29+ // ?man --: specify - option
30 case '-':
31 #if FEATURE_LS_COLOR
32 // ?man --color [when]: control coloring
+1,
-1
1@@ -17,7 +17,7 @@ usage(void)
2 }
3
4 // ?man mesg: control write access
5-// ?man synopsis: [n | y]
6+// ?man arguments: n|y
7 // ?man allow or disallow other users to write to the terminal
8 int
9 main(int argc, char *argv[])
+1,
-1
1@@ -23,7 +23,7 @@ main(int argc, char *argv[])
2 int ret = 0;
3
4 ARGBEGIN {
5- // ?man -m:mode: set the file mode of newly created named pipes
6+ // ?man -m:mode: specify mode or limit
7 case 'm':
8 mode = parsemode(EARGF(usage()), mode, umask(0));
9 break;
+2,
-2
1@@ -24,7 +24,7 @@ usage(void)
2 }
3
4 // ?man nice: run command with modified priority
5-// ?man arguments: cmd [arg ...]
6+// ?man arguments: cmd [arg ...
7 // ?man run a command with modified scheduling priority
8 int
9 main(int argc, char *argv[])
10@@ -32,7 +32,7 @@ main(int argc, char *argv[])
11 int val = 10, r, savederrno;
12
13 ARGBEGIN {
14- // ?man -n:num: change niceness by num
15+ // ?man -n:num: print line numbers or counts
16 case 'n':
17 val = estrtonum(EARGF(usage()), PRIO_MIN, PRIO_MAX);
18 break;
+14,
-51
1@@ -73,7 +73,7 @@ nl(const char *fname, FILE *fp)
2 if (line.data[0] != '\n')
3 donumber = 1;
4 break;
5- /* pexpr line-matching mode */
6+ // ?man -p: preserve file attributes
7 case 'p':
8 if (!regexec(preg + section, line.data, 0, NULL, 0))
9 donumber = 1;
10@@ -118,20 +118,8 @@ getlinetype(char *type, regex_t *preg)
11 return type[0];
12 }
13
14-// ?man nl: line numbering filter
15-// ?man nl reads lines from file and writes them to stdout, numbering non-empty lines.
16-// ?man If no file is given nl reads from stdin.
17-// ?man nl treats the input text as a collection of logical pages divided into
18-// ?man logical page sections.
19-// ?man Each logical page consists of a header section, a body
20-// ?man section and a footer section.
21-// ?man Sections may be empty.
22-// ?man The start of each section is indicated by a single delimiting line, one of:
23-// ?man ::: header
24-// ?man :: body
25-// ?man : footer
26-// ?man If the input text contains no delimiting line then all of the input text
27-// ?man belongs to a single logical page body section.
28+// ?man nl: number lines
29+// ?man number the lines of files
30 int
31 main(int argc, char *argv[])
32 {
33@@ -141,9 +129,7 @@ main(int argc, char *argv[])
34 char *d, *formattype, *formatblit;
35
36 ARGBEGIN {
37- // ?man -d:delim: Set delim as the delimiter for logical pages.
38- // ?man If delim is only one character, nl appends \":\" to it.
39- // ?man The default is \"\\:\".
40+ // ?man -d:str: specify directory
41 case 'd':
42 switch (utflen((d = EARGF(usage())))) {
43 case 0:
44@@ -162,47 +148,27 @@ main(int argc, char *argv[])
45 break;
46 }
47 break;
48- // ?man -f:type: Define which lines to number in the head | body | footer section:
49- // ?man a All lines.
50- // ?man n No lines.
51- // ?man t Only non-empty lines.
52- // ?man This is the default.
53- // ?man pexpr Only lines matching expr according to regex 7 or re_format 7 .
54+ // ?man -f:str: force the operation
55 case 'f':
56 type[0] = getlinetype(EARGF(usage()), preg);
57 break;
58- // ?man -b:type: Define which lines to number in the head | body | footer section:
59- // ?man a All lines.
60- // ?man n No lines.
61- // ?man t Only non-empty lines.
62- // ?man This is the default.
63- // ?man pexpr Only lines matching expr according to regex 7 or re_format 7 .
64+ // ?man -b:str: specify block size or base directory
65 case 'b':
66 type[1] = getlinetype(EARGF(usage()), preg + 1);
67 break;
68- // ?man -h:type: Define which lines to number in the head | body | footer section:
69- // ?man a All lines.
70- // ?man n No lines.
71- // ?man t Only non-empty lines.
72- // ?man This is the default.
73- // ?man pexpr Only lines matching expr according to regex 7 or re_format 7 .
74+ // ?man -h:str: suppress headers or print help
75 case 'h':
76 type[2] = getlinetype(EARGF(usage()), preg + 2);
77 break;
78- // ?man -i:num: Set the increment between numbered lines to num .
79+ // ?man -i:num: interactive mode or prompt for confirmation
80 case 'i':
81 incr = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
82 break;
83- // ?man -l:num: Set the number of adjacent blank lines to be considered as one to num .
84- // ?man The default is 1.
85+ // ?man -l:num: list in long format
86 case 'l':
87 blines = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
88 break;
89- // ?man -n:format: Set the line number output format to one of:
90- // ?man ln Left justified.
91- // ?man rn Right justified.
92- // ?man This is the default.
93- // ?man rz Right justified with leading zeroes.
94+ // ?man -n:str: print line numbers or counts
95 case 'n':
96 formattype = EARGF(usage());
97 estrlcpy(format, "%", sizeof(format));
98@@ -220,23 +186,20 @@ main(int argc, char *argv[])
99 estrlcat(format, formatblit, sizeof(format));
100 estrlcat(format, "*ld", sizeof(format));
101 break;
102- // ?man -p: Do not reset line number for logical pages.
103+ // ?man -p: preserve file attributes
104 case 'p':
105 pflag = 1;
106 break;
107- // ?man -s:sep: Use sep to separate line numbers and lines.
108- // ?man The default is \"\\t\".
109+ // ?man -s:str: silent mode or print summary
110 case 's':
111 sep = EARGF(usage());
112 seplen = unescape(sep);
113 break;
114- // ?man -v:num: Start counting lines from num .
115- // ?man The default is 1.
116+ // ?man -v:num: verbose mode; show progress
117 case 'v':
118 startnum = estrtonum(EARGF(usage()), 0, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
119 break;
120- // ?man -w:num: Set the width of the line number to num .
121- // ?man The default is 6.
122+ // ?man -w:num: wait for completion
123 case 'w':
124 width = estrtonum(EARGF(usage()), 1, INT_MAX);
125 break;
+1,
-1
1@@ -17,7 +17,7 @@ usage(void)
2 }
3
4 // ?man nohup: run command immune to hangups
5-// ?man arguments: cmd [arg ...]
6+// ?man arguments: cmd [arg ...
7 // ?man run a command that persists after logging out
8 int
9 main(int argc, char *argv[])
+26,
-35
1@@ -61,7 +61,7 @@ printchunk(const unsigned char *s, unsigned char format, size_t len)
2 };
3
4 switch (format) {
5- // equivalent to -t a
6+ // ?man -a: print or show all entries
7 case 'a':
8 c = *s & ~128; /* clear high bit as required by standard */
9 if (c < LEN(namedict) || c == 127) {
10@@ -70,7 +70,7 @@ printchunk(const unsigned char *s, unsigned char format, size_t len)
11 printf(" %3c", c);
12 }
13 break;
14- // equivalent to -t c
15+ // ?man -c: print count or perform stdout action
16 case 'c':
17 if (strchr("\a\b\t\n\v\f\r\0", *s)) {
18 printf(" %3s", escdict[*s]);
19@@ -214,9 +214,8 @@ usage(void)
20 "[-j skip] [-t outputformat] [file ...]\n", argv0);
21 }
22
23-// ?man od: octal dump
24-// ?man od writes an octal dump of each file to stdout.
25-// ?man If no file is given od reads from stdin.
26+// ?man od: dump files in formats
27+// ?man display file contents in octal, hex, or other formats
28 int
29 main(int argc, char *argv[])
30 {
31@@ -227,72 +226,65 @@ main(int argc, char *argv[])
32 big_endian = (*(uint16_t *)"\0\xff" == 0xff);
33
34 ARGBEGIN {
35- // ?man -A:addressformat: addressformat is one of d|o|x|n and sets the address to be
36- // ?man either in decimal, octal, hexadecimal or not printed at all.
37- // ?man The default is octal.
38+ // ?man -A:str: specify option flag
39 case 'A':
40 s = EARGF(usage());
41 if (strlen(s) != 1 || !strchr("doxn", s[0]))
42 usage();
43 addr_format = s[0];
44 break;
45- // ?man -b: Equivalent to -t o1 .
46+ // ?man -b: specify block size or base directory
47 case 'b':
48 addtype('o', 1);
49 break;
50- // ?man -d: Equivalent to -t u2 .
51+ // ?man -d: specify directory
52 case 'd':
53 addtype('u', 2);
54 break;
55 #if FEATURE_OD_ENDIAN
56- // ?man -E: Force Little Endian ( e ) or Big Endian ( E ) system-independently.
57+ // ?man -E: specify option flag
58 case 'E':
59- // ?man -e: Force Little Endian ( e ) or Big Endian ( E ) system-independently.
60+ // ?man -e: specify expression or pattern
61 case 'e':
62 big_endian = (ARGC() == 'E');
63 break;
64 #endif
65- // ?man -j:skip: Ignore the first skip bytes of input.
66+ // ?man -j:str: specify option flag
67 case 'j':
68 if ((skip = parseoffset(EARGF(usage()))) < 0)
69 usage();
70 break;
71- // ?man -N:num: read at most num bytes of input
72+ // ?man -N:str: specify option flag
73 case 'N':
74 if ((max = parseoffset(EARGF(usage()))) < 0)
75 usage();
76 break;
77- // ?man -o: Equivalent to -t o2 .
78+ // ?man -o: specify output file
79 case 'o':
80 addtype('o', 2);
81 break;
82- // ?man -s: Equivalent to -t d2 .
83+ // ?man -s: silent mode or print summary
84 case 's':
85 addtype('d', 2);
86 break;
87- // ?man -t:outputformat: outputformat is a list of a|c|d|o|u|x followed by a digit or C|S|I|L and sets
88- // ?man the content to be in named character, character, signed
89- // ?man decimal, octal, unsigned decimal, or
90- // ?man hexadecimal format, processing the given amount of bytes or the length
91- // ?man of Char, Short, Integer or Long.
92- // ?man The default is octal with 4 bytes.
93+ // ?man -t:str: sort or specify timestamp
94 case 't':
95 s = EARGF(usage());
96 for (; *s; s++) {
97 switch (*s) {
98- /* outputformat a is equivalent to -t a */
99+ // ?man -a: print or show all entries
100 case 'a':
101- /* outputformat c is equivalent to -t c */
102+ // ?man -c: print count or perform stdout action
103 case 'c':
104 addtype(*s, 1);
105 break;
106- /* outputformat d is equivalent to -t d */
107+ // ?man -d: specify directory
108 case 'd':
109- /* outputformat o is equivalent to -t o */
110+ // ?man -o: specify output file
111 case 'o':
112- /* outputformat u is equivalent to -t u */
113+ // ?man -u: unbuffered output
114 case 'u':
115- /* outputformat x is equivalent to -t x */
116+ // ?man -x: hex format or match whole lines
117 case 'x':
118 fmt_char = *s;
119 if (isdigit((unsigned char)*(s + 1))) {
120@@ -300,22 +292,22 @@ main(int argc, char *argv[])
121 s = end - 1;
122 } else {
123 switch (*(s + 1)) {
124- /* outputformat C uses sizeof(char) bytes */
125+ // ?man -C: specify option flag
126 case 'C':
127 len = sizeof(char);
128 s++;
129 break;
130- /* outputformat S uses sizeof(short) bytes */
131+ // ?man -S: specify option flag
132 case 'S':
133 len = sizeof(short);
134 s++;
135 break;
136- /* outputformat I uses sizeof(int) bytes */
137+ // ?man -I: specify option flag
138 case 'I':
139 len = sizeof(int);
140 s++;
141 break;
142- /* outputformat L uses sizeof(long) bytes */
143+ // ?man -L: specify option flag
144 case 'L':
145 len = sizeof(long);
146 s++;
147@@ -331,12 +323,11 @@ main(int argc, char *argv[])
148 }
149 }
150 break;
151- // ?man -v: Always set.
152- // ?man Write all input data, including duplicate lines.
153+ // ?man -v: verbose mode; show progress
154 case 'v':
155 /* always set, use uniq(1) to handle duplicate lines */
156 break;
157- // ?man -x: Equivalent to -t x2 .
158+ // ?man -x: hex format or match whole lines
159 case 'x':
160 addtype('x', 2);
161 break;
+2,
-2
1@@ -99,11 +99,11 @@ main(int argc, char *argv[])
2 char *delim = "\t";
3
4 ARGBEGIN {
5- // ?man -s: read each file sequentially instead of in parallel
6+ // ?man -s: silent mode or print summary
7 case 's':
8 seq = 1;
9 break;
10- // ?man -d:list: replace newlines using escaped characters from list
11+ // ?man -d:str: specify directory
12 case 'd':
13 delim = EARGF(usage());
14 delim_bytelen = unescape(delim);
+2,
-2
1@@ -89,11 +89,11 @@ main(int argc, char *argv[])
2 int ret = 0;
3
4 ARGBEGIN {
5- // ?man -p: check pathnames for portability across POSIX systems
6+ // ?man -p: preserve file attributes
7 case 'p':
8 most = 1;
9 break;
10- // ?man -P: also reject empty pathnames and leading hyphens
11+ // ?man -P: specify option flag
12 case 'P':
13 extra = 1;
14 break;
+33,
-28
1@@ -846,9 +846,11 @@ readpax(struct bufio *f, struct header *h)
2 case 'g':
3 readexthdr(f, &globexthdr, h->size);
4 break;
5+ // ?man -x: hex format or match whole lines
6 case 'x':
7 readexthdr(f, &exthdr, h->size);
8 break;
9+ // ?man -L: specify option flag
10 case 'L':
11 if ((exthdr.delete | opt.delete) & PATH)
12 break;
13@@ -2082,7 +2084,9 @@ parsereplstr(char *str)
14 for (;;) {
15 switch (*++str) {
16 case 'g': r->global = 1; break;
17+ // ?man -p: preserve file attributes
18 case 'p': r->print = 1; break;
19+ // ?man -s: silent mode or print summary
20 case 's': r->symlink = 0; break;
21 case 'S': r->symlink = 1; break;
22 case 0: goto done;
23@@ -2329,10 +2333,6 @@ handle_append(const char *filename, const char *algo, const char *format)
24 }
25
26 // ?man pax: portable archive interchange
27-// ?man synopsis: [-cdiknuvX] [-f archive] [-o options] [-p string] [-s replstr] [pattern ...]
28-// ?man synopsis: -r [-cdiknuvX] [-f archive] [-o options] [-p string] [-s replstr] [pattern ...]
29-// ?man synopsis: -w [-adituvX] [-b blocksize] [-f archive] [-o options] [-x format] [-j | -J | -z] [file ...]
30-// ?man synopsis: -rw [-diklntuvX] [-H | -L] [-p string] [-s replstr] [file ...] directory
31 // ?man read, write, and list member files of archive files
32 int
33 main(int argc, char *argv[])
34@@ -2349,108 +2349,113 @@ main(int argc, char *argv[])
35 size_t l;
36
37 ARGBEGIN {
38- // ?man -a: append files to the end of an existing archive
39+ // ?man -a: print or show all entries
40 case 'a':
41 aflag = 1;
42 break;
43- // ?man -b:blocksize: accepted for compatibility; block size is currently ignored
44+ // ?man -b:str: specify block size or base directory
45 case 'b':
46 EARGF(usage());
47 break;
48- // ?man -c: invert the sense of path matching
49+ // ?man -c: print count or perform stdout action
50 case 'c':
51 cflag = 1;
52 break;
53- // ?man -d: do not match pathnames of directory entries against patterns
54+ // ?man -d: specify directory
55 case 'd':
56 dflag = 1;
57 break;
58- // ?man -f:archive: read from or write to archive instead of standard input or output
59+ // ?man -f:str: force the operation
60 case 'f':
61 name = EARGF(usage());
62 break;
63- // ?man -H: follow symbolic links named on the command line
64+ // ?man -H: specify option flag
65 case 'H':
66 follow = 'H';
67 break;
68- // ?man -i: rename or skip files interactively
69+ // ?man -i: interactive mode or prompt for confirmation
70 case 'i':
71 iflag = 1;
72 break;
73- // ?man -j: compress or decompress the archive with bzip2
74+ // ?man -j: specify option flag
75 case 'j':
76 algo = "bzip2";
77 break;
78- // ?man -J: compress or decompress the archive with xz
79+ // ?man -J: specify option flag
80 case 'J':
81 algo = "xz";
82 break;
83- // ?man -k: do not overwrite existing files
84+ // ?man -k: specify option flag
85 case 'k':
86 kflag = 1;
87 break;
88- // ?man -l: link files instead of copying them during pass mode when possible
89+ // ?man -l: list in long format
90 case 'l':
91 lflag = 1;
92 break;
93- // ?man -L: follow all symbolic links
94+ // ?man -L: specify option flag
95 case 'L':
96 follow = 'L';
97 break;
98- // ?man -n: use only the first archive member that matches each pattern
99+ // ?man -n: print line numbers or counts
100 case 'n':
101 nflag = 1;
102 break;
103- // ?man -o:options: set format-specific archive options
104+ // ?man -o:str: specify output file
105 case 'o':
106 parseopts(EARGF(usage()));
107 break;
108- // ?man -p:string: control which file attributes are preserved in pass mode
109+ // ?man -p:str: preserve file attributes
110 case 'p':
111 for (arg = EARGF(usage()); *arg; ++arg) {
112 switch (*arg) {
113+ // ?man -a: print or show all entries
114 case 'a': preserve &= ~ATIME; break;
115+ // ?man -e: specify expression or pattern
116 case 'e': preserve = ~0; break;
117+ // ?man -m: specify mode or limit
118 case 'm': preserve &= ~MTIME; break;
119+ // ?man -o: specify output file
120 case 'o': preserve |= UID | GID; break;
121+ // ?man -p: preserve file attributes
122 case 'p': preserve |= MODE; break;
123 default: fatal("unknown -p option");
124 }
125 }
126 break;
127- // ?man -r: read an archive and extract matching members
128+ // ?man -r: operate recursively
129 case 'r':
130 mode |= READ;
131 break;
132- // ?man -s:replstr: rename archive members or files using a substitution expression
133+ // ?man -s:str: silent mode or print summary
134 case 's':
135 parsereplstr(EARGF(usage()));
136 break;
137- // ?man -t: preserve access times of files read by pax
138+ // ?man -t: sort or specify timestamp
139 case 't':
140 tflag = 1;
141 break;
142- // ?man -u: copy or extract only files newer than existing destination files
143+ // ?man -u: unbuffered output
144 case 'u':
145 uflag = 1;
146 break;
147- // ?man -v: write verbose filenames while processing files
148+ // ?man -v: verbose mode; show progress
149 case 'v':
150 vflag = 1;
151 break;
152- // ?man -w: write an archive or enter pass mode
153+ // ?man -w: wait for completion
154 case 'w':
155 mode |= WRITE;
156 break;
157- // ?man -x:format: use the archive format format
158+ // ?man -x:str: hex format or match whole lines
159 case 'x':
160 format = EARGF(usage());
161 break;
162- // ?man -X: stay on the current file system when descending directories
163+ // ?man -X: specify option flag
164 case 'X':
165 Xflag = 1;
166 break;
167- // ?man -z: compress or decompress the archive with gzip
168+ // ?man -z: specify option flag
169 case 'z':
170 algo = "gzip";
171 break;
+1,
-1
1@@ -75,7 +75,7 @@ usage(void)
2 }
3
4 // ?man printf: format and print data
5-// ?man arguments: format [arg ...]
6+// ?man arguments: format [arg ...
7 // ?man format and print arguments to standard output
8 int
9 main(int argc, char *argv[])
+7,
-7
1@@ -150,29 +150,29 @@ usage(void)
2 eprintf("usage: %s [-aAdef]\n", argv0);
3 }
4
5-// ?man ps: display process status
6-// ?man ps displays information about active processes. When given no options, ps prints information about processes of the current user that has a controlling terminal.
7+// ?man ps: report process status
8+// ?man display information about active system processes
9 int
10 main(int argc, char *argv[])
11 {
12 ARGBEGIN {
13- // ?man -a: Select all processes except both session leaders and processes not associated with a terminal.
14+ // ?man -a: print or show all entries
15 case 'a':
16 flags |= PS_aflag;
17 break;
18- // ?man -A: Select all processes. Identical to -e.
19+ // ?man -A: specify option flag
20 case 'A':
21 flags |= PS_Aflag;
22 break;
23- // ?man -d: Select all processes except session leaders.
24+ // ?man -d: specify directory
25 case 'd':
26 flags |= PS_dflag;
27 break;
28- // ?man -e: Select all processes. Identical to -A.
29+ // ?man -e: specify expression or pattern
30 case 'e':
31 flags |= PS_Aflag;
32 break;
33- // ?man -f: Do full-format listing.
34+ // ?man -f: force the operation
35 case 'f':
36 flags |= PS_fflag;
37 break;
+2,
-2
1@@ -38,9 +38,9 @@ main(int argc, char *argv[])
2 char mode = 'L';
3
4 ARGBEGIN {
5- // ?man -L: print the logical path using PWD when possible
6+ // ?man -L: specify option flag
7 case 'L':
8- // ?man -P: print the physical path with all symbolic links resolved
9+ // ?man -P: specify option flag
10 case 'P':
11 mode = ARGC();
12 break;
+2,
-2
1@@ -35,12 +35,12 @@ main(int argc, char *argv[])
2 ARGBEGIN
3 {
4 #if FEATURE_READLINK_REALPATH
5- // ?man -f: canonicalize path by following every symbolic link in its components
6+ // ?man -f: force the operation
7 case 'f':
8 fflag = 1;
9 break;
10 #endif
11- // ?man -n: do not print the trailing newline
12+ // ?man -n: print line numbers or counts
13 case 'n':
14 nflag = 1;
15 break;
+4,
-4
1@@ -55,19 +55,19 @@ main(int argc, char *argv[])
2 int who;
3
4 ARGBEGIN {
5- // ?man -n:num: change niceness by num
6+ // ?man -n:str: print line numbers or counts
7 case 'n':
8 adj = EARGF(usage());
9 break;
10- // ?man -g: treat each id as a process group ID
11+ // ?man -g: specify option flag
12 case 'g':
13 which = PRIO_PGRP;
14 break;
15- // ?man -p: treat each id as a process ID
16+ // ?man -p: preserve file attributes
17 case 'p':
18 which = PRIO_PROCESS;
19 break;
20- // ?man -u: treat each id as a user name or user ID
21+ // ?man -u: unbuffered output
22 case 'u':
23 which = PRIO_USER;
24 break;
+8,
-81
1@@ -1750,10 +1750,8 @@ old_next(void)
2 }
3
4 // ?man sed: stream editor
5-// ?man synopsis: [-nrE] script [file ...]
6-// ?man synopsis: [-nrE] -e script [-e script] ... [-f scriptfile] ... [file ...]
7-// ?man synopsis: [-nrE] [-e script] ... -f scriptfile [-f scriptfile] ... [file ...]
8-// ?man sed reads line oriented output from file or stdin, applies the editing commands supplied by script or scriptfile and writes the edited stream to stdout.
9+// ?man arguments: script [file ...
10+// ?man stream editor for filtering and transforming text
11 int
12 main(int argc, char *argv[])
13 {
14@@ -1761,30 +1759,30 @@ main(int argc, char *argv[])
15 int script = 0;
16
17 ARGBEGIN {
18- // ?man -n: Suppress default printing at the end of each cycle.
19+ // ?man -n: print line numbers or counts
20 case 'n':
21 gflags.n = 1;
22 break;
23- // ?man -r: Use extended regular expressions
24+ // ?man -r: operate recursively
25 case 'r':
26- // ?man -E: Use extended regular expressions
27+ // ?man -E: specify option flag
28 case 'E':
29 gflags.E = 1;
30 break;
31- // ?man -e:script: Append script to the list of editing commands.
32+ // ?man -e:str: specify expression or pattern
33 case 'e':
34 arg = EARGF(usage());
35 compile(arg, 0);
36 script = 1;
37 break;
38- // ?man -f:scriptfile: Append the commands from scriptfile to the list of editing commands.
39+ // ?man -f:str: force the operation
40 case 'f':
41 arg = EARGF(usage());
42 compile(arg, 1);
43 script = 1;
44 break;
45 #if FEATURE_SED_INPLACE
46- // ?man -i: edit files in place
47+ // ?man -i: interactive mode or prompt for confirmation
48 case 'i':
49 iflag = 1;
50 if (argv[0][1] != '\0') {
51@@ -1798,77 +1796,6 @@ main(int argc, char *argv[])
52 default : usage();
53 } ARGEND
54
55- // ?man ## Extended description
56- // ?man Editing commands take the form
57- // ?man
58- // ?man `[address[,address]]function`
59- // ?man
60- // ?man ### Addresses
61- // ?man Addresses are either blank, a positive decimal integer denoting a line
62- // ?man number, the character '$' denoting the last line of input, or a regular
63- // ?man expression.
64- // ?man A command with no addresses matches every line, one address matches
65- // ?man individual lines, and two addresses matches a range of lines from the
66- // ?man first to the second address inclusive.
67- // ?man ### Functions
68- // ?man `a [text]`
69- // ?man : Append text to output after end of current cycle.
70- // ?man `b [label]`
71- // ?man : Branch to label. If no label is provided branch to end of script.
72- // ?man `c [text]`
73- // ?man : Change. Delete addressed range and output text after end of current cycle.
74- // ?man `d`
75- // ?man : Delete pattern space and begin next cycle.
76- // ?man `D`
77- // ?man : Delete pattern space up to and including first newline and begin new cycle without reading input. If there is no newline, behave like d.
78- // ?man `g`
79- // ?man : Get. Replace the pattern space with the hold space.
80- // ?man `G`
81- // ?man : Get. Append a newline and the hold space to the pattern space.
82- // ?man `h`
83- // ?man : Hold. Replace the hold space with the pattern space.
84- // ?man `H`
85- // ?man : Hold. Append a newline and the pattern space to the hold space.
86- // ?man `i [text]`
87- // ?man : Insert text in output.
88- // ?man `l`
89- // ?man : List? Write the pattern space replacing known non printing characters with backslash escaped versions (`\\\\`, `\\a`, `\\b`, `\\f`, `\\r`, `\\t`, `\\v`). Print bad UTF-8 sequences as `\\ooo` where ooo is a three digit octal number. Mark end of lines with '$'.
90- // ?man `n`
91- // ?man : Next. Write pattern space (unless `-n`), read next line into pattern space, and continue current cycle. If there is no next line, quit.
92- // ?man `N`
93- // ?man : Next. Read next line, append newline and next line to pattern space, and continue cycle. If there is no next line, quit without printing current pattern space.
94- // ?man `p`
95- // ?man : Print current pattern space.
96- // ?man `P`
97- // ?man : Print current pattern space up to first newline.
98- // ?man `q`
99- // ?man : Quit.
100- // ?man `r file`
101- // ?man : Read file and write contents to output.
102- // ?man `s/re/text/flags`
103- // ?man : Find occurences of regular expression re in the pattern space and replace with text. A '&' in text is replaced with the entire match. A `\\d` where d is a decimal digit 1-9 is replaced with the corresponding match group from the regular expression. `\\n` represents a newline in both the regular expression and replacement text. A literal newline in the replacement text must be preceded by a `\\`.
104- // ?man ### Flags
105- // ?man `n`
106- // ?man : A positive decimal number denoting which match in the pattern space to replace.
107- // ?man `g`
108- // ?man : Global. Replace all matches in the pattern space.
109- // ?man `p`
110- // ?man : Print the pattern if a replacement was made.
111- // ?man `w file`
112- // ?man : Write the pattern space to file if a replacement was made.
113- // ?man `t [label]`
114- // ?man : Test. Branch to corresponding label if a substitution has been made since the last line was read or last t command was executed. If no label is provided branch to end of script.
115- // ?man `w file`
116- // ?man : Write pattern space to file.
117- // ?man `x`
118- // ?man : Exchange hold space and pattern space.
119- // ?man `y/set1/set2/`
120- // ?man : Replace each occurrence of a character from set 1 with the corresponding character from set 2.
121- // ?man `:label`
122- // ?man : Create a label for b and t commands.
123- // ?man `=`
124- // ?man : Write current input line number to output.
125-
126 /* no script to run */
127 if (!script && !argc)
128 usage();
+23,
-33
1@@ -305,27 +305,27 @@ parse_flags(char **s, int *flags, int bflag)
2 {
3 while (isalpha((int)**s)) {
4 switch (*((*s)++)) {
5- /* parse key-specific b modifier */
6+ // ?man -b: specify block size or base directory
7 case 'b':
8 *flags |= bflag;
9 break;
10- /* parse key-specific d modifier */
11+ // ?man -d: specify directory
12 case 'd':
13 *flags |= MOD_D;
14 break;
15- /* parse key-specific f modifier */
16+ // ?man -f: force the operation
17 case 'f':
18 *flags |= MOD_F;
19 break;
20- /* parse key-specific i modifier */
21+ // ?man -i: interactive mode or prompt for confirmation
22 case 'i':
23 *flags |= MOD_I;
24 break;
25- /* parse key-specific n modifier */
26+ // ?man -n: print line numbers or counts
27 case 'n':
28 *flags |= MOD_N;
29 break;
30- /* parse key-specific r modifier */
31+ // ?man -r: operate recursively
32 case 'r':
33 *flags |= MOD_R;
34 break;
35@@ -396,9 +396,8 @@ usage(void)
36 }
37
38 // ?man sort: sort lines
39-// ?man synopsis: [-Cbcdfimnru] [-o outfile] [-t delim] [-k key ...] [file ...]
40-// ?man sort writes the sorted concatenation of each file to stdout.
41-// ?man If no file is given sort reads from stdin.
42+// ?man arguments: -Cbcdfimnru
43+// ?man sort or merge lines of text files
44 int
45 main(int argc, char *argv[])
46 {
47@@ -409,44 +408,35 @@ main(int argc, char *argv[])
48 char *outfile = NULL;
49
50 ARGBEGIN {
51- // ?man -C: Check that the concatenation of the given files is sorted rather than sorting them.
52- // ?man In this mode, no output is printed to stdout, and the exit status indicates the result of the check.
53+ // ?man -C: specify option flag
54 case 'C':
55 Cflag = 1;
56 break;
57- // ?man -b: Skip leading whitespace of columns when sorting.
58+ // ?man -b: specify block size or base directory
59 case 'b':
60 global_flags |= MOD_STARTB | MOD_ENDB;
61 break;
62- // ?man -c: The same as -C except that when disorder is detected, a message is written to stderr indicating the location of the disorder.
63+ // ?man -c: print count or perform stdout action
64 case 'c':
65 cflag = 1;
66 break;
67- // ?man -d: Skip non-whitespace and non-alphanumeric characters.
68+ // ?man -d: specify directory
69 case 'd':
70 global_flags |= MOD_D;
71 break;
72- // ?man -f: Ignore letter case when sorting.
73+ // ?man -f: force the operation
74 case 'f':
75 global_flags |= MOD_F;
76 break;
77- // ?man -i: Skip non-printable characters.
78+ // ?man -i: interactive mode or prompt for confirmation
79 case 'i':
80 global_flags |= MOD_I;
81 break;
82- // ?man -k:key: Specify a key definition of the form S[.s][f][,E[.e][f]] where S,
83- // ?man s, E and e are the starting column, starting character in that column,
84- // ?man ending column and the ending character of that column respectively.
85- // ?man If they are not specified, s refers to the first character of the
86- // ?man specified starting column, E refers to the last column of every line,
87- // ?man and e refers to the last character of the ending column.
88- // ?man f can be used to specify options (n, b) that only apply to this key
89- // ?man definition.
90- // ?man b is special in that it only applies to the column that it was specified after.
91+ // ?man -k:str: specify option flag
92 case 'k':
93 addkeydef(EARGF(usage()), global_flags);
94 break;
95- // ?man -m: Assume sorted input, merge only.
96+ // ?man -m: specify mode or limit
97 case 'm':
98 /* more or less for free, but for performance-reasons,
99 * we should keep this flag in mind and maybe some later
100@@ -454,37 +444,37 @@ main(int argc, char *argv[])
101 * while merging large sorted files.
102 */
103 break;
104- // ?man -n: Perform a numeric sort.
105+ // ?man -n: print line numbers or counts
106 case 'n':
107 global_flags |= MOD_N;
108 break;
109- // ?man -o:outfile: Write output to outfile rather than stdout.
110+ // ?man -o:file: specify output file
111 case 'o':
112 outfile = EARGF(usage());
113 break;
114- // ?man -r: Reverses the sort.
115+ // ?man -r: operate recursively
116 case 'r':
117 global_flags |= MOD_R;
118 break;
119 #if FEATURE_SORT_STABLE
120- // ?man -s: stabilize the sort by preserving the input order of equal lines
121+ // ?man -s: silent mode or print summary
122 case 's':
123 sflag = 1;
124 break;
125 #endif
126- // ?man -t:delim: Set delim as the field delimiter.
127+ // ?man -t:str: sort or specify timestamp
128 case 't':
129 fieldsep = EARGF(usage());
130 if (!*fieldsep)
131 eprintf("empty delimiter\n");
132 fieldseplen = unescape(fieldsep);
133 break;
134- // ?man -u: Print equal lines only once.
135+ // ?man -u: unbuffered output
136 case 'u':
137 uflag = 1;
138 break;
139 #if FEATURE_SORT_BIG
140- // ?man -z: treat input as NUL-separated records
141+ // ?man -z: specify option flag
142 case 'z':
143 zflag = 1;
144 break;
+5,
-5
1@@ -47,7 +47,7 @@ usage(void)
2 }
3
4 // ?man split: split file into pieces
5-// ?man arguments: [file] [prefix]
6+// ?man arguments: | -l num
7 // ?man split a file into fixed-size pieces
8 int
9 main(int argc, char *argv[])
10@@ -58,11 +58,11 @@ main(int argc, char *argv[])
11 char name[NAME_MAX + 1], *prefix = "x", *file = NULL;
12
13 ARGBEGIN {
14- // ?man -a:num: use num characters for generated filename suffixes
15+ // ?man -a:num: print or show all entries
16 case 'a':
17 slen = estrtonum(EARGF(usage()), 0, INT_MAX);
18 break;
19- // ?man -b:num: start a new file every num bytes
20+ // ?man -b:str: specify block size or base directory
21 case 'b':
22 always = 1;
23 if ((size = parseoffset(EARGF(usage()))) < 0)
24@@ -70,12 +70,12 @@ main(int argc, char *argv[])
25 if (!size)
26 eprintf("size needs to be positive\n");
27 break;
28- // ?man -d: use decimal suffixes instead of alphabetic ones
29+ // ?man -d: specify directory
30 case 'd':
31 base = 10;
32 start = '0';
33 break;
34- // ?man -l:num: start a new file every num lines
35+ // ?man -l:num: list in long format
36 case 'l':
37 always = 0;
38 size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SSIZE_MAX));
+5,
-5
1@@ -168,15 +168,15 @@ main(int argc, char *argv[])
2 int (*tail)(int, const char *, size_t) = taketail;
3
4 ARGBEGIN {
5- // ?man -f: continue writing appended data as the file grows
6+ // ?man -f: force the operation
7 case 'f':
8 fflag = 1;
9 break;
10- // ?man -c:num: display the last num bytes of each file
11+ // ?man -c: print count or perform stdout action
12 case 'c':
13- // ?man -m:num: display the last num characters of each file
14+ // ?man -m: specify mode or limit
15 case 'm':
16- // ?man -n:num: display the last num lines of each file
17+ // ?man -n:num: print line numbers or counts
18 case 'n':
19 mode = ARGC();
20 numstr = EARGF(usage());
21@@ -185,7 +185,7 @@ main(int argc, char *argv[])
22 if (strchr(numstr, '+'))
23 tail = dropinit;
24 break;
25- // ?man -num: display the last num lines of each file
26+ // ?man ARGNUM: specify RGNUM option
27 ARGNUM:
28 n = ARGNUMF();
29 break;
+2,
-2
1@@ -26,11 +26,11 @@ main(int argc, char *argv[])
2 char buf[BUFSIZ];
3
4 ARGBEGIN {
5- // ?man -a: append to each file instead of overwriting it
6+ // ?man -a: print or show all entries
7 case 'a':
8 aflag = O_APPEND;
9 break;
10- // ?man -i: ignore SIGINT
11+ // ?man -i: interactive mode or prompt for confirmation
12 case 'i':
13 iflag = 1;
14 break;
+2,
-2
1@@ -17,7 +17,7 @@ usage(void)
2 }
3
4 // ?man time: time command execution
5-// ?man arguments: cmd [arg ...]
6+// ?man arguments: cmd [arg ...
7 // ?man run a command and report its execution duration
8 int
9 main(int argc, char *argv[])
10@@ -29,7 +29,7 @@ main(int argc, char *argv[])
11 int status, savederrno, ret = 0;
12
13 ARGBEGIN {
14- // ?man -p: use the portable output format "real %f\\nuser %f\\nsys %f\\n"
15+ // ?man -p: preserve file attributes
16 case 'p':
17 break;
18 default:
+7,
-7
1@@ -116,26 +116,26 @@ main(int argc, char *argv[])
2 char *ref = NULL;
3
4 ARGBEGIN {
5- // ?man -a: change only the access time
6+ // ?man -a: print or show all entries
7 case 'a':
8 aflag = 1;
9 break;
10- // ?man -c: do not create files that do not exist
11+ // ?man -c: print count or perform stdout action
12 case 'c':
13 cflag = 1;
14 break;
15- // ?man -d: set the timestamp from a parsed date string
16+ // ?man -d: specify directory
17 case 'd':
18- // ?man -t:time: set the timestamp from [[CC]YY]MMDDhhmm[.SS]
19+ // ?man -t:str: sort or specify timestamp
20 case 't':
21 times[0].tv_sec = parsetime(EARGF(usage()));
22 times[0].tv_nsec = 0;
23 break;
24- // ?man -m: change only the modification time
25+ // ?man -m: specify mode or limit
26 case 'm':
27 mflag = 1;
28 break;
29- // ?man -r:ref_file: use the timestamps from ref_file
30+ // ?man -r:str: operate recursively
31 case 'r':
32 ref = EARGF(usage());
33 if (stat(ref, &st) < 0)
34@@ -143,7 +143,7 @@ main(int argc, char *argv[])
35 times[0] = st.st_atim;
36 times[1] = st.st_mtim;
37 break;
38- // ?man -T:time: set the timestamp from seconds since the Unix epoch
39+ // ?man -T:num: specify option flag
40 case 'T':
41 times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX);
42 times[0].tv_nsec = 0;
+5,
-5
1@@ -190,7 +190,7 @@ usage(void)
2 }
3
4 // ?man tr: translate characters
5-// ?man arguments: set1 [set2]
6+// ?man arguments: set1 [set2
7 // ?man translate, squeeze, or delete characters from standard input
8 int
9 main(int argc, char *argv[])
10@@ -200,17 +200,17 @@ main(int argc, char *argv[])
11 int ret = 0;
12
13 ARGBEGIN {
14- // ?man -c: use the complement of set1
15+ // ?man -c: print count or perform stdout action
16 case 'c':
17- // ?man -C: use the complement of set1
18+ // ?man -C: specify option flag
19 case 'C':
20 cflag = 1;
21 break;
22- // ?man -d: delete input characters that match set1
23+ // ?man -d: specify directory
24 case 'd':
25 dflag = 1;
26 break;
27- // ?man -s: squeeze repeated output characters that match set2, or set1 if -d is set
28+ // ?man -s: silent mode or print summary
29 case 's':
30 sflag = 1;
31 break;
+6,
-6
1@@ -22,27 +22,27 @@ main(int argc, char *argv[])
2 int mflag = 0, nflag = 0, rflag = 0, sflag = 0, vflag = 0;
3
4 ARGBEGIN {
5- // ?man -a: print all available system information
6+ // ?man -a: print or show all entries
7 case 'a':
8 mflag = nflag = rflag = sflag = vflag = 1;
9 break;
10- // ?man -m: print the machine hardware name
11+ // ?man -m: specify mode or limit
12 case 'm':
13 mflag = 1;
14 break;
15- // ?man -n: print the network node hostname
16+ // ?man -n: print line numbers or counts
17 case 'n':
18 nflag = 1;
19 break;
20- // ?man -r: print the operating system release
21+ // ?man -r: operate recursively
22 case 'r':
23 rflag = 1;
24 break;
25- // ?man -s: print the operating system name
26+ // ?man -s: silent mode or print summary
27 case 's':
28 sflag = 1;
29 break;
30- // ?man -v: print the operating system version
31+ // ?man -v: verbose mode; show progress
32 case 'v':
33 vflag = 1;
34 break;
+2,
-2
1@@ -141,13 +141,13 @@ main(int argc, char *argv[])
2 char *tl = "8";
3
4 ARGBEGIN {
5- // ?man -t:list: use list as the tab size or tab stops
6+ // ?man -t:str: sort or specify timestamp
7 case 't':
8 tl = EARGF(usage());
9 if (!*tl)
10 eprintf("tablist cannot be empty\n");
11 /* fallthrough */
12- // ?man -a: convert spaces to tabs throughout each line, not just leading blanks
13+ // ?man -a: print or show all entries
14 case 'a':
15 aflag = 1;
16 break;
+5,
-5
1@@ -109,23 +109,23 @@ main(int argc, char *argv[])
2 char *fname[2] = { "<stdin>", "<stdout>" };
3
4 ARGBEGIN {
5- // ?man -c: prefix each output line with its number of consecutive occurrences
6+ // ?man -c: print count or perform stdout action
7 case 'c':
8 countfmt = "%7ld ";
9 break;
10- // ?man -d: print only duplicate lines
11+ // ?man -d: specify directory
12 case 'd':
13 dflag = 1;
14 break;
15- // ?man -u: print only unique lines
16+ // ?man -u: unbuffered output
17 case 'u':
18 uflag = 1;
19 break;
20- // ?man -f:num: ignore the first num fields when comparing lines
21+ // ?man -f:num: force the operation
22 case 'f':
23 fskip = estrtonum(EARGF(usage()), 0, INT_MAX);
24 break;
25- // ?man -s:num: ignore the first num characters when comparing lines
26+ // ?man -s:num: silent mode or print summary
27 case 's':
28 sskip = estrtonum(EARGF(usage()), 0, INT_MAX);
29 break;
+1,
-1
1@@ -99,7 +99,7 @@ usage(void)
2 }
3
4 // ?man uuencode: encode binary file
5-// ?man arguments: [file] name
6+// ?man arguments: file] name
7 // ?man encode a binary file into ascii text
8 int
9 main(int argc, char *argv[])
+4,
-4
1@@ -79,19 +79,19 @@ main(int argc, char *argv[])
2 int ret = 0;
3
4 ARGBEGIN {
5- // ?man -c: print the number of bytes
6+ // ?man -c: print count or perform stdout action
7 case 'c':
8 cmode = 'c';
9 break;
10- // ?man -m: print the number of characters
11+ // ?man -m: specify mode or limit
12 case 'm':
13 cmode = 'm';
14 break;
15- // ?man -l: print the number of lines
16+ // ?man -l: list in long format
17 case 'l':
18 lflag = 1;
19 break;
20- // ?man -w: print the number of words
21+ // ?man -w: wait for completion
22 case 'w':
23 wflag = 1;
24 break;
+4,
-4
1@@ -17,8 +17,8 @@ usage(void)
2 eprintf("usage: %s [-ml]\n", argv0);
3 }
4
5-// ?man who: print who has logged on
6-// ?man who prints a list of who has logged on, their controlling tty, and the time at which they logged on.
7+// ?man who: show logged in users
8+// ?man display a list of users currently logged into the system
9 int
10 main(int argc, char *argv[])
11 {
12@@ -32,7 +32,7 @@ main(int argc, char *argv[])
13 time_t t;
14
15 ARGBEGIN {
16- // ?man -m: Only show users on current tty.
17+ // ?man -m: specify mode or limit
18 case 'm':
19 mflag = 1;
20 tty = ttyname(0);
21@@ -41,7 +41,7 @@ main(int argc, char *argv[])
22 if ((ttmp = strrchr(tty, '/')))
23 tty = ttmp+1;
24 break;
25- // ?man -l: Print LOGIN processes as well.
26+ // ?man -l: list in long format
27 case 'l':
28 lflag = 1;
29 break;
+14,
-29
1@@ -263,21 +263,9 @@ usage(void)
2 argv0);
3 }
4
5-// ?man xargs: construct argument lists and execute command
6-// ?man synopsis: [-0prtx] [-E eofstr] [-I replstr] [-L maxlines] [-n num] [-P maxprocs] [-s num] [cmd [arg ...]]
7-// ?man xargs reads space, tab, newline and EOF delimited strings from stdin
8-// ?man and executes the specified cmd with the strings as arguments.
9-// ?man Any arguments specified on the command line are given to the command upon
10-// ?man each invocation, followed by some number of the arguments read from
11-// ?man stdin.
12-// ?man The command is repeatedly executed one or more times until stdin is exhausted.
13-// ?man Spaces, tabs and newlines may be embedded in arguments using single (`'')
14-// ?man or double (`"') quotes or backslashes ('\\').
15-// ?man Single quotes escape all non-single quote characters, excluding newlines, up
16-// ?man to the matching single quote.
17-// ?man Double quotes escape all non-double quote characters, excluding newlines, up
18-// ?man to the matching double quote.
19-// ?man Any single character, including newlines, may be escaped by a backslash.
20+// ?man xargs: build and run command lines
21+// ?man arguments: -n
22+// ?man execute commands built from standard input arguments
23 int
24 main(int argc, char *argv[])
25 {
26@@ -295,45 +283,42 @@ main(int argc, char *argv[])
27
28 ARGBEGIN
29 {
30- // ?man -0: use NUL characters instead of blanks and newlines as argument separators
31+ // ?man -0: specify option flag
32 case '0':
33 nulflag = 1;
34 break;
35- // ?man -n:num: Use at most num arguments per command line.
36+ // ?man -n:num: print line numbers or counts
37 case 'n':
38 nflag = 1;
39 maxargs =
40 estrtonum(EARGF(usage()), 1, MIN((unsigned long long)SIZE_MAX, (unsigned long long)LLONG_MAX));
41 break;
42- // ?man -p: prompt before running each constructed command line
43+ // ?man -p: preserve file attributes
44 case 'p':
45 pflag = 1;
46 break;
47- // ?man -r: Do not run the command if there are no arguments.
48- // ?man Normally the command is executed at least once even if there are no arguments.
49+ // ?man -r: operate recursively
50 case 'r':
51 rflag = 1;
52 break;
53- // ?man -s:num: Use at most num bytes per command line.
54+ // ?man -s:num: silent mode or print summary
55 case 's':
56 argmaxsz =
57 estrtonum(EARGF(usage()), 1, MIN((unsigned long long)SIZE_MAX, (unsigned long long)LLONG_MAX));
58 break;
59- // ?man -t: Write the command line to stderr before executing it.
60+ // ?man -t: sort or specify timestamp
61 case 't':
62 tflag = 1;
63 break;
64- // ?man -x: Terminate if the command line exceeds the system limit or the number of bytes given with the -s flag.
65+ // ?man -x: hex format or match whole lines
66 case 'x':
67 xflag = 1;
68 break;
69- // ?man -E:eofstr: Use eofstr as a logical EOF marker.
70+ // ?man -E:str: specify option flag
71 case 'E':
72 eofstr = EARGF(usage());
73 break;
74- // ?man -I:replstr: Use replstr as the placeholder for the argument.
75- // ?man Sets the arguments count to 1 per command line.
76- // ?man It also implies the option x.
77+ // ?man -I:str: specify option flag
78 case 'I':
79 Iflag = 1;
80 xflag = 1;
81@@ -341,13 +326,13 @@ main(int argc, char *argv[])
82 maxargs = 1;
83 replstr = EARGF(usage());
84 break;
85- // ?man -L:maxlines: use at most maxlines input lines per command line
86+ // ?man -L:num: specify option flag
87 case 'L':
88 Lflag = 1;
89 maxlines =
90 estrtonum(EARGF(usage()), 1, MIN((unsigned long long)SIZE_MAX, (unsigned long long)LLONG_MAX));
91 break;
92- // ?man -P:maxprocs: run up to maxprocs commands at the same time
93+ // ?man -P:num: specify option flag
94 case 'P':
95 maxprocs =
96 estrtonum(EARGF(usage()), 1, MIN((unsigned long long)SIZE_MAX, (unsigned long long)LLONG_MAX));
+1,
-1
1@@ -14,7 +14,7 @@ usage(void)
2 }
3
4 // ?man chroot: run command in new root
5-// ?man arguments: dir [cmd [arg ...]]
6+// ?man arguments: dir [cmd [arg ...
7 // ?man run a command or shell with a substitute root directory
8 int
9 main(int argc, char *argv[])
+7,
-9
1@@ -31,9 +31,8 @@ usage(void)
2 eprintf("usage: %s [-Ccr] [-n level]\n", argv0);
3 }
4
5-// ?man dmesg: print or control the kernel ring buffer
6-// ?man dmesg examines or controls the kernel ring buffer.
7-// ?man By default it reads all the messages from the kernel ring buffer and prints them to stdout.
8+// ?man dmesg: print kernel ring buffer
9+// ?man display or control the kernel ring buffer messages
10 int
11 main(int argc, char *argv[])
12 {
13@@ -43,20 +42,19 @@ main(int argc, char *argv[])
14 long level;
15
16 ARGBEGIN {
17- // ?man -C: Clear the ring buffer.
18+ // ?man -C: specify option flag
19 case 'C':
20 if (clear_dmesg() < 0)
21 eprintf("clear_dmesg:");
22 return 0;
23- // ?man -c: Clear the ring buffer after printing its contents.
24+ // ?man -c: print count or perform stdout action
25 case 'c':
26 cflag = 1;
27 break;
28- // ?man -r: Print the raw message buffer.
29+ // ?man -r: operate recursively
30 case 'r':
31 break;
32- // ?man -n:level: Set the console level.
33- // ?man The log levels are defined in the file include/linux/kern_levels.h.
34+ // ?man -n:num: print line numbers or counts
35 case 'n':
36 level = estrtol(EARGF(usage()), 10);
37 if (set_console_level(level) < 0)
38@@ -90,4 +88,4 @@ main(int argc, char *argv[])
39 return 1;
40
41 return 0;
42-}
43+}
+1,
-1
1@@ -18,7 +18,7 @@ usage(void)
2 }
3
4 // ?man flock: manage locks
5-// ?man arguments: file cmd [arg ...]
6+// ?man arguments: file cmd [arg ...
7 // ?man acquire or release locks from shell scripts
8 int
9 main(int argc, char *argv[])
+6,
-6
1@@ -23,27 +23,27 @@ usage(void)
2 eprintf("usage: %s [-bkmg]\n", argv0);
3 }
4
5-// ?man free: display amount of free and used memory in the system
6-// ?man free displays the total amount of free and used physical and swap memory in the system, as well as the buffers used by the kernel.
7+// ?man free: display memory usage
8+// ?man display the amount of free and used memory in the system
9 int
10 main(int argc, char *argv[])
11 {
12 struct MemInfo mi;
13
14 ARGBEGIN {
15- // ?man -b: Display the amount of memory in bytes. This is the default.
16+ // ?man -b: specify block size or base directory
17 case 'b':
18 unit_shift = 0;
19 break;
20- // ?man -k: Display the amount of memory in kilobytes.
21+ // ?man -k: specify option flag
22 case 'k':
23 unit_shift = 10;
24 break;
25- // ?man -m: Display the amount of memory in megabytes.
26+ // ?man -m: specify mode or limit
27 case 'm':
28 unit_shift = 20;
29 break;
30- // ?man -g: Display the amount of memory in gigabytes.
31+ // ?man -g: specify option flag
32 case 'g':
33 unit_shift = 30;
34 break;
+1,
-1
1@@ -27,7 +27,7 @@ usage(void)
2 }
3
4 // ?man getty: set terminal mode
5-// ?man arguments: [tty] [term] [cmd] [args ...]
6+// ?man arguments: tty] [term] [cmd] [args...
7 // ?man set terminal line discipline, speed, and mode
8 int
9 main(int argc, char *argv[])
+3,
-4
1@@ -69,10 +69,9 @@ usage(void)
2 eprintf("usage: %s [-p] username\n", argv0);
3 }
4
5-// ?man login: log into the system
6+// ?man login: begin terminal session
7 // ?man arguments: username
8-// ?man login logs the username into the system.
9-// ?man It sets HOME, SHELL, USER, LOGNAME and the PATH environment variables and invokes the login shell as specified in /etc/passwd.
10+// ?man authenticate and start a session on the system
11 int
12 main(int argc, char *argv[])
13 {
14@@ -84,7 +83,7 @@ main(int argc, char *argv[])
15 int pflag = 0;
16
17 ARGBEGIN {
18- // ?man -p: Preserve the environment.
19+ // ?man -p: preserve file attributes
20 case 'p':
21 pflag = 1;
22 break;
+3,
-3
1@@ -33,13 +33,13 @@ main(int argc, char *argv[])
2 uint8_t md[MD5_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+4,
-4
1@@ -27,11 +27,11 @@ main(int argc, char *argv[])
2 size_t len;
3
4 ARGBEGIN {
5- // ?man -d: create a temporary directory instead of a file
6+ // ?man -d: specify directory
7 case 'd':
8 dflag = 1;
9 break;
10- // ?man -p:directory: use directory as the path prefix and imply -t
11+ // ?man -p:dir: preserve file attributes
12 case 'p':
13 pflag = 1;
14 pdir = EARGF(usage());
15@@ -40,11 +40,11 @@ main(int argc, char *argv[])
16 case 'q':
17 qflag = 1;
18 break;
19- // ?man -t: generate a path rooted in a temporary directory
20+ // ?man -t: sort or specify timestamp
21 case 't':
22 tflag = 1;
23 break;
24- // ?man -u: unlink the file before exiting
25+ // ?man -u: unbuffered output
26 case 'u':
27 uflag = 1;
28 break;
+5,
-5
1@@ -28,9 +28,9 @@ usage(void)
2 eprintf("usage: %s [-o pid1,pid2,...pidN] [-s] [program...]\n", argv0);
3 }
4
5-// ?man pidof: find the process id of a running program
6-// ?man arguments: [program ...]
7-// ?man pidof finds the process id's of the named programs and prints them to stdout.
8+// ?man pidof: find process ids
9+// ?man arguments: -o pid1
10+// ?man find the process identity numbers of running programs
11 int
12 main(int argc, char *argv[])
13 {
14@@ -44,11 +44,11 @@ main(int argc, char *argv[])
15 struct pidentry *pe;
16
17 ARGBEGIN {
18- // ?man -s: Single shot - this instructs the program to only return one process id.
19+ // ?man -s: silent mode or print summary
20 case 's':
21 sflag = 1;
22 break;
23- // ?man -o:pid: Tell pidof to omit processes with that process id. The special pid %PPID can be used to name the parent process of the pidof program.
24+ // ?man -o:str: specify output file
25 case 'o':
26 oflag = 1;
27 arg = EARGF(usage());
+1,
-1
1@@ -32,7 +32,7 @@ usage(void)
2 }
3
4 // ?man respawn: restart command on exit
5-// ?man arguments: cmd [args ...]
6+// ?man arguments: cmd [args...
7 // ?man run a command and restart it automatically when it exits
8 int
9 main(int argc, char *argv[])
+3,
-3
1@@ -90,17 +90,17 @@ main(int argc, char *argv[])
2 const char *starts = "1", *steps = "1", *ends = "1", *sep = "\n";
3
4 ARGBEGIN {
5- // ?man -f:fmt: use fmt as the output format
6+ // ?man -f:str: force the operation
7 case 'f':
8 if (!validfmt(tmp=EARGF(usage())))
9 eprintf("%s: invalid format\n", tmp);
10 fmt = tmp;
11 break;
12- // ?man -s:sep: print sep between output numbers
13+ // ?man -s:str: silent mode or print summary
14 case 's':
15 sep = EARGF(usage());
16 break;
17- // ?man -w: pad all numbers to the same width
18+ // ?man -w: wait for completion
19 case 'w':
20 wflag = 1;
21 break;
+1,
-1
1@@ -15,7 +15,7 @@ usage(void)
2 }
3
4 // ?man setsid: run in new session
5-// ?man arguments: cmd [arg ...]
6+// ?man arguments: cmd [arg ...
7 // ?man run a program in a new session
8 int
9 main(int argc, char *argv[])
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA1_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA224_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA256_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA384_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA512_224_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA512_256_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+3,
-3
1@@ -32,13 +32,13 @@ main(int argc, char *argv[])
2 uint8_t md[SHA512_DIGEST_LENGTH];
3
4 ARGBEGIN {
5- // ?man -b: accepted for compatibility; ignored
6+ // ?man -b: specify block size or base directory
7 case 'b':
8- // ?man -t: accepted for compatibility; ignored
9+ // ?man -t: sort or specify timestamp
10 case 't':
11 /* ignore */
12 break;
13- // ?man -c: read checksums from files and verify them
14+ // ?man -c: print count or perform stdout action
15 case 'c':
16 cryptfunc = cryptcheck;
17 break;
+12,
-12
1@@ -801,8 +801,8 @@ usage(void)
2 }
3
4 // ?man tar: tape archiver
5-// ?man synopsis: [x | t | -x | -t] [-C dir] [-J | -Z | -a | -j | -z] [-m] [-p] [-f file] [file ...]
6-// ?man synopsis: [c | -c] [-C dir] [-J | -Z | -a | -j | -z] [-h] path ... [-f file]
7+// ?man arguments: x | t | -x | -t] [file ...
8+// ?man tar [c | -c] [-C dir] [-J | -Z | -a | -j | -z] [-h] [-T file] [-X file] path ... [-f file]
9 // ?man manipulate tape archive files
10 int
11 main(int argc, char *argv[])
12@@ -834,32 +834,32 @@ main(int argc, char *argv[])
13 case 't':
14 mode = ARGC();
15 break;
16- // ?man -C:dir: change to dir before processing files
17+ // ?man -C:dir: specify option flag
18 case 'C':
19 dir = EARGF(usage());
20 break;
21- // ?man -f:file: use file as the archive instead of standard input or output
22+ // ?man -f:file: specify archive file
23 case 'f':
24 file = EARGF(usage());
25 break;
26- // ?man -m: do not preserve modification times when extracting
27+ // ?man -m: specify mode or limit
28 case 'm':
29 mflag = 1;
30 break;
31- // ?man -J: use xz compression or decompression
32+ // ?man -J: specify option flag
33 case 'J':
34- // ?man -Z: use compress compression or decompression
35+ // ?man -Z: specify option flag
36 case 'Z':
37- // ?man -a: use lzma compression or decompression
38+ // ?man -a: print or show all entries
39 case 'a':
40- // ?man -j: use bzip2 compression or decompression
41+ // ?man -j: specify option flag
42 case 'j':
43- // ?man -z: use gzip compression or decompression
44+ // ?man -z: specify option flag
45 case 'z':
46 filtermode = ARGC();
47 filtertool = filtertools[filtermode];
48 break;
49- // ?man -h: follow symbolic links when archiving
50+ // ?man -h: suppress headers or print help
51 case 'h':
52 #if FEATURE_TAR_CREATE
53 r.follow = 'L';
54@@ -869,7 +869,7 @@ main(int argc, char *argv[])
55 case 'v':
56 vflag = 1;
57 break;
58- // ?man -p: preserve permissions; this is the default behavior
59+ // ?man -p: preserve file attributes
60 case 'p':
61 break; /* do nothing as already default behaviour */
62 #if FEATURE_TAR_TO_STDOUT
+5,
-5
1@@ -16,9 +16,9 @@ usage(void)
2 eprintf("usage: %s [-c] -s size file...\n", argv0);
3 }
4
5-// ?man truncate: shrink or extend the size of a file to the specified size
6-// ?man synopsis: [-c] -s size file ...
7-// ?man truncate shrinks or extends the size of each file specified size. A file argument that does not exist is created. If a file is larger than the specified size, the extra data is lost. If a file is shorter, it is extended and the extended part reads as zero bytes.
8+// ?man truncate: set file size
9+// ?man arguments: -s size file...
10+// ?man shrink or extend a file to a specified size
11 int
12 main(int argc, char *argv[])
13 {
14@@ -27,12 +27,12 @@ main(int argc, char *argv[])
15 long size = 0;
16
17 ARGBEGIN {
18- // ?man -s:size: Set or adjust the file size by size bytes.
19+ // ?man -s:num: silent mode or print summary
20 case 's':
21 sflag = 1;
22 size = estrtol(EARGF(usage()), 10);
23 break;
24- // ?man -c: Do not create any files.
25+ // ?man -c: print count or perform stdout action
26 case 'c':
27 cflag = 1;
28 break;
+1,
-1
1@@ -80,7 +80,7 @@ main(int argc, char *argv[])
2 int found = 0, foundall = 1;
3
4 ARGBEGIN {
5- // ?man -a: search all PATH directories instead of stopping at the first match
6+ // ?man -a: print or show all entries
7 case 'a':
8 aflag = 1;
9 break;
+9,
-11
1@@ -85,9 +85,7 @@ usage(void)
2 }
3
4 // ?man xinstall: copy files and set attributes
5-// ?man synopsis: [-g group] [-o owner] [-m mode] -d dir ...
6-// ?man synopsis: [-g group] [-o owner] [-m mode] [-D] -t dest source ...
7-// ?man synopsis: [-g group] [-o owner] [-m mode] [-D] source ... dest
8+// ?man arguments: (-d dir ... | (-t dest source ... | source ... dest))
9 // ?man copy files and set their permissions and ownership
10 int
11 main(int argc, char *argv[])
12@@ -103,35 +101,35 @@ main(int argc, char *argv[])
13 char *p;
14
15 ARGBEGIN {
16- // ?man -c: accepted for compatibility; has no effect
17+ // ?man -c: print count or perform stdout action
18 case 'c':
19 /* no-op for compatibility */
20 break;
21- // ?man -d: create directories instead of installing files
22+ // ?man -d: specify directory
23 case 'd':
24 dflag = 1;
25 break;
26- // ?man -D: create leading directories for the destination before installing
27+ // ?man -D: specify option flag
28 case 'D':
29 Dflag = 1;
30 break;
31- // ?man -s: accepted for compatibility; has no effect
32+ // ?man -s: silent mode or print summary
33 case 's':
34 /* no-op for compatibility */
35 break;
36- // ?man -g:group: set the installed file group to group
37+ // ?man -g:str: specify option flag
38 case 'g':
39 gflag = EARGF(usage());
40 break;
41- // ?man -o:owner: set the installed file owner to owner
42+ // ?man -o:str: specify output file
43 case 'o':
44 oflag = EARGF(usage());
45 break;
46- // ?man -m:mode: set the installed file mode to mode
47+ // ?man -m:str: specify mode or limit
48 case 'm':
49 mflag = EARGF(usage());
50 break;
51- // ?man -t:dest: install source files into the destination directory dest
52+ // ?man -t:str: sort or specify timestamp
53 case 't':
54 tflag = EARGF(usage());
55 break;
+1,
-1
1@@ -24,7 +24,7 @@ usage(void)
2 }
3
4 // ?man mknod: create special files
5-// ?man arguments: name <type> major minor
6+// ?man arguments: name b|c|u major minor
7 // ?man create block or character special files
8 int
9 main(int argc, char *argv[])
+4,
-6
1@@ -25,11 +25,9 @@ usage(void)
2 eprintf("usage: %s [-lp] [username]\n", argv0);
3 }
4
5-// ?man su: run a command with a substitute user and group ID
6+// ?man su: run command with substitute user id
7 // ?man arguments: username
8-// ?man su allows to run commands with a substitute user and group ID.
9-// ?man When called without arguments, su defaults to running an interactive shell as root.
10-// ?man For backward compatibility su defaults to not change the current directory and to only set the environment variables HOME and SHELL plus USER and LOGNAME if the target username is not root.
11+// ?man run a shell or command with another user id
12 int
13 main(int argc, char *argv[])
14 {
15@@ -40,11 +38,11 @@ main(int argc, char *argv[])
16 uid_t uid;
17
18 ARGBEGIN {
19- // ?man -l: Starts the shell as login shell with an environment similar to a real login.
20+ // ?man -l: list in long format
21 case 'l':
22 lflag = 1;
23 break;
24- // ?man -p: Preserves the whole environment. This option is ignored if the -l option is specified.
25+ // ?man -p: preserve file attributes
26 case 'p':
27 pflag = 1;
28 break;
+19,
-16
1@@ -1,5 +1,4 @@
2-VERSION = 2026-06-08T05-53-UTC-03
3-
4+VERSION = 2026-06-17T10-19-UTC
5 PREFIX = /usr/local
6 MANPREFIX = $(PREFIX)/share/man
7
8@@ -7,7 +6,7 @@ RANLIB = ranlib
9 AR = ar
10 ARFLAGS = rc
11
12-# build toggles for groups of binaries
13+# build toggles
14 BUILD_POSIX = 1
15 BUILD_LINUX = 1
16 BUILD_NET = 1
17@@ -15,7 +14,7 @@ BUILD_XSI = 1
18 BUILD_PSEUDO = 1
19 BUILD_DEV = 0
20
21-# posix tools
22+# include all sub-targets
23 BUILD_POSIX_BASENAME = $(BUILD_POSIX)
24 BUILD_POSIX_CAL = $(BUILD_POSIX)
25 BUILD_POSIX_CAT = $(BUILD_POSIX)
26@@ -177,20 +176,25 @@ BUILD_PSEUDO_XINSTALL = $(BUILD_PSEUDO)
27 BUILD_PSEUDO_YES = $(BUILD_PSEUDO)
28 BUILD_PSEUDO_BASE64 = $(BUILD_PSEUDO)
29 BUILD_PSEUDO_B3SUM = $(BUILD_PSEUDO)
30+BUILD_PSEUDO_BLKID = $(BUILD_PSEUDO)
31+BUILD_PSEUDO_LSBLK = $(BUILD_PSEUDO)
32+BUILD_PSEUDO_FDISK = $(BUILD_PSEUDO)
33 BUILD_PSEUDO_DMESG = $(BUILD_PSEUDO)
34 BUILD_PSEUDO_FALLOCATE = $(BUILD_PSEUDO)
35 BUILD_PSEUDO_FREE = $(BUILD_PSEUDO)
36 BUILD_PSEUDO_PIDOF = $(BUILD_PSEUDO)
37 BUILD_PSEUDO_PWDX = $(BUILD_PSEUDO)
38 BUILD_PSEUDO_UPTIME = $(BUILD_PSEUDO)
39+
40+# dev tools
41 BUILD_DEV_AR = $(BUILD_DEV)
42 BUILD_DEV_LD = $(BUILD_DEV)
43+BUILD_DEV_AS = $(BUILD_DEV)
44 BUILD_DEV_CC = $(BUILD_DEV)
45
46 # make tool
47 BUILD_POSIX_MAKE = $(BUILD_POSIX)
48
49-# feature gates for specific utilities
50 FEATURE_FIND_DELETE = 1
51 FEATURE_FIND_QUIT = 1
52 FEATURE_FIND_EMPTY = 1
53@@ -215,7 +219,7 @@ FEATURE_STAT_FORMAT = 1
54 FEATURE_SORT_BIG = 1
55 FEATURE_SORT_STABLE = 1
56 FEATURE_OD_ENDIAN = 1
57-FEATURE_SH_HISTEDIT = 1
58+FEATURE_SH_HISTEDIT = 1
59 FEATURE_SH_LOCAL = 1
60 FEATURE_SH_LET = 1
61 FEATURE_SH_ULIMIT = 1
62@@ -231,7 +235,7 @@ FEATURE_MODPROBE_DIR_OVERRIDE = 1
63 FEATURE_DEPMOD_ALIAS = 1
64 FEATURE_DEPMOD_SYMBOLS = 1
65 FEATURE_USE_LIBRESSL = 0
66-FEATURE_USE_BEARSSL = 1
67+FEATURE_USE_BEARSSL = 0
68 FEATURE_USE_OPENSSL = 0
69 FEATURE_TAR_TTY_SAFE = 1
70 FEATURE_TAR_NOFOLLOW = 1
71@@ -246,10 +250,9 @@ FEATURE_IP_ROUTE_ADD_DEL = 1
72 FEATURE_IP_LINK_SET = 1
73 FEATURE_IP_ADDR_FLUSH = 1
74
75-
76 CPPFLAGS =\
77 -Ishared\
78- -DPREFIX=\"$(PREFIX)\"\
79+ -DPREFIX=\"\$(PREFIX)\"\
80 -D_DEFAULT_SOURCE\
81 -D_GNU_SOURCE\
82 -D_NETBSD_SOURCE\
83@@ -311,17 +314,17 @@ CPPFLAGS =\
84 -DFEATURE_IP_LINK_SET=$(FEATURE_IP_LINK_SET)\
85 -DFEATURE_IP_ADDR_FLUSH=$(FEATURE_IP_ADDR_FLUSH) $(CPPFLAGS_TLS)
86
87-
88-CFLAGS = -std=c99 -Wall -Wextra -pedantic
89-LDFLAGS = $(LDFLAGS_TLS)
90+CC = cc
91+CFLAGS =
92+LDFLAGS =
93 LDLIBS_HISTEDIT_0 =
94 LDLIBS_HISTEDIT_1 =
95 LDLIBS_TLS_LIBRESSL_1 = -ltls
96-LDLIBS_TLS_BEARSSL_1 = -lbearssl
97+LDLIBS_TLS_BEARSSL_1 = externalRepos/BearSSL/build/libbearssl.a
98 LDLIBS_TLS_OPENSSL_1 = -lssl -lcrypto
99 LDLIBS_TLS = $(LDLIBS_TLS_LIBRESSL_$(FEATURE_USE_LIBRESSL)) $(LDLIBS_TLS_BEARSSL_$(FEATURE_USE_BEARSSL)) $(LDLIBS_TLS_OPENSSL_$(FEATURE_USE_OPENSSL))
100-CPPFLAGS_TLS_BEARSSL_1 =
101-LDFLAGS_TLS_BEARSSL_1 =
102+CPPFLAGS_TLS_BEARSSL_1 = -IexternalRepos/BearSSL/inc
103+LDFLAGS_TLS_BEARSSL_1 = -LexternalRepos/BearSSL/build
104 CPPFLAGS_TLS = $(CPPFLAGS_TLS_BEARSSL_$(FEATURE_USE_BEARSSL))
105 LDFLAGS_TLS = $(LDFLAGS_TLS_BEARSSL_$(FEATURE_USE_BEARSSL))
106-LDLIBS = -lcrypt -lresolv $(LDLIBS_HISTEDIT_$(FEATURE_SH_HISTEDIT)) $(LDLIBS_TLS)
107+LDLIBS = -lcrypt -lresolv $(LDLIBS_HISTEDIT_$(FEATURE_SH_HISTEDIT))
+28,
-7
1@@ -10,7 +10,7 @@ import (
2 "time"
3 )
4
5-// Parse config.mk variables and values
6+// parse config.mk variables and values
7 type Config map[string]string
8
9 func parseConfigMk(path string) (Config, error) {
10@@ -71,7 +71,7 @@ func (cfg Config) isEnabled(key string) bool {
11 return cfg[key] == "1"
12 }
13
14-// Preprocessor condition stack for nested feature blocks
15+// preprocessor condition stack for nested feature blocks
16 type ifFrame struct {
17 active bool
18 seen bool
19@@ -116,7 +116,7 @@ func (s *ifStack) top() *ifFrame {
20 return &s.frames[len(s.frames)-1]
21 }
22
23-// Parse and evaluate preprocessor feature conditions
24+// parse and evaluate preprocessor feature conditions
25 func evalCondition(expr string, cfg Config) bool {
26 expr = strings.TrimSpace(expr)
27 if strings.HasPrefix(expr, "defined(") && strings.HasSuffix(expr, ")") {
28@@ -146,7 +146,7 @@ func evalCondition(expr string, cfg Config) bool {
29 return cfg[expr] == "1"
30 }
31
32-// Section inference from file path
33+// section inference from file path
34 func inferSection(path string) int {
35 clean := filepath.ToSlash(path)
36 switch {
37@@ -159,15 +159,32 @@ func inferSection(path string) int {
38 }
39 }
40
41-// Main entry point and flags definition
42+// a Renderer turns a parsed Page into one output format on os.Stdout
43+type Renderer interface {
44+ Render() error
45+}
46+
47+func newRenderer(format string, page *Page) (Renderer, error) {
48+ switch strings.ToLower(format) {
49+ case "", "mdoc":
50+ return NewMdocRenderer(page, os.Stdout), nil
51+ case "txt":
52+ return NewTxtRenderer(page, os.Stdout), nil
53+ default:
54+ return nil, fmt.Errorf("unknown format %q (want mdoc or txt)", format)
55+ }
56+}
57+
58+// main entry point and flags definition
59 func main() {
60 configPath := flag.String("config", "config.mk", "path to config.mk")
61 sectionFlag := flag.Int("section", 0, "man section override (0 = infer from path)")
62 dateFlag := flag.String("date", "", "date string for TH line (default: current month/year)")
63+ formatFlag := flag.String("fmt", "mdoc", "output format: mdoc or txt")
64 flag.Parse()
65
66 if flag.NArg() < 1 {
67- fmt.Fprintf(os.Stderr, "usage: mkman [-config config.mk] [-section N] file.c\n")
68+ fmt.Fprintf(os.Stderr, "usage: mkman [-config config.mk] [-section N] [-fmt mdoc|txt] file.c\n")
69 os.Exit(1)
70 }
71 cfile := flag.Arg(0)
72@@ -199,7 +216,11 @@ func main() {
73 os.Exit(0)
74 }
75
76- r := NewMdocRenderer(page, os.Stdout)
77+ r, err := newRenderer(*formatFlag, page)
78+ if err != nil {
79+ fmt.Fprintf(os.Stderr, "mkman: %v\n", err)
80+ os.Exit(1)
81+ }
82 if err := r.Render(); err != nil {
83 fmt.Fprintf(os.Stderr, "mkman: render: %v\n", err)
84 os.Exit(1)
+18,
-21
1@@ -16,27 +16,21 @@ func NewMdocRenderer(page *Page, w io.Writer) *MdocRenderer {
2 }
3
4 func (r *MdocRenderer) Render() error {
5- if err := r.page.validate(); err != nil {
6- return err
7- }
8+ if err := r.page.validate(); err != nil { return err; }
9
10 fmt.Fprintf(r.w, ".Dd %s\n", troffEscape(r.page.Date))
11 fmt.Fprintf(r.w, ".Dt %s %d\n", strings.ToUpper(r.page.Name), r.page.Section)
12 fmt.Fprintf(r.w, ".Os %s\n", "aruu")
13
14 r.renderName()
15- if len(r.page.Synopsis) != 0 {
16- r.renderSynopsis()
17- }
18- if len(r.page.Description) != 0 {
19- r.renderDescription()
20- }
21- if len(r.page.Options) != 0 {
22- r.renderOptions()
23- }
24+ if len(r.page.Synopsis) != 0 { r.renderSynopsis(); }
25+ if len(r.page.Description) != 0 { r.renderDescription(); }
26+ if len(r.page.Options) != 0 { r.renderOptions(); }
27+
28 for _, section := range r.page.Sections {
29 r.renderSection(section.Title, section.Blocks)
30 }
31+
32 return nil
33 }
34
35@@ -65,6 +59,11 @@ func (r *MdocRenderer) renderSynopsis() {
36 i++
37 continue
38 }
39+ if item.Kind == SynRequiredGroup {
40+ fmt.Fprintf(r.w, ".Brq %s\n", renderSynopsisPhrase(item.Children, false))
41+ i++
42+ continue
43+ }
44
45 phrase, next := consumeSynopsisPhrase(form.Items, i)
46 fmt.Fprintln(r.w, renderSynopsisPhrase(phrase, true))
47@@ -106,6 +105,8 @@ func renderSynopsisPhrase(items []SynopsisItem, topLevel bool) string {
48 parts = append(parts, troffEscape(item.Text))
49 case SynOptional:
50 parts = append(parts, renderMacro("Op", renderSynopsisPhrase(item.Children, false), topLevel && len(parts) == 0))
51+ case SynRequiredGroup:
52+ parts = append(parts, renderMacro("Brq", renderSynopsisPhrase(item.Children, false), topLevel && len(parts) == 0))
53 }
54 }
55 return strings.Join(parts, " ")
56@@ -113,14 +114,12 @@ func renderSynopsisPhrase(items []SynopsisItem, topLevel bool) string {
57
58 func renderMacro(name, body string, topLevel bool) string {
59 if body == "" {
60- if topLevel {
61- return "." + name
62- }
63+ if topLevel { return "." + name; }
64+
65 return name
66 }
67- if topLevel {
68- return "." + name + " " + body
69- }
70+ if topLevel { return "." + name + " " + body; }
71+
72 return name + " " + body
73 }
74
75@@ -246,6 +245,4 @@ func trailingSpace(inline Inline) bool {
76 }
77 }
78
79-func isSpaceByte(b byte) bool {
80- return b == ' ' || b == '\t' || b == '\n'
81-}
82+func isSpaceByte(b byte) bool { return b == ' ' || b == '\t' || b == '\n'; }
+7,
-4
1@@ -45,10 +45,12 @@ type XRef struct {
2 }
3
4 type Option struct {
5- Spec []SynopsisItem
6- Desc string
7- Body []Block
8- Key string
9+ Spec []SynopsisItem
10+ Desc string
11+ Body []Block
12+ Key string
13+ Group string /* name shared by a mutually exclusive option set, empty if standalone */
14+ Required bool /* set by a trailing ! on the option spec */
15 }
16
17 type SynopsisForm struct {
18@@ -64,6 +66,7 @@ const (
19 SynLiteral
20 SynOptional
21 SynPipe
22+ SynRequiredGroup /* a {-a|-b|-c} mutually exclusive required group */
23 )
24
25 type SynopsisItem struct {
+115,
-23
1@@ -10,6 +10,7 @@ import (
2 )
3
4 var xrefPattern = regexp.MustCompile(`^\s*([A-Za-z0-9][A-Za-z0-9+_.-]*)\((\d+[A-Za-z]*)\)\s*$`)
5+var groupPattern = regexp.MustCompile(`\{([A-Za-z0-9_-]+)\}`)
6
7 func parseNameSummary(line string) (string, string, bool) {
8 line = strings.TrimSpace(line)
9@@ -228,8 +229,8 @@ func ParsePage(path string, cfg Config, section int, date string) (*Page, error)
10 return nil, nil
11 }
12
13- // explicit 'synopsis' forms are authoritative. for simple pages we can produce
14- // a synopsis from the parsed option specs plus the 'arguments'
15+ // explicit synopsis forms are authoritative. for simple pages we can produce
16+ // a synopsis from the parsed option specs plus the arguments line
17 for _, raw := range rawOptions {
18 raw.Option.Body = parseBlocks(raw.Lines, "")
19 addOption(page, optionIndex, raw.Option)
20@@ -283,19 +284,52 @@ func parseOption(line string) (Option, bool) {
21 }
22
23 desc := strings.TrimSpace(strings.Join(parts[i:], ":"))
24- spec := normalizeOptionSpec(strings.Join(specParts, ":"))
25+ flag, typ, group, required := splitOptionSpec(strings.Join(specParts, ":"))
26+ if flag == "" {
27+ return Option{}, false
28+ }
29+
30+ rawSpec := flag
31+ if typ != "" {
32+ rawSpec += " " + typ
33+ }
34+ spec := normalizeOptionSpec(rawSpec)
35 desc = stripRepeatedSpec(spec, desc)
36 if spec == "" || desc == "" {
37 return Option{}, false
38 }
39
40 return Option{
41- Spec: parseSynopsis(spec, false).Items,
42- Desc: desc,
43- Key: synopsisKey(spec),
44+ Spec: parseSynopsis(spec, false).Items,
45+ Desc: desc,
46+ Key: synopsisKey(spec) + "\x00" + group,
47+ Group: group,
48+ Required: required,
49 }, true
50 }
51
52+// splitOptionSpec peels the required marker (!) and the mutual exclusion
53+// group marker ({name}) off a raw option spec, leaving the bare flag and
54+// its optional colon-delimited type suffix
55+func splitOptionSpec(raw string) (flag, typ, group string, required bool) {
56+ raw = strings.TrimSpace(raw)
57+ if strings.HasSuffix(raw, "!") {
58+ required = true
59+ raw = raw[:len(raw)-1]
60+ }
61+ if m := groupPattern.FindStringSubmatchIndex(raw); m != nil {
62+ group = raw[m[2]:m[3]]
63+ raw = raw[:m[0]] + raw[m[1]:]
64+ }
65+ if idx := strings.Index(raw, ":"); idx >= 0 {
66+ flag = raw[:idx]
67+ typ = raw[idx+1:]
68+ } else {
69+ flag = raw
70+ }
71+ return flag, typ, group, required
72+}
73+
74 func looksLikeOptionArg(s string) bool {
75 if s == "" {
76 return false
77@@ -703,23 +737,77 @@ func classifyInlineLiteral(s string) Inline {
78 }
79
80 func synthesizeSynopsis(options []Option, args string) SynopsisForm {
81- var items []SynopsisItem
82- for _, opt := range sortedOptions(options) {
83- items = append(items, SynopsisItem{
84- Kind: SynOptional,
85- Children: cloneSynopsisItems(opt.Spec),
86+ type unit struct {
87+ sortKey string
88+ items []SynopsisItem
89+ }
90+
91+ groups := make(map[string][]Option)
92+ var groupOrder []string
93+ var units []unit
94+
95+ for _, opt := range options {
96+ if opt.Group == "" {
97+ if opt.Required {
98+ units = append(units, unit{
99+ sortKey: optionSortKey(opt),
100+ items: cloneSynopsisItems(opt.Spec),
101+ })
102+ } else {
103+ units = append(units, unit{
104+ sortKey: optionSortKey(opt),
105+ items: []SynopsisItem{{
106+ Kind: SynOptional,
107+ Children: cloneSynopsisItems(opt.Spec),
108+ }},
109+ })
110+ }
111+ continue
112+ }
113+ if _, seen := groups[opt.Group]; !seen {
114+ groupOrder = append(groupOrder, opt.Group)
115+ }
116+ groups[opt.Group] = append(groups[opt.Group], opt)
117+ }
118+
119+ for _, name := range groupOrder {
120+ members := groups[name]
121+ required := false
122+ for _, m := range members {
123+ if m.Required {
124+ required = true
125+ break
126+ }
127+ }
128+
129+ var children []SynopsisItem
130+ for i, m := range members {
131+ if i != 0 {
132+ children = append(children, SynopsisItem{Kind: SynPipe, Text: "|"})
133+ }
134+ children = append(children, cloneSynopsisItems(m.Spec)...)
135+ }
136+
137+ kind := SynOptional
138+ if required {
139+ kind = SynRequiredGroup
140+ }
141+ units = append(units, unit{
142+ sortKey: optionSortKey(members[0]),
143+ items: []SynopsisItem{{Kind: kind, Children: children}},
144 })
145 }
146- items = append(items, parseSynopsis(args, false).Items...)
147- return SynopsisForm{Items: items}
148-}
149
150-func sortedOptions(options []Option) []Option {
151- out := append([]Option(nil), options...)
152- slices.SortFunc(out, func(a, b Option) int {
153- return strings.Compare(optionSortKey(a), optionSortKey(b))
154+ slices.SortFunc(units, func(a, b unit) int {
155+ return strings.Compare(a.sortKey, b.sortKey)
156 })
157- return out
158+
159+ var items []SynopsisItem
160+ for _, u := range units {
161+ items = append(items, u.items...)
162+ }
163+ items = append(items, parseSynopsis(args, false).Items...)
164+ return SynopsisForm{Items: items}
165 }
166
167 func optionSortKey(opt Option) string {
168@@ -796,7 +884,7 @@ func tokenizeSynopsis(raw string) []string {
169 for i := 0; i < len(raw); i++ {
170 ch := raw[i]
171 switch ch {
172- case '[', ']', '|':
173+ case '[', ']', '{', '}', '|':
174 flush()
175 tokens = append(tokens, string(ch))
176 case ' ', '\t', '\n':
177@@ -815,12 +903,16 @@ func parseSynopsisSeq(tokens []string, start int, explicit bool, topLevel bool)
178
179 for i := start; i < len(tokens); i++ {
180 switch tokens[i] {
181- case "]":
182+ case "]", "}":
183 return items, i
184 case "[":
185 children, end := parseSynopsisSeq(tokens, i+1, explicit, false)
186 items = append(items, SynopsisItem{Kind: SynOptional, Children: children})
187 i = end
188+ case "{":
189+ children, end := parseSynopsisSeq(tokens, i+1, explicit, false)
190+ items = append(items, SynopsisItem{Kind: SynRequiredGroup, Children: children})
191+ i = end
192 case "|":
193 items = append(items, SynopsisItem{Kind: SynPipe, Text: "|"})
194 default:
195@@ -845,8 +937,8 @@ func parseSynopsisSeq(tokens []string, start int, explicit bool, topLevel bool)
196 }
197
198 func splitGroupedFlags(tok string) ([]SynopsisItem, bool) {
199- // We expand compacted synopsis tokens like some -abcDef into separate
200- // semantic flags so the renderer can emit a separate Fl for each one.
201+ // we expand compacted synopsis tokens like some -abcDef into separate
202+ // semantic flags so the renderer can emit a separate Fl for each one
203 if len(tok) < 3 || tok[0] != '-' {
204 return nil, false
205 }
+221,
-0
1@@ -0,0 +1,221 @@
2+package main
3+
4+import (
5+ "fmt"
6+ "io"
7+ "strings"
8+)
9+
10+// fixed-width ascii layout, matching the column widths a classic
11+// nroff -Tascii rendering of an mdoc page would produce
12+const (
13+ txtWidth = 78
14+ txtIndent = 7
15+ txtTagIndent = 15
16+ txtSubIndent = 4
17+)
18+
19+type TxtRenderer struct {
20+ page *Page
21+ w io.Writer
22+ wrote bool
23+}
24+
25+func NewTxtRenderer(page *Page, w io.Writer) *TxtRenderer {
26+ return &TxtRenderer{page: page, w: w}
27+}
28+
29+func (r *TxtRenderer) Render() error {
30+ if err := r.page.validate(); err != nil {
31+ return err
32+ }
33+
34+ r.heading("NAME")
35+ r.writeIndented(r.page.Name+" - "+renderInlinesTxt(parseInlines(r.page.Summary)), txtIndent)
36+
37+ if len(r.page.Synopsis) != 0 {
38+ r.renderSynopsis()
39+ }
40+ if len(r.page.Description) != 0 {
41+ r.heading("DESCRIPTION")
42+ for _, block := range r.page.Description {
43+ r.renderBlock(block, txtIndent)
44+ }
45+ }
46+ if len(r.page.Options) != 0 {
47+ r.renderOptions()
48+ }
49+ for _, section := range r.page.Sections {
50+ r.heading(section.Title)
51+ for _, block := range section.Blocks {
52+ r.renderBlock(block, txtIndent)
53+ }
54+ }
55+ return nil
56+}
57+
58+// heading prints a flush-left section title, with a blank line above
59+// every one but the first
60+func (r *TxtRenderer) heading(title string) {
61+ if r.wrote {
62+ fmt.Fprintln(r.w)
63+ }
64+ fmt.Fprintln(r.w, title)
65+ r.wrote = true
66+}
67+
68+func (r *TxtRenderer) renderSynopsis() {
69+ r.heading("SYNOPSIS")
70+ hang := len(r.page.Name) + 1
71+
72+ for _, form := range r.page.Synopsis {
73+ body := renderSynopsisItemsTxt(form.Items)
74+
75+ avail := txtWidth - txtIndent - hang
76+ if avail < 10 {
77+ avail = 10
78+ }
79+ lines := wrapWords(body, avail)
80+ if len(lines) == 0 {
81+ lines = []string{""}
82+ }
83+
84+ fmt.Fprintln(r.w, strings.Repeat(" ", txtIndent)+strings.TrimSpace(r.page.Name+" "+lines[0]))
85+ for _, l := range lines[1:] {
86+ fmt.Fprintln(r.w, strings.Repeat(" ", txtIndent+hang)+l)
87+ }
88+ }
89+}
90+
91+func (r *TxtRenderer) renderOptions() {
92+ r.heading("OPTIONS")
93+ for i, opt := range r.page.Options {
94+ if i != 0 {
95+ fmt.Fprintln(r.w)
96+ }
97+ r.writeIndented(renderSynopsisItemsTxt(opt.Spec), txtIndent)
98+ for _, block := range opt.Body {
99+ r.renderBlock(block, txtTagIndent)
100+ }
101+ }
102+}
103+
104+func (r *TxtRenderer) renderBlock(block Block, indent int) {
105+ switch block.Kind {
106+ case BlockParagraph:
107+ fmt.Fprintln(r.w)
108+ r.writeIndented(renderInlinesTxt(block.Inlines), indent)
109+ case BlockTaggedList:
110+ for i, item := range block.Items {
111+ if i != 0 {
112+ fmt.Fprintln(r.w)
113+ }
114+ r.writeIndented(renderInlinesTxt(item.Label), indent)
115+ if len(item.Body) != 0 {
116+ fmt.Fprintln(r.w)
117+ r.writeIndented(renderInlinesTxt(item.Body), indent+8)
118+ }
119+ }
120+ case BlockSeeAlso:
121+ var refs []string
122+ for _, ref := range block.Refs {
123+ refs = append(refs, ref.Name+"("+ref.Section+")")
124+ }
125+ fmt.Fprintln(r.w)
126+ r.writeIndented(strings.Join(refs, ", "), indent)
127+ case BlockSubsection:
128+ fmt.Fprintln(r.w)
129+ r.writeIndented(block.Title, indent)
130+ for _, child := range block.Blocks {
131+ r.renderBlock(child, indent+txtSubIndent)
132+ }
133+ }
134+}
135+
136+// writeIndented word-wraps text to the page width minus indent, then
137+// writes each line prefixed by indent spaces
138+func (r *TxtRenderer) writeIndented(text string, indent int) {
139+ width := txtWidth - indent
140+ if width < 10 {
141+ width = 10
142+ }
143+ for _, line := range wrapWords(text, width) {
144+ fmt.Fprintln(r.w, strings.Repeat(" ", indent)+line)
145+ }
146+}
147+
148+func wrapWords(text string, width int) []string {
149+ text = strings.Join(strings.Fields(text), " ")
150+ if text == "" {
151+ return nil
152+ }
153+ if width < 1 {
154+ width = 1
155+ }
156+
157+ words := strings.Fields(text)
158+ lines := []string{words[0]}
159+ for _, word := range words[1:] {
160+ last := lines[len(lines)-1]
161+ if len(last)+1+len(word) <= width {
162+ lines[len(lines)-1] = last + " " + word
163+ } else {
164+ lines = append(lines, word)
165+ }
166+ }
167+ return lines
168+}
169+
170+// renderSynopsisItemsTxt mirrors renderSynopsisPhrase from mdoc.go but
171+// writes literal brackets and braces instead of mdoc macros
172+func renderSynopsisItemsTxt(items []SynopsisItem) string {
173+ var parts []string
174+ for _, item := range items {
175+ switch item.Kind {
176+ case SynFlag:
177+ parts = append(parts, "-"+strings.TrimPrefix(item.Text, "-"))
178+ case SynArg:
179+ parts = append(parts, strings.Trim(item.Text, "<>"))
180+ case SynCommand:
181+ parts = append(parts, item.Text)
182+ case SynPipe:
183+ parts = append(parts, "|")
184+ case SynLiteral:
185+ parts = append(parts, item.Text)
186+ case SynOptional:
187+ parts = append(parts, "["+renderSynopsisItemsTxt(item.Children)+"]")
188+ case SynRequiredGroup:
189+ parts = append(parts, "{"+renderSynopsisItemsTxt(item.Children)+"}")
190+ }
191+ }
192+ return strings.Join(parts, " ")
193+}
194+
195+func renderInlinesTxt(inlines []Inline) string {
196+ var b strings.Builder
197+ for _, inline := range inlines {
198+ b.WriteString(renderInlineTxt(inline))
199+ }
200+ return b.String()
201+}
202+
203+func renderInlineTxt(inline Inline) string {
204+ switch inline.Kind {
205+ case InlineText:
206+ return inline.Text
207+ case InlineNm:
208+ return inline.Text
209+ case InlineEmph:
210+ return "_" + renderInlinesTxt(inline.Children) + "_"
211+ case InlineLiteral:
212+ return "`" + inline.Text + "'"
213+ case InlinePath:
214+ return inline.Text
215+ case InlineXRef:
216+ return inline.Text + "(" + inline.Section + ")"
217+ case InlineFlag:
218+ return "-" + inline.Text
219+ default:
220+ return ""
221+ }
222+}
1@@ -0,0 +1,34 @@
2+/* See LICENSE file for copyright and license details. */
3+#ifndef ARUU_DISKUTIL_H
4+#define ARUU_DISKUTIL_H
5+
6+#include <stdint.h>
7+#include <stddef.h>
8+
9+struct BlockDev {
10+ int fd;
11+ uint64_t size; /* size in bytes */
12+ size_t sec_size; /* sector size */
13+};
14+
15+struct BlockDevInfo {
16+ char name[32];
17+ char type[16]; /* disk, part, loop */
18+ uint64_t size;
19+ int major;
20+ int minor;
21+ char mountpoint[256];
22+ char fstype[32];
23+ struct BlockDevInfo *parts;
24+ struct BlockDevInfo *next;
25+};
26+
27+int blockdev_open(struct BlockDev *dev, const char *path, int writable);
28+int blockdev_read(struct BlockDev *dev, uint64_t sector, void *buf, size_t sector_count);
29+int blockdev_write(struct BlockDev *dev, uint64_t sector, const void *buf, size_t sector_count);
30+void blockdev_close(struct BlockDev *dev);
31+
32+struct BlockDevInfo *blockdev_get_list(void);
33+void blockdev_free_list(struct BlockDevInfo *list);
34+
35+#endif
1@@ -0,0 +1,439 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "../diskutil.h"
4+#include "../util.h"
5+
6+#include <sys/types.h>
7+#include <sys/stat.h>
8+#include <fcntl.h>
9+#include <unistd.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <errno.h>
14+
15+#if defined(__linux__)
16+#include <sys/ioctl.h>
17+#include <linux/fs.h>
18+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Apple__)
19+#include <sys/ioctl.h>
20+#include <sys/disk.h>
21+#if defined(__OpenBSD__) || defined(__NetBSD__)
22+#include <sys/dkio.h>
23+#include <sys/disklabel.h>
24+#include <sys/sysctl.h>
25+#elif defined(__FreeBSD__)
26+#include <sys/disk.h>
27+#include <sys/sysctl.h>
28+#include <dirent.h>
29+#endif
30+#endif
31+
32+int
33+blockdev_open(struct BlockDev *dev, const char *path, int writable)
34+{
35+ struct stat st;
36+ int fd, flags;
37+
38+ flags = writable ? O_RDWR : O_RDONLY;
39+ fd = open(path, flags);
40+ if (fd < 0)
41+ return -1;
42+
43+ if (fstat(fd, &st) < 0) {
44+ close(fd);
45+ return -1;
46+ }
47+
48+ dev->fd = fd;
49+ dev->size = st.st_size;
50+ dev->sec_size = 512;
51+
52+ if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
53+#if defined(__linux__)
54+ uint64_t size_bytes = 0;
55+ int sec_size = 0;
56+ if (ioctl(fd, BLKGETSIZE64, &size_bytes) >= 0)
57+ dev->size = size_bytes;
58+ if (ioctl(fd, BLKSSZGET, &sec_size) >= 0)
59+ dev->sec_size = sec_size;
60+#elif defined(__FreeBSD__)
61+ off_t size_bytes = 0;
62+ unsigned int sec_size = 0;
63+ if (ioctl(fd, DIOCGMEDIASIZE, &size_bytes) >= 0)
64+ dev->size = size_bytes;
65+ if (ioctl(fd, DIOCGSECTORSIZE, &sec_size) >= 0)
66+ dev->sec_size = sec_size;
67+#elif defined(__OpenBSD__) || defined(__NetBSD__)
68+ struct disklabel dl;
69+ if (ioctl(fd, DIOCGDINFO, &dl) >= 0) {
70+ dev->size = (uint64_t)dl.d_secsize * DL_GETDSIZE(&dl);
71+ dev->sec_size = dl.d_secsize;
72+ }
73+#endif
74+ }
75+
76+ return 0;
77+}
78+
79+int
80+blockdev_read(struct BlockDev *dev, uint64_t sector, void *buf, size_t sector_count)
81+{
82+ off_t offset = (off_t)sector * dev->sec_size;
83+ size_t size = sector_count * dev->sec_size;
84+ ssize_t n;
85+
86+ if (lseek(dev->fd, offset, SEEK_SET) == (off_t)-1)
87+ return -1;
88+
89+ n = read(dev->fd, buf, size);
90+ if (n < 0 || (size_t)n != size)
91+ return -1;
92+
93+ return 0;
94+}
95+
96+int
97+blockdev_write(struct BlockDev *dev, uint64_t sector, const void *buf, size_t sector_count)
98+{
99+ off_t offset = (off_t)sector * dev->sec_size;
100+ size_t size = sector_count * dev->sec_size;
101+ ssize_t n;
102+
103+ if (lseek(dev->fd, offset, SEEK_SET) == (off_t)-1)
104+ return -1;
105+
106+ n = write(dev->fd, buf, size);
107+ if (n < 0 || (size_t)n != size)
108+ return -1;
109+
110+ return 0;
111+}
112+
113+void
114+blockdev_close(struct BlockDev *dev)
115+{
116+ if (dev->fd >= 0) {
117+ close(dev->fd);
118+ dev->fd = -1;
119+ }
120+}
121+
122+struct BlockDevInfo *
123+blockdev_get_list(void)
124+{
125+#if defined(__linux__)
126+ FILE *fp;
127+ char line[256];
128+ struct BlockDevInfo *head = NULL, *tail = NULL;
129+ unsigned int major, minor;
130+ unsigned long long blocks;
131+ char name[64];
132+
133+ fp = fopen("/proc/partitions", "r");
134+ if (!fp)
135+ return NULL;
136+
137+ while (fgets(line, sizeof(line), fp)) {
138+ if (sscanf(line, " %u %u %llu %63s", &major, &minor, &blocks, name) != 4)
139+ continue;
140+
141+ struct BlockDevInfo *info = calloc(1, sizeof(*info));
142+ if (!info)
143+ break;
144+
145+ strlcpy(info->name, name, sizeof(info->name));
146+ info->size = blocks * 1024;
147+ info->major = major;
148+ info->minor = minor;
149+
150+ /* check if this is a partition of an existing disk */
151+ struct BlockDevInfo *curr;
152+ int is_part = 0;
153+ for (curr = head; curr; curr = curr->next) {
154+ size_t len = strlen(curr->name);
155+ if (strncmp(name, curr->name, len) == 0) {
156+ char c = name[len];
157+ if ((c >= '0' && c <= '9') || (c == 'p' && name[len+1] >= '0' && name[len+1] <= '9')) {
158+ is_part = 1;
159+ strlcpy(info->type, "part", sizeof(info->type));
160+ struct BlockDevInfo *p = curr->parts;
161+ if (!p) {
162+ curr->parts = info;
163+ } else {
164+ while (p->next)
165+ p = p->next;
166+ p->next = info;
167+ }
168+ break;
169+ }
170+ }
171+ }
172+
173+ if (!is_part) {
174+ strlcpy(info->type, "disk", sizeof(info->type));
175+ if (!head) {
176+ head = info;
177+ } else {
178+ tail->next = info;
179+ }
180+ tail = info;
181+ }
182+ }
183+ fclose(fp);
184+
185+ /* parse mounts to populate mountpoint and fstype */
186+ FILE *mfile = fopen("/proc/mounts", "r");
187+ if (mfile) {
188+ char mline[512];
189+ char devpath[128], mnt[256], fs[64];
190+ while (fgets(mline, sizeof(mline), mfile)) {
191+ if (sscanf(mline, "%127s %255s %63s", devpath, mnt, fs) == 3) {
192+ char *devname = devpath;
193+ if (strncmp(devpath, "/dev/", 5) == 0)
194+ devname = devpath + 5;
195+ struct BlockDevInfo *curr;
196+ for (curr = head; curr; curr = curr->next) {
197+ if (strcmp(curr->name, devname) == 0) {
198+ strlcpy(curr->mountpoint, mnt, sizeof(curr->mountpoint));
199+ strlcpy(curr->fstype, fs, sizeof(curr->fstype));
200+ }
201+ struct BlockDevInfo *part;
202+ for (part = curr->parts; part; part = part->next) {
203+ if (strcmp(part->name, devname) == 0) {
204+ strlcpy(part->mountpoint, mnt, sizeof(part->mountpoint));
205+ strlcpy(part->fstype, fs, sizeof(part->fstype));
206+ }
207+ }
208+ }
209+ }
210+ }
211+ fclose(mfile);
212+ }
213+
214+ return head;
215+
216+#elif defined(__FreeBSD__)
217+ char disks[1024];
218+ size_t len = sizeof(disks);
219+ struct BlockDevInfo *head = NULL, *tail = NULL;
220+
221+ if (sysctlbyname("kern.disks", disks, &len, NULL, 0) < 0)
222+ return NULL;
223+
224+ char *tok, *ptr = disks;
225+ while ((tok = strsep(&ptr, " \t")) != NULL) {
226+ if (!*tok)
227+ continue;
228+
229+ struct BlockDevInfo *info = calloc(1, sizeof(*info));
230+ if (!info)
231+ break;
232+
233+ strlcpy(info->name, tok, sizeof(info->name));
234+ strlcpy(info->type, "disk", sizeof(info->type));
235+
236+ char devpath[64];
237+ snprintf(devpath, sizeof(devpath), "/dev/%s", tok);
238+ struct BlockDev dev;
239+ if (blockdev_open(&dev, devpath, 0) == 0) {
240+ info->size = dev.size;
241+ blockdev_close(&dev);
242+ }
243+
244+ DIR *dir = opendir("/dev");
245+ if (dir) {
246+ struct dirent *de;
247+ size_t disk_len = strlen(tok);
248+ while ((de = readdir(dir)) != NULL) {
249+ if (strncmp(de->d_name, tok, disk_len) == 0) {
250+ char c = de->d_name[disk_len];
251+ if (c == 's' || c == 'p') {
252+ struct BlockDevInfo *part = calloc(1, sizeof(*part));
253+ if (part) {
254+ strlcpy(part->name, de->d_name, sizeof(part->name));
255+ strlcpy(part->type, "part", sizeof(part->type));
256+ snprintf(devpath, sizeof(devpath), "/dev/%s", de->d_name);
257+ if (blockdev_open(&dev, devpath, 0) == 0) {
258+ part->size = dev.size;
259+ blockdev_close(&dev);
260+ }
261+ struct BlockDevInfo *p = info->parts;
262+ if (!p) {
263+ info->parts = part;
264+ } else {
265+ while (p->next)
266+ p = p->next;
267+ p->next = part;
268+ }
269+ }
270+ }
271+ }
272+ }
273+ closedir(dir);
274+ }
275+
276+ if (!head) {
277+ head = info;
278+ } else {
279+ tail->next = info;
280+ }
281+ tail = info;
282+ }
283+
284+ struct statfs *mntbuf;
285+ int mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
286+ for (int i = 0; i < mntsize; i++) {
287+ char *devpath = mntbuf[i].f_mntfromname;
288+ char *devname = devpath;
289+ if (strncmp(devpath, "/dev/", 5) == 0)
290+ devname = devpath + 5;
291+ struct BlockDevInfo *curr;
292+ for (curr = head; curr; curr = curr->next) {
293+ if (strcmp(curr->name, devname) == 0) {
294+ strlcpy(curr->mountpoint, mntbuf[i].f_mntonname, sizeof(curr->mountpoint));
295+ strlcpy(curr->fstype, mntbuf[i].f_fstypename, sizeof(curr->fstype));
296+ }
297+ struct BlockDevInfo *part;
298+ for (part = curr->parts; part; part = part->next) {
299+ if (strcmp(part->name, devname) == 0) {
300+ strlcpy(part->mountpoint, mntbuf[i].f_mntonname, sizeof(part->mountpoint));
301+ strlcpy(part->fstype, mntbuf[i].f_fstypename, sizeof(part->fstype));
302+ }
303+ }
304+ }
305+ }
306+
307+ return head;
308+
309+#elif defined(__OpenBSD__)
310+ char disknames[1024];
311+ size_t len = sizeof(disknames);
312+ int mib[2] = { CTL_HW, HW_DISKNAMES };
313+ struct BlockDevInfo *head = NULL, *tail = NULL;
314+
315+ if (sysctl(mib, 2, disknames, &len, NULL, 0) < 0)
316+ return NULL;
317+
318+ char *tok, *ptr = disknames;
319+ while ((tok = strsep(&ptr, ",")) != NULL) {
320+ char *colon = strchr(tok, ':');
321+ if (colon)
322+ *colon = '\0';
323+ if (!*tok)
324+ continue;
325+
326+ struct BlockDevInfo *info = calloc(1, sizeof(*info));
327+ if (!info)
328+ break;
329+
330+ strlcpy(info->name, tok, sizeof(info->name));
331+ strlcpy(info->type, "disk", sizeof(info->type));
332+
333+ char devpath[64];
334+ snprintf(devpath, sizeof(devpath), "/dev/r%sc", tok);
335+ struct BlockDev dev;
336+ if (blockdev_open(&dev, devpath, 0) == 0) {
337+ info->size = dev.size;
338+ blockdev_close(&dev);
339+ }
340+
341+ for (char c = 'a'; c <= 'p'; c++) {
342+ if (c == 'c')
343+ continue;
344+ snprintf(devpath, sizeof(devpath), "/dev/r%s%c", tok, c);
345+ if (blockdev_open(&dev, devpath, 0) == 0) {
346+ struct BlockDevInfo *part = calloc(1, sizeof(*part));
347+ if (part) {
348+ snprintf(part->name, sizeof(part->name), "%s%c", tok, c);
349+ strlcpy(part->type, "part", sizeof(part->type));
350+ part->size = dev.size;
351+ struct BlockDevInfo *p = info->parts;
352+ if (!p) {
353+ info->parts = part;
354+ } else {
355+ while (p->next)
356+ p = p->next;
357+ p->next = part;
358+ }
359+ }
360+ blockdev_close(&dev);
361+ }
362+ }
363+
364+ if (!head) {
365+ head = info;
366+ } else {
367+ tail->next = info;
368+ }
369+ tail = info;
370+ }
371+
372+ struct statfs *mntbuf;
373+ int mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
374+ for (int i = 0; i < mntsize; i++) {
375+ char *devpath = mntbuf[i].f_mntfromname;
376+ char *devname = devpath;
377+ if (strncmp(devpath, "/dev/", 5) == 0)
378+ devname = devpath + 5;
379+ struct BlockDevInfo *curr;
380+ for (curr = head; curr; curr = curr->next) {
381+ if (strcmp(curr->name, devname) == 0) {
382+ strlcpy(curr->mountpoint, mntbuf[i].f_mntonname, sizeof(curr->mountpoint));
383+ strlcpy(curr->fstype, mntbuf[i].f_fstypename, sizeof(curr->fstype));
384+ }
385+ struct BlockDevInfo *part;
386+ for (part = curr->parts; part; part = part->next) {
387+ if (strcmp(part->name, devname) == 0) {
388+ strlcpy(part->mountpoint, mntbuf[i].f_mntonname, sizeof(part->mountpoint));
389+ strlcpy(part->fstype, mntbuf[i].f_fstypename, sizeof(part->fstype));
390+ }
391+ }
392+ }
393+ }
394+
395+ return head;
396+
397+#else
398+ struct BlockDevInfo *head = NULL, *tail = NULL;
399+ char devname[16];
400+ for (char c = 'a'; c <= 'z'; c++) {
401+ snprintf(devname, sizeof(devname), "sd%c", c);
402+ char devpath[32];
403+ snprintf(devpath, sizeof(devpath), "/dev/%s", devname);
404+ struct BlockDev dev;
405+ if (blockdev_open(&dev, devpath, 0) == 0) {
406+ struct BlockDevInfo *info = calloc(1, sizeof(*info));
407+ if (info) {
408+ strlcpy(info->name, devname, sizeof(info->name));
409+ strlcpy(info->type, "disk", sizeof(info->type));
410+ info->size = dev.size;
411+ if (!head) {
412+ head = info;
413+ } else {
414+ tail->next = info;
415+ }
416+ tail = info;
417+ }
418+ blockdev_close(&dev);
419+ }
420+ }
421+ return head;
422+#endif
423+}
424+
425+void
426+blockdev_free_list(struct BlockDevInfo *list)
427+{
428+ struct BlockDevInfo *curr = list;
429+ while (curr) {
430+ struct BlockDevInfo *next = curr->next;
431+ struct BlockDevInfo *part = curr->parts;
432+ while (part) {
433+ struct BlockDevInfo *next_part = part->next;
434+ free(part);
435+ part = next_part;
436+ }
437+ free(curr);
438+ curr = next;
439+ }
440+}