commit d85bb07
Antonio
·
2026-06-08 08:55:17 +0000 UTC
parent d85bb07
First commit Signed-off-by: Antonio <anto@shackles.my.domain>
+77,
-0
1@@ -0,0 +1,77 @@
2+Language: Cpp
3+BasedOnStyle: LLVM
4+AlignAfterOpenBracket: Align
5+AlignConsecutiveMacros: false
6+AlignConsecutiveAssignments: false
7+AlignConsecutiveDeclarations: false
8+AlignEscapedNewlines: Right
9+AlignOperands: Align
10+AlignTrailingComments: true
11+AllowAllArgumentsOnNextLine: true
12+AllowAllParametersOfDeclarationOnNextLine: true
13+AllowShortBlocksOnASingleLine: false
14+AllowShortCaseLabelsOnASingleLine: false
15+AllowShortFunctionsOnASingleLine: false
16+AllowShortIfStatementsOnASingleLine: false
17+AllowShortLoopsOnASingleLine: false
18+AlwaysBreakAfterDefinitionReturnType: TopLevel
19+AlwaysBreakAfterReturnType: TopLevelDefinitions
20+AlwaysBreakBeforeMultilineStrings: false
21+BinPackArguments: true
22+BinPackParameters: true
23+BraceWrapping:
24+ AfterCaseLabel: false
25+ AfterClass: false
26+ AfterControlStatement: Never
27+ AfterEnum: false
28+ AfterFunction: true
29+ AfterNamespace: false
30+ AfterObjCDeclaration: false
31+ AfterStruct: false
32+ AfterUnion: false
33+ AfterExternBlock: false
34+ BeforeCatch: false
35+ BeforeElse: false
36+ IndentBraces: false
37+ SplitEmptyFunction: true
38+ SplitEmptyRecord: true
39+ SplitEmptyNamespace: true
40+BreakBeforeBinaryOperators: None
41+BreakBeforeBraces: Custom
42+BreakBeforeTernaryOperators: true
43+BreakStringLiterals: true
44+ColumnLimit: 80
45+ContinuationIndentWidth: 8
46+DerivePointerAlignment: false
47+DisableFormat: false
48+FixNamespaceComments: true
49+IncludeBlocks: Preserve
50+IncludeCategories:
51+ - Regex: '^".*"'
52+ Priority: 1
53+ - Regex: '^<.*>'
54+ Priority: 2
55+IndentCaseLabels: false
56+IndentPPDirectives: None
57+IndentWidth: 8
58+IndentWrappedFunctionNames: false
59+KeepEmptyLinesAtTheStartOfBlocks: false
60+MaxEmptyLinesToKeep: 1
61+NamespaceIndentation: None
62+PointerAlignment: Right
63+ReflowComments: true
64+SortIncludes: true
65+SortUsingDeclarations: true
66+SpaceAfterCStyleCast: false
67+SpaceBeforeAssignmentOperators: true
68+SpaceBeforeParens: ControlStatements
69+SpaceInEmptyParentheses: false
70+SpacesBeforeTrailingComments: 1
71+SpacesInAngles: false
72+SpacesInContainerLiterals: false
73+SpacesInCStyleCastParentheses: false
74+SpacesInParentheses: false
75+SpacesInSquareBrackets: false
76+Standard: c++03
77+TabWidth: 8
78+UseTab: Always
A
LICENSE
+68,
-0
1@@ -0,0 +1,68 @@
2+Copyright (C) 2006, 2019 Rob Landley [rob@landley.net](mailto:rob@landley.net)
3+Copyright (c) 2011 Connor Lane Smith [cls@lubutu.com](mailto:cls@lubutu.com)
4+Copyright (c) 2011-2016 Dimitris Papastamos [sin@2f30.org](mailto:sin@2f30.org)
5+Copyright (c) 2011 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
6+Copyright (c) 2011 Kamil CholewiĆski [harry666t@gmail.com](mailto:harry666t@gmail.com)
7+Copyright (c) 2011 pancake [pancake@youterm.com](mailto:pancake@youterm.com)
8+Copyright (c) 2011 Random832 [random832@fastmail.us](mailto:random832@fastmail.us)
9+Copyright (c) 2011 Rob Pilling [robpilling@gmail.com](mailto:robpilling@gmail.com)
10+Copyright (c) 2012 Christoph Lohmann [20h@r-36.net](mailto:20h@r-36.net)
11+Copyright (c) 2012 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
12+Copyright (c) 2012 Kurt H. Maier [khm@sciops.net](mailto:khm@sciops.net)
13+Copyright (c) 2012 Robert Ransom [rransom.8774@gmail.com](mailto:rransom.8774@gmail.com)
14+Copyright (c) 2012 William Haddon [william@haddonthethird.net](mailto:william@haddonthethird.net)
15+Copyright (c) 2013 Anselm R Garbe [anselm@garbe.us](mailto:anselm@garbe.us)
16+Copyright (c) 2013 Christian Hesse [mail@eworm.de](mailto:mail@eworm.de)
17+Copyright (c) 2013 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
18+Copyright (c) 2013-2016 Dimitris Papapastamos [sin@2f30.org](mailto:sin@2f30.org)
19+Copyright (c) 2013 dsp [dsp@2f30.org](mailto:dsp@2f30.org)
20+Copyright (c) 2013 Federico G. Benavento [benavento@gmail.com](mailto:benavento@gmail.com)
21+Copyright (c) 2013 Jakob Kramer [jakob.kramer@gmx.de](mailto:jakob.kramer@gmx.de)
22+Copyright (c) 2013 Jesse Ogle [jesse.p.ogle@gmail.com](mailto:jesse.p.ogle@gmail.com)
23+Copyright (c) 2013 Lorenzo Cogotti [miciamail@hotmail.it](mailto:miciamail@hotmail.it)
24+Copyright (c) 2013 Markus Teich [markus.teich@stusta.mhn.de](mailto:markus.teich@stusta.mhn.de)
25+Copyright (c) 2013 Markus Wichmann [nullplan@gmx.net](mailto:nullplan@gmx.net)
26+Copyright (c) 2013 oblique [psyberbits@gmail.com](mailto:psyberbits@gmail.com)
27+Copyright (c) 2013 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
28+Copyright (c) 2013 s-p-k [mr.dwts@gmail.com](mailto:mr.dwts@gmail.com)
29+Copyright (c) 2013 Truls Becken [truls.becken@gmail.com](mailto:truls.becken@gmail.com)
30+Copyright (c) 2014 Adria Garriga [rhaps0dy@installgentoo.com](mailto:rhaps0dy@installgentoo.com)
31+Copyright (c) 2014 Ari Malinen [ari.malinen@gmail.com](mailto:ari.malinen@gmail.com)
32+Copyright (c) 2014 Brandon Mulcahy [brandon@jangler.info](mailto:brandon@jangler.info)
33+Copyright (c) 2014 Carlos J. Torres [vlaadbrain@gmail.com](mailto:vlaadbrain@gmail.com)
34+Copyright (c) 2014 Daniel Bainton [dpb@driftaway.org](mailto:dpb@driftaway.org)
35+Copyright (c) 2014 Evan Gates [evan.gates@gmail.com](mailto:evan.gates@gmail.com)
36+Copyright (c) 2014-2015 Greg Reagle [greg.reagle@umbc.edu](mailto:greg.reagle@umbc.edu)
37+Copyright (c) 2014-2016 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
38+Copyright (c) 2014 Jan Tatje [jan@jnt.io](mailto:jan@jnt.io)
39+Copyright (c) 2014 Jeffrey Picard [jeff@jeffreypicard.com](mailto:jeff@jeffreypicard.com)
40+Copyright (c) 2014-2016 Laslo Hunhold [dev@frign.de](mailto:dev@frign.de)
41+Copyright (c) 2014 Michael Forney [mforney@mforney.org](mailto:mforney@mforney.org)
42+Copyright (c) 2014 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
43+Copyright (c) 2014 Silvan Jegen [s.jegen@gmail.com](mailto:s.jegen@gmail.com)
44+Copyright (c) 2014 Tuukka Kataja [stuge@xor.fi](mailto:stuge@xor.fi)
45+Copyright (c) 2015 Dionysis Grigoropoulos [info@erethon.com](mailto:info@erethon.com)
46+Copyright (c) 2015 Quentin Rameau [quinq@fifth.space](mailto:quinq@fifth.space)
47+Copyright (c) 2015 Risto Salminen [ripejcp@gmail.com](mailto:ripejcp@gmail.com)
48+Copyright (c) 2015 Tai Chi Minh Ralph Eastwood [tcmreastwood@gmail.com](mailto:tcmreastwood@gmail.com)
49+Copyright (c) 2015 Wolfgang Corcoran-Mathe [wcm@sigwinch.xyz](mailto:wcm@sigwinch.xyz)
50+Copyright (c) 2016 Eivind Uggedal [eivind@uggedal.com](mailto:eivind@uggedal.com)
51+Copyright (c) 2016 Mattias Andrée [m@maandree.se](mailto:m@maandree.se)
52+Copyright (c) 2026 xplshn [anto@xplshn.com.ar](mailto:anto@xplshn.com.ar) (https://github.com/xplshn)
53+
54+Permission to use, copy, modify, and/or distribute this software for any
55+purpose with or without fee is hereby granted, provided that the above
56+copyright notice and this permission notice appear in all copies.
57+
58+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
59+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
61+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
64+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65+SOFTWARE.
66+
67+Portions of this software (specifically utils under net/) are partially
68+based on code written by Rob Landley
69+The rest are based on SBASE/UBASE source code
A
Makefile
+321,
-0
1@@ -0,0 +1,321 @@
2+.POSIX:
3+include config.mk
4+
5+.SUFFIXES:
6+.SUFFIXES: .y .o .c
7+
8+HDR =\
9+ shared/arg.h\
10+ shared/compat.h\
11+ shared/config.h\
12+ shared/crypt.h\
13+ shared/fs.h\
14+ shared/md5.h\
15+ shared/queue.h\
16+ shared/sha1.h\
17+ shared/sha224.h\
18+ shared/sha256.h\
19+ shared/sha384.h\
20+ shared/sha512.h\
21+ shared/sha512-224.h\
22+ shared/sha512-256.h\
23+ shared/text.h\
24+ shared/utf.h\
25+ shared/util.h\
26+ shared/passwd.h\
27+ shared/reboot.h\
28+ shared/rtc.h\
29+ shared/proc.h
30+
31+LIBUTFOBJ =\
32+ shared/libutf/fgetrune.o\
33+ shared/libutf/fputrune.o\
34+ shared/libutf/isalnumrune.o\
35+ shared/libutf/isalpharune.o\
36+ shared/libutf/isblankrune.o\
37+ shared/libutf/iscntrlrune.o\
38+ shared/libutf/isdigitrune.o\
39+ shared/libutf/isgraphrune.o\
40+ shared/libutf/isprintrune.o\
41+ shared/libutf/ispunctrune.o\
42+ shared/libutf/isspacerune.o\
43+ shared/libutf/istitlerune.o\
44+ shared/libutf/isxdigitrune.o\
45+ shared/libutf/lowerrune.o\
46+ shared/libutf/rune.o\
47+ shared/libutf/runetype.o\
48+ shared/libutf/upperrune.o\
49+ shared/libutf/utf.o\
50+ shared/libutf/utftorunestr.o
51+
52+LIBUTILOBJ =\
53+ shared/libutil/concat.o\
54+ shared/libutil/cp.o\
55+ shared/libutil/crypt.o\
56+ shared/libutil/confirm.o\
57+ shared/libutil/ealloc.o\
58+ shared/libutil/enmasse.o\
59+ shared/libutil/eprintf.o\
60+ shared/libutil/eregcomp.o\
61+ shared/libutil/estrtod.o\
62+ shared/libutil/fnck.o\
63+ shared/libutil/fshut.o\
64+ shared/libutil/getlines.o\
65+ shared/libutil/human.o\
66+ shared/libutil/linecmp.o\
67+ shared/libutil/md5.o\
68+ shared/libutil/memmem.o\
69+ shared/libutil/mkdirp.o\
70+ shared/libutil/mode.o\
71+ shared/libutil/parseoffset.o\
72+ shared/libutil/putword.o\
73+ shared/libutil/reallocarray.o\
74+ shared/libutil/recurse.o\
75+ shared/libutil/rm.o\
76+ shared/libutil/sha1.o\
77+ shared/libutil/sha224.o\
78+ shared/libutil/sha256.o\
79+ shared/libutil/sha384.o\
80+ shared/libutil/sha512.o\
81+ shared/libutil/sha512-224.o\
82+ shared/libutil/sha512-256.o\
83+ shared/libutil/strcasestr.o\
84+ shared/libutil/strlcat.o\
85+ shared/libutil/strlcpy.o\
86+ shared/libutil/strsep.o\
87+ shared/libutil/strnsubst.o\
88+ shared/libutil/strtonum.o\
89+ shared/libutil/writeall.o\
90+ shared/libutil/unescape.o\
91+ shared/libutil/agetcwd.o\
92+ shared/libutil/agetline.o\
93+ shared/libutil/apathmax.o\
94+ shared/libutil/estrtol.o\
95+ shared/libutil/estrtoul.o\
96+ shared/libutil/explicit_bzero.o\
97+ shared/libutil/passwd.o\
98+ shared/libutil/proc.o\
99+ shared/libutil/tty.o\
100+ shared/libutil/fconcat.o\
101+ shared/libutil/recurse_dir.o
102+
103+LIB = shared/libutf/libutf.a shared/libutil/libutil.a
104+
105+POSIX_BIN =\
106+ cmd/posix/basename\
107+ cmd/posix/cal\
108+ cmd/posix/cat\
109+ cmd/posix/chgrp\
110+ cmd/posix/chmod\
111+ cmd/posix/chown\
112+ cmd/posix/cksum\
113+ cmd/posix/cmp\
114+ cmd/posix/comm\
115+ cmd/posix/cp\
116+ cmd/posix/cut\
117+ cmd/posix/date\
118+ cmd/posix/dd\
119+ cmd/posix/df\
120+ cmd/posix/dirname\
121+ cmd/posix/du\
122+ cmd/posix/echo\
123+ cmd/posix/ed\
124+ cmd/posix/env\
125+ cmd/posix/expand\
126+ cmd/posix/expr\
127+ cmd/posix/false\
128+ cmd/posix/find\
129+ cmd/posix/fold\
130+ cmd/posix/getconf\
131+ cmd/posix/grep\
132+ cmd/posix/head\
133+ cmd/posix/id\
134+ cmd/posix/join\
135+ cmd/posix/kill\
136+ cmd/posix/link\
137+ cmd/posix/ln\
138+ cmd/posix/logger\
139+ cmd/posix/logname\
140+ cmd/posix/ls\
141+ cmd/posix/mesg\
142+ cmd/posix/mkdir\
143+ cmd/posix/mkfifo\
144+ cmd/posix/mv\
145+ cmd/posix/nice\
146+ cmd/posix/nl\
147+ cmd/posix/nohup\
148+ cmd/posix/od\
149+ cmd/posix/paste\
150+ cmd/posix/pathchk\
151+ cmd/posix/printf\
152+ cmd/posix/ps\
153+ cmd/posix/pwd\
154+ cmd/posix/readlink\
155+ cmd/posix/renice\
156+ cmd/posix/rm\
157+ cmd/posix/rmdir\
158+ cmd/posix/sed\
159+ cmd/posix/sleep\
160+ cmd/posix/sort\
161+ cmd/posix/split\
162+ cmd/posix/tail\
163+ cmd/posix/tee\
164+ cmd/posix/test\
165+ cmd/posix/time\
166+ cmd/posix/touch\
167+ cmd/posix/tr\
168+ cmd/posix/true\
169+ cmd/posix/tsort\
170+ cmd/posix/tty\
171+ cmd/posix/uname\
172+ cmd/posix/unexpand\
173+ cmd/posix/uniq\
174+ cmd/posix/unlink\
175+ cmd/posix/uudecode\
176+ cmd/posix/uuencode\
177+ cmd/posix/wc\
178+ cmd/posix/who\
179+ cmd/posix/xargs
180+
181+LINUX_BIN =\
182+ cmd/linux/blkdiscard\
183+ cmd/linux/chvt\
184+ cmd/linux/ctrlaltdel\
185+ cmd/linux/dmesg\
186+ cmd/linux/eject\
187+ cmd/linux/fallocate\
188+ cmd/linux/free\
189+ cmd/linux/freeramdisk\
190+ cmd/linux/fsfreeze\
191+ cmd/linux/hwclock\
192+ cmd/linux/insmod\
193+ cmd/linux/lsmod\
194+ cmd/linux/mkswap\
195+ cmd/linux/mount\
196+ cmd/linux/mountpoint\
197+ cmd/linux/pidof\
198+ cmd/linux/pivot_root\
199+ cmd/linux/pwdx\
200+ cmd/linux/readahead\
201+ cmd/linux/rmmod\
202+ cmd/linux/swaplabel\
203+ cmd/linux/swapoff\
204+ cmd/linux/swapon\
205+ cmd/linux/switch_root\
206+ cmd/linux/umount\
207+ cmd/linux/unshare\
208+ cmd/linux/uptime\
209+ cmd/linux/vtallow
210+
211+NET_BIN =\
212+ cmd/net/netcat\
213+ cmd/net/tftp\
214+ cmd/net/tunctl\
215+ cmd/net/wget\
216+ cmd/net/ping\
217+ cmd/net/ifconfig\
218+ cmd/net/host\
219+ cmd/net/httpd
220+
221+XSI_BIN =\
222+ cmd/xsi/mknod\
223+ cmd/xsi/passwd\
224+ cmd/xsi/su
225+
226+PSEUDO_BIN =\
227+ cmd/pseudo/chroot\
228+ cmd/pseudo/clear\
229+ cmd/pseudo/cols\
230+ cmd/pseudo/cron\
231+ cmd/pseudo/flock\
232+ cmd/pseudo/getty\
233+ cmd/pseudo/halt\
234+ cmd/pseudo/hostname\
235+ cmd/pseudo/killall5\
236+ cmd/pseudo/last\
237+ cmd/pseudo/lastlog\
238+ cmd/pseudo/login\
239+ cmd/pseudo/md5sum\
240+ cmd/pseudo/mktemp\
241+ cmd/pseudo/nologin\
242+ cmd/pseudo/pagesize\
243+ cmd/pseudo/printenv\
244+ cmd/pseudo/respawn\
245+ cmd/pseudo/rev\
246+ cmd/pseudo/seq\
247+ cmd/pseudo/setsid\
248+ cmd/pseudo/sha1sum\
249+ cmd/pseudo/sha224sum\
250+ cmd/pseudo/sha256sum\
251+ cmd/pseudo/sha384sum\
252+ cmd/pseudo/sha512sum\
253+ cmd/pseudo/sha512-224sum\
254+ cmd/pseudo/sha512-256sum\
255+ cmd/pseudo/sponge\
256+ cmd/pseudo/stat\
257+ cmd/pseudo/tar\
258+ cmd/pseudo/truncate\
259+ cmd/pseudo/watch\
260+ cmd/pseudo/which\
261+ cmd/pseudo/whoami\
262+ cmd/pseudo/xinstall\
263+ cmd/pseudo/yes
264+
265+MAKEOBJ =\
266+ cmd/posix/make/defaults.o\
267+ cmd/posix/make/main.o\
268+ cmd/posix/make/parser.o\
269+ cmd/posix/make/posix.o\
270+ cmd/posix/make/rules.o
271+
272+OBJ = $(LIBUTFOBJ) $(LIBUTILOBJ) $(MAKEOBJ)
273+
274+all: $(LIB) $(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN) cmd/posix/make/make
275+
276+$(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN): $(LIB)
277+
278+$(OBJ) $(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN): $(HDR)
279+
280+.o:
281+ $(CC) $(LDFLAGS) -o $@ $< $(LIB) $(LDLIBS)
282+
283+.c.o:
284+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
285+
286+.c:
287+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIB) $(LDLIBS)
288+
289+cmd/posix/bc.c: cmd/posix/bc.y
290+ $(YACC) -d -o $@ $<
291+
292+cmd/posix/bc: cmd/posix/bc.c
293+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ cmd/posix/bc.c $(LIB) $(LDLIBS)
294+
295+$(MAKEOBJ): cmd/posix/make/make.h
296+
297+cmd/posix/make/make: $(MAKEOBJ) $(LIB)
298+ $(CC) $(LDFLAGS) -o $@ $(MAKEOBJ) $(LIB) $(LDLIBS)
299+
300+shared/libutf/libutf.a: $(LIBUTFOBJ)
301+ $(AR) $(ARFLAGS) $@ $?
302+ $(RANLIB) $@
303+
304+shared/libutil/libutil.a: $(LIBUTILOBJ)
305+ $(AR) $(ARFLAGS) $@ $?
306+ $(RANLIB) $@
307+
308+cmd/posix/getconf: cmd/posix/getconf.h
309+
310+cmd/posix/getconf.h:
311+ scripts/getconf.sh > $@ || { rm -f $@; exit 1; }
312+
313+box: $(LIB)
314+ CC='$(CC)' CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' \
315+ LDFLAGS='$(LDFLAGS)' LDLIBS='$(LDLIBS)' OBJCOPY='$(OBJCOPY)' \
316+ scripts/mkbox
317+
318+clean:
319+ rm -f shared/libutf/*.o shared/libutil/*.o cmd/posix/make/*.o
320+ rm -f $(POSIX_BIN) $(LINUX_BIN) $(NET_BIN) $(XSI_BIN) $(PSEUDO_BIN) $(LIB)
321+ rm -f cmd/posix/make/make cmd/posix/getconf.h cmd/posix/bc.c
322+ rm -rf aruu-box .box
A
README
+181,
-0
1@@ -0,0 +1,181 @@
2+Argentino Roca Unix Utilities
3+=============================
4+
5+ARUU is a unified fork of sbase and ubase, it is an effort trying to
6+complete SBASE & UBASE., new utils partially based on toybox have
7+been added, specifically, the utils under cmd/net are partially based
8+on their toybox applet equivalent.
9+
10+OVERVIEW
11+========
12+
13+aruu builds two things:
14+
15+ 1. individual tool binaries (default 'make all')
16+ 2. aruu-box: a multi-call binary containing every tool ('make box')
17+
18+The multi-call binary is built by scripts/mkbox. It uses objcopy to
19+rename each tool's 'main' symbol, generates a C dispatch table, then
20+links everything into a single statically-dispatched binary. Invoke
21+tools by symlinking aruu-box to the tool name, or by running:
22+
23+ aruu-box <command> [args...]
24+
25+To install symlinks into a directory:
26+
27+ aruu-box -i /usr/local/bin
28+
29+REQUIREMENTS
30+============
31+
32+ cc POSIX.1-2008-compliant C compiler (pcc, etc)
33+ make POSIX make (pdpmake, gmake, bmake)
34+ ar archive tool
35+ ranlib archive indexer
36+ objcopy for 'make box' only
37+
38+Optional:
39+
40+ yacc only needed if rebuilding bc from bc.y
41+
42+BUILDING
43+========
44+
45+Build all individual tools:
46+
47+ make
48+
49+Build the multi-call binary:
50+
51+ make box
52+
53+Both targets can be combined:
54+
55+ make all box
56+
57+Configuration is in config.mk. Override compiler and flags:
58+
59+ make CC=musl-gcc CFLAGS='-Os -static'
60+
61+Override install prefix:
62+
63+ make PREFIX=/usr install
64+
65+INSTALL
66+=======
67+
68+ make install installs individual tools to $(PREFIX)/bin
69+ aruu-box -i /usr/bin installs symlinks for the box binary
70+
71+SOURCE LAYOUT
72+=============
73+
74+ config.mk build configuration
75+ Makefile pdpmake-compatible build rules
76+ scripts/
77+ mkbox builds aruu-box from compiled tool objects
78+ getconf.sh generates cmd/posix/getconf.h at build time
79+ shared/
80+ *.h project headers (util.h, arg.h, utf.h, ...)
81+ libutil/ utility library (eprintf, ealloc, recurse, ...)
82+ libutf/ UTF-8/rune library
83+ cmd/
84+ posix/ POSIX.1-2008 tools (cat, ls, grep, sed, ...)
85+ posix/make/ POSIX make implementation
86+ linux/ Linux-specific tools (mount, dmesg, insmod, ...)
87+ net/ networking tools (wget, ping, nc, ifconfig, ...)
88+ pseudo/ widely-used non-POSIX tools (tar, stat, seq, ...)
89+ xsi/ XSI-extension tools (mknod, su, passwd)
90+
91+TOOLS
92+=====
93+
94+posix: [, basename, cal, cat, chgrp, chmod, chown, cksum, cmp, comm,
95+ cp, cut, date, dd, df, dirname, du, echo, ed, env, expand,
96+ expr, false, find, fold, getconf, grep, head, id, join, kill,
97+ link, ln, logger, logname, ls, mesg, mkdir, mkfifo, mv, nice,
98+ nl, nohup, od, paste, pathchk, printf, ps, pwd, readlink,
99+ renice, rm, rmdir, sed, sleep, sort, split, tail, tee, test,
100+ time, touch, tr, true, tsort, tty, uname, unexpand, uniq,
101+ unlink, uudecode, uuencode, wc, who, xargs
102+
103+posix/make: make
104+
105+linux: blkdiscard, chvt, ctrlaltdel, dmesg, eject, fallocate, free,
106+ freeramdisk, fsfreeze, hwclock, insmod, lsmod, lsusb, mkswap,
107+ mount, mountpoint, pidof, pivot_root, pwdx, readahead, rmmod,
108+ swaplabel, swapoff, swapon, switch_root, sysctl, umount,
109+ unshare, uptime, vtallow
110+
111+net: host, httpd, ifconfig, netcat, ping, tftp, tunctl, wget
112+
113+pseudo: chroot, clear, cols, cron, flock, getty, halt, hostname,
114+ install, killall5, last, lastlog, login, md5sum, mktemp,
115+ nologin, pagesize, printenv, respawn, rev, seq, setsid,
116+ sha1sum, sha224sum, sha256sum, sha384sum, sha512sum,
117+ sha512-224sum, sha512-256sum, sponge, stat, tar, truncate,
118+ watch, which, whoami, yes
119+
120+xsi: mknod, passwd, su
121+
122+LICENSE
123+=======
124+
125+ISC, see ./LICENSE for details. Credits:
126+Copyright (C) 2006, 2019 Rob Landley [rob@landley.net](mailto:rob@landley.net)
127+Copyright (c) 2011 Connor Lane Smith [cls@lubutu.com](mailto:cls@lubutu.com)
128+Copyright (c) 2011-2016 Dimitris Papastamos [sin@2f30.org](mailto:sin@2f30.org)
129+Copyright (c) 2011 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
130+Copyright (c) 2011 Kamil CholewiĆski [harry666t@gmail.com](mailto:harry666t@gmail.com)
131+Copyright (c) 2011 pancake [pancake@youterm.com](mailto:pancake@youterm.com)
132+Copyright (c) 2011 Random832 [random832@fastmail.us](mailto:random832@fastmail.us)
133+Copyright (c) 2011 Rob Pilling [robpilling@gmail.com](mailto:robpilling@gmail.com)
134+Copyright (c) 2012 Christoph Lohmann [20h@r-36.net](mailto:20h@r-36.net)
135+Copyright (c) 2012 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
136+Copyright (c) 2012 Kurt H. Maier [khm@sciops.net](mailto:khm@sciops.net)
137+Copyright (c) 2012 Robert Ransom [rransom.8774@gmail.com](mailto:rransom.8774@gmail.com)
138+Copyright (c) 2012 William Haddon [william@haddonthethird.net](mailto:william@haddonthethird.net)
139+Copyright (c) 2013 Anselm R Garbe [anselm@garbe.us](mailto:anselm@garbe.us)
140+Copyright (c) 2013 Christian Hesse [mail@eworm.de](mailto:mail@eworm.de)
141+Copyright (c) 2013 David Galos [galosd83@students.rowan.edu](mailto:galosd83@students.rowan.edu)
142+Copyright (c) 2013-2016 Dimitris Papapastamos [sin@2f30.org](mailto:sin@2f30.org)
143+Copyright (c) 2013 dsp [dsp@2f30.org](mailto:dsp@2f30.org)
144+Copyright (c) 2013 Federico G. Benavento [benavento@gmail.com](mailto:benavento@gmail.com)
145+Copyright (c) 2013 Jakob Kramer [jakob.kramer@gmx.de](mailto:jakob.kramer@gmx.de)
146+Copyright (c) 2013 Jesse Ogle [jesse.p.ogle@gmail.com](mailto:jesse.p.ogle@gmail.com)
147+Copyright (c) 2013 Lorenzo Cogotti [miciamail@hotmail.it](mailto:miciamail@hotmail.it)
148+Copyright (c) 2013 Markus Teich [markus.teich@stusta.mhn.de](mailto:markus.teich@stusta.mhn.de)
149+Copyright (c) 2013 Markus Wichmann [nullplan@gmx.net](mailto:nullplan@gmx.net)
150+Copyright (c) 2013 oblique [psyberbits@gmail.com](mailto:psyberbits@gmail.com)
151+Copyright (c) 2013 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
152+Copyright (c) 2013 s-p-k [mr.dwts@gmail.com](mailto:mr.dwts@gmail.com)
153+Copyright (c) 2013 Truls Becken [truls.becken@gmail.com](mailto:truls.becken@gmail.com)
154+Copyright (c) 2014 Adria Garriga [rhaps0dy@installgentoo.com](mailto:rhaps0dy@installgentoo.com)
155+Copyright (c) 2014 Ari Malinen [ari.malinen@gmail.com](mailto:ari.malinen@gmail.com)
156+Copyright (c) 2014 Brandon Mulcahy [brandon@jangler.info](mailto:brandon@jangler.info)
157+Copyright (c) 2014 Carlos J. Torres [vlaadbrain@gmail.com](mailto:vlaadbrain@gmail.com)
158+Copyright (c) 2014 Daniel Bainton [dpb@driftaway.org](mailto:dpb@driftaway.org)
159+Copyright (c) 2014 Evan Gates [evan.gates@gmail.com](mailto:evan.gates@gmail.com)
160+Copyright (c) 2014-2015 Greg Reagle [greg.reagle@umbc.edu](mailto:greg.reagle@umbc.edu)
161+Copyright (c) 2014-2016 Hiltjo Posthuma [hiltjo@codemadness.org](mailto:hiltjo@codemadness.org)
162+Copyright (c) 2014 Jan Tatje [jan@jnt.io](mailto:jan@jnt.io)
163+Copyright (c) 2014 Jeffrey Picard [jeff@jeffreypicard.com](mailto:jeff@jeffreypicard.com)
164+Copyright (c) 2014-2016 Laslo Hunhold [dev@frign.de](mailto:dev@frign.de)
165+Copyright (c) 2014 Michael Forney [mforney@mforney.org](mailto:mforney@mforney.org)
166+Copyright (c) 2014 Roberto E. Vargas Caballero [k0ga@shike2.com](mailto:k0ga@shike2.com)
167+Copyright (c) 2014 Silvan Jegen [s.jegen@gmail.com](mailto:s.jegen@gmail.com)
168+Copyright (c) 2014 Tuukka Kataja [stuge@xor.fi](mailto:stuge@xor.fi)
169+Copyright (c) 2015 Dionysis Grigoropoulos [info@erethon.com](mailto:info@erethon.com)
170+Copyright (c) 2015 Quentin Rameau [quinq@fifth.space](mailto:quinq@fifth.space)
171+Copyright (c) 2015 Risto Salminen [ripejcp@gmail.com](mailto:ripejcp@gmail.com)
172+Copyright (c) 2015 Tai Chi Minh Ralph Eastwood [tcmreastwood@gmail.com](mailto:tcmreastwood@gmail.com)
173+Copyright (c) 2015 Wolfgang Corcoran-Mathe [wcm@sigwinch.xyz](mailto:wcm@sigwinch.xyz)
174+Copyright (c) 2016 Eivind Uggedal [eivind@uggedal.com](mailto:eivind@uggedal.com)
175+Copyright (c) 2016 Mattias Andrée [m@maandree.se](mailto:m@maandree.se)
176+Copyright (c) 2026 xplshn [anto@xplshn.com.ar](mailto:anto@xplshn.com.ar) (https://github.com/xplshn)
177+
178+Portions of this software (specifically utils under net/) are partially
179+based on code written by Rob Landley
180+The rest are based on SBASE/UBASE source code
181+
182+=~= Argentino Roca Unix Utilities =~= https://github.com/xplshn/aruu =~=
+48,
-0
1@@ -0,0 +1,48 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/mount.h>
5+#include <sys/stat.h>
6+#include <sys/types.h>
7+
8+#include <fcntl.h>
9+#include <stdint.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define OFFSET_IDX 0
15+#define LENGTH_IDX 1
16+
17+#define BLKDISCARD _IO(0x12, 119)
18+
19+static void
20+usage(void)
21+{
22+ eprintf("usage: %s device\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+ uint64_t range[2];
29+ int fd;
30+
31+ ARGBEGIN {
32+ default:
33+ usage();
34+ } ARGEND
35+
36+ if (argc != 1)
37+ usage();
38+
39+ fd = open(argv[0], O_RDWR);
40+ if (fd < 0)
41+ eprintf("open: %s:", argv[0]);
42+ range[OFFSET_IDX] = 0;
43+ if (ioctl(fd, BLKGETSIZE64, &range[LENGTH_IDX]) < 0)
44+ eprintf("BLKGETSIZE64: %s:", argv[0]);
45+ if (ioctl(fd, BLKDISCARD, range) < 0)
46+ eprintf("BLKDISCARD: %s:", argv[0]);
47+ close(fd);
48+ return 0;
49+}
+67,
-0
1@@ -0,0 +1,67 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/types.h>
5+
6+#include <fcntl.h>
7+#include <limits.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define KDGKBTYPE 0x4B33 /* get keyboard type */
15+
16+#define VT_ACTIVATE 0x5606 /* make vt active */
17+#define VT_WAITACTIVE 0x5607 /* wait for vt active */
18+
19+static char *vt[] = {
20+ "/proc/self/fd/0",
21+ "/dev/console",
22+ "/dev/tty",
23+ "/dev/tty0",
24+};
25+
26+static void
27+usage(void)
28+{
29+ eprintf("usage: %s num\n", argv0);
30+}
31+
32+int
33+main(int argc, char *argv[])
34+{
35+ unsigned int n, i;
36+ int fd;
37+ char c;
38+
39+ ARGBEGIN {
40+ default:
41+ usage();
42+ } ARGEND;
43+
44+ if (argc != 1)
45+ usage();
46+
47+ n = estrtonum(argv[0], 0, UINT_MAX);
48+ for (i = 0; i < LEN(vt); i++) {
49+ if ((fd = open(vt[i], O_RDONLY)) < 0)
50+ continue;
51+ c = 0;
52+ if (ioctl(fd, KDGKBTYPE, &c) == 0)
53+ goto found;
54+ if (close(fd) < 0)
55+ eprintf("close %s:", vt[i]);
56+ }
57+ eprintf("no console found\n");
58+
59+found:
60+ if (ioctl(fd, VT_ACTIVATE, n) == -1)
61+ eprintf("VT_ACTIVATE %u:", n);
62+ if (ioctl(fd, VT_WAITACTIVE, n) == -1)
63+ eprintf("VT_WAITACTIVE %u:", n);
64+ if (close(fd) < 0)
65+ eprintf("close %s:", vt[i]);
66+
67+ return 0;
68+}
+42,
-0
1@@ -0,0 +1,42 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/syscall.h>
4+
5+#include <stdio.h>
6+#include <unistd.h>
7+
8+#include "reboot.h"
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+ eprintf("usage: %s -h | -s\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+ int hflag = 0, sflag = 0, cmd;
21+
22+ ARGBEGIN {
23+ case 'h':
24+ hflag = 1;
25+ break;
26+ case 's':
27+ sflag = 1;
28+ break;
29+ default:
30+ usage();
31+ } ARGEND;
32+
33+ if (argc || !(hflag ^ sflag))
34+ usage();
35+
36+ cmd = hflag ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
37+
38+ if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
39+ cmd, NULL) < 0)
40+ eprintf("reboot:");
41+
42+ return 0;
43+}
+81,
-0
1@@ -0,0 +1,81 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/klog.h>
4+
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+enum {
13+ SYSLOG_ACTION_READ_ALL = 3,
14+ SYSLOG_ACTION_CLEAR = 5,
15+ SYSLOG_ACTION_CONSOLE_LEVEL = 8,
16+ SYSLOG_ACTION_SIZE_BUFFER = 10
17+};
18+
19+static void
20+dmesg_show(const void *buf, size_t n)
21+{
22+ const char *p = buf;
23+ ssize_t r;
24+
25+ r = write(1, p, n);
26+ if (r < 0)
27+ eprintf("write:");
28+ if (r > 0 && p[r - 1] != '\n')
29+ putchar('\n');
30+}
31+
32+static void
33+usage(void)
34+{
35+ eprintf("usage: %s [-Ccr] [-n level]\n", argv0);
36+}
37+
38+int
39+main(int argc, char *argv[])
40+{
41+ int n;
42+ char *buf;
43+ int cflag = 0;
44+ long level;
45+
46+ ARGBEGIN {
47+ case 'C':
48+ if (klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0)
49+ eprintf("klogctl:");
50+ return 0;
51+ case 'c':
52+ cflag = 1;
53+ break;
54+ case 'r':
55+ break;
56+ case 'n':
57+ level = estrtol(EARGF(usage()), 10);
58+ if (klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, level) < 0)
59+ eprintf("klogctl:");
60+ return 0;
61+ default:
62+ usage();
63+ } ARGEND;
64+
65+ n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
66+ if (n < 0)
67+ eprintf("klogctl:");
68+
69+ buf = emalloc(n);
70+
71+ n = klogctl(SYSLOG_ACTION_READ_ALL, buf, n);
72+ if (n < 0)
73+ eprintf("klogctl:");
74+
75+ dmesg_show(buf, n);
76+
77+ if (cflag && klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0)
78+ eprintf("klogctl:");
79+
80+ free(buf);
81+ return 0;
82+}
+68,
-0
1@@ -0,0 +1,68 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/stat.h>
5+#include <sys/types.h>
6+
7+#include <fcntl.h>
8+#include <stdio.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+enum {
14+ OPEN_TRAY = 0x5309,
15+ CLOSE_TRAY = 0x5319,
16+};
17+
18+static int tflag = 0;
19+static int ret = 0;
20+
21+static void
22+eject(const char *devname)
23+{
24+ int fd, out;
25+
26+ if ((fd = open(devname, O_RDONLY | O_NONBLOCK)) < 0) {
27+ weprintf("open %s:", devname);
28+ ret = 1;
29+ } else if (tflag && ioctl(fd, CLOSE_TRAY, &out) < 0) {
30+ weprintf("ioctl %s:", devname);
31+ ret = 1;
32+ } else if (!tflag && ioctl(fd, OPEN_TRAY, &out) < 0) {
33+ weprintf("ioctl %s:", devname);
34+ ret = 1;
35+ }
36+
37+ if (fd >= 0 && close(fd) < 0) {
38+ weprintf("close %s:", devname);
39+ ret = 1;
40+ }
41+}
42+
43+
44+static void
45+usage(void)
46+{
47+ eprintf("usage: %s [-t] [device ...]\n", argv0);
48+}
49+
50+int
51+main(int argc, char *argv[])
52+{
53+ ARGBEGIN {
54+ case 't':
55+ tflag = 1;
56+ break;
57+ default:
58+ usage();
59+ } ARGEND;
60+
61+ if (!argc) {
62+ eject("/dev/sr0");
63+ } else {
64+ for (; *argv; argc--, argv++)
65+ eject(*argv);
66+ }
67+
68+ return ret;
69+}
+55,
-0
1@@ -0,0 +1,55 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <fcntl.h>
6+#include <limits.h>
7+#include <stdint.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+ eprintf("usage: %s [-o num] -l num file ...\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+ int fd, ret = 0;
24+ off_t size = 0, offset = 0;
25+
26+ ARGBEGIN {
27+ case 'l':
28+ size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
29+ break;
30+ case 'o':
31+ offset = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
32+ break;
33+ default:
34+ usage();
35+ } ARGEND;
36+
37+ if (!argc || !size)
38+ usage();
39+
40+ for (; *argv; argc--, argv++) {
41+ if ((fd = open(*argv, O_RDWR | O_CREAT, 0644)) < 0) {
42+ weprintf("open %s:", *argv);
43+ ret = 1;
44+ } else if (posix_fallocate(fd, offset, size) < 0) {
45+ weprintf("posix_fallocate %s:", *argv);
46+ ret = 1;
47+ }
48+
49+ if (fd >= 0 && close(fd) < 0) {
50+ weprintf("close %s:", *argv);
51+ ret = 1;
52+ }
53+ }
54+
55+ return ret;
56+}
+72,
-0
1@@ -0,0 +1,72 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/sysinfo.h>
4+
5+#include <stdio.h>
6+#include <stdlib.h>
7+
8+#include "util.h"
9+
10+static unsigned int mem_unit = 1;
11+static unsigned int unit_shift;
12+
13+static unsigned long long
14+scale(unsigned long long v)
15+{
16+ return (v * mem_unit) >> unit_shift;
17+}
18+
19+static void
20+usage(void)
21+{
22+ eprintf("usage: %s [-bkmg]\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+ struct sysinfo info;
29+
30+ if (sysinfo(&info) < 0)
31+ eprintf("sysinfo:");
32+ mem_unit = info.mem_unit ? info.mem_unit : 1;
33+
34+ ARGBEGIN {
35+ case 'b':
36+ unit_shift = 0;
37+ break;
38+ case 'k':
39+ unit_shift = 10;
40+ break;
41+ case 'm':
42+ unit_shift = 20;
43+ break;
44+ case 'g':
45+ unit_shift = 30;
46+ break;
47+ default:
48+ usage();
49+ } ARGEND;
50+
51+ printf(" %13s%13s%13s%13s%13s\n",
52+ "total",
53+ "used",
54+ "free",
55+ "shared", "buffers");
56+ printf("Mem: ");
57+ printf("%13llu%13llu%13llu%13llu%13llu\n",
58+ scale(info.totalram),
59+ scale(info.totalram - info.freeram),
60+ scale(info.freeram),
61+ scale(info.sharedram),
62+ scale(info.bufferram));
63+ printf("-/+ buffers/cache:");
64+ printf("%13llu%13llu\n",
65+ scale(info.totalram - info.freeram - info.bufferram),
66+ scale(info.freeram + info.bufferram));
67+ printf("Swap:");
68+ printf("%13llu%13llu%13llu\n",
69+ scale(info.totalswap),
70+ scale(info.totalswap - info.freeswap),
71+ scale(info.freeswap));
72+ return 0;
73+}
+39,
-0
1@@ -0,0 +1,39 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/mount.h>
5+#include <sys/types.h>
6+
7+#include <fcntl.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+ eprintf("usage: %s\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+ char *dev = "/dev/ram";
24+ int fd;
25+
26+ ARGBEGIN {
27+ default:
28+ usage();
29+ } ARGEND;
30+
31+ if (argc != 0)
32+ usage();
33+
34+ if ((fd = open(dev, O_RDWR)) < 0)
35+ eprintf("open: %s:", dev);
36+ if (ioctl(fd, BLKFLSBUF, dev) < 0)
37+ eprintf("BLKFLSBUF %s:", dev);
38+ close(fd);
39+ return 0;
40+}
+54,
-0
1@@ -0,0 +1,54 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/stat.h>
5+#include <sys/types.h>
6+
7+#include <fcntl.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define FIFREEZE _IOWR('X', 119, int) /* Freeze */
15+#define FITHAW _IOWR('X', 120, int) /* Thaw */
16+
17+static void
18+usage(void)
19+{
20+ eprintf("usage: %s (-f | -u) mountpoint\n", argv0);
21+}
22+
23+int
24+main(int argc, char *argv[])
25+{
26+ int fflag = 0;
27+ int uflag = 0;
28+ long p = 1;
29+ int fd;
30+
31+ ARGBEGIN {
32+ case 'f':
33+ fflag = 1;
34+ break;
35+ case 'u':
36+ uflag = 1;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND;
41+
42+ if (argc != 1)
43+ usage();
44+
45+ if ((fflag ^ uflag) == 0)
46+ usage();
47+
48+ fd = open(argv[0], O_RDONLY);
49+ if (fd < 0)
50+ eprintf("open: %s:", argv[0]);
51+ if (ioctl(fd, fflag == 1 ? FIFREEZE : FITHAW, &p) < 0)
52+ eprintf("%s %s:", fflag == 1 ? "FIFREEZE" : "FITHAW", argv[0]);
53+ close(fd);
54+ return 0;
55+}
+159,
-0
1@@ -0,0 +1,159 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/stat.h>
5+#include <sys/time.h>
6+#include <sys/types.h>
7+
8+#include <fcntl.h>
9+#include <stdio.h>
10+#include <stdlib.h>
11+#include <string.h>
12+#include <time.h>
13+#include <unistd.h>
14+
15+#include "rtc.h"
16+#include "util.h"
17+
18+static void
19+readrtctm(struct tm *tm, int fd)
20+{
21+ struct rtc_time rt;
22+
23+ memset(&rt, 0, sizeof(rt));
24+ if (ioctl(fd, RTC_RD_TIME, &rt) < 0)
25+ eprintf("RTC_RD_TIME:");
26+ tm->tm_sec = rt.tm_sec;
27+ tm->tm_min = rt.tm_min;
28+ tm->tm_hour = rt.tm_hour;
29+ tm->tm_mday = rt.tm_mday;
30+ tm->tm_mon = rt.tm_mon;
31+ tm->tm_year = rt.tm_year;
32+ tm->tm_wday = rt.tm_wday;
33+ tm->tm_yday = rt.tm_yday;
34+ tm->tm_isdst = rt.tm_isdst;
35+}
36+
37+static void
38+writertctm(struct tm *tm, int fd)
39+{
40+ struct rtc_time rt;
41+
42+ rt.tm_sec = tm->tm_sec;
43+ rt.tm_min = tm->tm_min;
44+ rt.tm_hour = tm->tm_hour;
45+ rt.tm_mday = tm->tm_mday;
46+ rt.tm_mon = tm->tm_mon;
47+ rt.tm_year = tm->tm_year;
48+ rt.tm_wday = tm->tm_wday;
49+ rt.tm_yday = tm->tm_yday;
50+ rt.tm_isdst = tm->tm_isdst;
51+ if (ioctl(fd, RTC_SET_TIME, &rt) < 0)
52+ eprintf("RTC_SET_TIME:");
53+}
54+
55+static void
56+show(char *dev)
57+{
58+ struct tm tm;
59+ time_t t;
60+ int fd;
61+
62+ fd = open(dev, O_RDONLY);
63+ if (fd < 0)
64+ eprintf("open %s:", dev);
65+ readrtctm(&tm, fd);
66+ t = mktime(&tm);
67+ printf("%s", asctime(localtime(&t)));
68+ close(fd);
69+}
70+
71+static void
72+hctosys(char *dev)
73+{
74+ struct timeval tv;
75+ struct tm tm;
76+ int r;
77+ int fd;
78+
79+ fd = open(dev, O_RDONLY);
80+ if (fd < 0)
81+ eprintf("open %s:", dev);
82+ readrtctm(&tm, fd);
83+ tv.tv_sec = mktime(&tm);
84+ tv.tv_usec = 0;
85+ r = settimeofday(&tv, NULL);
86+ if (r < 0)
87+ eprintf("settimeofday:");
88+ close(fd);
89+}
90+
91+static void
92+systohc(char *dev)
93+{
94+ struct timeval tv;
95+ struct tm *tm;
96+ time_t t;
97+ int fd;
98+
99+ fd = open(dev, O_WRONLY);
100+ if (fd < 0)
101+ eprintf("open %s:", dev);
102+ gettimeofday(&tv, NULL);
103+ t = tv.tv_sec;
104+ tm = gmtime(&t);
105+ weprintf("warning: assuming UTC for systohc\n");
106+ writertctm(tm, fd);
107+ close(fd);
108+}
109+
110+static void
111+usage(void)
112+{
113+ eprintf("usage: %s [-rsw] [-u] [dev]\n", argv0);
114+}
115+
116+int
117+main(int argc, char *argv[])
118+{
119+ char *dev = "/dev/rtc";
120+ int rflag = 0;
121+ int sflag = 0;
122+ int wflag = 0;
123+
124+ ARGBEGIN {
125+ case 'r':
126+ rflag = 1;
127+ break;
128+ case 's':
129+ sflag = 1;
130+ break;
131+ case 'w':
132+ wflag = 1;
133+ break;
134+ case 'u':
135+ break;
136+ default:
137+ usage();
138+ } ARGEND;
139+
140+ if (argc > 1)
141+ usage();
142+ else if (argc == 1)
143+ dev = argv[0];
144+
145+ if ((rflag ^ sflag ^ wflag) == 0)
146+ eprintf("missing or incompatible function\n");
147+
148+ /* Only UTC support at the moment */
149+ setenv("TZ", "UTC0", 1);
150+ tzset();
151+
152+ if (rflag == 1)
153+ show(dev);
154+ else if (sflag == 1)
155+ hctosys(dev);
156+ else if (wflag == 1)
157+ systohc(dev);
158+
159+ return 0;
160+}
+69,
-0
1@@ -0,0 +1,69 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/syscall.h>
5+
6+#include <fcntl.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+ eprintf("usage: %s filename [args...]\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+ char *buf = NULL, *opts = NULL;
24+ size_t blen, plen = 0;
25+ int i, fd;
26+ ssize_t n;
27+ struct stat sb;
28+
29+ ARGBEGIN {
30+ default:
31+ usage();
32+ } ARGEND;
33+
34+ if (argc < 1)
35+ usage();
36+
37+ fd = open(argv[0], O_RDONLY);
38+ if (fd < 0)
39+ eprintf("open %s:", argv[0]);
40+ if (fstat(fd, &sb) < 0)
41+ eprintf("stat %s:", argv[0]);
42+ blen = sb.st_size;
43+ buf = emalloc(blen);
44+
45+ n = read(fd, buf, blen);
46+ if (n < 0 || (size_t)n != blen)
47+ eprintf("read:");
48+
49+ argc--;
50+ argv++;
51+
52+ for (i = 0; i < argc; i++)
53+ plen += strlen(argv[i]);
54+ if (plen > 0) {
55+ plen += argc;
56+ opts = ecalloc(1, plen);
57+ for (i = 0; i < argc; i++) {
58+ strcat(opts, argv[i]);
59+ if (i + 1 < argc)
60+ strcat(opts, " ");
61+ }
62+ }
63+
64+ if (syscall(__NR_init_module, buf, blen, !opts ? "" : opts) < 0)
65+ eprintf("init_module:");
66+
67+ free(opts);
68+ free(buf);
69+ return 0;
70+}
+67,
-0
1@@ -0,0 +1,67 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "text.h"
8+#include "util.h"
9+
10+static void parse_modline(char *buf, char **name, char **size,
11+ char **refcount, char **users);
12+
13+static void
14+usage(void)
15+{
16+ eprintf("usage: %s\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+ const char *modfile = "/proc/modules";
23+ FILE *fp;
24+ char *buf = NULL;
25+ char *name, *size, *refcount, *users;
26+ size_t bufsize = 0;
27+ size_t len;
28+
29+ ARGBEGIN {
30+ default:
31+ usage();
32+ } ARGEND;
33+
34+ if (argc > 0)
35+ usage();
36+
37+ fp = fopen(modfile, "r");
38+ if (!fp)
39+ eprintf("fopen %s:", modfile);
40+
41+ printf("%-23s Size Used by\n", "Module");
42+
43+ while (agetline(&buf, &bufsize, fp) != -1) {
44+ parse_modline(buf, &name, &size, &refcount, &users);
45+ if (!name || !size || !refcount || !users)
46+ eprintf("invalid format: %s\n", modfile);
47+ len = strlen(users) - 1;
48+ if (users[len] == ',' || users[len] == '-')
49+ users[len] = '\0';
50+ printf("%-20s%8s%3s %s\n", name, size, refcount,
51+ users);
52+ }
53+ if (ferror(fp))
54+ eprintf("%s: read error:", modfile);
55+ free(buf);
56+ fclose(fp);
57+ return 0;
58+}
59+
60+static void
61+parse_modline(char *buf, char **name, char **size,
62+ char **refcount, char **users)
63+{
64+ *name = strtok(buf, " ");
65+ *size = strtok(NULL, " ");
66+ *refcount = strtok(NULL, " ");
67+ *users = strtok(NULL, " ");
68+}
+58,
-0
1@@ -0,0 +1,58 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+
7+#include "text.h"
8+#include "util.h"
9+
10+static void
11+lsusb(const char *file)
12+{
13+ FILE *fp;
14+ char path[PATH_MAX];
15+ char *buf = NULL;
16+ size_t size = 0;
17+ unsigned int i = 0, busnum = 0, devnum = 0, pid = 0, vid = 0;
18+
19+ if (strlcpy(path, file, sizeof(path)) >= sizeof(path))
20+ eprintf("path too long\n");
21+ if (strlcat(path, "/uevent", sizeof(path)) >= sizeof(path))
22+ eprintf("path too long\n");
23+
24+ if (!(fp = fopen(path, "r")))
25+ return;
26+ while (agetline(&buf, &size, fp) != -1) {
27+ if (sscanf(buf, "BUSNUM=%u\n", &busnum) ||
28+ sscanf(buf, "DEVNUM=%u\n", &devnum) ||
29+ sscanf(buf, "PRODUCT=%x/%x/", &pid, &vid))
30+ i++;
31+ if (i == 3) {
32+ printf("Bus %03d Device %03d: ID %04x:%04x\n", busnum, devnum,
33+ pid, vid);
34+ break;
35+ }
36+ }
37+ if (ferror(fp))
38+ eprintf("%s: read error:", path);
39+ free(buf);
40+ fclose(fp);
41+}
42+
43+static void
44+usage(void)
45+{
46+ eprintf("usage: %s\n", argv0);
47+}
48+
49+int
50+main(int argc, char *argv[])
51+{
52+ ARGBEGIN {
53+ default:
54+ usage();
55+ } ARGEND;
56+
57+ recurse_dir("/sys/bus/usb/devices", lsusb);
58+ return 0;
59+}
+89,
-0
1@@ -0,0 +1,89 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <fcntl.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+#define SWAP_UUID_LENGTH 16
14+#define SWAP_LABEL_LENGTH 16
15+#define SWAP_MIN_PAGES 10
16+
17+struct swap_hdr {
18+ char bootbits[1024];
19+ unsigned int version;
20+ unsigned int last_page;
21+ unsigned int nr_badpages;
22+ unsigned char uuid[SWAP_UUID_LENGTH];
23+ char volume_name[SWAP_LABEL_LENGTH];
24+ unsigned int padding[117];
25+ unsigned int badpages[1];
26+};
27+
28+static void
29+usage(void)
30+{
31+ eprintf("usage: %s device\n", argv0);
32+}
33+
34+int
35+main(int argc, char *argv[])
36+{
37+ int fd;
38+ unsigned int pages;
39+ long pagesize;
40+ struct stat sb;
41+ char *buf;
42+ struct swap_hdr *hdr;
43+
44+ ARGBEGIN {
45+ default:
46+ usage();
47+ } ARGEND;
48+
49+ if (argc < 1)
50+ usage();
51+
52+ pagesize = sysconf(_SC_PAGESIZE);
53+ if (pagesize <= 0) {
54+ pagesize = sysconf(_SC_PAGE_SIZE);
55+ if (pagesize <= 0)
56+ eprintf("can't determine pagesize\n");
57+ }
58+
59+ fd = open(argv[0], O_RDWR);
60+ if (fd < 0)
61+ eprintf("open %s:", argv[0]);
62+ if (fstat(fd, &sb) < 0)
63+ eprintf("stat %s:", argv[0]);
64+
65+ buf = ecalloc(1, pagesize);
66+
67+ pages = sb.st_size / pagesize;
68+ if (pages < SWAP_MIN_PAGES)
69+ eprintf("swap space needs to be at least %ldKiB\n",
70+ SWAP_MIN_PAGES * pagesize / 1024);
71+
72+ /* Fill up the swap header */
73+ hdr = (struct swap_hdr *)buf;
74+ hdr->version = 1;
75+ hdr->last_page = pages - 1;
76+ strncpy(buf + pagesize - 10, "SWAPSPACE2", 10);
77+
78+ printf("Setting up swapspace version 1, size = %luKiB\n",
79+ (pages - 1) * pagesize / 1024);
80+
81+ /* Write out the signature page */
82+ if (write(fd, buf, pagesize) != pagesize)
83+ eprintf("unable to write signature page\n");
84+
85+ fsync(fd);
86+ close(fd);
87+ free(buf);
88+
89+ return 0;
90+}
+328,
-0
1@@ -0,0 +1,328 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/mount.h>
4+#include <sys/stat.h>
5+#include <sys/types.h>
6+#include <sys/wait.h>
7+
8+#include <errno.h>
9+#include <limits.h>
10+#include <mntent.h>
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <string.h>
14+#include <unistd.h>
15+
16+#include "text.h"
17+#include "util.h"
18+
19+#define FSOPTS_MAXLEN 512
20+
21+struct {
22+ const char *opt;
23+ const char *notopt;
24+ unsigned long v;
25+} optnames[] = {
26+ { "defaults", NULL, 0 },
27+ { "remount", NULL, MS_REMOUNT },
28+ { "ro", "rw", MS_RDONLY },
29+ { "sync", "async", MS_SYNCHRONOUS },
30+ { "dirsync", NULL, MS_DIRSYNC },
31+ { "nodev", "dev", MS_NODEV },
32+ { "noatime", "atime", MS_NOATIME },
33+ { "noauto", "auto", 0 },
34+ { "nodiratime", "diratime", MS_NODIRATIME },
35+ { "noexec", "exec", MS_NOEXEC },
36+ { "nosuid", "suid", MS_NOSUID },
37+ { "mand", "nomand", MS_MANDLOCK },
38+ { "relatime", "norelatime", MS_RELATIME },
39+ { "bind", NULL, MS_BIND },
40+ { NULL, NULL, 0 }
41+};
42+
43+static unsigned long argflags = 0;
44+static char fsopts[FSOPTS_MAXLEN] = "";
45+
46+static char *
47+findtype(const char *types, const char *t)
48+{
49+ const char *p;
50+ size_t len;
51+
52+ for (len = strlen(t); (p = strstr(types, t)); types = p + len) {
53+ if (!strncmp(p, t, len) && (p[len] == '\0' || p[len] == ','))
54+ return (char *)p;
55+ }
56+ return NULL;
57+}
58+
59+static void
60+parseopts(const char *popts, unsigned long *flags, char *data, size_t datasiz)
61+{
62+ unsigned int i, validopt;
63+ size_t optlen, dlen = 0;
64+ const char *name, *e;
65+
66+ name = popts;
67+ data[0] = '\0';
68+ do {
69+ if ((e = strstr(name, ",")))
70+ optlen = e - name;
71+ else
72+ optlen = strlen(name);
73+
74+ validopt = 0;
75+ for (i = 0; optnames[i].opt; i++) {
76+ if (optnames[i].opt &&
77+ !strncmp(name, optnames[i].opt, optlen)) {
78+ *flags |= optnames[i].v;
79+ validopt = 1;
80+ break;
81+ }
82+ if (optnames[i].notopt &&
83+ !strncmp(name, optnames[i].notopt, optlen)) {
84+ *flags &= ~optnames[i].v;
85+ validopt = 1;
86+ break;
87+ }
88+ }
89+
90+ if (!validopt && optlen > 0) {
91+ /* unknown option, pass as data option to mount() */
92+ if (dlen + optlen + 2 >= datasiz)
93+ return; /* prevent overflow */
94+ if (dlen)
95+ data[dlen++] = ',';
96+ memcpy(&data[dlen], name, optlen);
97+ dlen += optlen;
98+ data[dlen] = '\0';
99+ }
100+ name = e + 1;
101+ } while (e);
102+}
103+
104+static int
105+mounthelper(const char *fsname, const char *dir, const char *fstype)
106+{
107+ pid_t pid;
108+ char eprog[PATH_MAX];
109+ char const *eargv[10];
110+ int status, i;
111+
112+ pid = fork();
113+ switch(pid) {
114+ case -1:
115+ break;
116+ case 0:
117+ snprintf(eprog, sizeof(eprog), "mount.%s", fstype);
118+
119+ i = 0;
120+ eargv[i++] = eprog;
121+ if (argflags & MS_BIND)
122+ eargv[i++] = "-B";
123+ if (argflags & MS_MOVE)
124+ eargv[i++] = "-M";
125+ if (argflags & MS_REC)
126+ eargv[i++] = "-R";
127+
128+ if (fsopts[0]) {
129+ eargv[i++] = "-o";
130+ eargv[i++] = fsopts;
131+ }
132+ eargv[i++] = fsname;
133+ eargv[i++] = dir;
134+ eargv[i] = NULL;
135+
136+ execvp(eprog, (char * const *)eargv);
137+ if (errno == ENOENT)
138+ _exit(1);
139+ weprintf("execvp:");
140+ _exit(1);
141+ break;
142+ default:
143+ if (waitpid(pid, &status, 0) < 0) {
144+ weprintf("waitpid:");
145+ return -1;
146+ }
147+ if (WIFEXITED(status))
148+ return WEXITSTATUS(status);
149+ else if (WIFSIGNALED(status))
150+ return 1;
151+ break;
152+ }
153+ return 0;
154+}
155+
156+static int
157+mounted(const char *dir)
158+{
159+ FILE *fp;
160+ struct mntent *me, mebuf;
161+ struct stat st1, st2;
162+ char linebuf[256];
163+
164+ if (stat(dir, &st1) < 0) {
165+ weprintf("stat %s:", dir);
166+ return 0;
167+ }
168+ if (!(fp = setmntent("/proc/mounts", "r")))
169+ eprintf("setmntent %s:", "/proc/mounts");
170+
171+ while ((me = getmntent_r(fp, &mebuf, linebuf, sizeof(linebuf)))) {
172+ if (stat(me->mnt_dir, &st2) < 0) {
173+ weprintf("stat %s:", me->mnt_dir);
174+ continue;
175+ }
176+ if (st1.st_dev == st2.st_dev &&
177+ st1.st_ino == st2.st_ino)
178+ return 1;
179+ }
180+ endmntent(fp);
181+
182+ return 0;
183+}
184+
185+static void
186+usage(void)
187+{
188+ eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n",
189+ argv0);
190+}
191+
192+int
193+main(int argc, char *argv[])
194+{
195+ char *types = NULL, data[FSOPTS_MAXLEN] = "", *resolvpath = NULL;
196+ char *files[] = { "/proc/mounts", "/etc/fstab", NULL };
197+ const char *source, *target;
198+ struct mntent *me = NULL;
199+ int aflag = 0, status = 0, i, r;
200+ unsigned long flags = 0;
201+ FILE *fp;
202+
203+ ARGBEGIN {
204+ case 'B':
205+ argflags |= MS_BIND;
206+ break;
207+ case 'M':
208+ argflags |= MS_MOVE;
209+ break;
210+ case 'R':
211+ argflags |= MS_REC;
212+ break;
213+ case 'a':
214+ aflag = 1;
215+ break;
216+ case 'o':
217+ estrlcat(fsopts, EARGF(usage()), sizeof(fsopts));
218+ parseopts(fsopts, &flags, data, sizeof(data));
219+ break;
220+ case 't':
221+ types = EARGF(usage());
222+ break;
223+ case 'n':
224+ break;
225+ default:
226+ usage();
227+ } ARGEND;
228+
229+ if (argc < 1 && aflag == 0) {
230+ if (!(fp = fopen(files[0], "r")))
231+ eprintf("fopen %s:", files[0]);
232+ fconcat(fp, files[0], stdout, "<stdout>");
233+ fclose(fp);
234+ return 0;
235+ }
236+
237+ if (aflag == 1)
238+ goto mountall;
239+
240+ source = argv[0];
241+ target = argv[1];
242+
243+ if (!target) {
244+ target = argv[0];
245+ source = NULL;
246+ if (strcmp(target, "/") != 0) {
247+ if (!(resolvpath = realpath(target, NULL)))
248+ eprintf("realpath %s:", target);
249+ target = resolvpath;
250+ }
251+ }
252+
253+ for (i = 0; files[i]; i++) {
254+ if (!(fp = setmntent(files[i], "r"))) {
255+ if (strcmp(files[i], "/proc/mounts") != 0)
256+ weprintf("setmntent %s:", files[i]);
257+ continue;
258+ }
259+ while ((me = getmntent(fp))) {
260+ if (strcmp(me->mnt_dir, target) == 0 ||
261+ strcmp(me->mnt_fsname, target) == 0 ||
262+ (source && strcmp(me->mnt_dir, source) == 0) ||
263+ (source && strcmp(me->mnt_fsname, source) == 0)) {
264+ if (!source) {
265+ target = me->mnt_dir;
266+ source = me->mnt_fsname;
267+ }
268+ if (!fsopts[0])
269+ estrlcat(fsopts, me->mnt_opts, sizeof(fsopts));
270+ parseopts(fsopts, &flags, data, sizeof(data));
271+ if (!types)
272+ types = me->mnt_type;
273+ goto mountsingle;
274+ }
275+ }
276+ endmntent(fp);
277+ fp = NULL;
278+ }
279+ if (!source)
280+ eprintf("can't find %s in /etc/fstab\n", target);
281+
282+mountsingle:
283+ r = mounthelper(source, target, types);
284+ if (r == -1)
285+ status = 1;
286+ if (r > 0 && mount(source, target, types, argflags | flags, data) < 0) {
287+ weprintf("mount: %s:", source);
288+ status = 1;
289+ }
290+ if (fp)
291+ endmntent(fp);
292+ free(resolvpath);
293+ return status;
294+
295+mountall:
296+ if (!(fp = setmntent("/etc/fstab", "r")))
297+ eprintf("setmntent %s:", "/etc/fstab");
298+ while ((me = getmntent(fp))) {
299+ /* has "noauto" option or already mounted: skip */
300+ if (hasmntopt(me, MNTOPT_NOAUTO) || mounted(me->mnt_dir))
301+ continue;
302+ flags = 0;
303+ fsopts[0] = '\0';
304+ if (strlcat(fsopts, me->mnt_opts, sizeof(fsopts)) >= sizeof(fsopts)) {
305+ weprintf("%s: option string too long\n", me->mnt_dir);
306+ status = 1;
307+ continue;
308+ }
309+ parseopts(fsopts, &flags, data, sizeof(data));
310+ /* if -t types specified:
311+ * if non-match, skip
312+ * if match and prefixed with "no", skip */
313+ if (types &&
314+ ((types[0] == 'n' && types[1] == 'o' &&
315+ findtype(types + 2, me->mnt_type)) ||
316+ (!findtype(types, me->mnt_type))))
317+ continue;
318+
319+ r = mounthelper(me->mnt_fsname, me->mnt_dir, me->mnt_type);
320+ if (r > 0 && mount(me->mnt_fsname, me->mnt_dir, me->mnt_type,
321+ argflags | flags, data) < 0) {
322+ weprintf("mount: %s:", me->mnt_fsname);
323+ status = 1;
324+ }
325+ }
326+ endmntent(fp);
327+
328+ return status;
329+}
+102,
-0
1@@ -0,0 +1,102 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/sysmacros.h>
5+#include <sys/types.h>
6+
7+#include <mntent.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "util.h"
14+
15+static void
16+usage(void)
17+{
18+ eprintf("usage: %s [-dqx] target\n", argv0);
19+}
20+
21+int
22+main(int argc, char *argv[])
23+{
24+ int dflag = 0, qflag = 0, xflag = 0;
25+ int ret = 0;
26+ struct mntent *me = NULL;
27+ FILE *fp;
28+ struct stat st1, st2;
29+
30+ ARGBEGIN {
31+ case 'd':
32+ dflag = 1;
33+ break;
34+ case 'q':
35+ qflag = 1;
36+ break;
37+ case 'x':
38+ xflag = 1;
39+ break;
40+ default:
41+ usage();
42+ } ARGEND;
43+
44+ if (argc < 1)
45+ usage();
46+
47+ if (stat(argv[0], &st1) < 0) {
48+ if (qflag)
49+ return 1;
50+ eprintf("stat %s:", argv[0]);
51+ }
52+
53+ if (xflag) {
54+ if (!S_ISBLK(st1.st_mode)) {
55+ if (qflag)
56+ return 1;
57+ eprintf("stat: %s: not a block device\n",
58+ argv[0]);
59+ }
60+ printf("%u:%u\n", major(st1.st_rdev),
61+ minor(st1.st_rdev));
62+ return 0;
63+ }
64+
65+ if (!S_ISDIR(st1.st_mode)) {
66+ if (qflag)
67+ return 1;
68+ eprintf("stat %s: not a directory\n", argv[0]);
69+ }
70+
71+ if (dflag) {
72+ printf("%u:%u\n", major(st1.st_dev),
73+ minor(st1.st_dev));
74+ return 0;
75+ }
76+
77+ fp = setmntent("/proc/mounts", "r");
78+ if (!fp) {
79+ if (qflag)
80+ return 1;
81+ eprintf("setmntent %s:", "/proc/mounts");
82+ }
83+ while ((me = getmntent(fp)) != NULL) {
84+ if (stat(me->mnt_dir, &st2) < 0) {
85+ if (qflag)
86+ return 1;
87+ eprintf("stat %s:", me->mnt_dir);
88+ }
89+ if (st1.st_dev == st2.st_dev &&
90+ st1.st_ino == st2.st_ino)
91+ break;
92+ }
93+ endmntent(fp);
94+
95+ if (me == NULL)
96+ ret = 1;
97+
98+ if (!qflag)
99+ printf("%s %s a mountpoint\n", argv[0],
100+ !ret ? "is" : "is not");
101+
102+ return ret;
103+}
+116,
-0
1@@ -0,0 +1,116 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+
5+#include <dirent.h>
6+#include <libgen.h>
7+#include <limits.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "proc.h"
14+#include "queue.h"
15+#include "util.h"
16+
17+struct pidentry {
18+ pid_t pid;
19+ SLIST_ENTRY(pidentry) entry;
20+};
21+
22+static SLIST_HEAD(, pidentry) omitpid_head;
23+
24+static void
25+usage(void)
26+{
27+ eprintf("usage: %s [-o pid1,pid2,...pidN] [-s] [program...]\n", argv0);
28+}
29+
30+int
31+main(int argc, char *argv[])
32+{
33+ DIR *dp;
34+ struct dirent *entry;
35+ pid_t pid;
36+ struct procstat ps;
37+ char cmdline[BUFSIZ], *cmd, *cmdbase = NULL, *p, *arg = NULL;
38+ int i, found = 0;
39+ int sflag = 0, oflag = 0;
40+ struct pidentry *pe;
41+
42+ ARGBEGIN {
43+ case 's':
44+ sflag = 1;
45+ break;
46+ case 'o':
47+ oflag = 1;
48+ arg = EARGF(usage());
49+ break;
50+ default:
51+ usage();
52+ } ARGEND;
53+
54+ if (!argc)
55+ return 1;
56+
57+ SLIST_INIT(&omitpid_head);
58+
59+ if (oflag) {
60+ for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
61+ pe = emalloc(sizeof(*pe));
62+ if (strcmp(p, "%PPID") == 0)
63+ pe->pid = getppid();
64+ else
65+ pe->pid = estrtol(p, 10);
66+ SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
67+ }
68+ }
69+
70+ if (!(dp = opendir("/proc")))
71+ eprintf("opendir /proc:");
72+
73+ while ((entry = readdir(dp))) {
74+ if (!pidfile(entry->d_name))
75+ continue;
76+ pid = estrtol(entry->d_name, 10);
77+ if (oflag) {
78+ SLIST_FOREACH(pe, &omitpid_head, entry)
79+ if (pe->pid == pid)
80+ break;
81+ if (pe)
82+ continue;
83+ }
84+ if (parsestat(pid, &ps) < 0)
85+ continue;
86+ if (parsecmdline(ps.pid, cmdline,
87+ sizeof(cmdline)) < 0) {
88+ cmd = ps.comm;
89+ cmdbase = cmd;
90+ } else {
91+ if ((p = strchr(cmdline, ' ')))
92+ *p = '\0';
93+ cmd = cmdline;
94+ cmdbase = basename(cmdline);
95+ }
96+ /* Workaround for login shells */
97+ if (cmd[0] == '-')
98+ cmd++;
99+ for (i = 0; i < argc; i++) {
100+ if (strcmp(cmd, argv[i]) == 0 ||
101+ strcmp(cmdbase, argv[i]) == 0) {
102+ putword(stdout, entry->d_name);
103+ found++;
104+ if (sflag)
105+ goto out;
106+ }
107+ }
108+ }
109+
110+out:
111+ if (found)
112+ putchar('\n');
113+
114+ closedir(dp);
115+
116+ return found ? 0 : 1;
117+}
+31,
-0
1@@ -0,0 +1,31 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/syscall.h>
4+
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+ eprintf("usage: %s new-root put-old\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+ ARGBEGIN {
21+ default:
22+ usage();
23+ } ARGEND;
24+
25+ if (argc < 2)
26+ usage();
27+
28+ if (syscall(SYS_pivot_root, argv[0], argv[1]) < 0)
29+ eprintf("pivot_root:");
30+
31+ return 0;
32+}
+51,
-0
1@@ -0,0 +1,51 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <limits.h>
5+#include <stdio.h>
6+#include <string.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+ eprintf("usage: %s pid...\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+ int ret = 0;
21+ char path[PATH_MAX];
22+ char target[PATH_MAX + sizeof(" (deleted)")];
23+ ssize_t n;
24+
25+ ARGBEGIN {
26+ default:
27+ usage();
28+ } ARGEND;
29+
30+ if (argc == 0)
31+ usage();
32+
33+ for (; argc > 0; argc--, argv++) {
34+ n = snprintf(path, sizeof(path), "/proc/%s/cwd", *argv);
35+ if (n < 0 || n >= sizeof(path)) {
36+ errno = ESRCH;
37+ } else {
38+ n = readlink(path, target, sizeof(target) - 1);
39+ if (n >= 0) {
40+ target[n] = '\0';
41+ printf("%s: %s\n", *argv, target);
42+ continue;
43+ }
44+ }
45+ if (errno == ENOENT)
46+ errno = ESRCH;
47+ weprintf("%s:", *argv);
48+ ret = 1;
49+ }
50+
51+ return ret;
52+}
+38,
-0
1@@ -0,0 +1,38 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <limits.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+
8+#include "util.h"
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s file...\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+ FILE *fp;
20+
21+ ARGBEGIN {
22+ default:
23+ usage();
24+ } ARGEND;
25+
26+ if (argc == 0)
27+ usage();
28+
29+ for (; argc > 0; argc--, argv++) {
30+ if (!(fp = fopen(argv[0], "r"))) {
31+ weprintf("fopen %s:", argv[0]);
32+ continue;
33+ }
34+ if (readahead(fileno(fp), 0, -1) < 0)
35+ weprintf("readahead %s:", argv[0]);
36+ fclose(fp);
37+ }
38+ return 0;
39+}
+50,
-0
1@@ -0,0 +1,50 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/syscall.h>
4+
5+#include <fcntl.h>
6+#include <libgen.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+ eprintf("usage: %s [-fw] module...\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+ char *mod, *p;
24+ int i;
25+ int flags = O_NONBLOCK;
26+
27+ ARGBEGIN {
28+ case 'f':
29+ flags |= O_TRUNC;
30+ break;
31+ case 'w':
32+ flags &= ~O_NONBLOCK;
33+ break;
34+ default:
35+ usage();
36+ } ARGEND;
37+
38+ if (argc < 1)
39+ usage();
40+
41+ for (i = 0; i < argc; i++) {
42+ mod = argv[i];
43+ p = strrchr(mod, '.');
44+ if (p && !strcmp(p, ".ko"))
45+ *p = '\0';
46+ if (syscall(__NR_delete_module, mod, flags) < 0)
47+ eprintf("delete_module:");
48+ }
49+
50+ return 0;
51+}
+80,
-0
1@@ -0,0 +1,80 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+
5+#include <fcntl.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+#define SWAP_MAGIC1 "SWAPSPACE2"
14+#define SWAP_MAGIC2 "SWAP-SPACE"
15+#define SWAP_MAGIC_LENGTH (10)
16+#define SWAP_MAGIC_OFFSET (sysconf(_SC_PAGESIZE) - SWAP_MAGIC_LENGTH)
17+#define SWAP_LABEL_LENGTH (16)
18+#define SWAP_LABEL_OFFSET (1024 + 4 + 4 + 4 + 16)
19+
20+static void
21+usage(void)
22+{
23+ eprintf("usage: %s [-L label] device\n", argv0);
24+}
25+
26+int
27+main(int argc, char *argv[])
28+{
29+ int setlabel = 0;
30+ int fd;
31+ char magic[SWAP_MAGIC_LENGTH];
32+ char *label;
33+ char *device;
34+ int i;
35+
36+ ARGBEGIN {
37+ case 'L':
38+ setlabel = 1;
39+ label = EARGF(usage());
40+ break;
41+ default:
42+ usage();
43+ } ARGEND;
44+
45+ if (argc < 1)
46+ usage();
47+ device = argv[0];
48+
49+ fd = open(device, O_RDWR);
50+ if (fd < 0)
51+ eprintf("open %s:", device);
52+
53+ if (lseek(fd, SWAP_MAGIC_OFFSET, SEEK_SET) != SWAP_MAGIC_OFFSET)
54+ eprintf("failed seeking to magic position:");
55+ if (read(fd, magic, SWAP_MAGIC_LENGTH) != SWAP_MAGIC_LENGTH)
56+ eprintf("reading magic failed:");
57+ if (memcmp(magic, SWAP_MAGIC1, 10) && memcmp(magic, SWAP_MAGIC2, 10))
58+ eprintf("%s: is not a swap partition\n", device);
59+ if (lseek(fd, SWAP_LABEL_OFFSET, SEEK_SET) != SWAP_LABEL_OFFSET)
60+ eprintf("failed seeking to label position:");
61+
62+ if (!setlabel) {
63+ label = emalloc(SWAP_LABEL_LENGTH);
64+ if (read(fd, label, SWAP_LABEL_LENGTH) != SWAP_LABEL_LENGTH)
65+ eprintf("reading label failed:");
66+ for (i = 0; i < SWAP_LABEL_LENGTH && label[i] != '\0'; i++)
67+ if (i == (SWAP_LABEL_LENGTH - 1) && label[i] != '\0')
68+ eprintf("invalid label\n");
69+ printf("label: %s\n", label);
70+ free(label);
71+ } else {
72+ if (strlen(label) + 1 > SWAP_LABEL_LENGTH)
73+ eprintf("label too long\n");
74+ if (write(fd, label, strlen(label) + 1) != (ssize_t)strlen(label) + 1)
75+ eprintf("writing label failed:");
76+ }
77+
78+ fsync(fd);
79+ close(fd);
80+ return 0;
81+}
+59,
-0
1@@ -0,0 +1,59 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/swap.h>
4+
5+#include <mntent.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s -a | device\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ int i;
22+ int ret = 0;
23+ int all = 0;
24+ struct mntent *me;
25+ FILE *fp;
26+
27+ ARGBEGIN {
28+ case 'a':
29+ all = 1;
30+ break;
31+ default:
32+ usage();
33+ } ARGEND;
34+
35+ if ((!all && argc < 1) || (all && argc > 0))
36+ usage();
37+
38+ if (all) {
39+ fp = setmntent("/etc/fstab", "r");
40+ if (!fp)
41+ eprintf("setmntent %s:", "/etc/fstab");
42+ while ((me = getmntent(fp)) != NULL) {
43+ if (strcmp(me->mnt_type, MNTTYPE_SWAP) == 0) {
44+ if (swapoff(me->mnt_fsname) < 0) {
45+ weprintf("swapoff %s:", me->mnt_fsname);
46+ ret = 1;
47+ }
48+ }
49+ }
50+ endmntent(fp);
51+ } else {
52+ for (i = 0; i < argc; i++) {
53+ if (swapoff(argv[i]) < 0) {
54+ weprintf("swapoff %s:", argv[i]);
55+ ret = 1;
56+ }
57+ }
58+ }
59+ return ret;
60+}
+67,
-0
1@@ -0,0 +1,67 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/swap.h>
4+
5+#include <mntent.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s [-dp] -a | device\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ int i;
22+ int ret = 0;
23+ int flags = 0;
24+ int all = 0;
25+ struct mntent *me;
26+ FILE *fp;
27+
28+ ARGBEGIN {
29+ case 'a':
30+ all = 1;
31+ break;
32+ case 'd':
33+ flags |= SWAP_FLAG_DISCARD;
34+ break;
35+ case 'p':
36+ flags |= SWAP_FLAG_PREFER;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND;
41+
42+ if ((!all && argc < 1) || (all && argc > 0))
43+ usage();
44+
45+ if (all) {
46+ fp = setmntent("/etc/fstab", "r");
47+ if (!fp)
48+ eprintf("setmntent %s:", "/etc/fstab");
49+ while ((me = getmntent(fp)) != NULL) {
50+ if (strcmp(me->mnt_type, MNTTYPE_SWAP) == 0
51+ && (hasmntopt(me, MNTOPT_NOAUTO) == NULL)) {
52+ if (swapon(me->mnt_fsname, flags) < 0) {
53+ weprintf("swapon %s:", me->mnt_fsname);
54+ ret = 1;
55+ }
56+ }
57+ }
58+ endmntent(fp);
59+ } else {
60+ for (i = 0; i < argc; i++) {
61+ if (swapon(argv[i], flags) < 0) {
62+ weprintf("swapon %s:", argv[i]);
63+ ret = 1;
64+ }
65+ }
66+ }
67+ return ret;
68+}
+131,
-0
1@@ -0,0 +1,131 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/mount.h>
4+#include <sys/stat.h>
5+#include <sys/vfs.h>
6+
7+#include <dirent.h>
8+#include <fcntl.h>
9+#include <limits.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+
15+#include "util.h"
16+
17+#define RAMFS_MAGIC 0x858458f6 /* some random number */
18+#define TMPFS_MAGIC 0x01021994
19+
20+static void
21+delete_content(const char *dir, dev_t curdevice)
22+{
23+ char path[PATH_MAX];
24+ DIR *d;
25+ struct stat st;
26+ struct dirent *dent;
27+
28+ /* don't dive into other filesystems */
29+ if (lstat(dir, &st) < 0 || st.st_dev != curdevice)
30+ return;
31+ if (!(d = opendir(dir)))
32+ return;
33+ while ((dent = readdir(d))) {
34+ if (strcmp(dent->d_name, ".") == 0 ||
35+ strcmp(dent->d_name, "..") == 0)
36+ continue;
37+
38+ /* build path and dive deeper */
39+ if (strlcpy(path, dir, sizeof(path)) >= sizeof(path))
40+ eprintf("path too long\n");
41+ if (path[strlen(path) - 1] != '/')
42+ if (strlcat(path, "/", sizeof(path)) >= sizeof(path))
43+ eprintf("path too long\n");
44+ if (strlcat(path, dent->d_name, sizeof(path)) >= sizeof(path))
45+ eprintf("path too long\n");
46+
47+ if (lstat(path, &st) < 0)
48+ weprintf("lstat %s:", path);
49+
50+ if (S_ISDIR(st.st_mode)) {
51+ delete_content(path, curdevice);
52+ if (rmdir(path) < 0)
53+ weprintf("rmdir %s:", path);
54+ } else {
55+ if (unlink(path) < 0)
56+ weprintf("unlink %s:", path);
57+ }
58+ }
59+ closedir(d);
60+}
61+
62+static void
63+usage(void)
64+{
65+ eprintf("usage: %s [-c console] [newroot] [init] (PID 1)\n", argv0);
66+}
67+
68+int
69+main(int argc, char *argv[])
70+{
71+ char *console = NULL;
72+ dev_t curdev;
73+ struct stat st;
74+ struct statfs stfs;
75+
76+ ARGBEGIN {
77+ case 'c':
78+ console = EARGF(usage());
79+ break;
80+ default:
81+ usage();
82+ } ARGEND;
83+
84+ /* check number of args and if we are PID 1 */
85+ if (argc != 2 || getpid() != 1)
86+ usage();
87+
88+ /* chdir to newroot and make sure it's a different fs */
89+ if (chdir(argv[0]))
90+ eprintf("chdir %s:", argv[0]);
91+
92+ if (stat("/", &st))
93+ eprintf("stat %s:", "/");
94+
95+ curdev = st.st_dev;
96+ if (stat(".", &st))
97+ eprintf("stat %s:", ".");
98+ if (st.st_dev == curdev)
99+ usage();
100+
101+ /* avoids trouble with real filesystems */
102+ if (stat("/init", &st) || !S_ISREG(st.st_mode))
103+ eprintf("/init is not a regular file\n");
104+
105+ statfs("/", &stfs);
106+ if ((unsigned)stfs.f_type != RAMFS_MAGIC && (unsigned)stfs.f_type != TMPFS_MAGIC)
107+ eprintf("current filesystem is not a RAMFS or TMPFS\n");
108+
109+ /* wipe / */
110+ delete_content("/", curdev);
111+
112+ /* overmount / with newroot and chroot into it */
113+ if (mount(".", "/", NULL, MS_MOVE, NULL))
114+ eprintf("mount %s:", ".");
115+
116+ if (chroot("."))
117+ eprintf("chroot failed\n");
118+
119+ /* if -c is set, redirect stdin/stdout/stderr to console */
120+ if (console) {
121+ close(0);
122+ if (open(console, O_RDWR) == -1)
123+ eprintf("open %s:", console);
124+ dup2(0, 1);
125+ dup2(0, 2);
126+ }
127+
128+ /* execute init */
129+ execv(argv[1], argv);
130+ eprintf("can't execute '%s':", argv[1]);
131+ return 1;
132+}
+213,
-0
1@@ -0,0 +1,213 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <limits.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+#include <unistd.h>
9+
10+#include "text.h"
11+#include "util.h"
12+
13+static void
14+replacestr(char *s, int a, int b)
15+{
16+ for (; *s; s++)
17+ if (*s == a)
18+ *s = b;
19+}
20+
21+static int
22+getsysctl(char *variable, char **value)
23+{
24+ char path[PATH_MAX];
25+ char *p;
26+ char *buf, *tmp, c;
27+ int fd;
28+ ssize_t n;
29+ size_t sz, i;
30+
31+ replacestr(variable, '.', '/');
32+
33+ strlcpy(path, "/proc/sys/", sizeof(path));
34+ if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
35+ replacestr(variable, '/', '.');
36+ return -1;
37+ }
38+
39+ replacestr(variable, '/', '.');
40+
41+ fd = open(path, O_RDONLY);
42+ if (fd < 0)
43+ return -1;
44+
45+ i = 0;
46+ sz = 1;
47+ buf = NULL;
48+ while (1) {
49+ n = read(fd, &c, 1);
50+ if (n < 0) {
51+ close(fd);
52+ free(buf);
53+ return -1;
54+ }
55+ if (n == 0)
56+ break;
57+ if (i == sz - 1) {
58+ sz *= 2;
59+ tmp = realloc(buf, sz);
60+ if (!tmp) {
61+ close(fd);
62+ free(buf);
63+ return -1;
64+ }
65+ buf = tmp;
66+ }
67+ buf[i++] = c;
68+ }
69+ buf[i] = '\0';
70+
71+ p = strrchr(buf, '\n');
72+ if (p)
73+ *p = '\0';
74+
75+ *value = buf;
76+
77+ close(fd);
78+
79+ return 0;
80+}
81+
82+static int
83+setsysctl(char *variable, char *value)
84+{
85+ char path[PATH_MAX];
86+ int fd;
87+ ssize_t n;
88+
89+ replacestr(variable, '.', '/');
90+
91+ strlcpy(path, "/proc/sys/", sizeof(path));
92+ if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
93+ replacestr(variable, '/', '.');
94+ return -1;
95+ }
96+
97+ replacestr(variable, '/', '.');
98+
99+ fd = open(path, O_WRONLY);
100+ if (fd < 0)
101+ return -1;
102+
103+ n = write(fd, value, strlen(value));
104+ if ((size_t)n != strlen(value)) {
105+ close(fd);
106+ return -1;
107+ }
108+
109+ close(fd);
110+
111+ return 0;
112+}
113+
114+static int
115+parsepair(char *pair)
116+{
117+ char *p;
118+ char *variable;
119+ char *value;
120+
121+ for (p = pair; *p; p++) {
122+ if (p[0] == '.' && p[1] == '.') {
123+ weprintf("malformed input: %s\n", pair);
124+ return -1;
125+ }
126+ }
127+ p = strchr(pair, '=');
128+ if (p) {
129+ if (p[1] == '\0') {
130+ weprintf("malformed input: %s\n", pair);
131+ return -1;
132+ }
133+ *p = '\0';
134+ value = &p[1];
135+ } else {
136+ value = NULL;
137+ }
138+ variable = pair;
139+ if (value) {
140+ if (setsysctl(variable, value) < 0) {
141+ weprintf("failed to set sysctl for %s\n", variable);
142+ return -1;
143+ }
144+ } else {
145+ if (getsysctl(variable, &value) < 0) {
146+ weprintf("failed to get sysctl for %s\n", variable);
147+ return -1;
148+ }
149+ printf("%s = %s\n", variable, value);
150+ free(value);
151+ }
152+
153+ return 0;
154+}
155+
156+static void
157+usage(void)
158+{
159+ eprintf("usage: %s [-p file] variable[=value]...\n", argv0);
160+}
161+
162+int
163+main(int argc, char *argv[])
164+{
165+ FILE *fp;
166+ char *buf = NULL, *p;
167+ char *file = NULL;
168+ size_t size = 0;
169+ int i;
170+ int r = 0;
171+
172+ ARGBEGIN {
173+ case 'p':
174+ file = EARGF(usage());
175+ break;
176+ default:
177+ usage();
178+ } ARGEND;
179+
180+ if (!file && argc < 1)
181+ usage();
182+
183+ if (!file) {
184+ for (i = 0; i < argc; i++)
185+ if (parsepair(argv[i]) < 0)
186+ r = 1;
187+ } else {
188+ fp = fopen(file, "r");
189+ if (!fp)
190+ eprintf("fopen %s:", file);
191+ while (agetline(&buf, &size, fp) != -1) {
192+ p = buf;
193+ for (p = buf; *p == ' ' || *p == '\t'; p++)
194+ ;
195+ if (*p == '#' || *p == '\n')
196+ continue;
197+ for (p = buf; *p; p++) {
198+ if (*p == '\n') {
199+ *p = '\0';
200+ break;
201+ }
202+ }
203+ p = buf;
204+ if (parsepair(p) < 0)
205+ r = 1;
206+ }
207+ if (ferror(fp))
208+ eprintf("%s: read error:", file);
209+ free(buf);
210+ fclose(fp);
211+ }
212+
213+ return r;
214+}
+180,
-0
1@@ -0,0 +1,180 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/mount.h>
4+
5+#include <mntent.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "util.h"
11+
12+#ifdef STD_NON_POSIX
13+static int
14+fsopt_matches(const char *opts_list, const char *opt, size_t optlen)
15+{
16+ int match = 1;
17+
18+ if (optlen >= 2 && opt[0] == 'n' && opt[1] == 'o') {
19+ match--;
20+ opt += 2;
21+ optlen -= 2;
22+ }
23+
24+ if (optlen == 0)
25+ return 0;
26+
27+ if (match && optlen > 1 && *opt == '+') {
28+ opt++;
29+ optlen--;
30+ }
31+
32+ while (1) {
33+ if (strncmp(opts_list, opt, optlen) == 0) {
34+ const char *after_opt = opts_list + optlen;
35+ if (*after_opt == '\0' || *after_opt == ',')
36+ return match;
37+ }
38+
39+ opts_list = strchr(opts_list, ',');
40+ if (!opts_list)
41+ break;
42+ opts_list++;
43+ }
44+
45+ return !match;
46+}
47+
48+static int
49+fsopts_matches(const char *opts_list, const char *reqopts_list)
50+{
51+ const char *comma;
52+ size_t len;
53+
54+ if (!reqopts_list)
55+ return 1;
56+
57+ while (1) {
58+ comma = strchr(reqopts_list, ',');
59+ if (!comma)
60+ len = strlen(reqopts_list);
61+ else
62+ len = comma - reqopts_list;
63+
64+ if (len && !fsopt_matches(opts_list, reqopts_list, len))
65+ return 0;
66+
67+ if (!comma)
68+ break;
69+ reqopts_list = ++comma;
70+ }
71+
72+ return 1;
73+}
74+#endif
75+
76+static int
77+umountall(int flags
78+#ifdef STD_NON_POSIX
79+ , const char *oflag
80+#endif
81+)
82+{
83+ FILE *fp;
84+ struct mntent *me;
85+ int ret = 0;
86+ char **mntdirs = NULL;
87+ int len = 0;
88+
89+ fp = setmntent("/proc/mounts", "r");
90+ if (!fp)
91+ eprintf("setmntent %s:", "/proc/mounts");
92+ while ((me = getmntent(fp))) {
93+ if (strcmp(me->mnt_type, "proc") == 0)
94+ continue;
95+#ifdef STD_NON_POSIX
96+ if (oflag && !fsopts_matches(me->mnt_opts, oflag))
97+ continue;
98+#endif
99+ mntdirs = erealloc(mntdirs, ++len * sizeof(*mntdirs));
100+ mntdirs[len - 1] = estrdup(me->mnt_dir);
101+ }
102+ endmntent(fp);
103+ while (--len >= 0) {
104+ if (umount2(mntdirs[len], flags) < 0) {
105+ weprintf("umount2 %s:", mntdirs[len]);
106+ ret = 1;
107+ }
108+ free(mntdirs[len]);
109+ }
110+ free(mntdirs);
111+ return ret;
112+}
113+
114+static void
115+usage(void)
116+{
117+#ifdef STD_NON_POSIX
118+ weprintf("usage: %s [-lfn] [-O options] target...\n", argv0);
119+ weprintf("usage: %s -a [-lfn] [-O options]\n", argv0);
120+#else
121+ weprintf("usage: %s [-lfn] target...\n", argv0);
122+ weprintf("usage: %s -a [-lfn]\n", argv0);
123+#endif
124+ exit(1);
125+}
126+
127+int
128+main(int argc, char *argv[])
129+{
130+ int i;
131+ int aflag = 0;
132+ int flags = 0;
133+ int ret = 0;
134+#ifdef STD_NON_POSIX
135+ char *oflag = NULL;
136+#endif
137+
138+ ARGBEGIN {
139+ case 'a':
140+ aflag = 1;
141+ break;
142+ case 'f':
143+ flags |= MNT_FORCE;
144+ break;
145+ case 'l':
146+ flags |= MNT_DETACH;
147+ break;
148+ case 'n':
149+ break;
150+#ifdef STD_NON_POSIX
151+ case 'O':
152+ oflag = EARGF(usage());
153+ break;
154+#endif
155+ default:
156+ usage();
157+ } ARGEND;
158+
159+ if (argc < 1 && aflag == 0)
160+ usage();
161+
162+#ifdef STD_NON_POSIX
163+ if (oflag && aflag == 0)
164+ usage();
165+#endif
166+
167+ if (aflag == 1)
168+ return umountall(flags
169+#ifdef STD_NON_POSIX
170+ , oflag
171+#endif
172+ );
173+
174+ for (i = 0; i < argc; i++) {
175+ if (umount2(argv[i], flags) < 0) {
176+ weprintf("umount2 %s:", argv[i]);
177+ ret = 1;
178+ }
179+ }
180+ return ret;
181+}
1@@ -0,0 +1,54 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sched.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+ eprintf("usage: %s [-muinpU] cmd [args...]\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+ int flags = 0;
21+
22+ ARGBEGIN {
23+ case 'm':
24+ flags |= CLONE_NEWNS;
25+ break;
26+ case 'u':
27+ flags |= CLONE_NEWUTS;
28+ break;
29+ case 'i':
30+ flags |= CLONE_NEWIPC;
31+ break;
32+ case 'n':
33+ flags |= CLONE_NEWNET;
34+ break;
35+ case 'p':
36+ flags |= CLONE_NEWPID;
37+ break;
38+ case 'U':
39+ flags |= CLONE_NEWUSER;
40+ break;
41+ default:
42+ usage();
43+ } ARGEND;
44+
45+ if (argc < 1)
46+ usage();
47+
48+ if (unshare(flags) < 0)
49+ eprintf("unshare:");
50+
51+ if (execvp(argv[0], argv) < 0)
52+ eprintf("execvp:");
53+
54+ return 0;
55+}
+73,
-0
1@@ -0,0 +1,73 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/sysinfo.h>
4+
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+#include <time.h>
9+#include <utmpx.h>
10+
11+#include "config.h"
12+#include "util.h"
13+
14+static void
15+usage(void)
16+{
17+ eprintf("usage: %s\n", argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+ struct utmpx utx;
24+ FILE *ufp;
25+ struct sysinfo info;
26+ time_t tmptime;
27+ struct tm *now;
28+ unsigned int days, hours, minutes;
29+ int nusers = 0;
30+ size_t n;
31+
32+ ARGBEGIN {
33+ default:
34+ usage();
35+ } ARGEND;
36+
37+ if (sysinfo(&info) < 0)
38+ eprintf("sysinfo:");
39+ time(&tmptime);
40+ now = localtime(&tmptime);
41+ printf(" %02d:%02d:%02d up ", now->tm_hour, now->tm_min, now->tm_sec);
42+ info.uptime /= 60;
43+ minutes = info.uptime % 60;
44+ info.uptime /= 60;
45+ hours = info.uptime % 24;
46+ days = info.uptime / 24;
47+ if (days)
48+ printf("%d day%s, ", days, days != 1 ? "s" : "");
49+ if (hours)
50+ printf("%2d:%02d, ", hours, minutes);
51+ else
52+ printf("%d min, ", minutes);
53+
54+ if ((ufp = fopen(UTMP_PATH, "r"))) {
55+ while ((n = fread(&utx, sizeof(utx), 1, ufp)) > 0) {
56+ if (!utx.ut_user[0])
57+ continue;
58+ if (utx.ut_type != USER_PROCESS)
59+ continue;
60+ nusers++;
61+ }
62+ if (ferror(ufp))
63+ eprintf("%s: read error:", UTMP_PATH);
64+ fclose(ufp);
65+ printf(" %d user%s, ", nusers, nusers != 1 ? "s" : "");
66+ }
67+
68+ printf(" load average: %.02f, %.02f, %.02f\n",
69+ info.loads[0] / 65536.0f,
70+ info.loads[1] / 65536.0f,
71+ info.loads[2] / 65536.0f);
72+
73+ return 0;
74+}
+52,
-0
1@@ -0,0 +1,52 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+#include <sys/stat.h>
5+#include <sys/ioctl.h>
6+
7+#include <fcntl.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+#define CONSOLE "/dev/console"
15+
16+#define VT_LOCKSWITCH 0x560B /* disallow vt switching */
17+#define VT_UNLOCKSWITCH 0x560C /* allow vt switching */
18+
19+static void
20+usage(void)
21+{
22+ eprintf("usage: %s n | y\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+ int fd;
29+ int allow;
30+
31+ ARGBEGIN {
32+ default:
33+ usage();
34+ } ARGEND;
35+
36+ if (argc != 1)
37+ usage();
38+
39+ if (!strcmp(argv[0], "y"))
40+ allow = 1;
41+ else if (!strcmp(argv[0], "n"))
42+ allow = 0;
43+ else
44+ usage();
45+
46+ if ((fd = open(CONSOLE, O_WRONLY)) < 0)
47+ eprintf("open %s:", CONSOLE);
48+ if (ioctl(fd, allow ? VT_UNLOCKSWITCH : VT_LOCKSWITCH) < 0)
49+ eprintf("cannot %s VT switch:",
50+ allow ? "unlock" : "lock");
51+ close(fd);
52+ return 0;
53+}
+329,
-0
1@@ -0,0 +1,329 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "arg.h"
5+
6+#include <arpa/inet.h>
7+#include <ctype.h>
8+#include <errno.h>
9+#include <netdb.h>
10+#include <netinet/in.h>
11+#include <resolv.h>
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <string.h>
15+#include <sys/socket.h>
16+#include <sys/time.h>
17+#include <sys/types.h>
18+#include <unistd.h>
19+
20+struct RRType {
21+ const char *name;
22+ const char *msg;
23+ int type;
24+};
25+
26+static const struct RRType rrtypes[] = {
27+ { "A", "has address", 1 },
28+ { "NS", "name server", 2 },
29+ { "CNAME", "is a nickname for", 5 },
30+ { "SOA", "start of authority", 6 },
31+ { "PTR", "domain name pointer", 12 },
32+ { "MX", "mail is handled by", 15 },
33+ { "TXT", "descriptive text", 16 },
34+ { "AAAA", "has IPv6 address", 28 },
35+ { "SRV", "has SRV record", 33 },
36+ { "ANY", "has ANY record", 255 }
37+};
38+
39+static void
40+usage(void)
41+{
42+ eprintf("usage: %s [-t type] name [server]\n", argv0);
43+}
44+
45+static int
46+load_nameservers(char **ns, int max_ns)
47+{
48+ FILE *fp = fopen("/etc/resolv.conf", "r");
49+ char line[256];
50+ char *p, *end;
51+ int count = 0;
52+
53+ if (!fp)
54+ return 0;
55+
56+ while (fgets(line, sizeof(line), fp) && count < max_ns) {
57+ if (strncmp(line, "nameserver", 10) == 0 && isspace(line[10])) {
58+ p = line + 11;
59+ while (isspace(*p))
60+ p++;
61+ end = p;
62+ while (*end && !isspace(*end) && *end != '#')
63+ end++;
64+ *end = '\0';
65+ if (*p) {
66+ ns[count++] = estrdup(p);
67+ }
68+ }
69+ }
70+ fclose(fp);
71+ return count;
72+}
73+
74+static char *
75+reverse_ip(const char *ip_str, int *type)
76+{
77+ struct in_addr addr4;
78+ struct in6_addr addr6;
79+ unsigned char *p;
80+ char *buf = emalloc(256);
81+ int i, j;
82+
83+ if (inet_pton(AF_INET, ip_str, &addr4) > 0) {
84+ p = (unsigned char *)&addr4.s_addr;
85+ sprintf(buf, "%d.%d.%d.%d.in-addr.arpa", p[3], p[2], p[1], p[0]);
86+ *type = 12;
87+ return buf;
88+ } else if (inet_pton(AF_INET6, ip_str, &addr6) > 0) {
89+ p = (unsigned char *)&addr6.s6_addr;
90+ j = 0;
91+ for (i = 15; i >= 0; i--) {
92+ j += sprintf(buf + j, "%x.%x.", p[i] & 15, p[i] >> 4);
93+ }
94+ strcpy(buf + j, "ip6.arpa");
95+ *type = 12;
96+ return buf;
97+ }
98+
99+ free(buf);
100+ return NULL;
101+}
102+
103+static int
104+send_query(const char *ns, const char *name, int type, unsigned char *resp, int resp_len)
105+{
106+ struct addrinfo hints, *res;
107+ unsigned char query[512];
108+ struct timeval tv;
109+ int qlen;
110+ int sock = -1;
111+ int r;
112+
113+ qlen = res_mkquery(0, name, 1, type, NULL, 0, NULL, query, sizeof(query));
114+ if (qlen < 0) {
115+ weprintf("res_mkquery failed for %s\n", name);
116+ return -1;
117+ }
118+
119+ memset(&hints, 0, sizeof(hints));
120+ hints.ai_family = AF_UNSPEC;
121+ hints.ai_socktype = SOCK_DGRAM;
122+
123+ r = getaddrinfo(ns, "53", &hints, &res);
124+ if (r != 0) {
125+ weprintf("getaddrinfo %s: %s\n", ns, gai_strerror(r));
126+ return -1;
127+ }
128+
129+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
130+ if (sock < 0) {
131+ freeaddrinfo(res);
132+ return -1;
133+ }
134+
135+ tv.tv_sec = 5;
136+ tv.tv_usec = 0;
137+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
138+
139+ if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
140+ close(sock);
141+ freeaddrinfo(res);
142+ return -1;
143+ }
144+
145+ if (send(sock, query, qlen, 0) < 0) {
146+ close(sock);
147+ freeaddrinfo(res);
148+ return -1;
149+ }
150+
151+ r = recv(sock, resp, resp_len, 0);
152+ close(sock);
153+ freeaddrinfo(res);
154+
155+ return r;
156+}
157+
158+static unsigned short
159+peek_be(const unsigned char *p)
160+{
161+ return (p[0] << 8) | p[1];
162+}
163+
164+static int
165+parse_response(const unsigned char *resp, int resp_len, const char *query_name)
166+{
167+ const unsigned char *p;
168+ char name[256];
169+ char target[256];
170+ char ipv6[64];
171+ char mname[256], rname[256];
172+ const char *err;
173+ const char *msg;
174+ struct in_addr a;
175+ int rcode, qdcount, ancount;
176+ int i, n, type, rdlen, pref, n1, n2;
177+ unsigned int ttl;
178+
179+ if (resp_len < 12) {
180+ weprintf("response too short: %d\n", resp_len);
181+ return -1;
182+ }
183+
184+ rcode = resp[3] & 0x0f;
185+ if (rcode != 0) {
186+ err = "Unknown error";
187+ switch (rcode) {
188+ case 1: err = "Format error"; break;
189+ case 2: err = "Server failure"; break;
190+ case 3: err = "Non-existent domain"; break;
191+ case 4: err = "Not implemented"; break;
192+ case 5: err = "Refused"; break;
193+ }
194+ eprintf("Host not found: %s\n", err);
195+ }
196+
197+ qdcount = peek_be(resp + 4);
198+ ancount = peek_be(resp + 6);
199+
200+ p = resp + 12;
201+ for (i = 0; i < qdcount; i++) {
202+ n = dn_expand(resp, resp + resp_len, p, name, sizeof(name));
203+ if (n < 0)
204+ return -1;
205+ p += n + 4;
206+ }
207+
208+ if (ancount == 0) {
209+ printf("%s has no records\n", query_name);
210+ return 0;
211+ }
212+
213+ for (i = 0; i < ancount; i++) {
214+ n = dn_expand(resp, resp + resp_len, p, name, sizeof(name));
215+ if (n < 0)
216+ return -1;
217+ p += n;
218+ type = peek_be(p);
219+ ttl = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
220+ rdlen = peek_be(p + 8);
221+ p += 10;
222+
223+ (void)ttl;
224+
225+ if (type == 1) {
226+ memcpy(&a, p, 4);
227+ printf("%s has address %s\n", name, inet_ntoa(a));
228+ } else if (type == 28) {
229+ inet_ntop(AF_INET6, p, ipv6, sizeof(ipv6));
230+ printf("%s has IPv6 address %s\n", name, ipv6);
231+ } else if (type == 2 || type == 5 || type == 12) {
232+ dn_expand(resp, resp + resp_len, p, target, sizeof(target));
233+ msg = "has record";
234+ if (type == 2) msg = "name server";
235+ else if (type == 5) msg = "is a nickname for";
236+ else if (type == 12) msg = "domain name pointer";
237+ printf("%s %s %s\n", name, msg, target);
238+ } else if (type == 15) {
239+ pref = peek_be(p);
240+ dn_expand(resp, resp + resp_len, p + 2, target, sizeof(target));
241+ printf("%s mail is handled by %d %s\n", name, pref, target);
242+ } else if (type == 16) {
243+ printf("%s descriptive text \"%.*s\"\n", name, (int)p[0], (char *)(p + 1));
244+ } else if (type == 6) {
245+ n1 = dn_expand(resp, resp + resp_len, p, mname, sizeof(mname));
246+ n2 = dn_expand(resp, resp + resp_len, p + n1, rname, sizeof(rname));
247+ (void)n2;
248+ printf("%s start of authority %s %s\n", name, mname, rname);
249+ } else {
250+ printf("%s has unsupported record type %d\n", name, type);
251+ }
252+
253+ p += rdlen;
254+ }
255+
256+ return 0;
257+}
258+
259+int
260+main(int argc, char *argv[])
261+{
262+ unsigned char resp[65536];
263+ char *ns[8];
264+ char *tflag = NULL;
265+ char *name;
266+ char *query_name;
267+ char *rev;
268+ int ns_count = 0;
269+ int type = 1;
270+ int i, r;
271+
272+ ARGBEGIN {
273+ case 't':
274+ tflag = EARGF(usage());
275+ break;
276+ default:
277+ usage();
278+ } ARGEND
279+
280+ if (argc < 1)
281+ usage();
282+
283+ query_name = argv[0];
284+
285+ if (argc > 1) {
286+ ns[0] = argv[1];
287+ ns_count = 1;
288+ } else {
289+ ns_count = load_nameservers(ns, 8);
290+ if (ns_count == 0)
291+ eprintf("no nameservers found in /etc/resolv.conf\n");
292+ }
293+
294+ rev = reverse_ip(query_name, &type);
295+ if (rev) {
296+ name = rev;
297+ } else {
298+ name = query_name;
299+ if (tflag) {
300+ type = -1;
301+ for (i = 0; i < (int)LEN(rrtypes); i++) {
302+ if (strcasecmp(tflag, rrtypes[i].name) == 0) {
303+ type = rrtypes[i].type;
304+ break;
305+ }
306+ }
307+ if (type == -1)
308+ eprintf("invalid record type: %s\n", tflag);
309+ }
310+ }
311+
312+ for (i = 0; i < ns_count; i++) {
313+ r = send_query(ns[i], name, type, resp, sizeof(resp));
314+ if (r > 0) {
315+ parse_response(resp, r, query_name);
316+ break;
317+ }
318+ }
319+
320+ if (rev)
321+ free(rev);
322+
323+ if (argc == 1) {
324+ for (i = 0; i < ns_count; i++) {
325+ free(ns[i]);
326+ }
327+ }
328+
329+ return r > 0 ? 0 : 1;
330+}
+291,
-0
1@@ -0,0 +1,291 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "arg.h"
5+
6+#include <arpa/inet.h>
7+#include <ctype.h>
8+#include <dirent.h>
9+#include <errno.h>
10+#include <fcntl.h>
11+#include <netdb.h>
12+#include <netinet/in.h>
13+#include <stdio.h>
14+#include <stdlib.h>
15+#include <string.h>
16+#include <sys/socket.h>
17+#include <sys/stat.h>
18+#include <sys/types.h>
19+#include <time.h>
20+#include <unistd.h>
21+
22+static void
23+usage(void)
24+{
25+ eprintf("usage: %s [-e string] [-d string] [-v] [dir]\n", argv0);
26+}
27+
28+static char *
29+url_decode(char *s)
30+{
31+ char *r, *w;
32+ unsigned int val;
33+
34+ for (r = w = s; *r; ) {
35+ if (*r == '%' && isxdigit((unsigned char)r[1]) && isxdigit((unsigned char)r[2])) {
36+ sscanf(r + 1, "%2x", &val);
37+ *w++ = val;
38+ r += 3;
39+ } else if (*r == '+') {
40+ *w++ = ' ';
41+ r++;
42+ } else {
43+ *w++ = *r++;
44+ }
45+ }
46+ *w = '\0';
47+ return s;
48+}
49+
50+static char *
51+url_encode(const char *s)
52+{
53+ char *buf = emalloc(strlen(s) * 3 + 1);
54+ char *w = buf;
55+ const char *r = s;
56+
57+ while (*r) {
58+ if (isalnum((unsigned char)*r) || strchr("-._~", *r)) {
59+ *w++ = *r++;
60+ } else {
61+ w += sprintf(w, "%%%02X", (unsigned char)*r);
62+ r++;
63+ }
64+ }
65+ *w = '\0';
66+ return buf;
67+}
68+
69+static void
70+send_error(int status, const char *msg)
71+{
72+ printf("HTTP/1.1 %d %s\r\n"
73+ "Content-Type: text/html; charset=UTF-8\r\n"
74+ "Connection: close\r\n\r\n", status, msg);
75+ printf("<html><head><title>%d %s</title></head>"
76+ "<body><h3>%d %s</h3></body></html>\n", status, msg, status, msg);
77+}
78+
79+static int
80+is_under(const char *file, const char *dir)
81+{
82+ char *rfile = realpath(file, NULL);
83+ char *rdir = realpath(dir, NULL);
84+ int rc = 0;
85+ size_t len;
86+
87+ if (rfile && rdir) {
88+ len = strlen(rdir);
89+ if (strncmp(rfile, rdir, len) == 0) {
90+ if (rfile[len] == '\0' || rfile[len] == '/' || (len > 0 && rdir[len - 1] == '/'))
91+ rc = 1;
92+ }
93+ }
94+ free(rfile);
95+ free(rdir);
96+ return rc;
97+}
98+
99+static const char *
100+get_mime_type(const char *file)
101+{
102+ const char *ext = strrchr(file, '.');
103+ if (!ext)
104+ return "application/octet-stream";
105+ ext++;
106+
107+ if (strcasecmp(ext, "html") == 0 || strcasecmp(ext, "htm") == 0)
108+ return "text/html; charset=UTF-8";
109+ if (strcasecmp(ext, "css") == 0)
110+ return "text/css";
111+ if (strcasecmp(ext, "js") == 0)
112+ return "application/javascript";
113+ if (strcasecmp(ext, "png") == 0)
114+ return "image/png";
115+ if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0)
116+ return "image/jpeg";
117+ if (strcasecmp(ext, "gif") == 0)
118+ return "image/gif";
119+ if (strcasecmp(ext, "txt") == 0)
120+ return "text/plain; charset=UTF-8";
121+ if (strcasecmp(ext, "pdf") == 0)
122+ return "application/pdf";
123+ if (strcasecmp(ext, "zip") == 0)
124+ return "application/zip";
125+
126+ return "application/octet-stream";
127+}
128+
129+static void
130+handle_connection(void)
131+{
132+ struct stat st, st_idx;
133+ struct dirent *de;
134+ DIR *dir;
135+ char line[4096];
136+ char method[32], path[2048], proto[32];
137+ char index_path[sizeof(path) + 32];
138+ char file_buf[8192];
139+ char date_buf[64];
140+ const char *mime_type;
141+ char *query, *p, *enc;
142+ ssize_t n_read;
143+ size_t len;
144+ int fd;
145+
146+ if (!fgets(line, sizeof(line), stdin))
147+ return;
148+
149+ if (sscanf(line, "%31s %2047s %31s", method, path, proto) != 3) {
150+ send_error(400, "Bad Request");
151+ return;
152+ }
153+
154+ while (fgets(line, sizeof(line), stdin)) {
155+ if (line[0] == '\r' || line[0] == '\n')
156+ break;
157+ }
158+
159+ if (strcasecmp(method, "GET") != 0) {
160+ send_error(501, "Not Implemented");
161+ return;
162+ }
163+
164+ url_decode(path);
165+
166+ query = strchr(path, '?');
167+ if (query) {
168+ *query = '\0';
169+ setenv("QUERY_STRING", query + 1, 1);
170+ } else {
171+ unsetenv("QUERY_STRING");
172+ }
173+
174+ p = path;
175+ while (*p == '/')
176+ p++;
177+ if (*p == '\0')
178+ p = ".";
179+
180+ if (stat(p, &st) < 0) {
181+ send_error(404, "Not Found");
182+ return;
183+ }
184+
185+ if (!is_under(p, ".")) {
186+ send_error(403, "Forbidden");
187+ return;
188+ }
189+
190+ if (S_ISDIR(st.st_mode)) {
191+ len = strlen(path);
192+ if (len > 0 && path[len - 1] != '/') {
193+ printf("HTTP/1.1 302 Found\r\n"
194+ "Location: %s/\r\n"
195+ "Connection: close\r\n\r\n", path);
196+ return;
197+ }
198+
199+ snprintf(index_path, sizeof(index_path), "%s/index.html", p);
200+ if (stat(index_path, &st_idx) == 0 && S_ISREG(st_idx.st_mode)) {
201+ p = index_path;
202+ st = st_idx;
203+ goto serve_file;
204+ }
205+
206+ dir = opendir(p);
207+ if (!dir) {
208+ send_error(403, "Forbidden");
209+ return;
210+ }
211+
212+ printf("HTTP/1.1 200 OK\r\n"
213+ "Content-Type: text/html; charset=UTF-8\r\n"
214+ "Connection: close\r\n\r\n");
215+ printf("<html><head><title>Index of %s</title></head><body>\n", path);
216+ printf("<h3>Index of %s</h3><hr><pre>\n", path);
217+
218+ while ((de = readdir(dir))) {
219+ if (strcmp(de->d_name, ".") == 0)
220+ continue;
221+ enc = url_encode(de->d_name);
222+ printf("<a href=\"%s\">%s</a>\n", enc, de->d_name);
223+ free(enc);
224+ }
225+ printf("</pre><hr></body></html>\n");
226+ closedir(dir);
227+ return;
228+ }
229+
230+serve_file:
231+ fd = open(p, O_RDONLY);
232+ if (fd < 0) {
233+ send_error(403, "Forbidden");
234+ return;
235+ }
236+
237+ mime_type = get_mime_type(p);
238+ strftime(date_buf, sizeof(date_buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&st.st_mtime));
239+
240+ printf("HTTP/1.1 200 OK\r\n"
241+ "Content-Type: %s\r\n"
242+ "Content-Length: %lld\r\n"
243+ "Last-Modified: %s\r\n"
244+ "Connection: close\r\n\r\n",
245+ mime_type, (long long)st.st_size, date_buf);
246+
247+ while ((n_read = read(fd, file_buf, sizeof(file_buf))) > 0) {
248+ writeall(1, file_buf, n_read);
249+ }
250+ close(fd);
251+}
252+
253+int
254+main(int argc, char *argv[])
255+{
256+ char *eflag = NULL;
257+ char *dflag = NULL;
258+ char *enc;
259+
260+ ARGBEGIN {
261+ case 'e':
262+ eflag = EARGF(usage());
263+ break;
264+ case 'd':
265+ dflag = EARGF(usage());
266+ break;
267+ case 'v':
268+ break;
269+ default:
270+ usage();
271+ } ARGEND
272+
273+ if (eflag) {
274+ enc = url_encode(eflag);
275+ printf("%s\n", enc);
276+ free(enc);
277+ return 0;
278+ }
279+
280+ if (dflag) {
281+ printf("%s\n", url_decode(dflag));
282+ return 0;
283+ }
284+
285+ if (argc > 0) {
286+ if (chdir(argv[0]) < 0)
287+ eprintf("chdir %s:\n", argv[0]);
288+ }
289+
290+ handle_connection();
291+ return 0;
292+}
+392,
-0
1@@ -0,0 +1,392 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "arg.h"
5+
6+#include <arpa/inet.h>
7+#include <ctype.h>
8+#include <errno.h>
9+#include <net/if.h>
10+#include <net/if_arp.h>
11+#include <netinet/in.h>
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <string.h>
15+#include <sys/ioctl.h>
16+#include <sys/socket.h>
17+#include <sys/types.h>
18+#include <unistd.h>
19+
20+static void
21+usage(void)
22+{
23+ eprintf("usage: %s [-a] [interface [action ...]]\n", argv0);
24+}
25+
26+static void
27+print_ipv6(const char *name)
28+{
29+ FILE *fp = fopen("/proc/net/if_inet6", "r");
30+ char line[256];
31+ char addr_hex[40];
32+ char ifname[IFNAMSIZ];
33+ unsigned int ifindex, plen, scope, flags;
34+ int i, j;
35+ char ipv6_str[40];
36+ const char *scope_str;
37+
38+ if (!fp)
39+ return;
40+
41+ while (fgets(line, sizeof(line), fp)) {
42+ if (sscanf(line, "%32s %x %x %x %x %15s", addr_hex, &ifindex, &plen, &scope, &flags, ifname) == 6) {
43+ if (strcmp(name, ifname) == 0) {
44+ j = 0;
45+ for (i = 0; i < 32; i++) {
46+ ipv6_str[j++] = addr_hex[i];
47+ if (i > 0 && i < 31 && (i % 4 == 3))
48+ ipv6_str[j++] = ':';
49+ }
50+ ipv6_str[j] = '\0';
51+
52+ scope_str = "Unknown";
53+ switch (scope) {
54+ case 0x00: scope_str = "Global"; break;
55+ case 0x10: scope_str = "Host"; break;
56+ case 0x20: scope_str = "Link"; break;
57+ case 0x40: scope_str = "Site"; break;
58+ case 0x80: scope_str = "Compat"; break;
59+ }
60+ printf(" inet6 addr: %s/%d Scope:%s\n", ipv6_str, plen, scope_str);
61+ }
62+ }
63+ }
64+ fclose(fp);
65+}
66+
67+static void
68+display_interface(int sock, const char *name)
69+{
70+ struct ifreq ifr;
71+ struct sockaddr_in *sin;
72+ unsigned char *hwaddr;
73+ FILE *fp;
74+ char line[256];
75+ char *p, *ifname;
76+ short flags;
77+ int mtu = 0;
78+ int metric = 0;
79+ unsigned long long rx_bytes, rx_packets, rx_errs, rx_drop;
80+ unsigned long long tx_bytes, tx_packets, tx_errs, tx_drop;
81+
82+ memset(&ifr, 0, sizeof(ifr));
83+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
84+
85+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
86+ weprintf("ioctl SIOCGIFFLAGS %s:\n", name);
87+ return;
88+ }
89+ flags = ifr.ifr_flags;
90+
91+ printf("%-9s ", name);
92+
93+ if (ioctl(sock, SIOCGIFHWADDR, &ifr) >= 0) {
94+ hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
95+ printf("Link encap:");
96+ switch (ifr.ifr_hwaddr.sa_family) {
97+ case ARPHRD_ETHER:
98+ printf("Ethernet HWaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
99+ hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
100+ break;
101+ case ARPHRD_LOOPBACK:
102+ printf("Local Loopback\n");
103+ break;
104+ default:
105+ printf("UNSPEC\n");
106+ break;
107+ }
108+ } else {
109+ printf("Link encap:UNSPEC\n");
110+ }
111+
112+ memset(&ifr, 0, sizeof(ifr));
113+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
114+ if (ioctl(sock, SIOCGIFADDR, &ifr) >= 0) {
115+ sin = (struct sockaddr_in *)&ifr.ifr_addr;
116+ printf(" inet addr:%s", inet_ntoa(sin->sin_addr));
117+
118+ memset(&ifr, 0, sizeof(ifr));
119+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
120+ if (ioctl(sock, SIOCGIFBRDADDR, &ifr) >= 0) {
121+ sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;
122+ printf(" Bcast:%s", inet_ntoa(sin->sin_addr));
123+ }
124+
125+ memset(&ifr, 0, sizeof(ifr));
126+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
127+ if (ioctl(sock, SIOCGIFNETMASK, &ifr) >= 0) {
128+ sin = (struct sockaddr_in *)&ifr.ifr_netmask;
129+ printf(" Mask:%s", inet_ntoa(sin->sin_addr));
130+ }
131+ printf("\n");
132+ }
133+
134+ print_ipv6(name);
135+
136+ printf(" ");
137+ if (flags & IFF_UP) printf("UP ");
138+ if (flags & IFF_BROADCAST) printf("BROADCAST ");
139+ if (flags & IFF_DEBUG) printf("DEBUG ");
140+ if (flags & IFF_LOOPBACK) printf("LOOPBACK ");
141+ if (flags & IFF_POINTOPOINT) printf("POINTOPOINT ");
142+ if (flags & IFF_RUNNING) printf("RUNNING ");
143+ if (flags & IFF_NOARP) printf("NOARP ");
144+ if (flags & IFF_PROMISC) printf("PROMISC ");
145+ if (flags & IFF_ALLMULTI) printf("ALLMULTI ");
146+ if (flags & IFF_MULTICAST) printf("MULTICAST ");
147+
148+ memset(&ifr, 0, sizeof(ifr));
149+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
150+ if (ioctl(sock, SIOCGIFMTU, &ifr) >= 0)
151+ mtu = ifr.ifr_mtu;
152+ if (ioctl(sock, SIOCGIFMETRIC, &ifr) >= 0)
153+ metric = ifr.ifr_metric;
154+ printf(" MTU:%d Metric:%d\n", mtu, metric);
155+
156+ fp = fopen("/proc/net/dev", "r");
157+ if (fp) {
158+ while (fgets(line, sizeof(line), fp)) {
159+ p = strchr(line, ':');
160+ if (p) {
161+ *p = '\0';
162+ ifname = line;
163+ while (isspace(*ifname))
164+ ifname++;
165+ if (strcmp(ifname, name) == 0) {
166+ if (sscanf(p + 1, "%llu %llu %llu %llu %*u %*u %*u %*u %llu %llu %llu %llu",
167+ &rx_bytes, &rx_packets, &rx_errs, &rx_drop,
168+ &tx_bytes, &tx_packets, &tx_errs, &tx_drop) == 8) {
169+ printf(" RX packets:%llu errors:%llu dropped:%llu overruns:0 frame:0\n",
170+ rx_packets, rx_errs, rx_drop);
171+ printf(" TX packets:%llu errors:%llu dropped:%llu overruns:0 carrier:0\n",
172+ tx_packets, tx_errs, tx_drop);
173+ printf(" RX bytes:%llu TX bytes:%llu\n", rx_bytes, tx_bytes);
174+ }
175+ break;
176+ }
177+ }
178+ }
179+ fclose(fp);
180+ }
181+ printf("\n");
182+}
183+
184+static void
185+list_interfaces(int sock, int all)
186+{
187+ FILE *fp = fopen("/proc/net/dev", "r");
188+ struct ifreq ifr;
189+ char line[256];
190+ char *p, *name;
191+ int line_num = 0;
192+
193+ if (!fp)
194+ eprintf("fopen /proc/net/dev:\n");
195+
196+ while (fgets(line, sizeof(line), fp)) {
197+ line_num++;
198+ if (line_num <= 2)
199+ continue;
200+ p = strchr(line, ':');
201+ if (p) {
202+ *p = '\0';
203+ name = line;
204+ while (isspace(*name))
205+ name++;
206+ memset(&ifr, 0, sizeof(ifr));
207+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
208+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) >= 0) {
209+ if (all || (ifr.ifr_flags & IFF_UP)) {
210+ display_interface(sock, name);
211+ }
212+ }
213+ }
214+ }
215+ fclose(fp);
216+}
217+
218+int
219+main(int argc, char *argv[])
220+{
221+ struct ifreq ifr;
222+ struct sockaddr_in *sin;
223+ char *name;
224+ char *arg;
225+ char *slash;
226+ int aflag = 0;
227+ int sock = -1;
228+ int i = 1;
229+ int prefix;
230+ unsigned int mask;
231+
232+ ARGBEGIN {
233+ case 'a':
234+ aflag = 1;
235+ break;
236+ default:
237+ usage();
238+ } ARGEND
239+
240+ sock = socket(AF_INET, SOCK_DGRAM, 0);
241+ if (sock < 0)
242+ eprintf("socket:\n");
243+
244+ if (argc == 0) {
245+ list_interfaces(sock, aflag);
246+ close(sock);
247+ return 0;
248+ }
249+
250+ name = argv[0];
251+
252+ if (argc == 1) {
253+ display_interface(sock, name);
254+ close(sock);
255+ return 0;
256+ }
257+
258+ memset(&ifr, 0, sizeof(ifr));
259+ strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
260+
261+ while (i < argc) {
262+ arg = argv[i];
263+
264+ if (strcmp(arg, "up") == 0) {
265+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
266+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
267+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
268+ i++;
269+ } else if (strcmp(arg, "down") == 0) {
270+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
271+ ifr.ifr_flags &= ~IFF_UP;
272+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
273+ i++;
274+ } else if (strcmp(arg, "netmask") == 0) {
275+ if (i + 1 >= argc) eprintf("netmask needs an address\n");
276+ sin = (struct sockaddr_in *)&ifr.ifr_netmask;
277+ sin->sin_family = AF_INET;
278+ if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
279+ eprintf("invalid address: %s\n", argv[i + 1]);
280+ if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) eprintf("ioctl SIOCSIFNETMASK:");
281+ i += 2;
282+ } else if (strcmp(arg, "broadcast") == 0) {
283+ if (i + 1 >= argc) eprintf("broadcast needs an address\n");
284+ sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;
285+ sin->sin_family = AF_INET;
286+ if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
287+ eprintf("invalid address: %s\n", argv[i + 1]);
288+ if (ioctl(sock, SIOCSIFBRDADDR, &ifr) < 0) eprintf("ioctl SIOCSIFBRDADDR:");
289+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
290+ ifr.ifr_flags |= IFF_BROADCAST;
291+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
292+ i += 2;
293+ } else if (strcmp(arg, "mtu") == 0) {
294+ if (i + 1 >= argc) eprintf("mtu needs a value\n");
295+ ifr.ifr_mtu = atoi(argv[i + 1]);
296+ if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) eprintf("ioctl SIOCSIFMTU:");
297+ i += 2;
298+ } else if (strcmp(arg, "metric") == 0) {
299+ if (i + 1 >= argc) eprintf("metric needs a value\n");
300+ ifr.ifr_metric = atoi(argv[i + 1]);
301+ if (ioctl(sock, SIOCSIFMETRIC, &ifr) < 0) eprintf("ioctl SIOCSIFMETRIC:");
302+ i += 2;
303+ } else if (strcmp(arg, "txqueuelen") == 0) {
304+ if (i + 1 >= argc) eprintf("txqueuelen needs a value\n");
305+ ifr.ifr_qlen = atoi(argv[i + 1]);
306+ if (ioctl(sock, SIOCSIFTXQLEN, &ifr) < 0) eprintf("ioctl SIOCSIFTXQLEN:");
307+ i += 2;
308+ } else if (strcmp(arg, "dstaddr") == 0 || strcmp(arg, "pointopoint") == 0) {
309+ if (i + 1 >= argc) eprintf("%s needs an address\n", arg);
310+ sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
311+ sin->sin_family = AF_INET;
312+ if (inet_pton(AF_INET, argv[i + 1], &sin->sin_addr) <= 0)
313+ eprintf("invalid address: %s\n", argv[i + 1]);
314+ if (ioctl(sock, SIOCSIFDSTADDR, &ifr) < 0) eprintf("ioctl SIOCSIFDSTADDR:");
315+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
316+ ifr.ifr_flags |= IFF_POINTOPOINT;
317+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
318+ i += 2;
319+ } else if (strcmp(arg, "arp") == 0) {
320+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
321+ ifr.ifr_flags &= ~IFF_NOARP;
322+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
323+ i++;
324+ } else if (strcmp(arg, "-arp") == 0) {
325+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
326+ ifr.ifr_flags |= IFF_NOARP;
327+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
328+ i++;
329+ } else if (strcmp(arg, "promisc") == 0) {
330+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
331+ ifr.ifr_flags |= IFF_PROMISC;
332+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
333+ i++;
334+ } else if (strcmp(arg, "-promisc") == 0) {
335+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
336+ ifr.ifr_flags &= ~IFF_PROMISC;
337+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
338+ i++;
339+ } else if (strcmp(arg, "allmulti") == 0) {
340+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
341+ ifr.ifr_flags |= IFF_ALLMULTI;
342+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
343+ i++;
344+ } else if (strcmp(arg, "-allmulti") == 0) {
345+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
346+ ifr.ifr_flags &= ~IFF_ALLMULTI;
347+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
348+ i++;
349+ } else if (strcmp(arg, "multicast") == 0) {
350+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
351+ ifr.ifr_flags |= IFF_MULTICAST;
352+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
353+ i++;
354+ } else if (strcmp(arg, "-multicast") == 0) {
355+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
356+ ifr.ifr_flags &= ~IFF_MULTICAST;
357+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
358+ i++;
359+ } else {
360+ sin = (struct sockaddr_in *)&ifr.ifr_addr;
361+ sin->sin_family = AF_INET;
362+ slash = strchr(arg, '/');
363+ prefix = -1;
364+ if (slash) {
365+ *slash = '\0';
366+ prefix = atoi(slash + 1);
367+ }
368+ if (inet_pton(AF_INET, arg, &sin->sin_addr) <= 0) {
369+ eprintf("unknown action or invalid address: %s\n", arg);
370+ }
371+ if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) eprintf("ioctl SIOCSIFADDR:");
372+
373+ if (prefix >= 0) {
374+ mask = 0;
375+ if (prefix > 0)
376+ mask = htonl(~0U << (32 - prefix));
377+ sin = (struct sockaddr_in *)&ifr.ifr_netmask;
378+ sin->sin_family = AF_INET;
379+ sin->sin_addr.s_addr = mask;
380+ if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) eprintf("ioctl SIOCSIFNETMASK:");
381+ }
382+
383+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCGIFFLAGS:");
384+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
385+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) eprintf("ioctl SIOCSIFFLAGS:");
386+
387+ i++;
388+ }
389+ }
390+
391+ close(sock);
392+ return 0;
393+}
+222,
-0
1@@ -0,0 +1,222 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/socket.h>
4+#include <sys/types.h>
5+
6+#include <arpa/inet.h>
7+#include <netinet/in.h>
8+
9+#include <errno.h>
10+#include <fcntl.h>
11+#include <netdb.h>
12+#include <poll.h>
13+#include <stdio.h>
14+#include <stdlib.h>
15+#include <string.h>
16+#include <unistd.h>
17+
18+#include "util.h"
19+
20+static void
21+usage(void)
22+{
23+ eprintf("usage: %s [-lu] [-p localport] [host] [port]\n", argv0);
24+}
25+
26+static int
27+resolve(const char *host, const char *port, int family, int socktype,
28+ int passive, struct sockaddr_storage *addr, socklen_t *addrlen)
29+{
30+ struct addrinfo hints, *res;
31+ int r;
32+
33+ memset(&hints, 0, sizeof(hints));
34+ hints.ai_family = family;
35+ hints.ai_socktype = socktype;
36+ if (passive)
37+ hints.ai_flags = AI_PASSIVE;
38+
39+ if ((r = getaddrinfo(host, port, &hints, &res)) != 0) {
40+ weprintf("getaddrinfo: %s\n", gai_strerror(r));
41+ return -1;
42+ }
43+
44+ memcpy(addr, res->ai_addr, res->ai_addrlen);
45+ *addrlen = res->ai_addrlen;
46+ freeaddrinfo(res);
47+ return 0;
48+}
49+
50+int
51+main(int argc, char *argv[])
52+{
53+ struct sockaddr_storage local_addr, remote_addr;
54+ socklen_t local_len = sizeof(local_addr),
55+ remote_len = sizeof(remote_addr);
56+ struct pollfd fds[2];
57+ int listenfd = -1, sockfd = -1;
58+ int lflag = 0;
59+ int uflag = 0;
60+ char *port = NULL;
61+ char *host = NULL;
62+ char *local_port = NULL;
63+ int socktype;
64+ int n, opt;
65+ char buf[BUFSIZ];
66+
67+ ARGBEGIN
68+ {
69+ case 'l':
70+ lflag = 1;
71+ break;
72+ case 'p':
73+ local_port = EARGF(usage());
74+ break;
75+ case 'u':
76+ uflag = 1;
77+ break;
78+ default:
79+ usage();
80+ }
81+ ARGEND
82+
83+ socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
84+
85+ if (lflag) {
86+ /* server mode */
87+ if (!local_port) {
88+ if (argc == 1) {
89+ local_port = argv[0];
90+ argc = 0;
91+ } else {
92+ usage();
93+ }
94+ }
95+ memset(&local_addr, 0, sizeof(local_addr));
96+ if (resolve(NULL, local_port, AF_UNSPEC, socktype, 1,
97+ &local_addr, &local_len) < 0)
98+ return 1;
99+
100+ listenfd = socket(local_addr.ss_family, socktype, 0);
101+ if (listenfd < 0)
102+ eprintf("socket:");
103+
104+ opt = 1;
105+ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt,
106+ sizeof(opt));
107+
108+ if (bind(listenfd, (struct sockaddr *)&local_addr, local_len) <
109+ 0)
110+ eprintf("bind:");
111+
112+ if (!uflag) {
113+ if (listen(listenfd, 5) < 0)
114+ eprintf("listen:");
115+ sockfd = accept(listenfd,
116+ (struct sockaddr *)&remote_addr,
117+ &remote_len);
118+ if (sockfd < 0)
119+ eprintf("accept:");
120+ close(listenfd);
121+ } else {
122+ sockfd = listenfd;
123+ n = recvfrom(sockfd, buf, sizeof(buf), MSG_PEEK,
124+ (struct sockaddr *)&remote_addr,
125+ &remote_len);
126+ if (n < 0)
127+ eprintf("recvfrom:");
128+ if (connect(sockfd, (struct sockaddr *)&remote_addr,
129+ remote_len) < 0)
130+ eprintf("connect:");
131+ }
132+ } else {
133+ /* client mode */
134+ if (argc != 2)
135+ usage();
136+ host = argv[0];
137+ port = argv[1];
138+
139+ memset(&remote_addr, 0, sizeof(remote_addr));
140+ if (resolve(host, port, AF_UNSPEC, socktype, 0, &remote_addr,
141+ &remote_len) < 0)
142+ return 1;
143+
144+ sockfd = socket(remote_addr.ss_family, socktype, 0);
145+ if (sockfd < 0)
146+ eprintf("socket:");
147+
148+ if (local_port) {
149+ memset(&local_addr, 0, sizeof(local_addr));
150+ if (resolve(NULL, local_port, remote_addr.ss_family,
151+ socktype, 1, &local_addr, &local_len) < 0)
152+ return 1;
153+ opt = 1;
154+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt,
155+ sizeof(opt));
156+ if (bind(sockfd, (struct sockaddr *)&local_addr,
157+ local_len) < 0)
158+ eprintf("bind:");
159+ }
160+
161+ if (connect(sockfd, (struct sockaddr *)&remote_addr,
162+ remote_len) < 0)
163+ eprintf("connect:");
164+ }
165+
166+ fds[0].fd = 0;
167+ fds[0].events = POLLIN;
168+ fds[1].fd = sockfd;
169+ fds[1].events = POLLIN;
170+
171+ while (1) {
172+ if (poll(fds, 2, -1) < 0) {
173+ if (errno == EINTR)
174+ continue;
175+ eprintf("poll:");
176+ }
177+
178+ if (fds[0].revents & POLLIN) {
179+ n = read(0, buf, sizeof(buf));
180+ if (n < 0) {
181+ weprintf("read stdin:");
182+ break;
183+ }
184+ if (n == 0) {
185+ if (!uflag) {
186+ shutdown(sockfd, SHUT_WR);
187+ fds[0].fd = -1;
188+ } else {
189+ break;
190+ }
191+ } else {
192+ if (writeall(sockfd, buf, n) < 0) {
193+ weprintf("write socket:");
194+ break;
195+ }
196+ }
197+ }
198+
199+ if (fds[1].revents & POLLIN) {
200+ n = read(sockfd, buf, sizeof(buf));
201+ if (n < 0) {
202+ weprintf("read socket:");
203+ break;
204+ }
205+ if (n == 0) {
206+ break;
207+ } else {
208+ if (writeall(1, buf, n) < 0) {
209+ weprintf("write stdout:");
210+ break;
211+ }
212+ }
213+ }
214+
215+ if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) ||
216+ (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))) {
217+ break;
218+ }
219+ }
220+
221+ close(sockfd);
222+ return 0;
223+}
+311,
-0
1@@ -0,0 +1,311 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "arg.h"
5+
6+#include <arpa/inet.h>
7+#include <errno.h>
8+#include <netdb.h>
9+#include <netinet/in.h>
10+#include <netinet/ip.h>
11+#include <netinet/ip_icmp.h>
12+#include <poll.h>
13+#include <signal.h>
14+#include <stdio.h>
15+#include <stdlib.h>
16+#include <string.h>
17+#include <sys/socket.h>
18+#include <sys/time.h>
19+#include <sys/types.h>
20+#include <unistd.h>
21+
22+static int keep_running = 1;
23+
24+static void
25+usage(void)
26+{
27+ eprintf("usage: %s [-c count] [-i interval] [-s size] [-t ttl] [-w deadline] [-q] host\n", argv0);
28+}
29+
30+static void
31+sigint_handler(int sig)
32+{
33+ (void)sig;
34+ keep_running = 0;
35+}
36+
37+static unsigned short
38+checksum(unsigned short *addr, int len)
39+{
40+ unsigned long sum = 0;
41+
42+ while (len > 1) {
43+ sum += *addr++;
44+ len -= 2;
45+ }
46+ if (len > 0)
47+ sum += *(unsigned char *)addr;
48+ while (sum >> 16)
49+ sum = (sum & 0xffff) + (sum >> 16);
50+ return ~sum;
51+}
52+
53+static void
54+send_ping(int sock, struct sockaddr_in *dst, int seq, int size)
55+{
56+ struct icmphdr *icmp;
57+ char *packet;
58+ struct timeval tv;
59+ int packlen = sizeof(*icmp) + size;
60+
61+ packet = emalloc(packlen);
62+ memset(packet, 0, packlen);
63+
64+ icmp = (struct icmphdr *)packet;
65+ icmp->type = ICMP_ECHO;
66+ icmp->code = 0;
67+ icmp->un.echo.id = htons(getpid() & 0xffff);
68+ icmp->un.echo.sequence = htons(seq);
69+
70+ /* store timestamp in payload if size is large enough */
71+ if (size >= (int)sizeof(struct timeval)) {
72+ gettimeofday(&tv, NULL);
73+ memcpy(packet + sizeof(*icmp), &tv, sizeof(tv));
74+ }
75+
76+ icmp->checksum = checksum((unsigned short *)packet, packlen);
77+
78+ if (sendto(sock, packet, packlen, 0, (struct sockaddr *)dst, sizeof(*dst)) < 0)
79+ eprintf("sendto:");
80+
81+ free(packet);
82+}
83+
84+static double
85+get_time_ms(void)
86+{
87+ struct timeval tv;
88+ gettimeofday(&tv, NULL);
89+ return (double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0;
90+}
91+
92+static void
93+print_stats(const char *host, int sent, int received, double min_rtt, double max_rtt, double sum_rtt)
94+{
95+ printf("\n--- %s ping statistics ---\n", host);
96+ printf("%d packets transmitted, %d received, %d%% packet loss\n",
97+ sent, received, sent > 0 ? (sent - received) * 100 / sent : 0);
98+ if (received > 0) {
99+ printf("rtt min/avg/max = %.3f/%.3f/%.3f ms\n",
100+ min_rtt, sum_rtt / received, max_rtt);
101+ }
102+}
103+
104+int
105+main(int argc, char *argv[])
106+{
107+ struct addrinfo hints, *res;
108+ struct sockaddr_in dst;
109+ struct sockaddr_in from;
110+ struct pollfd pfd;
111+ struct timeval sent_tv;
112+ struct icmphdr *icmp;
113+ char *cflag = NULL;
114+ char *iflag = NULL;
115+ char *sflag = NULL;
116+ char *tflag = NULL;
117+ char *wflag = NULL;
118+ char *host;
119+ char *rxbuf;
120+ int qflag = 0;
121+ int count = 0;
122+ int size = 56;
123+ int ttl = 0;
124+ int deadline = 0;
125+ int sock = -1;
126+ int is_raw = 1;
127+ int seq = 1;
128+ int sent = 0;
129+ int received = 0;
130+ int r, optval, p_res, hlen;
131+ double interval = 1.0;
132+ double min_rtt = 999999.0;
133+ double max_rtt = 0.0;
134+ double sum_rtt = 0.0;
135+ double start_time, deadline_ms, next_send_ms, now, timeout_ms, time_to_deadline, rtt, sent_ms;
136+ ssize_t n;
137+ socklen_t fromlen;
138+
139+ ARGBEGIN {
140+ case 'c':
141+ cflag = EARGF(usage());
142+ break;
143+ case 'i':
144+ iflag = EARGF(usage());
145+ break;
146+ case 's':
147+ sflag = EARGF(usage());
148+ break;
149+ case 't':
150+ tflag = EARGF(usage());
151+ break;
152+ case 'w':
153+ wflag = EARGF(usage());
154+ break;
155+ case 'q':
156+ qflag = 1;
157+ break;
158+ default:
159+ usage();
160+ } ARGEND
161+
162+ if (argc < 1)
163+ usage();
164+
165+ host = argv[0];
166+
167+ if (cflag)
168+ count = estrtonum(cflag, 1, 1000000);
169+ if (iflag)
170+ interval = estrtod(iflag);
171+ if (sflag)
172+ size = estrtonum(sflag, 0, 65507);
173+ if (tflag)
174+ ttl = estrtonum(tflag, 1, 255);
175+ if (wflag)
176+ deadline = estrtonum(wflag, 1, 1000000);
177+
178+ memset(&hints, 0, sizeof(hints));
179+ hints.ai_family = AF_INET;
180+ hints.ai_socktype = SOCK_RAW;
181+
182+ r = getaddrinfo(host, NULL, &hints, &res);
183+ if (r != 0)
184+ eprintf("getaddrinfo %s: %s\n", host, gai_strerror(r));
185+
186+ memcpy(&dst, res->ai_addr, sizeof(dst));
187+ freeaddrinfo(res);
188+
189+ /* try opening raw icmp socket first, fallback to dgram */
190+ sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
191+ if (sock < 0) {
192+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
193+ if (sock < 0)
194+ eprintf("socket:");
195+ is_raw = 0;
196+ }
197+
198+ if (ttl > 0) {
199+ if (setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
200+ eprintf("setsockopt IP_TTL:");
201+ }
202+
203+ /* request that recvfrom returns the ttl value */
204+ optval = 1;
205+ if (is_raw) {
206+ setsockopt(sock, IPPROTO_IP, IP_RECVTTL, &optval, sizeof(optval));
207+ }
208+
209+ if (!qflag) {
210+ printf("PING %s (%s) %d bytes of data.\n",
211+ host, inet_ntoa(dst.sin_addr), size);
212+ }
213+
214+ signal(SIGINT, sigint_handler);
215+
216+ pfd.fd = sock;
217+ pfd.events = POLLIN;
218+
219+ start_time = get_time_ms();
220+ deadline_ms = deadline > 0 ? start_time + deadline * 1000.0 : 0.0;
221+ next_send_ms = start_time;
222+
223+ rxbuf = emalloc(size + 1024);
224+
225+ while (keep_running) {
226+ now = get_time_ms();
227+
228+ if (deadline > 0 && now >= deadline_ms)
229+ break;
230+
231+ if (count > 0 && sent >= count && received >= sent)
232+ break;
233+
234+ if (now >= next_send_ms && (count == 0 || sent < count)) {
235+ send_ping(sock, &dst, seq++, size);
236+ sent++;
237+ next_send_ms = now + interval * 1000.0;
238+ }
239+
240+ timeout_ms = next_send_ms - now;
241+ if (deadline > 0) {
242+ time_to_deadline = deadline_ms - now;
243+ if (time_to_deadline < timeout_ms)
244+ timeout_ms = time_to_deadline;
245+ }
246+ if (timeout_ms < 0)
247+ timeout_ms = 0;
248+
249+ if (count > 0 && sent >= count)
250+ timeout_ms = 2000.0;
251+
252+ p_res = poll(&pfd, 1, (int)timeout_ms);
253+ if (p_res < 0) {
254+ if (errno == EINTR)
255+ continue;
256+ eprintf("poll:\n");
257+ }
258+
259+ if (p_res > 0 && (pfd.revents & POLLIN)) {
260+ fromlen = sizeof(from);
261+ n = recvfrom(sock, rxbuf, size + 1024, 0, (struct sockaddr *)&from, &fromlen);
262+ if (n < 0) {
263+ if (errno == EINTR || errno == EAGAIN)
264+ continue;
265+ eprintf("recvfrom:\n");
266+ }
267+
268+ hlen = 0;
269+ if (is_raw) {
270+ struct ip *ip = (struct ip *)rxbuf;
271+ hlen = ip->ip_hl << 2;
272+ if (n < hlen + (int)sizeof(*icmp))
273+ continue;
274+ }
275+ icmp = (struct icmphdr *)(rxbuf + hlen);
276+
277+ if (icmp->type == ICMP_ECHOREPLY &&
278+ (!is_raw || ntohs(icmp->un.echo.id) == (getpid() & 0xffff))) {
279+ received++;
280+ rtt = get_time_ms();
281+ if (n - hlen - (int)sizeof(*icmp) >= (int)sizeof(struct timeval)) {
282+ memcpy(&sent_tv, rxbuf + hlen + sizeof(*icmp), sizeof(sent_tv));
283+ sent_ms = (double)sent_tv.tv_sec * 1000.0 + (double)sent_tv.tv_usec / 1000.0;
284+ rtt -= sent_ms;
285+ if (rtt < min_rtt)
286+ min_rtt = rtt;
287+ if (rtt > max_rtt)
288+ max_rtt = rtt;
289+ sum_rtt += rtt;
290+ if (!qflag) {
291+ printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%.3f ms\n",
292+ (int)n, inet_ntoa(from.sin_addr), ntohs(icmp->un.echo.sequence),
293+ is_raw ? ((struct ip *)rxbuf)->ip_ttl : 64, rtt);
294+ }
295+ } else {
296+ if (!qflag) {
297+ printf("%d bytes from %s: icmp_seq=%d ttl=%d\n",
298+ (int)n, inet_ntoa(from.sin_addr), ntohs(icmp->un.echo.sequence),
299+ is_raw ? ((struct ip *)rxbuf)->ip_ttl : 64);
300+ }
301+ }
302+ }
303+ }
304+ }
305+
306+ free(rxbuf);
307+ close(sock);
308+
309+ print_stats(host, sent, received, min_rtt, max_rtt, sum_rtt);
310+
311+ return received > 0 ? 0 : 1;
312+}
+309,
-0
1@@ -0,0 +1,309 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/time.h>
4+#include <sys/types.h>
5+#include <sys/socket.h>
6+
7+#include <netdb.h>
8+#include <netinet/in.h>
9+
10+#include <errno.h>
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <string.h>
14+#include <unistd.h>
15+
16+#include "util.h"
17+
18+#define BLKSIZE 512
19+#define HDRSIZE 4
20+#define PKTSIZE (BLKSIZE + HDRSIZE)
21+
22+#define TIMEOUT_SEC 5
23+/* transfer will time out after NRETRIES * TIMEOUT_SEC */
24+#define NRETRIES 5
25+
26+#define RRQ 1
27+#define WWQ 2
28+#define DATA 3
29+#define ACK 4
30+#define ERR 5
31+
32+static char *errtext[] = {
33+ "Undefined",
34+ "File not found",
35+ "Access violation",
36+ "Disk full or allocation exceeded",
37+ "Illegal TFTP operation",
38+ "Unknown transfer ID",
39+ "File already exists",
40+ "No such user"
41+};
42+
43+static struct sockaddr_storage to;
44+static socklen_t tolen;
45+static int timeout;
46+static int state;
47+static int s;
48+
49+static int
50+packreq(unsigned char *buf, int op, char *path, char *mode)
51+{
52+ unsigned char *p = buf;
53+
54+ *p++ = op >> 8;
55+ *p++ = op & 0xff;
56+ if (strlen(path) + 1 > 256)
57+ eprintf("filename too long\n");
58+ memcpy(p, path, strlen(path) + 1);
59+ p += strlen(path) + 1;
60+ memcpy(p, mode, strlen(mode) + 1);
61+ p += strlen(mode) + 1;
62+ return p - buf;
63+}
64+
65+static int
66+packack(unsigned char *buf, int blkno)
67+{
68+ buf[0] = ACK >> 8;
69+ buf[1] = ACK & 0xff;
70+ buf[2] = blkno >> 8;
71+ buf[3] = blkno & 0xff;
72+ return 4;
73+}
74+
75+static int
76+packdata(unsigned char *buf, int blkno)
77+{
78+ buf[0] = DATA >> 8;
79+ buf[1] = DATA & 0xff;
80+ buf[2] = blkno >> 8;
81+ buf[3] = blkno & 0xff;
82+ return 4;
83+}
84+
85+static int
86+unpackop(unsigned char *buf)
87+{
88+ return (buf[0] << 8) | (buf[1] & 0xff);
89+}
90+
91+static int
92+unpackblkno(unsigned char *buf)
93+{
94+ return (buf[2] << 8) | (buf[3] & 0xff);
95+}
96+
97+static int
98+unpackerrc(unsigned char *buf)
99+{
100+ int errc;
101+
102+ errc = (buf[2] << 8) | (buf[3] & 0xff);
103+ if (errc < 0 || errc >= LEN(errtext))
104+ eprintf("bad error code: %d\n", errc);
105+ return errc;
106+}
107+
108+static int
109+writepkt(unsigned char *buf, int len)
110+{
111+ int n;
112+
113+ n = sendto(s, buf, len, 0, (struct sockaddr *)&to,
114+ tolen);
115+ if (n < 0)
116+ if (errno != EINTR)
117+ eprintf("sendto:");
118+ return n;
119+}
120+
121+static int
122+readpkt(unsigned char *buf, int len)
123+{
124+ int n;
125+
126+ n = recvfrom(s, buf, len, 0, (struct sockaddr *)&to,
127+ &tolen);
128+ if (n < 0) {
129+ if (errno != EINTR && errno != EWOULDBLOCK)
130+ eprintf("recvfrom:");
131+ timeout++;
132+ if (timeout == NRETRIES)
133+ eprintf("transfer timed out\n");
134+ } else {
135+ timeout = 0;
136+ }
137+ return n;
138+}
139+
140+static void
141+getfile(char *file)
142+{
143+ unsigned char buf[PKTSIZE];
144+ int n, op, blkno, nextblkno = 1, done = 0;
145+
146+ state = RRQ;
147+ for (;;) {
148+ switch (state) {
149+ case RRQ:
150+ n = packreq(buf, RRQ, file, "octet");
151+ writepkt(buf, n);
152+ n = readpkt(buf, sizeof(buf));
153+ if (n > 0) {
154+ op = unpackop(buf);
155+ if (op != DATA && op != ERR)
156+ eprintf("bad opcode: %d\n", op);
157+ state = op;
158+ }
159+ break;
160+ case DATA:
161+ n -= HDRSIZE;
162+ if (n < 0)
163+ eprintf("truncated packet\n");
164+ blkno = unpackblkno(buf);
165+ if (blkno == nextblkno) {
166+ nextblkno++;
167+ write(1, &buf[HDRSIZE], n);
168+ }
169+ if (n < BLKSIZE)
170+ done = 1;
171+ state = ACK;
172+ break;
173+ case ACK:
174+ n = packack(buf, blkno);
175+ writepkt(buf, n);
176+ if (done)
177+ return;
178+ n = readpkt(buf, sizeof(buf));
179+ if (n > 0) {
180+ op = unpackop(buf);
181+ if (op != DATA && op != ERR)
182+ eprintf("bad opcode: %d\n", op);
183+ state = op;
184+ }
185+ break;
186+ case ERR:
187+ eprintf("error: %s\n", errtext[unpackerrc(buf)]);
188+ }
189+ }
190+}
191+
192+static void
193+putfile(char *file)
194+{
195+ unsigned char inbuf[PKTSIZE], outbuf[PKTSIZE];
196+ int inb, outb, op, blkno, nextblkno = 0, done = 0;
197+
198+ state = WWQ;
199+ for (;;) {
200+ switch (state) {
201+ case WWQ:
202+ outb = packreq(outbuf, WWQ, file, "octet");
203+ writepkt(outbuf, outb);
204+ inb = readpkt(inbuf, sizeof(inbuf));
205+ if (inb > 0) {
206+ op = unpackop(inbuf);
207+ if (op != ACK && op != ERR)
208+ eprintf("bad opcode: %d\n", op);
209+ state = op;
210+ }
211+ break;
212+ case DATA:
213+ if (blkno == nextblkno) {
214+ nextblkno++;
215+ packdata(outbuf, nextblkno);
216+ outb = read(0, &outbuf[HDRSIZE], BLKSIZE);
217+ if (outb < BLKSIZE)
218+ done = 1;
219+ }
220+ writepkt(outbuf, outb + HDRSIZE);
221+ inb = readpkt(inbuf, sizeof(inbuf));
222+ if (inb > 0) {
223+ op = unpackop(inbuf);
224+ if (op != ACK && op != ERR)
225+ eprintf("bad opcode: %d\n", op);
226+ state = op;
227+ }
228+ break;
229+ case ACK:
230+ if (inb < HDRSIZE)
231+ eprintf("truncated packet\n");
232+ blkno = unpackblkno(inbuf);
233+ if (blkno == nextblkno)
234+ if (done)
235+ return;
236+ state = DATA;
237+ break;
238+ case ERR:
239+ eprintf("error: %s\n", errtext[unpackerrc(inbuf)]);
240+ }
241+ }
242+}
243+
244+static void
245+usage(void)
246+{
247+ eprintf("usage: %s -h host [-p port] [-x | -c] file\n", argv0);
248+}
249+
250+int
251+main(int argc, char *argv[])
252+{
253+ struct addrinfo hints, *res, *r;
254+ struct timeval tv;
255+ char *host = NULL, *port = "tftp";
256+ void (*fn)(char *) = getfile;
257+ int ret;
258+
259+ ARGBEGIN {
260+ case 'h':
261+ host = EARGF(usage());
262+ break;
263+ case 'p':
264+ port = EARGF(usage());
265+ break;
266+ case 'x':
267+ fn = getfile;
268+ break;
269+ case 'c':
270+ fn = putfile;
271+ break;
272+ default:
273+ usage();
274+ } ARGEND
275+
276+ if (!host || !argc)
277+ usage();
278+
279+ memset(&hints, 0, sizeof(hints));
280+ hints.ai_family = AF_UNSPEC;
281+ hints.ai_socktype = SOCK_DGRAM;
282+ hints.ai_protocol = IPPROTO_UDP;
283+ ret = getaddrinfo(host, port, &hints, &res);
284+ if (ret)
285+ eprintf("getaddrinfo: %s\n", gai_strerror(ret));
286+
287+ for (r = res; r; r = r->ai_next) {
288+ if (r->ai_family != AF_INET &&
289+ r->ai_family != AF_INET6)
290+ continue;
291+ s = socket(r->ai_family, r->ai_socktype,
292+ r->ai_protocol);
293+ if (s < 0)
294+ continue;
295+ break;
296+ }
297+ if (!r)
298+ eprintf("cannot create socket\n");
299+ memcpy(&to, r->ai_addr, r->ai_addrlen);
300+ tolen = r->ai_addrlen;
301+ freeaddrinfo(res);
302+
303+ tv.tv_sec = TIMEOUT_SEC;
304+ tv.tv_usec = 0;
305+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
306+ eprintf("setsockopt:");
307+
308+ fn(argv[0]);
309+ return 0;
310+}
+98,
-0
1@@ -0,0 +1,98 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/socket.h>
5+#include <sys/stat.h>
6+#include <sys/types.h>
7+
8+#include <fcntl.h>
9+#include <limits.h>
10+#include <pwd.h>
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <string.h>
14+#include <unistd.h>
15+
16+#include <linux/if.h>
17+#include <linux/if_tun.h>
18+
19+#include "util.h"
20+
21+static int dflag;
22+static int tflag = 1;
23+static int Tflag;
24+static char *owner;
25+
26+static void
27+usage(void)
28+{
29+ eprintf("usage: %s [-dtT] [-u owner] [device]\n", argv0);
30+}
31+
32+int
33+main(int argc, char *argv[])
34+{
35+ struct ifreq ifr;
36+ struct passwd *pw;
37+ uid_t owner_uid = 0;
38+ int fd;
39+
40+ ARGBEGIN
41+ {
42+ case 'd':
43+ dflag = 1;
44+ tflag = 0;
45+ break;
46+ case 't':
47+ tflag = 1;
48+ dflag = 0;
49+ break;
50+ case 'T':
51+ Tflag = 1;
52+ break;
53+ case 'u':
54+ owner = EARGF(usage());
55+ break;
56+ default:
57+ usage();
58+ }
59+ ARGEND
60+
61+ if (owner) {
62+ pw = getpwnam(owner);
63+ if (!pw)
64+ owner_uid = estrtonum(owner, 0, UINT_MAX);
65+ else
66+ owner_uid = pw->pw_uid;
67+ }
68+
69+ fd = open("/dev/net/tun", O_RDWR);
70+ if (fd < 0)
71+ eprintf("open /dev/net/tun:");
72+
73+ memset(&ifr, 0, sizeof(ifr));
74+ ifr.ifr_flags = (Tflag ? IFF_TAP : IFF_TUN) | IFF_NO_PI;
75+
76+ if (argc > 0)
77+ estrlcpy(ifr.ifr_name, argv[0], sizeof(ifr.ifr_name));
78+
79+ if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
80+ eprintf("ioctl TUNSETIFF:");
81+
82+ if (tflag) {
83+ if (ioctl(fd, TUNSETPERSIST, (void *)1) < 0)
84+ eprintf("ioctl TUNSETPERSIST:");
85+ if (owner) {
86+ if (ioctl(fd, TUNSETOWNER, (void *)(long)owner_uid) < 0)
87+ eprintf("ioctl TUNSETOWNER:");
88+ }
89+ printf("Set '%s' persistent and owned by %u\n", ifr.ifr_name,
90+ owner_uid);
91+ } else if (dflag) {
92+ if (ioctl(fd, TUNSETPERSIST, (void *)0) < 0)
93+ eprintf("ioctl TUNSETPERSIST:");
94+ printf("Set '%s' non-persistent\n", ifr.ifr_name);
95+ }
96+
97+ close(fd);
98+ return 0;
99+}
+440,
-0
1@@ -0,0 +1,440 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "util.h"
4+#include "arg.h"
5+
6+#include <arpa/inet.h>
7+#include <ctype.h>
8+#include <errno.h>
9+#include <fcntl.h>
10+#include <netdb.h>
11+#include <netinet/in.h>
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <string.h>
15+#include <sys/socket.h>
16+#include <sys/types.h>
17+#include <unistd.h>
18+
19+struct Stream {
20+ int fd;
21+ char buf[8192];
22+ size_t len;
23+ size_t idx;
24+};
25+
26+static void
27+usage(void)
28+{
29+ eprintf("usage: %s [-O file] [-p post_data] [-r limit] url\n", argv0);
30+}
31+
32+static int
33+dial(const char *host, const char *port)
34+{
35+ struct addrinfo hints, *res, *rp;
36+ int fd = -1, r;
37+
38+ memset(&hints, 0, sizeof(hints));
39+ hints.ai_family = AF_UNSPEC;
40+ hints.ai_socktype = SOCK_STREAM;
41+
42+ r = getaddrinfo(host, port, &hints, &res);
43+ if (r != 0) {
44+ weprintf("getaddrinfo %s:%s: %s\n", host, port, gai_strerror(r));
45+ return -1;
46+ }
47+
48+ for (rp = res; rp; rp = rp->ai_next) {
49+ fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
50+ if (fd < 0)
51+ continue;
52+ if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0)
53+ break;
54+ close(fd);
55+ fd = -1;
56+ }
57+
58+ freeaddrinfo(res);
59+ return fd;
60+}
61+
62+static void
63+parse_url(char *url, char **host, char **port, char **path)
64+{
65+ char *p, *ss;
66+
67+ if (strncasecmp(url, "http://", 7) == 0) {
68+ url += 7;
69+ } else if (strncasecmp(url, "https://", 8) == 0) {
70+ url += 8;
71+ } else {
72+ eprintf("unsupported protocol or invalid url: %s\n", url);
73+ }
74+
75+ *host = url;
76+ p = strchr(url, '/');
77+ if (p) {
78+ *p = '\0';
79+ *path = p + 1;
80+ } else {
81+ *path = "";
82+ }
83+
84+ /* handle ipv6 brackets or host:port */
85+ if (**host == '[') {
86+ (*host)++;
87+ ss = strchr(*host, ']');
88+ if (ss) {
89+ *ss = '\0';
90+ ss++;
91+ if (*ss == ':')
92+ *port = ss + 1;
93+ else
94+ *port = "80";
95+ } else {
96+ eprintf("invalid ipv6 literal: %s\n", *host);
97+ }
98+ } else {
99+ p = strrchr(*host, ':');
100+ if (p) {
101+ *p = '\0';
102+ *port = p + 1;
103+ } else {
104+ *port = "80";
105+ }
106+ }
107+}
108+
109+static char *
110+find_header(const char *headers, const char *name)
111+{
112+ const char *p;
113+ size_t len = strlen(name);
114+
115+ p = headers;
116+ while (p && *p) {
117+ if (strncasecmp(p, name, len) == 0) {
118+ p += len;
119+ while (*p == ' ' || *p == '\t')
120+ p++;
121+ len = strcspn(p, "\r\n");
122+ return estrndup(p, len);
123+ }
124+ p = strchr(p, '\n');
125+ if (p)
126+ p++;
127+ }
128+ return NULL;
129+}
130+
131+static int
132+stream_getc(struct Stream *s)
133+{
134+ if (s->idx < s->len) {
135+ return (unsigned char)s->buf[s->idx++];
136+ }
137+ s->idx = 0;
138+ s->len = read(s->fd, s->buf, sizeof(s->buf));
139+ if (s->len <= 0)
140+ return EOF;
141+ return (unsigned char)s->buf[s->idx++];
142+}
143+
144+static size_t
145+stream_read(struct Stream *s, void *ptr, size_t size)
146+{
147+ size_t total = 0;
148+ size_t n;
149+ char *p = ptr;
150+
151+ while (total < size) {
152+ if (s->idx < s->len) {
153+ n = MIN(size - total, s->len - s->idx);
154+ memcpy(p + total, s->buf + s->idx, n);
155+ s->idx += n;
156+ total += n;
157+ } else {
158+ s->idx = 0;
159+ s->len = read(s->fd, s->buf, sizeof(s->buf));
160+ if (s->len <= 0)
161+ break;
162+ }
163+ }
164+ return total;
165+}
166+
167+static void
168+read_chunked(struct Stream *s, int out_fd)
169+{
170+ char line[128];
171+ char chunk_buf[8192];
172+ size_t line_len, n;
173+ long long chunk_size, remaining;
174+ int c;
175+
176+ for (;;) {
177+ line_len = 0;
178+ for (;;) {
179+ c = stream_getc(s);
180+ if (c == EOF)
181+ eprintf("unexpected end of file reading chunk size\n");
182+ if (c == '\n') {
183+ line[line_len] = '\0';
184+ break;
185+ }
186+ if (c != '\r' && line_len < sizeof(line) - 1) {
187+ line[line_len++] = c;
188+ }
189+ }
190+
191+ chunk_size = strtoll(line, NULL, 16);
192+ if (chunk_size == 0) {
193+ stream_getc(s);
194+ stream_getc(s);
195+ break;
196+ }
197+
198+ remaining = chunk_size;
199+ while (remaining > 0) {
200+ n = stream_read(s, chunk_buf, MIN(remaining, (long long)sizeof(chunk_buf)));
201+ if (n == 0)
202+ eprintf("unexpected end of file in chunk data\n");
203+ if (writeall(out_fd, chunk_buf, n) < 0)
204+ eprintf("write output:\n");
205+ remaining -= n;
206+ }
207+
208+ stream_getc(s);
209+ stream_getc(s);
210+ }
211+}
212+
213+static void
214+read_non_chunked(struct Stream *s, int out_fd, long long content_len)
215+{
216+ char chunk_buf[8192];
217+ long long remaining = content_len;
218+ size_t n, to_read;
219+
220+ while (content_len < 0 || remaining > 0) {
221+ to_read = sizeof(chunk_buf);
222+ if (content_len >= 0)
223+ to_read = (size_t)MIN(remaining, (long long)sizeof(chunk_buf));
224+ n = stream_read(s, chunk_buf, to_read);
225+ if (n == 0) {
226+ if (content_len >= 0)
227+ eprintf("unexpected end of file\n");
228+ break;
229+ }
230+ if (writeall(out_fd, chunk_buf, n) < 0)
231+ eprintf("write output:\n");
232+ if (content_len >= 0)
233+ remaining -= n;
234+ }
235+}
236+
237+int
238+main(int argc, char *argv[])
239+{
240+ struct Stream s;
241+ char *Oflag = NULL;
242+ char *pflag = NULL;
243+ char *rflag = NULL;
244+ char *url, *host, *port, *path, *loc;
245+ char *curr_host, *curr_port, *curr_path;
246+ char *new_url;
247+ char *cl_str;
248+ char *te_str;
249+ char *header_end;
250+ char *out_name;
251+ int redirects = 0;
252+ int max_redirects = 20;
253+ int sock = -1;
254+ int out_fd = 1;
255+ int chunked;
256+ int status;
257+ long long content_len;
258+ size_t total_read;
259+ ssize_t n;
260+ size_t dir_len;
261+ char *last_slash;
262+
263+ ARGBEGIN {
264+ case 'O':
265+ Oflag = EARGF(usage());
266+ break;
267+ case 'p':
268+ pflag = EARGF(usage());
269+ break;
270+ case 'r':
271+ rflag = EARGF(usage());
272+ break;
273+ default:
274+ usage();
275+ } ARGEND
276+
277+ if (argc < 1)
278+ usage();
279+
280+ if (rflag)
281+ max_redirects = estrtonum(rflag, 0, 1000);
282+
283+ url = estrdup(argv[0]);
284+
285+ while (sock < 0) {
286+ if (redirects > max_redirects)
287+ eprintf("too many redirects\n");
288+
289+ /* parse url and backup original parts for relative redirect resolves */
290+ curr_host = curr_port = curr_path = NULL;
291+ parse_url(url, &curr_host, &curr_port, &curr_path);
292+
293+ host = estrdup(curr_host);
294+ port = estrdup(curr_port);
295+ path = estrdup(curr_path);
296+
297+ sock = dial(host, port);
298+ if (sock < 0)
299+ eprintf("failed to connect to %s:%s\n", host, port);
300+
301+ if (pflag) {
302+ dprintf(sock, "POST /%s HTTP/1.1\r\n"
303+ "Host: %s\r\n"
304+ "User-Agent: wget/aruu\r\n"
305+#ifdef STD_NON_POSIX
306+ "Accept: */*\r\n"
307+#endif
308+ "Content-Length: %zu\r\n"
309+ "Connection: close\r\n\r\n",
310+ path, host, strlen(pflag));
311+ writeall(sock, pflag, strlen(pflag));
312+ } else {
313+ dprintf(sock, "GET /%s HTTP/1.1\r\n"
314+ "Host: %s\r\n"
315+ "User-Agent: wget/aruu\r\n"
316+#ifdef STD_NON_POSIX
317+ "Accept: */*\r\n"
318+#endif
319+ "Connection: close\r\n\r\n",
320+ path, host);
321+ }
322+
323+ /* read headers */
324+ total_read = 0;
325+ header_end = NULL;
326+ memset(s.buf, 0, sizeof(s.buf));
327+ while (total_read < sizeof(s.buf) - 1) {
328+ n = read(sock, s.buf + total_read, sizeof(s.buf) - 1 - total_read);
329+ if (n <= 0) {
330+ if (n < 0)
331+ eprintf("read socket:\n");
332+ else
333+ eprintf("connection closed by server\n");
334+ }
335+ total_read += n;
336+ s.buf[total_read] = '\0';
337+ header_end = strstr(s.buf, "\r\n\r\n");
338+ if (header_end)
339+ break;
340+ }
341+
342+ if (!header_end)
343+ eprintf("http header too large or not found\n");
344+
345+ *header_end = '\0';
346+ s.fd = sock;
347+ s.len = total_read;
348+ s.idx = (header_end + 4) - s.buf;
349+
350+ /* parse HTTP status code */
351+ if (strncasecmp(s.buf, "HTTP/1.1 ", 9) != 0 &&
352+ strncasecmp(s.buf, "HTTP/1.0 ", 9) != 0) {
353+ eprintf("invalid http response: %s\n", s.buf);
354+ }
355+ status = atoi(s.buf + 9);
356+
357+ if (status >= 300 && status < 400) {
358+ loc = find_header(s.buf, "Location:");
359+ if (!loc)
360+ eprintf("redirect response without location header\n");
361+
362+ if (strncasecmp(loc, "http://", 7) == 0 ||
363+ strncasecmp(loc, "https://", 8) == 0) {
364+ new_url = estrdup(loc);
365+ } else if (loc[0] == '/') {
366+ new_url = emalloc(8 + strlen(host) + strlen(port) + strlen(loc) + 2);
367+ sprintf(new_url, "http://%s:%s%s", host, port, loc);
368+ } else {
369+ last_slash = strrchr(path, '/');
370+ dir_len = 0;
371+ if (last_slash)
372+ dir_len = last_slash - path + 1;
373+ new_url = emalloc(8 + strlen(host) + strlen(port) + 1 + dir_len + strlen(loc) + 2);
374+ sprintf(new_url, "http://%s:%s/", host, port);
375+ if (dir_len > 0)
376+ strncat(new_url, path, dir_len);
377+ strcat(new_url, loc);
378+ }
379+
380+ free(loc);
381+ free(url);
382+ url = new_url;
383+ close(sock);
384+ sock = -1;
385+ redirects++;
386+ } else if (status != 200) {
387+ eprintf("server returned status: %d\n", status);
388+ }
389+
390+ free(host);
391+ free(port);
392+ free(path);
393+ }
394+
395+ /* parse headers for content length and chunked encoding */
396+ cl_str = find_header(s.buf, "Content-Length:");
397+ content_len = -1;
398+ if (cl_str) {
399+ content_len = strtoll(cl_str, NULL, 10);
400+ free(cl_str);
401+ }
402+
403+ te_str = find_header(s.buf, "Transfer-Encoding:");
404+ chunked = 0;
405+ if (te_str) {
406+ if (strcasecmp(te_str, "chunked") == 0)
407+ chunked = 1;
408+ free(te_str);
409+ }
410+
411+ /* open output file */
412+ out_name = NULL;
413+ if (Oflag) {
414+ out_name = Oflag;
415+ } else {
416+ last_slash = strrchr(url, '/');
417+ if (last_slash && *(last_slash + 1))
418+ out_name = last_slash + 1;
419+ else
420+ out_name = "index.html";
421+ }
422+
423+ if (strcmp(out_name, "-") != 0) {
424+ out_fd = open(out_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
425+ if (out_fd < 0)
426+ eprintf("open %s:\n", out_name);
427+ }
428+
429+ /* read and write body */
430+ if (chunked)
431+ read_chunked(&s, out_fd);
432+ else
433+ read_non_chunked(&s, out_fd, content_len);
434+
435+ close(sock);
436+ if (out_fd != 1)
437+ close(out_fd);
438+ free(url);
439+
440+ return 0;
441+}
+39,
-0
1@@ -0,0 +1,39 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <libgen.h>
4+#include <stdio.h>
5+#include <string.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s path [suffix]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ ssize_t off;
19+ size_t slen;
20+ char *p = "";
21+
22+ ARGBEGIN {
23+ default:
24+ usage();
25+ } ARGEND
26+
27+ if (argc != 1 && argc != 2)
28+ usage();
29+
30+ if (argv[0][0])
31+ p = basename(argv[0]);
32+ if (argc == 2 && (slen = strlen(argv[1])) > 0) {
33+ off = strlen(p) - slen;
34+ if (off > 0 && !strcmp(p + off, argv[1]))
35+ p[off] = '\0';
36+ }
37+ puts(p);
38+
39+ return fshut(stdout, "<stdout>");
40+}
+233,
-0
1@@ -0,0 +1,233 @@
2+/*
3+ * Copyright (C) Caldera International Inc. 2001-2002.
4+ * All rights reserved.
5+ *
6+ * Redistribution and use in source and binary forms, with or without
7+ * modification, are permitted provided that the following conditions
8+ * are met:
9+ * 1. Redistributions of source code and documentation must retain the above
10+ * copyright notice, this list of conditions and the following disclaimer.
11+ * 2. Redistributions in binary form must reproduce the above copyright
12+ * notice, this list of conditions and the following disclaimer in the
13+ * documentation and/or other materials provided with the distribution.
14+ * 3. All advertising materials mentioning features or use of this software
15+ * must display the following acknowledgement:
16+ * This product includes software developed or owned by Caldera
17+ * International, Inc.
18+ * 4. Neither the name of Caldera International, Inc. nor the names of other
19+ * contributors may be used to endorse or promote products derived from
20+ * this software without specific prior written permission.
21+ *
22+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
23+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
24+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26+ * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
27+ * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33+ * POSSIBILITY OF SUCH DAMAGE.
34+ */
35+
36+/*
37+ *
38+ * @(#)bc.library 8.1 (Berkeley) 6/6/93
39+ */
40+
41+scale = 20
42+define e(x){
43+ auto a, b, c, d, e, g, t, w, y
44+
45+ t = scale
46+ scale = t + .434*x + 1
47+
48+ w = 0
49+ if(x<0){
50+ x = -x
51+ w = 1
52+ }
53+ y = 0
54+ while(x>2){
55+ x = x/2
56+ y = y + 1
57+ }
58+
59+ a=1
60+ b=1
61+ c=b
62+ d=1
63+ e=1
64+ for(a=1;1==1;a++){
65+ b=b*x
66+ c=c*a+b
67+ d=d*a
68+ g = c/d
69+ if(g == e){
70+ g = g/1
71+ while(y--){
72+ g = g*g
73+ }
74+ scale = t
75+ if(w==1) return(1/g)
76+ return(g/1)
77+ }
78+ e=g
79+ }
80+}
81+
82+define l(x){
83+ auto a, b, c, d, e, f, g, u, s, t
84+ if(x <=0) return(1-10^scale)
85+ t = scale
86+
87+ f=1
88+ scale = scale + scale(x) - length(x) + 1
89+ s=scale
90+ while(x > 2){
91+ s = s + (length(x)-scale(x))/2 + 1
92+ if(s>0) scale = s
93+ x = sqrt(x)
94+ f=f*2
95+ }
96+ while(x < .5){
97+ s = s + (length(x)-scale(x))/2 + 1
98+ if(s>0) scale = s
99+ x = sqrt(x)
100+ f=f*2
101+ }
102+
103+ scale = t + length(f) - scale(f) + 1
104+ u = (x-1)/(x+1)
105+
106+ scale = scale + 1.1*length(t) - 1.1*scale(t)
107+ s = u*u
108+ b = 2*f
109+ c = b
110+ d = 1
111+ e = 1
112+ for(a=3;1==1;a=a+2){
113+ b=b*s
114+ c=c*a+d*b
115+ d=d*a
116+ g=c/d
117+ if(g==e){
118+ scale = t
119+ return(u*c/d)
120+ }
121+ e=g
122+ }
123+}
124+
125+define s(x){
126+ auto a, b, c, s, t, y, p, n, i
127+ t = scale
128+ y = x/.7853
129+ s = t + length(y) - scale(y)
130+ if(s<t) s=t
131+ scale = s
132+ p = a(1)
133+
134+ scale = 0
135+ if(x>=0) n = (x/(2*p)+1)/2
136+ if(x<0) n = (x/(2*p)-1)/2
137+ x = x - 4*n*p
138+ if(n%2!=0) x = -x
139+
140+ scale = t + length(1.2*t) - scale(1.2*t)
141+ y = -x*x
142+ a = x
143+ b = 1
144+ s = x
145+ for(i=3; 1==1; i=i+2){
146+ a = a*y
147+ b = b*i*(i-1)
148+ c = a/b
149+ if(c==0){scale=t; return(s/1)}
150+ s = s+c
151+ }
152+}
153+
154+define c(x){
155+ auto t
156+ t = scale
157+ scale = scale+1
158+ x = s(x+2*a(1))
159+ scale = t
160+ return(x/1)
161+}
162+
163+define a(x){
164+ auto a, b, c, d, e, f, g, s, t
165+ if(x==0) return(0)
166+ if(x==1) {
167+ if(scale<52) {
168+ return(.7853981633974483096156608458198757210492923498437764/1)
169+ }
170+ }
171+ t = scale
172+ f=1
173+ while(x > .5){
174+ scale = scale + 1
175+ x= -(1-sqrt(1.+x*x))/x
176+ f=f*2
177+ }
178+ while(x < -.5){
179+ scale = scale + 1
180+ x = -(1-sqrt(1.+x*x))/x
181+ f=f*2
182+ }
183+ s = -x*x
184+ b = f
185+ c = f
186+ d = 1
187+ e = 1
188+ for(a=3;1==1;a=a+2){
189+ b=b*s
190+ c=c*a+d*b
191+ d=d*a
192+ g=c/d
193+ if(g==e){
194+ scale = t
195+ return(x*c/d)
196+ }
197+ e=g
198+ }
199+}
200+
201+define j(n,x){
202+ auto a,b,c,d,e,g,i,s,k,t
203+
204+ t = scale
205+ k = 1.36*x + 1.16*t - n
206+ k = length(k) - scale(k)
207+ if(k>0) scale = scale + k
208+
209+ s= -x*x/4
210+ if(n<0){
211+ n= -n
212+ x= -x
213+ }
214+ a=1
215+ c=1
216+ for(i=1;i<=n;i++){
217+ a=a*x
218+ c = c*2*i
219+ }
220+ b=a
221+ d=1
222+ e=1
223+ for(i=1;1;i++){
224+ a=a*s
225+ b=b*i*(n+i) + a
226+ c=c*i*(n+i)
227+ g=b/c
228+ if(g==e){
229+ scale = t
230+ return(g/1)
231+ }
232+ e=g
233+ }
234+}
+922,
-0
1@@ -0,0 +1,922 @@
2+%{
3+#include <libgen.h>
4+#include <unistd.h>
5+
6+#include <assert.h>
7+#include <ctype.h>
8+#include <errno.h>
9+#include <setjmp.h>
10+#include <stdarg.h>
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <string.h>
14+
15+#include "arg.h"
16+#include "util.h"
17+
18+#define DIGITS "0123456789ABCDEF"
19+#define NESTED_MAX 32
20+
21+#define funid(f) ((f)[0] - 'a' + 1)
22+
23+int yydebug;
24+
25+typedef struct macro Macro;
26+
27+struct macro {
28+ int op;
29+ int id;
30+ char *name;
31+ int flowid;
32+ int nested;
33+};
34+
35+static int yyerror(char *);
36+static int yylex(void);
37+
38+static void quit(void);
39+static char *code(char *, ...);
40+static char *forcode(Macro *, char *, char *, char *, char *);
41+static char *whilecode(Macro *, char *, char *);
42+static char *ifcode(Macro *, char *, char *);
43+static char *funcode(Macro *, char *, char *, char *);
44+static char *param(char *, char *), *local(char *, char *);
45+static Macro *define(char *, char *);
46+static char *retcode(char *);
47+static char *brkcode(void);
48+static Macro *macro(int);
49+
50+static char *ftn(char *);
51+static char *var(char *);
52+static char *ary(char *);
53+static void writeout(char *);
54+
55+static char *yytext, *buff, *unwind;
56+static char *filename;
57+static FILE *filep;
58+static int lineno, nerr, flowid;
59+static jmp_buf recover;
60+static int nested, inhome;
61+static Macro macros[NESTED_MAX];
62+int cflag, dflag, lflag, sflag;
63+
64+static char *dcprog = "dc";
65+
66+%}
67+
68+%union {
69+ char *str;
70+ char id[2];
71+ Macro *macro;
72+}
73+
74+%token <id> ID
75+%token <str> STRING NUMBER
76+%token <str> EQOP '+' '-' '*' '/' '%' '^' INCDEC
77+%token HOME LOOP
78+%token DOT
79+%token EQ
80+%token LE
81+%token GE
82+%token NE
83+%token DEF
84+%token BREAK
85+%token QUIT
86+%token LENGTH
87+%token RETURN
88+%token FOR
89+%token IF
90+%token WHILE
91+%token SQRT
92+%token SCALE
93+%token IBASE
94+%token OBASE
95+%token AUTO PARAM
96+%token PRINT
97+
98+%type <str> item statlst scolonlst
99+%type <str> function assign nexpr expr exprstat rel stat ary cond
100+%type <str> autolst arglst parlst
101+%type <str> params param locals local
102+%type <macro> def if for while
103+
104+%right '=' EQOP
105+%left '+' '-'
106+%left '*' '/' '%'
107+%right '^'
108+
109+%start program
110+
111+%%
112+
113+program :
114+ | item program
115+ ;
116+
117+item : scolonlst '\n' {writeout($1);}
118+ | function {writeout($1);}
119+ ;
120+
121+function : def parlst '{' '\n' autolst statlst '}' {$$ = funcode($1, $2, $5, $6);}
122+ ;
123+
124+scolonlst: {$$ = code("");}
125+ | stat
126+ | scolonlst ';' stat {$$ = code("%s%s", $1, $3);}
127+ | scolonlst ';'
128+ ;
129+
130+statlst : {$$ = code("");}
131+ | stat
132+ | statlst '\n' stat {$$ = code("%s%s", $1, $3);}
133+ | statlst ';' stat {$$ = code("%s%s", $1, $3);}
134+ | statlst '\n'
135+ | statlst ';'
136+ ;
137+
138+stat : exprstat
139+ | PRINT expr {$$ = code("%sps.", $2);}
140+ | PRINT STRING {$$ = code("[%s]P", $2);}
141+ | PRINT STRING ',' expr {$$ = code("[%s]P%sps.", $2, $4);}
142+ | STRING {$$ = code("[%s]P", $1);}
143+ | BREAK {$$ = brkcode();}
144+ | QUIT {quit();}
145+ | RETURN {$$ = retcode(code(" 0"));}
146+ | RETURN '(' expr ')' {$$ = retcode($3);}
147+ | RETURN '(' ')' {$$ = retcode(code(" 0"));}
148+ | while cond stat {$$ = whilecode($1, $2, $3);}
149+ | if cond stat {$$ = ifcode($1, $2, $3);}
150+ | '{' statlst '}' {$$ = $2;}
151+ | for '(' expr ';' rel ';' expr ')' stat {$$ = forcode($1, $3, $5, $7, $9);}
152+ ;
153+
154+while : WHILE {$$ = macro(LOOP);}
155+ ;
156+
157+if : IF {$$ = macro(IF);}
158+ ;
159+
160+for : FOR {$$ = macro(LOOP);}
161+ ;
162+
163+def : DEF ID {$$ = macro(DEF);}
164+ ;
165+
166+parlst : '(' ')' {$$ = code("");}
167+ | '(' params ')' {$$ = $2;}
168+ ;
169+
170+params : param {$$ = param(NULL, $1);}
171+ | params ',' param {$$ = param($1, $3);}
172+ ;
173+
174+param : ID {$$ = var($1);}
175+ | ID '[' ']' {$$ = ary($1);}
176+ ;
177+
178+autolst : {$$ = code("");}
179+ | AUTO locals '\n' {$$ = $2;}
180+ | AUTO locals ';' {$$ = $2;}
181+ ;
182+
183+locals : local {$$ = local(NULL, $1);}
184+ | locals ',' local {$$ = local($1, $3);}
185+ ;
186+
187+local : ID {$$ = var($1);}
188+ | ID '[' ']' {$$ = ary($1);}
189+ ;
190+
191+arglst : expr
192+ | ID '[' ']' {$$ = code("%s", ary($1));}
193+ | expr ',' arglst {$$ = code("%s%s", $1, $3);}
194+ | ID '[' ']' ',' arglst {$$ = code("%s%s", ary($1), $5);}
195+ ;
196+
197+cond : '(' rel ')' {$$ = $2;}
198+ ;
199+
200+rel : expr {$$ = code("%s 0!=", $1);}
201+ | expr EQ expr {$$ = code("%s%s=", $1, $3);}
202+ | expr LE expr {$$ = code("%s%s!<", $1, $3);}
203+ | expr GE expr {$$ = code("%s%s!>", $1, $3);}
204+ | expr NE expr {$$ = code("%s%s!=", $1, $3);}
205+ | expr '<' expr {$$ = code("%s%s>", $1, $3);}
206+ | expr '>' expr {$$ = code("%s%s<", $1, $3);}
207+ ;
208+
209+exprstat: nexpr {$$ = code("%s%ss.", $1, code(sflag ? "" : "p"));}
210+ | assign {$$ = code("%ss.", $1);}
211+ ;
212+
213+expr : nexpr
214+ | assign
215+ ;
216+
217+nexpr : NUMBER {$$ = code(" %s", code($1));}
218+ | ID {$$ = code("l%s", var($1));}
219+ | DOT {$$ = code("l.");}
220+ | SCALE {$$ = code("K");}
221+ | IBASE {$$ = code("I");}
222+ | OBASE {$$ = code("O");}
223+ | ID ary {$$ = code("%s;%s", $2, ary($1));}
224+ | '(' expr ')' {$$ = $2;}
225+ | ID '(' arglst ')' {$$ = code("%sl%sx", $3, ftn($1));}
226+ | ID '(' ')' {$$ = code("l%sx", ftn($1));}
227+ | '-' expr {$$ = code("0%s-", $2);}
228+ | expr '+' expr {$$ = code("%s%s+", $1, $3);}
229+ | expr '-' expr {$$ = code("%s%s-", $1, $3);}
230+ | expr '*' expr {$$ = code("%s%s*", $1, $3);}
231+ | expr '/' expr {$$ = code("%s%s/", $1, $3);}
232+ | expr '%' expr {$$ = code("%s%s%%", $1, $3);}
233+ | expr '^' expr {$$ = code("%s%s^", $1, $3);}
234+ | LENGTH '(' expr ')' {$$ = code("%sZ", $3);}
235+ | SQRT '(' expr ')' {$$ = code("%sv", $3);}
236+ | SCALE '(' expr ')' {$$ = code("%sX", $3);}
237+ | INCDEC ID {$$ = code("l%s1%sds%s", var($2), code($1), var($2));}
238+ | INCDEC SCALE {$$ = code("K1%sk", code($1));}
239+ | INCDEC IBASE {$$ = code("I1%sdi", code($1));}
240+ | INCDEC OBASE {$$ = code("O1%sdo", code($1));}
241+ | INCDEC ID ary {$$ = code("%sdS_;%s1%sdL_:%s", $3, ary($2), code($1), ary($2));}
242+ | ID INCDEC {$$ = code("l%sd1%ss%s", var($1), code($2), var($1));}
243+ | SCALE INCDEC {$$ = code("Kd1%sk", code($2));}
244+ | IBASE INCDEC {$$ = code("Id1%si", code($2));}
245+ | OBASE INCDEC {$$ = code("Od1%so", code($2));}
246+ | ID ary INCDEC {$$ = code("%sds.;%sd1%sl.:%s", $2, ary($1), code($3), ary($1));}
247+ ;
248+
249+assign : ID '=' expr {$$ = code("%sds%s", $3, var($1));}
250+ | SCALE '=' expr {$$ = code("%sdk", $3);}
251+ | IBASE '=' expr {$$ = code("%sdi", $3);}
252+ | OBASE '=' expr {$$ = code("%sdo", $3);}
253+ | ID ary '=' expr {$$ = code("%sd%s:%s", $4, $2, ary($1));}
254+ | ID EQOP expr {$$ = code("%sl%s%sds%s", $3, var($1), code($2), var($1));}
255+ | SCALE EQOP expr {$$ = code("%sK%sdk", $3, code($2));}
256+ | IBASE EQOP expr {$$ = code("%sI%sdi", $3, code($2));}
257+ | OBASE EQOP expr {$$ = code("%sO%sdo", $3, code($2));}
258+ | ID ary EQOP expr {$$ = code("%s%sds.;%s%sdl.:s", $4, $2, ary($1), code($3), ary($1));}
259+ ;
260+
261+ary : '[' expr ']' {$$ = $2;}
262+ ;
263+
264+%%
265+static int
266+yyerror(char *s)
267+{
268+ fprintf(stderr, "bc: %s:%d: %s\n", filename, lineno, s);
269+ nerr++;
270+ longjmp(recover, 1);
271+}
272+
273+static void
274+writeout(char *s)
275+{
276+ if (write(1, s, strlen(s)) < 0)
277+ goto err;
278+ if (write(1, "\n", 1) < 0)
279+ goto err;
280+ free(s);
281+ return;
282+
283+err:
284+ eprintf("writing to dc:");
285+}
286+
287+static char *
288+code(char *fmt, ...)
289+{
290+ char *s, *t;
291+ va_list ap;
292+ int c, len, room;
293+
294+ va_start(ap, fmt);
295+ room = BUFSIZ;
296+ for (s = buff; *fmt; s += len) {
297+ len = 1;
298+ if ((c = *fmt++) != '%')
299+ goto append;
300+
301+ switch (*fmt++) {
302+ case 'd':
303+ c = va_arg(ap, int);
304+ len = snprintf(s, room, "%d", c);
305+ if (len < 0 || len >= room)
306+ goto err;
307+ break;
308+ case 'c':
309+ c = va_arg(ap, int);
310+ goto append;
311+ case 's':
312+ t = va_arg(ap, void *);
313+ len = strlen(t);
314+ if (len >= room)
315+ goto err;
316+ memcpy(s, t, len);
317+ free(t);
318+ break;
319+ case '%':
320+ append:
321+ if (room <= 1)
322+ goto err;
323+ *s = c;
324+ break;
325+ default:
326+ abort();
327+ }
328+
329+ room -= len;
330+ }
331+ va_end(ap);
332+
333+ *s = '\0';
334+ return estrdup(buff);
335+
336+err:
337+ eprintf("unable to code requested operation\n");
338+ return NULL;
339+}
340+
341+static Macro *
342+macro(int op)
343+{
344+ int preop;
345+ Macro *d, *p;
346+
347+ if (nested == NESTED_MAX)
348+ yyerror("too much nesting");
349+
350+ d = ¯os[nested];
351+ d->op = op;
352+ d->nested = nested++;
353+ d->name = NULL;
354+
355+ switch (op) {
356+ case HOME:
357+ d->id = 0;
358+ d->flowid = flowid;
359+ inhome = 1;
360+ break;
361+ case DEF:
362+ unwind = estrdup("");
363+ inhome = 0;
364+ d->id = funid(yytext);
365+ d->name = estrdup(yytext);
366+ d->flowid = macros[0].flowid;
367+ break;
368+ default:
369+ assert(nested > 1);
370+ preop = d[-1].op;
371+ d->flowid = d[-1].flowid;
372+ if (preop != HOME && preop != DEF) {
373+ if (d->flowid == 255)
374+ eprintf("too many control flow structures");
375+ d->flowid++;
376+ }
377+ d->id = d->flowid;
378+ if (!inhome) {
379+ /* populate reserved id */
380+ flowid = d->flowid;
381+ for (p = d; p != macros; --p)
382+ p[-1].flowid++;
383+ }
384+ break;
385+ }
386+
387+ return d;
388+}
389+
390+static char *
391+decl(int type, char *list, char *id)
392+{
393+ char *i1, *i2;
394+
395+ i1 = estrdup(id);
396+ i2 = estrdup(id);
397+ free(id);
398+
399+ if (!list)
400+ list = estrdup("");
401+
402+ unwind = code("%sL%ss.", unwind, i1);
403+
404+ return code((type == AUTO) ? "0S%s%s" : "S%s%s", i2, list);
405+}
406+
407+static char *
408+param(char *list, char *id)
409+{
410+ return decl(PARAM, list, id);
411+}
412+
413+static char *
414+local(char *list, char *id)
415+{
416+ return decl(AUTO, list, id);
417+}
418+
419+static char *
420+funcode(Macro *d, char *params, char *vars, char *body)
421+{
422+ char *s;
423+
424+ if (strlen(d->name) > 1) {
425+ s = code("[%s%s%s%s]s\"()%s\"",
426+ vars, params,
427+ body,
428+ retcode(code(" 0")),
429+ d->name);
430+ } else {
431+ s = code(sflag ? "[%s%s%s%s]s<%d>" : "[%s%s%s%s]s%c",
432+ vars, params,
433+ body,
434+ retcode(code(" 0")),
435+ d->id);
436+ free(d->name);
437+ }
438+
439+ free(unwind);
440+ unwind = NULL;
441+ nested--;
442+ inhome = 0;
443+
444+ return s;
445+}
446+
447+static char *
448+brkcode(void)
449+{
450+ Macro *d;
451+
452+ for (d = ¯os[nested-1]; d->op != HOME && d->op != LOOP; --d)
453+ ;
454+ if (d->op == HOME)
455+ yyerror("break not in for or while");
456+ return code(" %dQ", nested - d->nested);
457+}
458+
459+static char *
460+forcode(Macro *d, char *init, char *cmp, char *inc, char *body)
461+{
462+ char *s;
463+
464+ s = code(sflag ? "[%s%ss.%s<%d>]s<%d>" : "[%s%ss.%s%c]s%c",
465+ body,
466+ inc,
467+ estrdup(cmp),
468+ d->id, d->id);
469+ writeout(s);
470+
471+ s = code(sflag ? "%ss.%s<%d> " : "%ss.%s%c ",
472+ init,
473+ cmp,
474+ d->id);
475+ nested--;
476+
477+ return s;
478+}
479+
480+static char *
481+whilecode(Macro *d, char *cmp, char *body)
482+{
483+ char *s;
484+
485+ s = code(sflag ? "[%s%s<%d>]s<%d>" : "[%s%s%c]s%c",
486+ body,
487+ estrdup(cmp),
488+ d->id, d->id);
489+ writeout(s);
490+
491+ s = code(sflag ? "%s<%d> " : "%s%c ",
492+ cmp, d->id);
493+ nested--;
494+
495+ return s;
496+}
497+
498+static char *
499+ifcode(Macro *d, char *cmp, char *body)
500+{
501+ char *s;
502+
503+ s = code(sflag ? "[%s]s<%d>" : "[%s]s%c",
504+ body, d->id);
505+ writeout(s);
506+
507+ s = code(sflag ? "%s<%d> " : "%s%c ",
508+ cmp, d->id);
509+ nested--;
510+
511+ return s;
512+}
513+
514+static char *
515+retcode(char *expr)
516+{
517+ char *s;
518+
519+ if (nested < 2 || macros[1].op != DEF)
520+ yyerror("return must be in a function");
521+ return code("%s %s %dQ", expr, estrdup(unwind), nested - 1);
522+}
523+
524+static char *
525+ary(char *s)
526+{
527+ if (strlen(s) == 1)
528+ return code("%c", toupper(s[0]));
529+ return code("\"[]%s\"", estrdup(s));
530+}
531+
532+static char *
533+ftn(char *s)
534+{
535+ if (strlen(s) == 1)
536+ return code(sflag ? "<%d>" : "%c", funid(s));
537+ return code("\"()%s\"", estrdup(s));
538+}
539+
540+static char *
541+var(char *s)
542+{
543+ if (strlen(s) == 1)
544+ return code(s);
545+ return code("\"%s\"", estrdup(s));
546+}
547+
548+static void
549+quit(void)
550+{
551+ exit(nerr > 0 ? 1 : 0);
552+}
553+
554+static void
555+skipspaces(void)
556+{
557+ int ch;
558+
559+ while (isascii(ch = getc(filep)) && isspace(ch)) {
560+ if (ch == '\n') {
561+ lineno++;
562+ break;
563+ }
564+ }
565+ ungetc(ch, filep);
566+}
567+
568+static int
569+iden(int ch)
570+{
571+ static struct keyword {
572+ char *str;
573+ int token;
574+ } keywords[] = {
575+ {"define", DEF},
576+ {"break", BREAK},
577+ {"quit", QUIT},
578+ {"length", LENGTH},
579+ {"return", RETURN},
580+ {"for", FOR},
581+ {"if", IF},
582+ {"while", WHILE},
583+ {"sqrt", SQRT},
584+ {"scale", SCALE},
585+ {"ibase", IBASE},
586+ {"obase", OBASE},
587+ {"auto", AUTO},
588+ {"print", PRINT},
589+ {NULL}
590+ };
591+ struct keyword *p;
592+ char *bp;
593+
594+ ungetc(ch, filep);
595+ for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
596+ ch = getc(filep);
597+ if (!isascii(ch) || !islower(ch))
598+ break;
599+ *bp = ch;
600+ }
601+
602+ if (bp == &yytext[BUFSIZ])
603+ yyerror("too long token");
604+ *bp = '\0';
605+ ungetc(ch, filep);
606+
607+ if (strlen(yytext) == 1) {
608+ strcpy(yylval.id, yytext);
609+ return ID;
610+ }
611+
612+ for (p = keywords; p->str && strcmp(p->str, yytext); ++p)
613+ ;
614+ if (p->str)
615+ return p->token;
616+
617+ if (!sflag)
618+ yyerror("invalid keyword");
619+ strcpy(yylval.id, yytext);
620+ return ID;
621+}
622+
623+static char *
624+digits(char *bp)
625+{
626+ int ch;
627+ char *digits = DIGITS, *p;
628+
629+ while (bp < &yytext[BUFSIZ]) {
630+ ch = getc(filep);
631+ p = strchr(digits, ch);
632+ if (!p)
633+ break;
634+ *bp++ = ch;
635+ }
636+
637+ if (bp == &yytext[BUFSIZ])
638+ return NULL;
639+ ungetc(ch, filep);
640+
641+ return bp;
642+}
643+
644+static int
645+number(int ch)
646+{
647+ int d;
648+ char *bp;
649+
650+ ungetc(ch, filep);
651+ if ((bp = digits(yytext)) == NULL)
652+ goto toolong;
653+
654+ if ((ch = getc(filep)) != '.') {
655+ ungetc(ch, filep);
656+ goto end;
657+ }
658+ *bp++ = '.';
659+
660+ if ((bp = digits(bp)) == NULL)
661+ goto toolong;
662+
663+end:
664+ if (bp == &yytext[BUFSIZ])
665+ goto toolong;
666+ *bp = '\0';
667+ yylval.str = yytext;
668+
669+ return NUMBER;
670+
671+toolong:
672+ yyerror("too long number");
673+ return 0;
674+}
675+
676+static int
677+string(int ch)
678+{
679+ char *bp;
680+
681+ for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
682+ if ((ch = getc(filep)) == '"')
683+ break;
684+ *bp = ch;
685+ }
686+
687+ if (bp == &yytext[BUFSIZ])
688+ yyerror("too long string");
689+ *bp = '\0';
690+ yylval.str = estrdup(yytext);
691+
692+ return STRING;
693+}
694+
695+static int
696+follow(int next, int yes, int no)
697+{
698+ int ch;
699+
700+ ch = getc(filep);
701+ if (ch == next)
702+ return yes;
703+ ungetc(ch, filep);
704+ return no;
705+}
706+
707+static int
708+operand(int ch)
709+{
710+ int peekc;
711+
712+ switch (ch) {
713+ case '\n':
714+ case '{':
715+ case '}':
716+ case '[':
717+ case ']':
718+ case '(':
719+ case ')':
720+ case ',':
721+ case ';':
722+ return ch;
723+ case '.':
724+ peekc = ungetc(getc(filep), filep);
725+ if (strchr(DIGITS, peekc))
726+ return number(ch);
727+ return DOT;
728+ case '"':
729+ return string(ch);
730+ case '*':
731+ yylval.str = "*";
732+ return follow('=', EQOP, '*');
733+ case '/':
734+ yylval.str = "/";
735+ return follow('=', EQOP, '/');
736+ case '%':
737+ yylval.str = "%";
738+ return follow('=', EQOP, '%');
739+ case '=':
740+ return follow('=', EQ, '=');
741+ case '+':
742+ case '-':
743+ yylval.str = (ch == '+') ? "+" : "-";
744+ if (follow('=', EQOP, ch) != ch)
745+ return EQOP;
746+ return follow(ch, INCDEC, ch);
747+ case '^':
748+ yylval.str = "^";
749+ return follow('=', EQOP, '^');
750+ case '<':
751+ return follow('=', LE, '<');
752+ case '>':
753+ return follow('=', GE, '>');
754+ case '!':
755+ if (getc(filep) == '=')
756+ return NE;
757+ default:
758+ yyerror("invalid operand");
759+ return 0;
760+ }
761+}
762+
763+static void
764+comment(void)
765+{
766+ int c;
767+
768+ for (;;) {
769+ while ((c = getc(filep)) != '*') {
770+ if (c == '\n')
771+ lineno++;
772+ }
773+ if ((c = getc(filep)) == '/')
774+ break;
775+ ungetc(c, filep);
776+ }
777+}
778+
779+static int
780+yylex(void)
781+{
782+ int peekc, ch;
783+
784+repeat:
785+ skipspaces();
786+
787+ ch = getc(filep);
788+ if (ch == EOF) {
789+ return EOF;
790+ } else if (!isascii(ch)) {
791+ yyerror("invalid input character");
792+ } else if (islower(ch)) {
793+ return iden(ch);
794+ } else if (strchr(DIGITS, ch)) {
795+ return number(ch);
796+ } else {
797+ if (ch == '/') {
798+ peekc = getc(filep);
799+ if (peekc == '*') {
800+ comment();
801+ goto repeat;
802+ }
803+ ungetc(peekc, filep);
804+ }
805+ return operand(ch);
806+ }
807+
808+ return 0;
809+}
810+
811+static void
812+spawn(void)
813+{
814+ int fds[2];
815+ char *par = sflag ? "-i" : NULL;
816+ char errmsg[] = "bc:error execing dc\n";
817+
818+ if (pipe(fds) < 0)
819+ eprintf("creating pipe:");
820+
821+ switch (fork()) {
822+ case -1:
823+ eprintf("forking dc:");
824+ case 0:
825+ close(1);
826+ dup(fds[1]);
827+ close(fds[0]);
828+ close(fds[1]);
829+ break;
830+ default:
831+ close(0);
832+ dup(fds[0]);
833+ close(fds[0]);
834+ close(fds[1]);
835+ execlp(dcprog, "dc", par, (char *) NULL);
836+
837+ /* it shouldn't happen */
838+ write(3, errmsg, sizeof(errmsg)-1);
839+ _Exit(2);
840+ }
841+}
842+
843+static void
844+run(void)
845+{
846+ if (setjmp(recover)) {
847+ if (ferror(filep))
848+ eprintf("%s:", filename);
849+ if (feof(filep))
850+ return;
851+ }
852+ yyparse();
853+}
854+
855+static void
856+bc(char *fname)
857+{
858+ Macro *d;
859+
860+ lineno = 1;
861+ nested = 0;
862+
863+ macro(HOME);
864+ if (!fname) {
865+ filename = "<stdin>";
866+ filep = stdin;
867+ } else {
868+ filename = fname;
869+ if ((filep = fopen(fname, "r")) == NULL)
870+ eprintf("%s:", fname);
871+ }
872+
873+ run();
874+ fclose(filep);
875+}
876+
877+static void
878+usage(void)
879+{
880+ eprintf("usage: %s [-p dc][-cdls]\n", argv0);
881+}
882+
883+int
884+main(int argc, char *argv[])
885+{
886+ ARGBEGIN {
887+ case 'p':
888+ dcprog = EARGF(usage());
889+ break;
890+ case 'c':
891+ cflag = 1;
892+ break;
893+ case 'd':
894+ dflag = 1;
895+ yydebug = 3;
896+ break;
897+ case 'l':
898+ lflag = 1;
899+ break;
900+ case 's':
901+ sflag = 1;
902+ break;
903+ default:
904+ usage();
905+ } ARGEND
906+
907+ yytext = malloc(BUFSIZ);
908+ buff = malloc(BUFSIZ);
909+ if (!yytext || !buff)
910+ eprintf("out of memory\n");
911+ flowid = 128;
912+
913+ if (!cflag)
914+ spawn();
915+ if (lflag)
916+ bc(PREFIX "/share/misc/bc.library");
917+
918+ while (*argv)
919+ bc(*argv++);
920+ bc(NULL);
921+
922+ quit();
923+}
+226,
-0
1@@ -0,0 +1,226 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+#include <time.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+enum { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
14+enum caltype { JULIAN, GREGORIAN };
15+enum { TRANS_YEAR = 1752, TRANS_MONTH = SEP, TRANS_DAY = 2 };
16+
17+static struct tm *ltime;
18+
19+static int
20+isleap(size_t year, enum caltype cal)
21+{
22+ if (cal == GREGORIAN) {
23+ if (year % 400 == 0)
24+ return 1;
25+ if (year % 100 == 0)
26+ return 0;
27+ return (year % 4 == 0);
28+ }
29+ else { /* cal == Julian */
30+ return (year % 4 == 0);
31+ }
32+}
33+
34+static int
35+monthlength(size_t year, int month, enum caltype cal)
36+{
37+ int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
38+
39+ return (month == FEB && isleap(year, cal)) ? 29 : mdays[month];
40+}
41+
42+/* From http://www.tondering.dk/claus/cal/chrweek.php#calcdow */
43+static int
44+dayofweek(size_t year, int month, int dom, enum caltype cal)
45+{
46+ size_t y;
47+ int m, a;
48+
49+ a = (13 - month) / 12;
50+ y = year - a;
51+ m = month + 12 * a - 1;
52+
53+ if (cal == GREGORIAN)
54+ return (dom + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7;
55+ else /* cal == Julian */
56+ return (5 + dom + y + y / 4 + (31 * m) / 12) % 7;
57+}
58+
59+static void
60+printgrid(size_t year, int month, int fday, int line)
61+{
62+ enum caltype cal;
63+ int offset, dom, d = 0, trans; /* are we in the transition from Julian to Gregorian? */
64+ int today = 0;
65+
66+ cal = (year < TRANS_YEAR || (year == TRANS_YEAR && month <= TRANS_MONTH)) ? JULIAN : GREGORIAN;
67+ trans = (year == TRANS_YEAR && month == TRANS_MONTH);
68+ offset = dayofweek(year, month, 1, cal) - fday;
69+
70+ if (offset < 0)
71+ offset += 7;
72+ if (line == 1) {
73+ for (; d < offset; ++d)
74+ printf(" ");
75+ dom = 1;
76+ } else {
77+ dom = 8 - offset + (line - 2) * 7;
78+ if (trans && !(line == 2 && fday == 3))
79+ dom += 11;
80+ }
81+ if (ltime && year == ltime->tm_year + 1900 && month == ltime->tm_mon)
82+ today = ltime->tm_mday;
83+ for (; d < 7 && dom <= monthlength(year, month, cal); ++d, ++dom) {
84+ if (dom == today)
85+ printf("\x1b[7m%2d\x1b[0m ", dom); /* highlight today's date */
86+ else
87+ printf("%2d ", dom);
88+ if (trans && dom == TRANS_DAY)
89+ dom += 11;
90+ }
91+ for (; d < 7; ++d)
92+ printf(" ");
93+}
94+
95+static void
96+drawcal(size_t year, int month, size_t ncols, size_t nmons, int fday)
97+{
98+ char *smon[] = { "January", "February", "March", "April",
99+ "May", "June", "July", "August",
100+ "September", "October", "November", "December" };
101+ char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
102+ size_t m, n, col, cur_year, cur_month, dow;
103+ int line, pad;
104+ char month_year[sizeof("Su Mo Tu We Th Fr Sa")];
105+
106+ for (m = 0; m < nmons; ) {
107+ n = m;
108+ for (col = 0; m < nmons && col < ncols; ++col, ++m) {
109+ cur_year = year + m / 12;
110+ cur_month = month + m % 12;
111+ if (cur_month > 11) {
112+ cur_month -= 12;
113+ cur_year += 1;
114+ }
115+ snprintf(month_year, sizeof(month_year), "%s %zu", smon[cur_month], cur_year);
116+ pad = sizeof(month_year) - 1 - strlen(month_year);
117+ printf("%*s%s%*s ", pad / 2 + pad % 2, "", month_year, pad / 2, "");
118+ }
119+ putchar('\n');
120+ for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
121+ for (dow = fday; dow < (fday + 7); ++dow)
122+ printf("%s ", days[dow % 7]);
123+ printf(" ");
124+ }
125+ putchar('\n');
126+ for (line = 1; line <= 6; ++line) {
127+ for (col = 0, m = n; m < nmons && col < ncols; ++col, ++m) {
128+ cur_year = year + m / 12;
129+ cur_month = month + m % 12;
130+ if (cur_month > 11) {
131+ cur_month -= 12;
132+ cur_year += 1;
133+ }
134+ printgrid(cur_year, cur_month, fday, line);
135+ printf(" ");
136+ }
137+ putchar('\n');
138+ }
139+ }
140+}
141+
142+static void
143+usage(void)
144+{
145+ eprintf("usage: %s [-1 | -3 | -y | -n num] "
146+ "[-s | -m | -f num] [-c num] [[month] year]\n", argv0);
147+}
148+
149+int
150+main(int argc, char *argv[])
151+{
152+ time_t now;
153+ size_t year, ncols, nmons;
154+ int fday, month;
155+
156+ now = time(NULL);
157+ ltime = localtime(&now);
158+ year = ltime->tm_year + 1900;
159+ month = ltime->tm_mon + 1;
160+ fday = 0;
161+
162+ if (!isatty(STDOUT_FILENO))
163+ ltime = NULL; /* don't highlight today's date */
164+
165+ ncols = 3;
166+ nmons = 0;
167+
168+ ARGBEGIN {
169+ case '1':
170+ nmons = 1;
171+ break;
172+ case '3':
173+ nmons = 3;
174+ if (--month == 0) {
175+ month = 12;
176+ year--;
177+ }
178+ break;
179+ case 'c':
180+ ncols = estrtonum(EARGF(usage()), 0, MIN(SIZE_MAX, LLONG_MAX));
181+ break;
182+ case 'f':
183+ fday = estrtonum(EARGF(usage()), 0, 6);
184+ break;
185+ case 'm': /* Monday */
186+ fday = 1;
187+ break;
188+ case 'n':
189+ nmons = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
190+ break;
191+ case 's': /* Sunday */
192+ fday = 0;
193+ break;
194+ case 'y':
195+ month = 1;
196+ nmons = 12;
197+ break;
198+ default:
199+ usage();
200+ } ARGEND
201+
202+ if (nmons == 0) {
203+ if (argc == 1) {
204+ month = 1;
205+ nmons = 12;
206+ } else {
207+ nmons = 1;
208+ }
209+ }
210+
211+ switch (argc) {
212+ case 2:
213+ month = estrtonum(argv[0], 1, 12);
214+ argv++;
215+ case 1: /* fallthrough */
216+ year = estrtonum(argv[0], 0, INT_MAX);
217+ break;
218+ case 0:
219+ break;
220+ default:
221+ usage();
222+ }
223+
224+ drawcal(year, month - 1, ncols, nmons, fday);
225+
226+ return fshut(stdout, "<stdout>");
227+}
+52,
-0
1@@ -0,0 +1,52 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <string.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [-u] [file ...]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ int fd, ret = 0;
19+
20+ ARGBEGIN {
21+ case 'u':
22+ break;
23+ default:
24+ usage();
25+ } ARGEND
26+
27+ if (!argc) {
28+ if (concat(0, "<stdin>", 1, "<stdout>") < 0)
29+ ret = 1;
30+ } else {
31+ for (; *argv; argc--, argv++) {
32+ if (!strcmp(*argv, "-")) {
33+ *argv = "<stdin>";
34+ fd = 0;
35+ } else if ((fd = open(*argv, O_RDONLY)) < 0) {
36+ weprintf("open %s:", *argv);
37+ ret = 1;
38+ continue;
39+ }
40+ switch (concat(fd, *argv, 1, "<stdout>")) {
41+ case -1:
42+ ret = 1;
43+ break;
44+ case -2:
45+ return 1; /* exit on write error */
46+ }
47+ if (fd != 0)
48+ close(fd);
49+ }
50+ }
51+
52+ return ret;
53+}
+75,
-0
1@@ -0,0 +1,75 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <grp.h>
8+#include <unistd.h>
9+
10+#include "fs.h"
11+#include "util.h"
12+
13+static int hflag = 0;
14+static gid_t gid = -1;
15+static int ret = 0;
16+
17+static void
18+chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
19+{
20+ int flags = 0;
21+
22+ if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
23+ flags |= AT_SYMLINK_NOFOLLOW;
24+ if (fchownat(dirfd, name, -1, gid, flags) < 0) {
25+ weprintf("chown %s:", r->path);
26+ ret = 1;
27+ } else if (S_ISDIR(st->st_mode)) {
28+ recurse(dirfd, name, NULL, r);
29+ }
30+}
31+
32+static void
33+usage(void)
34+{
35+ eprintf("usage: %s [-h] [-R [-H | -L | -P]] group file ...\n", argv0);
36+}
37+
38+int
39+main(int argc, char *argv[])
40+{
41+ struct group *gr;
42+ struct recursor r = { .fn = chgrp, .maxdepth = 1, .follow = 'P' };
43+
44+ ARGBEGIN {
45+ case 'h':
46+ hflag = 1;
47+ break;
48+ case 'R':
49+ r.maxdepth = 0;
50+ break;
51+ case 'H':
52+ case 'L':
53+ case 'P':
54+ r.follow = ARGC();
55+ break;
56+ default:
57+ usage();
58+ } ARGEND
59+
60+ if (argc < 2)
61+ usage();
62+
63+ errno = 0;
64+ if ((gr = getgrnam(argv[0]))) {
65+ gid = gr->gr_gid;
66+ } else {
67+ if (errno)
68+ eprintf("getgrnam %s:", argv[0]);
69+ gid = estrtonum(argv[0], 0, UINT_MAX);
70+ }
71+
72+ for (argc--, argv++; *argv; argc--, argv++)
73+ recurse(AT_FDCWD, *argv, NULL, &r);
74+
75+ return ret || recurse_status;
76+}
+77,
-0
1@@ -0,0 +1,77 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <sys/stat.h>
5+
6+#include "fs.h"
7+#include "util.h"
8+
9+static char *modestr = "";
10+static mode_t mask = 0;
11+static int ret = 0;
12+
13+static void
14+chmodr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
15+{
16+ mode_t m;
17+
18+ m = parsemode(modestr, st->st_mode, mask);
19+ if (!S_ISLNK(st->st_mode) && fchmodat(dirfd, name, m, 0) < 0) {
20+ weprintf("chmod %s:", r->path);
21+ ret = 1;
22+ } else if (S_ISDIR(st->st_mode)) {
23+ recurse(dirfd, name, NULL, r);
24+ }
25+}
26+
27+static void
28+usage(void)
29+{
30+ eprintf("usage: %s [-R] mode file ...\n", argv0);
31+}
32+
33+int
34+main(int argc, char *argv[])
35+{
36+ struct recursor r = { .fn = chmodr, .maxdepth = 1, .follow = 'H', .flags = DIRFIRST };
37+ size_t i;
38+
39+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
40+
41+ for (; *argv && (*argv)[0] == '-'; argc--, argv++) {
42+ if (!(*argv)[1])
43+ usage();
44+ for (i = 1; (*argv)[i]; i++) {
45+ switch ((*argv)[i]) {
46+ case 'R':
47+ r.maxdepth = 0;
48+ break;
49+ case 'r': case 'w': case 'x': case 'X': case 's': case 't':
50+ /* -[rwxXst] are valid modes, so we're done */
51+ if (i == 1)
52+ goto done;
53+ /* fallthrough */
54+ case '-':
55+ /* -- terminator */
56+ if (i == 1 && !(*argv)[i + 1]) {
57+ argv++;
58+ argc--;
59+ goto done;
60+ }
61+ /* fallthrough */
62+ default:
63+ usage();
64+ }
65+ }
66+ }
67+done:
68+ mask = getumask();
69+ modestr = *argv;
70+
71+ if (argc < 2)
72+ usage();
73+
74+ for (--argc, ++argv; *argv; argc--, argv++)
75+ recurse(AT_FDCWD, *argv, NULL, &r);
76+
77+ return ret || recurse_status;
78+}
+104,
-0
1@@ -0,0 +1,104 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <fcntl.h>
5+#include <grp.h>
6+#include <limits.h>
7+#include <pwd.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "fs.h"
13+#include "util.h"
14+
15+static int hflag = 0;
16+static uid_t uid = -1;
17+static gid_t gid = -1;
18+static int ret = 0;
19+
20+static void
21+chownpwgr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
22+{
23+ int flags = 0;
24+
25+ if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
26+ flags |= AT_SYMLINK_NOFOLLOW;
27+
28+ if (fchownat(dirfd, name, uid, gid, flags) < 0) {
29+ weprintf("chown %s:", r->path);
30+ ret = 1;
31+ } else if (S_ISDIR(st->st_mode)) {
32+ recurse(dirfd, name, NULL, r);
33+ }
34+}
35+
36+static void
37+usage(void)
38+{
39+ eprintf("usage: %s [-h] [-R [-H | -L | -P]] owner[:[group]] file ...\n"
40+ " %s [-h] [-R [-H | -L | -P]] :group file ...\n",
41+ argv0, argv0);
42+}
43+
44+int
45+main(int argc, char *argv[])
46+{
47+ struct group *gr;
48+ struct passwd *pw;
49+ struct recursor r = { .fn = chownpwgr, .maxdepth = 1, .follow = 'P' };
50+ char *owner, *group;
51+
52+ ARGBEGIN {
53+ case 'h':
54+ hflag = 1;
55+ break;
56+ case 'r':
57+ case 'R':
58+ r.maxdepth = 0;
59+ break;
60+ case 'H':
61+ case 'L':
62+ case 'P':
63+ r.follow = ARGC();
64+ break;
65+ default:
66+ usage();
67+ } ARGEND
68+
69+ if (argc < 2)
70+ usage();
71+
72+ owner = argv[0];
73+ if ((group = strchr(owner, ':')))
74+ *group++ = '\0';
75+
76+ if (owner && *owner) {
77+ errno = 0;
78+ pw = getpwnam(owner);
79+ if (pw) {
80+ uid = pw->pw_uid;
81+ } else {
82+ if (errno)
83+ eprintf("getpwnam %s:", owner);
84+ uid = estrtonum(owner, 0, UINT_MAX);
85+ }
86+ }
87+ if (group && *group) {
88+ errno = 0;
89+ gr = getgrnam(group);
90+ if (gr) {
91+ gid = gr->gr_gid;
92+ } else {
93+ if (errno)
94+ eprintf("getgrnam %s:", group);
95+ gid = estrtonum(group, 0, UINT_MAX);
96+ }
97+ }
98+ if (uid == (uid_t)-1 && gid == (gid_t)-1)
99+ usage();
100+
101+ for (argc--, argv++; *argv; argc--, argv++)
102+ recurse(AT_FDCWD, *argv, NULL, &r);
103+
104+ return ret || recurse_status;
105+}
+132,
-0
1@@ -0,0 +1,132 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <inttypes.h>
5+#include <stdio.h>
6+#include <string.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static int ret = 0;
12+static const unsigned long crctab[] = { 0x00000000,
13+0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
14+0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
15+0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
16+0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
17+0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
18+0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
19+0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
20+0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
21+0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
22+0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
23+0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
24+0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
25+0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
26+0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
27+0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
28+0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
29+0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
30+0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
31+0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
32+0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
33+0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
34+0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
35+0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
36+0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
37+0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
38+0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
39+0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
40+0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
41+0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
42+0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
43+0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
44+0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
45+0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
46+0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
47+0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
48+0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
49+0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
50+0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
51+0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
52+0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
53+0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
54+0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
55+0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
56+0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
57+0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
58+0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
59+0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
60+0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
61+0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
62+0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
63+0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
64+};
65+
66+static void
67+cksum(int fd, const char *s)
68+{
69+ ssize_t n;
70+ size_t len = 0, i;
71+ uint32_t ck = 0;
72+ unsigned char buf[BUFSIZ];
73+
74+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
75+ for (i = 0; i < n; i++)
76+ ck = (ck << 8) ^ crctab[(ck >> 24) ^ buf[i]];
77+ len += n;
78+ }
79+ if (n < 0) {
80+ weprintf("read %s:", s ? s : "<stdin>");
81+ ret = 1;
82+ return;
83+ }
84+
85+ for (i = len; i; i >>= 8)
86+ ck = (ck << 8) ^ crctab[(ck >> 24) ^ (i & 0xFF)];
87+
88+ printf("%"PRIu32" %zu", ~ck, len);
89+ if (s) {
90+ putchar(' ');
91+ fputs(s, stdout);
92+ }
93+ putchar('\n');
94+}
95+
96+static void
97+usage(void)
98+{
99+ eprintf("usage: %s [file ...]\n", argv0);
100+}
101+
102+int
103+main(int argc, char *argv[])
104+{
105+ int fd;
106+
107+ ARGBEGIN {
108+ default:
109+ usage();
110+ } ARGEND
111+
112+ if (!argc) {
113+ cksum(0, NULL);
114+ } else {
115+ for (; *argv; argc--, argv++) {
116+ if (!strcmp(*argv, "-")) {
117+ *argv = "<stdin>";
118+ fd = 0;
119+ } else if ((fd = open(*argv, O_RDONLY)) < 0) {
120+ weprintf("open %s:", *argv);
121+ ret = 1;
122+ continue;
123+ }
124+ cksum(fd, *argv);
125+ if (fd != 0)
126+ close(fd);
127+ }
128+ }
129+
130+ ret |= fshut(stdout, "<stdout>");
131+
132+ return ret;
133+}
+82,
-0
1@@ -0,0 +1,82 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ enprintf(2, "usage: %s [-l | -s] file1 file2\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ FILE *fp[2];
19+ size_t line = 1, n;
20+ int ret = 0, lflag = 0, sflag = 0, same = 1, b[2];
21+
22+ ARGBEGIN {
23+ case 'l':
24+ lflag = 1;
25+ break;
26+ case 's':
27+ sflag = 1;
28+ break;
29+ default:
30+ usage();
31+ } ARGEND
32+
33+ if (argc != 2 || (lflag && sflag))
34+ usage();
35+
36+ for (n = 0; n < 2; n++) {
37+ if (!strcmp(argv[n], "-")) {
38+ argv[n] = "<stdin>";
39+ fp[n] = stdin;
40+ } else {
41+ if (!(fp[n] = fopen(argv[n], "r"))) {
42+ if (!sflag)
43+ weprintf("fopen %s:", argv[n]);
44+ return 2;
45+ }
46+ }
47+ }
48+
49+ for (n = 1; ; n++) {
50+ b[0] = getc(fp[0]);
51+ b[1] = getc(fp[1]);
52+
53+ if (b[0] == b[1]) {
54+ if (b[0] == EOF)
55+ break;
56+ else if (b[0] == '\n')
57+ line++;
58+ continue;
59+ } else if (b[0] == EOF || b[1] == EOF) {
60+ if (!sflag)
61+ weprintf("EOF on %s\n", argv[(b[0] != EOF)]);
62+ same = 0;
63+ break;
64+ } else if (!lflag) {
65+ if (!sflag)
66+ printf("%s %s differ: byte %zu, line %zu\n",
67+ argv[0], argv[1], n, line);
68+ same = 0;
69+ break;
70+ } else {
71+ printf("%zu %o %o\n", n, b[0], b[1]);
72+ same = 0;
73+ }
74+ }
75+
76+ if (!ret)
77+ ret = !same;
78+ if (fshut(fp[0], argv[0]) | (fp[0] != fp[1] && fshut(fp[1], argv[1])) |
79+ fshut(stdout, "<stdout>"))
80+ ret = 2;
81+
82+ return ret;
83+}
+97,
-0
1@@ -0,0 +1,97 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "text.h"
8+#include "util.h"
9+
10+static int show = 0x07;
11+
12+static void
13+printline(int pos, struct line *line)
14+{
15+ int i;
16+
17+ if (!(show & (0x1 << pos)))
18+ return;
19+
20+ for (i = 0; i < pos; i++) {
21+ if (show & (0x1 << i))
22+ putchar('\t');
23+ }
24+ fwrite(line->data, 1, line->len, stdout);
25+}
26+
27+static void
28+usage(void)
29+{
30+ eprintf("usage: %s [-123] file1 file2\n", argv0);
31+}
32+
33+int
34+main(int argc, char *argv[])
35+{
36+ FILE *fp[2];
37+ static struct line line[2];
38+ size_t linecap[2] = { 0, 0 };
39+ ssize_t len;
40+ int ret = 0, i, diff = 0, seenline = 0;
41+
42+ ARGBEGIN {
43+ case '1':
44+ case '2':
45+ case '3':
46+ show &= 0x07 ^ (1 << (ARGC() - '1'));
47+ break;
48+ default:
49+ usage();
50+ } ARGEND
51+
52+ if (argc != 2)
53+ usage();
54+
55+ for (i = 0; i < 2; i++) {
56+ if (!strcmp(argv[i], "-")) {
57+ argv[i] = "<stdin>";
58+ fp[i] = stdin;
59+ } else if (!(fp[i] = fopen(argv[i], "r"))) {
60+ eprintf("fopen %s:", argv[i]);
61+ }
62+ }
63+
64+ for (;;) {
65+ for (i = 0; i < 2; i++) {
66+ if (diff && i == (diff < 0))
67+ continue;
68+ if ((len = getline(&(line[i].data), &linecap[i],
69+ fp[i])) > 0) {
70+ line[i].len = len;
71+ seenline = 1;
72+ continue;
73+ }
74+ if (ferror(fp[i]))
75+ eprintf("getline %s:", argv[i]);
76+ if ((diff || seenline) && line[!i].data[0])
77+ printline(!i, &line[!i]);
78+ while ((len = getline(&(line[!i].data), &linecap[!i],
79+ fp[!i])) > 0) {
80+ line[!i].len = len;
81+ printline(!i, &line[!i]);
82+ }
83+ if (ferror(fp[!i]))
84+ eprintf("getline %s:", argv[!i]);
85+ goto end;
86+ }
87+ diff = linecmp(&line[0], &line[1]);
88+ LIMIT(diff, -1, 1);
89+ seenline = 0;
90+ printline((2 - diff) % 3, &line[MAX(0, diff)]);
91+ }
92+end:
93+ ret |= fshut(fp[0], argv[0]);
94+ ret |= (fp[0] != fp[1]) && fshut(fp[1], argv[1]);
95+ ret |= fshut(stdout, "<stdout>");
96+
97+ return ret;
98+}
+63,
-0
1@@ -0,0 +1,63 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include "fs.h"
6+#include "util.h"
7+
8+static void
9+usage(void)
10+{
11+ eprintf("usage: %s [-afipv] [-R [-H | -L | -P]] source ... dest\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+ struct stat st;
18+
19+ ARGBEGIN {
20+ case 'i':
21+ cp_iflag = 1;
22+ break;
23+ case 'a':
24+ cp_follow = 'P';
25+ cp_aflag = cp_pflag = cp_rflag = 1;
26+ break;
27+ case 'f':
28+ cp_fflag = 1;
29+ break;
30+ case 'p':
31+ cp_pflag = 1;
32+ break;
33+ case 'r':
34+ case 'R':
35+ cp_rflag = 1;
36+ break;
37+ case 'v':
38+ cp_vflag = 1;
39+ break;
40+ case 'H':
41+ case 'L':
42+ case 'P':
43+ cp_follow = ARGC();
44+ break;
45+ default:
46+ usage();
47+ } ARGEND
48+
49+ if (argc < 2)
50+ usage();
51+
52+ if (!cp_follow)
53+ cp_follow = cp_rflag ? 'P' : 'L';
54+
55+ if (argc > 2) {
56+ if (stat(argv[argc - 1], &st) < 0)
57+ eprintf("stat %s:", argv[argc - 1]);
58+ if (!S_ISDIR(st.st_mode))
59+ eprintf("%s: not a directory\n", argv[argc - 1]);
60+ }
61+ enmasse(argc, argv, cp);
62+
63+ return fshut(stdout, "<stdout>") || cp_status;
64+}
+215,
-0
1@@ -0,0 +1,215 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "text.h"
8+#include "utf.h"
9+#include "util.h"
10+
11+typedef struct Range {
12+ size_t min, max;
13+ struct Range *next;
14+} Range;
15+
16+static Range *list = NULL;
17+static char mode = 0;
18+static char *delim = "\t";
19+static size_t delimlen = 1;
20+static int nflag = 0;
21+static int sflag = 0;
22+
23+static void
24+insert(Range *r)
25+{
26+ Range *l, *p, *t;
27+
28+ for (p = NULL, l = list; l; p = l, l = l->next) {
29+ if (r->max && r->max + 1 < l->min) {
30+ r->next = l;
31+ break;
32+ } else if (!l->max || r->min < l->max + 2) {
33+ l->min = MIN(r->min, l->min);
34+ for (p = l, t = l->next; t; p = t, t = t->next)
35+ if (r->max && r->max + 1 < t->min)
36+ break;
37+ l->max = (p->max && r->max) ? MAX(p->max, r->max) : 0;
38+ l->next = t;
39+ return;
40+ }
41+ }
42+ if (p)
43+ p->next = r;
44+ else
45+ list = r;
46+}
47+
48+static void
49+parselist(char *str)
50+{
51+ char *s;
52+ size_t n = 1;
53+ Range *r;
54+
55+ if (!*str)
56+ eprintf("empty list\n");
57+ for (s = str; *s; s++) {
58+ if (*s == ' ')
59+ *s = ',';
60+ if (*s == ',')
61+ n++;
62+ }
63+ r = ereallocarray(NULL, n, sizeof(*r));
64+ for (s = str; n; n--, s++) {
65+ r->min = (*s == '-') ? 1 : strtoul(s, &s, 10);
66+ r->max = (*s == '-') ? strtoul(s + 1, &s, 10) : r->min;
67+ r->next = NULL;
68+ if (!r->min || (r->max && r->max < r->min) || (*s && *s != ','))
69+ eprintf("bad list value\n");
70+ insert(r++);
71+ }
72+}
73+
74+static size_t
75+seek(struct line *s, size_t pos, size_t *prev, size_t count)
76+{
77+ size_t n = pos - *prev, i, j;
78+
79+ if (mode == 'b') {
80+ if (n >= s->len)
81+ return s->len;
82+ if (nflag)
83+ while (n && !UTF8_POINT(s->data[n]))
84+ n--;
85+ *prev += n;
86+ return n;
87+ } else if (mode == 'c') {
88+ for (n++, i = 0; i < s->len; i++)
89+ if (UTF8_POINT(s->data[i]) && !--n)
90+ break;
91+ } else {
92+ for (i = (count < delimlen + 1) ? 0 : delimlen; n && i < s->len; ) {
93+ if ((s->len - i) >= delimlen &&
94+ !memcmp(s->data + i, delim, delimlen)) {
95+ if (!--n && count)
96+ break;
97+ i += delimlen;
98+ continue;
99+ }
100+ for (j = 1; j + i <= s->len && !fullrune(s->data + i, j); j++);
101+ i += j;
102+ }
103+ }
104+ *prev = pos;
105+
106+ return i;
107+}
108+
109+static void
110+cut(FILE *fp, const char *fname)
111+{
112+ Range *r;
113+ struct line s;
114+ static struct line line;
115+ static size_t size;
116+ size_t i, n, p;
117+ ssize_t len;
118+
119+ while ((len = getline(&line.data, &size, fp)) > 0) {
120+ line.len = len;
121+ if (line.data[line.len - 1] == '\n')
122+ line.data[--line.len] = '\0';
123+ if (mode == 'f' && !memmem(line.data, line.len, delim, delimlen)) {
124+ if (!sflag) {
125+ fwrite(line.data, 1, line.len, stdout);
126+ fputc('\n', stdout);
127+ }
128+ continue;
129+ }
130+ for (i = 0, p = 1, s = line, r = list; r; r = r->next) {
131+ n = seek(&s, r->min, &p, i);
132+ s.data += n;
133+ s.len -= n;
134+ i += (mode == 'f') ? delimlen : 1;
135+ if (!s.len)
136+ break;
137+ if (!r->max) {
138+ fwrite(s.data, 1, s.len, stdout);
139+ break;
140+ }
141+ n = seek(&s, r->max + 1, &p, i);
142+ i += (mode == 'f') ? delimlen : 1;
143+ if (fwrite(s.data, 1, n, stdout) != n)
144+ eprintf("fwrite <stdout>:");
145+ s.data += n;
146+ s.len -= n;
147+ }
148+ putchar('\n');
149+ }
150+ if (ferror(fp))
151+ eprintf("getline %s:", fname);
152+}
153+
154+static void
155+usage(void)
156+{
157+ eprintf("usage: %s -b list [-n] [file ...]\n"
158+ " %s -c list [file ...]\n"
159+ " %s -f list [-d delim] [-s] [file ...]\n",
160+ argv0, argv0, argv0);
161+}
162+
163+int
164+main(int argc, char *argv[])
165+{
166+ FILE *fp;
167+ int ret = 0;
168+
169+ ARGBEGIN {
170+ case 'b':
171+ case 'c':
172+ case 'f':
173+ mode = ARGC();
174+ parselist(EARGF(usage()));
175+ break;
176+ case 'd':
177+ delim = EARGF(usage());
178+ if (!*delim)
179+ eprintf("empty delimiter\n");
180+ delimlen = unescape(delim);
181+ break;
182+ case 'n':
183+ nflag = 1;
184+ break;
185+ case 's':
186+ sflag = 1;
187+ break;
188+ default:
189+ usage();
190+ } ARGEND
191+
192+ if (!mode)
193+ usage();
194+
195+ if (!argc)
196+ cut(stdin, "<stdin>");
197+ else {
198+ for (; *argv; argc--, argv++) {
199+ if (!strcmp(*argv, "-")) {
200+ *argv = "<stdin>";
201+ fp = stdin;
202+ } else if (!(fp = fopen(*argv, "r"))) {
203+ weprintf("fopen %s:", *argv);
204+ ret = 1;
205+ continue;
206+ }
207+ cut(fp, *argv);
208+ if (fp != stdin && fshut(fp, *argv))
209+ ret = 1;
210+ }
211+ }
212+
213+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
214+
215+ return ret;
216+}
+103,
-0
1@@ -0,0 +1,103 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <time.h>
8+
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+ eprintf("usage: %s [-u] [-d time] [+format | mmddHHMM[[CC]yy]]\n", argv0);
15+}
16+
17+static int
18+datefield(const char *s, size_t i)
19+{
20+ if (!isdigit(s[i]) || !isdigit(s[i+1]))
21+ eprintf("invalid date format: %s\n", s);
22+
23+ return (s[i] - '0') * 10 + (s[i+1] - '0');
24+}
25+
26+static void
27+setdate(const char *s, struct tm *now)
28+{
29+ struct tm date;
30+ struct timespec ts;
31+
32+ switch (strlen(s)) {
33+ case 8:
34+ date.tm_year = now->tm_year;
35+ break;
36+ case 10:
37+ date.tm_year = datefield(s, 8);
38+ if (date.tm_year < 69)
39+ date.tm_year += 100;
40+ break;
41+ case 12:
42+ date.tm_year = ((datefield(s, 8) - 19) * 100) + datefield(s, 10);
43+ break;
44+ default:
45+ eprintf("invalid date format: %s\n", s);
46+ break;
47+ }
48+
49+ date.tm_mon = datefield(s, 0) - 1;
50+ date.tm_mday = datefield(s, 2);
51+ date.tm_hour = datefield(s, 4);
52+ date.tm_min = datefield(s, 6);
53+ date.tm_sec = 0;
54+ date.tm_isdst = -1;
55+
56+ ts.tv_sec = mktime(&date);
57+ if (ts.tv_sec == -1)
58+ eprintf("mktime:");
59+ ts.tv_nsec = 0;
60+
61+ if (clock_settime(CLOCK_REALTIME, &ts) == -1)
62+ eprintf("clock_settime:");
63+}
64+
65+int
66+main(int argc, char *argv[])
67+{
68+ struct tm *now;
69+ time_t t;
70+ char buf[BUFSIZ], *fmt = "%a %b %e %H:%M:%S %Z %Y";
71+
72+ t = time(NULL);
73+ if (t == -1)
74+ eprintf("time:");
75+
76+ ARGBEGIN {
77+ case 'd':
78+ t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
79+ break;
80+ case 'u':
81+ if (setenv("TZ", "UTC0", 1) < 0)
82+ eprintf("setenv:");
83+ break;
84+ default:
85+ usage();
86+ } ARGEND
87+
88+ if (!(now = localtime(&t)))
89+ eprintf("localtime:");
90+ if (argc) {
91+ if (argc != 1)
92+ usage();
93+ if (argv[0][0] != '+') {
94+ setdate(argv[0], now);
95+ return 0;
96+ }
97+ fmt = &argv[0][1];
98+ }
99+
100+ strftime(buf, sizeof(buf), fmt, now);
101+ puts(buf);
102+
103+ return fshut(stdout, "<stdout>");
104+}
+237,
-0
1@@ -0,0 +1,237 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <fcntl.h>
5+#include <inttypes.h>
6+#include <stdint.h>
7+#include <string.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+static off_t ifull, ofull, ipart, opart;
13+
14+static void
15+usage(void)
16+{
17+ eprintf("usage: %s [operand...]\n", argv0);
18+}
19+
20+static size_t
21+parsesize(char *expr)
22+{
23+ char *s = expr;
24+ size_t n = 1;
25+
26+ for (;;) {
27+ n *= strtoumax(s, &s, 10);
28+ switch (*s) {
29+ case 'k': n <<= 10; s++; break;
30+ case 'b': n <<= 9; s++; break;
31+ }
32+ if (*s != 'x' || !s[1])
33+ break;
34+ s++;
35+ }
36+ if (*s || n == 0)
37+ eprintf("invalid block size expression '%s'\n", expr);
38+
39+ return n;
40+}
41+
42+static void
43+bswap(unsigned char *buf, size_t len)
44+{
45+ int c;
46+
47+ for (len &= ~1; len > 0; buf += 2, len -= 2) {
48+ c = buf[0];
49+ buf[0] = buf[1];
50+ buf[1] = c;
51+ }
52+}
53+
54+static void
55+lcase(unsigned char *buf, size_t len)
56+{
57+ for (; len > 0; buf++, len--)
58+ buf[0] = tolower(buf[0]);
59+}
60+
61+static void
62+ucase(unsigned char *buf, size_t len)
63+{
64+ for (; len > 0; buf++, len--)
65+ buf[0] = toupper(buf[0]);
66+}
67+
68+static void
69+summary(void)
70+{
71+ fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records in\n", (intmax_t)ifull, (intmax_t)ipart);
72+ fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t)ofull, (intmax_t)opart);
73+}
74+
75+int
76+main(int argc, char *argv[])
77+{
78+ enum {
79+ LCASE = 1 << 0,
80+ UCASE = 1 << 1,
81+ SWAB = 1 << 2,
82+ NOERROR = 1 << 3,
83+ NOTRUNC = 1 << 4,
84+ SYNC = 1 << 5,
85+ } conv = 0;
86+ char *arg, *val, *end;
87+ const char *iname = "-", *oname = "-";
88+ int ifd = 0, ofd = 1, eof = 0;
89+ size_t len, bs = 0, ibs = 512, obs = 512, ipos = 0, opos = 0;
90+ off_t skip = 0, seek = 0, count = -1;
91+ ssize_t ret;
92+ unsigned char *buf;
93+
94+ argv0 = argc ? (argc--, *argv++) : "dd";
95+ for (; argc > 0; argc--, argv++) {
96+ arg = *argv;
97+ val = strchr(arg, '=');
98+ if (!val)
99+ usage();
100+ *val++ = '\0';
101+ if (strcmp(arg, "if") == 0) {
102+ iname = val;
103+ } else if (strcmp(arg, "of") == 0) {
104+ oname = val;
105+ } else if (strcmp(arg, "ibs") == 0) {
106+ ibs = parsesize(val);
107+ } else if (strcmp(arg, "obs") == 0) {
108+ obs = parsesize(val);
109+ } else if (strcmp(arg, "bs") == 0) {
110+ bs = parsesize(val);
111+ } else if (strcmp(arg, "skip") == 0) {
112+ skip = estrtonum(val, 0, LLONG_MAX);
113+ } else if (strcmp(arg, "seek") == 0) {
114+ seek = estrtonum(val, 0, LLONG_MAX);
115+ } else if (strcmp(arg, "count") == 0) {
116+ count = estrtonum(val, 0, LLONG_MAX);
117+ } else if (strcmp(arg, "conv") == 0) {
118+ do {
119+ end = strchr(val, ',');
120+ if (end)
121+ *end++ = '\0';
122+ if (strcmp(val, "lcase") == 0)
123+ conv |= LCASE;
124+ else if (strcmp(val, "ucase") == 0)
125+ conv |= UCASE;
126+ else if (strcmp(val, "swab") == 0)
127+ conv |= SWAB;
128+ else if (strcmp(val, "noerror") == 0)
129+ conv |= NOERROR;
130+ else if (strcmp(val, "notrunc") == 0)
131+ conv |= NOTRUNC;
132+ else if (strcmp(val, "sync") == 0)
133+ conv |= SYNC;
134+ else
135+ eprintf("unknown conv flag '%s'\n", val);
136+ val = end;
137+ } while (val);
138+ } else {
139+ weprintf("unknown operand '%s'\n", arg);
140+ usage();
141+ }
142+ }
143+
144+ if (bs)
145+ ibs = obs = bs;
146+ if (strcmp(iname, "-") != 0) {
147+ ifd = open(iname, O_RDONLY);
148+ if (ifd < 0)
149+ eprintf("open %s:", iname);
150+ }
151+ if (strcmp(oname, "-") != 0) {
152+ ofd = open(oname, O_WRONLY | O_CREAT | (conv & NOTRUNC || seek ? 0 : O_TRUNC), 0666);
153+ if (ofd < 0)
154+ eprintf("open %s:", oname);
155+ }
156+
157+ len = MAX(ibs, obs) + ibs;
158+ buf = emalloc(len);
159+ if (skip && lseek(ifd, skip * ibs, SEEK_SET) < 0) {
160+ while (skip--) {
161+ ret = read(ifd, buf, ibs);
162+ if (ret < 0)
163+ eprintf("read:");
164+ if (ret == 0) {
165+ eof = 1;
166+ break;
167+ }
168+ }
169+ }
170+ if (seek) {
171+ if (!(conv & NOTRUNC) && ftruncate(ofd, seek * ibs) != 0)
172+ eprintf("ftruncate:");
173+ if (lseek(ofd, seek * ibs, SEEK_SET) < 0)
174+ eprintf("lseek:");
175+ /* XXX: handle non-seekable files */
176+ }
177+ while (!eof) {
178+ while (ipos - opos < obs) {
179+ if (ifull + ipart == count) {
180+ eof = 1;
181+ break;
182+ }
183+ ret = read(ifd, buf + ipos, ibs);
184+ if (ret == 0) {
185+ eof = 1;
186+ break;
187+ }
188+ if (ret < 0) {
189+ weprintf("read:");
190+ if (!(conv & NOERROR))
191+ return 1;
192+ summary();
193+ if (!(conv & SYNC))
194+ continue;
195+ ret = 0;
196+ }
197+ if (ret < ibs) {
198+ ipart++;
199+ if (conv & SYNC) {
200+ memset(buf + ipos + ret, 0, ibs - ret);
201+ ret = ibs;
202+ }
203+ } else {
204+ ifull++;
205+ }
206+ if (conv & SWAB)
207+ bswap(buf + ipos, ret);
208+ if (conv & LCASE)
209+ lcase(buf + ipos, ret);
210+ if (conv & UCASE)
211+ ucase(buf + ipos, ret);
212+ ipos += ret;
213+ if (bs && !(conv & (SWAB | LCASE | UCASE)))
214+ break;
215+ }
216+ if (ipos == opos)
217+ break;
218+ do {
219+ ret = write(ofd, buf + opos, MIN(obs, ipos - opos));
220+ if (ret < 0)
221+ eprintf("write:");
222+ if (ret == 0)
223+ eprintf("write returned 0\n");
224+ if (ret < obs)
225+ opart++;
226+ else
227+ ofull++;
228+ opos += ret;
229+ } while (ipos - opos >= (eof ? 1 : obs));
230+ if (opos < ipos)
231+ memmove(buf, buf + opos, ipos - opos);
232+ ipos -= opos;
233+ opos = 0;
234+ }
235+ summary();
236+
237+ return 0;
238+}
+139,
-0
1@@ -0,0 +1,139 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/statvfs.h>
4+
5+#include <mntent.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "util.h"
11+
12+static long blksize = 512;
13+static int aflag = 0;
14+static int hflag = 0;
15+static int kflag = 0;
16+
17+#define CALC_POWER(n, power, base, i) do { \
18+ while (n > power) { \
19+ power = power * base; \
20+ i++; \
21+ } \
22+} while(0)
23+
24+static void
25+print_human(
26+ const char *fsname,
27+ unsigned long long total,
28+ unsigned long long used,
29+ unsigned long long avail,
30+ int capacity,
31+ const char *dir)
32+{
33+ long base = 1024;
34+ unsigned long long power_total = base;
35+ unsigned long long power_used = base;
36+ unsigned long long power_avail = base;
37+ char postfixes[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'};
38+ int i = 0, j = 0, k = 0;
39+
40+ total = total * blksize;
41+ used = used * blksize;
42+ avail = avail * blksize;
43+
44+ CALC_POWER(total, power_total, base, i);
45+ CALC_POWER(used, power_used, base, j);
46+ CALC_POWER(avail, power_avail, base, k);
47+
48+ total = i ? total / (power_total / base) : total;
49+ used = j ? used / (power_used / base) : used;
50+ avail = k ? avail / (power_avail / base) : avail;
51+ printf("%-12s %9llu%c %9llu%c %9llu%c %7d%% %s\n",
52+ fsname, total, postfixes[i], used, postfixes[j],
53+ avail, postfixes[k], capacity, dir);
54+}
55+
56+static int
57+mnt_show(const char *fsname, const char *dir)
58+{
59+ struct statvfs s;
60+ unsigned long long total, used, avail;
61+ int capacity = 0;
62+ int bs;
63+
64+ if (statvfs(dir, &s) < 0)
65+ return -1;
66+
67+ bs = s.f_frsize / blksize;
68+ total = s.f_blocks * bs;
69+ avail = s.f_bfree * bs;
70+ used = total - avail;
71+
72+ if (used + avail) {
73+ capacity = (used * 100) / (used + avail);
74+ if (used * 100 != capacity * (used + avail))
75+ capacity++;
76+ }
77+
78+ if (hflag)
79+ print_human(fsname, total, used, avail, capacity, dir);
80+ else
81+ printf("%-12s %9llu %9llu %9llu %7d%% %s\n",
82+ fsname, total, used, avail, capacity, dir);
83+
84+ return 0;
85+}
86+
87+static void
88+usage(void)
89+{
90+ eprintf("usage: %s [-a]\n", argv0);
91+}
92+
93+int
94+main(int argc, char *argv[])
95+{
96+ struct mntent *me = NULL;
97+ FILE *fp;
98+ int ret = 0;
99+
100+ ARGBEGIN {
101+ case 'a':
102+ aflag = 1;
103+ break;
104+ case 'h':
105+ hflag = 1;
106+ kflag = 0;
107+ break;
108+ case 'k':
109+ kflag = 1;
110+ hflag = 0;
111+ blksize = 1024;
112+ break;
113+ case 's':
114+ case 'i':
115+ eprintf("not implemented\n");
116+ default:
117+ usage();
118+ } ARGEND;
119+
120+ if (hflag)
121+ printf("Filesystem Size Used "
122+ "Avail Capacity Mounted on\n");
123+ else
124+ printf("Filesystem %ld-blocks Used "
125+ "Avail Capacity Mounted on\n", blksize);
126+
127+ fp = setmntent("/proc/mounts", "r");
128+ if (!fp)
129+ eprintf("setmntent %s:", "/proc/mounts");
130+ while ((me = getmntent(fp)) != NULL) {
131+ if (aflag == 0)
132+ if (strcmp(me->mnt_type, "rootfs") == 0)
133+ continue;
134+ if (mnt_show(me->mnt_fsname, me->mnt_dir) < 0)
135+ ret = 1;
136+ }
137+ endmntent(fp);
138+
139+ return ret;
140+}
+27,
-0
1@@ -0,0 +1,27 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <libgen.h>
4+#include <stdio.h>
5+
6+#include "util.h"
7+
8+static void
9+usage(void)
10+{
11+ eprintf("usage: %s path\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+ ARGBEGIN {
18+ default:
19+ usage();
20+ } ARGEND
21+
22+ if (argc != 1)
23+ usage();
24+
25+ puts(dirname(argv[0]));
26+
27+ return fshut(stdout, "<stdout>");
28+}
+167,
-0
1@@ -0,0 +1,167 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/types.h>
5+
6+#include <errno.h>
7+#include <fcntl.h>
8+#include <limits.h>
9+#include <search.h>
10+#include <stdint.h>
11+#include <stdlib.h>
12+#include <stdio.h>
13+#include <unistd.h>
14+
15+#include "fs.h"
16+#include "util.h"
17+
18+static size_t maxdepth = SIZE_MAX;
19+static size_t blksize = 512;
20+
21+static int aflag = 0;
22+static int sflag = 0;
23+static int hflag = 0;
24+
25+struct file {
26+ dev_t devno;
27+ ino_t inode;
28+};
29+
30+static void
31+printpath(off_t n, const char *path)
32+{
33+ if (hflag)
34+ printf("%s\t%s\n", humansize(n * blksize), path);
35+ else
36+ printf("%jd\t%s\n", (intmax_t)n, path);
37+}
38+
39+static off_t
40+nblks(blkcnt_t blocks)
41+{
42+ return (512 * blocks + blksize - 1) / blksize;
43+}
44+
45+static int
46+cmp(const void *p1, const void *p2)
47+{
48+ const struct file *f1 = p1, *f2 = p2;
49+
50+ if (f1->devno > f2->devno)
51+ return -1;
52+ if (f1->devno < f2->devno)
53+ return 1;
54+
55+ /* f1->devno == f2->devno */
56+ if (f1->inode < f2->inode)
57+ return -1;
58+ if (f1->inode > f2->inode)
59+ return 1;
60+
61+ return 0;
62+}
63+
64+static int
65+duplicated(dev_t dev, ino_t ino)
66+{
67+ static void *tree;
68+ struct file **fpp, *fp, file = {dev, ino};
69+
70+ if ((fpp = tsearch(&file, &tree, cmp)) == NULL)
71+ eprintf("%s:", argv0);
72+
73+ if (*fpp != &file)
74+ return 1;
75+
76+ /* new file added */
77+ fp = emalloc(sizeof(*fp));
78+ *fp = file;
79+ *fpp = fp;
80+
81+ return 0;
82+}
83+
84+static void
85+du(int dirfd, const char *path, struct stat *st, void *data, struct recursor *r)
86+{
87+ off_t *total = data, subtotal;
88+
89+ subtotal = nblks(st->st_blocks);
90+ if (S_ISDIR(st->st_mode)) {
91+ recurse(dirfd, path, &subtotal, r);
92+ } else if (r->follow != 'P' || st->st_nlink > 1) {
93+ if (duplicated(st->st_dev, st->st_ino))
94+ goto print;
95+ }
96+
97+ *total += subtotal;
98+
99+print:
100+ if (!r->depth)
101+ printpath(*total, r->path);
102+ else if (!sflag && r->depth <= maxdepth && (S_ISDIR(st->st_mode) || aflag))
103+ printpath(subtotal, r->path);
104+}
105+
106+static void
107+usage(void)
108+{
109+ eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [-H | -L | -P] [-x] [file ...]\n", argv0);
110+}
111+
112+int
113+main(int argc, char *argv[])
114+{
115+ struct recursor r = { .fn = du, .follow = 'P' };
116+ off_t n = 0;
117+ int kflag = 0, dflag = 0;
118+ char *bsize;
119+
120+ ARGBEGIN {
121+ case 'a':
122+ aflag = 1;
123+ break;
124+ case 'd':
125+ dflag = 1;
126+ maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
127+ break;
128+ case 'h':
129+ hflag = 1;
130+ break;
131+ case 'k':
132+ kflag = 1;
133+ break;
134+ case 's':
135+ sflag = 1;
136+ break;
137+ case 'x':
138+ r.flags |= SAMEDEV;
139+ break;
140+ case 'H':
141+ case 'L':
142+ case 'P':
143+ r.follow = ARGC();
144+ break;
145+ default:
146+ usage();
147+ } ARGEND
148+
149+ if ((aflag && sflag) || (dflag && sflag))
150+ usage();
151+
152+ bsize = getenv("BLOCKSIZE");
153+ if (bsize)
154+ blksize = estrtonum(bsize, 1, MIN(LLONG_MAX, SIZE_MAX));
155+ if (kflag)
156+ blksize = 1024;
157+
158+ if (!argc) {
159+ recurse(AT_FDCWD, ".", &n, &r);
160+ } else {
161+ for (; *argv; argc--, argv++) {
162+ n = 0;
163+ recurse(AT_FDCWD, *argv, &n, &r);
164+ }
165+ }
166+
167+ return fshut(stdout, "<stdout>") || recurse_status;
168+}
+24,
-0
1@@ -0,0 +1,24 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <string.h>
5+#include "util.h"
6+
7+int
8+main(int argc, char *argv[])
9+{
10+ int nflag = 0;
11+
12+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
13+
14+ if (*argv && !strcmp(*argv, "-n")) {
15+ nflag = 1;
16+ argc--, argv++;
17+ }
18+
19+ for (; *argv; argc--, argv++)
20+ putword(stdout, *argv);
21+ if (!nflag)
22+ putchar('\n');
23+
24+ return fshut(stdout, "<stdout>");
25+}
+1722,
-0
1@@ -0,0 +1,1722 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <fcntl.h>
5+#include <regex.h>
6+#include <unistd.h>
7+
8+#include <ctype.h>
9+#include <limits.h>
10+#include <setjmp.h>
11+#include <signal.h>
12+#include <stdint.h>
13+#include <stdio.h>
14+#include <stdlib.h>
15+#include <string.h>
16+
17+#include "util.h"
18+
19+#define REGEXSIZE 100
20+#define LINESIZE 80
21+#define NUMLINES 32
22+#define CACHESIZ 4096
23+#define AFTER 0
24+#define BEFORE 1
25+
26+typedef struct {
27+ char *str;
28+ size_t cap;
29+ size_t siz;
30+} String;
31+
32+struct hline {
33+ off_t seek;
34+ char global;
35+ int next, prev;
36+};
37+
38+struct undo {
39+ int curln, lastln;
40+ size_t nr, cap;
41+ struct link {
42+ int to1, from1;
43+ int to2, from2;
44+ } *vec;
45+};
46+
47+static char *prompt = "*";
48+static regex_t *pattern;
49+static regmatch_t matchs[10];
50+static String lastre;
51+
52+static int optverbose, optprompt, exstatus, optdiag = 1;
53+static int marks['z' - 'a' + 1];
54+static int nlines, line1, line2;
55+static int curln, lastln, ocurln, olastln;
56+static jmp_buf savesp;
57+static char *lasterr;
58+static size_t idxsize, lastidx;
59+static struct hline *zero;
60+static String text;
61+static char savfname[FILENAME_MAX];
62+static char tmpname[FILENAME_MAX];
63+static int scratch;
64+static int pflag, modflag, uflag, gflag;
65+static size_t csize;
66+static String cmdline;
67+static char *ocmdline;
68+static int inputidx;
69+static char *rhs;
70+static char *lastmatch;
71+static struct undo udata;
72+static int newcmd;
73+
74+static sig_atomic_t intr, hup;
75+
76+static void undo(void);
77+
78+static void
79+error(char *msg)
80+{
81+ exstatus = 1;
82+ lasterr = msg;
83+ puts("?");
84+
85+ if (optverbose)
86+ puts(msg);
87+ if (!newcmd)
88+ undo();
89+
90+ curln = ocurln;
91+ longjmp(savesp, 1);
92+}
93+
94+static int
95+nextln(int line)
96+{
97+ ++line;
98+ return (line > lastln) ? 0 : line;
99+}
100+
101+static int
102+prevln(int line)
103+{
104+ --line;
105+ return (line < 0) ? lastln : line;
106+}
107+
108+static String *
109+copystring(String *s, char *from)
110+{
111+ size_t len;
112+ char *t;
113+
114+ if ((t = strdup(from)) == NULL)
115+ error("out of memory");
116+ len = strlen(t);
117+
118+ free(s->str);
119+ s->str = t;
120+ s->siz = len;
121+ s->cap = len;
122+
123+ return s;
124+}
125+
126+static String *
127+string(String *s)
128+{
129+ free(s->str);
130+ s->str = NULL;
131+ s->siz = 0;
132+ s->cap = 0;
133+
134+ return s;
135+}
136+
137+static char *
138+addchar(char c, String *s)
139+{
140+ size_t cap = s->cap, siz = s->siz;
141+ char *t = s->str;
142+
143+ if (siz >= cap &&
144+ (cap > SIZE_MAX - LINESIZE ||
145+ (t = realloc(t, cap += LINESIZE)) == NULL))
146+ error("out of memory");
147+ t[siz++] = c;
148+ s->siz = siz;
149+ s->cap = cap;
150+ s->str = t;
151+ return t;
152+}
153+
154+static void chksignals(void);
155+
156+static int
157+input(void)
158+{
159+ int ch;
160+
161+ chksignals();
162+
163+ ch = cmdline.str[inputidx];
164+ if (ch != '\0')
165+ inputidx++;
166+ return ch;
167+}
168+
169+static int
170+back(int c)
171+{
172+ if (c == '\0')
173+ return c;
174+ return cmdline.str[--inputidx] = c;
175+}
176+
177+static int
178+makeline(char *s, int *off)
179+{
180+ struct hline *lp;
181+ size_t len;
182+ char *begin = s;
183+ int c;
184+
185+ if (lastidx >= idxsize) {
186+ lp = NULL;
187+ if (idxsize <= SIZE_MAX - NUMLINES)
188+ lp = reallocarray(zero, idxsize + NUMLINES, sizeof(*lp));
189+ if (!lp)
190+ error("out of memory");
191+ idxsize += NUMLINES;
192+ zero = lp;
193+ }
194+ lp = zero + lastidx;
195+ lp->global = 0;
196+
197+ if (!s) {
198+ lp->seek = -1;
199+ len = 0;
200+ } else {
201+ while ((c = *s++) && c != '\n')
202+ ;
203+ len = s - begin;
204+ if ((lp->seek = lseek(scratch, 0, SEEK_END)) < 0 ||
205+ write(scratch, begin, len) < 0) {
206+ error("input/output error");
207+ }
208+ }
209+ if (off)
210+ *off = len;
211+ ++lastidx;
212+ return lp - zero;
213+}
214+
215+static int
216+getindex(int line)
217+{
218+ struct hline *lp;
219+ int n;
220+
221+ if (line == -1)
222+ line = 0;
223+ for (n = 0, lp = zero; n != line; n++)
224+ lp = zero + lp->next;
225+
226+ return lp - zero;
227+}
228+
229+static char *
230+gettxt(int line)
231+{
232+ static char buf[CACHESIZ];
233+ static off_t lasto;
234+ struct hline *lp;
235+ off_t off, block;
236+ ssize_t n;
237+ char *p;
238+
239+ lp = zero + getindex(line);
240+ text.siz = 0;
241+ off = lp->seek;
242+
243+ if (off == (off_t) -1)
244+ return addchar('\0', &text);
245+
246+repeat:
247+ chksignals();
248+ if (!csize || off < lasto || off - lasto >= csize) {
249+ block = off & ~(CACHESIZ-1);
250+ if (lseek(scratch, block, SEEK_SET) < 0 ||
251+ (n = read(scratch, buf, CACHESIZ)) < 0) {
252+ error("input/output error");
253+ }
254+ csize = n;
255+ lasto = block;
256+ }
257+ for (p = buf + off - lasto; p < buf + csize && *p != '\n'; ++p) {
258+ ++off;
259+ addchar(*p, &text);
260+ }
261+ if (csize == CACHESIZ && p == buf + csize)
262+ goto repeat;
263+
264+ addchar('\n', &text);
265+ addchar('\0', &text);
266+ return text.str;
267+}
268+
269+static void
270+setglobal(int i, int v)
271+{
272+ zero[getindex(i)].global = v;
273+}
274+
275+static void
276+clearundo(void)
277+{
278+ free(udata.vec);
279+ udata.vec = NULL;
280+ newcmd = udata.nr = udata.cap = 0;
281+ modflag = 0;
282+}
283+
284+static void
285+newundo(int from1, int from2)
286+{
287+ struct link *p;
288+
289+ if (newcmd) {
290+ clearundo();
291+ udata.curln = ocurln;
292+ udata.lastln = olastln;
293+ }
294+ if (udata.nr >= udata.cap) {
295+ size_t siz = (udata.cap + 10) * sizeof(struct link);
296+ if ((p = realloc(udata.vec, siz)) == NULL)
297+ error("out of memory");
298+ udata.vec = p;
299+ udata.cap = udata.cap + 10;
300+ }
301+ p = &udata.vec[udata.nr++];
302+ p->from1 = from1;
303+ p->to1 = zero[from1].next;
304+ p->from2 = from2;
305+ p->to2 = zero[from2].prev;
306+}
307+
308+/*
309+ * relink: to1 <- from1
310+ * from2 -> to2
311+ */
312+static void
313+relink(int to1, int from1, int from2, int to2)
314+{
315+ newundo(from1, from2);
316+ zero[from1].next = to1;
317+ zero[from2].prev = to2;
318+ modflag = 1;
319+}
320+
321+static void
322+undo(void)
323+{
324+ struct link *p;
325+
326+ if (udata.nr == 0)
327+ return;
328+ for (p = &udata.vec[udata.nr-1]; udata.nr > 0; --p) {
329+ --udata.nr;
330+ zero[p->from1].next = p->to1;
331+ zero[p->from2].prev = p->to2;
332+ }
333+ free(udata.vec);
334+ udata.vec = NULL;
335+ udata.cap = 0;
336+ curln = udata.curln;
337+ lastln = udata.lastln;
338+}
339+
340+static void
341+inject(char *s, int where)
342+{
343+ int off, k, begin, end;
344+
345+ if (where == BEFORE) {
346+ begin = getindex(curln-1);
347+ end = getindex(nextln(curln-1));
348+ } else {
349+ begin = getindex(curln);
350+ end = getindex(nextln(curln));
351+ }
352+ while (*s) {
353+ k = makeline(s, &off);
354+ s += off;
355+ relink(k, begin, k, begin);
356+ relink(end, k, end, k);
357+ ++lastln;
358+ ++curln;
359+ begin = k;
360+ }
361+}
362+
363+static void
364+clearbuf(void)
365+{
366+ if (scratch)
367+ close(scratch);
368+ remove(tmpname);
369+ free(zero);
370+ zero = NULL;
371+ scratch = csize = idxsize = lastidx = curln = lastln = 0;
372+ modflag = lastln = curln = 0;
373+}
374+
375+static void
376+setscratch(void)
377+{
378+ int r, k;
379+ char *dir;
380+
381+ clearbuf();
382+ clearundo();
383+ if ((dir = getenv("TMPDIR")) == NULL)
384+ dir = "/tmp";
385+ r = snprintf(tmpname, sizeof(tmpname), "%s/%s",
386+ dir, "ed.XXXXXX");
387+ if (r < 0 || (size_t)r >= sizeof(tmpname))
388+ error("scratch filename too long");
389+ if ((scratch = mkstemp(tmpname)) < 0)
390+ error("failed to create scratch file");
391+ if ((k = makeline(NULL, NULL)))
392+ error("input/output error in scratch file");
393+ relink(k, k, k, k);
394+ clearundo();
395+}
396+
397+static void
398+compile(int delim)
399+{
400+ int n, ret, c,bracket;
401+ static char buf[BUFSIZ];
402+
403+ if (!isgraph(delim))
404+ error("invalid pattern delimiter");
405+
406+ bracket = lastre.siz = 0;
407+ for (n = 0;; ++n) {
408+ c = input();
409+ if (c == delim && !bracket || c == '\0') {
410+ break;
411+ } else if (c == '\\') {
412+ addchar(c, &lastre);
413+ c = input();
414+ } else if (c == '[') {
415+ bracket = 1;
416+ } else if (c == ']') {
417+ bracket = 0;
418+ }
419+ addchar(c, &lastre);
420+ }
421+ if (n == 0) {
422+ if (!pattern)
423+ error("no previous pattern");
424+ return;
425+ }
426+ addchar('\0', &lastre);
427+
428+ if (pattern)
429+ regfree(pattern);
430+ if (!pattern && (!(pattern = malloc(sizeof(*pattern)))))
431+ error("out of memory");
432+ if ((ret = regcomp(pattern, lastre.str, 0))) {
433+ regerror(ret, pattern, buf, sizeof(buf));
434+ error(buf);
435+ }
436+}
437+
438+static int
439+match(int num)
440+{
441+ int r;
442+
443+ lastmatch = gettxt(num);
444+ text.str[text.siz - 2] = '\0';
445+ r = !regexec(pattern, lastmatch, 10, matchs, 0);
446+ text.str[text.siz - 2] = '\n';
447+
448+ return r;
449+}
450+
451+static int
452+rematch(int num)
453+{
454+ regoff_t off = matchs[0].rm_eo;
455+ regmatch_t *m;
456+ int r;
457+
458+ text.str[text.siz - 2] = '\0';
459+ r = !regexec(pattern, lastmatch + off, 10, matchs, REG_NOTBOL);
460+ text.str[text.siz - 2] = '\n';
461+
462+ if (!r)
463+ return 0;
464+
465+ if (matchs[0].rm_eo > 0) {
466+ lastmatch += off;
467+ return 1;
468+ }
469+
470+ /* Zero width match was found at the end of the input, done */
471+ if (lastmatch[off] == '\n') {
472+ lastmatch += off;
473+ return 0;
474+ }
475+
476+ /* Zero width match at the current posiion, find the next one */
477+ text.str[text.siz - 2] = '\0';
478+ r = !regexec(pattern, lastmatch + off + 1, 10, matchs, REG_NOTBOL);
479+ text.str[text.siz - 2] = '\n';
480+
481+ if (!r)
482+ return 0;
483+
484+ /* Re-adjust matches to account for +1 in regexec */
485+ for (m = matchs; m < &matchs[10]; m++) {
486+ m->rm_so += 1;
487+ m->rm_eo += 1;
488+ }
489+ lastmatch += off;
490+
491+ return 1;
492+}
493+
494+static int
495+search(int way)
496+{
497+ int i;
498+
499+ i = curln;
500+ do {
501+ chksignals();
502+
503+ i = (way == '?') ? prevln(i) : nextln(i);
504+ if (i > 0 && match(i))
505+ return i;
506+ } while (i != curln);
507+
508+ error("invalid address");
509+ return -1; /* not reached */
510+}
511+
512+static void
513+skipblank(void)
514+{
515+ char c;
516+
517+ while ((c = input()) == ' ' || c == '\t')
518+ ;
519+ back(c);
520+}
521+
522+static void
523+ensureblank(void)
524+{
525+ char c;
526+
527+ switch ((c = input())) {
528+ case ' ':
529+ case '\t':
530+ skipblank();
531+ case '\0':
532+ back(c);
533+ break;
534+ default:
535+ error("unknown command");
536+ }
537+}
538+
539+static int
540+getnum(void)
541+{
542+ int ln, n, c;
543+
544+ for (ln = 0; isdigit(c = input()); ln += n) {
545+ if (ln > INT_MAX/10)
546+ goto invalid;
547+ n = c - '0';
548+ ln *= 10;
549+ if (INT_MAX - ln < n)
550+ goto invalid;
551+ }
552+ back(c);
553+ return ln;
554+
555+invalid:
556+ error("invalid address");
557+ return -1; /* not reached */
558+}
559+
560+static int
561+linenum(int *line)
562+{
563+ int ln, c;
564+
565+ skipblank();
566+
567+ switch (c = input()) {
568+ case '.':
569+ ln = curln;
570+ break;
571+ case '\'':
572+ skipblank();
573+ if (!islower(c = input()))
574+ error("invalid mark character");
575+ if (!(ln = marks[c - 'a']))
576+ error("invalid address");
577+ break;
578+ case '$':
579+ ln = lastln;
580+ break;
581+ case '?':
582+ case '/':
583+ compile(c);
584+ ln = search(c);
585+ break;
586+ case '^':
587+ case '-':
588+ case '+':
589+ ln = curln;
590+ back(c);
591+ break;
592+ default:
593+ back(c);
594+ if (isdigit(c))
595+ ln = getnum();
596+ else
597+ return 0;
598+ break;
599+ }
600+ *line = ln;
601+ return 1;
602+}
603+
604+static int
605+address(int *line)
606+{
607+ int ln, sign, c, num;
608+
609+ if (!linenum(&ln))
610+ return 0;
611+
612+ for (;;) {
613+ skipblank();
614+ if ((c = input()) != '+' && c != '-' && c != '^')
615+ break;
616+ sign = c == '+' ? 1 : -1;
617+ num = isdigit(back(input())) ? getnum() : 1;
618+ num *= sign;
619+ if (INT_MAX - ln < num)
620+ goto invalid;
621+ ln += num;
622+ }
623+ back(c);
624+
625+ if (ln < 0 || ln > lastln)
626+ error("invalid address");
627+ *line = ln;
628+ return 1;
629+
630+invalid:
631+ error("invalid address");
632+ return -1; /* not reached */
633+}
634+
635+static void
636+getlst(void)
637+{
638+ int ln, c;
639+
640+ if ((c = input()) == ',') {
641+ line1 = 1;
642+ line2 = lastln;
643+ nlines = lastln;
644+ return;
645+ } else if (c == ';') {
646+ line1 = curln;
647+ line2 = lastln;
648+ nlines = lastln - curln + 1;
649+ return;
650+ }
651+ back(c);
652+ line2 = curln;
653+ for (nlines = 0; address(&ln); ) {
654+ line1 = line2;
655+ line2 = ln;
656+ ++nlines;
657+
658+ skipblank();
659+ if ((c = input()) != ',' && c != ';') {
660+ back(c);
661+ break;
662+ }
663+ if (c == ';')
664+ curln = line2;
665+ }
666+ if (nlines > 2)
667+ nlines = 2;
668+ else if (nlines <= 1)
669+ line1 = line2;
670+}
671+
672+static void
673+deflines(int def1, int def2)
674+{
675+ if (!nlines) {
676+ line1 = def1;
677+ line2 = def2;
678+ }
679+ if (line1 > line2 || line1 < 0 || line2 > lastln)
680+ error("invalid address");
681+}
682+
683+static void
684+quit(void)
685+{
686+ clearbuf();
687+ exit(exstatus);
688+}
689+
690+static void
691+setinput(char *s)
692+{
693+ copystring(&cmdline, s);
694+ inputidx = 0;
695+}
696+
697+static void
698+getinput(void)
699+{
700+ int ch;
701+
702+ string(&cmdline);
703+
704+ while ((ch = getchar()) != '\n' && ch != EOF) {
705+ if (ch == '\\') {
706+ if ((ch = getchar()) == EOF)
707+ break;
708+ if (ch != '\n')
709+ addchar('\\', &cmdline);
710+ }
711+ addchar(ch, &cmdline);
712+ }
713+
714+ addchar('\0', &cmdline);
715+ inputidx = 0;
716+
717+ if (ch == EOF) {
718+ chksignals();
719+ if (ferror(stdin)) {
720+ exstatus = 1;
721+ fputs("ed: error reading input\n", stderr);
722+ }
723+ quit();
724+ }
725+}
726+
727+static int
728+moreinput(void)
729+{
730+ if (!uflag)
731+ return cmdline.str[inputidx] != '\0';
732+
733+ getinput();
734+ return 1;
735+}
736+
737+static void dowrite(const char *, int);
738+
739+static void
740+dump(void)
741+{
742+ char *home;
743+
744+ if (modflag)
745+ return;
746+
747+ line1 = nextln(0);
748+ line2 = lastln;
749+
750+ if (!setjmp(savesp)) {
751+ dowrite("ed.hup", 1);
752+ return;
753+ }
754+
755+ home = getenv("HOME");
756+ if (!home || chdir(home) < 0)
757+ return;
758+
759+ if (!setjmp(savesp))
760+ dowrite("ed.hup", 1);
761+}
762+
763+static void
764+chksignals(void)
765+{
766+ if (hup) {
767+ exstatus = 1;
768+ dump();
769+ quit();
770+ }
771+
772+ if (intr) {
773+ intr = 0;
774+ newcmd = 1;
775+ clearerr(stdin);
776+ error("Interrupt");
777+ }
778+}
779+
780+static const char *
781+expandcmd(void)
782+{
783+ static String cmd;
784+ char *p;
785+ int c, repl = 0;
786+
787+ skipblank();
788+ if ((c = input()) != '!') {
789+ back(c);
790+ string(&cmd);
791+ } else if (cmd.siz) {
792+ --cmd.siz;
793+ repl = 1;
794+ } else {
795+ error("no previous command");
796+ }
797+
798+ while ((c = input()) != '\0') {
799+ switch (c) {
800+ case '%':
801+ if (savfname[0] == '\0')
802+ error("no current filename");
803+ repl = 1;
804+ for (p = savfname; *p; ++p)
805+ addchar(*p, &cmd);
806+ break;
807+ case '\\':
808+ c = input();
809+ if (c != '%') {
810+ back(c);
811+ c = '\\';
812+ }
813+ default:
814+ addchar(c, &cmd);
815+ }
816+ }
817+ addchar('\0', &cmd);
818+
819+ if (repl)
820+ puts(cmd.str);
821+
822+ return cmd.str;
823+}
824+
825+static void
826+dowrite(const char *fname, int trunc)
827+{
828+ size_t bytecount = 0;
829+ int i, r, line;
830+ FILE *aux;
831+ static int sh;
832+ static FILE *fp;
833+ char *mode;
834+
835+ if (fp) {
836+ sh ? pclose(fp) : fclose(fp);
837+ fp = NULL;
838+ }
839+
840+ if (fname[0] == '!') {
841+ sh = 1;
842+ if((fp = popen(expandcmd(), "w")) == NULL)
843+ error("bad exec");
844+ } else {
845+ sh = 0;
846+ mode = (trunc) ? "w" : "a";
847+ if ((fp = fopen(fname, mode)) == NULL)
848+ error("cannot open input file");
849+ }
850+
851+ line = curln;
852+ for (i = line1; i <= line2; ++i) {
853+ chksignals();
854+
855+ gettxt(i);
856+ bytecount += text.siz - 1;
857+ fwrite(text.str, 1, text.siz - 1, fp);
858+ }
859+
860+ curln = line2;
861+
862+ aux = fp;
863+ fp = NULL;
864+ r = sh ? pclose(aux) : fclose(aux);
865+ if (r)
866+ error("input/output error");
867+ strcpy(savfname, fname);
868+ if (!sh)
869+ modflag = 0;
870+ curln = line;
871+ if (optdiag)
872+ printf("%zu\n", bytecount);
873+}
874+
875+static void
876+doread(const char *fname)
877+{
878+ int r;
879+ size_t cnt;
880+ ssize_t len;
881+ char *p;
882+ FILE *aux;
883+ static size_t n;
884+ static int sh;
885+ static char *s;
886+ static FILE *fp;
887+
888+ if (fp) {
889+ sh ? pclose(fp) : fclose(fp);
890+ fp = NULL;
891+ }
892+
893+ if(fname[0] == '!') {
894+ sh = 1;
895+ if((fp = popen(expandcmd(), "r")) == NULL)
896+ error("bad exec");
897+ } else if ((fp = fopen(fname, "r")) == NULL) {
898+ error("cannot open input file");
899+ }
900+
901+ curln = line2;
902+ for (cnt = 0; (len = getline(&s, &n, fp)) > 0; cnt += (size_t)len) {
903+ chksignals();
904+ if (s[len-1] != '\n') {
905+ if (len+1 >= n) {
906+ if (n == SIZE_MAX || !(p = realloc(s, ++n)))
907+ error("out of memory");
908+ s = p;
909+ }
910+ s[len] = '\n';
911+ s[len+1] = '\0';
912+ }
913+ inject(s, AFTER);
914+ }
915+ if (optdiag)
916+ printf("%zu\n", cnt);
917+
918+ aux = fp;
919+ fp = NULL;
920+ r = sh ? pclose(aux) : fclose(aux);
921+ if (r)
922+ error("input/output error");
923+}
924+
925+static void
926+doprint(void)
927+{
928+ int i, c;
929+ char *s, *str;
930+
931+ if (line1 <= 0 || line2 > lastln)
932+ error("incorrect address");
933+ for (i = line1; i <= line2; ++i) {
934+ chksignals();
935+ if (pflag == 'n')
936+ printf("%d\t", i);
937+ for (s = gettxt(i); (c = *s) != '\n'; ++s) {
938+ if (pflag != 'l')
939+ goto print_char;
940+ switch (c) {
941+ case '$':
942+ str = "\\$";
943+ goto print_str;
944+ case '\t':
945+ str = "\\t";
946+ goto print_str;
947+ case '\b':
948+ str = "\\b";
949+ goto print_str;
950+ case '\\':
951+ str = "\\\\";
952+ goto print_str;
953+ default:
954+ if (!isprint(c)) {
955+ printf("\\x%x", 0xFF & c);
956+ break;
957+ }
958+ print_char:
959+ putchar(c);
960+ break;
961+ print_str:
962+ fputs(str, stdout);
963+ break;
964+ }
965+ }
966+ if (pflag == 'l')
967+ fputs("$", stdout);
968+ putc('\n', stdout);
969+ }
970+ curln = i - 1;
971+}
972+
973+static void
974+dohelp(void)
975+{
976+ if (lasterr)
977+ puts(lasterr);
978+}
979+
980+static void
981+chkprint(int flag)
982+{
983+ int c;
984+
985+ if (flag) {
986+ if ((c = input()) == 'p' || c == 'l' || c == 'n')
987+ pflag = c;
988+ else
989+ back(c);
990+ }
991+ if ((c = input()) != '\0' && c != '\n')
992+ error("invalid command suffix");
993+}
994+
995+static char *
996+getfname(int comm)
997+{
998+ int c;
999+ char *bp;
1000+ static char fname[FILENAME_MAX];
1001+
1002+ skipblank();
1003+ if ((c = input()) == '!') {
1004+ return strcpy(fname, "!");
1005+ }
1006+ back(c);
1007+ for (bp = fname; bp < &fname[FILENAME_MAX]; *bp++ = c) {
1008+ if ((c = input()) == '\0')
1009+ break;
1010+ }
1011+ if (bp == fname) {
1012+ if (savfname[0] == '\0')
1013+ error("no current filename");
1014+ return savfname;
1015+ }
1016+ if (bp == &fname[FILENAME_MAX])
1017+ error("file name too long");
1018+ *bp = '\0';
1019+
1020+ if (fname[0] == '!')
1021+ return fname;
1022+ if (savfname[0] == '\0' || comm == 'e' || comm == 'f')
1023+ strcpy(savfname, fname);
1024+ return fname;
1025+}
1026+
1027+static void
1028+append(int num)
1029+{
1030+ int ch;
1031+ static String line;
1032+
1033+ curln = num;
1034+ while (moreinput()) {
1035+ string(&line);
1036+ while ((ch = input()) != '\n' && ch != '\0')
1037+ addchar(ch, &line);
1038+ addchar('\n', &line);
1039+ addchar('\0', &line);
1040+
1041+ if (!strcmp(line.str, ".\n") || !strcmp(line.str, "."))
1042+ break;
1043+ inject(line.str, AFTER);
1044+ }
1045+}
1046+
1047+static void
1048+delete(int from, int to)
1049+{
1050+ int lto, lfrom;
1051+
1052+ if (!from)
1053+ error("incorrect address");
1054+
1055+ lfrom = getindex(prevln(from));
1056+ lto = getindex(nextln(to));
1057+ lastln -= to - from + 1;
1058+ curln = (from > lastln) ? lastln : from;;
1059+ relink(lto, lfrom, lto, lfrom);
1060+}
1061+
1062+static void
1063+move(int where)
1064+{
1065+ int before, after, lto, lfrom;
1066+
1067+ if (!line1 || (where >= line1 && where <= line2))
1068+ error("incorrect address");
1069+
1070+ before = getindex(prevln(line1));
1071+ after = getindex(nextln(line2));
1072+ lfrom = getindex(line1);
1073+ lto = getindex(line2);
1074+ relink(after, before, after, before);
1075+
1076+ if (where < line1) {
1077+ curln = where + line1 - line2 + 1;
1078+ } else {
1079+ curln = where;
1080+ where -= line1 - line2 + 1;
1081+ }
1082+ before = getindex(where);
1083+ after = getindex(nextln(where));
1084+ relink(lfrom, before, lfrom, before);
1085+ relink(after, lto, after, lto);
1086+}
1087+
1088+static void
1089+join(void)
1090+{
1091+ int i;
1092+ char *t, c;
1093+ static String s;
1094+
1095+ string(&s);
1096+ for (i = line1;; i = nextln(i)) {
1097+ chksignals();
1098+ for (t = gettxt(i); (c = *t) != '\n'; ++t)
1099+ addchar(*t, &s);
1100+ if (i == line2)
1101+ break;
1102+ }
1103+
1104+ addchar('\n', &s);
1105+ addchar('\0', &s);
1106+ delete(line1, line2);
1107+ inject(s.str, BEFORE);
1108+}
1109+
1110+static void
1111+scroll(int num)
1112+{
1113+ int max, ln, cnt;
1114+
1115+ if (!line1 || line1 == lastln)
1116+ error("incorrect address");
1117+
1118+ ln = line1;
1119+ max = line1 + num;
1120+ if (max > lastln)
1121+ max = lastln;
1122+ for (cnt = line1; cnt < max; cnt++) {
1123+ chksignals();
1124+ fputs(gettxt(ln), stdout);
1125+ ln = nextln(ln);
1126+ }
1127+ curln = ln;
1128+}
1129+
1130+static void
1131+copy(int where)
1132+{
1133+
1134+ if (!line1)
1135+ error("incorrect address");
1136+ curln = where;
1137+
1138+ while (line1 <= line2) {
1139+ chksignals();
1140+ inject(gettxt(line1), AFTER);
1141+ if (line2 >= curln)
1142+ line2 = nextln(line2);
1143+ line1 = nextln(line1);
1144+ if (line1 >= curln)
1145+ line1 = nextln(line1);
1146+ }
1147+}
1148+
1149+static void
1150+execsh(void)
1151+{
1152+ system(expandcmd());
1153+ if (optdiag)
1154+ puts("!");
1155+}
1156+
1157+static void
1158+getrhs(int delim)
1159+{
1160+ int c;
1161+ static String s;
1162+
1163+ string(&s);
1164+ while ((c = input()) != '\0' && c != delim)
1165+ addchar(c, &s);
1166+ addchar('\0', &s);
1167+ if (c == '\0') {
1168+ pflag = 'p';
1169+ back(c);
1170+ }
1171+
1172+ if (!strcmp("%", s.str)) {
1173+ if (!rhs)
1174+ error("no previous substitution");
1175+ free(s.str);
1176+ } else {
1177+ free(rhs);
1178+ rhs = s.str;
1179+ }
1180+ s.str = NULL;
1181+}
1182+
1183+static int
1184+getnth(void)
1185+{
1186+ int c;
1187+
1188+ if ((c = input()) == 'g') {
1189+ return -1;
1190+ } else if (isdigit(c)) {
1191+ if (c == '0')
1192+ return -1;
1193+ return c - '0';
1194+ } else {
1195+ back(c);
1196+ return 1;
1197+ }
1198+}
1199+
1200+static void
1201+addpre(String *s)
1202+{
1203+ char *p;
1204+
1205+ for (p = lastmatch; p < lastmatch + matchs[0].rm_so; ++p)
1206+ addchar(*p, s);
1207+}
1208+
1209+static void
1210+addpost(String *s)
1211+{
1212+ char c, *p;
1213+
1214+ for (p = lastmatch + matchs[0].rm_eo; (c = *p); ++p)
1215+ addchar(c, s);
1216+ addchar('\0', s);
1217+}
1218+
1219+static int
1220+addsub(String *s, int nth, int nmatch)
1221+{
1222+ char *end, *q, *p, c;
1223+ int sub;
1224+
1225+ if (nth != nmatch && nth != -1) {
1226+ q = lastmatch + matchs[0].rm_so;
1227+ end = lastmatch + matchs[0].rm_eo;
1228+ while (q < end)
1229+ addchar(*q++, s);
1230+ return 0;
1231+ }
1232+
1233+ for (p = rhs; (c = *p); ++p) {
1234+ switch (c) {
1235+ case '&':
1236+ sub = 0;
1237+ goto copy_match;
1238+ case '\\':
1239+ if ((c = *++p) == '\0')
1240+ return 1;
1241+ if (!isdigit(c))
1242+ goto copy_char;
1243+ sub = c - '0';
1244+ copy_match:
1245+ q = lastmatch + matchs[sub].rm_so;
1246+ end = lastmatch + matchs[sub].rm_eo;
1247+ while (q < end)
1248+ addchar(*q++, s);
1249+ break;
1250+ default:
1251+ copy_char:
1252+ addchar(c, s);
1253+ break;
1254+ }
1255+ }
1256+ return 1;
1257+}
1258+
1259+static void
1260+subline(int num, int nth)
1261+{
1262+ int i, m, changed;
1263+ static String s;
1264+
1265+ string(&s);
1266+ i = changed = 0;
1267+ for (m = match(num); m; m = (nth < 0 || i < nth) && rematch(num)) {
1268+ chksignals();
1269+ addpre(&s);
1270+ changed |= addsub(&s, nth, ++i);
1271+ }
1272+ if (!changed)
1273+ return;
1274+ addpost(&s);
1275+ delete(num, num);
1276+ curln = prevln(num);
1277+ inject(s.str, AFTER);
1278+}
1279+
1280+static void
1281+subst(int nth)
1282+{
1283+ int i, line, next;
1284+
1285+ line = line1;
1286+ for (i = 0; i < line2 - line1 + 1; i++) {
1287+ chksignals();
1288+
1289+ next = getindex(nextln(line));
1290+ subline(line, nth);
1291+
1292+ /*
1293+ * The substitution command can add lines, so
1294+ * we have to skip lines until we find the
1295+ * index that we saved before the substitution
1296+ */
1297+ do
1298+ line = nextln(line);
1299+ while (getindex(line) != next);
1300+ }
1301+}
1302+
1303+static void
1304+docmd(void)
1305+{
1306+ char *var;
1307+ int cmd, c, line3, num, trunc;
1308+
1309+repeat:
1310+ skipblank();
1311+ cmd = input();
1312+ trunc = pflag = 0;
1313+ switch (cmd) {
1314+ case '&':
1315+ skipblank();
1316+ chkprint(0);
1317+ if (!ocmdline)
1318+ error("no previous command");
1319+ setinput(ocmdline);
1320+ getlst();
1321+ goto repeat;
1322+ case '!':
1323+ execsh();
1324+ break;
1325+ case '\0':
1326+ num = gflag ? curln : curln+1;
1327+ deflines(num, num);
1328+ line1 = line2;
1329+ pflag = 'p';
1330+ goto print;
1331+ case 'l':
1332+ case 'n':
1333+ case 'p':
1334+ back(cmd);
1335+ chkprint(1);
1336+ deflines(curln, curln);
1337+ goto print;
1338+ case 'g':
1339+ case 'G':
1340+ case 'v':
1341+ case 'V':
1342+ error("cannot nest global commands");
1343+ case 'H':
1344+ if (nlines > 0)
1345+ goto unexpected;
1346+ chkprint(0);
1347+ optverbose ^= 1;
1348+ break;
1349+ case 'h':
1350+ if (nlines > 0)
1351+ goto unexpected;
1352+ chkprint(0);
1353+ dohelp();
1354+ break;
1355+ case 'w':
1356+ trunc = 1;
1357+ case 'W':
1358+ ensureblank();
1359+ deflines(nextln(0), lastln);
1360+ dowrite(getfname(cmd), trunc);
1361+ break;
1362+ case 'r':
1363+ ensureblank();
1364+ if (nlines > 1)
1365+ goto bad_address;
1366+ deflines(lastln, lastln);
1367+ doread(getfname(cmd));
1368+ break;
1369+ case 'd':
1370+ chkprint(1);
1371+ deflines(curln, curln);
1372+ delete(line1, line2);
1373+ break;
1374+ case '=':
1375+ if (nlines > 1)
1376+ goto bad_address;
1377+ chkprint(1);
1378+ deflines(lastln, lastln);
1379+ printf("%d\n", line1);
1380+ break;
1381+ case 'u':
1382+ if (nlines > 0)
1383+ goto bad_address;
1384+ chkprint(1);
1385+ if (udata.nr == 0)
1386+ error("nothing to undo");
1387+ undo();
1388+ break;
1389+ case 's':
1390+ deflines(curln, curln);
1391+ c = input();
1392+ compile(c);
1393+ getrhs(c);
1394+ num = getnth();
1395+ chkprint(1);
1396+ subst(num);
1397+ break;
1398+ case 'i':
1399+ if (nlines > 1)
1400+ goto bad_address;
1401+ chkprint(1);
1402+ deflines(curln, curln);
1403+ if (!line1)
1404+ line1++;
1405+ append(prevln(line1));
1406+ break;
1407+ case 'a':
1408+ if (nlines > 1)
1409+ goto bad_address;
1410+ chkprint(1);
1411+ deflines(curln, curln);
1412+ append(line1);
1413+ break;
1414+ case 'm':
1415+ deflines(curln, curln);
1416+ if (!address(&line3))
1417+ line3 = curln;
1418+ chkprint(1);
1419+ move(line3);
1420+ break;
1421+ case 't':
1422+ deflines(curln, curln);
1423+ if (!address(&line3))
1424+ line3 = curln;
1425+ chkprint(1);
1426+ copy(line3);
1427+ break;
1428+ case 'c':
1429+ chkprint(1);
1430+ deflines(curln, curln);
1431+ delete(line1, line2);
1432+ append(prevln(line1));
1433+ break;
1434+ case 'j':
1435+ chkprint(1);
1436+ deflines(curln, curln+1);
1437+ if (line1 != line2 && curln != 0)
1438+ join();
1439+ break;
1440+ case 'z':
1441+ if (nlines > 1)
1442+ goto bad_address;
1443+
1444+ num = 0;
1445+ if (isdigit(back(input())))
1446+ num = getnum();
1447+ else if ((var = getenv("LINES")) != NULL)
1448+ num = atoi(var) - 1;
1449+ if (num <= 0)
1450+ num = 23;
1451+ chkprint(1);
1452+ deflines(curln, curln);
1453+ scroll(num);
1454+ break;
1455+ case 'k':
1456+ if (nlines > 1)
1457+ goto bad_address;
1458+ if (!islower(c = input()))
1459+ error("invalid mark character");
1460+ chkprint(1);
1461+ deflines(curln, curln);
1462+ marks[c - 'a'] = line1;
1463+ break;
1464+ case 'P':
1465+ if (nlines > 0)
1466+ goto unexpected;
1467+ chkprint(1);
1468+ optprompt ^= 1;
1469+ break;
1470+ case 'x':
1471+ trunc = 1;
1472+ case 'X':
1473+ ensureblank();
1474+ if (nlines > 0)
1475+ goto unexpected;
1476+ exstatus = 0;
1477+ deflines(nextln(0), lastln);
1478+ dowrite(getfname(cmd), trunc);
1479+ case 'Q':
1480+ case 'q':
1481+ if (nlines > 0)
1482+ goto unexpected;
1483+ if (cmd != 'Q' && modflag)
1484+ goto modified;
1485+ modflag = 0;
1486+ quit();
1487+ break;
1488+ case 'f':
1489+ ensureblank();
1490+ if (nlines > 0)
1491+ goto unexpected;
1492+ if (back(input()) != '\0')
1493+ getfname(cmd);
1494+ else
1495+ puts(savfname);
1496+ chkprint(0);
1497+ break;
1498+ case 'E':
1499+ case 'e':
1500+ ensureblank();
1501+ if (nlines > 0)
1502+ goto unexpected;
1503+ if (cmd == 'e' && modflag)
1504+ goto modified;
1505+ setscratch();
1506+ deflines(curln, curln);
1507+ doread(getfname(cmd));
1508+ clearundo();
1509+ modflag = 0;
1510+ break;
1511+ default:
1512+ error("unknown command");
1513+ bad_address:
1514+ error("invalid address");
1515+ modified:
1516+ modflag = 0;
1517+ error("warning: file modified");
1518+ unexpected:
1519+ error("unexpected address");
1520+ }
1521+
1522+ if (!pflag)
1523+ return;
1524+ line1 = line2 = curln;
1525+
1526+print:
1527+ doprint();
1528+}
1529+
1530+static int
1531+chkglobal(void)
1532+{
1533+ int delim, c, dir, i, v;
1534+
1535+ uflag = 1;
1536+ gflag = 0;
1537+ skipblank();
1538+
1539+ switch (c = input()) {
1540+ case 'g':
1541+ uflag = 0;
1542+ case 'G':
1543+ dir = 1;
1544+ break;
1545+ case 'v':
1546+ uflag = 0;
1547+ case 'V':
1548+ dir = 0;
1549+ break;
1550+ default:
1551+ back(c);
1552+ return 0;
1553+ }
1554+ gflag = 1;
1555+ deflines(nextln(0), lastln);
1556+ delim = input();
1557+ compile(delim);
1558+
1559+ for (i = 1; i <= lastln; ++i) {
1560+ chksignals();
1561+ if (i >= line1 && i <= line2)
1562+ v = match(i) == dir;
1563+ else
1564+ v = 0;
1565+ setglobal(i, v);
1566+ }
1567+
1568+ return 1;
1569+}
1570+
1571+static void
1572+savecmd(void)
1573+{
1574+ int ch;
1575+
1576+ skipblank();
1577+ ch = input();
1578+ if (ch != '&') {
1579+ ocmdline = strdup(cmdline.str);
1580+ if (ocmdline == NULL)
1581+ error("out of memory");
1582+ }
1583+ back(ch);
1584+}
1585+
1586+static void
1587+doglobal(void)
1588+{
1589+ int cnt, ln, k, idx, c;
1590+
1591+ skipblank();
1592+ gflag = 1;
1593+ if (uflag)
1594+ chkprint(0);
1595+
1596+ ln = line1;
1597+ for (cnt = 0; cnt < lastln; ) {
1598+ chksignals();
1599+ k = getindex(ln);
1600+ if (zero[k].global) {
1601+ zero[k].global = 0;
1602+ curln = ln;
1603+ nlines = 0;
1604+
1605+ if (!uflag) {
1606+ idx = inputidx;
1607+ getlst();
1608+ for (;;) {
1609+ docmd();
1610+ if (!(c = input()))
1611+ break;
1612+ back(c);
1613+ }
1614+ inputidx = idx;
1615+ continue;
1616+ }
1617+
1618+ line1 = line2 = ln;
1619+ pflag = 0;
1620+ doprint();
1621+
1622+ for (;;) {
1623+ getinput();
1624+ if (strcmp(cmdline.str, "") == 0)
1625+ break;
1626+ savecmd();
1627+ getlst();
1628+ docmd();
1629+ }
1630+
1631+ } else {
1632+ cnt++;
1633+ ln = nextln(ln);
1634+ }
1635+ }
1636+}
1637+
1638+static void
1639+usage(void)
1640+{
1641+ eprintf("usage: %s [-s] [-p] [file]\n", argv0);
1642+}
1643+
1644+static void
1645+sigintr(int n)
1646+{
1647+ intr = 1;
1648+}
1649+
1650+static void
1651+sighup(int dummy)
1652+{
1653+ hup = 1;
1654+}
1655+
1656+static void
1657+edit(void)
1658+{
1659+ for (;;) {
1660+ newcmd = 1;
1661+ ocurln = curln;
1662+ olastln = lastln;
1663+ if (optprompt) {
1664+ fputs(prompt, stdout);
1665+ fflush(stdout);
1666+ }
1667+
1668+ getinput();
1669+ getlst();
1670+ chkglobal() ? doglobal() : docmd();
1671+ }
1672+}
1673+
1674+static void
1675+init(char *fname)
1676+{
1677+ size_t len;
1678+
1679+ setscratch();
1680+ if (!fname)
1681+ return;
1682+ if ((len = strlen(fname)) >= FILENAME_MAX || len == 0)
1683+ error("incorrect filename");
1684+ memcpy(savfname, fname, len);
1685+ doread(fname);
1686+ clearundo();
1687+}
1688+
1689+int
1690+main(int argc, char *argv[])
1691+{
1692+ ARGBEGIN {
1693+ case 'p':
1694+ prompt = EARGF(usage());
1695+ optprompt = 1;
1696+ break;
1697+ case 's':
1698+ optdiag = 0;
1699+ break;
1700+ default:
1701+ usage();
1702+ } ARGEND
1703+
1704+ if (argc > 1)
1705+ usage();
1706+
1707+ if (!setjmp(savesp)) {
1708+ sigaction(SIGINT,
1709+ &(struct sigaction) {.sa_handler = sigintr},
1710+ NULL);
1711+ sigaction(SIGHUP,
1712+ &(struct sigaction) {.sa_handler = sighup},
1713+ NULL);
1714+ sigaction(SIGQUIT,
1715+ &(struct sigaction) {.sa_handler = SIG_IGN},
1716+ NULL);
1717+ init(*argv);
1718+ }
1719+ edit();
1720+
1721+ /* not reached */
1722+ return 0;
1723+}
+49,
-0
1@@ -0,0 +1,49 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+extern char **environ;
12+
13+static void
14+usage(void)
15+{
16+ eprintf("usage: %s [-i] [-u var] ... [var=value] ... [cmd [arg ...]]\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+ int savederrno;
23+
24+ ARGBEGIN {
25+ case 'i':
26+ *environ = NULL;
27+ break;
28+ case 'u':
29+ if (unsetenv(EARGF(usage())) < 0)
30+ eprintf("unsetenv:");
31+ break;
32+ default:
33+ usage();
34+ } ARGEND
35+
36+ for (; *argv && strchr(*argv, '='); argc--, argv++)
37+ putenv(*argv);
38+
39+ if (*argv) {
40+ execvp(*argv, argv);
41+ savederrno = errno;
42+ weprintf("execvp %s:", *argv);
43+ _exit(126 + (savederrno == ENOENT));
44+ }
45+
46+ for (; *environ; environ++)
47+ puts(*environ);
48+
49+ return fshut(stdout, "<stdout>");
50+}
+131,
-0
1@@ -0,0 +1,131 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "utf.h"
8+#include "util.h"
9+
10+static int iflag = 0;
11+static size_t *tablist = NULL;
12+static size_t tablistlen = 0;
13+
14+static size_t
15+parselist(const char *s)
16+{
17+ size_t i;
18+ char *p, *tmp;
19+
20+ tmp = estrdup(s);
21+ for (i = 0; (p = strsep(&tmp, " ,")); i++) {
22+ if (*p == '\0')
23+ eprintf("empty field in tablist\n");
24+ tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
25+ tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
26+ if (i > 0 && tablist[i - 1] >= tablist[i])
27+ eprintf("tablist must be ascending\n");
28+ }
29+ tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
30+ /* tab length = 1 for the overflowing case later in the matcher */
31+ tablist[i] = 1;
32+
33+ return i;
34+}
35+
36+static int
37+expand(const char *file, FILE *fp)
38+{
39+ size_t bol = 1, col = 0, i;
40+ Rune r;
41+
42+ while (efgetrune(&r, fp, file)) {
43+ switch (r) {
44+ case '\t':
45+ if (tablistlen == 1)
46+ i = 0;
47+ else for (i = 0; i < tablistlen; i++)
48+ if (col < tablist[i])
49+ break;
50+ if (bol || !iflag) {
51+ do {
52+ col++;
53+ putchar(' ');
54+ } while (col % tablist[i]);
55+ } else {
56+ putchar('\t');
57+ col = tablist[i];
58+ }
59+ break;
60+ case '\b':
61+ bol = 0;
62+ if (col)
63+ col--;
64+ putchar('\b');
65+ break;
66+ case '\n':
67+ bol = 1;
68+ col = 0;
69+ putchar('\n');
70+ break;
71+ default:
72+ col++;
73+ if (r != ' ')
74+ bol = 0;
75+ efputrune(&r, stdout, "<stdout>");
76+ break;
77+ }
78+ }
79+
80+ return 0;
81+}
82+
83+static void
84+usage(void)
85+{
86+ eprintf("usage: %s [-i] [-t tablist] [file ...]\n", argv0);
87+}
88+
89+int
90+main(int argc, char *argv[])
91+{
92+ FILE *fp;
93+ int ret = 0;
94+ char *tl = "8";
95+
96+ ARGBEGIN {
97+ case 'i':
98+ iflag = 1;
99+ break;
100+ case 't':
101+ tl = EARGF(usage());
102+ if (!*tl)
103+ eprintf("tablist cannot be empty\n");
104+ break;
105+ default:
106+ usage();
107+ } ARGEND
108+
109+ tablistlen = parselist(tl);
110+
111+ if (!argc) {
112+ expand("<stdin>", stdin);
113+ } else {
114+ for (; *argv; argc--, argv++) {
115+ if (!strcmp(*argv, "-")) {
116+ *argv = "<stdin>";
117+ fp = stdin;
118+ } else if (!(fp = fopen(*argv, "r"))) {
119+ weprintf("fopen %s:", *argv);
120+ ret = 1;
121+ continue;
122+ }
123+ expand(*argv, fp);
124+ if (fp != stdin && fshut(fp, *argv))
125+ ret = 1;
126+ }
127+ }
128+
129+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
130+
131+ return ret;
132+}
+244,
-0
1@@ -0,0 +1,244 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "utf.h"
9+#include "util.h"
10+
11+/* tokens, one-character operators represent themselves */
12+enum {
13+ VAL = CHAR_MAX + 1, GE, LE, NE
14+};
15+
16+struct val {
17+ char *str;
18+ long long num;
19+};
20+
21+static void
22+tonum(struct val *v)
23+{
24+ const char *errstr;
25+ long long d;
26+
27+ /* check if val is the result of an earlier calculation */
28+ if (!v->str)
29+ return;
30+
31+ d = strtonum(v->str, LLONG_MIN, LLONG_MAX, &errstr);
32+ if (errstr)
33+ enprintf(2, "error: expected integer, got %s\n", v->str);
34+ v->num = d;
35+}
36+
37+static void
38+ezero(struct val *v)
39+{
40+ if (v->num != 0)
41+ return;
42+ enprintf(2, "division by zero\n");
43+}
44+
45+static int
46+valcmp(struct val *a, struct val *b)
47+{
48+ int ret;
49+ const char *err1, *err2;
50+ long long d1, d2;
51+
52+ d1 = strtonum(a->str, LLONG_MIN, LLONG_MAX, &err1);
53+ d2 = strtonum(b->str, LLONG_MIN, LLONG_MAX, &err2);
54+
55+ if (!err1 && !err2) {
56+ ret = (d1 > d2) - (d1 < d2);
57+ } else {
58+ ret = strcmp(a->str, b->str);
59+ }
60+
61+ return ret;
62+}
63+
64+static void
65+match(struct val *vstr, struct val *vregx, struct val *ret)
66+{
67+ regex_t re;
68+ regmatch_t matches[2];
69+ size_t anchlen;
70+ char *s, *p, *anchreg;
71+ char *str = vstr->str, *regx = vregx->str;
72+
73+ /* anchored regex */
74+ anchlen = strlen(regx) + 1 + 1;
75+ anchreg = emalloc(anchlen);
76+ estrlcpy(anchreg, "^", anchlen);
77+ estrlcat(anchreg, regx, anchlen);
78+ enregcomp(3, &re, anchreg, 0);
79+ free(anchreg);
80+
81+ if (regexec(&re, str, 2, matches, 0)) {
82+ regfree(&re);
83+ ret->str = re.re_nsub ? "" : NULL;
84+ return;
85+ } else if (re.re_nsub) {
86+ regfree(&re);
87+
88+ s = str + matches[1].rm_so;
89+ p = str + matches[1].rm_eo;
90+ *p = '\0';
91+ ret->str = enstrdup(3, s);
92+ return;
93+ } else {
94+ regfree(&re);
95+ str += matches[0].rm_so;
96+ ret->num = utfnlen(str, matches[0].rm_eo - matches[0].rm_so);
97+ return;
98+ }
99+}
100+
101+static void
102+doop(int *ophead, int *opp, struct val *valhead, struct val *valp)
103+{
104+ struct val ret = { .str = NULL, .num = 0 }, *a, *b;
105+ int op;
106+
107+ /* an operation "a op b" needs an operator and two values */
108+ if (opp[-1] == '(')
109+ enprintf(2, "syntax error: extra (\n");
110+ if (valp - valhead < 2)
111+ enprintf(2, "syntax error: missing expression or extra operator\n");
112+
113+ a = valp - 2;
114+ b = valp - 1;
115+ op = opp[-1];
116+
117+ switch (op) {
118+ case '|':
119+ if ( a->str && *a->str) ret.str = a->str;
120+ else if (!a->str && a->num) ret.num = a->num;
121+ else if ( b->str && *b->str) ret.str = b->str;
122+ else ret.num = b->num;
123+ break;
124+ case '&':
125+ if (((a->str && *a->str) || a->num) &&
126+ ((b->str && *b->str) || b->num)) {
127+ ret.str = a->str;
128+ ret.num = a->num;
129+ }
130+ break;
131+
132+ case '=': ret.num = (valcmp(a, b) == 0); break;
133+ case '>': ret.num = (valcmp(a, b) > 0); break;
134+ case GE : ret.num = (valcmp(a, b) >= 0); break;
135+ case '<': ret.num = (valcmp(a, b) < 0); break;
136+ case LE : ret.num = (valcmp(a, b) <= 0); break;
137+ case NE : ret.num = (valcmp(a, b) != 0); break;
138+
139+ case '+': tonum(a); tonum(b); ret.num = a->num + b->num; break;
140+ case '-': tonum(a); tonum(b); ret.num = a->num - b->num; break;
141+ case '*': tonum(a); tonum(b); ret.num = a->num * b->num; break;
142+ case '/': tonum(a); tonum(b); ezero(b); ret.num = a->num / b->num; break;
143+ case '%': tonum(a); tonum(b); ezero(b); ret.num = a->num % b->num; break;
144+
145+ case ':': match(a, b, &ret); break;
146+ }
147+
148+ valp[-2] = ret;
149+}
150+
151+static int
152+lex(char *s, struct val *v)
153+{
154+ int type = VAL;
155+ char *ops = "|&=><+-*/%():";
156+
157+ if (s[0] && strchr(ops, s[0]) && !s[1]) {
158+ /* one-char operand */
159+ type = s[0];
160+ } else if (s[0] && strchr("><!", s[0]) && s[1] == '=' && !s[2]) {
161+ /* two-char operand */
162+ type = (s[0] == '>') ? GE : (s[0] == '<') ? LE : NE;
163+ }
164+
165+ return type;
166+}
167+
168+static int
169+parse(char *expr[], int numexpr)
170+{
171+ struct val *valhead, *valp, v = { .str = NULL, .num = 0 };
172+ int *ophead, *opp, type, lasttype = 0;
173+ char prec[] = {
174+ [ 0 ] = 0, [VAL] = 0, ['('] = 0, [')'] = 0,
175+ ['|'] = 1,
176+ ['&'] = 2,
177+ ['='] = 3, ['>'] = 3, [GE] = 3, ['<'] = 3, [LE] = 3, [NE] = 3,
178+ ['+'] = 4, ['-'] = 4,
179+ ['*'] = 5, ['/'] = 5, ['%'] = 5,
180+ [':'] = 6,
181+ };
182+
183+ valp = valhead = enreallocarray(3, NULL, numexpr, sizeof(*valp));
184+ opp = ophead = enreallocarray(3, NULL, numexpr, sizeof(*opp));
185+ for (; *expr; expr++) {
186+ switch ((type = lex(*expr, &v))) {
187+ case VAL:
188+ /* treatment of *expr is not known until
189+ * doop(); treat as a string for now */
190+ valp->str = *expr;
191+ valp++;
192+ break;
193+ case '(':
194+ *opp++ = type;
195+ break;
196+ case ')':
197+ if (lasttype == '(')
198+ enprintf(2, "syntax error: empty ( )\n");
199+ while (opp > ophead && opp[-1] != '(')
200+ doop(ophead, opp--, valhead, valp--);
201+ if (opp == ophead)
202+ enprintf(2, "syntax error: extra )\n");
203+ opp--;
204+ break;
205+ default: /* operator */
206+ if (prec[lasttype])
207+ enprintf(2, "syntax error: extra operator\n");
208+ while (opp > ophead && prec[opp[-1]] >= prec[type])
209+ doop(ophead, opp--, valhead, valp--);
210+ *opp++ = type;
211+ break;
212+ }
213+ lasttype = type;
214+ v.str = NULL;
215+ v.num = 0;
216+ }
217+ while (opp > ophead)
218+ doop(ophead, opp--, valhead, valp--);
219+ if (valp == valhead)
220+ enprintf(2, "syntax error: missing expression\n");
221+ if (--valp > valhead)
222+ enprintf(2, "syntax error: extra expression\n");
223+
224+ if (valp->str)
225+ puts(valp->str);
226+ else
227+ printf("%lld\n", valp->num);
228+
229+ return (valp->str && *valp->str) || valp->num;
230+}
231+
232+int
233+main(int argc, char *argv[])
234+{
235+ int ret;
236+
237+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
238+
239+ ret = !parse(argv, argc);
240+
241+ if (fshut(stdout, "<stdout>"))
242+ ret = 3;
243+
244+ return ret;
245+}
+6,
-0
1@@ -0,0 +1,6 @@
2+/* See LICENSE file for copyright and license details. */
3+int
4+main(void)
5+{
6+ return 1;
7+}
+1103,
-0
1@@ -0,0 +1,1103 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <dirent.h>
4+#include <errno.h>
5+#include <fnmatch.h>
6+#include <grp.h>
7+#include <libgen.h>
8+#include <pwd.h>
9+#include <stdint.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <time.h>
14+#include <unistd.h>
15+
16+#include <sys/stat.h>
17+#include <sys/wait.h>
18+
19+#include "util.h"
20+
21+/* because putting integers in pointers is undefined by the standard */
22+union extra {
23+ void *p;
24+ intmax_t i;
25+};
26+
27+/* Argument passed into a primary's function */
28+struct arg {
29+ char *path;
30+ struct stat *st;
31+ union extra extra;
32+};
33+
34+/* Information about each primary, for lookup table */
35+struct pri_info {
36+ char *name;
37+ int (*func)(struct arg *arg);
38+ char **(*getarg)(char **argv, union extra *extra);
39+ void (*freearg)(union extra extra);
40+ char narg; /* -xdev, -depth, -print don't take args but have getarg() */
41+};
42+
43+/* Information about operators, for lookup table */
44+struct op_info {
45+ char *name; /* string representation of op */
46+ char type; /* from tok.type */
47+ char prec; /* precedence */
48+ char nargs; /* number of arguments (unary or binary) */
49+ char lassoc; /* left associative */
50+};
51+
52+/* Token when lexing/parsing
53+ * (although also used for the expression tree) */
54+struct tok {
55+ struct tok *left, *right; /* if (type == NOT) left = NULL */
56+ union extra extra;
57+ union {
58+ struct pri_info *pinfo; /* if (type == PRIM) */
59+ struct op_info *oinfo;
60+ } u;
61+ enum {
62+ PRIM = 0, LPAR, RPAR, NOT, AND, OR, END
63+ } type;
64+};
65+
66+/* structures used for arg.extra.p and tok.extra.p */
67+struct permarg {
68+ mode_t mode;
69+ char exact;
70+};
71+
72+struct okarg {
73+ char ***braces;
74+ char **argv;
75+};
76+
77+/* for all arguments that take a number
78+ * +n, n, -n mean > n, == n, < n respectively */
79+struct narg {
80+ int (*cmp)(int a, int b);
81+ int n;
82+};
83+
84+struct sizearg {
85+ struct narg n;
86+ char bytes; /* size is in bytes, not 512 byte sectors */
87+};
88+
89+struct execarg {
90+ union {
91+ struct {
92+ char ***braces; /* NULL terminated list of pointers into argv where {} were */
93+ } s; /* semicolon */
94+ struct {
95+ size_t arglen; /* number of bytes in argv before files are added */
96+ size_t filelen; /* numer of bytes in file names added to argv */
97+ size_t first; /* index one past last arg, where first file goes */
98+ size_t next; /* index where next file goes */
99+ size_t cap; /* capacity of argv */
100+ } p; /* plus */
101+ } u;
102+ char **argv; /* NULL terminated list of arguments (allocated if isplus) */
103+ char isplus; /* -exec + instead of -exec ; */
104+};
105+
106+/* used to find loops while recursing through directory structure */
107+struct findhist {
108+ struct findhist *next;
109+ char *path;
110+ dev_t dev;
111+ ino_t ino;
112+};
113+
114+/* Utility */
115+static int spawn(char *argv[]);
116+static int do_stat(char *path, struct stat *sb, struct findhist *hist);
117+
118+/* Primaries */
119+static int pri_name (struct arg *arg);
120+static int pri_path (struct arg *arg);
121+static int pri_nouser (struct arg *arg);
122+static int pri_nogroup(struct arg *arg);
123+static int pri_xdev (struct arg *arg);
124+static int pri_prune (struct arg *arg);
125+static int pri_perm (struct arg *arg);
126+static int pri_type (struct arg *arg);
127+static int pri_links (struct arg *arg);
128+static int pri_user (struct arg *arg);
129+static int pri_group (struct arg *arg);
130+static int pri_size (struct arg *arg);
131+static int pri_atime (struct arg *arg);
132+static int pri_ctime (struct arg *arg);
133+static int pri_mtime (struct arg *arg);
134+static int pri_exec (struct arg *arg);
135+static int pri_ok (struct arg *arg);
136+static int pri_print (struct arg *arg);
137+static int pri_print0 (struct arg *arg);
138+static int pri_newer (struct arg *arg);
139+static int pri_depth (struct arg *arg);
140+
141+/* Getargs */
142+static char **get_name_arg (char *argv[], union extra *extra);
143+static char **get_path_arg (char *argv[], union extra *extra);
144+static char **get_xdev_arg (char *argv[], union extra *extra);
145+static char **get_perm_arg (char *argv[], union extra *extra);
146+static char **get_type_arg (char *argv[], union extra *extra);
147+static char **get_n_arg (char *argv[], union extra *extra);
148+static char **get_user_arg (char *argv[], union extra *extra);
149+static char **get_group_arg(char *argv[], union extra *extra);
150+static char **get_size_arg (char *argv[], union extra *extra);
151+static char **get_exec_arg (char *argv[], union extra *extra);
152+static char **get_ok_arg (char *argv[], union extra *extra);
153+static char **get_print_arg(char *argv[], union extra *extra);
154+static char **get_newer_arg(char *argv[], union extra *extra);
155+static char **get_depth_arg(char *argv[], union extra *extra);
156+
157+/* Freeargs */
158+static void free_extra (union extra extra);
159+static void free_exec_arg(union extra extra);
160+static void free_ok_arg (union extra extra);
161+
162+/* Parsing/Building/Running */
163+static void fill_narg(char *s, struct narg *n);
164+static struct pri_info *find_primary(char *name);
165+static struct op_info *find_op(char *name);
166+static void parse(int argc, char **argv);
167+static int eval(struct tok *tok, struct arg *arg);
168+static void find(char *path, struct findhist *hist);
169+static void usage(void);
170+
171+/* for comparisons with narg */
172+static int cmp_gt(int a, int b) { return a > b; }
173+static int cmp_eq(int a, int b) { return a == b; }
174+static int cmp_lt(int a, int b) { return a < b; }
175+
176+/* order from find(1p), may want to alphabetize */
177+static struct pri_info primaries[] = {
178+ { "-name" , pri_name , get_name_arg , NULL , 1 },
179+ { "-path" , pri_path , get_path_arg , NULL , 1 },
180+ { "-nouser" , pri_nouser , NULL , NULL , 1 },
181+ { "-nogroup", pri_nogroup, NULL , NULL , 1 },
182+ { "-xdev" , pri_xdev , get_xdev_arg , NULL , 0 },
183+ { "-prune" , pri_prune , NULL , NULL , 1 },
184+ { "-perm" , pri_perm , get_perm_arg , free_extra , 1 },
185+ { "-type" , pri_type , get_type_arg , NULL , 1 },
186+ { "-links" , pri_links , get_n_arg , free_extra , 1 },
187+ { "-user" , pri_user , get_user_arg , NULL , 1 },
188+ { "-group" , pri_group , get_group_arg, NULL , 1 },
189+ { "-size" , pri_size , get_size_arg , free_extra , 1 },
190+ { "-atime" , pri_atime , get_n_arg , free_extra , 1 },
191+ { "-ctime" , pri_ctime , get_n_arg , free_extra , 1 },
192+ { "-mtime" , pri_mtime , get_n_arg , free_extra , 1 },
193+ { "-exec" , pri_exec , get_exec_arg , free_exec_arg, 1 },
194+ { "-ok" , pri_ok , get_ok_arg , free_ok_arg , 1 },
195+ { "-print" , pri_print , get_print_arg, NULL , 0 },
196+ { "-print0" , pri_print0 , get_print_arg, NULL , 0 },
197+ { "-newer" , pri_newer , get_newer_arg, NULL , 1 },
198+ { "-depth" , pri_depth , get_depth_arg, NULL , 0 },
199+
200+ { NULL, NULL, NULL, NULL, 0 }
201+};
202+
203+static struct op_info ops[] = {
204+ { "(" , LPAR, 0, 0, 0 }, /* parens are handled specially */
205+ { ")" , RPAR, 0, 0, 0 },
206+ { "!" , NOT , 3, 1, 0 },
207+ { "-a", AND , 2, 2, 1 },
208+ { "-o", OR , 1, 2, 1 },
209+
210+ { NULL, 0, 0, 0, 0 }
211+};
212+
213+extern char **environ;
214+
215+static struct tok *toks; /* holds allocated array of all toks created while parsing */
216+static struct tok *root; /* points to root of expression tree, inside toks array */
217+
218+static struct timespec start; /* time find was started, used for -[acm]time */
219+
220+static size_t envlen; /* number of bytes in environ, used to calculate against ARG_MAX */
221+static size_t argmax; /* value of ARG_MAX retrieved using sysconf(3p) */
222+
223+static struct {
224+ char ret ; /* return value from main */
225+ char depth; /* -depth, directory contents before directory itself */
226+ char h ; /* -H, follow symlinks on command line */
227+ char l ; /* -L, follow all symlinks (command line and search) */
228+ char prune; /* hit -prune */
229+ char xdev ; /* -xdev, prune directories on different devices */
230+ char print; /* whether we will need -print when parsing */
231+} gflags;
232+
233+/*
234+ * Utility
235+ */
236+static int
237+spawn(char *argv[])
238+{
239+ pid_t pid;
240+ int status;
241+
242+ /* flush stdout so that -print output always appears before
243+ * any output from the command and does not get cut-off in
244+ * the middle of a line. */
245+ fflush(stdout);
246+
247+ switch((pid = fork())) {
248+ case -1:
249+ eprintf("fork:");
250+ case 0:
251+ execvp(*argv, argv);
252+ weprintf("exec %s failed:", *argv);
253+ _exit(1);
254+ }
255+
256+ /* FIXME: proper course of action for waitpid() on EINTR? */
257+ waitpid(pid, &status, 0);
258+ return status;
259+}
260+
261+static int
262+do_stat(char *path, struct stat *sb, struct findhist *hist)
263+{
264+ if (gflags.l || (gflags.h && !hist)) {
265+ if (stat(path, sb) == 0) {
266+ return 0;
267+ } else if (errno != ENOENT && errno != ENOTDIR) {
268+ return -1;
269+ }
270+ }
271+
272+ return lstat(path, sb);
273+}
274+
275+/*
276+ * Primaries
277+ */
278+static int
279+pri_name(struct arg *arg)
280+{
281+ int ret;
282+ char *path;
283+
284+ path = estrdup(arg->path);
285+ ret = !fnmatch((char *)arg->extra.p, basename(path), 0);
286+ free(path);
287+
288+ return ret;
289+}
290+
291+static int
292+pri_path(struct arg *arg)
293+{
294+ return !fnmatch((char *)arg->extra.p, arg->path, 0);
295+}
296+
297+/* FIXME: what about errors? find(1p) literally just says
298+ * "for which the getpwuid() function ... returns NULL" */
299+static int
300+pri_nouser(struct arg *arg)
301+{
302+ return !getpwuid(arg->st->st_uid);
303+}
304+
305+static int
306+pri_nogroup(struct arg *arg)
307+{
308+ return !getgrgid(arg->st->st_gid);
309+}
310+
311+static int
312+pri_xdev(struct arg *arg)
313+{
314+ return 1;
315+}
316+
317+static int
318+pri_prune(struct arg *arg)
319+{
320+ return gflags.prune = 1;
321+}
322+
323+static int
324+pri_perm(struct arg *arg)
325+{
326+ struct permarg *p = (struct permarg *)arg->extra.p;
327+
328+ return (arg->st->st_mode & 07777 & (p->exact ? -1U : p->mode)) == p->mode;
329+}
330+
331+static int
332+pri_type(struct arg *arg)
333+{
334+ switch ((char)arg->extra.i) {
335+ default : return 0; /* impossible, but placate warnings */
336+ case 'b': return S_ISBLK (arg->st->st_mode);
337+ case 'c': return S_ISCHR (arg->st->st_mode);
338+ case 'd': return S_ISDIR (arg->st->st_mode);
339+ case 'l': return S_ISLNK (arg->st->st_mode);
340+ case 'p': return S_ISFIFO(arg->st->st_mode);
341+ case 'f': return S_ISREG (arg->st->st_mode);
342+ case 's': return S_ISSOCK(arg->st->st_mode);
343+ }
344+}
345+
346+static int
347+pri_links(struct arg *arg)
348+{
349+ struct narg *n = arg->extra.p;
350+ return n->cmp(arg->st->st_nlink, n->n);
351+}
352+
353+static int
354+pri_user(struct arg *arg)
355+{
356+ return arg->st->st_uid == (uid_t)arg->extra.i;
357+}
358+
359+static int
360+pri_group(struct arg *arg)
361+{
362+ return arg->st->st_gid == (gid_t)arg->extra.i;
363+}
364+
365+static int
366+pri_size(struct arg *arg)
367+{
368+ struct sizearg *s = arg->extra.p;
369+ off_t size = arg->st->st_size;
370+
371+ if (!s->bytes)
372+ size = size / 512 + !!(size % 512);
373+
374+ return s->n.cmp(size, s->n.n);
375+}
376+
377+/* FIXME: ignoring nanoseconds in atime, ctime, mtime */
378+static int
379+pri_atime(struct arg *arg)
380+{
381+ struct narg *n = arg->extra.p;
382+ return n->cmp((start.tv_sec - arg->st->st_atime) / 86400, n->n);
383+}
384+
385+static int
386+pri_ctime(struct arg *arg)
387+{
388+ struct narg *n = arg->extra.p;
389+ return n->cmp((start.tv_sec - arg->st->st_ctime) / 86400, n->n);
390+}
391+
392+static int
393+pri_mtime(struct arg *arg)
394+{
395+ struct narg *n = arg->extra.p;
396+ return n->cmp((start.tv_sec - arg->st->st_mtime) / 86400, n->n);
397+}
398+
399+static int
400+pri_exec(struct arg *arg)
401+{
402+ int status;
403+ size_t len;
404+ char **sp, ***brace;
405+ struct execarg *e = arg->extra.p;
406+
407+ if (e->isplus) {
408+ len = strlen(arg->path) + 1;
409+
410+ /* if we reached ARG_MAX, fork, exec, wait, free file names, reset list */
411+ if (len + e->u.p.arglen + e->u.p.filelen + envlen > argmax) {
412+ e->argv[e->u.p.next] = NULL;
413+
414+ status = spawn(e->argv);
415+ gflags.ret = gflags.ret || status;
416+
417+ for (sp = e->argv + e->u.p.first; *sp; sp++)
418+ free(*sp);
419+
420+ e->u.p.next = e->u.p.first;
421+ e->u.p.filelen = 0;
422+ }
423+
424+ /* if we have too many files, realloc (with space for NULL termination) */
425+ if (e->u.p.next + 1 == e->u.p.cap)
426+ e->argv = ereallocarray(e->argv, e->u.p.cap *= 2, sizeof(*e->argv));
427+
428+ e->argv[e->u.p.next++] = estrdup(arg->path);
429+ e->u.p.filelen += len + sizeof(arg->path);
430+
431+ return 1;
432+ } else {
433+ /* insert path everywhere user gave us {} */
434+ for (brace = e->u.s.braces; *brace; brace++)
435+ **brace = arg->path;
436+
437+ status = spawn(e->argv);
438+ return !status;
439+ }
440+}
441+
442+static int
443+pri_ok(struct arg *arg)
444+{
445+ int status, reply;
446+ char ***brace, c;
447+ struct okarg *o = arg->extra.p;
448+
449+ fprintf(stderr, "%s: %s ? ", *o->argv, arg->path);
450+ reply = fgetc(stdin);
451+
452+ /* throw away rest of line */
453+ while ((c = fgetc(stdin)) != '\n' && c != EOF)
454+ /* FIXME: what if the first character of the rest of the line is a null
455+ * byte? */
456+ ;
457+
458+ if (feof(stdin)) /* FIXME: ferror()? */
459+ clearerr(stdin);
460+
461+ if (reply != 'y' && reply != 'Y')
462+ return 0;
463+
464+ /* insert filename everywhere user gave us {} */
465+ for (brace = o->braces; *brace; brace++)
466+ **brace = arg->path;
467+
468+ status = spawn(o->argv);
469+ return !!status;
470+}
471+
472+static int
473+pri_print(struct arg *arg)
474+{
475+ if (puts(arg->path) == EOF)
476+ eprintf("puts failed:");
477+ return 1;
478+}
479+
480+static int
481+pri_print0(struct arg *arg)
482+{
483+ if (fwrite(arg->path, strlen(arg->path) + 1, 1, stdout) != 1)
484+ eprintf("fwrite failed:");
485+ return 1;
486+}
487+
488+/* FIXME: ignoring nanoseconds */
489+static int
490+pri_newer(struct arg *arg)
491+{
492+ return arg->st->st_mtime > (time_t)arg->extra.i;
493+}
494+
495+static int
496+pri_depth(struct arg *arg)
497+{
498+ return 1;
499+}
500+
501+/*
502+ * Getargs
503+ * consume any arguments for given primary and fill extra
504+ * return pointer to last argument, the pointer will be incremented in parse()
505+ */
506+static char **
507+get_name_arg(char *argv[], union extra *extra)
508+{
509+ extra->p = *argv;
510+ return argv;
511+}
512+
513+static char **
514+get_path_arg(char *argv[], union extra *extra)
515+{
516+ extra->p = *argv;
517+ return argv;
518+}
519+
520+static char **
521+get_xdev_arg(char *argv[], union extra *extra)
522+{
523+ gflags.xdev = 1;
524+ return argv;
525+}
526+
527+static char **
528+get_perm_arg(char *argv[], union extra *extra)
529+{
530+ mode_t mask;
531+ struct permarg *p = extra->p = emalloc(sizeof(*p));
532+
533+ if (**argv == '-')
534+ (*argv)++;
535+ else
536+ p->exact = 1;
537+
538+ mask = umask(0);
539+ umask(mask);
540+
541+ p->mode = parsemode(*argv, 0, mask);
542+
543+ return argv;
544+}
545+
546+static char **
547+get_type_arg(char *argv[], union extra *extra)
548+{
549+ if (!strchr("bcdlpfs", **argv))
550+ eprintf("invalid type %c for -type primary\n", **argv);
551+
552+ extra->i = **argv;
553+ return argv;
554+}
555+
556+static char **
557+get_n_arg(char *argv[], union extra *extra)
558+{
559+ struct narg *n = extra->p = emalloc(sizeof(*n));
560+ fill_narg(*argv, n);
561+ return argv;
562+}
563+
564+static char **
565+get_user_arg(char *argv[], union extra *extra)
566+{
567+ char *end;
568+ struct passwd *p = getpwnam(*argv);
569+
570+ if (p) {
571+ extra->i = p->pw_uid;
572+ } else {
573+ extra->i = strtol(*argv, &end, 10);
574+ if (end == *argv || *end)
575+ eprintf("unknown user '%s'\n", *argv);
576+ }
577+ return argv;
578+}
579+
580+static char **
581+get_group_arg(char *argv[], union extra *extra)
582+{
583+ char *end;
584+ struct group *g = getgrnam(*argv);
585+
586+ if (g) {
587+ extra->i = g->gr_gid;
588+ } else {
589+ extra->i = strtol(*argv, &end, 10);
590+ if (end == *argv || *end)
591+ eprintf("unknown group '%s'\n", *argv);
592+ }
593+ return argv;
594+}
595+
596+static char **
597+get_size_arg(char *argv[], union extra *extra)
598+{
599+ char *p = *argv + strlen(*argv);
600+ struct sizearg *s = extra->p = emalloc(sizeof(*s));
601+ /* if the number is followed by 'c', the size will by in bytes */
602+ if ((s->bytes = (p > *argv && *--p == 'c')))
603+ *p = '\0';
604+
605+ fill_narg(*argv, &s->n);
606+ return argv;
607+}
608+
609+static char **
610+get_exec_arg(char *argv[], union extra *extra)
611+{
612+ char **arg, **new, ***braces;
613+ int nbraces = 0;
614+ struct execarg *e = extra->p = emalloc(sizeof(*e));
615+
616+ for (arg = argv; *arg; arg++)
617+ if (!strcmp(*arg, ";"))
618+ break;
619+ else if (arg > argv && !strcmp(*(arg - 1), "{}") && !strcmp(*arg, "+"))
620+ break;
621+ else if (!strcmp(*arg, "{}"))
622+ nbraces++;
623+
624+ if (!*arg)
625+ eprintf("no terminating ; or {} + for -exec primary\n");
626+
627+ e->isplus = **arg == '+';
628+ *arg = NULL;
629+
630+ if (e->isplus) {
631+ *(arg - 1) = NULL; /* don't need the {} in there now */
632+ e->u.p.arglen = e->u.p.filelen = 0;
633+ e->u.p.first = e->u.p.next = arg - argv - 1;
634+ e->u.p.cap = (arg - argv) * 2;
635+ e->argv = ereallocarray(NULL, e->u.p.cap, sizeof(*e->argv));
636+
637+ for (arg = argv, new = e->argv; *arg; arg++, new++) {
638+ *new = *arg;
639+ e->u.p.arglen += strlen(*arg) + 1 + sizeof(*arg);
640+ }
641+ arg++; /* due to our extra NULL */
642+ } else {
643+ e->argv = argv;
644+ e->u.s.braces = ereallocarray(NULL, ++nbraces, sizeof(*e->u.s.braces)); /* ++ for NULL */
645+
646+ for (arg = argv, braces = e->u.s.braces; *arg; arg++)
647+ if (!strcmp(*arg, "{}"))
648+ *braces++ = arg;
649+ *braces = NULL;
650+ }
651+ gflags.print = 0;
652+ return arg;
653+}
654+
655+static char **
656+get_ok_arg(char *argv[], union extra *extra)
657+{
658+ char **arg, ***braces;
659+ int nbraces = 0;
660+ struct okarg *o = extra->p = emalloc(sizeof(*o));
661+
662+ for (arg = argv; *arg; arg++)
663+ if (!strcmp(*arg, ";"))
664+ break;
665+ else if (!strcmp(*arg, "{}"))
666+ nbraces++;
667+
668+ if (!*arg)
669+ eprintf("no terminating ; for -ok primary\n");
670+ *arg = NULL;
671+
672+ o->argv = argv;
673+ o->braces = ereallocarray(NULL, ++nbraces, sizeof(*o->braces));
674+
675+ for (arg = argv, braces = o->braces; *arg; arg++)
676+ if (!strcmp(*arg, "{}"))
677+ *braces++ = arg;
678+ *braces = NULL;
679+
680+ gflags.print = 0;
681+ return arg;
682+}
683+
684+static char **
685+get_print_arg(char *argv[], union extra *extra)
686+{
687+ gflags.print = 0;
688+ return argv;
689+}
690+
691+/* FIXME: ignoring nanoseconds */
692+static char **
693+get_newer_arg(char *argv[], union extra *extra)
694+{
695+ struct stat st;
696+
697+ if (do_stat(*argv, &st, NULL))
698+ eprintf("failed to stat '%s':", *argv);
699+
700+ extra->i = st.st_mtime;
701+ return argv;
702+}
703+
704+static char **
705+get_depth_arg(char *argv[], union extra *extra)
706+{
707+ gflags.depth = 1;
708+ return argv;
709+}
710+
711+/*
712+ * Freeargs
713+ */
714+static void
715+free_extra(union extra extra)
716+{
717+ free(extra.p);
718+}
719+
720+static void
721+free_exec_arg(union extra extra)
722+{
723+ int status;
724+ char **arg;
725+ struct execarg *e = extra.p;
726+
727+ if (!e->isplus) {
728+ free(e->u.s.braces);
729+ } else {
730+ e->argv[e->u.p.next] = NULL;
731+
732+ /* if we have files, do the last exec */
733+ if (e->u.p.first != e->u.p.next) {
734+ status = spawn(e->argv);
735+ gflags.ret = gflags.ret || status;
736+ }
737+ for (arg = e->argv + e->u.p.first; *arg; arg++)
738+ free(*arg);
739+ free(e->argv);
740+ }
741+ free(e);
742+}
743+
744+static void
745+free_ok_arg(union extra extra)
746+{
747+ struct okarg *o = extra.p;
748+
749+ free(o->braces);
750+ free(o);
751+}
752+
753+/*
754+ * Parsing/Building/Running
755+ */
756+static void
757+fill_narg(char *s, struct narg *n)
758+{
759+ char *end;
760+
761+ switch (*s) {
762+ case '+': n->cmp = cmp_gt; s++; break;
763+ case '-': n->cmp = cmp_lt; s++; break;
764+ default : n->cmp = cmp_eq; break;
765+ }
766+ n->n = strtol(s, &end, 10);
767+ if (end == s || *end)
768+ eprintf("bad number '%s'\n", s);
769+}
770+
771+static struct pri_info *
772+find_primary(char *name)
773+{
774+ struct pri_info *p;
775+
776+ for (p = primaries; p->name; p++)
777+ if (!strcmp(name, p->name))
778+ return p;
779+ return NULL;
780+}
781+
782+static struct op_info *
783+find_op(char *name)
784+{
785+ struct op_info *o;
786+
787+ for (o = ops; o->name; o++)
788+ if (!strcmp(name, o->name))
789+ return o;
790+ return NULL;
791+}
792+
793+/* given the expression from the command line
794+ * 1) convert arguments from strings to tok and place in an array duplicating
795+ * the infix expression given, inserting "-a" where it was omitted
796+ * 2) allocate an array to hold the correct number of tok, and convert from
797+ * infix to rpn (using shunting-yard), add -a and -print if necessary
798+ * 3) evaluate the rpn filling in left and right pointers to create an
799+ * expression tree (tok are still all contained in the rpn array, just
800+ * pointing at eachother)
801+ */
802+static void
803+parse(int argc, char **argv)
804+{
805+ struct tok *tok, *rpn, *out, **top, *infix, **stack;
806+ struct op_info *op;
807+ struct pri_info *pri;
808+ char **arg;
809+ int lasttype = -1;
810+ size_t ntok = 0;
811+ struct tok and = { .u.oinfo = find_op("-a"), .type = AND };
812+
813+ gflags.print = 1;
814+
815+ /* convert argv to infix expression of tok, inserting in *tok */
816+ infix = ereallocarray(NULL, 2 * argc + 1, sizeof(*infix));
817+ for (arg = argv, tok = infix; *arg; arg++, tok++) {
818+ pri = find_primary(*arg);
819+
820+ if (pri) { /* token is a primary, fill out tok and get arguments */
821+ if (lasttype == PRIM || lasttype == RPAR) {
822+ *tok++ = and;
823+ ntok++;
824+ }
825+ if (pri->getarg) {
826+ if (pri->narg && !*++arg)
827+ eprintf("no argument for primary %s\n", pri->name);
828+ arg = pri->getarg(arg, &tok->extra);
829+ }
830+ tok->u.pinfo = pri;
831+ tok->type = PRIM;
832+ } else if ((op = find_op(*arg))) { /* token is an operator */
833+ if (lasttype == LPAR && op->type == RPAR)
834+ eprintf("empty parens\n");
835+ if ((lasttype == PRIM || lasttype == RPAR) &&
836+ (op->type == NOT || op->type == LPAR)) { /* need another implicit -a */
837+ *tok++ = and;
838+ ntok++;
839+ }
840+ tok->type = op->type;
841+ tok->u.oinfo = op;
842+ } else {
843+ /* token is neither primary nor operator, must be */
844+ if ((*arg)[0] == '-') /* an unsupported option */
845+ eprintf("unknown operand: %s\n", *arg);
846+ else /* or a path in the wrong place */
847+ eprintf("paths must precede expression: %s\n", *arg);
848+ }
849+ if (tok->type != LPAR && tok->type != RPAR)
850+ ntok++; /* won't have parens in rpn */
851+ lasttype = tok->type;
852+ }
853+ tok->type = END;
854+ ntok++;
855+
856+ if (gflags.print && (arg != argv)) /* need to add -a -print (not just -print) */
857+ gflags.print++;
858+
859+ /* use shunting-yard to convert from infix to rpn
860+ * https://en.wikipedia.org/wiki/Shunting-yard_algorithm
861+ * read from infix, resulting rpn ends up in rpn, next position in rpn is out
862+ * push operators onto stack, next position in stack is top */
863+ rpn = ereallocarray(NULL, ntok + gflags.print, sizeof(*rpn));
864+ stack = ereallocarray(NULL, argc + gflags.print, sizeof(*stack));
865+ for (tok = infix, out = rpn, top = stack; tok->type != END; tok++) {
866+ switch (tok->type) {
867+ case PRIM: *out++ = *tok; break;
868+ case LPAR: *top++ = tok; break;
869+ case RPAR:
870+ while (top-- > stack && (*top)->type != LPAR)
871+ *out++ = **top;
872+ if (top < stack)
873+ eprintf("extra )\n");
874+ break;
875+ default:
876+ /* this expression can be simplified, but I decided copy the
877+ * verbage from the wikipedia page in order to more clearly explain
878+ * what's going on */
879+ while (top-- > stack &&
880+ (( tok->u.oinfo->lassoc && tok->u.oinfo->prec <= (*top)->u.oinfo->prec) ||
881+ (!tok->u.oinfo->lassoc && tok->u.oinfo->prec < (*top)->u.oinfo->prec)))
882+ *out++ = **top;
883+
884+ /* top now points to either an operator we didn't pop, or stack[-1]
885+ * either way we need to increment it before using it, then
886+ * increment again so the stack works */
887+ top++;
888+ *top++ = tok;
889+ break;
890+ }
891+ }
892+ while (top-- > stack) {
893+ if ((*top)->type == LPAR)
894+ eprintf("extra (\n");
895+ *out++ = **top;
896+ }
897+
898+ /* if there was no expression, use -print
899+ * if there was an expression but no -print, -exec, or -ok, add -a -print
900+ * in rpn, not infix */
901+ if (gflags.print)
902+ *out++ = (struct tok){ .u.pinfo = find_primary("-print"), .type = PRIM };
903+ if (gflags.print == 2)
904+ *out++ = and;
905+
906+ out->type = END;
907+
908+ /* rpn now holds all operators and arguments in reverse polish notation
909+ * values are pushed onto stack, operators pop values off stack into left
910+ * and right pointers, pushing operator node back onto stack
911+ * could probably just do this during shunting-yard, but this is simpler
912+ * code IMO */
913+ for (tok = rpn, top = stack; tok->type != END; tok++) {
914+ if (tok->type == PRIM) {
915+ *top++ = tok;
916+ } else {
917+ if (top - stack < tok->u.oinfo->nargs)
918+ eprintf("insufficient arguments for operator %s\n", tok->u.oinfo->name);
919+ tok->right = *--top;
920+ tok->left = tok->u.oinfo->nargs == 2 ? *--top : NULL;
921+ *top++ = tok;
922+ }
923+ }
924+ if (--top != stack)
925+ eprintf("extra arguments\n");
926+
927+ toks = rpn;
928+ root = *top;
929+
930+ free(infix);
931+ free(stack);
932+}
933+
934+/* for a primary, run and return result
935+ * for an operator evaluate the left side of the tree, decide whether or not to
936+ * evaluate the right based on the short-circuit boolean logic, return result
937+ * NOTE: operator NOT has NULL left side, expression on right side
938+ */
939+static int
940+eval(struct tok *tok, struct arg *arg)
941+{
942+ int ret;
943+
944+ if (!tok)
945+ return 0;
946+
947+ if (tok->type == PRIM) {
948+ arg->extra = tok->extra;
949+ return tok->u.pinfo->func(arg);
950+ }
951+
952+ ret = eval(tok->left, arg);
953+
954+ if ((tok->type == AND && ret) || (tok->type == OR && !ret) || tok->type == NOT)
955+ ret = eval(tok->right, arg);
956+
957+ return ret ^ (tok->type == NOT);
958+}
959+
960+/* evaluate path, if it's a directory iterate through directory entries and
961+ * recurse
962+ */
963+static void
964+find(char *path, struct findhist *hist)
965+{
966+ struct stat st;
967+ DIR *dir;
968+ struct dirent *de;
969+ struct findhist *f, cur;
970+ size_t namelen, pathcap = 0, len;
971+ struct arg arg = { path, &st, { NULL } };
972+ char *p, *pathbuf = NULL;
973+
974+ len = strlen(path) + 2; /* \0 and '/' */
975+
976+ if (do_stat(path, &st, hist) < 0) {
977+ weprintf("failed to stat %s:", path);
978+ gflags.ret = 1;
979+ return;
980+ }
981+
982+ gflags.prune = 0;
983+
984+ /* don't eval now iff we will hit the eval at the bottom which means
985+ * 1. we are a directory 2. we have -depth 3. we don't have -xdev or we are
986+ * on same device (so most of the time we eval here) */
987+ if (!S_ISDIR(st.st_mode) ||
988+ !gflags.depth ||
989+ (gflags.xdev && hist && st.st_dev != hist->dev))
990+ eval(root, &arg);
991+
992+ if (!S_ISDIR(st.st_mode) ||
993+ gflags.prune ||
994+ (gflags.xdev && hist && st.st_dev != hist->dev))
995+ return;
996+
997+ for (f = hist; f; f = f->next) {
998+ if (f->dev == st.st_dev && f->ino == st.st_ino) {
999+ weprintf("loop detected '%s' is '%s'\n", path, f->path);
1000+ gflags.ret = 1;
1001+ return;
1002+ }
1003+ }
1004+ cur.next = hist;
1005+ cur.path = path;
1006+ cur.dev = st.st_dev;
1007+ cur.ino = st.st_ino;
1008+
1009+ if (!(dir = opendir(path))) {
1010+ weprintf("failed to opendir %s:", path);
1011+ gflags.ret = 1;
1012+ /* should we just ignore this since we hit an error? */
1013+ if (gflags.depth)
1014+ eval(root, &arg);
1015+ return;
1016+ }
1017+
1018+ while (errno = 0, (de = readdir(dir))) {
1019+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1020+ continue;
1021+ namelen = strlen(de->d_name);
1022+ if (len + namelen > pathcap) {
1023+ pathcap = len + namelen;
1024+ pathbuf = erealloc(pathbuf, pathcap);
1025+ }
1026+ p = pathbuf + estrlcpy(pathbuf, path, pathcap);
1027+ if (*--p != '/')
1028+ estrlcat(pathbuf, "/", pathcap);
1029+ estrlcat(pathbuf, de->d_name, pathcap);
1030+ find(pathbuf, &cur);
1031+ }
1032+ free(pathbuf);
1033+ if (errno) {
1034+ weprintf("readdir %s:", path);
1035+ gflags.ret = 1;
1036+ closedir(dir);
1037+ return;
1038+ }
1039+ closedir(dir);
1040+
1041+ if (gflags.depth)
1042+ eval(root, &arg);
1043+}
1044+
1045+static void
1046+usage(void)
1047+{
1048+ eprintf("usage: %s [-H | -L] path ... [expression ...]\n", argv0);
1049+}
1050+
1051+int
1052+main(int argc, char **argv)
1053+{
1054+ char **paths;
1055+ int npaths;
1056+ struct tok *t;
1057+
1058+ ARGBEGIN {
1059+ case 'H':
1060+ gflags.h = 1;
1061+ gflags.l = 0;
1062+ break;
1063+ case 'L':
1064+ gflags.l = 1;
1065+ gflags.h = 0;
1066+ break;
1067+ default:
1068+ usage();
1069+ } ARGEND
1070+
1071+ paths = argv;
1072+
1073+ for (; *argv && **argv != '-' && strcmp(*argv, "!") && strcmp(*argv, "("); argv++)
1074+ ;
1075+
1076+ if (!(npaths = argv - paths))
1077+ eprintf("must specify a path\n");
1078+
1079+ parse(argc - npaths, argv);
1080+
1081+ /* calculate number of bytes in environ for -exec {} + ARG_MAX avoidance
1082+ * libc implementation defined whether null bytes, pointers, and alignment
1083+ * are counted, so count them */
1084+ for (argv = environ; *argv; argv++)
1085+ envlen += strlen(*argv) + 1 + sizeof(*argv);
1086+
1087+ if ((argmax = sysconf(_SC_ARG_MAX)) == (size_t)-1)
1088+ argmax = _POSIX_ARG_MAX;
1089+
1090+ if (clock_gettime(CLOCK_REALTIME, &start) < 0)
1091+ weprintf("clock_gettime() failed:");
1092+
1093+ while (npaths--)
1094+ find(*paths++, NULL);
1095+
1096+ for (t = toks; t->type != END; t++)
1097+ if (t->type == PRIM && t->u.pinfo->freearg)
1098+ t->u.pinfo->freearg(t->extra);
1099+ free(toks);
1100+
1101+ gflags.ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
1102+
1103+ return gflags.ret;
1104+}
+130,
-0
1@@ -0,0 +1,130 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "text.h"
10+#include "util.h"
11+#include "utf.h"
12+
13+static int bflag = 0;
14+static int sflag = 0;
15+static size_t width = 80;
16+
17+static void
18+foldline(struct line *l, const char *fname) {
19+ size_t i, col, last, spacesect, len;
20+ Rune r;
21+ int runelen;
22+
23+ for (i = 0, last = 0, col = 0, spacesect = 0; i < l->len; i += runelen) {
24+ if (col >= width && ((l->data[i] != '\r' && l->data[i] != '\b') || bflag)) {
25+ if (bflag && col > width)
26+ i -= runelen; /* never split a character */
27+ len = ((sflag && spacesect) ? spacesect : i) - last;
28+ if (fwrite(l->data + last, 1, len, stdout) != len)
29+ eprintf("fwrite <stdout>:");
30+ if (l->data[i] != '\n')
31+ putchar('\n');
32+ if (sflag && spacesect)
33+ i = spacesect;
34+ last = i;
35+ col = 0;
36+ spacesect = 0;
37+ }
38+ runelen = charntorune(&r, l->data + i, l->len - i);
39+ if (!runelen || r == Runeerror)
40+ eprintf("charntorune: %s: invalid utf\n", fname);
41+ if (sflag && isblankrune(r))
42+ spacesect = i + runelen;
43+ if (!bflag && iscntrl(l->data[i])) {
44+ switch(l->data[i]) {
45+ case '\b':
46+ col -= (col > 0);
47+ break;
48+ case '\r':
49+ col = 0;
50+ break;
51+ case '\t':
52+ col += (8 - (col % 8));
53+ if (col >= width)
54+ i--;
55+ break;
56+ }
57+ } else {
58+ col += bflag ? runelen : 1;
59+ }
60+ }
61+ if (l->len - last)
62+ fwrite(l->data + last, 1, l->len - last, stdout);
63+}
64+
65+static void
66+fold(FILE *fp, const char *fname)
67+{
68+ static struct line line;
69+ static size_t size = 0;
70+ ssize_t len;
71+
72+ while ((len = getline(&line.data, &size, fp)) > 0) {
73+ line.len = len;
74+ foldline(&line, fname);
75+ }
76+ if (ferror(fp))
77+ eprintf("getline %s:", fname);
78+}
79+
80+static void
81+usage(void)
82+{
83+ eprintf("usage: %s [-bs] [-w num | -num] [FILE ...]\n", argv0);
84+}
85+
86+int
87+main(int argc, char *argv[])
88+{
89+ FILE *fp;
90+ int ret = 0;
91+
92+ ARGBEGIN {
93+ case 'b':
94+ bflag = 1;
95+ break;
96+ case 's':
97+ sflag = 1;
98+ break;
99+ case 'w':
100+ width = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
101+ break;
102+ ARGNUM:
103+ if (!(width = ARGNUMF()))
104+ eprintf("illegal width value, too small\n");
105+ break;
106+ default:
107+ usage();
108+ } ARGEND
109+
110+ if (!argc) {
111+ fold(stdin, "<stdin>");
112+ } else {
113+ for (; *argv; argc--, argv++) {
114+ if (!strcmp(*argv, "-")) {
115+ *argv = "<stdin>";
116+ fp = stdin;
117+ } else if (!(fp = fopen(*argv, "r"))) {
118+ weprintf("fopen %s:", *argv);
119+ ret = 1;
120+ continue;
121+ }
122+ fold(fp, *argv);
123+ if (fp != stdin && fshut(fp, *argv))
124+ ret = 1;
125+ }
126+ }
127+
128+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
129+
130+ return ret;
131+}
+108,
-0
1@@ -0,0 +1,108 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <unistd.h>
5+#include <limits.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "util.h"
10+
11+struct var {
12+ const char *k;
13+ long v;
14+};
15+
16+#include "getconf.h"
17+
18+void
19+usage(void)
20+{
21+ eprintf("usage: %s [-v spec] var [path]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ size_t len;
28+ long res;
29+ int i;
30+ char *str;
31+
32+ ARGBEGIN {
33+ case 'v':
34+ /* ignore */
35+ EARGF(usage());
36+ break;
37+ default:
38+ usage();
39+ break;
40+ } ARGEND
41+
42+ if (argc == 1) {
43+ /* sysconf */
44+ for (i = 0; i < LEN(sysconf_l); i++) {
45+ if (strcmp(argv[0], sysconf_l[i].k))
46+ continue;
47+ errno = 0;
48+ if ((res = sysconf(sysconf_l[i].v)) < 0) {
49+ if (errno)
50+ eprintf("sysconf %ld:", sysconf_l[i].v);
51+ puts("undefined");
52+ } else {
53+ printf("%ld\n", res);
54+ }
55+ return fshut(stdout, "<stdout>");
56+ }
57+ /* confstr */
58+ for (i = 0; i < LEN(confstr_l); i++) {
59+ if (strcmp(argv[0], confstr_l[i].k))
60+ continue;
61+ errno = 0;
62+ if (!(len = confstr(confstr_l[i].v, NULL, 0))) {
63+ if (errno)
64+ eprintf("confstr %ld:", confstr_l[i].v);
65+ puts("undefined");
66+ } else {
67+ str = emalloc(len);
68+ errno = 0;
69+ if (!confstr(confstr_l[i].v, str, len)) {
70+ if (errno)
71+ eprintf("confstr %ld:", confstr_l[i].v);
72+ puts("undefined");
73+ } else {
74+ puts(str);
75+ }
76+ free(str);
77+ }
78+ return fshut(stdout, "<stdout>");
79+ }
80+ /* limits */
81+ for (i = 0; i < LEN(limits_l); i++) {
82+ if (strcmp(argv[0], limits_l[i].k))
83+ continue;
84+ printf("%ld\n", limits_l[i].v);
85+ return fshut(stdout, "<stdout>");
86+ }
87+ } else if (argc == 2) {
88+ /* pathconf */
89+ for (i = 0; i < LEN(pathconf_l); i++) {
90+ if (strcmp(argv[0], pathconf_l[i].k))
91+ continue;
92+ errno = 0;
93+ if ((res = pathconf(argv[1], pathconf_l[i].v)) < 0) {
94+ if (errno)
95+ eprintf("pathconf %ld:", pathconf_l[i].v);
96+ puts("undefined");
97+ } else {
98+ printf("%ld\n", res);
99+ }
100+ return fshut(stdout, "<stdout>");
101+ }
102+ } else {
103+ usage();
104+ }
105+
106+ eprintf("invalid variable: %s\n", argv[0]);
107+
108+ return 0;
109+}
+266,
-0
1@@ -0,0 +1,266 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <regex.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <strings.h>
8+
9+#include "queue.h"
10+#include "util.h"
11+
12+enum { Match = 0, NoMatch = 1, Error = 2 };
13+
14+static void addpattern(const char *);
15+static void addpatternfile(FILE *);
16+static int grep(FILE *, const char *);
17+
18+static int Eflag;
19+static int Fflag;
20+static int Hflag;
21+static int eflag;
22+static int fflag;
23+static int hflag;
24+static int iflag;
25+static int sflag;
26+static int vflag;
27+static int wflag;
28+static int xflag;
29+static int many;
30+static int mode;
31+
32+struct pattern {
33+ regex_t preg;
34+ SLIST_ENTRY(pattern) entry;
35+ char pattern[];
36+};
37+
38+static SLIST_HEAD(phead, pattern) phead;
39+
40+static void
41+addpattern(const char *pattern)
42+{
43+ struct pattern *pnode;
44+ size_t patlen;
45+
46+ patlen = strlen(pattern);
47+
48+ pnode = enmalloc(Error, sizeof(*pnode) + patlen + 9);
49+ SLIST_INSERT_HEAD(&phead, pnode, entry);
50+
51+ if (Fflag || (!xflag && !wflag)) {
52+ memcpy(pnode->pattern, pattern, patlen + 1);
53+ } else {
54+ sprintf(pnode->pattern, "%s%s%s%s%s",
55+ xflag ? "^" : "\\<",
56+ Eflag ? "(" : "\\(",
57+ pattern,
58+ Eflag ? ")" : "\\)",
59+ xflag ? "$" : "\\>");
60+ }
61+}
62+
63+static void
64+addpatternfile(FILE *fp)
65+{
66+ static char *buf = NULL;
67+ static size_t size = 0;
68+ ssize_t len = 0;
69+
70+ while ((len = getline(&buf, &size, fp)) > 0) {
71+ if (buf[len - 1] == '\n')
72+ buf[len - 1] = '\0';
73+ addpattern(buf);
74+ }
75+ if (ferror(fp))
76+ enprintf(Error, "read error:");
77+}
78+
79+static int
80+grep(FILE *fp, const char *str)
81+{
82+ static char *buf = NULL;
83+ static size_t size = 0;
84+ ssize_t len = 0;
85+ long c = 0, n;
86+ struct pattern *pnode;
87+ int match, result = NoMatch;
88+
89+ for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) {
90+ /* Remove the trailing newline if one is present. */
91+ if (buf[len - 1] == '\n')
92+ buf[len - 1] = '\0';
93+ match = 0;
94+ SLIST_FOREACH(pnode, &phead, entry) {
95+ if (Fflag) {
96+ if (xflag) {
97+ if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) {
98+ match = 1;
99+ break;
100+ }
101+ } else {
102+ if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) {
103+ match = 1;
104+ break;
105+ }
106+ }
107+ } else {
108+ if (regexec(&pnode->preg, buf, 0, NULL, 0) == 0) {
109+ match = 1;
110+ break;
111+ }
112+ }
113+ }
114+ if (match != vflag) {
115+ result = Match;
116+ switch (mode) {
117+ case 'c':
118+ c++;
119+ break;
120+ case 'l':
121+ puts(str);
122+ goto end;
123+ case 'q':
124+ exit(Match);
125+ default:
126+ if (!hflag && (many || Hflag))
127+ printf("%s:", str);
128+ if (mode == 'n')
129+ printf("%ld:", n);
130+ puts(buf);
131+ break;
132+ }
133+ }
134+ }
135+ if (mode == 'c')
136+ printf("%ld\n", c);
137+end:
138+ if (ferror(fp)) {
139+ weprintf("%s: read error:", str);
140+ result = Error;
141+ }
142+ return result;
143+}
144+
145+static void
146+usage(void)
147+{
148+ enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f file] "
149+ "[pattern] [file ...]\n", argv0);
150+}
151+
152+int
153+main(int argc, char *argv[])
154+{
155+ struct pattern *pnode;
156+ int m, flags = REG_NOSUB, match = NoMatch;
157+ FILE *fp;
158+ char *arg;
159+
160+ SLIST_INIT(&phead);
161+
162+ ARGBEGIN {
163+ case 'E':
164+ Eflag = 1;
165+ Fflag = 0;
166+ flags |= REG_EXTENDED;
167+ break;
168+ case 'F':
169+ Fflag = 1;
170+ Eflag = 0;
171+ flags &= ~REG_EXTENDED;
172+ break;
173+ case 'H':
174+ Hflag = 1;
175+ hflag = 0;
176+ break;
177+ case 'e':
178+ arg = EARGF(usage());
179+ if (!(fp = fmemopen(arg, strlen(arg) + 1, "r")))
180+ eprintf("fmemopen:");
181+ addpatternfile(fp);
182+ efshut(fp, arg);
183+ eflag = 1;
184+ break;
185+ case 'f':
186+ arg = EARGF(usage());
187+ fp = fopen(arg, "r");
188+ if (!fp)
189+ enprintf(Error, "fopen %s:", arg);
190+ addpatternfile(fp);
191+ efshut(fp, arg);
192+ fflag = 1;
193+ break;
194+ case 'h':
195+ hflag = 1;
196+ Hflag = 0;
197+ break;
198+ case 'c':
199+ case 'l':
200+ case 'n':
201+ case 'q':
202+ mode = ARGC();
203+ break;
204+ case 'i':
205+ flags |= REG_ICASE;
206+ iflag = 1;
207+ break;
208+ case 's':
209+ sflag = 1;
210+ break;
211+ case 'v':
212+ vflag = 1;
213+ break;
214+ case 'w':
215+ wflag = 1;
216+ break;
217+ case 'x':
218+ xflag = 1;
219+ break;
220+ default:
221+ usage();
222+ } ARGEND
223+
224+ if (argc == 0 && !eflag && !fflag)
225+ usage(); /* no pattern */
226+
227+ /* just add literal pattern to list */
228+ if (!eflag && !fflag) {
229+ if (!(fp = fmemopen(argv[0], strlen(argv[0]) + 1, "r")))
230+ eprintf("fmemopen:");
231+ addpatternfile(fp);
232+ efshut(fp, argv[0]);
233+ argc--;
234+ argv++;
235+ }
236+
237+ if (!Fflag)
238+ /* Compile regex for all search patterns */
239+ SLIST_FOREACH(pnode, &phead, entry)
240+ enregcomp(Error, &pnode->preg, pnode->pattern, flags);
241+ many = (argc > 1);
242+ if (argc == 0) {
243+ match = grep(stdin, "<stdin>");
244+ } else {
245+ for (; *argv; argc--, argv++) {
246+ if (!strcmp(*argv, "-")) {
247+ *argv = "<stdin>";
248+ fp = stdin;
249+ } else if (!(fp = fopen(*argv, "r"))) {
250+ if (!sflag)
251+ weprintf("fopen %s:", *argv);
252+ match = Error;
253+ continue;
254+ }
255+ m = grep(fp, *argv);
256+ if (m == Error || (match != Error && m == Match))
257+ match = m;
258+ if (fp != stdin && fshut(fp, *argv))
259+ match = Error;
260+ }
261+ }
262+
263+ if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
264+ match = Error;
265+
266+ return match;
267+}
+77,
-0
1@@ -0,0 +1,77 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "util.h"
9+
10+static void
11+head(FILE *fp, const char *fname, size_t n)
12+{
13+ char *buf = NULL;
14+ size_t i = 0, size = 0;
15+ ssize_t len;
16+
17+ while (i < n && (len = getline(&buf, &size, fp)) > 0) {
18+ fwrite(buf, 1, len, stdout);
19+ i += (len && (buf[len - 1] == '\n'));
20+ }
21+ free(buf);
22+ if (ferror(fp))
23+ eprintf("getline %s:", fname);
24+}
25+
26+static void
27+usage(void)
28+{
29+ eprintf("usage: %s [-num | -n num] [file ...]\n", argv0);
30+}
31+
32+int
33+main(int argc, char *argv[])
34+{
35+ size_t n = 10;
36+ FILE *fp;
37+ int ret = 0, newline = 0, many = 0;
38+
39+ ARGBEGIN {
40+ case 'n':
41+ n = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
42+ break;
43+ ARGNUM:
44+ n = ARGNUMF();
45+ break;
46+ default:
47+ usage();
48+ } ARGEND
49+
50+ if (!argc) {
51+ head(stdin, "<stdin>", n);
52+ } else {
53+ many = argc > 1;
54+ for (newline = 0; *argv; argc--, argv++) {
55+ if (!strcmp(*argv, "-")) {
56+ *argv = "<stdin>";
57+ fp = stdin;
58+ } else if (!(fp = fopen(*argv, "r"))) {
59+ weprintf("fopen %s:", *argv);
60+ ret = 1;
61+ continue;
62+ }
63+ if (many) {
64+ if (newline)
65+ putchar('\n');
66+ printf("==> %s <==\n", *argv);
67+ }
68+ newline = 1;
69+ head(fp, *argv, n);
70+ if (fp != stdin && fshut(fp, *argv))
71+ ret = 1;
72+ }
73+ }
74+
75+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
76+
77+ return ret;
78+}
+176,
-0
1@@ -0,0 +1,176 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+
5+#include <ctype.h>
6+#include <errno.h>
7+#include <grp.h>
8+#include <limits.h>
9+#include <pwd.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <unistd.h>
13+
14+#include "util.h"
15+
16+static void groupid(struct passwd *pw);
17+static void user(struct passwd *pw);
18+static void userid(uid_t id);
19+static void usernam(const char *nam);
20+
21+static int gflag = 0;
22+static int uflag = 0;
23+static int Gflag = 0;
24+static int nflag = 0;
25+
26+static void
27+groupid(struct passwd *pw)
28+{
29+ gid_t gid, groups[NGROUPS_MAX];
30+ struct group *gr;
31+ int ngroups;
32+ int i;
33+
34+ ngroups = NGROUPS_MAX;
35+ getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
36+ for (i = 0; i < ngroups; i++) {
37+ gid = groups[i];
38+ if (nflag) {
39+ if (!(gr = getgrgid(gid)))
40+ eprintf("getgrgid:");
41+ printf("%s", gr->gr_name);
42+ } else
43+ printf("%u", gid);
44+
45+ if (i < ngroups - 1)
46+ putchar(' ');
47+ }
48+ putchar('\n');
49+}
50+
51+static void
52+user(struct passwd *pw)
53+{
54+ struct group *gr;
55+ gid_t gid, groups[NGROUPS_MAX];
56+ int ngroups;
57+ int i;
58+
59+ if (uflag) {
60+ if (nflag)
61+ printf("%s\n", pw->pw_name);
62+ else
63+ printf("%u\n", pw->pw_uid);
64+ return;
65+ } else if (gflag) {
66+ if (nflag) {
67+ if (!(gr = getgrgid(pw->pw_gid)))
68+ eprintf("getgrgid:");
69+ printf("%s\n", gr->gr_name);
70+ } else
71+ printf("%u\n", pw->pw_gid);
72+ return;
73+ }
74+
75+ printf("uid=%u(%s)", pw->pw_uid, pw->pw_name);
76+ printf(" gid=%u", pw->pw_gid);
77+ if (!(gr = getgrgid(pw->pw_gid)))
78+ eprintf("getgrgid:");
79+ printf("(%s)", gr->gr_name);
80+
81+ ngroups = NGROUPS_MAX;
82+ getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
83+ for (i = 0; i < ngroups; i++) {
84+ gid = groups[i];
85+ printf("%s%u", !i ? " groups=" : ",", gid);
86+ if (!(gr = getgrgid(gid)))
87+ eprintf("getgrgid:");
88+ printf("(%s)", gr->gr_name);
89+ }
90+ putchar('\n');
91+}
92+
93+static void
94+usernam(const char *nam)
95+{
96+ struct passwd *pw;
97+
98+ errno = 0;
99+ pw = getpwnam(nam);
100+ if (!pw) {
101+ if (errno)
102+ eprintf("getpwnam %s:", nam);
103+ else
104+ eprintf("getpwnam %s: no such user\n", nam);
105+ }
106+ if (Gflag)
107+ groupid(pw);
108+ else
109+ user(pw);
110+}
111+
112+static void
113+userid(uid_t id)
114+{
115+ struct passwd *pw;
116+
117+ errno = 0;
118+ pw = getpwuid(id);
119+ if (!pw) {
120+ if (errno)
121+ eprintf("getpwuid %d:", id);
122+ else
123+ eprintf("getpwuid %d: no such user\n", id);
124+ }
125+ if (Gflag)
126+ groupid(pw);
127+ else
128+ user(pw);
129+}
130+
131+static void
132+usage(void)
133+{
134+ eprintf("usage: %s [-n] [-g | -u | -G] [user | uid]\n", argv0);
135+}
136+
137+int
138+main(int argc, char *argv[])
139+{
140+ ARGBEGIN {
141+ case 'g':
142+ gflag = 1;
143+ break;
144+ case 'u':
145+ uflag = 1;
146+ break;
147+ case 'G':
148+ Gflag = 1;
149+ break;
150+ case 'n':
151+ nflag = 1;
152+ break;
153+ default:
154+ usage();
155+ } ARGEND;
156+
157+ /* ensure that only one of -g, -u, or -G was specified */
158+ if (gflag + uflag + Gflag > 1)
159+ usage();
160+
161+ switch (argc) {
162+ case 0:
163+ userid(getuid());
164+ break;
165+ case 1:
166+ /* user names can't begin [0-9] */
167+ if (isdigit(argv[0][0]))
168+ userid(estrtol(argv[0], 0));
169+ else
170+ usernam(argv[0]);
171+ break;
172+ default:
173+ usage();
174+ }
175+
176+ return 0;
177+}
+529,
-0
1@@ -0,0 +1,529 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "text.h"
10+#include "utf.h"
11+#include "util.h"
12+
13+enum {
14+ INIT = 1,
15+ GROW = 2,
16+};
17+
18+enum {
19+ EXPAND = 0,
20+ RESET = 1,
21+};
22+
23+enum { FIELD_ERROR = -2, };
24+
25+struct field {
26+ char *s;
27+ size_t len;
28+};
29+
30+struct jline {
31+ struct line text;
32+ size_t nf;
33+ size_t maxf;
34+ struct field *fields;
35+};
36+
37+struct spec {
38+ size_t fileno;
39+ size_t fldno;
40+};
41+
42+struct outlist {
43+ size_t ns;
44+ size_t maxs;
45+ struct spec **specs;
46+};
47+
48+struct span {
49+ size_t nl;
50+ size_t maxl;
51+ struct jline **lines;
52+};
53+
54+static char *sep = NULL;
55+static char *replace = NULL;
56+static const char defaultofs = ' ';
57+static const int jfield = 1; /* POSIX default join field */
58+static int unpairsa = 0, unpairsb = 0;
59+static int oflag = 0;
60+static int pairs = 1;
61+static size_t seplen;
62+static struct outlist output;
63+
64+static void
65+usage(void)
66+{
67+ eprintf("usage: %s [-1 field] [-2 field] [-o list] [-e string] "
68+ "[-a | -v fileno] [-t delim] file1 file2\n", argv0);
69+}
70+
71+static void
72+prfield(struct field *fp)
73+{
74+ if (fwrite(fp->s, 1, fp->len, stdout) != fp->len)
75+ eprintf("fwrite:");
76+}
77+
78+static void
79+prsep(void)
80+{
81+ if (sep)
82+ fwrite(sep, 1, seplen, stdout);
83+ else
84+ putchar(defaultofs);
85+}
86+
87+static void
88+swaplines(struct jline *la, struct jline *lb)
89+{
90+ struct jline tmp;
91+
92+ tmp = *la;
93+ *la = *lb;
94+ *lb = tmp;
95+}
96+
97+static void
98+prjoin(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
99+{
100+ struct spec *sp;
101+ struct field *joinfield;
102+ size_t i;
103+
104+ if (jfa >= la->nf || jfb >= lb->nf)
105+ return;
106+
107+ joinfield = &la->fields[jfa];
108+
109+ if (oflag) {
110+ for (i = 0; i < output.ns; i++) {
111+ sp = output.specs[i];
112+
113+ if (sp->fileno == 1) {
114+ if (sp->fldno < la->nf)
115+ prfield(&la->fields[sp->fldno]);
116+ else if (replace)
117+ fputs(replace, stdout);
118+ } else if (sp->fileno == 2) {
119+ if (sp->fldno < lb->nf)
120+ prfield(&lb->fields[sp->fldno]);
121+ else if (replace)
122+ fputs(replace, stdout);
123+ } else if (sp->fileno == 0) {
124+ prfield(joinfield);
125+ }
126+
127+ if (i < output.ns - 1)
128+ prsep();
129+ }
130+ } else {
131+ prfield(joinfield);
132+ prsep();
133+
134+ for (i = 0; i < la->nf; i++) {
135+ if (i != jfa) {
136+ prfield(&la->fields[i]);
137+ prsep();
138+ }
139+ }
140+ for (i = 0; i < lb->nf; i++) {
141+ if (i != jfb) {
142+ prfield(&lb->fields[i]);
143+ if (i < lb->nf - 1)
144+ prsep();
145+ }
146+ }
147+ }
148+ putchar('\n');
149+}
150+
151+static void
152+prline(struct jline *lp)
153+{
154+ if (fwrite(lp->text.data, 1, lp->text.len, stdout) != lp->text.len)
155+ eprintf("fwrite:");
156+ putchar('\n');
157+}
158+
159+static int
160+jlinecmp(struct jline *la, struct jline *lb, size_t jfa, size_t jfb)
161+{
162+ int status;
163+
164+ /* return FIELD_ERROR if both lines are short */
165+ if (jfa >= la->nf) {
166+ status = (jfb >= lb->nf) ? FIELD_ERROR : -1;
167+ } else if (jfb >= lb->nf) {
168+ status = 1;
169+ } else {
170+ status = memcmp(la->fields[jfa].s, lb->fields[jfb].s,
171+ MAX(la->fields[jfa].len, lb->fields[jfb].len));
172+ LIMIT(status, -1, 1);
173+ }
174+
175+ return status;
176+}
177+
178+static void
179+addfield(struct jline *lp, char *sp, size_t len)
180+{
181+ if (lp->nf >= lp->maxf) {
182+ lp->fields = ereallocarray(lp->fields, (GROW * lp->maxf),
183+ sizeof(struct field));
184+ lp->maxf *= GROW;
185+ }
186+ lp->fields[lp->nf].s = sp;
187+ lp->fields[lp->nf].len = len;
188+ lp->nf++;
189+}
190+
191+static void
192+prspanjoin(struct span *spa, struct span *spb, size_t jfa, size_t jfb)
193+{
194+ size_t i, j;
195+
196+ for (i = 0; i < (spa->nl - 1); i++)
197+ for (j = 0; j < (spb->nl - 1); j++)
198+ prjoin(spa->lines[i], spb->lines[j], jfa, jfb);
199+}
200+
201+static struct jline *
202+makeline(char *s, size_t len)
203+{
204+ struct jline *lp;
205+ char *tmp;
206+ size_t i, end;
207+
208+ if (s[len - 1] == '\n')
209+ s[--len] = '\0';
210+
211+ lp = ereallocarray(NULL, INIT, sizeof(struct jline));
212+ lp->text.data = s;
213+ lp->text.len = len;
214+ lp->fields = ereallocarray(NULL, INIT, sizeof(struct field));
215+ lp->nf = 0;
216+ lp->maxf = INIT;
217+
218+ for (i = 0; i < lp->text.len && isblank(lp->text.data[i]); i++)
219+ ;
220+ while (i < lp->text.len) {
221+ if (sep) {
222+ if ((lp->text.len - i) < seplen ||
223+ !(tmp = memmem(lp->text.data + i,
224+ lp->text.len - i, sep, seplen))) {
225+ goto eol;
226+ }
227+ end = tmp - lp->text.data;
228+ addfield(lp, lp->text.data + i, end - i);
229+ i = end + seplen;
230+ } else {
231+ for (end = i; !(isblank(lp->text.data[end])); end++) {
232+ if (end + 1 == lp->text.len)
233+ goto eol;
234+ }
235+ addfield(lp, lp->text.data + i, end - i);
236+ for (i = end; isblank(lp->text.data[i]); i++)
237+ ;
238+ }
239+ }
240+eol:
241+ addfield(lp, lp->text.data + i, lp->text.len - i);
242+
243+ return lp;
244+}
245+
246+static int
247+addtospan(struct span *sp, FILE *fp, int reset)
248+{
249+ char *newl = NULL;
250+ ssize_t len;
251+ size_t size = 0;
252+
253+ if ((len = getline(&newl, &size, fp)) < 0) {
254+ if (ferror(fp))
255+ eprintf("getline:");
256+ else
257+ return 0;
258+ }
259+
260+ if (reset)
261+ sp->nl = 0;
262+
263+ if (sp->nl >= sp->maxl) {
264+ sp->lines = ereallocarray(sp->lines, (GROW * sp->maxl),
265+ sizeof(struct jline *));
266+ sp->maxl *= GROW;
267+ }
268+
269+ sp->lines[sp->nl] = makeline(newl, len);
270+ sp->nl++;
271+ return 1;
272+}
273+
274+static void
275+initspan(struct span *sp)
276+{
277+ sp->nl = 0;
278+ sp->maxl = INIT;
279+ sp->lines = ereallocarray(NULL, INIT, sizeof(struct jline *));
280+}
281+
282+static void
283+freespan(struct span *sp)
284+{
285+ size_t i;
286+
287+ for (i = 0; i < sp->nl; i++) {
288+ free(sp->lines[i]->fields);
289+ free(sp->lines[i]->text.data);
290+ }
291+ free(sp->lines);
292+}
293+
294+static void
295+initolist(struct outlist *olp)
296+{
297+ olp->ns = 0;
298+ olp->maxs = 1;
299+ olp->specs = ereallocarray(NULL, INIT, sizeof(struct spec *));
300+}
301+
302+static void
303+addspec(struct outlist *olp, struct spec *sp)
304+{
305+ if (olp->ns >= olp->maxs) {
306+ olp->specs = ereallocarray(olp->specs, (GROW * olp->maxs),
307+ sizeof(struct spec *));
308+ olp->maxs *= GROW;
309+ }
310+ olp->specs[olp->ns] = sp;
311+ olp->ns++;
312+}
313+
314+static struct spec *
315+makespec(char *s)
316+{
317+ struct spec *sp;
318+ int fileno;
319+ size_t fldno;
320+
321+ if (!strcmp(s, "0")) { /* join field must be 0 and nothing else */
322+ fileno = 0;
323+ fldno = 0;
324+ } else if ((s[0] == '1' || s[0] == '2') && s[1] == '.') {
325+ fileno = s[0] - '0';
326+ fldno = estrtonum(&s[2], 1, MIN(LLONG_MAX, SIZE_MAX)) - 1;
327+ } else {
328+ eprintf("%s: invalid format\n", s);
329+ }
330+
331+ sp = ereallocarray(NULL, INIT, sizeof(struct spec));
332+ sp->fileno = fileno;
333+ sp->fldno = fldno;
334+ return sp;
335+}
336+
337+static void
338+makeolist(struct outlist *olp, char *s)
339+{
340+ char *item, *sp;
341+ sp = s;
342+
343+ while (sp) {
344+ item = sp;
345+ sp = strpbrk(sp, ", \t");
346+ if (sp)
347+ *sp++ = '\0';
348+ addspec(olp, makespec(item));
349+ }
350+}
351+
352+static void
353+freespecs(struct outlist *olp)
354+{
355+ size_t i;
356+
357+ for (i = 0; i < olp->ns; i++)
358+ free(olp->specs[i]);
359+}
360+
361+static void
362+join(FILE *fa, FILE *fb, size_t jfa, size_t jfb)
363+{
364+ struct span spa, spb;
365+ int cmp, eofa, eofb;
366+
367+ initspan(&spa);
368+ initspan(&spb);
369+ cmp = eofa = eofb = 0;
370+
371+ addtospan(&spa, fa, RESET);
372+ addtospan(&spb, fb, RESET);
373+
374+ while (spa.nl && spb.nl) {
375+ if ((cmp = jlinecmp(spa.lines[0], spb.lines[0], jfa, jfb)) < 0) {
376+ if (unpairsa)
377+ prline(spa.lines[0]);
378+ if (!addtospan(&spa, fa, RESET)) {
379+ if (unpairsb) { /* a is EOF'd; print the rest of b */
380+ do
381+ prline(spb.lines[0]);
382+ while (addtospan(&spb, fb, RESET));
383+ }
384+ eofa = eofb = 1;
385+ } else {
386+ continue;
387+ }
388+ } else if (cmp > 0) {
389+ if (unpairsb)
390+ prline(spb.lines[0]);
391+ if (!addtospan(&spb, fb, RESET)) {
392+ if (unpairsa) { /* b is EOF'd; print the rest of a */
393+ do
394+ prline(spa.lines[0]);
395+ while (addtospan(&spa, fa, RESET));
396+ }
397+ eofa = eofb = 1;
398+ } else {
399+ continue;
400+ }
401+ } else if (cmp == 0) {
402+ /* read all consecutive matching lines from a */
403+ do {
404+ if (!addtospan(&spa, fa, EXPAND)) {
405+ eofa = 1;
406+ spa.nl++;
407+ break;
408+ }
409+ } while (jlinecmp(spa.lines[spa.nl-1], spb.lines[0], jfa, jfb) == 0);
410+
411+ /* read all consecutive matching lines from b */
412+ do {
413+ if (!addtospan(&spb, fb, EXPAND)) {
414+ eofb = 1;
415+ spb.nl++;
416+ break;
417+ }
418+ } while (jlinecmp(spa.lines[0], spb.lines[spb.nl-1], jfa, jfb) == 0);
419+
420+ if (pairs)
421+ prspanjoin(&spa, &spb, jfa, jfb);
422+
423+ } else { /* FIELD_ERROR: both lines lacked join fields */
424+ if (unpairsa)
425+ prline(spa.lines[0]);
426+ if (unpairsb)
427+ prline(spb.lines[0]);
428+ eofa = addtospan(&spa, fa, RESET) ? 0 : 1;
429+ eofb = addtospan(&spb, fb, RESET) ? 0 : 1;
430+ if (!eofa && !eofb)
431+ continue;
432+ }
433+
434+ if (eofa) {
435+ spa.nl = 0;
436+ } else {
437+ swaplines(spa.lines[0], spa.lines[spa.nl - 1]); /* ugly */
438+ spa.nl = 1;
439+ }
440+
441+ if (eofb) {
442+ spb.nl = 0;
443+ } else {
444+ swaplines(spb.lines[0], spb.lines[spb.nl - 1]); /* ugly */
445+ spb.nl = 1;
446+ }
447+ }
448+ freespan(&spa);
449+ freespan(&spb);
450+}
451+
452+
453+int
454+main(int argc, char *argv[])
455+{
456+ size_t jf[2] = { jfield, jfield, };
457+ FILE *fp[2];
458+ int ret = 0, n;
459+ char *fno;
460+
461+ ARGBEGIN {
462+ case '1':
463+ jf[0] = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
464+ break;
465+ case '2':
466+ jf[1] = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
467+ break;
468+ case 'a':
469+ fno = EARGF(usage());
470+ if (strcmp(fno, "1") == 0)
471+ unpairsa = 1;
472+ else if (strcmp(fno, "2") == 0)
473+ unpairsb = 1;
474+ else
475+ usage();
476+ break;
477+ case 'e':
478+ replace = EARGF(usage());
479+ break;
480+ case 'o':
481+ oflag = 1;
482+ initolist(&output);
483+ makeolist(&output, EARGF(usage()));
484+ break;
485+ case 't':
486+ sep = EARGF(usage());
487+ break;
488+ case 'v':
489+ pairs = 0;
490+ fno = EARGF(usage());
491+ if (strcmp(fno, "1") == 0)
492+ unpairsa = 1;
493+ else if (strcmp(fno, "2") == 0)
494+ unpairsb = 1;
495+ else
496+ usage();
497+ break;
498+ default:
499+ usage();
500+ } ARGEND
501+
502+ if (sep)
503+ seplen = unescape(sep);
504+
505+ if (argc != 2)
506+ usage();
507+
508+ for (n = 0; n < 2; n++) {
509+ if (!strcmp(argv[n], "-")) {
510+ argv[n] = "<stdin>";
511+ fp[n] = stdin;
512+ } else if (!(fp[n] = fopen(argv[n], "r"))) {
513+ eprintf("fopen %s:", argv[n]);
514+ }
515+ }
516+
517+ jf[0]--;
518+ jf[1]--;
519+
520+ join(fp[0], fp[1], jf[0], jf[1]);
521+
522+ if (oflag)
523+ freespecs(&output);
524+
525+ if (fshut(fp[0], argv[0]) | (fp[0] != fp[1] && fshut(fp[1], argv[1])) |
526+ fshut(stdout, "<stdout>"))
527+ ret = 2;
528+
529+ return ret;
530+}
+131,
-0
1@@ -0,0 +1,131 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/wait.h>
4+
5+#include <ctype.h>
6+#include <limits.h>
7+#include <signal.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <strings.h>
11+
12+#include "util.h"
13+
14+struct {
15+ const char *name;
16+ const int sig;
17+} sigs[] = {
18+ { "0", 0 },
19+#define SIG(n) { #n, SIG##n }
20+ SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
21+ SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
22+ SIG(TERM), SIG(TRAP), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2),
23+ SIG(URG),
24+#undef SIG
25+};
26+
27+const char *
28+sig2name(const int sig)
29+{
30+ size_t i;
31+
32+ for (i = 0; i < LEN(sigs); i++)
33+ if (sigs[i].sig == sig)
34+ return sigs[i].name;
35+ eprintf("%d: bad signal number\n", sig);
36+
37+ return NULL; /* not reached */
38+}
39+
40+int
41+name2sig(const char *name)
42+{
43+ size_t i;
44+
45+ for (i = 0; i < LEN(sigs); i++)
46+ if (!strcasecmp(sigs[i].name, name))
47+ return sigs[i].sig;
48+ eprintf("%s: bad signal name\n", name);
49+
50+ return -1; /* not reached */
51+}
52+
53+static void
54+usage(void)
55+{
56+ eprintf("usage: %s [-s signame | -num | -signame] pid ...\n"
57+ " %s -l [num]\n", argv0, argv0);
58+}
59+
60+int
61+main(int argc, char *argv[])
62+{
63+ pid_t pid;
64+ size_t i;
65+ int ret = 0, sig = SIGTERM;
66+
67+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
68+
69+ if (!argc)
70+ usage();
71+
72+ if ((*argv)[0] == '-') {
73+ switch ((*argv)[1]) {
74+ case 'l':
75+ if ((*argv)[2])
76+ goto longopt;
77+ argc--, argv++;
78+ if (!argc) {
79+ for (i = 0; i < LEN(sigs); i++)
80+ puts(sigs[i].name);
81+ } else if (argc == 1) {
82+ sig = estrtonum(*argv, 0, INT_MAX);
83+ if (sig > 128)
84+ sig = WTERMSIG(sig);
85+ puts(sig2name(sig));
86+ } else {
87+ usage();
88+ }
89+ return fshut(stdout, "<stdout>");
90+ case 's':
91+ if ((*argv)[2])
92+ goto longopt;
93+ argc--, argv++;
94+ if (!argc)
95+ usage();
96+ sig = name2sig(*argv);
97+ argc--, argv++;
98+ break;
99+ case '-':
100+ if ((*argv)[2])
101+ goto longopt;
102+ argc--, argv++;
103+ break;
104+ default:
105+ longopt:
106+ /* XSI-extensions -argnum and -argname*/
107+ if (isdigit((*argv)[1])) {
108+ sig = estrtonum((*argv) + 1, 0, INT_MAX);
109+ sig2name(sig);
110+ } else {
111+ sig = name2sig((*argv) + 1);
112+ }
113+ argc--, argv++;
114+ }
115+ }
116+
117+ if (argc && !strcmp(*argv, "--"))
118+ argc--, argv++;
119+
120+ if (!argc)
121+ usage();
122+
123+ for (; *argv; argc--, argv++) {
124+ pid = estrtonum(*argv, INT_MIN, INT_MAX);
125+ if (kill(pid, sig) < 0) {
126+ weprintf("kill %d:", pid);
127+ ret = 1;
128+ }
129+ }
130+
131+ return ret;
132+}
+27,
-0
1@@ -0,0 +1,27 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <unistd.h>
4+
5+#include "util.h"
6+
7+static void
8+usage(void)
9+{
10+ eprintf("usage: %s target name\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+ ARGBEGIN {
17+ default:
18+ usage();
19+ } ARGEND
20+
21+ if (argc != 2)
22+ usage();
23+
24+ if (link(argv[0], argv[1]) < 0)
25+ eprintf("link:");
26+
27+ return 0;
28+}
+103,
-0
1@@ -0,0 +1,103 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <libgen.h>
8+#include <string.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+static void
14+usage(void)
15+{
16+ eprintf("usage: %s [-f] [-L | -P | -s] target [name]\n"
17+ " %s [-f] [-L | -P | -s] target ... dir\n", argv0, argv0);
18+}
19+
20+int
21+main(int argc, char *argv[])
22+{
23+ char *targetdir = ".", *target = NULL;
24+ int ret = 0, sflag = 0, fflag = 0, dirfd = AT_FDCWD,
25+ hastarget = 0, flags = AT_SYMLINK_FOLLOW;
26+ struct stat st, tst;
27+
28+ ARGBEGIN {
29+ case 'f':
30+ fflag = 1;
31+ break;
32+ case 'L':
33+ flags |= AT_SYMLINK_FOLLOW;
34+ break;
35+ case 'P':
36+ flags &= ~AT_SYMLINK_FOLLOW;
37+ break;
38+ case 's':
39+ sflag = 1;
40+ break;
41+ default:
42+ usage();
43+ } ARGEND
44+
45+ if (!argc)
46+ usage();
47+
48+ if (argc > 1) {
49+ if (!stat(argv[argc - 1], &st) && S_ISDIR(st.st_mode)) {
50+ if ((dirfd = open(argv[argc - 1], O_RDONLY)) < 0)
51+ eprintf("open %s:", argv[argc - 1]);
52+ targetdir = argv[argc - 1];
53+ if (targetdir[strlen(targetdir) - 1] == '/')
54+ targetdir[strlen(targetdir) - 1] = '\0';
55+ } else if (argc == 2) {
56+ hastarget = 1;
57+ target = argv[argc - 1];
58+ } else {
59+ eprintf("%s: not a directory\n", argv[argc - 1]);
60+ }
61+ argv[argc - 1] = NULL;
62+ argc--;
63+ }
64+
65+ for (; *argv; argc--, argv++) {
66+ if (!hastarget)
67+ target = basename(*argv);
68+
69+ if (!sflag) {
70+ if (stat(*argv, &st) < 0) {
71+ weprintf("stat %s:", *argv);
72+ ret = 1;
73+ continue;
74+ } else if (fstatat(dirfd, target, &tst, AT_SYMLINK_NOFOLLOW) < 0) {
75+ if (errno != ENOENT) {
76+ weprintf("fstatat %s %s:", targetdir, target);
77+ ret = 1;
78+ continue;
79+ }
80+ } else if (st.st_dev == tst.st_dev && st.st_ino == tst.st_ino) {
81+ if (!fflag) {
82+ weprintf("%s and %s/%s are the same file\n",
83+ *argv, targetdir, target);
84+ ret = 1;
85+ }
86+ continue;
87+ }
88+ }
89+
90+ if (fflag && unlinkat(dirfd, target, 0) < 0 && errno != ENOENT) {
91+ weprintf("unlinkat %s %s:", targetdir, target);
92+ ret = 1;
93+ continue;
94+ }
95+ if ((sflag ? symlinkat(*argv, dirfd, target) :
96+ linkat(AT_FDCWD, *argv, dirfd, target, flags)) < 0) {
97+ weprintf("%s %s <- %s/%s:", sflag ? "symlinkat" : "linkat",
98+ *argv, targetdir, target);
99+ ret = 1;
100+ }
101+ }
102+
103+ return ret;
104+}
+91,
-0
1@@ -0,0 +1,91 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+#include <strings.h>
7+#define SYSLOG_NAMES
8+#include <syslog.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+static int
14+decodetable(CODE *table, char *name)
15+{
16+ CODE *c;
17+
18+ for (c = table; c->c_name; c++)
19+ if (!strcasecmp(name, c->c_name))
20+ return c->c_val;
21+ eprintf("invalid priority name: %s\n", name);
22+
23+ return -1; /* not reached */
24+}
25+
26+static int
27+decodepri(char *pri)
28+{
29+ char *lev, *fac = pri;
30+
31+ if (!(lev = strchr(pri, '.')))
32+ eprintf("invalid priority name: %s\n", pri);
33+ *lev++ = '\0';
34+ if (!*lev)
35+ eprintf("invalid priority name: %s\n", pri);
36+
37+ return (decodetable(facilitynames, fac) & LOG_FACMASK) |
38+ (decodetable(prioritynames, lev) & LOG_PRIMASK);
39+}
40+
41+static void
42+usage(void)
43+{
44+ eprintf("usage: %s [-is] [-p priority] [-t tag] [message ...]\n", argv0);
45+}
46+
47+int
48+main(int argc, char *argv[])
49+{
50+ size_t sz;
51+ int logflags = 0, priority = LOG_NOTICE, i;
52+ char *buf = NULL, *tag = NULL;
53+
54+ ARGBEGIN {
55+ case 'i':
56+ logflags |= LOG_PID;
57+ break;
58+ case 'p':
59+ priority = decodepri(EARGF(usage()));
60+ break;
61+ case 's':
62+ logflags |= LOG_PERROR;
63+ break;
64+ case 't':
65+ tag = EARGF(usage());
66+ break;
67+ default:
68+ usage();
69+ } ARGEND
70+
71+ openlog(tag ? tag : getlogin(), logflags, 0);
72+
73+ if (!argc) {
74+ while (getline(&buf, &sz, stdin) > 0)
75+ syslog(priority, "%s", buf);
76+ } else {
77+ for (i = 0, sz = 0; i < argc; i++)
78+ sz += strlen(argv[i]);
79+ sz += argc;
80+ buf = ecalloc(1, sz);
81+ for (i = 0; i < argc; i++) {
82+ estrlcat(buf, argv[i], sz);
83+ if (i + 1 < argc)
84+ estrlcat(buf, " ", sz);
85+ }
86+ syslog(priority, "%s", buf);
87+ }
88+
89+ closelog();
90+
91+ return fshut(stdin, "<stdin>");
92+}
+29,
-0
1@@ -0,0 +1,29 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <unistd.h>
5+
6+#include "util.h"
7+
8+static void
9+usage(void)
10+{
11+ eprintf("usage: %s\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+ char *login;
18+
19+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
20+
21+ if (argc)
22+ usage();
23+
24+ if ((login = getlogin()))
25+ puts(login);
26+ else
27+ eprintf("no login name\n");
28+
29+ return fshut(stdout, "<stdout>");
30+}
+491,
-0
1@@ -0,0 +1,491 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/types.h>
5+#ifndef major
6+#include <sys/sysmacros.h>
7+#endif
8+
9+#include <dirent.h>
10+#include <grp.h>
11+#include <pwd.h>
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <string.h>
15+#include <time.h>
16+#include <unistd.h>
17+
18+#include "utf.h"
19+#include "util.h"
20+
21+struct entry {
22+ char *name;
23+ mode_t mode, tmode;
24+ nlink_t nlink;
25+ uid_t uid;
26+ gid_t gid;
27+ off_t size;
28+ struct timespec t;
29+ dev_t dev;
30+ dev_t rdev;
31+ ino_t ino, tino;
32+};
33+
34+static struct {
35+ dev_t dev;
36+ ino_t ino;
37+} *tree;
38+
39+static int ret = 0;
40+static int Aflag = 0;
41+static int aflag = 0;
42+static int cflag = 0;
43+static int dflag = 0;
44+static int Fflag = 0;
45+static int fflag = 0;
46+static int Hflag = 0;
47+static int hflag = 0;
48+static int iflag = 0;
49+static int Lflag = 0;
50+static int lflag = 0;
51+static int nflag = 0;
52+static int pflag = 0;
53+static int qflag = 0;
54+static int Rflag = 0;
55+static int rflag = 0;
56+static int Uflag = 0;
57+static int uflag = 0;
58+static int first = 1;
59+static char sort = 0;
60+static int showdirs;
61+
62+static void ls(const char *, const struct entry *, int);
63+
64+static void
65+mkent(struct entry *ent, char *path, int dostat, int follow)
66+{
67+ struct stat st;
68+
69+ ent->name = path;
70+ if (!dostat)
71+ return;
72+ if ((follow ? stat : lstat)(path, &st) < 0)
73+ eprintf("%s %s:", follow ? "stat" : "lstat", path);
74+ ent->mode = st.st_mode;
75+ ent->nlink = st.st_nlink;
76+ ent->uid = st.st_uid;
77+ ent->gid = st.st_gid;
78+ ent->size = st.st_size;
79+ if (cflag)
80+ ent->t = st.st_ctim;
81+ else if (uflag)
82+ ent->t = st.st_atim;
83+ else
84+ ent->t = st.st_mtim;
85+ ent->dev = st.st_dev;
86+ ent->rdev = st.st_rdev;
87+ ent->ino = st.st_ino;
88+ if (S_ISLNK(ent->mode)) {
89+ if (stat(path, &st) == 0) {
90+ ent->tmode = st.st_mode;
91+ ent->dev = st.st_dev;
92+ ent->tino = st.st_ino;
93+ } else {
94+ ent->tmode = ent->tino = 0;
95+ }
96+ }
97+}
98+
99+static char *
100+indicator(mode_t mode)
101+{
102+ if (pflag || Fflag)
103+ if (S_ISDIR(mode))
104+ return "/";
105+
106+ if (Fflag) {
107+ if (S_ISLNK(mode))
108+ return "@";
109+ else if (S_ISFIFO(mode))
110+ return "|";
111+ else if (S_ISSOCK(mode))
112+ return "=";
113+ else if (mode & S_IXUSR || mode & S_IXGRP || mode & S_IXOTH)
114+ return "*";
115+ }
116+
117+ return "";
118+}
119+
120+static void
121+printname(const char *name)
122+{
123+ const char *c;
124+ Rune r;
125+ size_t l;
126+
127+ for (c = name; *c; c += l) {
128+ l = chartorune(&r, c);
129+ if (!qflag || isprintrune(r))
130+ fwrite(c, 1, l, stdout);
131+ else
132+ putchar('?');
133+ }
134+}
135+
136+static void
137+output(const struct entry *ent)
138+{
139+ struct group *gr;
140+ struct passwd *pw;
141+ struct tm *tm;
142+ ssize_t len;
143+ char *fmt, buf[BUFSIZ], pwname[_SC_LOGIN_NAME_MAX],
144+ grname[_SC_LOGIN_NAME_MAX], mode[] = "----------";
145+
146+ if (iflag)
147+ printf("%lu ", (unsigned long)ent->ino);
148+ if (!lflag) {
149+ printname(ent->name);
150+ puts(indicator(ent->mode));
151+ return;
152+ }
153+ if (S_ISREG(ent->mode))
154+ mode[0] = '-';
155+ else if (S_ISBLK(ent->mode))
156+ mode[0] = 'b';
157+ else if (S_ISCHR(ent->mode))
158+ mode[0] = 'c';
159+ else if (S_ISDIR(ent->mode))
160+ mode[0] = 'd';
161+ else if (S_ISFIFO(ent->mode))
162+ mode[0] = 'p';
163+ else if (S_ISLNK(ent->mode))
164+ mode[0] = 'l';
165+ else if (S_ISSOCK(ent->mode))
166+ mode[0] = 's';
167+ else
168+ mode[0] = '?';
169+
170+ if (ent->mode & S_IRUSR) mode[1] = 'r';
171+ if (ent->mode & S_IWUSR) mode[2] = 'w';
172+ if (ent->mode & S_IXUSR) mode[3] = 'x';
173+ if (ent->mode & S_IRGRP) mode[4] = 'r';
174+ if (ent->mode & S_IWGRP) mode[5] = 'w';
175+ if (ent->mode & S_IXGRP) mode[6] = 'x';
176+ if (ent->mode & S_IROTH) mode[7] = 'r';
177+ if (ent->mode & S_IWOTH) mode[8] = 'w';
178+ if (ent->mode & S_IXOTH) mode[9] = 'x';
179+
180+ if (ent->mode & S_ISUID) mode[3] = (mode[3] == 'x') ? 's' : 'S';
181+ if (ent->mode & S_ISGID) mode[6] = (mode[6] == 'x') ? 's' : 'S';
182+ if (ent->mode & S_ISVTX) mode[9] = (mode[9] == 'x') ? 't' : 'T';
183+
184+ if (!nflag && (pw = getpwuid(ent->uid)))
185+ snprintf(pwname, sizeof(pwname), "%s", pw->pw_name);
186+ else
187+ snprintf(pwname, sizeof(pwname), "%d", ent->uid);
188+
189+ if (!nflag && (gr = getgrgid(ent->gid)))
190+ snprintf(grname, sizeof(grname), "%s", gr->gr_name);
191+ else
192+ snprintf(grname, sizeof(grname), "%d", ent->gid);
193+
194+ if (time(NULL) > ent->t.tv_sec + (180 * 24 * 60 * 60)) /* 6 months ago? */
195+ fmt = "%b %d %Y";
196+ else
197+ fmt = "%b %d %H:%M";
198+
199+ if ((tm = localtime(&ent->t.tv_sec)))
200+ strftime(buf, sizeof(buf), fmt, tm);
201+ else
202+ snprintf(buf, sizeof(buf), "%lld", (long long)(ent->t.tv_sec));
203+ printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
204+
205+ if (S_ISBLK(ent->mode) || S_ISCHR(ent->mode))
206+ printf("%4u, %4u ", major(ent->rdev), minor(ent->rdev));
207+ else if (hflag)
208+ printf("%10s ", humansize(ent->size));
209+ else
210+ printf("%10lu ", (unsigned long)ent->size);
211+ printf("%s ", buf);
212+ printname(ent->name);
213+ fputs(indicator(ent->mode), stdout);
214+ if (S_ISLNK(ent->mode)) {
215+ if ((len = readlink(ent->name, buf, sizeof(buf) - 1)) < 0)
216+ eprintf("readlink %s:", ent->name);
217+ buf[len] = '\0';
218+ printf(" -> %s%s", buf, indicator(ent->tmode));
219+ }
220+ putchar('\n');
221+}
222+
223+static int
224+entcmp(const void *va, const void *vb)
225+{
226+ int cmp = 0;
227+ const struct entry *a = va, *b = vb;
228+
229+ switch (sort) {
230+ case 'S':
231+ cmp = b->size - a->size;
232+ break;
233+ case 't':
234+ if (!(cmp = b->t.tv_sec - a->t.tv_sec))
235+ cmp = b->t.tv_nsec - a->t.tv_nsec;
236+ break;
237+ }
238+
239+ if (!cmp)
240+ cmp = strcmp(a->name, b->name);
241+
242+ return rflag ? 0 - cmp : cmp;
243+}
244+
245+static void
246+lsdir(const char *path, const struct entry *dir)
247+{
248+ DIR *dp;
249+ struct entry *ent, *ents = NULL;
250+ struct dirent *d;
251+ size_t i, n = 0;
252+ char prefix[PATH_MAX];
253+
254+ if (!(dp = opendir(dir->name))) {
255+ ret = 1;
256+ weprintf("opendir %s%s:", path, dir->name);
257+ return;
258+ }
259+ if (chdir(dir->name) < 0)
260+ eprintf("chdir %s:", dir->name);
261+
262+ while ((d = readdir(dp))) {
263+ if (d->d_name[0] == '.' && !aflag && !Aflag)
264+ continue;
265+ else if (Aflag)
266+ if (strcmp(d->d_name, ".") == 0 ||
267+ strcmp(d->d_name, "..") == 0)
268+ continue;
269+
270+ ents = ereallocarray(ents, ++n, sizeof(*ents));
271+ mkent(&ents[n - 1], estrdup(d->d_name), Fflag || iflag ||
272+ lflag || pflag || Rflag || sort, Lflag);
273+ }
274+
275+ closedir(dp);
276+
277+ if (!Uflag)
278+ qsort(ents, n, sizeof(*ents), entcmp);
279+
280+ if (path[0] || showdirs) {
281+ fputs(path, stdout);
282+ printname(dir->name);
283+ puts(":");
284+ }
285+ for (i = 0; i < n; i++)
286+ output(&ents[i]);
287+
288+ if (Rflag) {
289+ if (snprintf(prefix, PATH_MAX, "%s%s/", path, dir->name) >=
290+ PATH_MAX)
291+ eprintf("path too long: %s%s\n", path, dir->name);
292+
293+ for (i = 0; i < n; i++) {
294+ ent = &ents[i];
295+ if (strcmp(ent->name, ".") == 0 ||
296+ strcmp(ent->name, "..") == 0)
297+ continue;
298+ if (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Lflag)
299+ continue;
300+
301+ ls(prefix, ent, 1);
302+ }
303+ }
304+
305+ for (i = 0; i < n; ++i)
306+ free(ents[i].name);
307+ free(ents);
308+}
309+
310+static int
311+visit(const struct entry *ent)
312+{
313+ dev_t dev;
314+ ino_t ino;
315+ int i;
316+
317+ dev = ent->dev;
318+ ino = S_ISLNK(ent->mode) ? ent->tino : ent->ino;
319+
320+ for (i = 0; i < PATH_MAX && tree[i].ino; ++i) {
321+ if (ino == tree[i].ino && dev == tree[i].dev)
322+ return -1;
323+ }
324+
325+ tree[i].ino = ino;
326+ tree[i].dev = dev;
327+
328+ return i;
329+}
330+
331+static void
332+ls(const char *path, const struct entry *ent, int listdir)
333+{
334+ int treeind;
335+ char cwd[PATH_MAX];
336+
337+ if (!listdir) {
338+ output(ent);
339+ } else if (S_ISDIR(ent->mode) ||
340+ (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode))) {
341+ if ((treeind = visit(ent)) < 0) {
342+ ret = 1;
343+ weprintf("%s%s: Already visited\n", path, ent->name);
344+ return;
345+ }
346+
347+ if (!getcwd(cwd, PATH_MAX))
348+ eprintf("getcwd:");
349+
350+ if (first)
351+ first = 0;
352+ else
353+ putchar('\n');
354+
355+ lsdir(path, ent);
356+ tree[treeind].ino = 0;
357+
358+ if (chdir(cwd) < 0)
359+ eprintf("chdir %s:", cwd);
360+ }
361+}
362+
363+static void
364+usage(void)
365+{
366+ eprintf("usage: %s [-1AacdFfHhiLlnpqRrtUu] [file ...]\n", argv0);
367+}
368+
369+int
370+main(int argc, char *argv[])
371+{
372+ struct entry ent, *dents, *fents;
373+ size_t i, ds, fs;
374+
375+ tree = ereallocarray(NULL, PATH_MAX, sizeof(*tree));
376+
377+ ARGBEGIN {
378+ case '1':
379+ /* force output to 1 entry per line */
380+ qflag = 1;
381+ break;
382+ case 'A':
383+ Aflag = 1;
384+ break;
385+ case 'a':
386+ aflag = 1;
387+ break;
388+ case 'c':
389+ cflag = 1;
390+ uflag = 0;
391+ break;
392+ case 'd':
393+ dflag = 1;
394+ break;
395+ case 'f':
396+ aflag = 1;
397+ fflag = 1;
398+ Uflag = 1;
399+ break;
400+ case 'F':
401+ Fflag = 1;
402+ break;
403+ case 'H':
404+ Hflag = 1;
405+ break;
406+ case 'h':
407+ hflag = 1;
408+ break;
409+ case 'i':
410+ iflag = 1;
411+ break;
412+ case 'L':
413+ Lflag = 1;
414+ break;
415+ case 'l':
416+ lflag = 1;
417+ break;
418+ case 'n':
419+ lflag = 1;
420+ nflag = 1;
421+ break;
422+ case 'p':
423+ pflag = 1;
424+ break;
425+ case 'q':
426+ qflag = 1;
427+ break;
428+ case 'R':
429+ Rflag = 1;
430+ break;
431+ case 'r':
432+ rflag = 1;
433+ break;
434+ case 'S':
435+ sort = 'S';
436+ break;
437+ case 't':
438+ sort = 't';
439+ break;
440+ case 'U':
441+ Uflag = 1;
442+ break;
443+ case 'u':
444+ uflag = 1;
445+ cflag = 0;
446+ break;
447+ default:
448+ usage();
449+ } ARGEND
450+
451+ switch (argc) {
452+ case 0: /* fallthrough */
453+ *--argv = ".", ++argc;
454+ case 1:
455+ mkent(&ent, argv[0], 1, Hflag || Lflag);
456+ ls("", &ent, (!dflag && S_ISDIR(ent.mode)) ||
457+ (S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) &&
458+ !(dflag || Fflag || lflag)));
459+
460+ break;
461+ default:
462+ for (i = ds = fs = 0, fents = dents = NULL; i < argc; ++i) {
463+ mkent(&ent, argv[i], 1, Hflag || Lflag);
464+
465+ if ((!dflag && S_ISDIR(ent.mode)) ||
466+ (S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) &&
467+ !(dflag || Fflag || lflag))) {
468+ dents = ereallocarray(dents, ++ds, sizeof(*dents));
469+ memcpy(&dents[ds - 1], &ent, sizeof(ent));
470+ } else {
471+ fents = ereallocarray(fents, ++fs, sizeof(*fents));
472+ memcpy(&fents[fs - 1], &ent, sizeof(ent));
473+ }
474+ }
475+
476+ showdirs = ds > 1 || (ds && fs);
477+
478+ qsort(fents, fs, sizeof(ent), entcmp);
479+ qsort(dents, ds, sizeof(ent), entcmp);
480+
481+ for (i = 0; i < fs; ++i)
482+ ls("", &fents[i], 0);
483+ free(fents);
484+ if (fs && ds)
485+ putchar('\n');
486+ for (i = 0; i < ds; ++i)
487+ ls("", &dents[i], 1);
488+ free(dents);
489+ }
490+
491+ return (fshut(stdout, "<stdout>") | ret);
492+}
+61,
-0
1@@ -0,0 +1,61 @@
2+char defaults[] =
3+ ".SUFFIXES: .o .c .y .l .a .sh .f\n"
4+
5+ "AR = ar\n"
6+ "ARFLAGS = -rv\n"
7+ "CC = c99\n"
8+ "CFLAGS = -O\n"
9+ "FC = fort77\n"
10+ "FFLAGS = -O 1\n"
11+ "LDFLAGS =\n"
12+ "LEX = lex\n"
13+ "LFLAGS =\n"
14+ "YACC = yacc\n"
15+ "YFLAGS =\n"
16+ "SHELL = /bin/sh\n"
17+
18+ ".c:\n"
19+ "\t${CC} ${CFLAGS} ${LDFLAGS} -o $@ $<\n"
20+
21+ ".f:\n"
22+ "\t${FC} ${FFLAGS} ${LDFLAGS} -o $@ $<\n"
23+
24+ ".sh:\n"
25+ "\tcp $< $@\n"
26+ "\tchmod a+x $@\n"
27+
28+ ".c.o:\n"
29+ "\t${CC} ${CFLAGS} -c $<\n"
30+
31+ ".f.o:\n"
32+ "\t${FC} ${FFLAGS} -c $<\n"
33+
34+ ".y.o:\n"
35+ "\t${YACC} ${YFLAGS} $<\n"
36+ "\t${CC} ${CFLAGS} -c y.tab.c\n"
37+ "\trm -f y.tab.c\n"
38+ "\tmv y.tab.o $@\n"
39+
40+ ".l.o:\n"
41+ "\t${LEX} ${LFLAGS} $<\n"
42+ "\t${CC} ${CFLAGS} -c lex.yy.c\n"
43+ "\trm -f lex.yy.c\n"
44+ "\tmv lex.yy.o $@\n"
45+
46+ ".y.c:\n"
47+ "\t${YACC} ${YFLAGS} $<\n"
48+ "\tmv y.tab.c $@\n"
49+
50+ ".l.c:\n"
51+ "\t${LEX} ${LFLAGS} $<\n"
52+ "\tmv lex.yy.c $@\n"
53+
54+ ".c.a:\n"
55+ "\t${CC} -c ${CFLAGS} $<\n"
56+ "\t${AR} ${ARFLAGS} $@ $*.o\n"
57+ "\trm -f $*.o\n"
58+
59+ ".f.a:\n"
60+ "\t${FC} -c ${FFLAGS} $<\n"
61+ "\t${AR} ${ARFLAGS} $@ $*.o\n"
62+ "\trm -f $*.o\n";
+377,
-0
1@@ -0,0 +1,377 @@
2+#include <errno.h>
3+#include <signal.h>
4+#include <stdarg.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "make.h"
10+
11+#ifndef SIGINT
12+#define SIGINT -1
13+#endif
14+
15+#ifndef SIGTERM
16+#define SIGTERM -1
17+#endif
18+
19+#ifndef SIGQUIT
20+#define SIGQUIT -1
21+#endif
22+
23+#ifndef SIGHUP
24+#define SIGHUP -1
25+#endif
26+
27+int kflag, dflag, nflag, iflag, sflag;
28+int eflag, pflag, tflag, qflag;
29+int exitstatus;
30+volatile sig_atomic_t stop;
31+
32+void
33+debug(char *fmt, ...)
34+{
35+ va_list va;
36+
37+ if (!dflag)
38+ return;
39+
40+ va_start(va, fmt);
41+ vfprintf(stdout, fmt, va);
42+ fputc('\n', stdout);
43+ va_end(va);
44+}
45+
46+int
47+hash(char *name)
48+{
49+ int c;
50+ unsigned h = 5381;
51+
52+ while (c = *name++)
53+ h = h*33 ^ c;
54+
55+ return h;
56+}
57+
58+void *
59+emalloc(size_t siz)
60+{
61+ void *p;
62+
63+ if ((p = malloc(siz)) == NULL) {
64+ perror("make");
65+ exit(EXIT_FAILURE);
66+ }
67+
68+ return p;
69+}
70+
71+void *
72+erealloc(void *p, size_t siz)
73+{
74+ if ((p = realloc(p, siz)) == NULL) {
75+ perror("make");
76+ exit(EXIT_FAILURE);
77+ }
78+
79+ return p;
80+}
81+
82+char *
83+estrdup(char *s)
84+{
85+ size_t len;
86+
87+ len = strlen(s) + 1;
88+ return memcpy(emalloc(len), s, len);
89+}
90+
91+void
92+sighandler(int signo)
93+{
94+ killchild();
95+ stop = signo;
96+}
97+
98+static void
99+usage(void)
100+{
101+ fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
102+ "[macro=value ...] [target ...]\n",
103+ stderr);
104+ exit(EXIT_FAILURE);
105+}
106+
107+static char *
108+getarg(char **args, char ***argv)
109+{
110+ char *s;
111+
112+ if ((*args)[1]) {
113+ s = (*args) + 1;
114+ *args += strlen(*args) - 1;
115+ return s;
116+ }
117+
118+ if (!argv)
119+ usage();
120+
121+ if ((*argv)[1] == NULL)
122+ usage();
123+ (*argv)++;
124+
125+ return **argv;
126+}
127+
128+static void
129+appendmakeflags(char *text)
130+{
131+ int n;
132+ char *s, *t, *fmt;
133+
134+ s = getmacro("MAKEFLAGS");
135+ fmt = *s ? "%s %s" : "%s%s";
136+ n = snprintf(NULL, 0, fmt, s, text);
137+
138+ t = emalloc(n+1);
139+ snprintf(t, n+1, fmt, s, text);
140+ setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);
141+
142+ free(t);
143+}
144+
145+static int
146+hasargs(int c)
147+{
148+ return c == 'f' || c == 'j';
149+}
150+
151+static void
152+parseflag(int flag, char **args, char ***argv)
153+{
154+ if (hasargs(flag))
155+ getarg(args, argv);
156+
157+ switch (flag) {
158+ case 'j':
159+ case 'f':
160+ break;
161+ case 'e':
162+ eflag = 1;
163+ appendmakeflags("-e");
164+ break;
165+ case 'i':
166+ iflag = 1;
167+ appendmakeflags("-i");
168+ break;
169+ case 'k':
170+ kflag = 1;
171+ appendmakeflags("-k");
172+ break;
173+ case 'n':
174+ nflag = 1;
175+ appendmakeflags("-n");
176+ break;
177+ case 'p':
178+ pflag = 1;
179+ break;
180+ case 'q':
181+ qflag = 1;
182+ appendmakeflags("-q");
183+ break;
184+ case 'r':
185+ addtarget(".SUFFIXES", 0);
186+ appendmakeflags("-r");
187+ break;
188+ case 'S':
189+ kflag = 0;
190+ appendmakeflags("-S");
191+ break;
192+ case 's':
193+ sflag = 1;
194+ appendmakeflags("-s");
195+ break;
196+ case 't':
197+ tflag = 1;
198+ appendmakeflags("-t");
199+ break;
200+ case 'd':
201+ dflag = 1;
202+ appendmakeflags("-d");
203+ break;
204+ default:
205+ usage();
206+ }
207+}
208+
209+static int
210+assign(char *s, int where, int export)
211+{
212+ int pos;
213+ char *t;
214+
215+ if ((t = strchr(s, '=')) == NULL)
216+ return 0;
217+
218+ pos = t - s;
219+
220+ appendmakeflags(s);
221+ t = estrdup(s);
222+ t[pos] = '\0';
223+
224+ setmacro(t, t+pos+1, where, export);
225+ free(t);
226+ return 1;
227+}
228+
229+static void
230+parseargv(char **argv, char ***targets, int where, int export)
231+{
232+ char *s;
233+ char *hm = NULL;
234+
235+ for ( ; *argv; ++argv) {
236+ s = *argv;
237+ if (hm == NULL && strcmp(s, "--") == 0) {
238+ hm = *argv;
239+ } else if (hm && s[0] == '-') {
240+ break;
241+ } else if (s[0] != '-') {
242+ if (!assign(s, where, export))
243+ break;
244+ continue;
245+ }
246+ while (hm == NULL && *++s)
247+ parseflag(*s, &s, &argv);
248+ }
249+
250+ if (targets)
251+ *targets = argv;
252+}
253+
254+static void
255+parsemakeflags(void)
256+{
257+ int c, n;
258+ char *s, *flags, **arr;
259+
260+ if ((flags = getenv("MAKEFLAGS")) == NULL)
261+ return;
262+
263+ setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
264+
265+ while (*flags == ' ' || *flags == '\t')
266+ flags++;
267+
268+ if (flags[0] != '-' && !strchr(flags, '=')) {
269+ while (*flags) {
270+ parseflag(*flags, &flags, NULL);
271+ flags++;
272+ }
273+ } else {
274+ n = 0;
275+ arr = NULL;
276+ for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) {
277+ n++;
278+ arr = erealloc(arr, sizeof(char *) * (n+1));
279+ arr[n-1] = s;
280+ arr[n] = NULL;
281+ }
282+
283+ if (arr)
284+ parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
285+ free(arr);
286+ }
287+}
288+
289+static void
290+parsemakefiles(char **argv)
291+{
292+ char *s, *arg;
293+ int c, hasmake;
294+
295+ hasmake = 0;
296+ for ( ; *argv && **argv == '-'; ++argv) {
297+ for (s = *argv; c = *s; ++s) {
298+ if (hasargs(c))
299+ arg = getarg(&s, &argv);
300+
301+ if (c == 'f') {
302+ if (strcmp(arg, "-") == 0)
303+ arg = NULL;
304+ parse(arg);
305+ hasmake = 1;
306+ }
307+ }
308+ }
309+
310+ if (hasmake)
311+ return;
312+
313+ if (parse("makefile"))
314+ return;
315+ if (parse("Makefile"))
316+ return;
317+}
318+
319+/*
320+ * We want to enable debug as earlier as possible,
321+ * if we wait until we read the Makefiles then
322+ * we are going to lose to much debug information.
323+ */
324+static void
325+enadebug(char *argv[])
326+{
327+ int c;
328+ char *p;
329+
330+ for ( ; *argv && **argv == '-'; ++argv) {
331+ p = *argv;
332+ for (++p; c = *p; ++p) {
333+ if (hasargs(c))
334+ getarg(&p, &argv);
335+ if (c == 'd')
336+ dflag = 1;
337+ }
338+ }
339+}
340+
341+int
342+main(int argc, char *argv[])
343+{
344+ char *arg0, **targets;
345+
346+ signal(SIGINT, sighandler);
347+ signal(SIGHUP, sighandler);
348+ signal(SIGTERM, sighandler);
349+ signal(SIGQUIT, sighandler);
350+
351+ targets = NULL;
352+ arg0 = *argv++;
353+
354+ enadebug(argv);
355+ inject(defaults);
356+ setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
357+
358+ parsemakeflags();
359+ parseargv(argv, &targets, CMDLINE, EXPORT);
360+ parsemakefiles(argv);
361+
362+ if (pflag) {
363+ dumpmacros();
364+ dumprules();
365+ exit(EXIT_SUCCESS);
366+ }
367+
368+ if (!*targets) {
369+ build(NULL);
370+ } else {
371+ while (*targets)
372+ build(*targets++);
373+ }
374+
375+ exit(exitstatus);
376+
377+ return 0;
378+}
+87,
-0
1@@ -0,0 +1,87 @@
2+#include <stddef.h>
3+#include <time.h>
4+
5+typedef struct target Target;
6+
7+enum {
8+ NOEXPORT,
9+ EXPORT,
10+};
11+
12+enum {
13+ UNDEF,
14+ ENVIRON,
15+ CMDLINE,
16+ INTERNAL,
17+ MAKEFILE,
18+ MAKEFLAGS,
19+};
20+
21+struct loc {
22+ char *fname;
23+ int lineno;
24+};
25+
26+struct action {
27+ char *line;
28+ struct loc loc;
29+};
30+
31+struct target {
32+ char *name;
33+ char *target;
34+ char *req;
35+ time_t stamp;
36+ int defined;
37+
38+ int ndeps;
39+ struct target **deps;
40+
41+ int nactions;
42+ struct action *actions;
43+
44+ struct target *next;
45+};
46+
47+void *emalloc(size_t);
48+void *erealloc(void *, size_t);
49+char *estrdup(char *);
50+
51+void dumprules(void);
52+void dumpmacros(void);
53+
54+char *expandstring(char *, Target *, struct loc *);
55+void addtarget(char *, int);
56+void inject(char *);
57+int build(char *);
58+int hash(char *);
59+int parse(char *);
60+void debug(char *, ...);
61+void error(char *, ...);
62+void warning(char *, ...);
63+void adddep(char *, char *);
64+void addrule(char *, struct action *, int);
65+void freeloc(struct loc *);
66+
67+char *getmacro(char *);
68+void setmacro(char *, char *, int, int);
69+
70+/* system depdendant */
71+void killchild(void);
72+time_t stamp(char *);
73+int launch(char *, int);
74+int putenv(char *);
75+void exportvar(char *, char *);
76+int is_dir(char *);
77+
78+/* main.c */
79+extern int kflag, dflag, nflag, iflag, sflag;
80+extern int eflag, pflag, tflag, qflag;
81+extern int exitstatus;
82+
83+#ifdef SIGABRT
84+extern volatile sig_atomic_t stop;
85+#endif
86+
87+/* defaults.c */
88+extern char defaults[];
+1034,
-0
1@@ -0,0 +1,1034 @@
2+#include <assert.h>
3+#include <ctype.h>
4+#include <errno.h>
5+#include <limits.h>
6+#include <stdarg.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+
11+#include "make.h"
12+
13+#define MAXREPL 30
14+#define TABSIZ 64
15+#define MAXTOKEN FILENAME_MAX
16+#define ITEM 128
17+
18+typedef struct macro Macro;
19+
20+enum inputype {
21+ FTFILE,
22+ FTEXPAN,
23+};
24+
25+enum {
26+ STBEGIN,
27+ STINTERNAL,
28+ STREPLACE,
29+ STTO,
30+ STEND,
31+};
32+
33+struct input {
34+ int siz;
35+ int type;
36+
37+ FILE *fp;
38+ struct loc loc;
39+
40+ int pos;
41+ char *buf;
42+
43+ struct input *prev;
44+};
45+
46+struct macro {
47+ char *name;
48+ char *value;
49+ int where;
50+
51+ struct macro *next;
52+};
53+
54+static struct input *input;
55+static char token[MAXTOKEN];
56+static int tok;
57+static Macro *htab[TABSIZ];
58+
59+void
60+dumpmacros(void)
61+{
62+ Macro **pp, *p;
63+
64+ for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
65+ for (p = *pp; p; p = p->next)
66+ printf("%s = %s\n", p->name, getmacro(p->name));
67+ }
68+}
69+
70+static Macro *
71+lookup(char *name)
72+{
73+ Macro *mp;
74+ int h = hash(name) & TABSIZ-1;
75+
76+ for (mp = htab[h]; mp && strcmp(mp->name, name); mp = mp->next)
77+ ;
78+
79+ if (mp)
80+ return mp;
81+
82+ mp = emalloc(sizeof(*mp));
83+ mp->name = estrdup(name);
84+ mp->value = estrdup("");
85+ mp->next = htab[h];
86+ mp->where = UNDEF;
87+ htab[h] = mp;
88+
89+ return mp;
90+}
91+
92+static char *
93+macroinfo(char *name, int *pwhere, Macro **mpp)
94+{
95+ char *s, *t;
96+ int hide, where;
97+ Macro *mp = lookup(name);
98+
99+ hide = 0;
100+ if (!strcmp(name, "SHELL") || !strcmp(name, "MAKEFLAGS"))
101+ hide = 1;
102+
103+ s = mp->value;
104+ where = mp->where;
105+
106+ if (!hide && (where == UNDEF || where == INTERNAL || eflag)) {
107+ t = getenv(name);
108+ if (t) {
109+ where = ENVIRON;
110+ s = t;
111+ }
112+ }
113+
114+ if (pwhere)
115+ *pwhere = where;
116+ if (mpp)
117+ *mpp = mp;
118+
119+ return s;
120+}
121+
122+char *
123+getmacro(char *name)
124+{
125+ return macroinfo(name, NULL, NULL);
126+}
127+
128+void
129+setmacro(char *name, char *val, int where, int export)
130+{
131+ int owhere, set;
132+ char *s;
133+ Macro *mp;
134+
135+ assert(where != ENVIRON);
136+
137+ s = macroinfo(name, &owhere, &mp);
138+
139+ /*
140+ * Default values are defined before anything else, and marked
141+ * as INTERNAL because they are injected as parseable text, and
142+ * MAKEFILE and INTERNAL variables are always overriden. ENVIRON
143+ * macros are generated in macroinfo() and this is why this function
144+ * should not receive a where == ENVIRON ever.
145+ */
146+ switch (owhere) {
147+ case UNDEF:
148+ case INTERNAL:
149+ case MAKEFILE:
150+ set = 1;
151+ break;
152+ case ENVIRON:
153+ set = (where == MAKEFLAGS || where == CMDLINE);
154+ set |= (where == MAKEFILE && !eflag);
155+ break;
156+ case MAKEFLAGS:
157+ set = (where == CMDLINE || where == MAKEFLAGS);
158+ break;
159+ case CMDLINE:
160+ set = (where == CMDLINE);
161+ break;
162+ default:
163+ abort();
164+ }
165+
166+ if (!set) {
167+ debug("hidding override of %s from '%s' to '%s'", name, s, val);
168+ } else {
169+ debug("override %s from '%s' to '%s'", name, s, val);
170+ free(mp->value);
171+ mp->value = estrdup(val);
172+ mp->where = where;
173+
174+ if (export && strcmp(name, "SHELL") != 0) {
175+ debug("exporting macro %s", name);
176+ exportvar(name, val);
177+ }
178+ }
179+}
180+
181+void
182+freeloc(struct loc *loc)
183+{
184+ free(loc->fname);
185+}
186+
187+static struct loc *
188+getloc(void)
189+{
190+ struct input *ip;
191+
192+ for (ip = input; ip && ip->type != FTFILE; ip = ip->prev)
193+ ;
194+ if (!ip)
195+ return NULL;
196+
197+ return &ip->loc;
198+}
199+
200+
201+void
202+error(char *fmt, ...)
203+{
204+ va_list va;
205+ struct loc *loc;
206+
207+ fprintf(stderr, "make: error: ");
208+ if ((loc = getloc()) != NULL)
209+ fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
210+
211+ va_start(va, fmt);
212+ vfprintf(stderr, fmt, va);
213+ va_end(va);
214+ putc('\n', stderr);
215+
216+ exit(EXIT_FAILURE);
217+}
218+
219+void
220+warning(char *fmt, ...)
221+{
222+ va_list va;
223+ struct loc *loc;
224+
225+ fprintf(stderr, "make: warning: ");
226+ if ((loc = getloc()) != NULL)
227+ fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno);
228+
229+ va_start(va, fmt);
230+ vfprintf(stderr, fmt, va);
231+ va_end(va);
232+ putc('\n', stderr);
233+}
234+
235+static void
236+pop(void)
237+{
238+ struct input *ip = input->prev;
239+
240+ if (input->type == FTFILE) {
241+ if (input->fp)
242+ fclose(input->fp);
243+ freeloc(&input->loc);
244+ }
245+ free(input->buf);
246+ free(input);
247+
248+ input = ip;
249+}
250+
251+static void
252+push(int type, ...)
253+{
254+ int line, len, pos;
255+ FILE *fp = NULL;
256+ char *buf, *s, *fname = NULL;
257+ va_list va;
258+ struct input *ip;
259+
260+ va_start(va, type);
261+ switch (type) {
262+ case FTFILE:
263+ fp = va_arg(va, FILE *);
264+ s = va_arg(va, char *);
265+ line = va_arg(va, int);
266+ fname = estrdup(s);
267+ buf = emalloc(BUFSIZ);
268+ pos = len = BUFSIZ;
269+ break;
270+ case FTEXPAN:
271+ s = va_arg(va, char *);
272+ buf = estrdup(s);
273+ line = pos = 0;
274+ len = strlen(s);
275+ break;
276+ }
277+ va_end(va);
278+
279+ ip = emalloc(sizeof(*ip));
280+ ip->siz = len;
281+ ip->buf = buf;
282+ ip->type = type;
283+ ip->fp = fp;
284+ ip->loc.fname = fname;
285+ ip->loc.lineno = line;
286+ ip->pos = pos;
287+ ip->prev = input;
288+
289+ input = ip;
290+}
291+
292+static char *
293+trim(char *s)
294+{
295+ size_t len;
296+
297+ while (isspace(*s))
298+ s++;
299+
300+ for (len = strlen(s); len > 0 && isspace(s[len-1]); --len)
301+ s[len-1] = '\0';
302+
303+ return s;
304+}
305+
306+static void
307+include(char *s)
308+{
309+ int len;
310+ FILE *fp;
311+ char *fil, *t;
312+
313+ s = trim(s);
314+ fil = expandstring(s, NULL, getloc());
315+
316+ t = trim(fil);
317+ if (strlen(t) != 0) {
318+ debug("including '%s'", t);
319+ if ((fp = fopen(t, "r")) == NULL)
320+ error("opening %s:%s", t, strerror(errno));
321+ push(FTFILE, fp, t, 0);
322+ }
323+
324+ free(fil);
325+}
326+
327+static char *
328+nextline(void)
329+{
330+ int c;
331+ FILE *fp;
332+ char *s, *lim;
333+
334+ assert(input->type == FTFILE);
335+
336+repeat:
337+ fp = input->fp;
338+ if (!fp || feof(fp))
339+ return NULL;
340+
341+ lim = &input->buf[input->siz];
342+ for (s = input->buf; s < lim; *s++ = c) {
343+ c = getc(fp);
344+ if (c == '\n' || c == EOF) {
345+ input->loc.lineno++;
346+ *s++ = '\n';
347+ break;
348+ }
349+ if (c > UCHAR_MAX || c < 0)
350+ error("invalid character '%c' (%d)", c, c);
351+ }
352+
353+
354+ if (s == lim)
355+ error("too long line");
356+ if (ferror(fp))
357+ error(strerror(errno));
358+ *s = '\0';
359+
360+ if (!strcmp(input->buf, ""))
361+ goto repeat;
362+
363+ if (!strncmp(input->buf, "include", 7) && isblank(input->buf[7])) {
364+ input->pos = input->siz;
365+ include(input->buf+7);
366+ goto repeat;
367+ }
368+
369+ input->pos = 0;
370+
371+
372+ return input->buf;
373+}
374+
375+static int
376+empty(struct input *ip)
377+{
378+ return ip->pos == ip->siz || ip->buf[ip->pos] == '\0';
379+}
380+
381+static int
382+moreinput(void)
383+{
384+ while (input) {
385+ if (!empty(input))
386+ break;
387+
388+ switch (input->type) {
389+ case FTEXPAN:
390+ pop();
391+ break;
392+ case FTFILE:
393+ if (!nextline())
394+ pop();
395+ break;
396+ }
397+ }
398+
399+ return input != NULL;
400+}
401+
402+static int
403+nextc(void)
404+{
405+ if (!moreinput())
406+ return EOF;
407+
408+ return input->buf[input->pos++];
409+}
410+
411+/*
412+ * This function only can be called after a call to nextc
413+ * that didn't return EOF. It can return '\0', but as
414+ * it is used only to check against '$' then it is not
415+ * a problem.
416+ */
417+static int
418+ahead(void)
419+{
420+ return input->buf[input->pos];
421+}
422+
423+static int
424+back(int c)
425+{
426+ if (c == EOF)
427+ return c;
428+ assert(input->pos > 0);
429+ return input->buf[--input->pos] = c;
430+}
431+
432+static void
433+comment(void)
434+{
435+ int c;
436+
437+ while ((c = nextc()) != EOF && c != '\n') {
438+ if (c == '\\' && nextc() == EOF)
439+ break;
440+ }
441+}
442+
443+static void
444+skipspaces(void)
445+{
446+ int c;
447+
448+ for (c = nextc(); c == ' ' || c == '\t'; c = nextc())
449+ ;
450+ back(c);
451+}
452+
453+static int
454+validchar(int c)
455+{
456+ if (c == EOF)
457+ return 0;
458+ return c == '.' || c == '/' || c == '_' || c == '-' || isalnum(c);
459+}
460+
461+static char *
462+expandmacro(char *name)
463+{
464+ char *s;
465+
466+ s = expandstring(getmacro(name), NULL, getloc());
467+ debug("macro %s expanded to '%s'", name, s);
468+
469+ return s;
470+}
471+
472+static void
473+replace(char *line, char *repl, char *to)
474+{
475+ int siz, at, len, replsiz, tosiz, sep, pos;
476+ char *oline, *s, *cur, *buf;
477+
478+ debug("replacing '%s', with '%s' to '%s'", line, repl, to);
479+ oline = line;
480+ tosiz = strlen(to);
481+ replsiz = strlen(repl);
482+
483+ buf = NULL;
484+ for (pos = 0; *line; pos += siz) {
485+ cur = NULL;
486+ siz = 0;
487+
488+ for (siz = 0; *line == ' ' || *line == '\t'; ++siz) {
489+ cur = erealloc(cur, siz+1);
490+ cur[siz] = *line++;
491+ }
492+
493+ len = strcspn(line, " \t");
494+ at = len - replsiz;
495+ if (at < 0 || memcmp(line + at, repl, replsiz)) {
496+ cur = erealloc(cur, siz + len);
497+ memcpy(cur + siz, line, len);
498+ siz += len;
499+ } else {
500+ cur = erealloc(cur, siz + at + tosiz);
501+ memcpy(cur + siz, line, at);
502+ memcpy(cur + siz + at, to, tosiz);
503+ siz += at + tosiz;
504+ }
505+
506+ line += len;
507+ buf = erealloc(buf, pos + siz);
508+ memcpy(buf + pos, cur, siz);
509+ free(cur);
510+ }
511+
512+ if (pos > 0) {
513+ buf = erealloc(buf, pos + 1);
514+ buf[pos] = '\0';
515+ debug("\treplace '%s' with '%s'", oline, buf);
516+ push(FTEXPAN, buf);
517+ }
518+
519+ free(buf);
520+}
521+
522+static void
523+expandsimple(Target *tp)
524+{
525+ char *s;
526+ Target **p;
527+ int len, c;
528+
529+ switch (c = nextc()) {
530+ case '@':
531+ if (!tp || !tp->target)
532+ return;
533+ push(FTEXPAN, tp->target);
534+ break;
535+ case '<':
536+ if (!tp || !tp->req)
537+ return;
538+ push(FTEXPAN, tp->req);
539+ break;
540+ case '*':
541+ if (!tp || !tp->target)
542+ return;
543+ s = strrchr(tp->target, '.');
544+ if (!s) {
545+ push(FTEXPAN, tp->target);
546+ return;
547+ }
548+
549+ len = s - tp->target;
550+ s = emalloc(len+1);
551+ memcpy(s, tp->target, len);
552+ s[len] = '\0';
553+ push(FTEXPAN, s);
554+ free(s);
555+ break;
556+ case '?':
557+ if (!tp)
558+ return;
559+
560+ if (tp->req && stamp(tp->req) > tp->stamp) {
561+ push(FTEXPAN, " ");
562+ push(FTEXPAN, tp->req);
563+ }
564+
565+ for (p = tp->deps; p && *p; ++p) {
566+ if (stamp((*p)->name) > tp->stamp) {
567+ push(FTEXPAN, " ");
568+ push(FTEXPAN, (*p)->name);
569+ }
570+ }
571+ break;
572+ default:
573+ token[0] = c;
574+ token[1] = '\0';
575+ s = expandmacro(token);
576+ push(FTEXPAN, s);
577+ free(s);
578+ break;
579+ }
580+}
581+
582+static int
583+internal(int ch)
584+{
585+ switch (ch) {
586+ case '@':
587+ case '?':
588+ case '*':
589+ case '<':
590+ return 1;
591+ default:
592+ return 0;
593+ }
594+}
595+
596+static void
597+expansion(Target *tp)
598+{
599+ int delim, c, repli, toi, namei, st;
600+ char name[MAXTOKEN], repl[MAXREPL], to[MAXREPL];
601+ char *s, *erepl;
602+
603+ c = nextc();
604+ if (c == '(')
605+ delim = ')';
606+ else if (c == '{')
607+ delim = '}';
608+ else
609+ delim = 0;
610+
611+ if (!delim) {
612+ back(c);
613+ expandsimple(tp);
614+ return;
615+ }
616+
617+ s = NULL;
618+ namei = repli = toi = 0;
619+ st = STBEGIN;
620+
621+ while (st != STEND && (c = nextc()) != EOF) {
622+ switch (st) {
623+ case STBEGIN:
624+ if (c == ':') {
625+ st = STREPLACE;
626+ name[namei] = '\0';
627+ s = expandmacro(name);
628+ break;
629+ }
630+ if (c == delim) {
631+ name[namei] = '\0';
632+ s = expandmacro(name);
633+ goto no_replace;
634+ }
635+ if (namei == MAXTOKEN-1)
636+ error("expansion text too long");
637+
638+ if (namei == 0 && internal(c)) {
639+ name[namei++] = '$';
640+ name[namei++] = c;
641+ name[namei] = '\0';
642+ st = STINTERNAL;
643+ s = expandstring(name, tp, getloc());
644+ break;
645+ }
646+
647+ if (!validchar(c))
648+ error("invalid macro name in expansion");
649+ name[namei++] = c;
650+ break;
651+ case STINTERNAL:
652+ if (c == delim)
653+ goto no_replace;
654+ if (c != ':')
655+ error("invalid internal macro in expansion");
656+ st = STREPLACE;
657+ break;
658+ case STREPLACE:
659+ if (c == '=') {
660+ st = STTO;
661+ break;
662+ }
663+ if (c == delim)
664+ error("invalid replacement pattern in expansion");
665+ if (repli == MAXREPL-1)
666+ error("macro replacement too big");
667+ repl[repli++] = c;
668+ break;
669+ case STTO:
670+ if (c == delim) {
671+ st = STEND;
672+ break;
673+ }
674+
675+ if (toi == MAXREPL-1)
676+ error("macro substiturion too big");
677+ to[toi++] = c;
678+ break;
679+ }
680+ }
681+
682+ if (c == EOF)
683+ error("found eof while parsing expansion");
684+
685+ repl[repli] = '\0';
686+ to[toi] = '\0';
687+
688+ erepl = expandstring(repl, tp, getloc());
689+ replace(s, erepl, to);
690+
691+ free(erepl);
692+ free(s);
693+ return;
694+
695+no_replace:
696+ push(FTEXPAN, s);
697+ free(s);
698+}
699+
700+/*
701+ * Horrible hack to do string expansion.
702+ * We cannot use normal push and nextc because that
703+ * would consume characters of the current file too.
704+ * For that reason it cleans the input and it recovers
705+ * it later.
706+ */
707+char *
708+expandstring(char *line, Target *tp, struct loc *loc)
709+{
710+ int c, n;
711+ char *s;
712+ struct input *ip = input;
713+
714+ input = NULL;
715+ push(FTFILE, NULL, loc->fname, loc->lineno);
716+ push(FTEXPAN, line);
717+
718+ n = 0;
719+ s = NULL;
720+ while ((c = nextc()) != EOF) {
721+ if (c != '$') {
722+ s = erealloc(s, ++n);
723+ s[n-1] = c;
724+ continue;
725+ }
726+
727+ if ((c = nextc()) == '$') {
728+ s = erealloc(s, n += 2);
729+ s[n-2] = '$';
730+ s[n-1] = '$';
731+ } else {
732+ back(c);
733+ expansion(tp);
734+ }
735+ }
736+
737+ s = erealloc(s, n+1);
738+ s[n] = '\0';
739+ input = ip;
740+
741+ return s;
742+}
743+
744+static int
745+item(void)
746+{
747+ int c;
748+ char *s;
749+ char buf[MAXTOKEN];
750+
751+ for (s = buf; s < &buf[MAXTOKEN] - 1; ) {
752+ c = nextc();
753+ if (c == '$' && ahead() != '$')
754+ expansion(NULL);
755+ else if (validchar(c))
756+ *s++ = c;
757+ else
758+ break;
759+ }
760+ back(c);
761+
762+ if (s >= &buf[MAXTOKEN] - 1)
763+ error("token too long");
764+ if (s == buf)
765+ error("invalid empty token");
766+ *s++ = '\0';
767+ memcpy(token, buf, s - buf);
768+
769+ return ITEM;
770+}
771+
772+static int
773+next(void)
774+{
775+ int c;
776+
777+repeat:
778+ /*
779+ * It is better to avoid skipspaces() here, because
780+ * it can generate the need for 2 calls to back(),
781+ * and we need the character anyway.
782+ */
783+ c = nextc();
784+ if (c == ' ' || c == '\t')
785+ goto repeat;
786+
787+ if (c == '\\') {
788+ if ((c = nextc()) == '\n')
789+ goto repeat;
790+ back(c);
791+ c = '\\';
792+ }
793+
794+ switch (c) {
795+ case EOF:
796+ strcpy(token, "<EOF>");
797+ tok = EOF;
798+ break;
799+ case '$':
800+ if ((c = nextc()) == '$')
801+ goto single;
802+ back(c);
803+ expansion(NULL);
804+ goto repeat;
805+ case '#':
806+ comment();
807+ c = '\n';
808+ case ';':
809+ case ':':
810+ case '=':
811+ case '\n':
812+ single:
813+ token[0] = c;
814+ token[1] = '\0';
815+ tok = c;
816+ break;
817+ default:
818+ if (!validchar(c))
819+ error("unexpected character '%c'", c);
820+ back(c);
821+ tok = item();
822+ break;
823+ }
824+
825+ return tok;
826+}
827+
828+static char *
829+readmacrodef(void)
830+{
831+ int n, c;
832+ char *line;
833+
834+ n = 0;
835+ line = NULL;
836+ while ((c = nextc()) != EOF) {
837+ line = erealloc(line, n+1);
838+ if (c == '\n')
839+ break;
840+ if (c == '#') {
841+ comment();
842+ break;
843+ }
844+ if (c == '\\') {
845+ if ((c = nextc()) != '\n') {
846+ back(c);
847+ c = '\\';
848+ } else {
849+ skipspaces();
850+ c = ' ';
851+ }
852+ }
853+
854+ line[n++] = c;
855+ }
856+ if (c == EOF)
857+ error("EOF while looking for end of line");
858+ line[n] = '\0';
859+
860+ return line;
861+}
862+
863+static struct action
864+readcmd(void)
865+{
866+ int n, c;
867+ struct loc *loc;
868+ struct action act;
869+
870+ skipspaces();
871+
872+ loc = getloc();
873+ act.loc.fname = estrdup(loc->fname);
874+ act.loc.lineno = loc->lineno;
875+
876+ n = 0;
877+ act.line = NULL;
878+ while ((c = nextc()) != EOF) {
879+ act.line = erealloc(act.line, n+1);
880+ if (c == '\n')
881+ break;
882+ if (c == '\\') {
883+ if ((c = nextc()) == '\n') {
884+ if ((c = nextc()) != '\t')
885+ back(c);
886+ continue;
887+ }
888+ back(c);
889+ c = '\\';
890+ }
891+ act.line[n++] = c;
892+ }
893+ if (c == EOF)
894+ error("EOF while looking for end of command");
895+ act.line[n] = '\0';
896+
897+ return act;
898+}
899+
900+static void
901+rule(char *targets[], int ntargets)
902+{
903+ int c, i, j, ndeps, nactions;
904+ struct action *acts;
905+ char **deps = NULL;
906+
907+ if (ntargets == 0)
908+ error("missing target");
909+
910+ for (ndeps = 0; next() == ITEM; ++ndeps) {
911+ deps = erealloc(deps, (ndeps+1) * sizeof(char *));
912+ deps[ndeps] = estrdup(token);
913+ }
914+
915+ if (tok != '\n' && tok != ';')
916+ error("garbage at the end of the line");
917+
918+ nactions = 0;
919+ acts = NULL;
920+ if (tok == ';') {
921+ nactions++;
922+ acts = erealloc(acts, nactions * sizeof(*acts));
923+ acts[nactions-1] = readcmd();
924+ }
925+
926+ for (;;) {
927+ if ((c = nextc()) == '#') {
928+ comment();
929+ continue;
930+ }
931+ if (c != '\t')
932+ break;
933+ nactions++;
934+ acts = erealloc(acts, nactions * sizeof(*acts));
935+ acts[nactions-1] = readcmd();
936+ }
937+ back(c);
938+
939+ for (i = 0; i < ntargets; i++) {
940+ addtarget(targets[i], ndeps);
941+ for (j = 0; j < ndeps; j++)
942+ adddep(targets[i], deps[j]);
943+ if (nactions > 0)
944+ addrule(targets[i], acts, nactions);
945+ }
946+
947+ for (i = 0; i < ndeps; i++)
948+ free(deps[i]);
949+ free(deps);
950+
951+ for (i = 0; i < nactions; i++) {
952+ free(acts[i].line);
953+ freeloc(&acts[i].loc);
954+ }
955+ free(acts);
956+}
957+
958+static void
959+assign(char *macros[], int where, int n)
960+{
961+ char *defs;
962+
963+ if (n != 1)
964+ error("invalid macro definition");
965+
966+ skipspaces();
967+ defs = readmacrodef();
968+ setmacro(*macros, defs, where, NOEXPORT);
969+ free(defs);
970+}
971+
972+void
973+parseinput(int where)
974+{
975+ int i, n;
976+ char **targets;
977+
978+ while (moreinput()) {
979+ n = 0;
980+ targets = NULL;
981+
982+ next();
983+ if (tok == '\n')
984+ continue;
985+
986+ while (tok == ITEM) {
987+ n++;
988+ targets = erealloc(targets, n * sizeof(char *));
989+ targets[n-1] = estrdup(token);
990+ next();
991+ }
992+
993+ switch (tok) {
994+ case ':':
995+ rule(targets, n);
996+ break;
997+ case '=':
998+ assign(targets, where, n);
999+ break;
1000+ default:
1001+ error("unexpected token '%s'(%d)", token, tok);
1002+ }
1003+
1004+ for (i = 0; i < n; i++)
1005+ free(targets[i]);
1006+ free(targets);
1007+ }
1008+}
1009+
1010+int
1011+parse(char *fname)
1012+{
1013+ FILE *fp;
1014+
1015+ if (!fname) {
1016+ fp = stdin;
1017+ fname = "<stdin>";
1018+ } else if ((fp = fopen(fname, "r")) == NULL) {
1019+ return 0;
1020+ }
1021+
1022+ debug("parsing %s", fname);
1023+ push(FTFILE, fp, fname, 0);
1024+ parseinput(MAKEFILE);
1025+
1026+ return 1;
1027+}
1028+
1029+void
1030+inject(char *s)
1031+{
1032+ push(FTFILE, NULL, "<internal>", 0);
1033+ push(FTEXPAN, s);
1034+ parseinput(INTERNAL);
1035+}
+119,
-0
1@@ -0,0 +1,119 @@
2+#undef _POSIX_C_SOURCE
3+#define _POSIX_C_SOURCE 200809L
4+
5+#include <signal.h>
6+#include <sys/stat.h>
7+#include <sys/wait.h>
8+#include <unistd.h>
9+
10+#include <errno.h>
11+#include <stdio.h>
12+#include <string.h>
13+
14+#include "make.h"
15+
16+
17+static volatile pid_t pid;
18+
19+void
20+killchild(void)
21+{
22+ if (pid != 0)
23+ kill(pid, SIGTERM);
24+ pid = 0;
25+}
26+
27+int
28+is_dir(char *fname)
29+{
30+ struct stat st;
31+
32+ if (stat(fname, &st) < 0)
33+ return 0;
34+ return S_ISDIR(st.st_mode);
35+}
36+
37+void
38+exportvar(char *var, char *value)
39+{
40+ int n;
41+ char *buf;
42+
43+ n = snprintf(NULL, 0, "%s=%s", var, value);
44+ buf = emalloc(n+1);
45+ snprintf(buf, n+1, "%s=%s", var, value);
46+ putenv(buf);
47+}
48+
49+time_t
50+stamp(char *name)
51+{
52+ struct stat st;
53+
54+ if (stat(name, &st) < 0)
55+ return -1;
56+
57+ return st.st_mtime;
58+}
59+
60+int
61+launch(char *cmd, int ignore)
62+{
63+ int st;
64+ sigset_t new, old;
65+ char *name, *shell;
66+ char *args[] = {NULL, "-ec" , cmd, NULL};
67+ static int initsignals;
68+ extern char **environ;
69+ extern void sighandler(int);
70+
71+ if (!initsignals) {
72+ struct sigaction act = {
73+ .sa_handler = sighandler
74+ };
75+
76+ /* avoid BSD weirdness signal restart handling */
77+ sigaction(SIGINT, &act, NULL);
78+ sigaction(SIGHUP, &act, NULL);
79+ sigaction(SIGTERM, &act, NULL);
80+ sigaction(SIGQUIT, &act, NULL);
81+ initsignals = 1;
82+ }
83+
84+ sigfillset(&new);
85+ sigprocmask(SIG_BLOCK, &new, &old);
86+ if (stop)
87+ goto unblock;
88+
89+ switch (pid = fork()) {
90+ case -1:
91+ perror("make");
92+ unblock:
93+ sigprocmask(SIG_SETMASK, &old, NULL);
94+ return -1;
95+ case 0:
96+ signal(SIGINT, SIG_DFL);
97+ signal(SIGHUP, SIG_DFL);
98+ signal(SIGTERM, SIG_DFL);
99+ signal(SIGQUIT, SIG_DFL);
100+
101+ sigprocmask(SIG_SETMASK, &old, NULL);
102+
103+ shell = getmacro("SHELL");
104+
105+ if (ignore)
106+ args[1] = "-c";
107+ if ((name = strrchr(shell, '/')) != NULL)
108+ ++name;
109+ else
110+ name = shell;
111+ args[0] = name;
112+ execve(shell, args, environ);
113+ _exit(127);
114+ default:
115+ sigprocmask(SIG_SETMASK, &old, NULL);
116+ wait(&st);
117+
118+ return st;
119+ }
120+}
+582,
-0
1@@ -0,0 +1,582 @@
2+#include <signal.h>
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "make.h"
8+
9+#define TABSIZ 128
10+#define FORCE 1
11+#define NOFORCE 0
12+
13+static Target *htab[TABSIZ], *deftarget;
14+
15+void
16+dumprules(void)
17+{
18+ int i;
19+ Target **pp, **q, *p;
20+
21+ for (pp = htab; pp < &htab[TABSIZ]; ++pp) {
22+ for (p = *pp; p; p = p->next) {
23+ if (!p->defined)
24+ continue;
25+ printf("%s:", p->name);
26+ for (q = p->deps; q && *q; ++q)
27+ printf(" %s", (*q)->name);
28+ putchar('\n');
29+ for (i = 0; i < p->nactions; i++)
30+ printf("\t%s\n", p->actions[i].line);
31+ putchar('\n');
32+ }
33+ }
34+}
35+
36+static Target *
37+lookup(char *name)
38+{
39+ Target *tp;
40+ int h = hash(name) & TABSIZ-1;
41+
42+ for (tp = htab[h]; tp && strcmp(tp->name, name); tp = tp->next)
43+ ;
44+
45+ if (tp)
46+ return tp;
47+
48+ tp = emalloc(sizeof(*tp));
49+ tp->name = estrdup(name);
50+ tp->target = tp->name;
51+ tp->req = NULL;
52+ tp->ndeps = 0;
53+ tp->deps = NULL;
54+ tp->actions = NULL;
55+ tp->nactions = 0;
56+ tp->next = htab[h];
57+ tp->defined = 0;
58+ htab[h] = tp;
59+
60+ return tp;
61+}
62+
63+static void
64+cleanup(Target *tp)
65+{
66+ int sig, precious;
67+ Target *p, **q;
68+
69+ sig = stop;
70+ printf("make: signal %d arrived\n", sig);
71+
72+ precious = 0;
73+ p = lookup(".PRECIOUS");
74+ for (q = p->deps; q && *q; q++) {
75+ if (strcmp((*q)->name, tp->name) == 0) {
76+ precious = 1;
77+ break;
78+ }
79+ }
80+
81+ if (!precious && !nflag && !qflag && !is_dir(tp->name)) {
82+ printf("make: trying to remove target %s\n", tp->name);
83+ remove(tp->name);
84+ }
85+
86+ signal(sig, SIG_DFL);
87+ raise(sig);
88+}
89+
90+static int
91+depends(char *target, char *dep)
92+{
93+ int i;
94+ Target **p, *tp = lookup(target);
95+
96+ for (p = tp->deps; p && *p; ++p) {
97+ if (strcmp((*p)->name, target) == 0)
98+ return 1;
99+ }
100+
101+ return 0;
102+}
103+
104+static int
105+is_suffix(char *s)
106+{
107+ int n;
108+
109+ if (s[0] != '.')
110+ return 0;
111+
112+ for (n = 0; s = strchr(s, '.'); n++)
113+ s++;
114+
115+ return n == 2;
116+}
117+
118+void
119+addtarget(char *target, int ndeps)
120+{
121+ Target *tp = lookup(target);
122+
123+ tp->defined = 1;
124+ if (!deftarget && target[0] != '.') {
125+ deftarget = tp;
126+ return;
127+ }
128+
129+ if (strcmp(target, ".SUFFIXES") == 0 && ndeps == 0) {
130+ free(tp->deps);
131+ tp->deps = NULL;
132+ tp->ndeps = 0;
133+ return;
134+ }
135+
136+ if (strcmp(target, ".DEFAULT") == 0) {
137+ if (ndeps > 0)
138+ error("DEFAULT rule with prerequisites");
139+ return;
140+ }
141+
142+ if (strcmp(target, ".SILENT") == 0 && ndeps == 0) {
143+ sflag = 1;
144+ return;
145+ }
146+
147+ if (strcmp(target, ".IGNORE") == 0 && ndeps == 0) {
148+ iflag = 1;
149+ return;
150+ }
151+}
152+
153+void
154+adddep(char *target, char *dep)
155+{
156+ int i;
157+ size_t siz;
158+ Target **p, *tp = lookup(target);
159+
160+ if (depends(dep, target)) {
161+ warning("circular dependency %s <- %s dropped", target, dep);
162+ return;
163+ }
164+
165+ for (p = tp->deps; p && *p; ++p) {
166+ if (strcmp((*p)->name, dep) == 0)
167+ return;
168+ }
169+
170+ tp->ndeps++;
171+ siz = (tp->ndeps + 1) * sizeof(Target *);
172+ tp->deps = erealloc(tp->deps, siz);
173+ tp->deps[tp->ndeps-1] = lookup(dep);
174+ tp->deps[tp->ndeps] = NULL;
175+
176+ debug("adding dependency %s <- %s", target, dep);
177+}
178+
179+static void
180+freeaction(struct action *act)
181+{
182+ free(act->line);
183+ freeloc(&act->loc);
184+}
185+
186+void
187+addrule(char *target, struct action *acts, int n)
188+{
189+ int i;
190+ struct action *v;
191+ Target *tp = lookup(target);
192+
193+ debug("adding actions for target %s", target);
194+
195+ if (tp->actions) {
196+ debug("overring actions of target %s", target);
197+ for (i = 0; i < tp->nactions; i++)
198+ freeaction(&tp->actions[i]);
199+ free(tp->actions);
200+ }
201+
202+ v = emalloc(n * sizeof(*v));
203+ for (i = 0; i < n; i++) {
204+ v[i].line = estrdup(acts[i].line);
205+ v[i].loc.lineno = acts[i].loc.lineno;
206+ v[i].loc.fname = estrdup(acts[i].loc.fname);
207+ }
208+
209+ tp->nactions = n;
210+ tp->actions = v;
211+}
212+
213+static int
214+execline(Target *tp, char *line, int ignore, int silence)
215+{
216+ char *s, *t;
217+ Target *p, **q;
218+ int r, at, plus, minus, l;
219+
220+ debug("executing '%s'", line);
221+
222+ at = plus = minus = 0;
223+ for (s = line; ; s++) {
224+ switch (*s) {
225+ case '@':
226+ at = 1;
227+ break;
228+ case '-':
229+ minus = 1;
230+ break;
231+ case '+':
232+ plus = 1;
233+ break;
234+ default:
235+ goto out_loop;
236+ }
237+ }
238+
239+out_loop:
240+ /* unescape $$ */
241+ for (l = strlen(s)+1, t = s; *t; --l, ++t) {
242+ if (t[0] == '$' && t[1] == '$') {
243+ memmove(t+1, t+2, l-2);
244+ l--;
245+ }
246+ }
247+
248+ if (tflag && !plus)
249+ return 0;
250+
251+ if (sflag || silence || (qflag && !plus))
252+ at = 1;
253+ if (nflag)
254+ at = 0;
255+ if (!at) {
256+ puts(s);
257+ fflush(stdout);
258+ }
259+
260+ if ((nflag || qflag) && !plus) {
261+ if (qflag)
262+ exitstatus = 1;
263+ return 0;
264+ }
265+
266+ if (minus || iflag || ignore)
267+ ignore = 1;
268+
269+ r = launch(s, ignore);
270+ if (ignore)
271+ return 0;
272+
273+ return r;
274+}
275+
276+static int
277+touch(char *name, int ignore, int silence)
278+{
279+ char *cmd;
280+ int r, n;
281+
282+ n = snprintf(NULL, 0, "touch %s", name) + 1;
283+ cmd = emalloc(n);
284+ snprintf(cmd, n, "touch %s", name);
285+
286+ if (!sflag && !silence)
287+ puts(cmd);
288+
289+ r = system(cmd);
290+ free(cmd);
291+
292+ if (ignore || iflag)
293+ return 0;
294+
295+ return r;
296+}
297+
298+static int
299+touchdeps(Target *tp, int ignore, int silent)
300+{
301+ int r;
302+ Target **p;
303+
304+ if (tp->req) {
305+ r = touch(tp->req, silent, ignore);
306+ if (r)
307+ return r;
308+ }
309+
310+ for (p = tp->deps; p && *p; ++p) {
311+ r = touch((*p)->name, silent, ignore);
312+ if (r)
313+ return r;
314+ }
315+
316+ return 0;
317+}
318+
319+static int
320+run(Target *tp)
321+{
322+ int r, i, ignore, silent;
323+ char *s;
324+ Target *p, **q;
325+
326+ silent = 0;
327+ p = lookup(".SILENT");
328+ for (q = p->deps; q && *q; ++q) {
329+ if (strcmp((*q)->name, tp->name) == 0) {
330+ debug("target %s error silent by .SILENT", tp->name);
331+ silent = 1;
332+ }
333+ }
334+
335+ ignore = 0;
336+ p = lookup(".IGNORE");
337+ for (q = p->deps; q && *q; ++q) {
338+ if (strcmp((*q)->name, tp->name) == 0) {
339+ debug("target %s error ignored by .IGNORE", tp->name);
340+ ignore = 1;
341+ }
342+ }
343+
344+ if (tflag) {
345+ r = touchdeps(tp, ignore, silent);
346+ if (r)
347+ return r;
348+ }
349+
350+ for (i = 0; i < tp->nactions; i++) {
351+ struct action *p;
352+
353+ if (stop)
354+ cleanup(tp);
355+
356+ p = &tp->actions[i];
357+ debug("executing action '%s'", p->line);
358+ s = expandstring(p->line, tp, &p->loc);
359+ r = execline(tp, s, ignore, silent);
360+ free(s);
361+
362+ if (r)
363+ return r;
364+ }
365+
366+ if (tflag) {
367+ r = touch(tp->target, ignore, silent);
368+ if (r)
369+ return r;
370+ }
371+
372+ return 0;
373+}
374+
375+static int
376+enabled(char *suffix)
377+{
378+ Target **p, *tp = lookup(".SUFFIXES");
379+
380+ for (p = tp->deps; p && *p; ++p) {
381+ if (strcmp(suffix, (*p)->name) == 0)
382+ return 1;
383+ }
384+
385+ return 0;
386+}
387+
388+static Target *
389+inference(Target *tp, int force)
390+{
391+ time_t t;
392+ int tolen, r;
393+ char *to, *from;
394+ Target *q, **p, *suffixes;
395+ char buf[FILENAME_MAX], fname[FILENAME_MAX];
396+
397+ debug("searching an inference rule for %s", tp->name);
398+
399+ to = strrchr(tp->name, '.');
400+ if (to && !enabled(to))
401+ return NULL;
402+ tolen = to ? to - tp->name : strlen(tp->name);
403+
404+ if (!to)
405+ to = "";
406+
407+ suffixes = lookup(".SUFFIXES");
408+ for (p = suffixes->deps; p && *p; ++p) {
409+ from = (*p)->name;
410+ debug("trying suffix %s", from);
411+
412+ r = snprintf(buf,
413+ sizeof(buf),
414+ "%s%s",
415+ from, to);
416+
417+ if (r < 0 || r >= sizeof(buf))
418+ error("suffixes too long %s %s", from, to);
419+
420+ q = lookup(buf);
421+ if (!q->actions)
422+ continue;
423+
424+ r = snprintf(fname,
425+ sizeof(fname),
426+ "%*.*s%s",
427+ tolen, tolen, tp->name, from);
428+
429+ if (r < 0 || r >= sizeof(fname)) {
430+ error("prerequisite name too long %s %s",
431+ tp->name, from);
432+ }
433+
434+ debug("\tsearching prerequisite %s", fname);
435+
436+ t = stamp(fname);
437+ if (t == -1) {
438+ debug("\tprerequisite %s not found", fname);
439+ continue;
440+ }
441+
442+ if (!force && t <= tp->stamp) {
443+ debug("\tdiscarded because is newer");
444+ debug("\t%s: %s", tp->name, ctime(&tp->stamp));
445+ debug("\t%s: %s", fname, ctime(&t));
446+ continue;
447+ }
448+
449+ free(q->req);
450+ q->req = estrdup(fname);
451+ q->deps = tp->deps;
452+ q->target = tp->name;
453+ q->stamp = tp->stamp;
454+
455+ debug("using inference rule %s with %s", q->name, fname);
456+ return q;
457+ }
458+
459+ return NULL;
460+}
461+
462+static int
463+update(Target *tp)
464+{
465+ Target *p;
466+
467+ debug("%s needs to be updated", tp->name);
468+
469+ if (tp->actions) {
470+ debug("using target rule to build %s", tp->name);
471+ return run(tp);
472+ }
473+
474+ if ((p = inference(tp, FORCE)) != NULL) {
475+ debug("using inference rule %s", p->name);
476+ return run(p);
477+ }
478+
479+ p = lookup(".DEFAULT");
480+ if (p->defined) {
481+ debug("using default rule");
482+ return run(p);
483+ }
484+
485+ debug("not rule found to update %s", tp->name);
486+
487+ if (!tp->defined)
488+ error("don't know how to make %s", tp->name);
489+
490+ return 0;
491+}
492+
493+static int
494+rebuild(Target *tp, int *buildp)
495+{
496+ Target **p, *q;;
497+ int r, need, build, err, def;
498+
499+ debug("checking rebuild of %s", tp->name);
500+
501+ tp->stamp = stamp(tp->name);
502+
503+ def = err = need = 0;
504+ for (p = tp->deps; p && *p; ++p) {
505+ if (stop)
506+ cleanup(tp);
507+
508+ q = *p;
509+ debug("checking dependency %s", q->name);
510+
511+ if (strcmp(q->name, tp->name) == 0 && q->actions)
512+ def = 1;
513+
514+ build = 0;
515+ if (rebuild(q, &build) != 0) {
516+ err = 1;
517+ continue;
518+ }
519+
520+ if (build) {
521+ debug("rebuild of %s forces rebuild of %s",
522+ q->name, tp->name);
523+ need = 1;
524+ } else if (q->stamp > tp->stamp) {
525+ debug("dependency %s is newer than %s",
526+ q->name, tp->name);
527+ need = 1;
528+ }
529+ }
530+
531+ if (tp->stamp == -1) {
532+ need = 1;
533+ } else if (!def) {
534+ debug("no action found for %s, looking a inference rule",
535+ tp->name);
536+ if (inference(tp, NOFORCE))
537+ need = 1;
538+ }
539+
540+ if (err) {
541+ warning("target %s not remade because of errors", tp->name);
542+ return 1;
543+ } else if (need) {
544+ *buildp = 1;
545+
546+ debug("target %s needs updating", tp->name);
547+ r = update(tp);
548+ if (r == 0)
549+ return 0;
550+
551+ if (stop)
552+ cleanup(tp);
553+
554+ exitstatus = 1;
555+
556+ if (!kflag)
557+ error("target %s: error %d", tp->name, r);
558+ else
559+ warning("target %s: error %d", tp->name, r);
560+ return r;
561+ }
562+
563+ return 0;
564+}
565+
566+int
567+build(char *name)
568+{
569+ int build, r;
570+
571+ if (!name) {
572+ if (!deftarget) {
573+ printf("make: no target to make\n");
574+ return 0;
575+ }
576+ name = deftarget->name;
577+ }
578+
579+ debug("checking target %s", name);
580+
581+ build = 0;
582+ return rebuild(lookup(name), &build);
583+}
+53,
-0
1@@ -0,0 +1,53 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/types.h>
5+
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s [n|y]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ struct stat sb;
22+ mode_t mode;
23+
24+ ARGBEGIN {
25+ default:
26+ usage();
27+ } ARGEND;
28+
29+ if (argc > 1)
30+ usage();
31+
32+ if (isatty(2) == 0)
33+ eprintf("stderr: not a tty\n");
34+
35+ if (fstat(2, &sb) < 0)
36+ eprintf("fstat stderr:");
37+
38+ if (argc == 0) {
39+ puts(sb.st_mode & (S_IWGRP | S_IWOTH) ? "is y" : "is n");
40+ return 0;
41+ }
42+
43+ if (argv[0][0] == 'y' && argv[0][1] == '\0')
44+ mode = sb.st_mode | S_IWGRP | S_IWOTH;
45+ else if (argv[0][0] == 'n' && argv[0][1] == '\0')
46+ mode = sb.st_mode & ~(S_IWGRP | S_IWOTH);
47+ else
48+ usage();
49+
50+ if (fchmod(2, mode) < 0)
51+ eprintf("fchmod stderr:");
52+
53+ return 0;
54+}
+49,
-0
1@@ -0,0 +1,49 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <stdlib.h>
7+
8+#include "util.h"
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s [-p] [-m mode] name ...\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+ mode_t mode, mask;
20+ int pflag = 0, ret = 0;
21+
22+ mask = umask(0);
23+ mode = 0777 & ~mask;
24+
25+ ARGBEGIN {
26+ case 'p':
27+ pflag = 1;
28+ break;
29+ case 'm':
30+ mode = parsemode(EARGF(usage()), 0777, mask);
31+ break;
32+ default:
33+ usage();
34+ } ARGEND
35+
36+ if (!argc)
37+ usage();
38+
39+ for (; *argv; argc--, argv++) {
40+ if (pflag) {
41+ if (mkdirp(*argv, mode, 0777 & (~mask | 0300)) < 0)
42+ ret = 1;
43+ } else if (mkdir(*argv, mode) < 0) {
44+ weprintf("mkdir %s:", *argv);
45+ ret = 1;
46+ }
47+ }
48+
49+ return ret;
50+}
+39,
-0
1@@ -0,0 +1,39 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <stdlib.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [-m mode] name ...\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ mode_t mode = 0666;
19+ int ret = 0;
20+
21+ ARGBEGIN {
22+ case 'm':
23+ mode = parsemode(EARGF(usage()), mode, umask(0));
24+ break;
25+ default:
26+ usage();
27+ } ARGEND
28+
29+ if (!argc)
30+ usage();
31+
32+ for (; *argv; argc--, argv++) {
33+ if (mkfifo(*argv, mode) < 0) {
34+ weprintf("mkfifo %s:", *argv);
35+ ret = 1;
36+ }
37+ }
38+
39+ return ret;
40+}
+68,
-0
1@@ -0,0 +1,68 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <stdio.h>
8+
9+#include "fs.h"
10+#include "util.h"
11+
12+static int mv_status = 0;
13+
14+static int
15+mv(const char *s1, const char *s2, int depth)
16+{
17+ struct recursor r = { .fn = rm, .follow = 'P', .flags = SILENT };
18+
19+ if (!rename(s1, s2))
20+ return 0;
21+ if (errno == EXDEV) {
22+ cp_aflag = cp_rflag = cp_pflag = 1;
23+ cp_follow = 'P';
24+ cp_status = 0;
25+ rm_status = 0;
26+ cp(s1, s2, depth);
27+ if (cp_status == 0)
28+ recurse(AT_FDCWD, s1, NULL, &r);
29+ if (cp_status || rm_status)
30+ mv_status = 1;
31+ } else {
32+ weprintf("%s -> %s:", s1, s2);
33+ mv_status = 1;
34+ }
35+
36+ return 0;
37+}
38+
39+static void
40+usage(void)
41+{
42+ eprintf("usage: %s [-f] source ... dest\n", argv0);
43+}
44+
45+int
46+main(int argc, char *argv[])
47+{
48+ struct stat st;
49+
50+ ARGBEGIN {
51+ case 'f':
52+ break;
53+ default:
54+ usage();
55+ } ARGEND
56+
57+ if (argc < 2)
58+ usage();
59+
60+ if (argc > 2) {
61+ if (stat(argv[argc - 1], &st) < 0)
62+ eprintf("stat %s:", argv[argc - 1]);
63+ if (!S_ISDIR(st.st_mode))
64+ eprintf("%s: not a directory\n", argv[argc - 1]);
65+ }
66+ enmasse(argc, argv, mv);
67+
68+ return mv_status;
69+}
+56,
-0
1@@ -0,0 +1,56 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/resource.h>
4+
5+#include <errno.h>
6+#include <stdlib.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+#ifndef PRIO_MIN
12+#define PRIO_MIN -NZERO
13+#endif
14+
15+#ifndef PRIO_MAX
16+#define PRIO_MAX (NZERO-1)
17+#endif
18+
19+static void
20+usage(void)
21+{
22+ eprintf("usage: %s [-n inc] cmd [arg ...]\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+ int val = 10, r, savederrno;
29+
30+ ARGBEGIN {
31+ case 'n':
32+ val = estrtonum(EARGF(usage()), PRIO_MIN, PRIO_MAX);
33+ break;
34+ default:
35+ usage();
36+ break;
37+ } ARGEND
38+
39+ if (!argc)
40+ usage();
41+
42+ errno = 0;
43+ r = getpriority(PRIO_PROCESS, 0);
44+ if (errno)
45+ weprintf("getpriority:");
46+ else
47+ val += r;
48+ LIMIT(val, PRIO_MIN, PRIO_MAX);
49+ if (setpriority(PRIO_PROCESS, 0, val) < 0)
50+ weprintf("setpriority:");
51+
52+ execvp(argv[0], argv);
53+ savederrno = errno;
54+ weprintf("execvp %s:", argv[0]);
55+
56+ _exit(126 + (savederrno == ENOENT));
57+}
+212,
-0
1@@ -0,0 +1,212 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "text.h"
10+#include "utf.h"
11+#include "util.h"
12+
13+static size_t startnum = 1;
14+static size_t incr = 1;
15+static size_t blines = 1;
16+static size_t delimlen = 2;
17+static size_t seplen = 1;
18+static int width = 6;
19+static int pflag = 0;
20+static char type[] = { 'n', 't', 'n' }; /* footer, body, header */
21+static char *delim = "\\:";
22+static char format[6] = "%*ld";
23+static char *sep = "\t";
24+static regex_t preg[3];
25+
26+static int
27+getsection(struct line *l, int *section)
28+{
29+ size_t i;
30+ int sectionchanged = 0, newsection = *section;
31+
32+ for (i = 0; (l->len - i) >= delimlen &&
33+ !memcmp(l->data + i, delim, delimlen); i += delimlen) {
34+ if (!sectionchanged) {
35+ sectionchanged = 1;
36+ newsection = 0;
37+ } else {
38+ newsection = (newsection + 1) % 3;
39+ }
40+ }
41+
42+ if (!(l->len - i) || l->data[i] == '\n')
43+ *section = newsection;
44+ else
45+ sectionchanged = 0;
46+
47+ return sectionchanged;
48+}
49+
50+static void
51+nl(const char *fname, FILE *fp)
52+{
53+ static struct line line;
54+ static size_t size;
55+ size_t number = startnum, bl = 1;
56+ ssize_t len;
57+ int donumber, oldsection, section = 1;
58+
59+ while ((len = getline(&line.data, &size, fp)) > 0) {
60+ line.len = len;
61+ donumber = 0;
62+ oldsection = section;
63+
64+ if (getsection(&line, §ion)) {
65+ if ((section >= oldsection) && !pflag)
66+ number = startnum;
67+ continue;
68+ }
69+
70+ switch (type[section]) {
71+ case 't':
72+ if (line.data[0] != '\n')
73+ donumber = 1;
74+ break;
75+ case 'p':
76+ if (!regexec(preg + section, line.data, 0, NULL, 0))
77+ donumber = 1;
78+ break;
79+ case 'a':
80+ if (line.data[0] == '\n' && bl < blines) {
81+ ++bl;
82+ } else {
83+ donumber = 1;
84+ bl = 1;
85+ }
86+ }
87+
88+ if (donumber) {
89+ printf(format, width, number);
90+ fwrite(sep, 1, seplen, stdout);
91+ number += incr;
92+ }
93+ fwrite(line.data, 1, line.len, stdout);
94+ }
95+ free(line.data);
96+ if (ferror(fp))
97+ eprintf("getline %s:", fname);
98+}
99+
100+static void
101+usage(void)
102+{
103+ eprintf("usage: %s [-p] [-b type] [-d delim] [-f type]\n"
104+ " [-h type] [-i num] [-l num] [-n format]\n"
105+ " [-s sep] [-v num] [-w num] [file]\n", argv0);
106+}
107+
108+static char
109+getlinetype(char *type, regex_t *preg)
110+{
111+ if (type[0] == 'p')
112+ eregcomp(preg, type + 1, REG_NOSUB);
113+ else if (!type[0] || !strchr("ant", type[0]))
114+ usage();
115+
116+ return type[0];
117+}
118+
119+int
120+main(int argc, char *argv[])
121+{
122+ FILE *fp = NULL;
123+ size_t s;
124+ int ret = 0;
125+ char *d, *formattype, *formatblit;
126+
127+ ARGBEGIN {
128+ case 'd':
129+ switch (utflen((d = EARGF(usage())))) {
130+ case 0:
131+ eprintf("empty logical page delimiter\n");
132+ case 1:
133+ s = strlen(d);
134+ delim = emalloc(s + 1 + 1);
135+ estrlcpy(delim, d, s + 1 + 1);
136+ estrlcat(delim, ":", s + 1 + 1);
137+ delimlen = s + 1;
138+ break;
139+ default:
140+ delim = d;
141+ delimlen = strlen(delim);
142+ break;
143+ }
144+ break;
145+ case 'f':
146+ type[0] = getlinetype(EARGF(usage()), preg);
147+ break;
148+ case 'b':
149+ type[1] = getlinetype(EARGF(usage()), preg + 1);
150+ break;
151+ case 'h':
152+ type[2] = getlinetype(EARGF(usage()), preg + 2);
153+ break;
154+ case 'i':
155+ incr = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
156+ break;
157+ case 'l':
158+ blines = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
159+ break;
160+ case 'n':
161+ formattype = EARGF(usage());
162+ estrlcpy(format, "%", sizeof(format));
163+
164+ if (!strcmp(formattype, "ln")) {
165+ formatblit = "-";
166+ } else if (!strcmp(formattype, "rn")) {
167+ formatblit = "";
168+ } else if (!strcmp(formattype, "rz")) {
169+ formatblit = "0";
170+ } else {
171+ eprintf("%s: bad format\n", formattype);
172+ }
173+
174+ estrlcat(format, formatblit, sizeof(format));
175+ estrlcat(format, "*ld", sizeof(format));
176+ break;
177+ case 'p':
178+ pflag = 1;
179+ break;
180+ case 's':
181+ sep = EARGF(usage());
182+ seplen = unescape(sep);
183+ break;
184+ case 'v':
185+ startnum = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
186+ break;
187+ case 'w':
188+ width = estrtonum(EARGF(usage()), 1, INT_MAX);
189+ break;
190+ default:
191+ usage();
192+ } ARGEND
193+
194+ if (argc > 1)
195+ usage();
196+
197+ if (!argc) {
198+ nl("<stdin>", stdin);
199+ } else {
200+ if (!strcmp(argv[0], "-")) {
201+ argv[0] = "<stdin>";
202+ fp = stdin;
203+ } else if (!(fp = fopen(argv[0], "r"))) {
204+ eprintf("fopen %s:", argv[0]);
205+ }
206+ nl(argv[0], fp);
207+ }
208+
209+ ret |= fp && fp != stdin && fshut(fp, argv[0]);
210+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
211+
212+ return ret;
213+}
+48,
-0
1@@ -0,0 +1,48 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <signal.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s cmd [arg ...]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ int fd, savederrno;
22+
23+ ARGBEGIN {
24+ default:
25+ usage();
26+ } ARGEND
27+
28+ if (!argc)
29+ usage();
30+
31+ if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
32+ enprintf(127, "signal HUP:");
33+
34+ if (isatty(STDOUT_FILENO)) {
35+ if ((fd = open("nohup.out", O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR)) < 0)
36+ enprintf(127, "open nohup.out:");
37+ if (dup2(fd, STDOUT_FILENO) < 0)
38+ enprintf(127, "dup2:");
39+ close(fd);
40+ }
41+ if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
42+ enprintf(127, "dup2:");
43+
44+ execvp(argv[0], argv);
45+ savederrno = errno;
46+ weprintf("execvp %s:", argv[0]);
47+
48+ _exit(126 + (savederrno == ENOENT));
49+}
+332,
-0
1@@ -0,0 +1,332 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <fcntl.h>
5+#include <stdint.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <unistd.h>
10+
11+#include "queue.h"
12+#include "util.h"
13+
14+struct type {
15+ unsigned char format;
16+ unsigned int len;
17+ TAILQ_ENTRY(type) entry;
18+};
19+
20+static TAILQ_HEAD(head, type) head = TAILQ_HEAD_INITIALIZER(head);
21+static unsigned char addr_format = 'o';
22+static off_t skip = 0;
23+static off_t max = -1;
24+static size_t linelen = 1;
25+static int big_endian;
26+
27+static void
28+printaddress(off_t addr)
29+{
30+ char fmt[] = "%07j#";
31+
32+ if (addr_format == 'n') {
33+ fputc(' ', stdout);
34+ } else {
35+ fmt[4] = addr_format;
36+ printf(fmt, (intmax_t)addr);
37+ }
38+}
39+
40+static void
41+printchunk(const unsigned char *s, unsigned char format, size_t len)
42+{
43+ long long res, basefac;
44+ size_t i;
45+ char fmt[] = " %#*ll#";
46+ unsigned char c;
47+
48+ const char *namedict[] = {
49+ "nul", "soh", "stx", "etx", "eot", "enq", "ack",
50+ "bel", "bs", "ht", "nl", "vt", "ff", "cr",
51+ "so", "si", "dle", "dc1", "dc2", "dc3", "dc4",
52+ "nak", "syn", "etb", "can", "em", "sub", "esc",
53+ "fs", "gs", "rs", "us", "sp",
54+ };
55+ const char *escdict[] = {
56+ ['\0'] = "\\0", ['\a'] = "\\a",
57+ ['\b'] = "\\b", ['\t'] = "\\t",
58+ ['\n'] = "\\n", ['\v'] = "\\v",
59+ ['\f'] = "\\f", ['\r'] = "\\r",
60+ };
61+
62+ switch (format) {
63+ case 'a':
64+ c = *s & ~128; /* clear high bit as required by standard */
65+ if (c < LEN(namedict) || c == 127) {
66+ printf(" %3s", (c == 127) ? "del" : namedict[c]);
67+ } else {
68+ printf(" %3c", c);
69+ }
70+ break;
71+ case 'c':
72+ if (strchr("\a\b\t\n\v\f\r\0", *s)) {
73+ printf(" %3s", escdict[*s]);
74+ } else if (!isprint(*s)) {
75+ printf(" %3o", *s);
76+ } else {
77+ printf(" %3c", *s);
78+ }
79+ break;
80+ default:
81+ if (big_endian) {
82+ for (res = 0, basefac = 1, i = len; i; i--) {
83+ res += s[i - 1] * basefac;
84+ basefac <<= 8;
85+ }
86+ } else {
87+ for (res = 0, basefac = 1, i = 0; i < len; i++) {
88+ res += s[i] * basefac;
89+ basefac <<= 8;
90+ }
91+ }
92+ fmt[2] = big_endian ? '-' : ' ';
93+ fmt[6] = format;
94+ printf(fmt, (int)(3 * len + len - 1), res);
95+ }
96+}
97+
98+static void
99+printline(const unsigned char *line, size_t len, off_t addr)
100+{
101+ struct type *t = NULL;
102+ size_t i;
103+ int first = 1;
104+ unsigned char *tmp;
105+
106+ if (TAILQ_EMPTY(&head))
107+ goto once;
108+ TAILQ_FOREACH(t, &head, entry) {
109+once:
110+ if (first) {
111+ printaddress(addr);
112+ first = 0;
113+ } else {
114+ printf("%*c", (addr_format == 'n') ? 1 : 7, ' ');
115+ }
116+ for (i = 0; i < len; i += MIN(len - i, t ? t->len : 4)) {
117+ if (len - i < (t ? t->len : 4)) {
118+ tmp = ecalloc(t ? t->len : 4, 1);
119+ memcpy(tmp, line + i, len - i);
120+ printchunk(tmp, t ? t->format : 'o',
121+ t ? t->len : 4);
122+ free(tmp);
123+ } else {
124+ printchunk(line + i, t ? t->format : 'o',
125+ t ? t->len : 4);
126+ }
127+ }
128+ fputc('\n', stdout);
129+ if (TAILQ_EMPTY(&head) || (!len && !first))
130+ break;
131+ }
132+}
133+
134+static int
135+od(int fd, char *fname, int last)
136+{
137+ static unsigned char *line;
138+ static size_t lineoff;
139+ static off_t addr;
140+ unsigned char buf[BUFSIZ];
141+ size_t i, size = sizeof(buf);
142+ ssize_t n;
143+
144+ while (skip - addr > 0) {
145+ n = read(fd, buf, MIN(skip - addr, sizeof(buf)));
146+ if (n < 0)
147+ weprintf("read %s:", fname);
148+ if (n <= 0)
149+ return n;
150+ addr += n;
151+ }
152+ if (!line)
153+ line = emalloc(linelen);
154+
155+ for (;;) {
156+ if (max >= 0)
157+ size = MIN(max - (addr - skip), size);
158+ if ((n = read(fd, buf, size)) <= 0)
159+ break;
160+ for (i = 0; i < n; i++, addr++) {
161+ line[lineoff++] = buf[i];
162+ if (lineoff == linelen) {
163+ printline(line, lineoff, addr - lineoff + 1);
164+ lineoff = 0;
165+ }
166+ }
167+ }
168+ if (n < 0) {
169+ weprintf("read %s:", fname);
170+ return n;
171+ }
172+ if (lineoff && last)
173+ printline(line, lineoff, addr - lineoff);
174+ if (last)
175+ printline((unsigned char *)"", 0, addr);
176+ return 0;
177+}
178+
179+static int
180+lcm(unsigned int a, unsigned int b)
181+{
182+ unsigned int c, d, e;
183+
184+ for (c = a, d = b; c ;) {
185+ e = c;
186+ c = d % c;
187+ d = e;
188+ }
189+
190+ return a / d * b;
191+}
192+
193+static void
194+addtype(char format, int len)
195+{
196+ struct type *t;
197+
198+ t = emalloc(sizeof(*t));
199+ t->format = format;
200+ t->len = len;
201+ TAILQ_INSERT_TAIL(&head, t, entry);
202+}
203+
204+static void
205+usage(void)
206+{
207+ eprintf("usage: %s [-bdosvx] [-A addressformat] [-E | -e] [-j skip] "
208+ "[-t outputformat] [file ...]\n", argv0);
209+}
210+
211+int
212+main(int argc, char *argv[])
213+{
214+ int fd;
215+ struct type *t;
216+ int ret = 0, len;
217+ char *s;
218+
219+ big_endian = (*(uint16_t *)"\0\xff" == 0xff);
220+
221+ ARGBEGIN {
222+ case 'A':
223+ s = EARGF(usage());
224+ if (strlen(s) != 1 || !strchr("doxn", s[0]))
225+ usage();
226+ addr_format = s[0];
227+ break;
228+ case 'b':
229+ addtype('o', 1);
230+ break;
231+ case 'd':
232+ addtype('u', 2);
233+ break;
234+ case 'E':
235+ case 'e':
236+ big_endian = (ARGC() == 'E');
237+ break;
238+ case 'j':
239+ if ((skip = parseoffset(EARGF(usage()))) < 0)
240+ usage();
241+ break;
242+ case 'N':
243+ if ((max = parseoffset(EARGF(usage()))) < 0)
244+ usage();
245+ break;
246+ case 'o':
247+ addtype('o', 2);
248+ break;
249+ case 's':
250+ addtype('d', 2);
251+ break;
252+ case 't':
253+ s = EARGF(usage());
254+ for (; *s; s++) {
255+ switch (*s) {
256+ case 'a':
257+ case 'c':
258+ addtype(*s, 1);
259+ break;
260+ case 'd':
261+ case 'o':
262+ case 'u':
263+ case 'x':
264+ /* todo: allow multiple digits */
265+ if (*(s+1) > '0' && *(s+1) <= '9') {
266+ len = *(s+1) - '0';
267+ } else {
268+ switch (*(s+1)) {
269+ case 'C':
270+ len = sizeof(char);
271+ break;
272+ case 'S':
273+ len = sizeof(short);
274+ break;
275+ case 'I':
276+ len = sizeof(int);
277+ break;
278+ case 'L':
279+ len = sizeof(long);
280+ break;
281+ default:
282+ len = sizeof(int);
283+ }
284+ }
285+ addtype(*s, len);
286+ break;
287+ default:
288+ usage();
289+ }
290+ }
291+ break;
292+ case 'v':
293+ /* always set - use uniq(1) to handle duplicate lines */
294+ break;
295+ case 'x':
296+ addtype('x', 2);
297+ break;
298+ default:
299+ usage();
300+ } ARGEND
301+
302+ /* line length is lcm of type lengths and >= 16 by doubling */
303+ TAILQ_FOREACH(t, &head, entry)
304+ linelen = lcm(linelen, t->len);
305+ if (TAILQ_EMPTY(&head))
306+ linelen = 16;
307+ while (linelen < 16)
308+ linelen *= 2;
309+
310+ if (!argc) {
311+ if (od(0, "<stdin>", 1) < 0)
312+ ret = 1;
313+ } else {
314+ for (; *argv; argc--, argv++) {
315+ if (!strcmp(*argv, "-")) {
316+ *argv = "<stdin>";
317+ fd = 0;
318+ } else if ((fd = open(*argv, O_RDONLY)) < 0) {
319+ weprintf("open %s:", *argv);
320+ ret = 1;
321+ continue;
322+ }
323+ if (od(fd, *argv, (!*(argv + 1))) < 0)
324+ ret = 1;
325+ if (fd != 0)
326+ close(fd);
327+ }
328+ }
329+
330+ ret |= fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>");
331+
332+ return ret;
333+}
+144,
-0
1@@ -0,0 +1,144 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdlib.h>
4+#include <string.h>
5+
6+#include "utf.h"
7+#include "util.h"
8+
9+struct fdescr {
10+ FILE *fp;
11+ const char *name;
12+};
13+
14+static void
15+sequential(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
16+{
17+ Rune c, last;
18+ size_t i, d;
19+
20+ for (i = 0; i < fdescrlen; i++) {
21+ d = 0;
22+ last = 0;
23+
24+ while (efgetrune(&c, dsc[i].fp, dsc[i].name)) {
25+ if (last == '\n') {
26+ if (delim[d] != '\0')
27+ efputrune(&delim[d], stdout, "<stdout>");
28+ d = (d + 1) % delimlen;
29+ }
30+
31+ if (c != '\n')
32+ efputrune(&c, stdout, "<stdout>");
33+ last = c;
34+ }
35+
36+ if (last == '\n')
37+ efputrune(&last, stdout, "<stdout>");
38+ }
39+}
40+
41+static void
42+parallel(struct fdescr *dsc, int fdescrlen, Rune *delim, size_t delimlen)
43+{
44+ Rune c, d;
45+ size_t i, m;
46+ ssize_t last;
47+
48+nextline:
49+ last = -1;
50+
51+ for (i = 0; i < fdescrlen; i++) {
52+ d = delim[i % delimlen];
53+ c = 0;
54+
55+ while (efgetrune(&c, dsc[i].fp, dsc[i].name)) {
56+ for (m = last + 1; m < i; m++) {
57+ if (delim[m % delimlen] != '\0')
58+ efputrune(&delim[m % delimlen], stdout, "<stdout>");
59+ }
60+ last = i;
61+ if (c == '\n') {
62+ if (i != fdescrlen - 1)
63+ c = d;
64+ efputrune(&c, stdout, "<stdout>");
65+ break;
66+ }
67+ efputrune(&c, stdout, "<stdout>");
68+ }
69+
70+ if (c == 0 && last != -1) {
71+ if (i == fdescrlen - 1)
72+ putchar('\n');
73+ else if (d != '\0')
74+ efputrune(&d, stdout, "<stdout>");
75+ last++;
76+ }
77+ }
78+ if (last != -1)
79+ goto nextline;
80+}
81+
82+static void
83+usage(void)
84+{
85+ eprintf("usage: %s [-s] [-d list] file ...\n", argv0);
86+}
87+
88+int
89+main(int argc, char *argv[])
90+{
91+ struct fdescr *dsc;
92+ Rune *delim_rune = NULL;
93+ size_t delim_runelen, i, delim_bytelen = 1;
94+ int seq = 0, ret = 0;
95+ char *delim = "\t";
96+
97+ ARGBEGIN {
98+ case 's':
99+ seq = 1;
100+ break;
101+ case 'd':
102+ delim = EARGF(usage());
103+ delim_bytelen = unescape(delim);
104+ break;
105+ default:
106+ usage();
107+ } ARGEND
108+
109+ if (!argc)
110+ usage();
111+
112+ /* populate delimiters */
113+ delim_rune = ereallocarray(NULL,
114+ utfmemlen(delim, delim_bytelen) + 1, sizeof(*delim_rune));
115+ if (!(delim_runelen = utfntorunestr(delim, delim_bytelen, delim_rune))) {
116+ usage();
117+ }
118+
119+ /* populate file list */
120+ dsc = ereallocarray(NULL, argc, sizeof(*dsc));
121+
122+ for (i = 0; i < argc; i++) {
123+ if (!strcmp(argv[i], "-")) {
124+ argv[i] = "<stdin>";
125+ dsc[i].fp = stdin;
126+ } else if (!(dsc[i].fp = fopen(argv[i], "r"))) {
127+ eprintf("fopen %s:", argv[i]);
128+ }
129+ dsc[i].name = argv[i];
130+ }
131+
132+ if (seq) {
133+ sequential(dsc, argc, delim_rune, delim_runelen);
134+ } else {
135+ parallel(dsc, argc, delim_rune, delim_runelen);
136+ }
137+
138+ for (i = 0; i < argc; i++)
139+ if (dsc[i].fp != stdin && fshut(dsc[i].fp, argv[i]))
140+ ret |= fshut(dsc[i].fp, argv[i]);
141+
142+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
143+
144+ return ret;
145+}
+104,
-0
1@@ -0,0 +1,104 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <limits.h>
7+#include <stdint.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+
12+#include "util.h"
13+
14+#define PORTABLE_CHARACTER_SET "0123456789._-qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
15+/* If your system supports more other characters, but not all non-NUL characters, define SYSTEM_CHARACTER_SET. */
16+
17+static int most = 0;
18+static int extra = 0;
19+
20+static int
21+pathchk(char *filename)
22+{
23+ char *invalid, *invalid_end, *p, *q;
24+ const char *character_set;
25+ size_t len, maxlen;
26+ struct stat st;
27+
28+ /* Empty? */
29+ if (extra && !*filename)
30+ eprintf("empty filename\n");
31+
32+ /* Leading hyphen? */
33+ if (extra && ((*filename == '-') || strstr(filename, "/-")))
34+ eprintf("%s: leading '-' in component of filename\n", filename);
35+
36+ /* Nonportable character? */
37+#ifdef SYSTEM_CHARACTER_SET
38+ character_set = "/"SYSTEM_CHARACTER_SET;
39+#else
40+ character_set = 0;
41+#endif
42+ if (most)
43+ character_set = "/"PORTABLE_CHARACTER_SET;
44+ if (character_set && *(invalid = filename + strspn(filename, character_set))) {
45+ for (invalid_end = invalid + 1; *invalid_end & 0x80; invalid_end++);
46+ p = estrdup(filename);
47+ *invalid_end = 0;
48+ eprintf("%s: nonportable character '%s'\n", p, invalid);
49+ }
50+
51+ /* Symlink error? Non-searchable directory? */
52+ if (lstat(filename, &st) && errno != ENOENT) {
53+ /* lstat rather than stat, so that if filename is a bad symlink, but
54+ * all parents are OK, no error will be detected. */
55+ eprintf("%s:", filename);
56+ }
57+
58+ /* Too long pathname? */
59+ maxlen = most ? _POSIX_PATH_MAX : PATH_MAX;
60+ if (strlen(filename) >= maxlen)
61+ eprintf("%s: is longer than %zu bytes\n", filename, maxlen);
62+
63+ /* Too long component? */
64+ maxlen = most ? _POSIX_NAME_MAX : NAME_MAX;
65+ for (p = filename; p; p = q) {
66+ q = strchr(p, '/');
67+ len = q ? (size_t)(q++ - p) : strlen(p);
68+ if (len > maxlen)
69+ eprintf("%s: includes component longer than %zu bytes\n",
70+ filename, maxlen);
71+ }
72+
73+ return 0;
74+}
75+
76+static void
77+usage(void)
78+{
79+ eprintf("usage: %s [-pP] filename...\n", argv0);
80+}
81+
82+int
83+main(int argc, char *argv[])
84+{
85+ int ret = 0;
86+
87+ ARGBEGIN {
88+ case 'p':
89+ most = 1;
90+ break;
91+ case 'P':
92+ extra = 1;
93+ break;
94+ default:
95+ usage();
96+ } ARGEND
97+
98+ if (!argc)
99+ usage();
100+
101+ for (; argc--; argv++)
102+ ret |= pathchk(*argv);
103+
104+ return ret;
105+}
+313,
-0
1@@ -0,0 +1,313 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <errno.h>
5+#include <limits.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "utf.h"
11+#include "util.h"
12+
13+#define is_odigit(c) ('0' <= (c) && (c) <= '7')
14+
15+static size_t
16+unescape_pct(char *s, char *is_pct)
17+{
18+ static const char escapes[256] = {
19+ ['"'] = '"',
20+ ['\''] = '\'',
21+ ['\\'] = '\\',
22+ ['a'] = '\a',
23+ ['b'] = '\b',
24+ ['E'] = 033,
25+ ['e'] = 033,
26+ ['f'] = '\f',
27+ ['n'] = '\n',
28+ ['r'] = '\r',
29+ ['t'] = '\t',
30+ ['v'] = '\v'
31+ };
32+ size_t m, q;
33+ char *r, *w;
34+
35+ for (r = w = s; *r;) {
36+ if (*r != '\\') {
37+ is_pct[w - s] = (*r == '%');
38+ *w++ = *r++;
39+ continue;
40+ }
41+ r++;
42+ if (!*r) {
43+ eprintf("null escape sequence\n");
44+ } else if (escapes[(unsigned char)*r]) {
45+ is_pct[w - s] = 0;
46+ *w++ = escapes[(unsigned char)*r++];
47+ } else if (is_odigit(*r)) {
48+ for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
49+ q = q * 8 + (*r - '0');
50+ is_pct[w - s] = 0;
51+ *w++ = MIN(q, 255);
52+ } else if (*r == 'x' && isxdigit(r[1])) {
53+ r++;
54+ for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
55+ if (isdigit(*r))
56+ q = q * 16 + (*r - '0');
57+ else
58+ q = q * 16 + (tolower(*r) - 'a' + 10);
59+ is_pct[w - s] = 0;
60+ *w++ = q;
61+ } else {
62+ eprintf("invalid escape sequence '\\%c'\n", *r);
63+ }
64+ }
65+ *w = '\0';
66+
67+ return w - s;
68+}
69+
70+static void
71+usage(void)
72+{
73+ eprintf("usage: %s format [arg ...]\n", argv0);
74+}
75+
76+int
77+main(int argc, char *argv[])
78+{
79+ Rune *rarg;
80+ size_t i, j, f, formatlen, blen, nflags;
81+ long long num;
82+ double dou;
83+ int cooldown = 0, width, precision, ret = 0, argi, lastargi;
84+ int has_width, has_precision;
85+ char *format, *tmp, *arg, *fmt, *fmt_ptr, *is_pct;
86+
87+ argv0 = argv[0];
88+ if (argc < 2)
89+ usage();
90+
91+ format = argv[1];
92+ if ((tmp = strstr(format, "\\c"))) {
93+ *tmp = 0;
94+ cooldown = 1;
95+ }
96+ is_pct = ecalloc(strlen(format) + 1, sizeof(*is_pct));
97+ formatlen = unescape_pct(format, is_pct);
98+ if (formatlen == 0) {
99+ free(is_pct);
100+ return 0;
101+ }
102+ lastargi = 0;
103+ for (i = 0, argi = 2; !cooldown || i < formatlen; i++, i = cooldown ? i : (i % formatlen)) {
104+ if (i == 0) {
105+ if (lastargi == argi)
106+ break;
107+ lastargi = argi;
108+ }
109+
110+ if (format[i] != '%' || !is_pct[i]) {
111+ putchar(format[i]);
112+ continue;
113+ }
114+
115+ /* flag */
116+ f = ++i;
117+ nflags = strspn(&format[f], "#-+ 0");
118+ i += nflags;
119+
120+ if (nflags > INT_MAX)
121+ eprintf("Too many flags in format\n");
122+
123+ /* field width */
124+ has_width = 0;
125+ width = 0;
126+ if (format[i] == '*') {
127+ has_width = 1;
128+ if (argi < argc)
129+ width = estrtonum(argv[argi++], INT_MIN, INT_MAX);
130+ else
131+ cooldown = 1;
132+ i++;
133+ } else {
134+ j = i;
135+ i += strspn(&format[i], "+-0123456789");
136+ if (j != i) {
137+ has_width = 1;
138+ tmp = estrndup(format + j, i - j);
139+ width = estrtonum(tmp, INT_MIN, INT_MAX);
140+ free(tmp);
141+ }
142+ }
143+
144+ /* field precision */
145+ has_precision = 0;
146+ precision = 0;
147+ if (format[i] == '.') {
148+ has_precision = 1;
149+ if (format[++i] == '*') {
150+ if (argi < argc)
151+ precision = estrtonum(argv[argi++], INT_MIN, INT_MAX);
152+ else
153+ cooldown = 1;
154+ i++;
155+ } else {
156+ j = i;
157+ i += strspn(&format[i], "+-0123456789");
158+ if (j != i) {
159+ tmp = estrndup(format + j, i - j);
160+ precision = estrtonum(tmp, INT_MIN, INT_MAX);
161+ free(tmp);
162+ }
163+ }
164+ }
165+
166+ if (format[i] != '%' || !is_pct[i]) {
167+ if (argi < argc)
168+ arg = argv[argi++];
169+ else {
170+ arg = "";
171+ cooldown = 1;
172+ }
173+ } else {
174+ putchar('%');
175+ continue;
176+ }
177+
178+ switch (format[i]) {
179+ case 'b':
180+ if ((tmp = strstr(arg, "\\c"))) {
181+ *tmp = 0;
182+ blen = unescape(arg);
183+ fwrite(arg, sizeof(*arg), blen, stdout);
184+ free(is_pct);
185+ return 0;
186+ }
187+ blen = unescape(arg);
188+ fwrite(arg, sizeof(*arg), blen, stdout);
189+ break;
190+ case 'c':
191+ unescape(arg);
192+ rarg = ereallocarray(NULL, utflen(arg) + 1, sizeof(*rarg));
193+ utftorunestr(arg, rarg);
194+ efputrune(rarg, stdout, "<stdout>");
195+ free(rarg);
196+ break;
197+ case 's':
198+ fmt = emalloc(nflags + 10);
199+ fmt_ptr = fmt;
200+ *fmt_ptr++ = '%';
201+ memcpy(fmt_ptr, &format[f], nflags);
202+ fmt_ptr += nflags;
203+ if (has_width)
204+ *fmt_ptr++ = '*';
205+ if (has_precision) {
206+ *fmt_ptr++ = '.';
207+ *fmt_ptr++ = '*';
208+ }
209+ *fmt_ptr++ = 's';
210+ *fmt_ptr = '\0';
211+
212+ if (has_width && has_precision)
213+ printf(fmt, width, precision, arg);
214+ else if (has_width)
215+ printf(fmt, width, arg);
216+ else if (has_precision)
217+ printf(fmt, precision, arg);
218+ else
219+ printf(fmt, arg);
220+ free(fmt);
221+ break;
222+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
223+ for (j = 0; isspace(arg[j]); j++);
224+ if (arg[j] == '\'' || arg[j] == '\"') {
225+ arg += j + 1;
226+ unescape(arg);
227+ rarg = ereallocarray(NULL, utflen(arg) + 1, sizeof(*rarg));
228+ utftorunestr(arg, rarg);
229+ num = rarg[0];
230+ } else if (arg[0]) {
231+ errno = 0;
232+ if (format[i] == 'd' || format[i] == 'i')
233+ num = strtol(arg, &tmp, 0);
234+ else
235+ num = strtoul(arg, &tmp, 0);
236+
237+ if (tmp == arg || *tmp != '\0') {
238+ ret = 1;
239+ weprintf("%%%c %s: conversion error\n",
240+ format[i], arg);
241+ }
242+ if (errno == ERANGE) {
243+ ret = 1;
244+ weprintf("%%%c %s: out of range\n",
245+ format[i], arg);
246+ }
247+ } else {
248+ num = 0;
249+ }
250+ fmt = emalloc(nflags + 15);
251+ fmt_ptr = fmt;
252+ *fmt_ptr++ = '%';
253+ memcpy(fmt_ptr, &format[f], nflags);
254+ fmt_ptr += nflags;
255+ if (has_width)
256+ *fmt_ptr++ = '*';
257+ if (has_precision) {
258+ *fmt_ptr++ = '.';
259+ *fmt_ptr++ = '*';
260+ }
261+ *fmt_ptr++ = 'l';
262+ *fmt_ptr++ = 'l';
263+ *fmt_ptr++ = format[i];
264+ *fmt_ptr = '\0';
265+
266+ if (has_width && has_precision)
267+ printf(fmt, width, precision, num);
268+ else if (has_width)
269+ printf(fmt, width, num);
270+ else if (has_precision)
271+ printf(fmt, precision, num);
272+ else
273+ printf(fmt, num);
274+ free(fmt);
275+ break;
276+ case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
277+ fmt = emalloc(nflags + 15);
278+ fmt_ptr = fmt;
279+ *fmt_ptr++ = '%';
280+ memcpy(fmt_ptr, &format[f], nflags);
281+ fmt_ptr += nflags;
282+ if (has_width)
283+ *fmt_ptr++ = '*';
284+ if (has_precision) {
285+ *fmt_ptr++ = '.';
286+ *fmt_ptr++ = '*';
287+ }
288+ *fmt_ptr++ = format[i];
289+ *fmt_ptr = '\0';
290+
291+ dou = (strlen(arg) > 0) ? estrtod(arg) : 0;
292+ if (has_width && has_precision)
293+ printf(fmt, width, precision, dou);
294+ else if (has_width)
295+ printf(fmt, width, dou);
296+ else if (has_precision)
297+ printf(fmt, precision, dou);
298+ else
299+ printf(fmt, dou);
300+ free(fmt);
301+ break;
302+ case '\0':
303+ eprintf("Missing format specifier.\n");
304+ break;
305+ default:
306+ eprintf("Invalid format specifier '%c'.\n", format[i]);
307+ }
308+ if (argi >= argc)
309+ cooldown = 1;
310+ }
311+
312+ free(is_pct);
313+ return fshut(stdout, "<stdout>") | ret;
314+}
+180,
-0
1@@ -0,0 +1,180 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/sysinfo.h>
5+
6+#include <errno.h>
7+#include <libgen.h>
8+#include <limits.h>
9+#include <pwd.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <time.h>
14+#include <unistd.h>
15+
16+#include "proc.h"
17+#include "util.h"
18+
19+static void psout(struct procstat *ps);
20+static void psr(const char *file);
21+
22+enum {
23+ PS_aflag = 1 << 0,
24+ PS_Aflag = 1 << 1,
25+ PS_dflag = 1 << 2,
26+ PS_fflag = 1 << 3
27+};
28+
29+static int flags;
30+
31+static void
32+psout(struct procstat *ps)
33+{
34+ struct procstatus pstatus;
35+ char cmdline[BUFSIZ], *cmd;
36+ char buf[BUFSIZ];
37+ char ttystr[TTY_NAME_MAX], *myttystr;
38+ int tty_maj, tty_min;
39+ uid_t myeuid;
40+ unsigned sutime;
41+ time_t start;
42+ char stimestr[sizeof("%H:%M")];
43+ struct sysinfo info;
44+ struct passwd *pw;
45+ struct winsize w;
46+
47+ /* Ignore session leaders */
48+ if (flags & PS_dflag)
49+ if (ps->pid == ps->sid)
50+ return;
51+
52+ devtotty(ps->tty_nr, &tty_maj, &tty_min);
53+ ttytostr(tty_maj, tty_min, ttystr, sizeof(ttystr));
54+
55+ /* Only print processes that are associated with
56+ * a terminal and they are not session leaders */
57+ if (flags & PS_aflag)
58+ if (ps->pid == ps->sid || ttystr[0] == '?')
59+ return;
60+
61+ if (parsestatus(ps->pid, &pstatus) < 0)
62+ return;
63+
64+ /* This is the default case, only print processes that have
65+ * the same controlling terminal as the invoker and the same
66+ * euid as the current user */
67+ if (!(flags & (PS_aflag | PS_Aflag | PS_dflag))) {
68+ myttystr = ttyname(0);
69+ if (myttystr) {
70+ if (strcmp(myttystr + strlen("/dev/"), ttystr))
71+ return;
72+ } else {
73+ /* The invoker has no controlling terminal - just
74+ * go ahead and print the processes anyway */
75+ ttystr[0] = '?';
76+ ttystr[1] = '\0';
77+ }
78+ myeuid = geteuid();
79+ if (myeuid != pstatus.euid)
80+ return;
81+ }
82+
83+ sutime = (ps->stime + ps->utime) / sysconf(_SC_CLK_TCK);
84+
85+ ioctl(1, TIOCGWINSZ, &w);
86+ if (!(flags & PS_fflag)) {
87+ snprintf(buf, sizeof(buf), "%5d %-6s %02u:%02u:%02u %s", ps->pid, ttystr,
88+ sutime / 3600, (sutime % 3600) / 60, sutime % 60,
89+ ps->comm);
90+ if (w.ws_col)
91+ printf("%.*s\n", w.ws_col, buf);
92+ else
93+ printf("%s\n", buf);
94+ } else {
95+ errno = 0;
96+ pw = getpwuid(pstatus.uid);
97+ if (!pw)
98+ eprintf("getpwuid %d:", pstatus.uid);
99+
100+ if (sysinfo(&info) < 0)
101+ eprintf("sysinfo:");
102+
103+ start = time(NULL) - info.uptime;
104+ start += (ps->starttime / sysconf(_SC_CLK_TCK));
105+ strftime(stimestr, sizeof(stimestr),
106+ "%H:%M", localtime(&start));
107+
108+ /* For kthreads/zombies /proc/<pid>/cmdline will be
109+ * empty so use ps->comm in that case */
110+ if (parsecmdline(ps->pid, cmdline, sizeof(cmdline)) < 0)
111+ cmd = ps->comm;
112+ else
113+ cmd = cmdline;
114+
115+ snprintf(buf, sizeof(buf), "%-8s %5d %5d ? %5s %-5s %02u:%02u:%02u %s%s%s",
116+ pw->pw_name, ps->pid,
117+ ps->ppid, stimestr, ttystr,
118+ sutime / 3600, (sutime % 3600) / 60, sutime % 60,
119+ (cmd == ps->comm) ? "[" : "", cmd,
120+ (cmd == ps->comm) ? "]" : "");
121+ if (w.ws_col)
122+ printf("%.*s\n", w.ws_col, buf);
123+ else
124+ printf("%s\n", buf);
125+ }
126+}
127+
128+static void
129+psr(const char *file)
130+{
131+ char path[PATH_MAX], *p;
132+ struct procstat ps;
133+ pid_t pid;
134+
135+ if (strlcpy(path, file, sizeof(path)) >= sizeof(path))
136+ eprintf("path too long\n");
137+ p = basename(path);
138+ if (pidfile(p) == 0)
139+ return;
140+ pid = estrtol(p, 10);
141+ if (parsestat(pid, &ps) < 0)
142+ return;
143+ psout(&ps);
144+}
145+
146+static void
147+usage(void)
148+{
149+ eprintf("usage: %s [-aAdef]\n", argv0);
150+}
151+
152+int
153+main(int argc, char *argv[])
154+{
155+ ARGBEGIN {
156+ case 'a':
157+ flags |= PS_aflag;
158+ break;
159+ case 'A':
160+ flags |= PS_Aflag;
161+ break;
162+ case 'd':
163+ flags |= PS_dflag;
164+ break;
165+ case 'e':
166+ flags |= PS_Aflag;
167+ break;
168+ case 'f':
169+ flags |= PS_fflag;
170+ break;
171+ default:
172+ usage();
173+ } ARGEND;
174+
175+ if (!(flags & PS_fflag))
176+ printf(" PID TTY TIME CMD\n");
177+ else
178+ printf("UID PID PPID C STIME TTY TIME CMD\n");
179+ recurse_dir("/proc", psr);
180+ return 0;
181+}
+50,
-0
1@@ -0,0 +1,50 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static const char *
12+getpwd(const char *cwd)
13+{
14+ const char *pwd;
15+ struct stat cst, pst;
16+
17+ if (!(pwd = getenv("PWD")) || pwd[0] != '/' || stat(pwd, &pst) < 0)
18+ return cwd;
19+ if (stat(cwd, &cst) < 0)
20+ eprintf("stat %s:", cwd);
21+
22+ return (pst.st_dev == cst.st_dev && pst.st_ino == cst.st_ino) ? pwd : cwd;
23+}
24+
25+static void
26+usage(void)
27+{
28+ eprintf("usage: %s [-LP]\n", argv0);
29+}
30+
31+int
32+main(int argc, char *argv[])
33+{
34+ char cwd[PATH_MAX];
35+ char mode = 'L';
36+
37+ ARGBEGIN {
38+ case 'L':
39+ case 'P':
40+ mode = ARGC();
41+ break;
42+ default:
43+ usage();
44+ } ARGEND
45+
46+ if (!getcwd(cwd, sizeof(cwd)))
47+ eprintf("getcwd:");
48+ puts((mode == 'L') ? getpwd(cwd) : cwd);
49+
50+ return fshut(stdout, "<stdout>");
51+}
+68,
-0
1@@ -0,0 +1,68 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+#ifdef STD_NON_POSIX
15+ eprintf("usage: %s [-fn] path\n", argv0);
16+#else
17+ eprintf("usage: %s [-n] path\n", argv0);
18+#endif
19+}
20+
21+int
22+main(int argc, char *argv[])
23+{
24+ char buf[PATH_MAX];
25+ ssize_t n;
26+ int nflag = 0;
27+#ifdef STD_NON_POSIX
28+ int fflag = 0;
29+#endif
30+
31+ ARGBEGIN
32+ {
33+#ifdef STD_NON_POSIX
34+ case 'f':
35+ fflag = 1;
36+ break;
37+#endif
38+ case 'n':
39+ nflag = 1;
40+ break;
41+ default:
42+ usage();
43+ }
44+ ARGEND
45+
46+ if (argc != 1)
47+ usage();
48+
49+ if (strlen(argv[0]) >= PATH_MAX)
50+ eprintf("path too long\n");
51+
52+#ifdef STD_NON_POSIX
53+ if (fflag) {
54+ if (!realpath(argv[0], buf))
55+ eprintf("realpath %s:", argv[0]);
56+ } else
57+#endif
58+ {
59+ if ((n = readlink(argv[0], buf, PATH_MAX - 1)) < 0)
60+ eprintf("readlink %s:", argv[0]);
61+ buf[n] = '\0';
62+ }
63+
64+ fputs(buf, stdout);
65+ if (!nflag)
66+ putchar('\n');
67+
68+ return fshut(stdout, "<stdout>");
69+}
+93,
-0
1@@ -0,0 +1,93 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/resource.h>
4+
5+#include <errno.h>
6+#include <pwd.h>
7+#include <stdlib.h>
8+
9+#include "util.h"
10+
11+#ifndef PRIO_MIN
12+#define PRIO_MIN -NZERO
13+#endif
14+
15+#ifndef PRIO_MAX
16+#define PRIO_MAX (NZERO-1)
17+#endif
18+
19+static int
20+renice(int which, int who, long adj)
21+{
22+ errno = 0;
23+ adj += getpriority(which, who);
24+ if (errno) {
25+ weprintf("getpriority %d:", who);
26+ return 0;
27+ }
28+
29+ adj = MAX(PRIO_MIN, MIN(adj, PRIO_MAX));
30+ if (setpriority(which, who, (int)adj) < 0) {
31+ weprintf("setpriority %d:", who);
32+ return 0;
33+ }
34+
35+ return 1;
36+}
37+
38+static void
39+usage(void)
40+{
41+ eprintf("usage: %s -n num [-g | -p | -u] id ...\n", argv0);
42+}
43+
44+int
45+main(int argc, char *argv[])
46+{
47+ const char *adj = NULL;
48+ long val;
49+ int which = PRIO_PROCESS, ret = 0;
50+ struct passwd *pw;
51+ int who;
52+
53+ ARGBEGIN {
54+ case 'n':
55+ adj = EARGF(usage());
56+ break;
57+ case 'g':
58+ which = PRIO_PGRP;
59+ break;
60+ case 'p':
61+ which = PRIO_PROCESS;
62+ break;
63+ case 'u':
64+ which = PRIO_USER;
65+ break;
66+ default:
67+ usage();
68+ } ARGEND
69+
70+ if (!argc || !adj)
71+ usage();
72+
73+ val = estrtonum(adj, PRIO_MIN, PRIO_MAX);
74+ for (; *argv; argc--, argv++) {
75+ if (which == PRIO_USER) {
76+ errno = 0;
77+ if (!(pw = getpwnam(*argv))) {
78+ if (errno)
79+ weprintf("getpwnam %s:", *argv);
80+ else
81+ weprintf("getpwnam %s: no user found\n", *argv);
82+ ret = 1;
83+ continue;
84+ }
85+ who = pw->pw_uid;
86+ } else {
87+ who = estrtonum(*argv, 1, INT_MAX);
88+ }
89+ if (!renice(which, who, val))
90+ ret = 1;
91+ }
92+
93+ return ret;
94+}
+87,
-0
1@@ -0,0 +1,87 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <string.h>
5+
6+#include "fs.h"
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [-f] [-iRr] file ...\n", argv0);
13+}
14+
15+static int
16+forbidden(char *path, struct stat *root)
17+{
18+ char *s, *t;
19+ size_t n;
20+ struct stat st;
21+ static int w1, w2;
22+
23+ n = strlen(path);
24+ for (t = path + n; t > path && t[-1] == '/'; --t)
25+ ;
26+ for (s = t; s > path && s[-1] != '/'; --s)
27+ ;
28+ n = t - s;
29+ if (n == 1 && *s == '.' || n == 2 && s[0] == '.' && s[1] == '.') {
30+ if (!w1)
31+ weprintf("\".\" and \"..\" may not be removed\n");
32+ w1 = 1;
33+ return 1;
34+ }
35+
36+ if (stat(path, &st) < 0)
37+ return 0;
38+ if (st.st_dev == root->st_dev && st.st_ino == root->st_ino) {
39+ if (!w2)
40+ weprintf("\"/\" may not be removed\n");
41+ w2 = 1;
42+ return 1;
43+ }
44+
45+ return 0;
46+}
47+
48+int
49+main(int argc, char *argv[])
50+{
51+ char *s;
52+ struct stat st;
53+ struct recursor r = { .fn = rm, .maxdepth = 1, .follow = 'P' };
54+
55+ ARGBEGIN {
56+ case 'f':
57+ r.flags |= SILENT | IGNORE;
58+ break;
59+ case 'i':
60+ r.flags |= CONFIRM;
61+ break;
62+ case 'R':
63+ case 'r':
64+ r.maxdepth = 0;
65+ break;
66+ default:
67+ usage();
68+ } ARGEND
69+
70+ if (!argc) {
71+ if (!(r.flags & IGNORE))
72+ usage();
73+ else
74+ return 0;
75+ }
76+
77+ if (stat("/", &st) < 0)
78+ eprintf("stat root:");
79+ for (; *argv; argc--, argv++) {
80+ if (forbidden(*argv, &st)) {
81+ rm_status = 1;
82+ continue;
83+ }
84+ recurse(AT_FDCWD, *argv, NULL, &r);
85+ }
86+
87+ return rm_status || recurse_status;
88+}
+49,
-0
1@@ -0,0 +1,49 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <libgen.h>
4+#include <string.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [-p] dir ...\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ int pflag = 0, ret = 0;
19+ char *d;
20+
21+ ARGBEGIN {
22+ case 'p':
23+ pflag = 1;
24+ break;
25+ default:
26+ usage();
27+ } ARGEND
28+
29+ if (!argc)
30+ usage();
31+
32+ for (; *argv; argc--, argv++) {
33+ if (rmdir(*argv) < 0) {
34+ weprintf("rmdir %s:", *argv);
35+ ret = 1;
36+ } else if (pflag) {
37+ d = dirname(*argv);
38+ for (; strcmp(d, "/") && strcmp(d, ".") ;) {
39+ if (rmdir(d) < 0) {
40+ weprintf("rmdir %s:", d);
41+ ret = 1;
42+ break;
43+ }
44+ d = dirname(d);
45+ }
46+ }
47+ }
48+
49+ return ret;
50+}
+1738,
-0
1@@ -0,0 +1,1738 @@
2+/* FIXME: summary
3+ * decide whether we enforce valid UTF-8, right now it's enforced in certain
4+ * parts of the script, but not the input...
5+ * nul bytes cause explosions due to use of libc string functions. thoughts?
6+ * lack of newline at end of file, currently we add one. what should we do?
7+ * allow "\\t" for "\t" etc. in regex? in replacement text?
8+ * POSIX says don't flush on N when out of input, but GNU and busybox do.
9+ */
10+
11+#include <ctype.h>
12+#include <errno.h>
13+#include <regex.h>
14+#include <stdlib.h>
15+#include <string.h>
16+
17+#include "utf.h"
18+#include "util.h"
19+
20+/* Types */
21+
22+/* used as queue for writes and stack for {,:,b,t */
23+typedef struct {
24+ void **data;
25+ size_t size;
26+ size_t cap;
27+} Vec;
28+
29+/* used for arbitrary growth, str is a C string
30+ * FIXME: does it make sense to keep track of length? or just rely on libc
31+ * string functions? If we want to support nul bytes everything changes
32+ */
33+typedef struct {
34+ char *str;
35+ size_t cap;
36+} String;
37+
38+typedef struct Cmd Cmd;
39+typedef struct {
40+ void (*fn)(Cmd *);
41+ char *(*getarg)(Cmd *, char *);
42+ void (*freearg)(Cmd *);
43+ unsigned char naddr;
44+} Fninfo;
45+
46+typedef struct {
47+ union {
48+ size_t lineno;
49+ regex_t *re;
50+ } u;
51+ enum {
52+ IGNORE, /* empty address, ignore */
53+ EVERY , /* every line */
54+ LINE , /* line number */
55+ LAST , /* last line ($) */
56+ REGEX , /* use included regex */
57+ LASTRE, /* use most recently used regex */
58+ } type;
59+} Addr;
60+
61+/* DISCUSS: naddr is not strictly necessary, but very helpful
62+ * naddr == 0 iff beg.type == EVERY && end.type == IGNORE
63+ * naddr == 1 iff beg.type != IGNORE && end.type == IGNORE
64+ * naddr == 2 iff beg.type != IGNORE && end.type != IGNORE
65+ */
66+typedef struct {
67+ Addr beg;
68+ Addr end;
69+ unsigned char naddr;
70+} Range;
71+
72+typedef struct {
73+ regex_t *re; /* if NULL use last regex */
74+ String repl;
75+ FILE *file;
76+ size_t occurrence; /* 0 for all (g flag) */
77+ Rune delim;
78+ unsigned int p:1;
79+} Sarg;
80+
81+typedef struct {
82+ Rune *set1;
83+ Rune *set2;
84+} Yarg;
85+
86+typedef struct {
87+ String str; /* a,c,i text. r file path */
88+ void (*print)(char *, FILE *); /* check_puts for a, write_file for r, unused for c,i */
89+} ACIRarg;
90+
91+struct Cmd {
92+ Range range;
93+ Fninfo *fninfo;
94+ union {
95+ Cmd *jump; /* used for b,t when running */
96+ char *label; /* used for :,b,t when building */
97+ ptrdiff_t offset; /* used for { (pointers break during realloc) */
98+ FILE *file; /* used for w */
99+
100+ /* FIXME: Should the following be in the union? or pointers and malloc? */
101+ Sarg s;
102+ Yarg y;
103+ ACIRarg acir;
104+ } u; /* I find your lack of anonymous unions disturbing */
105+ unsigned int in_match:1;
106+ unsigned int negate :1;
107+};
108+
109+/* Files for w command (and s' w flag) */
110+typedef struct {
111+ char *path;
112+ FILE *file;
113+} Wfile;
114+
115+/*
116+ * Function Declarations
117+ */
118+
119+/* Dynamically allocated arrays and strings */
120+static void resize(void **ptr, size_t *nmemb, size_t size, size_t new_nmemb, void **next);
121+static void *pop(Vec *v);
122+static void push(Vec *v, void *p);
123+static void stracat(String *dst, char *src);
124+static void strnacat(String *dst, char *src, size_t n);
125+static void stracpy(String *dst, char *src);
126+
127+/* Cleanup and errors */
128+static void usage(void);
129+
130+/* Parsing functions and related utilities */
131+static void compile(char *s, int isfile);
132+static int read_line(FILE *f, String *s);
133+static char *make_range(Range *range, char *s);
134+static char *make_addr(Addr *addr, char *s);
135+static char *find_delim(char *s, Rune delim, int do_brackets);
136+static char *chompr(char *s, Rune rune);
137+static char *chomp(char *s);
138+static Rune *strtorunes(char *s, size_t nrunes);
139+static long stol(char *s, char **endp);
140+static size_t escapes(char *beg, char *end, Rune delim, int n_newline);
141+static size_t echarntorune(Rune *r, char *s, size_t n);
142+static void insert_labels(void);
143+
144+/* Get and Free arg and related utilities */
145+static char *get_aci_arg(Cmd *c, char *s);
146+static void aci_append(Cmd *c, char *s);
147+static void free_acir_arg(Cmd *c);
148+static char *get_bt_arg(Cmd *c, char *s);
149+static char *get_r_arg(Cmd *c, char *s);
150+static char *get_s_arg(Cmd *c, char *s);
151+static void free_s_arg(Cmd *c);
152+static char *get_w_arg(Cmd *c, char *s);
153+static char *get_y_arg(Cmd *c, char *s);
154+static void free_y_arg(Cmd *c);
155+static char *get_colon_arg(Cmd *c, char *s);
156+static char *get_lbrace_arg(Cmd *c, char *s);
157+static char *get_rbrace_arg(Cmd *c, char *s);
158+static char *semicolon_arg(char *s);
159+
160+/* Running */
161+static void run(void);
162+static int in_range(Cmd *c);
163+static int match_addr(Addr *a);
164+static int next_file(void);
165+static int is_eof(FILE *f);
166+static void do_writes(void);
167+static void write_file(char *path, FILE *out);
168+static void check_puts(char *s, FILE *f);
169+static void update_ranges(Cmd *beg, Cmd *end);
170+
171+/* Sed functions */
172+static void cmd_y(Cmd *c);
173+static void cmd_x(Cmd *c);
174+static void cmd_w(Cmd *c);
175+static void cmd_t(Cmd *c);
176+static void cmd_s(Cmd *c);
177+static void cmd_r(Cmd *c);
178+static void cmd_q(Cmd *c);
179+static void cmd_P(Cmd *c);
180+static void cmd_p(Cmd *c);
181+static void cmd_N(Cmd *c);
182+static void cmd_n(Cmd *c);
183+static void cmd_l(Cmd *c);
184+static void cmd_i(Cmd *c);
185+static void cmd_H(Cmd *c);
186+static void cmd_h(Cmd *c);
187+static void cmd_G(Cmd *c);
188+static void cmd_g(Cmd *c);
189+static void cmd_D(Cmd *c);
190+static void cmd_d(Cmd *c);
191+static void cmd_c(Cmd *c);
192+static void cmd_b(Cmd *c);
193+static void cmd_a(Cmd *c);
194+static void cmd_colon(Cmd *c);
195+static void cmd_equal(Cmd *c);
196+static void cmd_lbrace(Cmd *c);
197+static void cmd_rbrace(Cmd *c);
198+static void cmd_last(Cmd *c);
199+
200+/* Actions */
201+static void new_line(void);
202+static void app_line(void);
203+static void new_next(void);
204+static void old_next(void);
205+
206+/*
207+ * Globals
208+ */
209+static Vec braces, labels, branches; /* holds ptrdiff_t. addrs of {, :, bt */
210+static Vec writes; /* holds cmd*. writes scheduled by a and r commands */
211+static Vec wfiles; /* holds Wfile*. files for w and s///w commands */
212+
213+static Cmd *prog, *pc; /* Program, program counter */
214+static size_t pcap;
215+static size_t lineno;
216+
217+static regex_t *lastre; /* last used regex for empty regex search */
218+static char **files; /* list of file names from argv */
219+static FILE *file; /* current file we are reading */
220+static int ret; /* exit status */
221+
222+static String patt, hold, genbuf;
223+
224+static struct {
225+ unsigned int n :1; /* -n (no print) */
226+ unsigned int E :1; /* -E (extended re) */
227+ unsigned int s :1; /* s/// replacement happened */
228+ unsigned int aci_cont:1; /* a,c,i text continuation */
229+ unsigned int s_cont :1; /* s/// replacement text continuation */
230+ unsigned int halt :1; /* halt execution */
231+} gflags;
232+
233+/* FIXME: move character inside Fninfo and only use 26*sizeof(Fninfo) instead of 127*sizeof(Fninfo) bytes */
234+static Fninfo fns[] = {
235+ ['a'] = { cmd_a , get_aci_arg , free_acir_arg , 1 }, /* schedule write of text for later */
236+ ['b'] = { cmd_b , get_bt_arg , NULL , 2 }, /* branch to label char *label when building, Cmd *jump when running */
237+ ['c'] = { cmd_c , get_aci_arg , free_acir_arg , 2 }, /* delete pattern space. at 0 or 1 addr or end of 2 addr, write text */
238+ ['d'] = { cmd_d , NULL , NULL , 2 }, /* delete pattern space */
239+ ['D'] = { cmd_D , NULL , NULL , 2 }, /* delete to first newline and start new cycle without reading (if no newline, d) */
240+ ['g'] = { cmd_g , NULL , NULL , 2 }, /* replace pattern space with hold space */
241+ ['G'] = { cmd_G , NULL , NULL , 2 }, /* append newline and hold space to pattern space */
242+ ['h'] = { cmd_h , NULL , NULL , 2 }, /* replace hold space with pattern space */
243+ ['H'] = { cmd_H , NULL , NULL , 2 }, /* append newline and pattern space to hold space */
244+ ['i'] = { cmd_i , get_aci_arg , free_acir_arg , 1 }, /* write text */
245+ ['l'] = { cmd_l , NULL , NULL , 2 }, /* write pattern space in 'visually unambiguous form' */
246+ ['n'] = { cmd_n , NULL , NULL , 2 }, /* write pattern space (unless -n) read to replace pattern space (if no input, quit) */
247+ ['N'] = { cmd_N , NULL , NULL , 2 }, /* append to pattern space separated by newline, line number changes (if no input, quit) */
248+ ['p'] = { cmd_p , NULL , NULL , 2 }, /* write pattern space */
249+ ['P'] = { cmd_P , NULL , NULL , 2 }, /* write pattern space up to first newline */
250+ ['q'] = { cmd_q , NULL , NULL , 1 }, /* quit */
251+ ['r'] = { cmd_r , get_r_arg , free_acir_arg , 1 }, /* write contents of file (unable to open/read treated as empty file) */
252+ ['s'] = { cmd_s , get_s_arg , free_s_arg , 2 }, /* find/replace/all that crazy s stuff */
253+ ['t'] = { cmd_t , get_bt_arg , NULL , 2 }, /* if s/// succeeded (since input or last t) branch to label (branch to end if no label) */
254+ ['w'] = { cmd_w , get_w_arg , NULL , 2 }, /* append pattern space to file */
255+ ['x'] = { cmd_x , NULL , NULL , 2 }, /* exchange pattern and hold spaces */
256+ ['y'] = { cmd_y , get_y_arg , free_y_arg , 2 }, /* replace runes in set1 with runes in set2 */
257+ [':'] = { cmd_colon , get_colon_arg , NULL , 0 }, /* defines label for later b and t commands */
258+ ['='] = { cmd_equal , NULL , NULL , 1 }, /* printf("%d\n", line_number); */
259+ ['{'] = { cmd_lbrace, get_lbrace_arg, NULL , 2 }, /* if we match, run commands, otherwise jump to close */
260+ ['}'] = { cmd_rbrace, get_rbrace_arg, NULL , 0 }, /* noop, hold onto open for ease of building scripts */
261+
262+ [0x7f] = { NULL, NULL, NULL, 0 }, /* index is checked with isascii(3p). fill out rest of array */
263+};
264+
265+/*
266+ * Function Definitions
267+ */
268+
269+/* given memory pointed to by *ptr that currently holds *nmemb members of size
270+ * size, realloc to hold new_nmemb members, return new_nmemb in *memb and one
271+ * past old end in *next. if realloc fails...explode
272+ */
273+static void
274+resize(void **ptr, size_t *nmemb, size_t size, size_t new_nmemb, void **next)
275+{
276+ void *n, *tmp;
277+
278+ if (new_nmemb) {
279+ tmp = ereallocarray(*ptr, new_nmemb, size);
280+ } else { /* turns out realloc(*ptr, 0) != free(*ptr) */
281+ free(*ptr);
282+ tmp = NULL;
283+ }
284+ n = (char *)tmp + *nmemb * size;
285+ *nmemb = new_nmemb;
286+ *ptr = tmp;
287+ if (next)
288+ *next = n;
289+}
290+
291+static void *
292+pop(Vec *v)
293+{
294+ if (!v->size)
295+ return NULL;
296+ return v->data[--v->size];
297+}
298+
299+static void
300+push(Vec *v, void *p)
301+{
302+ if (v->size == v->cap)
303+ resize((void **)&v->data, &v->cap, sizeof(*v->data), v->cap * 2 + 1, NULL);
304+ v->data[v->size++] = p;
305+}
306+
307+static void
308+stracat(String *dst, char *src)
309+{
310+ int new = !dst->cap;
311+ size_t len;
312+
313+ len = (new ? 0 : strlen(dst->str)) + strlen(src) + 1;
314+ if (dst->cap < len)
315+ resize((void **)&dst->str, &dst->cap, 1, len * 2, NULL);
316+ if (new)
317+ *dst->str = '\0';
318+ strcat(dst->str, src);
319+}
320+
321+static void
322+strnacat(String *dst, char *src, size_t n)
323+{
324+ int new = !dst->cap;
325+ size_t len;
326+
327+ len = strlen(src);
328+ len = (new ? 0 : strlen(dst->str)) + MIN(n, len) + 1;
329+ if (dst->cap < len)
330+ resize((void **)&dst->str, &dst->cap, 1, len * 2, NULL);
331+ if (new)
332+ *dst->str = '\0';
333+ strlcat(dst->str, src, len);
334+}
335+
336+static void
337+stracpy(String *dst, char *src)
338+{
339+ size_t len;
340+
341+ len = strlen(src) + 1;
342+ if (dst->cap < len)
343+ resize((void **)&dst->str, &dst->cap, 1, len * 2, NULL);
344+ strcpy(dst->str, src);
345+}
346+
347+static void
348+leprintf(char *s)
349+{
350+ if (errno)
351+ eprintf("%zu: %s: %s\n", lineno, s, strerror(errno));
352+ else
353+ eprintf("%zu: %s\n", lineno, s);
354+}
355+
356+/* FIXME: write usage message */
357+static void
358+usage(void)
359+{
360+ eprintf("usage: sed [-nrE] script [file ...]\n"
361+ " sed [-nrE] -e script [-e script] ... [-f scriptfile] ... [file ...]\n"
362+ " sed [-nrE] [-e script] ... -f scriptfile [-f scriptfile] ... [file ...]\n");
363+}
364+
365+/* Differences from POSIX
366+ * we allows semicolons and trailing blanks inside {}
367+ * we allow spaces after ! (and in between !s)
368+ * we allow extended regular expressions (-E)
369+ */
370+static void
371+compile(char *s, int isfile)
372+{
373+ FILE *f;
374+
375+ if (isfile) {
376+ f = fopen(s, "r");
377+ if (!f)
378+ eprintf("fopen %s:", s);
379+ } else {
380+ if (!*s) /* empty string script */
381+ return;
382+ f = fmemopen(s, strlen(s), "r");
383+ if (!f)
384+ eprintf("fmemopen:");
385+ }
386+
387+ /* NOTE: get arg functions can't use genbuf */
388+ while (read_line(f, &genbuf) != EOF) {
389+ s = genbuf.str;
390+
391+ /* if the first two characters of the script are "#n" default output shall be suppressed */
392+ if (++lineno == 1 && *s == '#' && s[1] == 'n') {
393+ gflags.n = 1;
394+ continue;
395+ }
396+
397+ if (gflags.aci_cont) {
398+ aci_append(pc - 1, s);
399+ continue;
400+ }
401+ if (gflags.s_cont)
402+ s = (pc - 1)->fninfo->getarg(pc - 1, s);
403+
404+ while (*s) {
405+ s = chompr(s, ';');
406+ if (!*s || *s == '#')
407+ break;
408+
409+ if ((size_t)(pc - prog) == pcap)
410+ resize((void **)&prog, &pcap, sizeof(*prog), pcap * 2 + 1, (void **)&pc);
411+
412+ pc->range.beg.type = pc->range.end.type = IGNORE;
413+ pc->fninfo = NULL;
414+ pc->in_match = 0;
415+
416+ s = make_range(&pc->range, s);
417+ s = chomp(s);
418+ pc->negate = *s == '!';
419+ s = chompr(s, '!');
420+
421+ if (!isascii(*s) || !(pc->fninfo = &fns[(unsigned)*s])->fn)
422+ leprintf("bad sed function");
423+ if (pc->range.naddr > pc->fninfo->naddr)
424+ leprintf("wrong number of addresses");
425+ s++;
426+
427+ if (pc->fninfo->getarg)
428+ s = pc->fninfo->getarg(pc, s);
429+
430+ pc++;
431+ }
432+ }
433+
434+ fshut(f, s);
435+}
436+
437+/* FIXME: if we decide to honor lack of trailing newline, set/clear a global
438+ * flag when reading a line
439+ */
440+static int
441+read_line(FILE *f, String *s)
442+{
443+ ssize_t len;
444+
445+ if (!f)
446+ return EOF;
447+
448+ if ((len = getline(&s->str, &s->cap, f)) < 0) {
449+ if (ferror(f))
450+ eprintf("getline:");
451+ return EOF;
452+ }
453+ if (s->str[--len] == '\n')
454+ s->str[len] = '\0';
455+ return 0;
456+}
457+
458+/* read first range from s, return pointer to one past end of range */
459+static char *
460+make_range(Range *range, char *s)
461+{
462+ s = make_addr(&range->beg, s);
463+
464+ if (*s == ',')
465+ s = make_addr(&range->end, s + 1);
466+ else
467+ range->end.type = IGNORE;
468+
469+ if (range->beg.type == EVERY && range->end.type == IGNORE) range->naddr = 0;
470+ else if (range->beg.type != IGNORE && range->end.type == IGNORE) range->naddr = 1;
471+ else if (range->beg.type != IGNORE && range->end.type != IGNORE) range->naddr = 2;
472+ else leprintf("this is impossible...");
473+
474+ return s;
475+}
476+
477+/* read first addr from s, return pointer to one past end of addr */
478+static char *
479+make_addr(Addr *addr, char *s)
480+{
481+ Rune r;
482+ char *p = s + strlen(s);
483+ size_t rlen = echarntorune(&r, s, p - s);
484+
485+ if (r == '$') {
486+ addr->type = LAST;
487+ s += rlen;
488+ } else if (isdigitrune(r)) {
489+ addr->type = LINE;
490+ addr->u.lineno = stol(s, &s);
491+ } else if (r == '/' || r == '\\') {
492+ Rune delim;
493+ if (r == '\\') {
494+ s += rlen;
495+ rlen = echarntorune(&r, s, p - s);
496+ }
497+ if (r == '\\')
498+ leprintf("bad delimiter '\\'");
499+ delim = r;
500+ s += rlen;
501+ rlen = echarntorune(&r, s, p - s);
502+ if (r == delim) {
503+ addr->type = LASTRE;
504+ s += rlen;
505+ } else {
506+ addr->type = REGEX;
507+ p = find_delim(s, delim, 1);
508+ if (!*p)
509+ leprintf("unclosed regex");
510+ p -= escapes(s, p, delim, 0);
511+ *p++ = '\0';
512+ addr->u.re = emalloc(sizeof(*addr->u.re));
513+ eregcomp(addr->u.re, s, gflags.E ? REG_EXTENDED : 0);
514+ s = p;
515+ }
516+ } else {
517+ addr->type = EVERY;
518+ }
519+
520+ return s;
521+}
522+
523+/* return pointer to first delim in s that is not escaped
524+ * and if do_brackets is set, not in [] (note possible [::], [..], [==], inside [])
525+ * return pointer to trailing nul byte if no delim found
526+ *
527+ * any escaped character that is not special is just itself (POSIX undefined)
528+ * FIXME: pull out into some util thing, will be useful for ed as well
529+ */
530+static char *
531+find_delim(char *s, Rune delim, int do_brackets)
532+{
533+ enum {
534+ OUTSIDE , /* not in brackets */
535+ BRACKETS_OPENING, /* last char was first [ or last two were first [^ */
536+ BRACKETS_INSIDE , /* inside [] */
537+ INSIDE_OPENING , /* inside [] and last char was [ */
538+ CLASS_INSIDE , /* inside class [::], or colating element [..] or [==], inside [] */
539+ CLASS_CLOSING , /* inside class [::], or colating element [..] or [==], and last character was the respective : . or = */
540+ } state = OUTSIDE;
541+
542+ Rune r, c = 0; /* no c won't be used uninitialized, shutup -Wall */
543+ size_t rlen;
544+ int escape = 0;
545+ char *end = s + strlen(s);
546+
547+ for (; *s; s += rlen) {
548+ rlen = echarntorune(&r, s, end - s);
549+
550+ if (state == BRACKETS_OPENING && r == '^' ) { continue; }
551+ else if (state == BRACKETS_OPENING && r == ']' ) { state = BRACKETS_INSIDE ; continue; }
552+ else if (state == BRACKETS_OPENING ) { state = BRACKETS_INSIDE ; }
553+
554+ if (state == CLASS_CLOSING && r == ']' ) { state = BRACKETS_INSIDE ; }
555+ else if (state == CLASS_CLOSING ) { state = CLASS_INSIDE ; }
556+ else if (state == CLASS_INSIDE && r == c ) { state = CLASS_CLOSING ; }
557+ else if (state == INSIDE_OPENING && (r == ':' ||
558+ r == '.' ||
559+ r == '=') ) { state = CLASS_INSIDE ; c = r; }
560+ else if (state == INSIDE_OPENING && r == ']' ) { state = OUTSIDE ; }
561+ else if (state == INSIDE_OPENING ) { state = BRACKETS_INSIDE ; }
562+ else if (state == BRACKETS_INSIDE && r == '[' ) { state = INSIDE_OPENING ; }
563+ else if (state == BRACKETS_INSIDE && r == ']' ) { state = OUTSIDE ; }
564+ else if (state == OUTSIDE && escape ) { escape = 0 ; }
565+ else if (state == OUTSIDE && r == '\\' ) { escape = 1 ; }
566+ else if (state == OUTSIDE && r == delim) return s;
567+ else if (state == OUTSIDE && do_brackets && r == '[' ) { state = BRACKETS_OPENING; }
568+ }
569+ return s;
570+}
571+
572+static char *
573+chomp(char *s)
574+{
575+ return chompr(s, 0);
576+}
577+
578+/* eat all leading whitespace and occurrences of rune */
579+static char *
580+chompr(char *s, Rune rune)
581+{
582+ Rune r;
583+ size_t rlen;
584+ char *end = s + strlen(s);
585+
586+ while (*s && (rlen = echarntorune(&r, s, end - s)) && (isspacerune(r) || r == rune))
587+ s += rlen;
588+ return s;
589+}
590+
591+/* convert first nrunes Runes from UTF-8 string s in allocated Rune*
592+ * NOTE: sequence must be valid UTF-8, check first */
593+static Rune *
594+strtorunes(char *s, size_t nrunes)
595+{
596+ Rune *rs, *rp;
597+
598+ rp = rs = ereallocarray(NULL, nrunes + 1, sizeof(*rs));
599+
600+ while (nrunes--)
601+ s += chartorune(rp++, s);
602+
603+ *rp = '\0';
604+ return rs;
605+}
606+
607+static long
608+stol(char *s, char **endp)
609+{
610+ long n;
611+ errno = 0;
612+ n = strtol(s, endp, 10);
613+
614+ if (errno)
615+ leprintf("strtol:");
616+ if (*endp == s)
617+ leprintf("strtol: invalid number");
618+
619+ return n;
620+}
621+
622+/* from beg to end replace "\\d" with "d" and "\\n" with "\n" (where d is delim)
623+ * if delim is 'n' and n_newline is 0 then "\\n" is replaced with "n" (normal)
624+ * if delim is 'n' and n_newline is 1 then "\\n" is replaced with "\n" (y command)
625+ * if delim is 0 all escaped characters represent themselves (aci text)
626+ * memmove rest of string (beyond end) into place
627+ * return the number of converted escapes (backslashes removed)
628+ * FIXME: this has had too many corner cases slapped on and is ugly. rewrite better
629+ */
630+static size_t
631+escapes(char *beg, char *end, Rune delim, int n_newline)
632+{
633+ size_t num = 0;
634+ char *src = beg, *dst = beg;
635+
636+ while (src < end) {
637+ /* handle escaped backslash specially so we don't think the second
638+ * backslash is escaping something */
639+ if (*src == '\\' && src[1] == '\\') {
640+ *dst++ = *src++;
641+ if (delim)
642+ *dst++ = *src++;
643+ else
644+ src++;
645+ } else if (*src == '\\' && !delim) {
646+ src++;
647+ } else if (*src == '\\' && src[1]) {
648+ Rune r;
649+ size_t rlen;
650+ num++;
651+ src++;
652+ rlen = echarntorune(&r, src, end - src);
653+
654+ if (r == 'n' && delim == 'n') {
655+ *src = n_newline ? '\n' : 'n'; /* src so we can still memmove() */
656+ } else if (r == 'n') {
657+ *src = '\n';
658+ } else if (r != delim) {
659+ *dst++ = '\\';
660+ num--;
661+ }
662+
663+ memmove(dst, src, rlen);
664+ dst += rlen;
665+ src += rlen;
666+ } else {
667+ *dst++ = *src++;
668+ }
669+ }
670+ memmove(dst, src, strlen(src) + 1);
671+ return num;
672+}
673+
674+static size_t
675+echarntorune(Rune *r, char *s, size_t n)
676+{
677+ size_t rlen = charntorune(r, s, n);
678+ if (!rlen || *r == Runeerror)
679+ leprintf("invalid UTF-8");
680+ return rlen;
681+}
682+
683+static void
684+insert_labels(void)
685+{
686+ size_t i;
687+ Cmd *from, *to;
688+
689+ while (branches.size) {
690+ from = prog + (ptrdiff_t)pop(&branches);
691+
692+ if (!from->u.label) {/* no label branch to end of script */
693+ from->u.jump = pc - 1;
694+ } else {
695+ for (i = 0; i < labels.size; i++) {
696+ to = prog + (ptrdiff_t)labels.data[i];
697+ if (!strcmp(from->u.label, to->u.label)) {
698+ from->u.jump = to;
699+ break;
700+ }
701+ }
702+ if (i == labels.size)
703+ leprintf("bad label");
704+ }
705+ }
706+}
707+
708+/*
709+ * Getargs / Freeargs
710+ * Read argument from s, return pointer to one past last character of argument
711+ */
712+
713+/* POSIX compliant
714+ * i\
715+ * foobar
716+ *
717+ * also allow the following non POSIX compliant
718+ * i # empty line
719+ * ifoobar
720+ * ifoobar\
721+ * baz
722+ *
723+ * FIXME: GNU and busybox discard leading spaces
724+ * i foobar
725+ * i foobar
726+ * ifoobar
727+ * are equivalent in GNU and busybox. We don't. Should we?
728+ */
729+static char *
730+get_aci_arg(Cmd *c, char *s)
731+{
732+ c->u.acir.print = check_puts;
733+ c->u.acir.str = (String){ NULL, 0 };
734+
735+ gflags.aci_cont = !!*s; /* no continue flag if empty string */
736+
737+ /* neither empty string nor POSIX compliant */
738+ if (*s && !(*s == '\\' && !s[1]))
739+ aci_append(c, s);
740+
741+ return s + strlen(s);
742+}
743+
744+static void
745+aci_append(Cmd *c, char *s)
746+{
747+ char *end = s + strlen(s), *p = end;
748+
749+ gflags.aci_cont = 0;
750+ while (--p >= s && *p == '\\')
751+ gflags.aci_cont = !gflags.aci_cont;
752+
753+ if (gflags.aci_cont)
754+ *--end = '\n';
755+
756+ escapes(s, end, 0, 0);
757+ stracat(&c->u.acir.str, s);
758+}
759+
760+static void
761+free_acir_arg(Cmd *c)
762+{
763+ free(c->u.acir.str.str);
764+}
765+
766+/* POSIX dictates that label is rest of line, including semicolons, trailing
767+ * whitespace, closing braces, etc. and can be limited to 8 bytes
768+ *
769+ * I allow a semicolon or closing brace to terminate a label name, it's not
770+ * POSIX compliant, but it's useful and every sed version I've tried to date
771+ * does the same.
772+ *
773+ * FIXME: POSIX dictates that leading whitespace is ignored but trailing
774+ * whitespace is not. This is annoying and we should probably get rid of it.
775+ */
776+static char *
777+get_bt_arg(Cmd *c, char *s)
778+{
779+ char *p = semicolon_arg(s = chomp(s));
780+
781+ if (p != s) {
782+ c->u.label = estrndup(s, p - s);
783+ } else {
784+ c->u.label = NULL;
785+ }
786+
787+ push(&branches, (void *)(c - prog));
788+
789+ return p;
790+}
791+
792+/* POSIX dictates file name is rest of line including semicolons, trailing
793+ * whitespace, closing braces, etc. and file name must be preceded by a space
794+ *
795+ * I allow a semicolon or closing brace to terminate a file name and don't
796+ * enforce leading space.
797+ *
798+ * FIXME: decide whether trailing whitespace should be included and fix
799+ * accordingly
800+ */
801+static char *
802+get_r_arg(Cmd *c, char *s)
803+{
804+ char *p = semicolon_arg(s = chomp(s));
805+
806+ if (p == s)
807+ leprintf("no file name");
808+
809+ c->u.acir.str.str = estrndup(s, p - s);
810+ c->u.acir.print = write_file;
811+
812+ return p;
813+}
814+
815+/* we allow "\\n" in replacement text to mean "\n" (undefined in POSIX)
816+ *
817+ * FIXME: allow other escapes in regex and replacement? if so change escapes()
818+ */
819+static char *
820+get_s_arg(Cmd *c, char *s)
821+{
822+ Rune delim, r;
823+ Cmd buf;
824+ char *p;
825+ int esc, lastre;
826+
827+ /* s/Find/Replace/Flags */
828+
829+ /* Find */
830+ if (!gflags.s_cont) { /* NOT continuing from literal newline in replacement text */
831+ lastre = 0;
832+ c->u.s.repl = (String){ NULL, 0 };
833+ c->u.s.occurrence = 1;
834+ c->u.s.file = NULL;
835+ c->u.s.p = 0;
836+
837+ if (!*s || *s == '\\')
838+ leprintf("bad delimiter");
839+
840+ p = s + strlen(s);
841+ s += echarntorune(&delim, s, p - s);
842+ c->u.s.delim = delim;
843+
844+ echarntorune(&r, s, p - s);
845+ if (r == delim) /* empty regex */
846+ lastre = 1;
847+
848+ p = find_delim(s, delim, 1);
849+ if (!*p)
850+ leprintf("missing second delimiter");
851+ p -= escapes(s, p, delim, 0);
852+ *p = '\0';
853+
854+ if (lastre) {
855+ c->u.s.re = NULL;
856+ } else {
857+ c->u.s.re = emalloc(sizeof(*c->u.s.re));
858+ /* FIXME: different eregcomp that calls fatal */
859+ eregcomp(c->u.s.re, s, gflags.E ? REG_EXTENDED : 0);
860+ }
861+ s = p + runelen(delim);
862+ }
863+
864+ /* Replace */
865+ delim = c->u.s.delim;
866+
867+ p = find_delim(s, delim, 0);
868+ p -= escapes(s, p, delim, 0);
869+ if (!*p) { /* no third delimiter */
870+ /* FIXME: same backslash counting as aci_append() */
871+ if (p[-1] != '\\')
872+ leprintf("missing third delimiter or <backslash><newline>");
873+ p[-1] = '\n';
874+ gflags.s_cont = 1;
875+ } else {
876+ gflags.s_cont = 0;
877+ }
878+
879+ /* check for bad references in replacement text */
880+ *p = '\0';
881+ for (esc = 0, p = s; *p; p++) {
882+ if (esc) {
883+ esc = 0;
884+ if (isdigit(*p) && c->u.s.re && (size_t)(*p - '0') > c->u.s.re->re_nsub)
885+ leprintf("back reference number greater than number of groups");
886+ } else if (*p == '\\') {
887+ esc = 1;
888+ }
889+ }
890+ stracat(&c->u.s.repl, s);
891+
892+ if (gflags.s_cont)
893+ return p;
894+
895+ s = p + runelen(delim);
896+
897+ /* Flags */
898+ p = semicolon_arg(s = chomp(s));
899+
900+ /* FIXME: currently for simplicity take last of g or occurrence flags and
901+ * ignore multiple p flags. need to fix that */
902+ for (; s < p; s++) {
903+ if (isdigit(*s)) {
904+ c->u.s.occurrence = stol(s, &s);
905+ s--; /* for loop will advance pointer */
906+ } else {
907+ switch (*s) {
908+ case 'g': c->u.s.occurrence = 0; break;
909+ case 'p': c->u.s.p = 1; break;
910+ case 'w':
911+ /* must be last flag, take everything up to newline/semicolon
912+ * s == p after this */
913+ s = get_w_arg(&buf, chomp(s+1));
914+ c->u.s.file = buf.u.file;
915+ break;
916+ }
917+ }
918+ }
919+ return p;
920+}
921+
922+static void
923+free_s_arg(Cmd *c)
924+{
925+ if (c->u.s.re)
926+ regfree(c->u.s.re);
927+ free(c->u.s.re);
928+ free(c->u.s.repl.str);
929+}
930+
931+/* see get_r_arg notes */
932+static char *
933+get_w_arg(Cmd *c, char *s)
934+{
935+ char *p = semicolon_arg(s = chomp(s));
936+ Wfile *w, **wp;
937+
938+ if (p == s)
939+ leprintf("no file name");
940+
941+ for (wp = (Wfile **)wfiles.data; (size_t)(wp - (Wfile **)wfiles.data) < wfiles.size; wp++) {
942+ if (strlen((*wp)->path) == (size_t)(p - s) && !strncmp(s, (*wp)->path, p - s)) {
943+ c->u.file = (*wp)->file;
944+ return p;
945+ }
946+ }
947+
948+ w = emalloc(sizeof(*w));
949+ w->path = estrndup(s, p - s);
950+
951+ if (!(w->file = fopen(w->path, "w")))
952+ leprintf("fopen failed");
953+
954+ c->u.file = w->file;
955+
956+ push(&wfiles, w);
957+ return p;
958+}
959+
960+static char *
961+get_y_arg(Cmd *c, char *s)
962+{
963+ Rune delim;
964+ char *p = s + strlen(s);
965+ size_t rlen = echarntorune(&delim, s, p - s);
966+ size_t nrunes1, nrunes2;
967+
968+ c->u.y.set1 = c->u.y.set2 = NULL;
969+
970+ s += rlen;
971+ p = find_delim(s, delim, 0);
972+ p -= escapes(s, p, delim, 1);
973+ nrunes1 = utfnlen(s, p - s);
974+ c->u.y.set1 = strtorunes(s, nrunes1);
975+
976+ s = p + rlen;
977+ p = find_delim(s, delim, 0);
978+ p -= escapes(s, p, delim, 1);
979+ nrunes2 = utfnlen(s, p - s);
980+
981+ if (nrunes1 != nrunes2)
982+ leprintf("different set lengths");
983+
984+ c->u.y.set2 = strtorunes(s, utfnlen(s, p - s));
985+
986+ return p + rlen;
987+}
988+
989+static void
990+free_y_arg(Cmd *c)
991+{
992+ free(c->u.y.set1);
993+ free(c->u.y.set2);
994+}
995+
996+/* see get_bt_arg notes */
997+static char *
998+get_colon_arg(Cmd *c, char *s)
999+{
1000+ char *p = semicolon_arg(s = chomp(s));
1001+
1002+ if (p == s)
1003+ leprintf("no label name");
1004+
1005+ c->u.label = estrndup(s, p - s);
1006+ push(&labels, (void *)(c - prog));
1007+ return p;
1008+}
1009+
1010+static char *
1011+get_lbrace_arg(Cmd *c, char *s)
1012+{
1013+ push(&braces, (void *)(c - prog));
1014+ return s;
1015+}
1016+
1017+static char *
1018+get_rbrace_arg(Cmd *c, char *s)
1019+{
1020+ Cmd *lbrace;
1021+
1022+ if (!braces.size)
1023+ leprintf("extra }");
1024+
1025+ lbrace = prog + (ptrdiff_t)pop(&braces);
1026+ lbrace->u.offset = c - prog;
1027+ return s;
1028+}
1029+
1030+/* s points to beginning of an argument that may be semicolon terminated
1031+ * return pointer to semicolon or nul byte after string
1032+ * or closing brace as to not force ; before }
1033+ * FIXME: decide whether or not to eat trailing whitespace for arguments that
1034+ * we allow semicolon/brace termination that POSIX doesn't
1035+ * b, r, t, w, :
1036+ * POSIX says trailing whitespace is part of label name, file name, etc.
1037+ * we should probably eat it
1038+ */
1039+static char *
1040+semicolon_arg(char *s)
1041+{
1042+ char *p = strpbrk(s, ";}");
1043+ if (!p)
1044+ p = s + strlen(s);
1045+ return p;
1046+}
1047+
1048+static void
1049+run(void)
1050+{
1051+ lineno = 0;
1052+ if (braces.size)
1053+ leprintf("extra {");
1054+
1055+ /* genbuf has already been initialized, patt will be in new_line
1056+ * (or we'll halt) */
1057+ stracpy(&hold, "");
1058+
1059+ insert_labels();
1060+ next_file();
1061+ new_line();
1062+
1063+ for (pc = prog; !gflags.halt; pc++)
1064+ pc->fninfo->fn(pc);
1065+}
1066+
1067+/* return true if we are in range for c, set c->in_match appropriately */
1068+static int
1069+in_range(Cmd *c)
1070+{
1071+ if (match_addr(&c->range.beg)) {
1072+ if (c->range.naddr == 2) {
1073+ if (c->range.end.type == LINE && c->range.end.u.lineno <= lineno)
1074+ c->in_match = 0;
1075+ else
1076+ c->in_match = 1;
1077+ }
1078+ return !c->negate;
1079+ }
1080+ if (c->in_match && match_addr(&c->range.end)) {
1081+ c->in_match = 0;
1082+ return !c->negate;
1083+ }
1084+ return c->in_match ^ c->negate;
1085+}
1086+
1087+/* return true if addr matches current line */
1088+static int
1089+match_addr(Addr *a)
1090+{
1091+ switch (a->type) {
1092+ default:
1093+ case IGNORE: return 0;
1094+ case EVERY: return 1;
1095+ case LINE: return lineno == a->u.lineno;
1096+ case LAST:
1097+ while (is_eof(file) && !next_file())
1098+ ;
1099+ return !file;
1100+ case REGEX:
1101+ lastre = a->u.re;
1102+ return !regexec(a->u.re, patt.str, 0, NULL, 0);
1103+ case LASTRE:
1104+ if (!lastre)
1105+ leprintf("no previous regex");
1106+ return !regexec(lastre, patt.str, 0, NULL, 0);
1107+ }
1108+}
1109+
1110+/* move to next input file
1111+ * stdin if first call and no files
1112+ * return 0 for success and 1 for no more files
1113+ */
1114+static int
1115+next_file(void)
1116+{
1117+ static unsigned char first = 1;
1118+
1119+ if (file == stdin)
1120+ clearerr(file);
1121+ else if (file)
1122+ fshut(file, "<file>");
1123+ /* given no files, default to stdin */
1124+ file = first && !*files ? stdin : NULL;
1125+ first = 0;
1126+
1127+ while (!file && *files) {
1128+ if (!strcmp(*files, "-")) {
1129+ file = stdin;
1130+ } else if (!(file = fopen(*files, "r"))) {
1131+ /* warn this file didn't open, but move on to next */
1132+ weprintf("fopen %s:", *files);
1133+ ret = 1;
1134+ }
1135+ files++;
1136+ }
1137+
1138+ return !file;
1139+}
1140+
1141+/* test if stream is at EOF */
1142+static int
1143+is_eof(FILE *f)
1144+{
1145+ int c;
1146+
1147+ if (!f || feof(f))
1148+ return 1;
1149+
1150+ c = fgetc(f);
1151+ if (c == EOF && ferror(f))
1152+ eprintf("fgetc:");
1153+ if (c != EOF && ungetc(c, f) == EOF)
1154+ eprintf("ungetc EOF\n");
1155+
1156+ return c == EOF;
1157+}
1158+
1159+/* perform writes that were scheduled
1160+ * for aci this is check_puts(string, stdout)
1161+ * for r this is write_file(path, stdout)
1162+ */
1163+static void
1164+do_writes(void)
1165+{
1166+ Cmd *c;
1167+ size_t i;
1168+
1169+ for (i = 0; i < writes.size; i++) {
1170+ c = writes.data[i];
1171+ c->u.acir.print(c->u.acir.str.str, stdout);
1172+ }
1173+ writes.size = 0;
1174+}
1175+
1176+/* used for r's u.acir.print()
1177+ * FIXME: something like util's concat() would be better
1178+ */
1179+static void
1180+write_file(char *path, FILE *out)
1181+{
1182+ FILE *in = fopen(path, "r");
1183+ if (!in) /* no file is treated as empty file */
1184+ return;
1185+
1186+ while (read_line(in, &genbuf) != EOF)
1187+ check_puts(genbuf.str, out);
1188+
1189+ fshut(in, path);
1190+}
1191+
1192+static void
1193+check_puts(char *s, FILE *f)
1194+{
1195+ if (s && fputs(s, f) == EOF)
1196+ eprintf("fputs:");
1197+ if (fputs("\n", f) == EOF)
1198+ eprintf("fputs:");
1199+}
1200+
1201+/* iterate from beg to end updating ranges so we don't miss any commands
1202+ * e.g. sed -n '1d;1,3p' should still print lines 2 and 3
1203+ */
1204+static void
1205+update_ranges(Cmd *beg, Cmd *end)
1206+{
1207+ while (beg < end)
1208+ in_range(beg++);
1209+}
1210+
1211+/*
1212+ * Sed functions
1213+ */
1214+static void
1215+cmd_a(Cmd *c)
1216+{
1217+ if (in_range(c))
1218+ push(&writes, c);
1219+}
1220+
1221+static void
1222+cmd_b(Cmd *c)
1223+{
1224+ if (!in_range(c))
1225+ return;
1226+
1227+ /* if we jump backwards update to end, otherwise update to destination */
1228+ update_ranges(c + 1, c->u.jump > c ? c->u.jump : prog + pcap);
1229+ pc = c->u.jump;
1230+}
1231+
1232+static void
1233+cmd_c(Cmd *c)
1234+{
1235+ if (!in_range(c))
1236+ return;
1237+
1238+ /* write the text on the last line of the match */
1239+ if (!c->in_match)
1240+ check_puts(c->u.acir.str.str, stdout);
1241+ /* otherwise start the next cycle without printing pattern space
1242+ * effectively deleting the text */
1243+ new_next();
1244+}
1245+
1246+static void
1247+cmd_d(Cmd *c)
1248+{
1249+ if (!in_range(c))
1250+ return;
1251+
1252+ new_next();
1253+}
1254+
1255+static void
1256+cmd_D(Cmd *c)
1257+{
1258+ char *p;
1259+
1260+ if (!in_range(c))
1261+ return;
1262+
1263+ if ((p = strchr(patt.str, '\n'))) {
1264+ p++;
1265+ memmove(patt.str, p, strlen(p) + 1);
1266+ old_next();
1267+ } else {
1268+ new_next();
1269+ }
1270+}
1271+
1272+static void
1273+cmd_g(Cmd *c)
1274+{
1275+ if (in_range(c))
1276+ stracpy(&patt, hold.str);
1277+}
1278+
1279+static void
1280+cmd_G(Cmd *c)
1281+{
1282+ if (!in_range(c))
1283+ return;
1284+
1285+ stracat(&patt, "\n");
1286+ stracat(&patt, hold.str);
1287+}
1288+
1289+static void
1290+cmd_h(Cmd *c)
1291+{
1292+ if (in_range(c))
1293+ stracpy(&hold, patt.str);
1294+}
1295+
1296+static void
1297+cmd_H(Cmd *c)
1298+{
1299+ if (!in_range(c))
1300+ return;
1301+
1302+ stracat(&hold, "\n");
1303+ stracat(&hold, patt.str);
1304+}
1305+
1306+static void
1307+cmd_i(Cmd *c)
1308+{
1309+ if (in_range(c))
1310+ check_puts(c->u.acir.str.str, stdout);
1311+}
1312+
1313+/* I think it makes sense to print invalid UTF-8 sequences in octal to satisfy
1314+ * the "visually unambiguous form" sed(1p)
1315+ */
1316+static void
1317+cmd_l(Cmd *c)
1318+{
1319+ Rune r;
1320+ char *p, *end;
1321+ size_t rlen;
1322+
1323+ char *escapes[] = { /* FIXME: 7 entries and search instead of 127 */
1324+ ['\\'] = "\\\\", ['\a'] = "\\a", ['\b'] = "\\b",
1325+ ['\f'] = "\\f" , ['\r'] = "\\r", ['\t'] = "\\t",
1326+ ['\v'] = "\\v" , [0x7f] = NULL, /* fill out the table */
1327+ };
1328+
1329+ if (!in_range(c))
1330+ return;
1331+
1332+ /* FIXME: line wrapping. sed(1p) says "length at which folding occurs is
1333+ * unspecified, but should be appropraite for the output device"
1334+ * just wrap at 80 Runes?
1335+ */
1336+ for (p = patt.str, end = p + strlen(p); p < end; p += rlen) {
1337+ if (isascii(*p) && escapes[(unsigned int)*p]) {
1338+ fputs(escapes[(unsigned int)*p], stdout);
1339+ rlen = 1;
1340+ } else if (!(rlen = charntorune(&r, p, end - p))) {
1341+ /* ran out of chars, print the bytes of the short sequence */
1342+ for (; p < end; p++)
1343+ printf("\\%03hho", (unsigned char)*p);
1344+ break;
1345+ } else if (r == Runeerror) {
1346+ for (; rlen; rlen--, p++)
1347+ printf("\\%03hho", (unsigned char)*p);
1348+ } else {
1349+ while (fwrite(p, rlen, 1, stdout) < 1 && errno == EINTR)
1350+ ;
1351+ if (ferror(stdout))
1352+ eprintf("fwrite:");
1353+ }
1354+ }
1355+ check_puts("$", stdout);
1356+}
1357+
1358+static void
1359+cmd_n(Cmd *c)
1360+{
1361+ if (!in_range(c))
1362+ return;
1363+
1364+ if (!gflags.n)
1365+ check_puts(patt.str, stdout);
1366+ do_writes();
1367+ new_line();
1368+}
1369+
1370+static void
1371+cmd_N(Cmd *c)
1372+{
1373+ if (!in_range(c))
1374+ return;
1375+ do_writes();
1376+ app_line();
1377+}
1378+
1379+static void
1380+cmd_p(Cmd *c)
1381+{
1382+ if (in_range(c))
1383+ check_puts(patt.str, stdout);
1384+}
1385+
1386+static void
1387+cmd_P(Cmd *c)
1388+{
1389+ char *p;
1390+
1391+ if (!in_range(c))
1392+ return;
1393+
1394+ if ((p = strchr(patt.str, '\n')))
1395+ *p = '\0';
1396+
1397+ check_puts(patt.str, stdout);
1398+
1399+ if (p)
1400+ *p = '\n';
1401+}
1402+
1403+static void
1404+cmd_q(Cmd *c)
1405+{
1406+ if (!in_range(c))
1407+ return;
1408+
1409+ if (!gflags.n)
1410+ check_puts(patt.str, stdout);
1411+ do_writes();
1412+ gflags.halt = 1;
1413+}
1414+
1415+static void
1416+cmd_r(Cmd *c)
1417+{
1418+ if (in_range(c))
1419+ push(&writes, c);
1420+}
1421+
1422+static void
1423+cmd_s(Cmd *c)
1424+{
1425+ String tmp;
1426+ Rune r;
1427+ size_t plen, rlen, len;
1428+ char *p, *s, *end;
1429+ unsigned int matches = 0, last_empty = 1, qflag = 0, cflags = 0;
1430+ regex_t *re;
1431+ regmatch_t *rm, *pmatch = NULL;
1432+
1433+ if (!in_range(c))
1434+ return;
1435+
1436+ if (!c->u.s.re && !lastre)
1437+ leprintf("no previous regex");
1438+
1439+ re = c->u.s.re ? c->u.s.re : lastre;
1440+ lastre = re;
1441+
1442+ plen = re->re_nsub + 1;
1443+ pmatch = ereallocarray(NULL, plen, sizeof(regmatch_t));
1444+
1445+ *genbuf.str = '\0';
1446+ s = patt.str;
1447+
1448+ while (!qflag && !regexec(re, s, plen, pmatch, cflags)) {
1449+ cflags = REG_NOTBOL; /* match against beginning of line first time, but not again */
1450+ if (!*s) /* match against empty string first time, but not again */
1451+ qflag = 1;
1452+
1453+ /* don't substitute if last match was not empty but this one is.
1454+ * s_a*_._g
1455+ * foobar -> .f.o.o.b.r.
1456+ */
1457+ if ((last_empty || pmatch[0].rm_eo) &&
1458+ (++matches == c->u.s.occurrence || !c->u.s.occurrence)) {
1459+ /* copy over everything before the match */
1460+ strnacat(&genbuf, s, pmatch[0].rm_so);
1461+
1462+ /* copy over replacement text, taking into account &, backreferences, and \ escapes */
1463+ for (p = c->u.s.repl.str, len = strcspn(p, "\\&"); *p; len = strcspn(++p, "\\&")) {
1464+ strnacat(&genbuf, p, len);
1465+ p += len;
1466+ switch (*p) {
1467+ default: leprintf("this shouldn't be possible");
1468+ case '\0':
1469+ /* we're at the end, back up one so the ++p will put us on
1470+ * the null byte to break out of the loop */
1471+ --p;
1472+ break;
1473+ case '&':
1474+ strnacat(&genbuf, s + pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so);
1475+ break;
1476+ case '\\':
1477+ if (isdigit(*++p)) { /* backreference */
1478+ /* only need to check here if using lastre, otherwise we checked when building */
1479+ if (!c->u.s.re && (size_t)(*p - '0') > re->re_nsub)
1480+ leprintf("back reference number greater than number of groups");
1481+ rm = &pmatch[*p - '0'];
1482+ strnacat(&genbuf, s + rm->rm_so, rm->rm_eo - rm->rm_so);
1483+ } else { /* character after backslash taken literally (well one byte, but it works) */
1484+ strnacat(&genbuf, p, 1);
1485+ }
1486+ break;
1487+ }
1488+ }
1489+ } else {
1490+ /* not replacing, copy over everything up to and including the match */
1491+ strnacat(&genbuf, s, pmatch[0].rm_eo);
1492+ }
1493+
1494+ if (!pmatch[0].rm_eo) { /* empty match, advance one rune and add it to output */
1495+ end = s + strlen(s);
1496+ rlen = charntorune(&r, s, end - s);
1497+
1498+ if (!rlen) { /* ran out of bytes, copy short sequence */
1499+ stracat(&genbuf, s);
1500+ s = end;
1501+ } else { /* copy whether or not it's a good rune */
1502+ strnacat(&genbuf, s, rlen);
1503+ s += rlen;
1504+ }
1505+ }
1506+ last_empty = !pmatch[0].rm_eo;
1507+ s += pmatch[0].rm_eo;
1508+ }
1509+ free(pmatch);
1510+
1511+ if (!(matches && matches >= c->u.s.occurrence)) /* no replacement */
1512+ return;
1513+
1514+ gflags.s = 1;
1515+
1516+ stracat(&genbuf, s);
1517+
1518+ tmp = patt;
1519+ patt = genbuf;
1520+ genbuf = tmp;
1521+
1522+ if (c->u.s.p)
1523+ check_puts(patt.str, stdout);
1524+ if (c->u.s.file)
1525+ check_puts(patt.str, c->u.s.file);
1526+}
1527+
1528+static void
1529+cmd_t(Cmd *c)
1530+{
1531+ if (!in_range(c) || !gflags.s)
1532+ return;
1533+
1534+ /* if we jump backwards update to end, otherwise update to destination */
1535+ update_ranges(c + 1, c->u.jump > c ? c->u.jump : prog + pcap);
1536+ pc = c->u.jump;
1537+ gflags.s = 0;
1538+}
1539+
1540+static void
1541+cmd_w(Cmd *c)
1542+{
1543+ if (in_range(c))
1544+ check_puts(patt.str, c->u.file);
1545+}
1546+
1547+static void
1548+cmd_x(Cmd *c)
1549+{
1550+ String tmp;
1551+
1552+ if (!in_range(c))
1553+ return;
1554+
1555+ tmp = patt;
1556+ patt = hold;
1557+ hold = tmp;
1558+}
1559+
1560+static void
1561+cmd_y(Cmd *c)
1562+{
1563+ String tmp;
1564+ Rune r, *rp;
1565+ size_t n, rlen;
1566+ char *s, *end, buf[UTFmax];
1567+
1568+ if (!in_range(c))
1569+ return;
1570+
1571+ *genbuf.str = '\0';
1572+ for (s = patt.str, end = s + strlen(s); *s; s += rlen) {
1573+ if (!(rlen = charntorune(&r, s, end - s))) { /* ran out of chars, copy rest */
1574+ stracat(&genbuf, s);
1575+ break;
1576+ } else if (r == Runeerror) { /* bad UTF-8 sequence, copy bytes */
1577+ strnacat(&genbuf, s, rlen);
1578+ } else {
1579+ for (rp = c->u.y.set1; *rp; rp++)
1580+ if (*rp == r)
1581+ break;
1582+ if (*rp) { /* found r in set1, replace with Rune from set2 */
1583+ n = runetochar(buf, c->u.y.set2 + (rp - c->u.y.set1));
1584+ strnacat(&genbuf, buf, n);
1585+ } else {
1586+ strnacat(&genbuf, s, rlen);
1587+ }
1588+ }
1589+ }
1590+ tmp = patt;
1591+ patt = genbuf;
1592+ genbuf = tmp;
1593+}
1594+
1595+static void
1596+cmd_colon(Cmd *c)
1597+{
1598+}
1599+
1600+static void
1601+cmd_equal(Cmd *c)
1602+{
1603+ if (in_range(c))
1604+ printf("%zu\n", lineno);
1605+}
1606+
1607+static void
1608+cmd_lbrace(Cmd *c)
1609+{
1610+ Cmd *jump;
1611+
1612+ if (in_range(c))
1613+ return;
1614+
1615+ /* update ranges on all commands we skip */
1616+ jump = prog + c->u.offset;
1617+ update_ranges(c + 1, jump);
1618+ pc = jump;
1619+}
1620+
1621+static void
1622+cmd_rbrace(Cmd *c)
1623+{
1624+}
1625+
1626+/* not actually a sed function, but acts like one, put in last spot of script */
1627+static void
1628+cmd_last(Cmd *c)
1629+{
1630+ if (!gflags.n)
1631+ check_puts(patt.str, stdout);
1632+ do_writes();
1633+ new_next();
1634+}
1635+
1636+/*
1637+ * Actions
1638+ */
1639+
1640+/* read new line, continue current cycle */
1641+static void
1642+new_line(void)
1643+{
1644+ while (read_line(file, &patt) == EOF) {
1645+ if (next_file()) {
1646+ gflags.halt = 1;
1647+ return;
1648+ }
1649+ }
1650+ gflags.s = 0;
1651+ lineno++;
1652+}
1653+
1654+/* append new line, continue current cycle
1655+ * FIXME: used for N, POSIX specifies do not print pattern space when out of
1656+ * input, but GNU does so busybox does as well. Currently we don't.
1657+ * Should we?
1658+ */
1659+static void
1660+app_line(void)
1661+{
1662+ while (read_line(file, &genbuf) == EOF) {
1663+ if (next_file()) {
1664+ gflags.halt = 1;
1665+ return;
1666+ }
1667+ }
1668+
1669+ stracat(&patt, "\n");
1670+ stracat(&patt, genbuf.str);
1671+ gflags.s = 0;
1672+ lineno++;
1673+}
1674+
1675+/* read new line, start new cycle */
1676+static void
1677+new_next(void)
1678+{
1679+ *patt.str = '\0';
1680+ update_ranges(pc + 1, prog + pcap);
1681+ new_line();
1682+ pc = prog - 1;
1683+}
1684+
1685+/* keep old pattern space, start new cycle */
1686+static void
1687+old_next(void)
1688+{
1689+ update_ranges(pc + 1, prog + pcap);
1690+ pc = prog - 1;
1691+}
1692+
1693+int
1694+main(int argc, char *argv[])
1695+{
1696+ char *arg;
1697+ int script = 0;
1698+
1699+ ARGBEGIN {
1700+ case 'n':
1701+ gflags.n = 1;
1702+ break;
1703+ case 'r':
1704+ case 'E':
1705+ gflags.E = 1;
1706+ break;
1707+ case 'e':
1708+ arg = EARGF(usage());
1709+ compile(arg, 0);
1710+ script = 1;
1711+ break;
1712+ case 'f':
1713+ arg = EARGF(usage());
1714+ compile(arg, 1);
1715+ script = 1;
1716+ break;
1717+ default : usage();
1718+ } ARGEND
1719+
1720+ /* no script to run */
1721+ if (!script && !argc)
1722+ usage();
1723+
1724+ /* no script yet, next argument is script */
1725+ if (!script)
1726+ compile(*argv++, 0);
1727+
1728+ /* shrink/grow memory to fit and add our last instruction */
1729+ resize((void **)&prog, &pcap, sizeof(*prog), pc - prog + 1, NULL);
1730+ pc = prog + pcap - 1;
1731+ pc->fninfo = &(Fninfo){ cmd_last, NULL, NULL, 0 };
1732+
1733+ files = argv;
1734+ run();
1735+
1736+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
1737+
1738+ return ret;
1739+}
+30,
-0
1@@ -0,0 +1,30 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <unistd.h>
4+
5+#include "util.h"
6+
7+static void
8+usage(void)
9+{
10+ eprintf("usage: %s num\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+ unsigned seconds;
17+
18+ ARGBEGIN {
19+ default:
20+ usage();
21+ } ARGEND
22+
23+ if (argc != 1)
24+ usage();
25+
26+ seconds = estrtonum(argv[0], 0, UINT_MAX);
27+ while ((seconds = sleep(seconds)) > 0)
28+ ;
29+
30+ return 0;
31+}
+438,
-0
1@@ -0,0 +1,438 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "queue.h"
9+#include "text.h"
10+#include "utf.h"
11+#include "util.h"
12+
13+struct keydef {
14+ int start_column;
15+ int end_column;
16+ int start_char;
17+ int end_char;
18+ int flags;
19+ TAILQ_ENTRY(keydef) entry;
20+};
21+
22+struct column {
23+ struct line line;
24+ size_t cap;
25+};
26+
27+enum {
28+ MOD_N = 1 << 0,
29+ MOD_STARTB = 1 << 1,
30+ MOD_ENDB = 1 << 2,
31+ MOD_R = 1 << 3,
32+ MOD_D = 1 << 4,
33+ MOD_F = 1 << 5,
34+ MOD_I = 1 << 6,
35+};
36+
37+static TAILQ_HEAD(kdhead, keydef) kdhead = TAILQ_HEAD_INITIALIZER(kdhead);
38+
39+static int Cflag = 0, cflag = 0, uflag = 0;
40+static char *fieldsep = NULL;
41+static size_t fieldseplen = 0;
42+static struct column col1, col2;
43+
44+static void
45+skipblank(struct line *a)
46+{
47+ while (a->len && (*(a->data) == ' ' || *(a->data) == '\t')) {
48+ a->data++;
49+ a->len--;
50+ }
51+}
52+
53+static void
54+skipnonblank(struct line *a)
55+{
56+ while (a->len && (*(a->data) != '\n' && *(a->data) != ' ' &&
57+ *(a->data) != '\t')) {
58+ a->data++;
59+ a->len--;
60+ }
61+}
62+
63+static void
64+skipcolumn(struct line *a, int skip_to_next_col)
65+{
66+ char *s;
67+
68+ if (fieldsep) {
69+ if ((s = memmem(a->data, a->len, fieldsep, fieldseplen))) {
70+ if (skip_to_next_col)
71+ s += fieldseplen;
72+ a->len -= s - a->data;
73+ a->data = s;
74+ } else {
75+ a->data += a->len - 1;
76+ a->len = 1;
77+ }
78+ } else {
79+ skipblank(a);
80+ skipnonblank(a);
81+ }
82+}
83+
84+static void
85+columns(struct line *line, const struct keydef *kd, struct column *col)
86+{
87+ Rune r;
88+ struct line start, end;
89+ size_t utflen, rlen;
90+ int i;
91+
92+ start.data = line->data;
93+ start.len = line->len;
94+ for (i = 1; i < kd->start_column; i++)
95+ skipcolumn(&start, 1);
96+ if (kd->flags & MOD_STARTB)
97+ skipblank(&start);
98+ for (utflen = 0; start.len > 1 && utflen < kd->start_char - 1;) {
99+ rlen = chartorune(&r, start.data);
100+ start.data += rlen;
101+ start.len -= rlen;
102+ utflen++;
103+ }
104+
105+ end.data = line->data;
106+ end.len = line->len;
107+ if (kd->end_column) {
108+ for (i = 1; i < kd->end_column; i++)
109+ skipcolumn(&end, 1);
110+ if (kd->flags & MOD_ENDB)
111+ skipblank(&end);
112+ if (kd->end_char) {
113+ for (utflen = 0; end.len > 1 && utflen < kd->end_char;) {
114+ rlen = chartorune(&r, end.data);
115+ end.data += rlen;
116+ end.len -= rlen;
117+ utflen++;
118+ }
119+ } else {
120+ skipcolumn(&end, 0);
121+ }
122+ } else {
123+ end.data += end.len - 1;
124+ end.len = 1;
125+ }
126+ col->line.len = MAX(0, end.data - start.data);
127+ if (!(col->line.data) || col->cap < col->line.len + 1) {
128+ free(col->line.data);
129+ col->line.data = emalloc(col->line.len + 1);
130+ col->cap = col->line.len + 1;
131+ }
132+ memcpy(col->line.data, start.data, col->line.len);
133+ col->line.data[col->line.len] = '\0';
134+}
135+
136+static int
137+skipmodcmp(struct line *a, struct line *b, int flags)
138+{
139+ Rune r1, r2;
140+ size_t offa = 0, offb = 0;
141+
142+ do {
143+ offa += chartorune(&r1, a->data + offa);
144+ offb += chartorune(&r2, b->data + offb);
145+
146+ if (flags & MOD_D && flags & MOD_I) {
147+ while (offa < a->len && ((!isblankrune(r1) &&
148+ !isalnumrune(r1)) || (!isprintrune(r1))))
149+ offa += chartorune(&r1, a->data + offa);
150+ while (offb < b->len && ((!isblankrune(r2) &&
151+ !isalnumrune(r2)) || (!isprintrune(r2))))
152+ offb += chartorune(&r2, b->data + offb);
153+ }
154+ else if (flags & MOD_D) {
155+ while (offa < a->len && !isblankrune(r1) &&
156+ !isalnumrune(r1))
157+ offa += chartorune(&r1, a->data + offa);
158+ while (offb < b->len && !isblankrune(r2) &&
159+ !isalnumrune(r2))
160+ offb += chartorune(&r2, b->data + offb);
161+ }
162+ else if (flags & MOD_I) {
163+ while (offa < a->len && !isprintrune(r1))
164+ offa += chartorune(&r1, a->data + offa);
165+ while (offb < b->len && !isprintrune(r2))
166+ offb += chartorune(&r2, b->data + offb);
167+ }
168+ if (flags & MOD_F) {
169+ r1 = toupperrune(r1);
170+ r2 = toupperrune(r2);
171+ }
172+ } while (r1 && r1 == r2);
173+
174+ return r1 - r2;
175+}
176+
177+static int
178+slinecmp(struct line *a, struct line *b)
179+{
180+ int res = 0;
181+ double x, y;
182+ struct keydef *kd;
183+
184+ TAILQ_FOREACH(kd, &kdhead, entry) {
185+ columns(a, kd, &col1);
186+ columns(b, kd, &col2);
187+
188+ /* if -u is given, don't use default key definition
189+ * unless it is the only one */
190+ if (uflag && kd == TAILQ_LAST(&kdhead, kdhead) &&
191+ TAILQ_LAST(&kdhead, kdhead) != TAILQ_FIRST(&kdhead)) {
192+ res = 0;
193+ } else if (kd->flags & MOD_N) {
194+ x = strtod(col1.line.data, NULL);
195+ y = strtod(col2.line.data, NULL);
196+ res = (x < y) ? -1 : (x > y);
197+ } else if (kd->flags & (MOD_D | MOD_F | MOD_I)) {
198+ res = skipmodcmp(&col1.line, &col2.line, kd->flags);
199+ } else {
200+ res = linecmp(&col1.line, &col2.line);
201+ }
202+
203+ if (kd->flags & MOD_R)
204+ res = -res;
205+ if (res)
206+ break;
207+ }
208+
209+ return res;
210+}
211+
212+static int
213+check(FILE *fp, const char *fname)
214+{
215+ static struct line prev, cur, tmp;
216+ static size_t prevsize, cursize, tmpsize;
217+ ssize_t len;
218+
219+ if (!prev.data) {
220+ if ((len = getline(&prev.data, &prevsize, fp)) < 0)
221+ eprintf("getline:");
222+ prev.len = len;
223+ }
224+ while ((len = getline(&cur.data, &cursize, fp)) > 0) {
225+ cur.len = len;
226+ if (uflag > slinecmp(&cur, &prev)) {
227+ if (!Cflag) {
228+ weprintf("disorder %s: ", fname);
229+ fwrite(cur.data, 1, cur.len, stderr);
230+ }
231+ return 1;
232+ }
233+ tmp = cur;
234+ tmpsize = cursize;
235+ cur = prev;
236+ cursize = prevsize;
237+ prev = tmp;
238+ prevsize = tmpsize;
239+ }
240+
241+ return 0;
242+}
243+
244+static int
245+parse_flags(char **s, int *flags, int bflag)
246+{
247+ while (isalpha((int)**s)) {
248+ switch (*((*s)++)) {
249+ case 'b':
250+ *flags |= bflag;
251+ break;
252+ case 'd':
253+ *flags |= MOD_D;
254+ break;
255+ case 'f':
256+ *flags |= MOD_F;
257+ break;
258+ case 'i':
259+ *flags |= MOD_I;
260+ break;
261+ case 'n':
262+ *flags |= MOD_N;
263+ break;
264+ case 'r':
265+ *flags |= MOD_R;
266+ break;
267+ default:
268+ return -1;
269+ }
270+ }
271+
272+ return 0;
273+}
274+
275+static void
276+addkeydef(char *kdstr, int flags)
277+{
278+ struct keydef *kd;
279+
280+ kd = enmalloc(2, sizeof(*kd));
281+
282+ /* parse key definition kdstr with format
283+ * start_column[.start_char][flags][,end_column[.end_char][flags]]
284+ */
285+ kd->start_column = 1;
286+ kd->start_char = 1;
287+ kd->end_column = 0; /* 0 means end of line */
288+ kd->end_char = 0; /* 0 means end of column */
289+ kd->flags = flags;
290+
291+ if ((kd->start_column = strtol(kdstr, &kdstr, 10)) < 1)
292+ enprintf(2, "invalid start column in key definition\n");
293+
294+ if (*kdstr == '.') {
295+ if ((kd->start_char = strtol(kdstr + 1, &kdstr, 10)) < 1)
296+ enprintf(2, "invalid start character in key "
297+ "definition\n");
298+ }
299+ if (parse_flags(&kdstr, &kd->flags, MOD_STARTB) < 0)
300+ enprintf(2, "invalid start flags in key definition\n");
301+
302+ if (*kdstr == ',') {
303+ if ((kd->end_column = strtol(kdstr + 1, &kdstr, 10)) < 0)
304+ enprintf(2, "invalid end column in key definition\n");
305+ if (*kdstr == '.') {
306+ if ((kd->end_char = strtol(kdstr + 1, &kdstr, 10)) < 0)
307+ enprintf(2, "invalid end character in key "
308+ "definition\n");
309+ }
310+ if (parse_flags(&kdstr, &kd->flags, MOD_ENDB) < 0)
311+ enprintf(2, "invalid end flags in key definition\n");
312+ }
313+
314+ if (*kdstr != '\0')
315+ enprintf(2, "invalid key definition\n");
316+
317+ TAILQ_INSERT_TAIL(&kdhead, kd, entry);
318+}
319+
320+static void
321+usage(void)
322+{
323+ enprintf(2, "usage: %s [-Cbcdfimnru] [-o outfile] [-t delim] "
324+ "[-k def]... [file ...]\n", argv0);
325+}
326+
327+int
328+main(int argc, char *argv[])
329+{
330+ FILE *fp, *ofp = stdout;
331+ struct linebuf linebuf = EMPTY_LINEBUF;
332+ size_t i;
333+ int global_flags = 0, ret = 0;
334+ char *outfile = NULL;
335+
336+ ARGBEGIN {
337+ case 'C':
338+ Cflag = 1;
339+ break;
340+ case 'b':
341+ global_flags |= MOD_STARTB | MOD_ENDB;
342+ break;
343+ case 'c':
344+ cflag = 1;
345+ break;
346+ case 'd':
347+ global_flags |= MOD_D;
348+ break;
349+ case 'f':
350+ global_flags |= MOD_F;
351+ break;
352+ case 'i':
353+ global_flags |= MOD_I;
354+ break;
355+ case 'k':
356+ addkeydef(EARGF(usage()), global_flags);
357+ break;
358+ case 'm':
359+ /* more or less for free, but for performance-reasons,
360+ * we should keep this flag in mind and maybe some later
361+ * day implement it properly so we don't run out of memory
362+ * while merging large sorted files.
363+ */
364+ break;
365+ case 'n':
366+ global_flags |= MOD_N;
367+ break;
368+ case 'o':
369+ outfile = EARGF(usage());
370+ break;
371+ case 'r':
372+ global_flags |= MOD_R;
373+ break;
374+ case 't':
375+ fieldsep = EARGF(usage());
376+ if (!*fieldsep)
377+ eprintf("empty delimiter\n");
378+ fieldseplen = unescape(fieldsep);
379+ break;
380+ case 'u':
381+ uflag = 1;
382+ break;
383+ default:
384+ usage();
385+ } ARGEND
386+
387+ /* -b shall only apply to custom key definitions */
388+ if (TAILQ_EMPTY(&kdhead) && global_flags)
389+ addkeydef("1", global_flags & ~(MOD_STARTB | MOD_ENDB));
390+ if (TAILQ_EMPTY(&kdhead) || (!Cflag && !cflag))
391+ addkeydef("1", global_flags & MOD_R);
392+
393+ if (!argc) {
394+ if (Cflag || cflag) {
395+ if (check(stdin, "<stdin>") && !ret)
396+ ret = 1;
397+ } else {
398+ getlines(stdin, &linebuf);
399+ }
400+ } else for (; *argv; argc--, argv++) {
401+ if (!strcmp(*argv, "-")) {
402+ *argv = "<stdin>";
403+ fp = stdin;
404+ } else if (!(fp = fopen(*argv, "r"))) {
405+ enprintf(2, "fopen %s:", *argv);
406+ continue;
407+ }
408+ if (Cflag || cflag) {
409+ if (check(fp, *argv) && !ret)
410+ ret = 1;
411+ } else {
412+ getlines(fp, &linebuf);
413+ }
414+ if (fp != stdin && fshut(fp, *argv))
415+ ret = 2;
416+ }
417+
418+ if (!Cflag && !cflag) {
419+ if (outfile && !(ofp = fopen(outfile, "w")))
420+ eprintf("fopen %s:", outfile);
421+
422+ qsort(linebuf.lines, linebuf.nlines, sizeof(*linebuf.lines),
423+ (int (*)(const void *, const void *))slinecmp);
424+
425+ for (i = 0; i < linebuf.nlines; i++) {
426+ if (!uflag || i == 0 ||
427+ slinecmp(&linebuf.lines[i], &linebuf.lines[i - 1])) {
428+ fwrite(linebuf.lines[i].data, 1,
429+ linebuf.lines[i].len, ofp);
430+ }
431+ }
432+ }
433+
434+ if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>") |
435+ fshut(stderr, "<stderr>"))
436+ ret = 2;
437+
438+ return ret;
439+}
+111,
-0
1@@ -0,0 +1,111 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "util.h"
10+
11+static int base = 26, start = 'a';
12+
13+static int
14+itostr(char *str, int x, int n)
15+{
16+ str[n] = '\0';
17+ while (n-- > 0) {
18+ str[n] = start + (x % base);
19+ x /= base;
20+ }
21+
22+ return x ? -1 : 0;
23+}
24+
25+static FILE *
26+nextfile(FILE *f, char *buf, int plen, int slen)
27+{
28+ static int filecount = 0;
29+
30+ if (f)
31+ fshut(f, "<file>");
32+ if (itostr(buf + plen, filecount++, slen) < 0)
33+ return NULL;
34+
35+ if (!(f = fopen(buf, "w")))
36+ eprintf("'%s':", buf);
37+
38+ return f;
39+}
40+
41+static void
42+usage(void)
43+{
44+ eprintf("usage: %s [-a num] [-b num[k|m|g] | -l num] [-d] "
45+ "[file [prefix]]\n", argv0);
46+}
47+
48+int
49+main(int argc, char *argv[])
50+{
51+ FILE *in = stdin, *out = NULL;
52+ off_t size = 1000, n;
53+ int ret = 0, ch, plen, slen = 2, always = 0;
54+ char name[NAME_MAX + 1], *prefix = "x", *file = NULL;
55+
56+ ARGBEGIN {
57+ case 'a':
58+ slen = estrtonum(EARGF(usage()), 0, INT_MAX);
59+ break;
60+ case 'b':
61+ always = 1;
62+ if ((size = parseoffset(EARGF(usage()))) < 0)
63+ return 1;
64+ if (!size)
65+ eprintf("size needs to be positive\n");
66+ break;
67+ case 'd':
68+ base = 10;
69+ start = '0';
70+ break;
71+ case 'l':
72+ always = 0;
73+ size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SSIZE_MAX));
74+ break;
75+ default:
76+ usage();
77+ } ARGEND
78+
79+ if (*argv)
80+ file = *argv++;
81+ if (*argv)
82+ prefix = *argv++;
83+ if (*argv)
84+ usage();
85+
86+ plen = strlen(prefix);
87+ if (plen + slen > NAME_MAX)
88+ eprintf("names cannot exceed %d bytes\n", NAME_MAX);
89+ estrlcpy(name, prefix, sizeof(name));
90+
91+ if (file && strcmp(file, "-")) {
92+ if (!(in = fopen(file, "r")))
93+ eprintf("fopen %s:", file);
94+ }
95+
96+ n = 0;
97+ while ((ch = getc(in)) != EOF) {
98+ if (!out || n >= size) {
99+ if (!(out = nextfile(out, name, plen, slen)))
100+ eprintf("fopen: %s:", name);
101+ n = 0;
102+ }
103+ n += (always || ch == '\n');
104+ putc(ch, out);
105+ }
106+
107+ ret |= (in != stdin) && fshut(in, "<infile>");
108+ ret |= out && (out != stdout) && fshut(out, "<outfile>");
109+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
110+
111+ return ret;
112+}
+229,
-0
1@@ -0,0 +1,229 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <fcntl.h>
6+#include <unistd.h>
7+#include <stdint.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "utf.h"
14+#include "util.h"
15+
16+static char mode = 'n';
17+
18+static int
19+dropinit(int fd, const char *fname, size_t count)
20+{
21+ Rune r;
22+ char buf[BUFSIZ], *p;
23+ ssize_t n;
24+ int nr;
25+
26+ if (count < 2)
27+ goto copy;
28+ count--; /* numbering starts at 1 */
29+ while (count && (n = read(fd, buf, sizeof(buf))) > 0) {
30+ switch (mode) {
31+ case 'n': /* lines */
32+ for (p = buf; count && n > 0; p++, n--) {
33+ if (*p == '\n')
34+ count--;
35+ }
36+ break;
37+ case 'c': /* bytes */
38+ if (count > n) {
39+ count -= n;
40+ } else {
41+ p = buf + count;
42+ n -= count;
43+ count = 0;
44+ }
45+ break;
46+ case 'm': /* runes */
47+ for (p = buf; count && n > 0; p += nr, n -= nr, count--) {
48+ nr = charntorune(&r, p, n);
49+ if (!nr) {
50+ /* we don't have a full rune, move
51+ * remaining data to beginning and read
52+ * again */
53+ memmove(buf, p, n);
54+ break;
55+ }
56+ }
57+ break;
58+ }
59+ }
60+ if (count) {
61+ if (n < 0)
62+ weprintf("read %s:", fname);
63+ if (n <= 0)
64+ return n;
65+ }
66+
67+ /* write the rest of the buffer */
68+ if (writeall(1, p, n) < 0)
69+ eprintf("write:");
70+copy:
71+ switch (concat(fd, fname, 1, "<stdout>")) {
72+ case -1: /* read error */
73+ return -1;
74+ case -2: /* write error */
75+ exit(1);
76+ default:
77+ return 0;
78+ }
79+}
80+
81+static int
82+taketail(int fd, const char *fname, size_t count)
83+{
84+ static char *buf = NULL;
85+ static size_t size = 0;
86+ char *p;
87+ size_t len = 0, left;
88+ ssize_t n;
89+
90+ if (!count)
91+ return 0;
92+ for (;;) {
93+ if (len + BUFSIZ > size) {
94+ /* make sure we have at least BUFSIZ to read */
95+ size += 2 * BUFSIZ;
96+ buf = erealloc(buf, size);
97+ }
98+ n = read(fd, buf + len, size - len);
99+ if (n < 0) {
100+ weprintf("read %s:", fname);
101+ return -1;
102+ }
103+ if (n == 0)
104+ break;
105+ len += n;
106+ switch (mode) {
107+ case 'n': /* lines */
108+ /* ignore the last character; if it is a newline, it
109+ * ends the last line */
110+ for (p = buf + len - 2, left = count; p >= buf; p--) {
111+ if (*p != '\n')
112+ continue;
113+ left--;
114+ if (!left) {
115+ p++;
116+ break;
117+ }
118+ }
119+ break;
120+ case 'c': /* bytes */
121+ p = count < len ? buf + len - count : buf;
122+ break;
123+ case 'm': /* runes */
124+ for (p = buf + len - 1, left = count; p >= buf; p--) {
125+ /* skip utf-8 continuation bytes */
126+ if (UTF8_POINT(*p))
127+ continue;
128+ left--;
129+ if (!left)
130+ break;
131+ }
132+ break;
133+ }
134+ if (p > buf) {
135+ len -= p - buf;
136+ memmove(buf, p, len);
137+ }
138+ }
139+ if (writeall(1, buf, len) < 0)
140+ eprintf("write:");
141+ return 0;
142+}
143+
144+static void
145+usage(void)
146+{
147+ eprintf("usage: %s [-f] [-c num | -m num | -n num | -num] [file ...]\n", argv0);
148+}
149+
150+int
151+main(int argc, char *argv[])
152+{
153+ struct stat st1, st2;
154+ int fd;
155+ size_t n = 10;
156+ int fflag = 0, ret = 0, newline = 0, many = 0;
157+ char *numstr;
158+ int (*tail)(int, const char *, size_t) = taketail;
159+
160+ ARGBEGIN {
161+ case 'f':
162+ fflag = 1;
163+ break;
164+ case 'c':
165+ case 'm':
166+ case 'n':
167+ mode = ARGC();
168+ numstr = EARGF(usage());
169+ n = MIN(llabs(estrtonum(numstr, LLONG_MIN + 1,
170+ MIN(LLONG_MAX, SIZE_MAX))), SIZE_MAX);
171+ if (strchr(numstr, '+'))
172+ tail = dropinit;
173+ break;
174+ ARGNUM:
175+ n = ARGNUMF();
176+ break;
177+ default:
178+ usage();
179+ } ARGEND
180+
181+ if (!argc) {
182+ if (tail(0, "<stdin>", n) < 0)
183+ ret = 1;
184+ } else {
185+ if ((many = argc > 1) && fflag)
186+ usage();
187+ for (newline = 0; *argv; argc--, argv++) {
188+ if (!strcmp(*argv, "-")) {
189+ *argv = "<stdin>";
190+ fd = 0;
191+ } else if ((fd = open(*argv, O_RDONLY)) < 0) {
192+ weprintf("open %s:", *argv);
193+ ret = 1;
194+ continue;
195+ }
196+ if (many)
197+ printf("%s==> %s <==\n", newline ? "\n" : "", *argv);
198+ if (fstat(fd, &st1) < 0)
199+ eprintf("fstat %s:", *argv);
200+ if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mode)))
201+ fflag = 0;
202+ newline = 1;
203+ if (tail(fd, *argv, n) < 0) {
204+ ret = 1;
205+ fflag = 0;
206+ }
207+
208+ if (!fflag) {
209+ if (fd != 0)
210+ close(fd);
211+ continue;
212+ }
213+ for (;;) {
214+ if (concat(fd, *argv, 1, "<stdout>") < 0)
215+ exit(1);
216+ if (fstat(fd, &st2) < 0)
217+ eprintf("fstat %s:", *argv);
218+ if (st2.st_size < st1.st_size) {
219+ fprintf(stderr, "%s: file truncated\n", *argv);
220+ if (lseek(fd, SEEK_SET, 0) < 0)
221+ eprintf("lseek:");
222+ }
223+ st1 = st2;
224+ sleep(1);
225+ }
226+ }
227+ }
228+
229+ return ret;
230+}
+60,
-0
1@@ -0,0 +1,60 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <signal.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [-ai] [file ...]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ int *fds = NULL;
19+ size_t i, nfds;
20+ ssize_t n;
21+ int ret = 0, aflag = O_TRUNC, iflag = 0;
22+ char buf[BUFSIZ];
23+
24+ ARGBEGIN {
25+ case 'a':
26+ aflag = O_APPEND;
27+ break;
28+ case 'i':
29+ iflag = 1;
30+ break;
31+ default:
32+ usage();
33+ } ARGEND
34+
35+ if (iflag && signal(SIGINT, SIG_IGN) == SIG_ERR)
36+ eprintf("signal:");
37+ nfds = argc + 1;
38+ fds = ecalloc(nfds, sizeof(*fds));
39+
40+ for (i = 0; i < argc; i++) {
41+ if ((fds[i] = open(argv[i], O_WRONLY|O_CREAT|aflag, 0666)) < 0) {
42+ weprintf("open %s:", argv[i]);
43+ ret = 1;
44+ }
45+ }
46+ fds[i] = 1;
47+
48+ while ((n = read(0, buf, sizeof(buf))) > 0) {
49+ for (i = 0; i < nfds; i++) {
50+ if (fds[i] >= 0 && writeall(fds[i], buf, n) < 0) {
51+ weprintf("write %s:", (i != argc) ? argv[i] : "<stdout>");
52+ fds[i] = -1;
53+ ret = 1;
54+ }
55+ }
56+ }
57+ if (n < 0)
58+ eprintf("read <stdin>:");
59+
60+ return ret;
61+}
+247,
-0
1@@ -0,0 +1,247 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <ctype.h>
6+#include <fcntl.h>
7+#include <string.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+static int
13+intcmp(char *a, char *b)
14+{
15+ char *s;
16+ int asign = *a == '-' ? -1 : 1;
17+ int bsign = *b == '-' ? -1 : 1;
18+
19+ if (*a == '-' || *a == '+') a += 1;
20+ if (*b == '-' || *b == '+') b += 1;
21+
22+ if (!*a || !*b)
23+ goto noint;
24+ for (s = a; *s; s++)
25+ if (!isdigit(*s))
26+ goto noint;
27+ for (s = b; *s; s++)
28+ if (!isdigit(*s))
29+ goto noint;
30+
31+ while (*a == '0') a++;
32+ while (*b == '0') b++;
33+ asign *= !!*a;
34+ bsign *= !!*b;
35+
36+ if (asign != bsign)
37+ return asign < bsign ? -1 : 1;
38+ else if (strlen(a) != strlen(b))
39+ return asign * (strlen(a) < strlen(b) ? -1 : 1);
40+ else
41+ return asign * strcmp(a, b);
42+
43+noint:
44+ enprintf(2, "expected integer operands\n");
45+
46+ return 0; /* not reached */
47+}
48+
49+static int
50+mtimecmp(struct stat *buf1, struct stat *buf2)
51+{
52+ if (buf1->st_mtime < buf2->st_mtime) return -1;
53+ if (buf1->st_mtime > buf2->st_mtime) return +1;
54+#ifdef st_mtime
55+ if (buf1->st_mtim.tv_nsec < buf2->st_mtim.tv_nsec) return -1;
56+ if (buf1->st_mtim.tv_nsec > buf2->st_mtim.tv_nsec) return +1;
57+#endif
58+ return 0;
59+}
60+
61+static int unary_b(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISBLK (buf.st_mode); }
62+static int unary_c(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISCHR (buf.st_mode); }
63+static int unary_d(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISDIR (buf.st_mode); }
64+static int unary_f(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISREG (buf.st_mode); }
65+static int unary_g(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISGID & buf.st_mode ; }
66+static int unary_h(char *s) { struct stat buf; if (lstat(s, &buf)) return 0; return S_ISLNK (buf.st_mode); }
67+static int unary_k(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISVTX & buf.st_mode ; }
68+static int unary_p(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISFIFO (buf.st_mode); }
69+static int unary_S(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISSOCK (buf.st_mode); }
70+static int unary_s(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return buf.st_size ; }
71+static int unary_u(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISUID & buf.st_mode ; }
72+
73+static int unary_n(char *s) { return *s; }
74+static int unary_z(char *s) { return !*s; }
75+
76+static int unary_e(char *s) { return !faccessat(AT_FDCWD, s, F_OK, AT_EACCESS); }
77+static int unary_r(char *s) { return !faccessat(AT_FDCWD, s, R_OK, AT_EACCESS); }
78+static int unary_w(char *s) { return !faccessat(AT_FDCWD, s, W_OK, AT_EACCESS); }
79+static int unary_x(char *s) { return !faccessat(AT_FDCWD, s, X_OK, AT_EACCESS); }
80+
81+static int unary_t(char *s) { int fd = enstrtonum(2, s, 0, INT_MAX); return isatty(fd); }
82+
83+static int binary_se(char *s1, char *s2) { return !strcmp(s1, s2); }
84+static int binary_sn(char *s1, char *s2) { return strcmp(s1, s2); }
85+
86+static int binary_eq(char *s1, char *s2) { return intcmp(s1, s2) == 0; }
87+static int binary_ne(char *s1, char *s2) { return intcmp(s1, s2) != 0; }
88+static int binary_gt(char *s1, char *s2) { return intcmp(s1, s2) > 0; }
89+static int binary_ge(char *s1, char *s2) { return intcmp(s1, s2) >= 0; }
90+static int binary_lt(char *s1, char *s2) { return intcmp(s1, s2) < 0; }
91+static int binary_le(char *s1, char *s2) { return intcmp(s1, s2) <= 0; }
92+
93+static int
94+binary_ef(char *s1, char *s2)
95+{
96+ struct stat buf1, buf2;
97+ if (stat(s1, &buf1) || stat(s2, &buf2)) return 0;
98+ return buf1.st_dev == buf2.st_dev && buf1.st_ino == buf2.st_ino;
99+}
100+
101+static int
102+binary_ot(char *s1, char *s2)
103+{
104+ struct stat buf1, buf2;
105+ if (stat(s1, &buf1) || stat(s2, &buf2)) return 0;
106+ return mtimecmp(&buf1, &buf2) < 0;
107+}
108+
109+static int
110+binary_nt(char *s1, char *s2)
111+{
112+ struct stat buf1, buf2;
113+ if (stat(s1, &buf1) || stat(s2, &buf2)) return 0;
114+ return mtimecmp(&buf1, &buf2) > 0;
115+}
116+
117+struct test {
118+ char *name;
119+ union {
120+ int (*u)(char *);
121+ int (*b)(char *, char *);
122+ } func;
123+};
124+
125+static struct test unary[] = {
126+ { "-b", { .u = unary_b } },
127+ { "-c", { .u = unary_c } },
128+ { "-d", { .u = unary_d } },
129+ { "-e", { .u = unary_e } },
130+ { "-f", { .u = unary_f } },
131+ { "-g", { .u = unary_g } },
132+ { "-h", { .u = unary_h } },
133+ { "-k", { .u = unary_k } },
134+ { "-L", { .u = unary_h } },
135+ { "-n", { .u = unary_n } },
136+ { "-p", { .u = unary_p } },
137+ { "-r", { .u = unary_r } },
138+ { "-S", { .u = unary_S } },
139+ { "-s", { .u = unary_s } },
140+ { "-t", { .u = unary_t } },
141+ { "-u", { .u = unary_u } },
142+ { "-w", { .u = unary_w } },
143+ { "-x", { .u = unary_x } },
144+ { "-z", { .u = unary_z } },
145+
146+ { NULL },
147+};
148+
149+static struct test binary[] = {
150+ { "=" , { .b = binary_se } },
151+ { "!=" , { .b = binary_sn } },
152+ { "-eq", { .b = binary_eq } },
153+ { "-ne", { .b = binary_ne } },
154+ { "-gt", { .b = binary_gt } },
155+ { "-ge", { .b = binary_ge } },
156+ { "-lt", { .b = binary_lt } },
157+ { "-le", { .b = binary_le } },
158+ { "-ef", { .b = binary_ef } },
159+ { "-ot", { .b = binary_ot } },
160+ { "-nt", { .b = binary_nt } },
161+
162+ { NULL },
163+};
164+
165+static struct test *
166+find_test(struct test *tests, char *name)
167+{
168+ struct test *t;
169+
170+ for (t = tests; t->name; t++)
171+ if (!strcmp(t->name, name))
172+ return t;
173+
174+ return NULL;
175+}
176+
177+static int
178+noarg(char *argv[])
179+{
180+ return 0;
181+}
182+
183+static int
184+onearg(char *argv[])
185+{
186+ return unary_n(argv[0]);
187+}
188+
189+static int
190+twoarg(char *argv[])
191+{
192+ struct test *t;
193+
194+ if (!strcmp(argv[0], "!"))
195+ return !onearg(argv + 1);
196+
197+ if ((t = find_test(unary, *argv)))
198+ return t->func.u(argv[1]);
199+
200+ enprintf(2, "bad unary test %s\n", argv[0]);
201+
202+ return 0; /* not reached */
203+}
204+
205+static int
206+threearg(char *argv[])
207+{
208+ struct test *t = find_test(binary, argv[1]);
209+
210+ if (t)
211+ return t->func.b(argv[0], argv[2]);
212+
213+ if (!strcmp(argv[0], "!"))
214+ return !twoarg(argv + 1);
215+
216+ enprintf(2, "bad binary test %s\n", argv[1]);
217+
218+ return 0; /* not reached */
219+}
220+
221+static int
222+fourarg(char *argv[])
223+{
224+ if (!strcmp(argv[0], "!"))
225+ return !threearg(argv + 1);
226+
227+ enprintf(2, "too many arguments\n");
228+
229+ return 0; /* not reached */
230+}
231+
232+int
233+main(int argc, char *argv[])
234+{
235+ int (*narg[])(char *[]) = { noarg, onearg, twoarg, threearg, fourarg };
236+ size_t len;
237+
238+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
239+
240+ len = argv0 ? strlen(argv0) : 0;
241+ if (len && argv0[--len] == '[' && (!len || argv0[--len] == '/') && strcmp(argv[--argc], "]"))
242+ enprintf(2, "no matching ]\n");
243+
244+ if (argc > 4)
245+ enprintf(2, "too many arguments\n");
246+
247+ return !narg[argc](argv);
248+}
+73,
-0
1@@ -0,0 +1,73 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/times.h>
4+#include <sys/wait.h>
5+
6+#include <errno.h>
7+#include <stdio.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s [-p] cmd [arg ...]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ pid_t pid;
22+ struct tms tms; /* user and sys times */
23+ clock_t r0, r1; /* real time */
24+ long ticks; /* per second */
25+ int status, savederrno, ret = 0;
26+
27+ ARGBEGIN {
28+ case 'p':
29+ break;
30+ default:
31+ usage();
32+ } ARGEND
33+
34+ if (!argc)
35+ usage();
36+
37+ if ((ticks = sysconf(_SC_CLK_TCK)) <= 0)
38+ eprintf("sysconf _SC_CLK_TCK:");
39+
40+ if ((r0 = times(&tms)) == (clock_t)-1)
41+ eprintf("times:");
42+
43+ switch ((pid = fork())) {
44+ case -1:
45+ eprintf("fork:");
46+ case 0:
47+ execvp(argv[0], argv);
48+ savederrno = errno;
49+ weprintf("execvp %s:", argv[0]);
50+ _exit(126 + (savederrno == ENOENT));
51+ default:
52+ break;
53+ }
54+ waitpid(pid, &status, 0);
55+
56+ if ((r1 = times(&tms)) == (clock_t)-1)
57+ eprintf("times:");
58+
59+ if (WIFSIGNALED(status)) {
60+ fprintf(stderr, "Command terminated by signal %d\n",
61+ WTERMSIG(status));
62+ ret = 128 + WTERMSIG(status);
63+ }
64+
65+ fprintf(stderr, "real %f\nuser %f\nsys %f\n",
66+ (r1 - r0) / (double)ticks,
67+ tms.tms_cutime / (double)ticks,
68+ tms.tms_cstime / (double)ticks);
69+
70+ if (WIFEXITED(status))
71+ ret = WEXITSTATUS(status);
72+
73+ return ret;
74+}
+159,
-0
1@@ -0,0 +1,159 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <time.h>
10+#include <unistd.h>
11+
12+#include "util.h"
13+
14+static int aflag;
15+static int cflag;
16+static int mflag;
17+static struct timespec times[2] = {{.tv_nsec = UTIME_NOW}};
18+
19+static void
20+touch(const char *file)
21+{
22+ int fd, ret;
23+
24+ if (utimensat(AT_FDCWD, file, times, 0) == 0)
25+ return;
26+ if (errno != ENOENT)
27+ eprintf("utimensat %s:", file);
28+ if (cflag)
29+ return;
30+ if ((fd = open(file, O_WRONLY | O_CREAT, 0666)) < 0)
31+ eprintf("open %s:", file);
32+ ret = futimens(fd, times);
33+ close(fd);
34+ if (ret < 0)
35+ eprintf("futimens %s:", file);
36+}
37+
38+static time_t
39+parsetime(char *str)
40+{
41+ time_t now;
42+ struct tm *cur, t = { 0 };
43+ int zulu = 0;
44+ char *format;
45+ size_t len = strlen(str);
46+
47+ if ((now = time(NULL)) == -1)
48+ eprintf("time:");
49+ if (!(cur = localtime(&now)))
50+ eprintf("localtime:");
51+ t.tm_isdst = -1;
52+
53+ switch (len) {
54+ /* -t flag argument */
55+ case 8:
56+ t.tm_year = cur->tm_year;
57+ format = "%m%d%H%M";
58+ break;
59+ case 10:
60+ format = "%y%m%d%H%M";
61+ break;
62+ case 11:
63+ t.tm_year = cur->tm_year;
64+ format = "%m%d%H%M.%S";
65+ break;
66+ case 12:
67+ format = "%Y%m%d%H%M";
68+ break;
69+ case 13:
70+ format = "%y%m%d%H%M.%S";
71+ break;
72+ case 15:
73+ format = "%Y%m%d%H%M.%S";
74+ break;
75+ /* -d flag argument */
76+ case 19:
77+ format = "%Y-%m-%dT%H:%M:%S";
78+ break;
79+ case 20:
80+ /* only Zulu-timezone supported */
81+ if (str[19] != 'Z')
82+ eprintf("Invalid time zone\n");
83+ str[19] = 0;
84+ zulu = 1;
85+ format = "%Y-%m-%dT%H:%M:%S";
86+ break;
87+ default:
88+ eprintf("Invalid date format length\n", str);
89+ }
90+
91+ if (!strptime(str, format, &t))
92+ eprintf("strptime %s: Invalid date format\n", str);
93+ if (zulu) {
94+ t.tm_hour += t.tm_gmtoff / 60;
95+ t.tm_gmtoff = 0;
96+ t.tm_zone = "Z";
97+ }
98+
99+ return mktime(&t);
100+}
101+
102+static void
103+usage(void)
104+{
105+ eprintf("usage: %s [-acm] [-d time | -r ref_file | -t time | -T time] "
106+ "file ...\n", argv0);
107+}
108+
109+int
110+main(int argc, char *argv[])
111+{
112+ struct stat st;
113+ char *ref = NULL;
114+
115+ ARGBEGIN {
116+ case 'a':
117+ aflag = 1;
118+ break;
119+ case 'c':
120+ cflag = 1;
121+ break;
122+ case 'd':
123+ case 't':
124+ times[0].tv_sec = parsetime(EARGF(usage()));
125+ times[0].tv_nsec = 0;
126+ break;
127+ case 'm':
128+ mflag = 1;
129+ break;
130+ case 'r':
131+ ref = EARGF(usage());
132+ if (stat(ref, &st) < 0)
133+ eprintf("stat '%s':", ref);
134+ times[0] = st.st_atim;
135+ times[1] = st.st_mtim;
136+ break;
137+ case 'T':
138+ times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX);
139+ times[0].tv_nsec = 0;
140+ break;
141+ default:
142+ usage();
143+ } ARGEND
144+
145+ if (!argc)
146+ usage();
147+ if (!aflag && !mflag)
148+ aflag = mflag = 1;
149+ if (!ref)
150+ times[1] = times[0];
151+ if (!aflag)
152+ times[0].tv_nsec = UTIME_OMIT;
153+ if (!mflag)
154+ times[1].tv_nsec = UTIME_OMIT;
155+
156+ for (; *argv; argc--, argv++)
157+ touch(*argv);
158+
159+ return 0;
160+}
+318,
-0
1@@ -0,0 +1,318 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdlib.h>
4+
5+#include "utf.h"
6+#include "util.h"
7+
8+static int cflag = 0;
9+static int dflag = 0;
10+static int sflag = 0;
11+
12+struct range {
13+ Rune start;
14+ Rune end;
15+ size_t quant;
16+};
17+
18+static struct {
19+ char *name;
20+ int (*check)(Rune);
21+} classes[] = {
22+ { "alnum", isalnumrune },
23+ { "alpha", isalpharune },
24+ { "blank", isblankrune },
25+ { "cntrl", iscntrlrune },
26+ { "digit", isdigitrune },
27+ { "graph", isgraphrune },
28+ { "lower", islowerrune },
29+ { "print", isprintrune },
30+ { "punct", ispunctrune },
31+ { "space", isspacerune },
32+ { "upper", isupperrune },
33+ { "xdigit", isxdigitrune },
34+};
35+
36+#define ISLOWERBIT 1U << 6
37+#define ISUPPERBIT 1U << 10
38+
39+static struct range *set1 = NULL;
40+static size_t set1ranges = 0;
41+static unsigned set1checks = 0;
42+static struct range *set2 = NULL;
43+static size_t set2ranges = 0;
44+static unsigned set2checks = 0;
45+
46+static int
47+check(Rune rune, unsigned checks)
48+{
49+ size_t i;
50+
51+ for (i = 0; checks && i < LEN(classes); i++, checks >>= 1)
52+ if (checks & 1 && classes[i].check(rune))
53+ return 1;
54+
55+ return 0;
56+}
57+
58+static size_t
59+rangelen(struct range r)
60+{
61+ return (r.end - r.start + 1) * r.quant;
62+}
63+
64+static size_t
65+setlen(struct range *set, size_t setranges)
66+{
67+ size_t len = 0, i;
68+
69+ for (i = 0; i < setranges; i++)
70+ len += rangelen(set[i]);
71+
72+ return len;
73+}
74+
75+static int
76+rstrmatch(Rune *r, char *s, size_t n)
77+{
78+ size_t i;
79+
80+ for (i = 0; i < n; i++)
81+ if (r[i] != s[i])
82+ return 0;
83+ return 1;
84+}
85+
86+static size_t
87+makeset(char *str, struct range **set, unsigned *checks)
88+{
89+ Rune *rstr;
90+ size_t len, i, j, m, n;
91+ size_t q, setranges = 0;
92+ int factor, base;
93+
94+ /* rstr defines at most len ranges */
95+ unescape(str);
96+ rstr = ereallocarray(NULL, utflen(str) + 1, sizeof(*rstr));
97+ len = utftorunestr(str, rstr);
98+ *set = ereallocarray(NULL, len, sizeof(**set));
99+
100+ for (i = 0; i < len; i++) {
101+ if (rstr[i] == '[') {
102+ j = i;
103+nextbrack:
104+ if (j >= len)
105+ goto literal;
106+ for (m = j; m < len; m++)
107+ if (rstr[m] == ']') {
108+ j = m;
109+ break;
110+ }
111+ if (j == i)
112+ goto literal;
113+
114+ /* CLASSES [=EQUIV=] (skip) */
115+ if (j - i > 3 && rstr[i + 1] == '=' && rstr[m - 1] == '=') {
116+ if (j - i != 4)
117+ goto literal;
118+ (*set)[setranges].start = rstr[i + 2];
119+ (*set)[setranges].end = rstr[i + 2];
120+ (*set)[setranges].quant = 1;
121+ setranges++;
122+ i = j;
123+ continue;
124+ }
125+
126+ /* CLASSES [:CLASS:] */
127+ if (j - i > 3 && rstr[i + 1] == ':' && rstr[m - 1] == ':') {
128+ for (n = 0; n < LEN(classes); n++) {
129+ if (rstrmatch(rstr + i + 2, classes[n].name, j - i - 3)) {
130+ *checks |= 1 << n;
131+ i = j;
132+ break;
133+ }
134+ }
135+ if (n < LEN(classes))
136+ continue;
137+ eprintf("Invalid character class.\n");
138+ }
139+
140+ /* REPEAT [_*n] (only allowed in set2) */
141+ if (j - i > 2 && rstr[i + 2] == '*') {
142+ /* check if right side of '*' is a number */
143+ q = 0;
144+ factor = 1;
145+ base = (rstr[i + 3] == '0') ? 8 : 10;
146+ for (n = j - 1; n > i + 2; n--) {
147+ if (rstr[n] < '0' || rstr[n] > '9') {
148+ n = 0;
149+ break;
150+ }
151+ q += (rstr[n] - '0') * factor;
152+ factor *= base;
153+ }
154+ if (n == 0) {
155+ j = m + 1;
156+ goto nextbrack;
157+ }
158+ (*set)[setranges].start = rstr[i + 1];
159+ (*set)[setranges].end = rstr[i + 1];
160+ (*set)[setranges].quant = q ? q : setlen(set1, MAX(set1ranges, 1));
161+ setranges++;
162+ i = j;
163+ continue;
164+ }
165+
166+ j = m + 1;
167+ goto nextbrack;
168+ }
169+literal:
170+ /* RANGES [_-__-_], _-__-_ */
171+ /* LITERALS _______ */
172+ (*set)[setranges].start = rstr[i];
173+
174+ if (i < len - 2 && rstr[i + 1] == '-' && rstr[i + 2] >= rstr[i])
175+ i += 2;
176+ (*set)[setranges].end = rstr[i];
177+ (*set)[setranges].quant = 1;
178+ setranges++;
179+ }
180+
181+ free(rstr);
182+ return setranges;
183+}
184+
185+static void
186+usage(void)
187+{
188+ eprintf("usage: %s [-cCds] set1 [set2]\n", argv0);
189+}
190+
191+int
192+main(int argc, char *argv[])
193+{
194+ Rune r, lastrune = 0;
195+ size_t off1, off2, i, m;
196+ int ret = 0;
197+
198+ ARGBEGIN {
199+ case 'c':
200+ case 'C':
201+ cflag = 1;
202+ break;
203+ case 'd':
204+ dflag = 1;
205+ break;
206+ case 's':
207+ sflag = 1;
208+ break;
209+ default:
210+ usage();
211+ } ARGEND
212+
213+ if (!argc || argc > 2 || (dflag == sflag && argc != 2) ||
214+ (dflag && argc != 1))
215+ usage();
216+
217+ set1ranges = makeset(argv[0], &set1, &set1checks);
218+ if (argc == 2) {
219+ set2ranges = makeset(argv[1], &set2, &set2checks);
220+ /* sanity checks as we are translating */
221+ if (!set2ranges && !set2checks)
222+ eprintf("cannot map to an empty set.\n");
223+ if (set2checks && set2checks != ISLOWERBIT &&
224+ set2checks != ISUPPERBIT) {
225+ eprintf("can only map to 'lower' and 'upper' class.\n");
226+ }
227+ }
228+read:
229+ if (!efgetrune(&r, stdin, "<stdin>")) {
230+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
231+ return ret;
232+ }
233+ if (argc == 1 && sflag)
234+ goto write;
235+ for (i = 0, off1 = 0; i < set1ranges; off1 += rangelen(set1[i]), i++) {
236+ if (set1[i].start <= r && r <= set1[i].end) {
237+ if (dflag) {
238+ if (cflag)
239+ goto write;
240+ else
241+ goto read;
242+ }
243+ if (cflag)
244+ goto write;
245+
246+ /* map r to set2 */
247+ if (set2checks) {
248+ if (set2checks == ISLOWERBIT)
249+ r = tolowerrune(r);
250+ else
251+ r = toupperrune(r);
252+ } else {
253+ off1 += r - set1[i].start;
254+ if (off1 > setlen(set2, set2ranges) - 1) {
255+ r = set2[set2ranges - 1].end;
256+ goto write;
257+ }
258+ for (m = 0, off2 = 0; m < set2ranges; m++) {
259+ if (off2 + rangelen(set2[m]) > off1) {
260+ m++;
261+ break;
262+ }
263+ off2 += rangelen(set2[m]);
264+ }
265+ m--;
266+ r = set2[m].start + (off1 - off2) / set2[m].quant;
267+ }
268+ goto write;
269+ }
270+ }
271+ if (check(r, set1checks)) {
272+ if (cflag)
273+ goto write;
274+ if (dflag)
275+ goto read;
276+ if (set2checks) {
277+ if (set2checks == ISLOWERBIT)
278+ r = tolowerrune(r);
279+ else
280+ r = toupperrune(r);
281+ } else {
282+ r = set2[set2ranges - 1].end;
283+ }
284+ goto write;
285+ }
286+ if (!dflag && cflag) {
287+ if (set2checks) {
288+ if (set2checks == ISLOWERBIT)
289+ r = tolowerrune(r);
290+ else
291+ r = toupperrune(r);
292+ } else {
293+ r = set2[set2ranges - 1].end;
294+ }
295+ goto write;
296+ }
297+ if (dflag && cflag)
298+ goto read;
299+write:
300+ if (argc == 1 && sflag && r == lastrune) {
301+ if (check(r, set1checks))
302+ goto read;
303+ for (i = 0; i < set1ranges; i++) {
304+ if (set1[i].start <= r && r <= set1[i].end)
305+ goto read;
306+ }
307+ }
308+ if (argc == 2 && sflag && r == lastrune) {
309+ if (set2checks && check(r, set2checks))
310+ goto read;
311+ for (i = 0; i < set2ranges; i++) {
312+ if (set2[i].start <= r && r <= set2[i].end)
313+ goto read;
314+ }
315+ }
316+ efputrune(&r, stdout, "<stdout>");
317+ lastrune = r;
318+ goto read;
319+}
+6,
-0
1@@ -0,0 +1,6 @@
2+/* See LICENSE file for copyright and license details. */
3+int
4+main(void)
5+{
6+ return 0;
7+}
+209,
-0
1@@ -0,0 +1,209 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <string.h>
5+#include <stdlib.h>
6+#include <ctype.h>
7+
8+#include "util.h"
9+
10+enum { WHITE = 0, GREY, BLACK };
11+
12+struct vertex;
13+
14+struct edge {
15+ struct vertex *to;
16+ struct edge *next;
17+};
18+
19+struct vertex {
20+ char *name;
21+ struct vertex *next;
22+ struct edge edges;
23+ size_t in_edges;
24+ int colour;
25+};
26+
27+static struct vertex graph;
28+
29+static void
30+find_vertex(const char *name, struct vertex **it, struct vertex **prev)
31+{
32+ for (*prev = &graph; (*it = (*prev)->next); *prev = *it) {
33+ int cmp = strcmp(name, (*it)->name);
34+ if (cmp > 0)
35+ continue;
36+ if (cmp < 0)
37+ *it = 0;
38+ return;
39+ }
40+}
41+
42+static void
43+find_edge(struct vertex *from, const char *to, struct edge **it, struct edge **prev)
44+{
45+ for (*prev = &(from->edges); (*it = (*prev)->next); *prev = *it) {
46+ int cmp = strcmp(to, (*it)->to->name);
47+ if (cmp > 0)
48+ continue;
49+ if (cmp < 0)
50+ *it = 0;
51+ return;
52+ }
53+}
54+
55+static struct vertex *
56+add_vertex(char *name)
57+{
58+ struct vertex *vertex;
59+ struct vertex *prev;
60+
61+ find_vertex(name, &vertex, &prev);
62+ if (vertex)
63+ return vertex;
64+
65+ vertex = encalloc(2, 1, sizeof(*vertex));
66+ vertex->name = name;
67+ vertex->next = prev->next;
68+ prev->next = vertex;
69+
70+ return vertex;
71+}
72+
73+static struct edge *
74+add_edge(struct vertex *from, struct vertex* to)
75+{
76+ struct edge *edge;
77+ struct edge *prev;
78+
79+ find_edge(from, to->name, &edge, &prev);
80+ if (edge)
81+ return edge;
82+
83+ edge = encalloc(2, 1, sizeof(*edge));
84+ edge->to = to;
85+ edge->next = prev->next;
86+ prev->next = edge;
87+ to->in_edges += 1;
88+
89+ return edge;
90+}
91+
92+static void
93+load_graph(FILE *fp)
94+{
95+#define SKIP(VAR, START, FUNC) for (VAR = START; FUNC(*VAR) && *VAR; VAR++)
96+#define TOKEN_END(P) do { if (*P) *P++ = 0; else P = 0; } while (0)
97+
98+ char *line = 0;
99+ size_t size = 0;
100+ ssize_t len;
101+ char *p;
102+ char *name;
103+ struct vertex *from = 0;
104+
105+ while ((len = getline(&line, &size, fp)) != -1) {
106+ if (line[len - 1] == '\n')
107+ line[--len] = 0;
108+ for (p = line; p;) {
109+ SKIP(name, p, isspace);
110+ if (!*name)
111+ break;
112+ SKIP(p, name, !isspace);
113+ TOKEN_END(p);
114+ if (!from) {
115+ from = add_vertex(enstrdup(2, name));
116+ } else if (strcmp(from->name, name)) {
117+ add_edge(from, add_vertex(enstrdup(2, name)));
118+ from = 0;
119+ } else {
120+ from = 0;
121+ }
122+ }
123+ }
124+
125+ free(line);
126+
127+ if (from)
128+ enprintf(2, "odd number of tokens in input\n");
129+}
130+
131+static int
132+sort_graph_visit(struct vertex *u)
133+{
134+ struct edge *e = &(u->edges);
135+ struct vertex *v;
136+ int r = 0;
137+ u->colour = GREY;
138+ printf("%s\n", u->name);
139+ while ((e = e->next)) {
140+ v = e->to;
141+ if (v->colour == WHITE) {
142+ v->in_edges -= 1;
143+ if (v->in_edges == 0)
144+ r |= sort_graph_visit(v);
145+ } else if (v->colour == GREY) {
146+ r = 1;
147+ fprintf(stderr, "%s: loop detected between %s and %s\n",
148+ argv0, u->name, v->name);
149+ }
150+ }
151+ u->colour = BLACK;
152+ return r;
153+}
154+
155+static int
156+sort_graph(void)
157+{
158+ struct vertex *u, *prev;
159+ int r = 0;
160+ size_t in_edges;
161+ for (in_edges = 0; graph.next; in_edges++) {
162+ for (prev = &graph; (u = prev->next); prev = u) {
163+ if (u->colour != WHITE)
164+ goto unlist;
165+ if (u->in_edges > in_edges)
166+ continue;
167+ r |= sort_graph_visit(u);
168+ unlist:
169+ prev->next = u->next;
170+ u = prev;
171+ }
172+ }
173+ return r;
174+}
175+
176+static void
177+usage(void)
178+{
179+ enprintf(2, "usage: %s [file]\n", argv0);
180+}
181+
182+int
183+main(int argc, char *argv[])
184+{
185+ FILE *fp = stdin;
186+ const char *fn = "<stdin>";
187+ int ret = 0;
188+
189+ ARGBEGIN {
190+ default:
191+ usage();
192+ } ARGEND
193+
194+ if (argc > 1)
195+ usage();
196+ if (argc && strcmp(*argv, "-"))
197+ if (!(fp = fopen(fn = *argv, "r")))
198+ enprintf(2, "fopen %s:", *argv);
199+
200+ memset(&graph, 0, sizeof(graph));
201+ load_graph(fp);
202+ enfshut(2, fp, fn);
203+
204+ ret = sort_graph();
205+
206+ if (fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>"))
207+ ret = 2;
208+
209+ return ret;
210+}
+31,
-0
1@@ -0,0 +1,31 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <unistd.h>
5+
6+#include "util.h"
7+
8+static void
9+usage(void)
10+{
11+ enprintf(2, "usage: %s\n", argv0);
12+}
13+
14+int
15+main(int argc, char *argv[])
16+{
17+ char *tty;
18+
19+ ARGBEGIN {
20+ default:
21+ usage();
22+ } ARGEND
23+
24+ if (argc)
25+ usage();
26+
27+ tty = ttyname(STDIN_FILENO);
28+ puts(tty ? tty : "not a tty");
29+
30+ enfshut(2, stdout, "<stdout>");
31+ return !tty;
32+}
+62,
-0
1@@ -0,0 +1,62 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/utsname.h>
4+
5+#include <stdio.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [-amnrsv]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ struct utsname u;
19+ int mflag = 0, nflag = 0, rflag = 0, sflag = 0, vflag = 0;
20+
21+ ARGBEGIN {
22+ case 'a':
23+ mflag = nflag = rflag = sflag = vflag = 1;
24+ break;
25+ case 'm':
26+ mflag = 1;
27+ break;
28+ case 'n':
29+ nflag = 1;
30+ break;
31+ case 'r':
32+ rflag = 1;
33+ break;
34+ case 's':
35+ sflag = 1;
36+ break;
37+ case 'v':
38+ vflag = 1;
39+ break;
40+ default:
41+ usage();
42+ } ARGEND
43+
44+ if (argc)
45+ usage();
46+
47+ if (uname(&u) < 0)
48+ eprintf("uname:");
49+
50+ if (sflag || !(nflag || rflag || vflag || mflag))
51+ putword(stdout, u.sysname);
52+ if (nflag)
53+ putword(stdout, u.nodename);
54+ if (rflag)
55+ putword(stdout, u.release);
56+ if (vflag)
57+ putword(stdout, u.version);
58+ if (mflag)
59+ putword(stdout, u.machine);
60+ putchar('\n');
61+
62+ return fshut(stdout, "<stdout>");
63+}
+174,
-0
1@@ -0,0 +1,174 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "utf.h"
8+#include "util.h"
9+
10+static int aflag = 0;
11+static size_t *tablist = NULL;
12+static size_t tablistlen = 8;
13+
14+static size_t
15+parselist(const char *s)
16+{
17+ size_t i;
18+ char *p, *tmp;
19+
20+ tmp = estrdup(s);
21+ for (i = 0; (p = strsep(&tmp, " ,")); i++) {
22+ if (*p == '\0')
23+ eprintf("empty field in tablist\n");
24+ tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
25+ tablist[i] = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
26+ if (i > 0 && tablist[i - 1] >= tablist[i])
27+ eprintf("tablist must be ascending\n");
28+ }
29+ tablist = ereallocarray(tablist, i + 1, sizeof(*tablist));
30+
31+ return i;
32+}
33+
34+static void
35+unexpandspan(size_t last, size_t col)
36+{
37+ size_t off, i, j;
38+ Rune r;
39+
40+ if (tablistlen == 1) {
41+ i = 0;
42+ off = last % tablist[i];
43+
44+ if ((col - last) + off >= tablist[i] && last < col)
45+ last -= off;
46+
47+ r = '\t';
48+ for (; last + tablist[i] <= col; last += tablist[i])
49+ efputrune(&r, stdout, "<stdout>");
50+ r = ' ';
51+ for (; last < col; last++)
52+ efputrune(&r, stdout, "<stdout>");
53+ } else {
54+ for (i = 0; i < tablistlen; i++)
55+ if (col < tablist[i])
56+ break;
57+ for (j = 0; j < tablistlen; j++)
58+ if (last < tablist[j])
59+ break;
60+ r = '\t';
61+ for (; j < i; j++) {
62+ efputrune(&r, stdout, "<stdout>");
63+ last = tablist[j];
64+ }
65+ r = ' ';
66+ for (; last < col; last++)
67+ efputrune(&r, stdout, "<stdout>");
68+ }
69+}
70+
71+static void
72+unexpand(const char *file, FILE *fp)
73+{
74+ Rune r;
75+ size_t last = 0, col = 0, i;
76+ int bol = 1;
77+
78+ while (efgetrune(&r, fp, file)) {
79+ switch (r) {
80+ case ' ':
81+ if (!bol && !aflag)
82+ last++;
83+ col++;
84+ break;
85+ case '\t':
86+ if (tablistlen == 1) {
87+ if (!bol && !aflag)
88+ last += tablist[0] - col % tablist[0];
89+ col += tablist[0] - col % tablist[0];
90+ } else {
91+ for (i = 0; i < tablistlen; i++)
92+ if (col < tablist[i])
93+ break;
94+ if (!bol && !aflag)
95+ last = tablist[i];
96+ col = tablist[i];
97+ }
98+ break;
99+ case '\b':
100+ if (bol || aflag)
101+ unexpandspan(last, col);
102+ col -= (col > 0);
103+ last = col;
104+ bol = 0;
105+ break;
106+ case '\n':
107+ if (bol || aflag)
108+ unexpandspan(last, col);
109+ last = col = 0;
110+ bol = 1;
111+ break;
112+ default:
113+ if (bol || aflag)
114+ unexpandspan(last, col);
115+ last = ++col;
116+ bol = 0;
117+ break;
118+ }
119+ if ((r != ' ' && r != '\t') || (!aflag && !bol))
120+ efputrune(&r, stdout, "<stdout>");
121+ }
122+ if (last < col && (bol || aflag))
123+ unexpandspan(last, col);
124+}
125+
126+static void
127+usage(void)
128+{
129+ eprintf("usage: %s [-a] [-t tablist] [file ...]\n", argv0);
130+}
131+
132+int
133+main(int argc, char *argv[])
134+{
135+ FILE *fp;
136+ int ret = 0;
137+ char *tl = "8";
138+
139+ ARGBEGIN {
140+ case 't':
141+ tl = EARGF(usage());
142+ if (!*tl)
143+ eprintf("tablist cannot be empty\n");
144+ /* Fallthrough: -t implies -a */
145+ case 'a':
146+ aflag = 1;
147+ break;
148+ default:
149+ usage();
150+ } ARGEND
151+
152+ tablistlen = parselist(tl);
153+
154+ if (!argc) {
155+ unexpand("<stdin>", stdin);
156+ } else {
157+ for (; *argv; argc--, argv++) {
158+ if (!strcmp(*argv, "-")) {
159+ *argv = "<stdin>";
160+ fp = stdin;
161+ } else if (!(fp = fopen(*argv, "r"))) {
162+ weprintf("fopen %s:", *argv);
163+ ret = 1;
164+ continue;
165+ }
166+ unexpand(*argv, fp);
167+ if (fp != stdin && fshut(fp, *argv))
168+ ret = 1;
169+ }
170+ }
171+
172+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
173+
174+ return ret;
175+}
+144,
-0
1@@ -0,0 +1,144 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "text.h"
9+#include "util.h"
10+
11+static const char *countfmt = "";
12+static int dflag = 0;
13+static int uflag = 0;
14+static int fskip = 0;
15+static int sskip = 0;
16+
17+static struct line prevl;
18+static ssize_t prevoff = -1;
19+static long prevlinecount = 0;
20+
21+static size_t
22+uniqskip(struct line *l)
23+{
24+ size_t i;
25+ int f = fskip, s = sskip;
26+
27+ for (i = 0; i < l->len && f; --f) {
28+ while (isblank(l->data[i]))
29+ i++;
30+ while (i < l->len && !isblank(l->data[i]))
31+ i++;
32+ }
33+ for (; s && i < l->len && l->data[i] != '\n'; --s, i++)
34+ ;
35+
36+ return i;
37+}
38+
39+static void
40+uniqline(FILE *ofp, struct line *l)
41+{
42+ size_t loff;
43+
44+ if (l) {
45+ loff = uniqskip(l);
46+
47+ if (prevoff >= 0 && (l->len - loff) == (prevl.len - prevoff) &&
48+ !memcmp(l->data + loff, prevl.data + prevoff, l->len - loff)) {
49+ ++prevlinecount;
50+ return;
51+ }
52+ }
53+
54+ if (prevoff >= 0) {
55+ if ((prevlinecount == 1 && !dflag) ||
56+ (prevlinecount != 1 && !uflag)) {
57+ if (*countfmt)
58+ fprintf(ofp, countfmt, prevlinecount);
59+ fwrite(prevl.data, 1, prevl.len, ofp);
60+ }
61+ prevoff = -1;
62+ }
63+
64+ if (l) {
65+ if (!prevl.data || l->len >= prevl.len) {
66+ prevl.data = erealloc(prevl.data, l->len);
67+ }
68+ prevl.len = l->len;
69+ memcpy(prevl.data, l->data, prevl.len);
70+ prevoff = loff;
71+ }
72+ prevlinecount = 1;
73+}
74+
75+static void
76+uniq(FILE *fp, FILE *ofp)
77+{
78+ static struct line line;
79+ static size_t size;
80+ ssize_t len;
81+
82+ while ((len = getline(&line.data, &size, fp)) > 0) {
83+ line.len = len;
84+ uniqline(ofp, &line);
85+ }
86+}
87+
88+static void
89+uniqfinish(FILE *ofp)
90+{
91+ uniqline(ofp, NULL);
92+}
93+
94+static void
95+usage(void)
96+{
97+ eprintf("usage: %s [-c] [-d | -u] [-f fields] [-s chars]"
98+ " [input [output]]\n", argv0);
99+}
100+
101+int
102+main(int argc, char *argv[])
103+{
104+ FILE *fp[2] = { stdin, stdout };
105+ int ret = 0, i;
106+ char *fname[2] = { "<stdin>", "<stdout>" };
107+
108+ ARGBEGIN {
109+ case 'c':
110+ countfmt = "%7ld ";
111+ break;
112+ case 'd':
113+ dflag = 1;
114+ break;
115+ case 'u':
116+ uflag = 1;
117+ break;
118+ case 'f':
119+ fskip = estrtonum(EARGF(usage()), 0, INT_MAX);
120+ break;
121+ case 's':
122+ sskip = estrtonum(EARGF(usage()), 0, INT_MAX);
123+ break;
124+ default:
125+ usage();
126+ } ARGEND
127+
128+ if (argc > 2)
129+ usage();
130+
131+ for (i = 0; i < argc; i++) {
132+ if (strcmp(argv[i], "-")) {
133+ fname[i] = argv[i];
134+ if (!(fp[i] = fopen(argv[i], (i == 0) ? "r" : "w")))
135+ eprintf("fopen %s:", argv[i]);
136+ }
137+ }
138+
139+ uniq(fp[0], fp[1]);
140+ uniqfinish(fp[1]);
141+
142+ ret |= fshut(fp[0], fname[0]) | fshut(fp[1], fname[1]);
143+
144+ return ret;
145+}
+27,
-0
1@@ -0,0 +1,27 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <unistd.h>
4+
5+#include "util.h"
6+
7+static void
8+usage(void)
9+{
10+ eprintf("usage: %s file\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+ ARGBEGIN {
17+ default:
18+ usage();
19+ } ARGEND
20+
21+ if (argc != 1)
22+ usage();
23+
24+ if (unlink(argv[0]) < 0)
25+ eprintf("unlink: '%s':", argv[0]);
26+
27+ return 0;
28+}
+282,
-0
1@@ -0,0 +1,282 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "util.h"
11+
12+static int mflag = 0;
13+static int oflag = 0;
14+
15+static FILE *
16+parsefile(const char *fname)
17+{
18+ struct stat st;
19+ int ret;
20+
21+ if (!strcmp(fname, "/dev/stdout") || !strcmp(fname, "-"))
22+ return stdout;
23+ ret = lstat(fname, &st);
24+ /* if it is a new file, try to open it */
25+ if (ret < 0 && errno == ENOENT)
26+ goto tropen;
27+ if (ret < 0) {
28+ weprintf("lstat %s:", fname);
29+ return NULL;
30+ }
31+ if (!S_ISREG(st.st_mode)) {
32+ weprintf("for safety uudecode operates only on regular files and /dev/stdout\n");
33+ return NULL;
34+ }
35+tropen:
36+ return fopen(fname, "w");
37+}
38+
39+static void
40+parseheader(FILE *fp, const char *s, char **header, mode_t *mode, char **fname)
41+{
42+ static char bufs[PATH_MAX + 18]; /* len header + mode + maxname */
43+ char *p, *q;
44+ size_t n;
45+
46+ if (!fgets(bufs, sizeof(bufs), fp))
47+ if (ferror(fp))
48+ eprintf("%s: read error:", s);
49+ if (bufs[0] == '\0' || feof(fp))
50+ eprintf("empty or nil header string\n");
51+ if (!(p = strchr(bufs, '\n')))
52+ eprintf("header string too long or non-newline terminated file\n");
53+ p = bufs;
54+ if (!(q = strchr(p, ' ')))
55+ eprintf("malformed mode string in header, expected ' '\n");
56+ *header = bufs;
57+ *q++ = '\0';
58+ p = q;
59+ /* now header should be null terminated, q points to mode */
60+ if (!(q = strchr(p, ' ')))
61+ eprintf("malformed mode string in header, expected ' '\n");
62+ *q++ = '\0';
63+ /* now mode should be null terminated, q points to fname */
64+ *mode = parsemode(p, *mode, 0);
65+ n = strlen(q);
66+ while (n > 0 && (q[n - 1] == '\n' || q[n - 1] == '\r'))
67+ q[--n] = '\0';
68+ if (n > 0)
69+ *fname = q;
70+ else
71+ eprintf("header string does not contain output file\n");
72+}
73+
74+static const char b64dt[] = {
75+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
76+ -1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
77+ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1, 0,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6,
78+ 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
79+ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
80+ 49,50,51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
81+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
82+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
83+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
84+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
85+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
86+};
87+
88+static void
89+uudecodeb64(FILE *fp, FILE *outfp)
90+{
91+ char bufb[60], *pb;
92+ char out[45], *po;
93+ size_t n;
94+ int b = 0, e, t = -1, l = 1;
95+ unsigned char b24[3] = {0, 0, 0};
96+
97+ while ((n = fread(bufb, 1, sizeof(bufb), fp))) {
98+ for (pb = bufb, po = out; pb < bufb + n; pb++) {
99+ if (*pb == '\n') {
100+ l++;
101+ continue;
102+ } else if (*pb == '=') {
103+ switch (b) {
104+ case 0:
105+ /* expected '=' remaining
106+ * including footer */
107+ if (--t) {
108+ fwrite(out, 1,
109+ (po - out),
110+ outfp);
111+ return;
112+ }
113+ continue;
114+ case 1:
115+ eprintf("%d: unexpected \"=\""
116+ "appeared\n", l);
117+ case 2:
118+ *po++ = b24[0];
119+ b = 0;
120+ t = 5; /* expect 5 '=' */
121+ continue;
122+ case 3:
123+ *po++ = b24[0];
124+ *po++ = b24[1];
125+ b = 0;
126+ t = 6; /* expect 6 '=' */
127+ continue;
128+ }
129+ } else if ((e = b64dt[(int)*pb]) == -1)
130+ eprintf("%d: invalid byte \"%c\"\n", l, *pb);
131+ else if (e == -2) /* whitespace */
132+ continue;
133+ else if (t > 0) /* state is parsing pad/footer */
134+ eprintf("%d: invalid byte \"%c\""
135+ " after padding\n",
136+ l, *pb);
137+ switch (b) { /* decode next base64 chr based on state */
138+ case 0: b24[0] |= e << 2; break;
139+ case 1: b24[0] |= (e >> 4) & 0x3;
140+ b24[1] |= (e & 0xf) << 4; break;
141+ case 2: b24[1] |= (e >> 2) & 0xf;
142+ b24[2] |= (e & 0x3) << 6; break;
143+ case 3: b24[2] |= e; break;
144+ }
145+ if (++b == 4) { /* complete decoding an octet */
146+ *po++ = b24[0];
147+ *po++ = b24[1];
148+ *po++ = b24[2];
149+ b24[0] = b24[1] = b24[2] = 0;
150+ b = 0;
151+ }
152+ }
153+ fwrite(out, 1, (po - out), outfp);
154+ }
155+ eprintf("%d: invalid uudecode footer \"====\" not found\n", l);
156+}
157+
158+static void
159+uudecode(FILE *fp, FILE *outfp)
160+{
161+ char *bufb = NULL, *p;
162+ size_t n = 0;
163+ ssize_t len;
164+ int ch, i;
165+
166+#define DEC(c) (((c) - ' ') & 077) /* single character decode */
167+#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
168+#define OUT_OF_RANGE(c) eprintf("character %c out of range: [%d-%d]\n", (c), 1 + ' ', 077 + ' ' + 1)
169+
170+ while ((len = getline(&bufb, &n, fp)) > 0) {
171+ p = bufb;
172+ /* trim newlines */
173+ if (!len || bufb[len - 1] != '\n')
174+ eprintf("no newline found, aborting\n");
175+ bufb[len - 1] = '\0';
176+
177+ /* check for last line */
178+ if ((i = DEC(*p)) <= 0)
179+ break;
180+ for (++p; i > 0; p += 4, i -= 3) {
181+ if (i >= 3) {
182+ if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
183+ IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
184+ OUT_OF_RANGE(*p);
185+
186+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
187+ putc(ch, outfp);
188+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
189+ putc(ch, outfp);
190+ ch = DEC(p[2]) << 6 | DEC(p[3]);
191+ putc(ch, outfp);
192+ } else {
193+ if (i >= 1) {
194+ if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
195+ OUT_OF_RANGE(*p);
196+
197+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
198+ putc(ch, outfp);
199+ }
200+ if (i >= 2) {
201+ if (!(IS_DEC(*(p + 1)) &&
202+ IS_DEC(*(p + 2))))
203+ OUT_OF_RANGE(*p);
204+
205+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
206+ putc(ch, outfp);
207+ }
208+ }
209+ }
210+ if (ferror(fp))
211+ eprintf("read error:");
212+ }
213+ /* check for end or fail */
214+ if ((len = getline(&bufb, &n, fp)) < 0)
215+ eprintf("getline:");
216+ if (len < 3 || strncmp(bufb, "end", 3) || bufb[3] != '\n')
217+ eprintf("invalid uudecode footer \"end\" not found\n");
218+ free(bufb);
219+}
220+
221+static void
222+usage(void)
223+{
224+ eprintf("usage: %s [-m] [-o output] [file]\n", argv0);
225+}
226+
227+int
228+main(int argc, char *argv[])
229+{
230+ FILE *fp = NULL, *nfp = NULL;
231+ mode_t mode = 0;
232+ int ret = 0;
233+ char *fname, *header, *ifname, *ofname = NULL;
234+ void (*d) (FILE *, FILE *) = NULL;
235+
236+ ARGBEGIN {
237+ case 'm':
238+ mflag = 1; /* accepted but unused (autodetect file type) */
239+ break;
240+ case 'o':
241+ oflag = 1;
242+ ofname = EARGF(usage());
243+ break;
244+ default:
245+ usage();
246+ } ARGEND
247+
248+ if (argc > 1)
249+ usage();
250+
251+ if (!argc || !strcmp(argv[0], "-")) {
252+ fp = stdin;
253+ ifname = "<stdin>";
254+ } else {
255+ if (!(fp = fopen(argv[0], "r")))
256+ eprintf("fopen %s:", argv[0]);
257+ ifname = argv[0];
258+ }
259+
260+ parseheader(fp, ifname, &header, &mode, &fname);
261+
262+ if (!strncmp(header, "begin", sizeof("begin")))
263+ d = uudecode;
264+ else if (!strncmp(header, "begin-base64", sizeof("begin-base64")))
265+ d = uudecodeb64;
266+ else
267+ eprintf("unknown header %s:", header);
268+
269+ if (oflag)
270+ fname = ofname;
271+ if (!(nfp = parsefile(fname)))
272+ eprintf("fopen %s:", fname);
273+
274+ d(fp, nfp);
275+
276+ if (nfp != stdout && chmod(fname, mode) < 0)
277+ eprintf("chmod %s:", fname);
278+
279+ ret |= fshut(fp, (fp == stdin) ? "<stdin>" : argv[0]);
280+ ret |= fshut(nfp, (nfp == stdout) ? "<stdout>" : fname);
281+
282+ return ret;
283+}
+129,
-0
1@@ -0,0 +1,129 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <stdio.h>
6+#include <string.h>
7+
8+#include "util.h"
9+
10+static unsigned int
11+b64e(unsigned char *b)
12+{
13+ unsigned int o, p = b[2] | (b[1] << 8) | (b[0] << 16);
14+ const char b64et[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15+
16+ o = b64et[p & 0x3f]; p >>= 6;
17+ o = (o << 8) | b64et[p & 0x3f]; p >>= 6;
18+ o = (o << 8) | b64et[p & 0x3f]; p >>= 6;
19+ o = (o << 8) | b64et[p & 0x3f];
20+
21+ return o;
22+}
23+
24+static void
25+uuencodeb64(FILE *fp, const char *name, const char *s)
26+{
27+ struct stat st;
28+ ssize_t n, m = 0;
29+ unsigned char buf[45], *pb;
30+ unsigned int out[sizeof(buf)/3 + 1], *po;
31+
32+ if (fstat(fileno(fp), &st) < 0)
33+ eprintf("fstat %s:", s);
34+ printf("begin-base64 %o %s\n", st.st_mode & 0777, name);
35+ /* write line by line */
36+ while ((n = fread(buf, 1, sizeof(buf), fp))) {
37+ /* clear old buffer if converting with non-multiple of 3 */
38+ if (n != sizeof(buf) && (m = n % 3) != 0) {
39+ buf[n] = '\0'; /* m == 2 */
40+ if (m == 1) buf[n+1] = '\0'; /* m == 1 */
41+ }
42+ for (pb = buf, po = out; pb < buf + n; pb += 3)
43+ *po++ = b64e(pb);
44+ if (m != 0) {
45+ unsigned int mask = 0xffffffff, dest = 0x3d3d3d3d;
46+ /* m==2 -> 0x00ffffff; m==1 -> 0x0000ffff */
47+ mask >>= ((3-m) << 3);
48+ po[-1] = (po[-1] & mask) | (dest & ~mask);
49+ }
50+ *po++ = '\n';
51+ fwrite(out, 1, (po - out) * sizeof(unsigned int) - 3, stdout);
52+ }
53+ if (ferror(fp))
54+ eprintf("'%s' read error:", s);
55+ puts("====");
56+}
57+
58+static void
59+uuencode(FILE *fp, const char *name, const char *s)
60+{
61+ struct stat st;
62+ unsigned char buf[45], *p;
63+ ssize_t n;
64+ int ch;
65+
66+ if (fstat(fileno(fp), &st) < 0)
67+ eprintf("fstat %s:", s);
68+ printf("begin %o %s\n", st.st_mode & 0777, name);
69+ while ((n = fread(buf, 1, sizeof(buf), fp))) {
70+ ch = ' ' + (n & 0x3f);
71+ putchar(ch == ' ' ? '`' : ch);
72+ for (p = buf; n > 0; n -= 3, p += 3) {
73+ if (n < 3) {
74+ p[2] = '\0';
75+ if (n < 2)
76+ p[1] = '\0';
77+ }
78+ ch = ' ' + ((p[0] >> 2) & 0x3f);
79+ putchar(ch == ' ' ? '`' : ch);
80+ ch = ' ' + (((p[0] << 4) | ((p[1] >> 4) & 0xf)) & 0x3f);
81+ putchar(ch == ' ' ? '`' : ch);
82+ ch = ' ' + (((p[1] << 2) | ((p[2] >> 6) & 0x3)) & 0x3f);
83+ putchar(ch == ' ' ? '`' : ch);
84+ ch = ' ' + (p[2] & 0x3f);
85+ putchar(ch == ' ' ? '`' : ch);
86+ }
87+ putchar('\n');
88+ }
89+ if (ferror(fp))
90+ eprintf("'%s' read error:", s);
91+ printf("%c\nend\n", '`');
92+}
93+
94+static void
95+usage(void)
96+{
97+ eprintf("usage: %s [-m] [file] name\n", argv0);
98+}
99+
100+int
101+main(int argc, char *argv[])
102+{
103+ FILE *fp = NULL;
104+ void (*uuencode_f)(FILE *, const char *, const char *) = uuencode;
105+ int ret = 0;
106+
107+ ARGBEGIN {
108+ case 'm':
109+ uuencode_f = uuencodeb64;
110+ break;
111+ default:
112+ usage();
113+ } ARGEND
114+
115+ if (!argc || argc > 2)
116+ usage();
117+
118+ if (argc == 1 || !strcmp(argv[0], "-")) {
119+ uuencode_f(stdin, argv[0], "<stdin>");
120+ } else {
121+ if (!(fp = fopen(argv[0], "r")))
122+ eprintf("fopen %s:", argv[0]);
123+ uuencode_f(fp, argv[1], argv[0]);
124+ }
125+
126+ ret |= fp && fshut(fp, argv[0]);
127+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
128+
129+ return ret;
130+}
+122,
-0
1@@ -0,0 +1,122 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <string.h>
4+
5+#include "utf.h"
6+#include "util.h"
7+
8+static int lflag = 0;
9+static int wflag = 0;
10+static char cmode = 0;
11+static size_t tc = 0, tl = 0, tw = 0;
12+
13+static void
14+output(const char *str, size_t nc, size_t nl, size_t nw)
15+{
16+ int first = 1;
17+
18+ if (lflag) {
19+ first = 0;
20+ printf("%zu", nl);
21+ }
22+ if (wflag) {
23+ if (!first)
24+ putchar(' ');
25+ first = 0;
26+ printf("%zu", nw);
27+ }
28+ if (cmode) {
29+ if (!first)
30+ putchar(' ');
31+ printf("%zu", nc);
32+ }
33+ if (str)
34+ printf(" %s", str);
35+ putchar('\n');
36+}
37+
38+static void
39+wc(FILE *fp, const char *str)
40+{
41+ int word = 0, rlen;
42+ Rune c;
43+ size_t nc = 0, nl = 0, nw = 0;
44+
45+ while ((rlen = efgetrune(&c, fp, str))) {
46+ nc += (cmode == 'c') ? rlen : (c != Runeerror);
47+ if (c == '\n')
48+ nl++;
49+ if (!isspacerune(c))
50+ word = 1;
51+ else if (word) {
52+ word = 0;
53+ nw++;
54+ }
55+ }
56+ if (word)
57+ nw++;
58+ tc += nc;
59+ tl += nl;
60+ tw += nw;
61+ output(str, nc, nl, nw);
62+}
63+
64+static void
65+usage(void)
66+{
67+ eprintf("usage: %s [-c | -m] [-lw] [file ...]\n", argv0);
68+}
69+
70+int
71+main(int argc, char *argv[])
72+{
73+ FILE *fp;
74+ int many;
75+ int ret = 0;
76+
77+ ARGBEGIN {
78+ case 'c':
79+ cmode = 'c';
80+ break;
81+ case 'm':
82+ cmode = 'm';
83+ break;
84+ case 'l':
85+ lflag = 1;
86+ break;
87+ case 'w':
88+ wflag = 1;
89+ break;
90+ default:
91+ usage();
92+ } ARGEND
93+
94+ if (!lflag && !wflag && !cmode) {
95+ cmode = 'c';
96+ lflag = 1;
97+ wflag = 1;
98+ }
99+
100+ if (!argc) {
101+ wc(stdin, NULL);
102+ } else {
103+ for (many = (argc > 1); *argv; argc--, argv++) {
104+ if (!strcmp(*argv, "-")) {
105+ *argv = "<stdin>";
106+ fp = stdin;
107+ } else if (!(fp = fopen(*argv, "r"))) {
108+ weprintf("fopen %s:", *argv);
109+ ret = 1;
110+ continue;
111+ }
112+ wc(fp, *argv);
113+ if (fp != stdin && fshut(fp, *argv))
114+ ret = 1;
115+ }
116+ if (many)
117+ output("total", tc, tl, tw);
118+ }
119+
120+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
121+
122+ return ret;
123+}
+64,
-0
1@@ -0,0 +1,64 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+#include <time.h>
7+#include <unistd.h>
8+#include <utmp.h>
9+
10+#include "config.h"
11+#include "util.h"
12+
13+static void
14+usage(void)
15+{
16+ eprintf("usage: %s [-ml]\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+ struct utmp usr;
23+ FILE *ufp;
24+ char timebuf[sizeof "yyyy-mm-dd hh:mm"];
25+ char *tty, *ttmp;
26+ int mflag = 0, lflag = 0;
27+ time_t t;
28+
29+ ARGBEGIN {
30+ case 'm':
31+ mflag = 1;
32+ tty = ttyname(0);
33+ if (!tty)
34+ eprintf("ttyname: stdin:");
35+ if ((ttmp = strrchr(tty, '/')))
36+ tty = ttmp+1;
37+ break;
38+ case 'l':
39+ lflag = 1;
40+ break;
41+ default:
42+ usage();
43+ } ARGEND;
44+
45+ if (argc > 0)
46+ usage();
47+
48+ if (!(ufp = fopen(UTMP_PATH, "r")))
49+ eprintf("fopen: %s:", UTMP_PATH);
50+
51+ while (fread(&usr, sizeof(usr), 1, ufp) == 1) {
52+ if (!*usr.ut_name || !*usr.ut_line ||
53+ usr.ut_line[0] == '~')
54+ continue;
55+ if (mflag != 0 && strcmp(usr.ut_line, tty) != 0)
56+ continue;
57+ if (!!strcmp(usr.ut_name, "LOGIN") == lflag)
58+ continue;
59+ t = usr.ut_time;
60+ strftime(timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime(&t));
61+ printf("%-8s %-12s %-16s\n", usr.ut_name, usr.ut_line, timebuf);
62+ }
63+ fclose(ufp);
64+ return 0;
65+}
+405,
-0
1@@ -0,0 +1,405 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/wait.h>
4+
5+#include <errno.h>
6+#include <limits.h>
7+#include <stdint.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "util.h"
14+
15+#define NARGS 10000
16+
17+static int inputc(void);
18+static void fillargbuf(int);
19+static int eatspace(void);
20+static int parsequote(int);
21+static int parseescape(void);
22+static char *poparg(void);
23+static void waitchld(int);
24+static void spawn(void);
25+
26+static size_t argbsz;
27+static size_t argbpos;
28+static size_t maxargs;
29+static size_t curprocs, maxprocs = 1;
30+static int nerrors;
31+static int nulflag, nflag, pflag, rflag, tflag, xflag, Iflag, Lflag;
32+static size_t maxlines;
33+static int newline = 1;
34+static int arg_newline;
35+static char *argb;
36+static char **cmd;
37+static char *eofstr;
38+
39+static int
40+inputc(void)
41+{
42+ int ch;
43+
44+ ch = getc(stdin);
45+ if (ch == EOF && ferror(stdin))
46+ eprintf("getc <stdin>:");
47+ if (ch == '\n')
48+ newline = 1;
49+
50+ return ch;
51+}
52+
53+static void
54+fillargbuf(int ch)
55+{
56+ if (argbpos >= argbsz) {
57+ argbsz = argbpos == 0 ? 1 : argbsz * 2;
58+ argb = erealloc(argb, argbsz);
59+ }
60+ argb[argbpos] = ch;
61+}
62+
63+static int
64+eatspace(void)
65+{
66+ int ch;
67+
68+ while ((ch = inputc()) != EOF) {
69+ if (nulflag || !(ch == ' ' || ch == '\t' || ch == '\n')) {
70+ ungetc(ch, stdin);
71+ return ch;
72+ }
73+ }
74+ return -1;
75+}
76+
77+static int
78+parsequote(int q)
79+{
80+ int ch;
81+
82+ while ((ch = inputc()) != EOF) {
83+ if (ch == q)
84+ return 0;
85+ if (ch != '\n') {
86+ fillargbuf(ch);
87+ argbpos++;
88+ }
89+ }
90+
91+ return -1;
92+}
93+
94+static int
95+parseescape(void)
96+{
97+ int ch;
98+
99+ if ((ch = inputc()) != EOF) {
100+ fillargbuf(ch);
101+ argbpos++;
102+ return ch;
103+ }
104+
105+ return -1;
106+}
107+
108+static char *
109+poparg(void)
110+{
111+ int ch;
112+
113+ argbpos = 0;
114+ if (eatspace() < 0)
115+ return NULL;
116+
117+ arg_newline = newline;
118+ newline = 0;
119+ while ((ch = inputc()) != EOF) {
120+ /* NUL separator: no escaping */
121+ if (nulflag) {
122+ if (ch == '\0')
123+ goto out;
124+ else
125+ goto fill;
126+ }
127+
128+ switch (ch) {
129+ case ' ':
130+ case '\t':
131+ if (Iflag)
132+ goto fill;
133+ case '\n':
134+ goto out;
135+ case '\'':
136+ if (parsequote('\'') < 0)
137+ eprintf("unterminated single quote\n");
138+ break;
139+ case '\"':
140+ if (parsequote('\"') < 0)
141+ eprintf("unterminated double quote\n");
142+ break;
143+ case '\\':
144+ if (parseescape() < 0)
145+ eprintf("backslash at EOF\n");
146+ break;
147+ default:
148+ fill:
149+ fillargbuf(ch);
150+ argbpos++;
151+ break;
152+ }
153+ }
154+out:
155+ fillargbuf('\0');
156+
157+ return (eofstr && !strcmp(argb, eofstr)) ? NULL : argb;
158+}
159+
160+static void
161+waitchld(int waitall)
162+{
163+ pid_t pid;
164+ int status;
165+
166+ while ((pid = waitpid(-1, &status,
167+ !waitall && curprocs < maxprocs ? WNOHANG : 0)) >
168+ 0) {
169+ curprocs--;
170+
171+ if (WIFEXITED(status)) {
172+ if (WEXITSTATUS(status) == 255)
173+ exit(124);
174+ if (WEXITSTATUS(status) == 127 ||
175+ WEXITSTATUS(status) == 126)
176+ exit(WEXITSTATUS(status));
177+ if (WEXITSTATUS(status))
178+ nerrors++;
179+ }
180+ if (WIFSIGNALED(status))
181+ exit(125);
182+ }
183+ if (pid == -1 && errno != ECHILD)
184+ eprintf("waitpid:");
185+}
186+
187+static int
188+prompt(void)
189+{
190+ FILE *fp;
191+ int ch, ret;
192+
193+ if (!(fp = fopen("/dev/tty", "r")))
194+ return -1;
195+
196+ fputs("?...", stderr);
197+ fflush(stderr);
198+
199+ ch = fgetc(fp);
200+ ret = (ch == 'y' || ch == 'Y');
201+ if (ch != EOF && ch != '\n') {
202+ while ((ch = fgetc(fp)) != EOF) {
203+ if (ch == '\n')
204+ break;
205+ }
206+ }
207+
208+ fclose(fp);
209+
210+ return ret;
211+}
212+
213+static void
214+spawn(void)
215+{
216+ int savederrno;
217+ int first = 1;
218+ char **p;
219+
220+ if (pflag || tflag) {
221+ for (p = cmd; *p; p++) {
222+ if (!first)
223+ fputc(' ', stderr);
224+ fputs(*p, stderr);
225+ first = 0;
226+ }
227+ if (pflag) {
228+ switch (prompt()) {
229+ case -1:
230+ break; /* error */
231+ case 0:
232+ return; /* no */
233+ case 1:
234+ goto dospawn; /* yes */
235+ }
236+ }
237+ fputc('\n', stderr);
238+ fflush(stderr);
239+ }
240+
241+dospawn:
242+ switch (fork()) {
243+ case -1:
244+ eprintf("fork:");
245+ case 0:
246+ execvp(*cmd, cmd);
247+ savederrno = errno;
248+ weprintf("execvp %s:", *cmd);
249+ _exit(126 + (savederrno == ENOENT));
250+ }
251+ curprocs++;
252+ waitchld(0);
253+}
254+
255+static void
256+usage(void)
257+{
258+ eprintf("usage: %s [-0prtx] [-E eofstr] [-I replstr] [-L maxlines] [-n "
259+ "num] [-P maxprocs] [-s num] "
260+ "[cmd [arg ...]]\n",
261+ argv0);
262+}
263+
264+int
265+main(int argc, char *argv[])
266+{
267+ int ret = 0, leftover = 0, i, j;
268+ size_t argsz, argmaxsz;
269+ size_t arglen, a;
270+ char *arg = "";
271+ char *replstr;
272+
273+ if ((argmaxsz = sysconf(_SC_ARG_MAX)) == (size_t)-1)
274+ argmaxsz = _POSIX_ARG_MAX;
275+ /* Leave some room for environment variables */
276+ argmaxsz -= 4096;
277+ cmd = emalloc(NARGS * sizeof(*cmd));
278+
279+ ARGBEGIN
280+ {
281+ case '0':
282+ nulflag = 1;
283+ break;
284+ case 'n':
285+ nflag = 1;
286+ maxargs =
287+ estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
288+ break;
289+ case 'p':
290+ pflag = 1;
291+ break;
292+ case 'r':
293+ rflag = 1;
294+ break;
295+ case 's':
296+ argmaxsz =
297+ estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
298+ break;
299+ case 't':
300+ tflag = 1;
301+ break;
302+ case 'x':
303+ xflag = 1;
304+ break;
305+ case 'E':
306+ eofstr = EARGF(usage());
307+ break;
308+ case 'I':
309+ Iflag = 1;
310+ xflag = 1;
311+ nflag = 1;
312+ maxargs = 1;
313+ replstr = EARGF(usage());
314+ break;
315+ case 'L':
316+ Lflag = 1;
317+ maxlines =
318+ estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
319+ break;
320+ case 'P':
321+ maxprocs =
322+ estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
323+ break;
324+ default:
325+ usage();
326+ }
327+ ARGEND
328+
329+ do {
330+ size_t linecount = 0;
331+ argsz = 0;
332+ i = 0;
333+ a = 0;
334+ if (argc) {
335+ for (; i < argc; i++) {
336+ cmd[i] = estrdup(argv[i]);
337+ argsz += strlen(cmd[i]) + 1;
338+ }
339+ } else {
340+ cmd[i] = estrdup("/bin/echo");
341+ argsz += strlen("/bin/echo") + 1;
342+ i++;
343+ }
344+ while (leftover || (arg = poparg())) {
345+ if (arg) {
346+ if (linecount == 0) {
347+ linecount = 1;
348+ } else if (arg_newline) {
349+ linecount++;
350+ arg_newline = 0;
351+ }
352+ if (Lflag && linecount > maxlines) {
353+ leftover = 1;
354+ break;
355+ }
356+ }
357+ arglen = strlen(arg);
358+ if (argsz + arglen >= argmaxsz || i >= NARGS - 1) {
359+ if (xflag || arglen >= argmaxsz || leftover)
360+ eprintf("insufficient argument "
361+ "space\n");
362+ leftover = 1;
363+ break;
364+ }
365+
366+ if (!Iflag) {
367+ cmd[i] = estrdup(arg);
368+ argsz += arglen + 1;
369+ } else {
370+ for (j = 1; j < i; j++) {
371+ char *p = cmd[j];
372+ argsz -= strlen(cmd[j]);
373+ strnsubst(&cmd[j], replstr, arg, 255);
374+ argsz += strlen(cmd[j]);
375+ free(p);
376+ }
377+ }
378+
379+ i++;
380+ a++;
381+ leftover = 0;
382+ if (nflag && a >= maxargs)
383+ break;
384+ }
385+ cmd[i] = NULL;
386+ if (a >= maxargs && nflag)
387+ spawn();
388+ else if (Lflag && linecount >= maxlines)
389+ spawn();
390+ else if (!a || (i == 1 && rflag))
391+ ;
392+ else
393+ spawn();
394+ for (; i >= 0; i--)
395+ free(cmd[i]);
396+ } while (arg);
397+
398+ free(argb);
399+
400+ waitchld(1);
401+
402+ if (nerrors || (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>")))
403+ ret = 123;
404+
405+ return ret;
406+}
+49,
-0
1@@ -0,0 +1,49 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdlib.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s dir [cmd [arg ...]]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ char *shell[] = { "/bin/sh", "-i", NULL }, *aux, *cmd;
19+ int savederrno;
20+
21+ ARGBEGIN {
22+ default:
23+ usage();
24+ } ARGEND
25+
26+ if (!argc)
27+ usage();
28+
29+ if ((aux = getenv("SHELL")))
30+ shell[0] = aux;
31+
32+ if (chroot(argv[0]) < 0)
33+ eprintf("chroot %s:", argv[0]);
34+
35+ if (chdir("/") < 0)
36+ eprintf("chdir:");
37+
38+ if (argc == 1) {
39+ cmd = *shell;
40+ execvp(cmd, shell);
41+ } else {
42+ cmd = argv[1];
43+ execvp(cmd, argv + 1);
44+ }
45+
46+ savederrno = errno;
47+ weprintf("execvp %s:", cmd);
48+
49+ _exit(126 + (savederrno == ENOENT));
50+}
+23,
-0
1@@ -0,0 +1,23 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+
5+#include "util.h"
6+
7+static void
8+usage(void)
9+{
10+ eprintf("usage: %s\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+ argv0 = argv[0], argc--, argv++;
17+
18+ if (argc)
19+ usage();
20+
21+ printf("\x1b[2J\x1b[H");
22+
23+ return 0;
24+}
+98,
-0
1@@ -0,0 +1,98 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+
5+#include <limits.h>
6+#include <stdint.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <unistd.h>
11+
12+#include "text.h"
13+#include "util.h"
14+
15+static void
16+usage(void)
17+{
18+ eprintf("usage: %s [-c num] [file ...]\n", argv0);
19+}
20+
21+int
22+main(int argc, char *argv[])
23+{
24+ FILE *fp;
25+ struct winsize w;
26+ struct linebuf b = EMPTY_LINEBUF;
27+ size_t chars = 65, maxlen = 0, i, j, k, len, cols, rows;
28+ int cflag = 0, ret = 0;
29+ char *p;
30+
31+ ARGBEGIN {
32+ case 'c':
33+ cflag = 1;
34+ chars = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
35+ break;
36+ default:
37+ usage();
38+ } ARGEND
39+
40+ if (!cflag) {
41+ if ((p = getenv("COLUMNS")))
42+ chars = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
43+ else if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) && w.ws_col > 0)
44+ chars = w.ws_col;
45+ }
46+
47+ if (!argc) {
48+ getlines(stdin, &b);
49+ } else {
50+ for (; *argv; argc--, argv++) {
51+ if (!strcmp(*argv, "-")) {
52+ *argv = "<stdin>";
53+ fp = stdin;
54+ } else if (!(fp = fopen(*argv, "r"))) {
55+ weprintf("fopen %s:", *argv);
56+ ret = 1;
57+ continue;
58+ }
59+ getlines(fp, &b);
60+ if (fp != stdin && fshut(fp, *argv))
61+ ret = 1;
62+ }
63+ }
64+
65+ for (i = 0; i < b.nlines; i++) {
66+ for (j = 0, len = 0; j < b.lines[i].len; j++) {
67+ if (UTF8_POINT(b.lines[i].data[j]))
68+ len++;
69+ }
70+ if (len && b.lines[i].data[b.lines[i].len - 1] == '\n') {
71+ b.lines[i].data[--(b.lines[i].len)] = '\0';
72+ len--;
73+ }
74+ if (len > maxlen)
75+ maxlen = len;
76+ }
77+
78+ for (cols = 1; (cols + 1) * maxlen + cols <= chars; cols++);
79+ rows = b.nlines / cols + (b.nlines % cols > 0);
80+
81+ for (i = 0; i < rows; i++) {
82+ for (j = 0; j < cols && i + j * rows < b.nlines; j++) {
83+ for (k = 0, len = 0; k < b.lines[i + j * rows].len; k++) {
84+ if (UTF8_POINT(b.lines[i + j * rows].data[k]))
85+ len++;
86+ }
87+ fwrite(b.lines[i + j * rows].data, 1,
88+ b.lines[i + j * rows].len, stdout);
89+ if (j < cols - 1)
90+ for (k = len; k < maxlen + 1; k++)
91+ putchar(' ');
92+ }
93+ putchar('\n');
94+ }
95+
96+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
97+
98+ return ret;
99+}
+566,
-0
1@@ -0,0 +1,566 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+#include <sys/wait.h>
5+
6+#include <errno.h>
7+#include <limits.h>
8+#include <signal.h>
9+#include <stdarg.h>
10+#include <stdlib.h>
11+#include <stdio.h>
12+#include <ctype.h>
13+#include <string.h>
14+#include <syslog.h>
15+#include <time.h>
16+#include <unistd.h>
17+
18+#include "queue.h"
19+#include "util.h"
20+
21+struct field {
22+ enum {
23+ ERROR,
24+ WILDCARD,
25+ NUMBER,
26+ RANGE,
27+ REPEAT,
28+ LIST
29+ } type;
30+ long *val;
31+ int len;
32+};
33+
34+struct ctabentry {
35+ struct field min;
36+ struct field hour;
37+ struct field mday;
38+ struct field mon;
39+ struct field wday;
40+ char *cmd;
41+ TAILQ_ENTRY(ctabentry) entry;
42+};
43+
44+struct jobentry {
45+ char *cmd;
46+ pid_t pid;
47+ TAILQ_ENTRY(jobentry) entry;
48+};
49+
50+static sig_atomic_t chldreap;
51+static sig_atomic_t reload;
52+static sig_atomic_t quit;
53+static TAILQ_HEAD(, ctabentry) ctabhead = TAILQ_HEAD_INITIALIZER(ctabhead);
54+static TAILQ_HEAD(, jobentry) jobhead = TAILQ_HEAD_INITIALIZER(jobhead);
55+static char *config = "/etc/crontab";
56+static char *pidfile = "/var/run/crond.pid";
57+static int nflag;
58+
59+static void
60+loginfo(const char *fmt, ...)
61+{
62+ va_list ap;
63+ va_start(ap, fmt);
64+ if (nflag == 0)
65+ vsyslog(LOG_INFO, fmt, ap);
66+ else
67+ vfprintf(stdout, fmt, ap);
68+ fflush(stdout);
69+ va_end(ap);
70+}
71+
72+static void
73+logwarn(const char *fmt, ...)
74+{
75+ va_list ap;
76+ va_start(ap, fmt);
77+ if (nflag == 0)
78+ vsyslog(LOG_WARNING, fmt, ap);
79+ else
80+ vfprintf(stderr, fmt, ap);
81+ va_end(ap);
82+}
83+
84+static void
85+logerr(const char *fmt, ...)
86+{
87+ va_list ap;
88+ va_start(ap, fmt);
89+ if (nflag == 0)
90+ vsyslog(LOG_ERR, fmt, ap);
91+ else
92+ vfprintf(stderr, fmt, ap);
93+ va_end(ap);
94+}
95+
96+static void
97+runjob(char *cmd)
98+{
99+ struct jobentry *je;
100+ time_t t;
101+ pid_t pid;
102+
103+ t = time(NULL);
104+
105+ /* If command is already running, skip it */
106+ TAILQ_FOREACH(je, &jobhead, entry) {
107+ if (strcmp(je->cmd, cmd) == 0) {
108+ loginfo("already running %s pid: %d at %s",
109+ je->cmd, je->pid, ctime(&t));
110+ return;
111+ }
112+ }
113+
114+ switch ((pid = fork())) {
115+ case -1:
116+ logerr("error: failed to fork job: %s time: %s",
117+ cmd, ctime(&t));
118+ return;
119+ case 0:
120+ setsid();
121+ loginfo("run: %s pid: %d at %s",
122+ cmd, getpid(), ctime(&t));
123+ execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
124+ logerr("error: failed to execute job: %s time: %s",
125+ cmd, ctime(&t));
126+ _exit(1);
127+ default:
128+ je = emalloc(sizeof(*je));
129+ je->cmd = estrdup(cmd);
130+ je->pid = pid;
131+ TAILQ_INSERT_TAIL(&jobhead, je, entry);
132+ }
133+}
134+
135+static void
136+waitjob(void)
137+{
138+ struct jobentry *je, *tmp;
139+ int status;
140+ time_t t;
141+ pid_t pid;
142+
143+ t = time(NULL);
144+
145+ while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
146+ je = NULL;
147+ TAILQ_FOREACH(tmp, &jobhead, entry) {
148+ if (tmp->pid == pid) {
149+ je = tmp;
150+ break;
151+ }
152+ }
153+ if (je) {
154+ TAILQ_REMOVE(&jobhead, je, entry);
155+ free(je->cmd);
156+ free(je);
157+ }
158+ if (WIFEXITED(status) == 1)
159+ loginfo("complete: pid: %d returned: %d time: %s",
160+ pid, WEXITSTATUS(status), ctime(&t));
161+ else if (WIFSIGNALED(status) == 1)
162+ loginfo("complete: pid: %d terminated by signal: %s time: %s",
163+ pid, strsignal(WTERMSIG(status)), ctime(&t));
164+ else if (WIFSTOPPED(status) == 1)
165+ loginfo("complete: pid: %d stopped by signal: %s time: %s",
166+ pid, strsignal(WSTOPSIG(status)), ctime(&t));
167+ }
168+}
169+
170+static int
171+isleap(int year)
172+{
173+ if (year % 400 == 0)
174+ return 1;
175+ if (year % 100 == 0)
176+ return 0;
177+ return (year % 4 == 0);
178+}
179+
180+static int
181+daysinmon(int mon, int year)
182+{
183+ int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
184+ if (year < 1900)
185+ year += 1900;
186+ if (isleap(year))
187+ days[1] = 29;
188+ return days[mon];
189+}
190+
191+static int
192+matchentry(struct ctabentry *cte, struct tm *tm)
193+{
194+ struct {
195+ struct field *f;
196+ int tm;
197+ int len;
198+ } matchtbl[] = {
199+ { .f = &cte->min, .tm = tm->tm_min, .len = 60 },
200+ { .f = &cte->hour, .tm = tm->tm_hour, .len = 24 },
201+ { .f = &cte->mday, .tm = tm->tm_mday, .len = daysinmon(tm->tm_mon, tm->tm_year) },
202+ { .f = &cte->mon, .tm = tm->tm_mon, .len = 12 },
203+ { .f = &cte->wday, .tm = tm->tm_wday, .len = 7 },
204+ };
205+ size_t i;
206+ int j;
207+
208+ for (i = 0; i < LEN(matchtbl); i++) {
209+ switch (matchtbl[i].f->type) {
210+ case WILDCARD:
211+ continue;
212+ case NUMBER:
213+ if (matchtbl[i].f->val[0] == matchtbl[i].tm)
214+ continue;
215+ break;
216+ case RANGE:
217+ if (matchtbl[i].f->val[0] <= matchtbl[i].tm)
218+ if (matchtbl[i].f->val[1] >= matchtbl[i].tm)
219+ continue;
220+ break;
221+ case REPEAT:
222+ if (matchtbl[i].tm > 0) {
223+ if (matchtbl[i].tm % matchtbl[i].f->val[0] == 0)
224+ continue;
225+ } else {
226+ if (matchtbl[i].len % matchtbl[i].f->val[0] == 0)
227+ continue;
228+ }
229+ break;
230+ case LIST:
231+ for (j = 0; j < matchtbl[i].f->len; j++)
232+ if (matchtbl[i].f->val[j] == matchtbl[i].tm)
233+ break;
234+ if (j < matchtbl[i].f->len)
235+ continue;
236+ break;
237+ default:
238+ break;
239+ }
240+ break;
241+ }
242+ if (i != LEN(matchtbl))
243+ return 0;
244+ return 1;
245+}
246+
247+static int
248+parsefield(const char *field, long low, long high, struct field *f)
249+{
250+ int i;
251+ char *e1, *e2;
252+ const char *p;
253+
254+ p = field;
255+ while (isdigit(*p))
256+ p++;
257+
258+ f->type = ERROR;
259+
260+ switch (*p) {
261+ case '*':
262+ if (strcmp(field, "*") == 0) {
263+ f->val = NULL;
264+ f->len = 0;
265+ f->type = WILDCARD;
266+ } else if (strncmp(field, "*/", 2) == 0) {
267+ f->val = emalloc(sizeof(*f->val));
268+ f->len = 1;
269+
270+ errno = 0;
271+ f->val[0] = strtol(field + 2, &e1, 10);
272+ if (e1[0] != '\0' || errno != 0 || f->val[0] == 0)
273+ break;
274+
275+ f->type = REPEAT;
276+ }
277+ break;
278+ case '\0':
279+ f->val = emalloc(sizeof(*f->val));
280+ f->len = 1;
281+
282+ errno = 0;
283+ f->val[0] = strtol(field, &e1, 10);
284+ if (e1[0] != '\0' || errno != 0)
285+ break;
286+
287+ f->type = NUMBER;
288+ break;
289+ case '-':
290+ f->val = emalloc(2 * sizeof(*f->val));
291+ f->len = 2;
292+
293+ errno = 0;
294+ f->val[0] = strtol(field, &e1, 10);
295+ if (e1[0] != '-' || errno != 0)
296+ break;
297+
298+ errno = 0;
299+ f->val[1] = strtol(e1 + 1, &e2, 10);
300+ if (e2[0] != '\0' || errno != 0)
301+ break;
302+
303+ f->type = RANGE;
304+ break;
305+ case ',':
306+ for (i = 1; isdigit(*p) || *p == ','; p++)
307+ if (*p == ',')
308+ i++;
309+ f->val = emalloc(i * sizeof(*f->val));
310+ f->len = i;
311+
312+ errno = 0;
313+ f->val[0] = strtol(field, &e1, 10);
314+ if (f->val[0] < low || f->val[0] > high)
315+ break;
316+
317+ for (i = 1; *e1 == ',' && errno == 0; i++) {
318+ errno = 0;
319+ f->val[i] = strtol(e1 + 1, &e2, 10);
320+ e1 = e2;
321+ }
322+ if (e1[0] != '\0' || errno != 0)
323+ break;
324+
325+ f->type = LIST;
326+ break;
327+ default:
328+ return -1;
329+ }
330+
331+ for (i = 0; i < f->len; i++)
332+ if (f->val[i] < low || f->val[i] > high)
333+ f->type = ERROR;
334+
335+ if (f->type == ERROR) {
336+ free(f->val);
337+ return -1;
338+ }
339+
340+ return 0;
341+}
342+
343+static void
344+freecte(struct ctabentry *cte, int nfields)
345+{
346+ switch (nfields) {
347+ case 6:
348+ free(cte->cmd);
349+ case 5:
350+ free(cte->wday.val);
351+ case 4:
352+ free(cte->mon.val);
353+ case 3:
354+ free(cte->mday.val);
355+ case 2:
356+ free(cte->hour.val);
357+ case 1:
358+ free(cte->min.val);
359+ }
360+ free(cte);
361+}
362+
363+static void
364+unloadentries(void)
365+{
366+ struct ctabentry *cte, *tmp;
367+
368+ for (cte = TAILQ_FIRST(&ctabhead); cte; cte = tmp) {
369+ tmp = TAILQ_NEXT(cte, entry);
370+ TAILQ_REMOVE(&ctabhead, cte, entry);
371+ freecte(cte, 6);
372+ }
373+}
374+
375+static int
376+loadentries(void)
377+{
378+ struct ctabentry *cte;
379+ FILE *fp;
380+ char *line = NULL, *p, *col;
381+ int r = 0, y;
382+ size_t size = 0;
383+ ssize_t len;
384+ struct fieldlimits {
385+ char *name;
386+ long min;
387+ long max;
388+ struct field *f;
389+ } flim[] = {
390+ { "min", 0, 59, NULL },
391+ { "hour", 0, 23, NULL },
392+ { "mday", 1, 31, NULL },
393+ { "mon", 1, 12, NULL },
394+ { "wday", 0, 6, NULL }
395+ };
396+ size_t x;
397+
398+ if ((fp = fopen(config, "r")) == NULL) {
399+ logerr("error: can't open %s: %s\n", config, strerror(errno));
400+ return -1;
401+ }
402+
403+ for (y = 0; (len = getline(&line, &size, fp)) != -1; y++) {
404+ p = line;
405+ if (line[0] == '#' || line[0] == '\n' || line[0] == '\0')
406+ continue;
407+
408+ cte = emalloc(sizeof(*cte));
409+ flim[0].f = &cte->min;
410+ flim[1].f = &cte->hour;
411+ flim[2].f = &cte->mday;
412+ flim[3].f = &cte->mon;
413+ flim[4].f = &cte->wday;
414+
415+ for (x = 0; x < LEN(flim); x++) {
416+ do
417+ col = strsep(&p, "\t\n ");
418+ while (col && col[0] == '\0');
419+
420+ if (!col || parsefield(col, flim[x].min, flim[x].max, flim[x].f) < 0) {
421+ logerr("error: failed to parse `%s' field on line %d\n",
422+ flim[x].name, y + 1);
423+ freecte(cte, x);
424+ r = -1;
425+ break;
426+ }
427+ }
428+
429+ if (r == -1)
430+ break;
431+
432+ col = strsep(&p, "\n");
433+ if (col)
434+ while (col[0] == '\t' || col[0] == ' ')
435+ col++;
436+ if (!col || col[0] == '\0') {
437+ logerr("error: missing `cmd' field on line %d\n",
438+ y + 1);
439+ freecte(cte, 5);
440+ r = -1;
441+ break;
442+ }
443+ cte->cmd = estrdup(col);
444+
445+ TAILQ_INSERT_TAIL(&ctabhead, cte, entry);
446+ }
447+
448+ if (r < 0)
449+ unloadentries();
450+
451+ free(line);
452+ fclose(fp);
453+
454+ return r;
455+}
456+
457+static void
458+reloadentries(void)
459+{
460+ unloadentries();
461+ if (loadentries() < 0)
462+ logwarn("warning: discarding old crontab entries\n");
463+}
464+
465+static void
466+sighandler(int sig)
467+{
468+ switch (sig) {
469+ case SIGCHLD:
470+ chldreap = 1;
471+ break;
472+ case SIGHUP:
473+ reload = 1;
474+ break;
475+ case SIGTERM:
476+ quit = 1;
477+ break;
478+ }
479+}
480+
481+static void
482+usage(void)
483+{
484+ eprintf("usage: %s [-f file] [-n]\n", argv0);
485+}
486+
487+int
488+main(int argc, char *argv[])
489+{
490+ FILE *fp;
491+ struct ctabentry *cte;
492+ time_t t;
493+ struct tm *tm;
494+ struct sigaction sa;
495+
496+ ARGBEGIN {
497+ case 'n':
498+ nflag = 1;
499+ break;
500+ case 'f':
501+ config = EARGF(usage());
502+ break;
503+ default:
504+ usage();
505+ } ARGEND
506+
507+ if (argc > 0)
508+ usage();
509+
510+ if (nflag == 0) {
511+ openlog(argv[0], LOG_CONS | LOG_PID, LOG_CRON);
512+ if (daemon(1, 0) < 0) {
513+ logerr("error: failed to daemonize %s\n", strerror(errno));
514+ return 1;
515+ }
516+ if ((fp = fopen(pidfile, "w"))) {
517+ fprintf(fp, "%d\n", getpid());
518+ fclose(fp);
519+ }
520+ }
521+
522+ sa.sa_handler = sighandler;
523+ sigfillset(&sa.sa_mask);
524+ sa.sa_flags = SA_RESTART;
525+ sigaction(SIGCHLD, &sa, NULL);
526+ sigaction(SIGHUP, &sa, NULL);
527+ sigaction(SIGTERM, &sa, NULL);
528+
529+ loadentries();
530+
531+ while (1) {
532+ t = time(NULL);
533+ sleep(60 - t % 60);
534+
535+ if (quit == 1) {
536+ if (nflag == 0)
537+ unlink(pidfile);
538+ unloadentries();
539+ /* Don't wait or kill forked processes, just exit */
540+ break;
541+ }
542+
543+ if (reload == 1 || chldreap == 1) {
544+ if (reload == 1) {
545+ reloadentries();
546+ reload = 0;
547+ }
548+ if (chldreap == 1) {
549+ waitjob();
550+ chldreap = 0;
551+ }
552+ continue;
553+ }
554+
555+ TAILQ_FOREACH(cte, &ctabhead, entry) {
556+ t = time(NULL);
557+ tm = localtime(&t);
558+ if (matchentry(cte, tm) == 1)
559+ runjob(cte->cmd);
560+ }
561+ }
562+
563+ if (nflag == 0)
564+ closelog();
565+
566+ return 0;
567+}
+82,
-0
1@@ -0,0 +1,82 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/file.h>
4+#include <sys/wait.h>
5+
6+#include <errno.h>
7+#include <fcntl.h>
8+#include <stdio.h>
9+#include <unistd.h>
10+
11+#include "util.h"
12+
13+static void
14+usage(void)
15+{
16+ eprintf("usage: %s [-nosux] file cmd [arg ...]\n", argv0);
17+}
18+
19+int
20+main(int argc, char *argv[])
21+{
22+ int fd, status, savederrno, flags = LOCK_EX, nonblk = 0, oflag = 0;
23+ pid_t pid;
24+
25+ ARGBEGIN {
26+ case 'n':
27+ nonblk = LOCK_NB;
28+ break;
29+ case 'o':
30+ oflag = 1;
31+ break;
32+ case 's':
33+ flags = LOCK_SH;
34+ break;
35+ case 'u':
36+ flags = LOCK_UN;
37+ break;
38+ case 'x':
39+ flags = LOCK_EX;
40+ break;
41+ default:
42+ usage();
43+ } ARGEND
44+
45+ if (argc < 2)
46+ usage();
47+
48+ if ((fd = open(*argv, O_RDONLY | O_CREAT, 0644)) < 0)
49+ eprintf("open %s:", *argv);
50+
51+ if (flock(fd, flags | nonblk)) {
52+ if (nonblk && errno == EWOULDBLOCK)
53+ return 1;
54+ eprintf("flock:");
55+ }
56+
57+ switch ((pid = fork())) {
58+ case -1:
59+ eprintf("fork:");
60+ case 0:
61+ if (oflag && close(fd) < 0)
62+ eprintf("close:");
63+ argv++;
64+ execvp(*argv, argv);
65+ savederrno = errno;
66+ weprintf("execvp %s:", *argv);
67+ _exit(126 + (savederrno == ENOENT));
68+ default:
69+ break;
70+ }
71+ if (waitpid(pid, &status, 0) < 0)
72+ eprintf("waitpid:");
73+
74+ if (close(fd) < 0)
75+ eprintf("close:");
76+
77+ if (WIFSIGNALED(status))
78+ return 128 + WTERMSIG(status);
79+ if (WIFEXITED(status))
80+ return WEXITSTATUS(status);
81+
82+ return 0;
83+}
+140,
-0
1@@ -0,0 +1,140 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/stat.h>
5+#include <sys/types.h>
6+
7+#include <fcntl.h>
8+#include <limits.h>
9+#include <signal.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+#include <utmp.h>
15+
16+#include "config.h"
17+#include "util.h"
18+
19+static char *tty = "/dev/tty1";
20+static char *defaultterm = "linux";
21+
22+static void
23+usage(void)
24+{
25+ eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0);
26+}
27+
28+int
29+main(int argc, char *argv[])
30+{
31+ char term[128], logname[LOGIN_NAME_MAX], c;
32+ char hostname[HOST_NAME_MAX + 1];
33+ struct utmp usr;
34+ struct sigaction sa;
35+ FILE *fp;
36+ int fd;
37+ unsigned int i = 0;
38+ ssize_t n;
39+ long pos;
40+
41+ ARGBEGIN {
42+ default:
43+ usage();
44+ } ARGEND;
45+
46+ strlcpy(term, defaultterm, sizeof(term));
47+ if (argc > 0) {
48+ tty = argv[0];
49+ if (argc > 1)
50+ strlcpy(term, argv[1], sizeof(term));
51+ }
52+
53+ sa.sa_handler = SIG_IGN;
54+ sa.sa_flags = 0;
55+ sigemptyset(&sa.sa_mask);
56+ sigaction(SIGHUP, &sa, NULL);
57+
58+ setenv("TERM", term, 1);
59+
60+ setsid();
61+
62+ fd = open(tty, O_RDWR);
63+ if (fd < 0)
64+ eprintf("open %s:", tty);
65+ if (isatty(fd) == 0)
66+ eprintf("%s is not a tty\n", tty);
67+
68+ /* steal the controlling terminal if necessary */
69+ if (ioctl(fd, TIOCSCTTY, (void *)1) != 0)
70+ weprintf("TIOCSCTTY: could not set controlling tty\n");
71+ vhangup();
72+ close(fd);
73+
74+ fd = open(tty, O_RDWR);
75+ if (fd < 0)
76+ eprintf("open %s:", tty);
77+ dup2(fd, 0);
78+ dup2(fd, 1);
79+ dup2(fd, 2);
80+ if (fchown(fd, 0, 0) < 0)
81+ weprintf("fchown %s:", tty);
82+ if (fchmod(fd, 0600) < 0)
83+ weprintf("fchmod %s:", tty);
84+ if (fd > 2)
85+ close(fd);
86+
87+ sa.sa_handler = SIG_DFL;
88+ sa.sa_flags = 0;
89+ sigemptyset(&sa.sa_mask);
90+ sigaction(SIGHUP, &sa, NULL);
91+
92+ /* Clear all utmp entries for this tty */
93+ fp = fopen(UTMP_PATH, "r+");
94+ if (fp) {
95+ do {
96+ pos = ftell(fp);
97+ if (fread(&usr, sizeof(usr), 1, fp) != 1)
98+ break;
99+ if (usr.ut_line[0] == '\0')
100+ continue;
101+ if (strcmp(usr.ut_line, tty) != 0)
102+ continue;
103+ memset(&usr, 0, sizeof(usr));
104+ fseek(fp, pos, SEEK_SET);
105+ if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
106+ break;
107+ } while (1);
108+ if (ferror(fp))
109+ weprintf("%s: I/O error:", UTMP_PATH);
110+ fclose(fp);
111+ }
112+
113+ if (argc > 2)
114+ return execvp(argv[2], argv + 2);
115+
116+ if (gethostname(hostname, sizeof(hostname)) == 0)
117+ printf("%s ", hostname);
118+ printf("login: ");
119+ fflush(stdout);
120+
121+ /* Flush pending input */
122+ ioctl(0, TCFLSH, (void *)0);
123+ memset(logname, 0, sizeof(logname));
124+ while (1) {
125+ n = read(0, &c, 1);
126+ if (n < 0)
127+ eprintf("read:");
128+ if (n == 0)
129+ return 1;
130+ if (i >= sizeof(logname) - 1)
131+ eprintf("login name too long\n");
132+ if (c == '\n' || c == '\r')
133+ break;
134+ logname[i++] = c;
135+ }
136+ if (logname[0] == '-')
137+ eprintf("login name cannot start with '-'\n");
138+ if (logname[0] == '\0')
139+ return 1;
140+ return execlp("/bin/login", "login", "-p", logname, NULL);
141+}
+51,
-0
1@@ -0,0 +1,51 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/syscall.h>
4+
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <unistd.h>
8+
9+#include "reboot.h"
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s [-pr]\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ int pflag = 0, rflag = 0;
22+ int cmd = LINUX_REBOOT_CMD_HALT;
23+
24+ ARGBEGIN {
25+ case 'p':
26+ pflag = 1;
27+ break;
28+ case 'r':
29+ rflag = 1;
30+ break;
31+ default:
32+ usage();
33+ } ARGEND;
34+
35+ if (argc > 0)
36+ usage();
37+
38+ sync();
39+
40+ if (pflag && rflag)
41+ usage();
42+
43+ if (pflag)
44+ cmd = LINUX_REBOOT_CMD_POWER_OFF;
45+ if (rflag)
46+ cmd = LINUX_REBOOT_CMD_RESTART;
47+
48+ if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1,
49+ LINUX_REBOOT_MAGIC2, cmd, NULL) < 0)
50+ eprintf("reboot:");
51+ return 0;
52+}
+36,
-0
1@@ -0,0 +1,36 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <string.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s [name]\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ char host[HOST_NAME_MAX + 1];
19+
20+ ARGBEGIN {
21+ default:
22+ usage();
23+ } ARGEND
24+
25+ if (!argc) {
26+ if (gethostname(host, sizeof(host)) < 0)
27+ eprintf("gethostname:");
28+ puts(host);
29+ } else if (argc == 1) {
30+ if (sethostname(argv[0], strlen(argv[0])) < 0)
31+ eprintf("sethostname:");
32+ } else {
33+ usage();
34+ }
35+
36+ return fshut(stdout, "<stdout>");
37+}
+111,
-0
1@@ -0,0 +1,111 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <dirent.h>
4+#include <limits.h>
5+#include <signal.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <unistd.h>
10+
11+#include "proc.h"
12+#include "queue.h"
13+#include "util.h"
14+
15+struct {
16+ const char *name;
17+ int sig;
18+} sigs[] = {
19+#define SIG(n) { #n, SIG##n }
20+ SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
21+ SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
22+ SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
23+#undef SIG
24+};
25+
26+struct pidentry {
27+ pid_t pid;
28+ SLIST_ENTRY(pidentry) entry;
29+};
30+
31+static SLIST_HEAD(, pidentry) omitpid_head;
32+
33+static void
34+usage(void)
35+{
36+ eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0);
37+}
38+
39+int
40+main(int argc, char *argv[])
41+{
42+ struct pidentry *pe;
43+ struct dirent *entry;
44+ DIR *dp;
45+ char *p, *arg = NULL;
46+ char *end, *v;
47+ int oflag = 0;
48+ int sig = SIGTERM;
49+ pid_t pid;
50+ size_t i;
51+
52+ ARGBEGIN {
53+ case 's':
54+ v = EARGF(usage());
55+ sig = strtol(v, &end, 0);
56+ if (*end == '\0')
57+ break;
58+ for (i = 0; i < LEN(sigs); i++) {
59+ if (strcasecmp(v, sigs[i].name) == 0) {
60+ sig = sigs[i].sig;
61+ break;
62+ }
63+ }
64+ if (i == LEN(sigs))
65+ eprintf("%s: unknown signal\n", v);
66+ break;
67+ case 'o':
68+ oflag = 1;
69+ arg = EARGF(usage());
70+ break;
71+ default:
72+ usage();
73+ } ARGEND;
74+
75+ SLIST_INIT(&omitpid_head);
76+
77+ if (oflag) {
78+ for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
79+ pe = emalloc(sizeof(*pe));
80+ pe->pid = estrtol(p, 10);
81+ SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
82+ }
83+ }
84+
85+ if (sig != SIGSTOP && sig != SIGCONT)
86+ kill(-1, SIGSTOP);
87+
88+ if (!(dp = opendir("/proc")))
89+ eprintf("opendir /proc:");
90+ while ((entry = readdir(dp))) {
91+ if (pidfile(entry->d_name) == 0)
92+ continue;
93+ pid = estrtol(entry->d_name, 10);
94+ if (pid == 1 || pid == getpid() ||
95+ getsid(pid) == getsid(0) || getsid(pid) == 0)
96+ continue;
97+ if (oflag == 1) {
98+ SLIST_FOREACH(pe, &omitpid_head, entry)
99+ if (pe->pid == pid)
100+ break;
101+ if (pe)
102+ continue;
103+ }
104+ kill(pid, sig);
105+ }
106+ closedir(dp);
107+
108+ if (sig != SIGSTOP && sig != SIGCONT)
109+ kill(-1, SIGCONT);
110+
111+ return 0;
112+}
+64,
-0
1@@ -0,0 +1,64 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <libgen.h>
5+#include <paths.h>
6+#include <pwd.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <time.h>
11+#include <utmp.h>
12+#include <unistd.h>
13+
14+#include "config.h"
15+#include "util.h"
16+
17+static void
18+usage(void)
19+{
20+ eprintf("usage: %s [user]\n", argv0);
21+}
22+
23+int
24+main(int argc, char **argv)
25+{
26+ FILE *fp;
27+ struct utmp ut;
28+ char *user, *file, *prog;
29+ time_t t;
30+
31+ ARGBEGIN {
32+ default:
33+ usage();
34+ } ARGEND;
35+
36+ switch (argc) {
37+ case 0:
38+ user = NULL;
39+ break;
40+ case 1:
41+ user = argv[0];
42+ break;
43+ default:
44+ usage();
45+ }
46+
47+ prog = basename(argv0);
48+ file = (!strcmp(prog, "last")) ? WTMP_PATH : BTMP_PATH;
49+ if ((fp = fopen(file, "r")) == NULL)
50+ eprintf("fopen %s:", file);
51+
52+ while (fread(&ut, sizeof(ut), 1, fp) == 1) {
53+ if (ut.ut_type != USER_PROCESS ||
54+ (user && strcmp(user, ut.ut_name))) {
55+ continue;
56+ }
57+
58+ t = ut.ut_time;
59+ printf("%-8.8s %-8.8s %-16.16s %s",
60+ ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t));
61+ }
62+ if (fclose(fp))
63+ eprintf("fclose %s:", file);
64+ return 0;
65+}
+78,
-0
1@@ -0,0 +1,78 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <paths.h>
5+#include <pwd.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+#include <time.h>
10+#include <utmp.h>
11+
12+#include "text.h"
13+#include "util.h"
14+
15+#define PASSWD "/etc/passwd"
16+
17+static FILE *last;
18+
19+static void
20+lastlog(char *user)
21+{
22+ struct passwd *pwd;
23+ struct lastlog ll;
24+ time_t lltime;
25+
26+ errno = 0;
27+ if ((pwd = getpwnam(user)) == NULL) {
28+ if (errno)
29+ weprintf("getpwnam %s:", user);
30+ else
31+ weprintf("unknown user: %s\n", user);
32+ return;
33+ }
34+
35+ fseek(last, pwd->pw_uid * sizeof(struct lastlog), 0);
36+ fread(&ll, sizeof(struct lastlog), 1, last);
37+
38+ if (ferror(last))
39+ eprintf("%s: read error:", _PATH_LASTLOG);
40+
41+ /* on glibc `ll_time' can be an int32_t with compat32
42+ * avoid compiler warning when calling ctime() */
43+ lltime = ll.ll_time;
44+ printf("%-8.8s %-8.8s %-16.16s %s",
45+ user, ll.ll_line, ll.ll_host, ctime(&lltime));
46+}
47+
48+int
49+main(int argc, char **argv)
50+{
51+ FILE *fp;
52+ char *line = NULL, *p;
53+ size_t sz = 0;
54+
55+ if ((last = fopen(_PATH_LASTLOG, "r")) == NULL)
56+ eprintf("fopen %s:", _PATH_LASTLOG);
57+
58+ if (argc > 1) {
59+ while (*++argv)
60+ lastlog(*argv);
61+ } else {
62+ if ((fp = fopen(PASSWD, "r")) == NULL)
63+ eprintf("fopen %s:", PASSWD);
64+ while (agetline(&line, &sz, fp) != -1) {
65+ if ((p = strchr(line, ':')) == NULL)
66+ eprintf("invalid passwd entry\n");
67+ *p = '\0';
68+ lastlog(line);
69+ }
70+ if (fclose(fp))
71+ eprintf("fclose %s:", PASSWD);
72+ free(line);
73+ }
74+
75+ if (fclose(last))
76+ eprintf("fclose %s:", _PATH_LASTLOG);
77+
78+ return 0;
79+}
+130,
-0
1@@ -0,0 +1,130 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/types.h>
5+
6+#include <errno.h>
7+#include <grp.h>
8+#include <pwd.h>
9+#include <stdio.h>
10+#include <stdlib.h>
11+#include <string.h>
12+#include <time.h>
13+#include <unistd.h>
14+#include <utmp.h>
15+
16+#include "config.h"
17+#include "passwd.h"
18+#include "util.h"
19+
20+/* Write utmp entry */
21+static void
22+writeutmp(const char *user, const char *tty)
23+{
24+ struct utmp usr;
25+ FILE *fp;
26+
27+ memset(&usr, 0, sizeof(usr));
28+
29+ usr.ut_type = USER_PROCESS;
30+ usr.ut_pid = getpid();
31+ strlcpy(usr.ut_user, user, sizeof(usr.ut_user));
32+ strlcpy(usr.ut_line, tty, sizeof(usr.ut_line));
33+ usr.ut_tv.tv_sec = time(NULL);
34+
35+ fp = fopen(UTMP_PATH, "a");
36+ if (fp) {
37+ if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
38+ if (ferror(fp))
39+ weprintf("%s: write error:", UTMP_PATH);
40+ fclose(fp);
41+ } else {
42+ weprintf("fopen %s:", UTMP_PATH);
43+ }
44+}
45+
46+static int
47+dologin(struct passwd *pw, int preserve)
48+{
49+ char *shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell;
50+
51+ if (preserve == 0)
52+ clearenv();
53+ setenv("HOME", pw->pw_dir, 1);
54+ setenv("SHELL", shell, 1);
55+ setenv("USER", pw->pw_name, 1);
56+ setenv("LOGNAME", pw->pw_name, 1);
57+ setenv("PATH", ENV_PATH, 1);
58+ if (chdir(pw->pw_dir) < 0)
59+ eprintf("chdir %s:", pw->pw_dir);
60+ execlp(shell, shell, "-l", NULL);
61+ weprintf("execlp %s:", shell);
62+ return (errno == ENOENT) ? 127 : 126;
63+}
64+
65+static void
66+usage(void)
67+{
68+ eprintf("usage: %s [-p] username\n", argv0);
69+}
70+
71+int
72+main(int argc, char *argv[])
73+{
74+ struct passwd *pw;
75+ char *pass, *user;
76+ char *tty;
77+ uid_t uid;
78+ gid_t gid;
79+ int pflag = 0;
80+
81+ ARGBEGIN {
82+ case 'p':
83+ pflag = 1;
84+ break;
85+ default:
86+ usage();
87+ } ARGEND;
88+
89+ if (argc < 1)
90+ usage();
91+
92+ if (isatty(0) == 0 || isatty(1) == 0 || isatty(2) == 0)
93+ eprintf("no tty");
94+
95+ user = argv[0];
96+ errno = 0;
97+ pw = getpwnam(user);
98+ if (!pw) {
99+ if (errno)
100+ eprintf("getpwnam %s:", user);
101+ else
102+ eprintf("who are you?\n");
103+ }
104+
105+ uid = pw->pw_uid;
106+ gid = pw->pw_gid;
107+
108+ /* Flush pending input */
109+ ioctl(0, TCFLSH, (void *)0);
110+
111+ pass = getpass("Password: ");
112+ if (!pass)
113+ eprintf("getpass:");
114+ if (pw_check(pw, pass) <= 0)
115+ exit(1);
116+
117+ tty = ttyname(0);
118+ if (!tty)
119+ eprintf("ttyname:");
120+
121+ writeutmp(user, tty);
122+
123+ if (initgroups(user, gid) < 0)
124+ eprintf("initgroups:");
125+ if (setgid(gid) < 0)
126+ eprintf("setgid:");
127+ if (setuid(uid) < 0)
128+ eprintf("setuid:");
129+
130+ return dologin(pw, pflag);
131+}
+46,
-0
1@@ -0,0 +1,46 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <stdint.h>
6+
7+#include "crypt.h"
8+#include "md5.h"
9+#include "util.h"
10+
11+static struct md5 s;
12+struct crypt_ops md5_ops = {
13+ md5_init,
14+ md5_update,
15+ md5_sum,
16+ &s,
17+};
18+
19+static void
20+usage(void)
21+{
22+ eprintf("usage: %s [-c] [file ...]\n", argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
29+ uint8_t md[MD5_DIGEST_LENGTH];
30+
31+ ARGBEGIN {
32+ case 'b':
33+ case 't':
34+ /* ignore */
35+ break;
36+ case 'c':
37+ cryptfunc = cryptcheck;
38+ break;
39+ default:
40+ usage();
41+ } ARGEND
42+
43+ ret |= cryptfunc(argc, argv, &md5_ops, md, sizeof(md));
44+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
45+
46+ return ret;
47+}
+92,
-0
1@@ -0,0 +1,92 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <libgen.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <unistd.h>
8+
9+#include "util.h"
10+
11+static void
12+usage(void)
13+{
14+ eprintf("usage: %s [-dqtu] [-p directory] [template]\n", argv0);
15+}
16+
17+int
18+main(int argc, char *argv[])
19+{
20+ int dflag = 0, pflag = 0, qflag = 0, tflag = 0, uflag = 0, fd;
21+ char *template = "tmp.XXXXXXXXXX", *tmpdir = "", *pdir,
22+ *p, path[PATH_MAX], tmp[PATH_MAX];
23+ size_t len;
24+
25+ ARGBEGIN {
26+ case 'd':
27+ dflag = 1;
28+ break;
29+ case 'p':
30+ pflag = 1;
31+ pdir = EARGF(usage());
32+ break;
33+ case 'q':
34+ qflag = 1;
35+ break;
36+ case 't':
37+ tflag = 1;
38+ break;
39+ case 'u':
40+ uflag = 1;
41+ break;
42+ default:
43+ usage();
44+ } ARGEND
45+
46+ if (argc > 1)
47+ usage();
48+ else if (argc == 1)
49+ template = argv[0];
50+
51+ if (!argc || pflag || tflag) {
52+ if ((p = getenv("TMPDIR")))
53+ tmpdir = p;
54+ else if (pflag)
55+ tmpdir = pdir;
56+ else
57+ tmpdir = "/tmp";
58+ }
59+
60+ len = estrlcpy(path, tmpdir, sizeof(path));
61+ if (path[0] && path[len - 1] != '/')
62+ estrlcat(path, "/", sizeof(path));
63+
64+ estrlcpy(tmp, template, sizeof(tmp));
65+ p = dirname(tmp);
66+ if (!(p[0] == '.' && p[1] == '\0')) {
67+ if (tflag && !pflag)
68+ eprintf("template must not contain directory separators in -t mode\n");
69+ }
70+ estrlcat(path, template, sizeof(path));
71+
72+ if (dflag) {
73+ if (!mkdtemp(path)) {
74+ if (!qflag)
75+ eprintf("mkdtemp %s:", path);
76+ return 1;
77+ }
78+ } else {
79+ if ((fd = mkstemp(path)) < 0) {
80+ if (!qflag)
81+ eprintf("mkstemp %s:", path);
82+ return 1;
83+ }
84+ if (close(fd))
85+ eprintf("close %s:", path);
86+ }
87+ if (uflag)
88+ unlink(path);
89+ puts(path);
90+
91+ efshut(stdout, "<stdout>");
92+ return 0;
93+}
+22,
-0
1@@ -0,0 +1,22 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <stdio.h>
5+#include <unistd.h>
6+
7+int
8+main(void)
9+{
10+ int fd;
11+ char buf[BUFSIZ];
12+ ssize_t n;
13+
14+ fd = open("/etc/nologin.txt", O_RDONLY);
15+ if (fd >= 0) {
16+ while ((n = read(fd, buf, sizeof(buf))) > 0)
17+ write(STDOUT_FILENO, buf, n);
18+ close(fd);
19+ } else {
20+ printf("The account is currently unavailable.\n");
21+ }
22+ return 1;
23+}
+32,
-0
1@@ -0,0 +1,32 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ long pagesz;
19+
20+ ARGBEGIN {
21+ default:
22+ usage();
23+ } ARGEND;
24+
25+ pagesz = sysconf(_SC_PAGESIZE);
26+ if (pagesz <= 0) {
27+ pagesz = sysconf(_SC_PAGE_SIZE);
28+ if (pagesz <= 0)
29+ eprintf("can't determine pagesize\n");
30+ }
31+ printf("%ld\n", pagesz);
32+ return 0;
33+}
+39,
-0
1@@ -0,0 +1,39 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+
6+#include "util.h"
7+
8+extern char **environ;
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s [var ...]\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+ char *var;
20+ int ret = 0;
21+
22+ ARGBEGIN {
23+ default:
24+ usage();
25+ } ARGEND
26+
27+ if (!argc) {
28+ for (; *environ; environ++)
29+ puts(*environ);
30+ } else {
31+ for (; *argv; argc--, argv++) {
32+ if ((var = getenv(*argv)))
33+ puts(var);
34+ else
35+ ret = 1;
36+ }
37+ }
38+
39+ return fshut(stdout, "<stdout>") ? 2 : ret;
40+}
+113,
-0
1@@ -0,0 +1,113 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/time.h>
5+#include <sys/types.h>
6+#include <sys/wait.h>
7+
8+#include <errno.h>
9+#include <fcntl.h>
10+#include <poll.h>
11+#include <signal.h>
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <unistd.h>
15+
16+#include "util.h"
17+
18+static void
19+sigterm(int sig)
20+{
21+ if (sig == SIGTERM) {
22+ kill(0, SIGTERM);
23+ _exit(0);
24+ }
25+}
26+
27+static void
28+usage(void)
29+{
30+ eprintf("usage: %s [-l fifo] [-d N] cmd [args...]\n", argv0);
31+}
32+
33+int
34+main(int argc, char *argv[])
35+{
36+ char *fifo = NULL;
37+ unsigned int delay = 0;
38+ pid_t pid;
39+ char buf[BUFSIZ];
40+ int savederrno;
41+ ssize_t n;
42+ struct pollfd pollset[1];
43+ int polln;
44+
45+ ARGBEGIN {
46+ case 'd':
47+ delay = estrtol(EARGF(usage()), 0);
48+ break;
49+ case 'l':
50+ fifo = EARGF(usage());
51+ break;
52+ default:
53+ usage();
54+ } ARGEND;
55+
56+ if (argc < 1)
57+ usage();
58+
59+ if (fifo && delay > 0)
60+ usage();
61+
62+ setsid();
63+
64+ signal(SIGTERM, sigterm);
65+
66+ if (fifo) {
67+ pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
68+ if (pollset->fd < 0)
69+ eprintf("open %s:", fifo);
70+ pollset->events = POLLIN;
71+ }
72+
73+ while (1) {
74+ if (fifo) {
75+ pollset->revents = 0;
76+ polln = poll(pollset, 1, -1);
77+ if (polln <= 0) {
78+ if (polln == 0 || errno == EAGAIN)
79+ continue;
80+ eprintf("poll:");
81+ }
82+ while ((n = read(pollset->fd, buf, sizeof(buf))) > 0)
83+ ;
84+ if (n < 0)
85+ if (errno != EAGAIN)
86+ eprintf("read %s:", fifo);
87+ if (n == 0) {
88+ close(pollset->fd);
89+ pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
90+ if (pollset->fd < 0)
91+ eprintf("open %s:", fifo);
92+ pollset->events = POLLIN;
93+ }
94+ }
95+ pid = fork();
96+ if (pid < 0)
97+ eprintf("fork:");
98+ switch (pid) {
99+ case 0:
100+ execvp(argv[0], argv);
101+ savederrno = errno;
102+ weprintf("execvp %s:", argv[0]);
103+ _exit(savederrno == ENOENT ? 127 : 126);
104+ break;
105+ default:
106+ waitpid(pid, NULL, 0);
107+ break;
108+ }
109+ if (!fifo)
110+ sleep(delay);
111+ }
112+ /* not reachable */
113+ return 0;
114+}
+74,
-0
1@@ -0,0 +1,74 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <string.h>
5+#include <unistd.h>
6+
7+#include "text.h"
8+#include "util.h"
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s [file ...]\n", argv0);
14+}
15+
16+static void
17+rev(FILE *fp)
18+{
19+ static char *line = NULL;
20+ static size_t size = 0;
21+ size_t i;
22+ ssize_t n;
23+ int lf;
24+
25+ while ((n = getline(&line, &size, fp)) > 0) {
26+ lf = n && line[n - 1] == '\n';
27+ i = n -= lf;
28+ for (n = 0; i--;) {
29+ if (UTF8_POINT(line[i])) {
30+ n++;
31+ } else {
32+ fwrite(line + i, 1, n + 1, stdout);
33+ n = 0;
34+ }
35+ }
36+ if (n)
37+ fwrite(line, 1, n, stdout);
38+ if (lf)
39+ fputc('\n', stdout);
40+ }
41+}
42+
43+int
44+main(int argc, char *argv[])
45+{
46+ FILE *fp;
47+ int ret = 0;
48+
49+ ARGBEGIN {
50+ default:
51+ usage();
52+ } ARGEND
53+
54+ if (!argc) {
55+ rev(stdin);
56+ } else {
57+ for (; *argv; argc--, argv++) {
58+ if (!strcmp(*argv, "-")) {
59+ *argv = "<stdin>";
60+ fp = stdin;
61+ } else if (!(fp = fopen(*argv, "r"))) {
62+ weprintf("fopen %s:", *argv);
63+ ret = 1;
64+ continue;
65+ }
66+ rev(fp);
67+ if (fp != stdin && fshut(fp, *argv))
68+ ret = 1;
69+ }
70+ }
71+
72+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
73+
74+ return ret;
75+}
+147,
-0
1@@ -0,0 +1,147 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "util.h"
8+
9+static int
10+digitsleft(const char *d)
11+{
12+ int shift;
13+ char *exp;
14+
15+ if (*d == '+')
16+ d++;
17+ exp = strpbrk(d, "eE");
18+ shift = exp ? estrtonum(exp + 1, INT_MIN, INT_MAX) : 0;
19+
20+ return MAX(0, strspn(d, "-0123456789") + shift);
21+}
22+
23+static int
24+digitsright(const char *d)
25+{
26+ int shift, after;
27+ char *exp;
28+
29+ exp = strpbrk(d, "eE");
30+ shift = exp ? estrtonum(&exp[1], INT_MIN, INT_MAX) : 0;
31+ after = (d = strchr(d, '.')) ? strspn(&d[1], "0123456789") : 0;
32+
33+ return MAX(0, after - shift);
34+}
35+
36+static int
37+validfmt(const char *fmt)
38+{
39+ int occur = 0;
40+
41+literal:
42+ while (*fmt)
43+ if (*fmt++ == '%')
44+ goto format;
45+ return occur == 1;
46+
47+format:
48+ if (*fmt == '%') {
49+ fmt++;
50+ goto literal;
51+ }
52+ fmt += strspn(fmt, "-+#0 '");
53+ fmt += strspn(fmt, "0123456789");
54+ if (*fmt == '.') {
55+ fmt++;
56+ fmt += strspn(fmt, "0123456789");
57+ }
58+ if (*fmt == 'L')
59+ fmt++;
60+
61+ switch (*fmt) {
62+ case 'f': case 'F':
63+ case 'g': case 'G':
64+ case 'e': case 'E':
65+ case 'a': case 'A':
66+ occur++;
67+ goto literal;
68+ default:
69+ return 0;
70+ }
71+}
72+
73+static void
74+usage(void)
75+{
76+ eprintf("usage: %s [-f fmt] [-s sep] [-w] "
77+ "[startnum [step]] endnum\n", argv0);
78+}
79+
80+int
81+main(int argc, char *argv[])
82+{
83+ double start, step, end, out, dir;
84+ int wflag = 0, left, right;
85+ char *tmp, ftmp[BUFSIZ], *fmt = ftmp;
86+ const char *starts = "1", *steps = "1", *ends = "1", *sep = "\n";
87+
88+ ARGBEGIN {
89+ case 'f':
90+ if (!validfmt(tmp=EARGF(usage())))
91+ eprintf("%s: invalid format\n", tmp);
92+ fmt = tmp;
93+ break;
94+ case 's':
95+ sep = EARGF(usage());
96+ break;
97+ case 'w':
98+ wflag = 1;
99+ break;
100+ default:
101+ usage();
102+ } ARGEND
103+
104+ switch (argc) {
105+ case 3:
106+ steps = argv[1];
107+ argv[1] = argv[2];
108+ /* fallthrough */
109+ case 2:
110+ starts = argv[0];
111+ argv++;
112+ /* fallthrough */
113+ case 1:
114+ ends = argv[0];
115+ break;
116+ default:
117+ usage();
118+ }
119+ start = estrtod(starts);
120+ step = estrtod(steps);
121+ end = estrtod(ends);
122+
123+ dir = (step > 0) ? 1.0 : -1.0;
124+ if (step == 0 || start * dir > end * dir)
125+ return 1;
126+
127+ if (fmt == ftmp) {
128+ right = MAX(digitsright(starts),
129+ MAX(digitsright(ends),
130+ digitsright(steps)));
131+
132+ if (wflag) {
133+ left = MAX(digitsleft(starts), digitsleft(ends));
134+
135+ snprintf(ftmp, sizeof ftmp, "%%0%d.%df",
136+ right + left + (right != 0), right);
137+ } else
138+ snprintf(ftmp, sizeof ftmp, "%%.%df", right);
139+ }
140+ for (out = start; out * dir <= end * dir; out += step) {
141+ if (out != start)
142+ fputs(sep, stdout);
143+ printf(fmt, out);
144+ }
145+ putchar('\n');
146+
147+ return fshut(stdout, "<stdout>");
148+}
+48,
-0
1@@ -0,0 +1,48 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <unistd.h>
5+
6+#include "util.h"
7+
8+static int fflag = 0;
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s [-f] cmd [arg ...]\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+ int savederrno;
20+
21+ ARGBEGIN {
22+ case 'f':
23+ fflag = 1;
24+ break;
25+ default:
26+ usage();
27+ } ARGEND
28+
29+ if (!argc)
30+ usage();
31+
32+ if (fflag || getpgrp() == getpid()) {
33+ switch (fork()) {
34+ case -1:
35+ eprintf("fork:");
36+ case 0:
37+ break;
38+ default:
39+ return 0;
40+ }
41+ }
42+ if (setsid() < 0)
43+ eprintf("setsid:");
44+ execvp(argv[0], argv);
45+ savederrno = errno;
46+ weprintf("execvp %s:", argv[0]);
47+
48+ _exit(126 + (savederrno == ENOENT));
49+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha1.h"
8+#include "util.h"
9+
10+static struct sha1 s;
11+struct crypt_ops sha1_ops = {
12+ sha1_init,
13+ sha1_update,
14+ sha1_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA1_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha1_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha224.h"
8+#include "util.h"
9+
10+static struct sha224 s;
11+struct crypt_ops sha224_ops = {
12+ sha224_init,
13+ sha224_update,
14+ sha224_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA224_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha224_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha256.h"
8+#include "util.h"
9+
10+static struct sha256 s;
11+struct crypt_ops sha256_ops = {
12+ sha256_init,
13+ sha256_update,
14+ sha256_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA256_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha256_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha384.h"
8+#include "util.h"
9+
10+static struct sha384 s;
11+struct crypt_ops sha384_ops = {
12+ sha384_init,
13+ sha384_update,
14+ sha384_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA384_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha384_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha512-224.h"
8+#include "util.h"
9+
10+static struct sha512_224 s;
11+struct crypt_ops sha512_224_ops = {
12+ sha512_224_init,
13+ sha512_224_update,
14+ sha512_224_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA512_224_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha512_224_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha512-256.h"
8+#include "util.h"
9+
10+static struct sha512_256 s;
11+struct crypt_ops sha512_256_ops = {
12+ sha512_256_init,
13+ sha512_256_update,
14+ sha512_256_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA512_256_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha512_256_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+45,
-0
1@@ -0,0 +1,45 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdint.h>
4+#include <stdio.h>
5+
6+#include "crypt.h"
7+#include "sha512.h"
8+#include "util.h"
9+
10+static struct sha512 s;
11+struct crypt_ops sha512_ops = {
12+ sha512_init,
13+ sha512_update,
14+ sha512_sum,
15+ &s,
16+};
17+
18+static void
19+usage(void)
20+{
21+ eprintf("usage: %s [-c] [file ...]\n", argv0);
22+}
23+
24+int
25+main(int argc, char *argv[])
26+{
27+ int ret = 0, (*cryptfunc)(int, char **, struct crypt_ops *, uint8_t *, size_t) = cryptmain;
28+ uint8_t md[SHA512_DIGEST_LENGTH];
29+
30+ ARGBEGIN {
31+ case 'b':
32+ case 't':
33+ /* ignore */
34+ break;
35+ case 'c':
36+ cryptfunc = cryptcheck;
37+ break;
38+ default:
39+ usage();
40+ } ARGEND
41+
42+ ret |= cryptfunc(argc, argv, &sha512_ops, md, sizeof(md));
43+ ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
44+
45+ return ret;
46+}
+42,
-0
1@@ -0,0 +1,42 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <stdlib.h>
5+#include <unistd.h>
6+
7+#include "util.h"
8+
9+static void
10+usage(void)
11+{
12+ eprintf("usage: %s file\n", argv0);
13+}
14+
15+int
16+main(int argc, char *argv[])
17+{
18+ char tmp[] = "/tmp/sponge-XXXXXX";
19+ int fd, tmpfd;
20+
21+ ARGBEGIN {
22+ default:
23+ usage();
24+ } ARGEND
25+
26+ if (argc != 1)
27+ usage();
28+
29+ if ((tmpfd = mkstemp(tmp)) < 0)
30+ eprintf("mkstemp:");
31+ unlink(tmp);
32+ if (concat(0, "<stdin>", tmpfd, "<tmpfile>") < 0)
33+ return 1;
34+ if (lseek(tmpfd, 0, SEEK_SET) < 0)
35+ eprintf("lseek:");
36+
37+ if ((fd = creat(argv[0], 0666)) < 0)
38+ eprintf("creat %s:", argv[0]);
39+ if (concat(tmpfd, "<tmpfile>", fd, argv[0]) < 0)
40+ return 1;
41+
42+ return 0;
43+}
+90,
-0
1@@ -0,0 +1,90 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/sysmacros.h>
5+#include <sys/types.h>
6+
7+#include <inttypes.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <time.h>
11+#include <unistd.h>
12+
13+#include "util.h"
14+
15+static void
16+show_stat_terse(const char *file, struct stat *st)
17+{
18+ printf("%s ", file);
19+ printf("%lu %lu ", (unsigned long)st->st_size,
20+ (unsigned long)st->st_blocks);
21+ printf("%04o %u %u ", st->st_mode & 0777, st->st_uid, st->st_gid);
22+ printf("%llx ", (unsigned long long)st->st_dev);
23+ printf("%lu %lu ", (unsigned long)st->st_ino, (unsigned long)st->st_nlink);
24+ printf("%d %d ", major(st->st_rdev), minor(st->st_rdev));
25+ printf("%ld %ld %ld ", st->st_atime, st->st_mtime, st->st_ctime);
26+ printf("%lu\n", (unsigned long)st->st_blksize);
27+}
28+
29+static void
30+show_stat(const char *file, struct stat *st)
31+{
32+ char buf[100];
33+
34+ printf(" File: â%sâ\n", file);
35+ printf(" Size: %lu\tBlocks: %lu\tIO Block: %lu\n", (unsigned long)st->st_size,
36+ (unsigned long)st->st_blocks, (unsigned long)st->st_blksize);
37+ printf("Device: %xh/%ud\tInode: %lu\tLinks %lu\n", major(st->st_dev),
38+ minor(st->st_dev), (unsigned long)st->st_ino, (unsigned long)st->st_nlink);
39+ printf("Access: %04o\tUid: %u\tGid: %u\n", st->st_mode & 0777, st->st_uid, st->st_gid);
40+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_atime));
41+ printf("Access: %s\n", buf);
42+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_mtime));
43+ printf("Modify: %s\n", buf);
44+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_ctime));
45+ printf("Change: %s\n", buf);
46+}
47+
48+static void
49+usage(void)
50+{
51+ eprintf("usage: %s [-L] [-t] [file...]\n", argv0);
52+}
53+
54+int
55+main(int argc, char *argv[])
56+{
57+ struct stat st;
58+ int i, ret = 0;
59+ int (*fn)(const char *, struct stat *) = lstat;
60+ char *fnname = "lstat";
61+ void (*showstat)(const char *, struct stat *) = show_stat;
62+
63+ ARGBEGIN {
64+ case 'L':
65+ fn = stat;
66+ fnname = "stat";
67+ break;
68+ case 't':
69+ showstat = show_stat_terse;
70+ break;
71+ default:
72+ usage();
73+ } ARGEND;
74+
75+ if (argc == 0) {
76+ if (fstat(0, &st) < 0)
77+ eprintf("stat <stdin>:");
78+ show_stat("<stdin>", &st);
79+ }
80+
81+ for (i = 0; i < argc; i++) {
82+ if (fn(argv[i], &st) == -1) {
83+ weprintf("%s %s:", fnname, argv[i]);
84+ ret = 1;
85+ continue;
86+ }
87+ showstat(argv[i], &st);
88+ }
89+
90+ return ret;
91+}
+697,
-0
1@@ -0,0 +1,697 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/time.h>
5+#include <sys/types.h>
6+#ifndef major
7+#include <sys/sysmacros.h>
8+#endif
9+
10+#include <assert.h>
11+#include <errno.h>
12+#include <fcntl.h>
13+#include <grp.h>
14+#include <libgen.h>
15+#include <pwd.h>
16+#include <stdio.h>
17+#include <stdlib.h>
18+#include <string.h>
19+#include <unistd.h>
20+
21+#include "fs.h"
22+#include "utf.h"
23+#include "util.h"
24+
25+#ifdef STD_NON_POSIX
26+static void
27+safe_puts(const char *s)
28+{
29+ Rune r;
30+ int n;
31+
32+ if (isatty(1)) {
33+ while (*s) {
34+ n = chartorune(&r, s);
35+ if (r == Runeerror) {
36+ putchar('?');
37+ s++;
38+ } else if (isprintrune(r)) {
39+ fputrune(&r, stdout);
40+ s += n;
41+ } else {
42+ putchar('?');
43+ s += n;
44+ }
45+ }
46+ putchar('\n');
47+ } else {
48+ puts(s);
49+ }
50+}
51+#else
52+#define safe_puts(s) puts(s)
53+#endif
54+
55+#define BLKSIZ (sizeof (struct header)) /* must equal 512 bytes */
56+
57+enum Type {
58+ REG = '0',
59+ AREG = '\0',
60+ HARDLINK = '1',
61+ SYMLINK = '2',
62+ CHARDEV = '3',
63+ BLOCKDEV = '4',
64+ DIRECTORY = '5',
65+ FIFO = '6',
66+ RESERVED = '7'
67+};
68+
69+struct header {
70+ char name[100];
71+ char mode[8];
72+ char uid[8];
73+ char gid[8];
74+ char size[12];
75+ char mtime[12];
76+ char chksum[8];
77+ char type;
78+ char linkname[100];
79+ char magic[6];
80+ char version[2];
81+ char uname[32];
82+ char gname[32];
83+ char major[8];
84+ char minor[8];
85+ char prefix[155];
86+ char padding[12];
87+};
88+
89+static struct dirtime {
90+ char *name;
91+ time_t mtime;
92+} *dirtimes;
93+
94+static size_t dirtimeslen;
95+
96+static int tarfd;
97+static ino_t tarinode;
98+static dev_t tardev;
99+
100+static int mflag, vflag;
101+static int filtermode;
102+static const char *filtertool;
103+
104+static const char *filtertools[] = {
105+ ['J'] = "xz",
106+ ['Z'] = "compress",
107+ ['a'] = "lzma",
108+ ['j'] = "bzip2",
109+ ['z'] = "gzip",
110+};
111+
112+static void
113+pushdirtime(char *name, time_t mtime)
114+{
115+ dirtimes = ereallocarray(dirtimes, dirtimeslen + 1, sizeof(*dirtimes));
116+ dirtimes[dirtimeslen].name = estrdup(name);
117+ dirtimes[dirtimeslen].mtime = mtime;
118+ dirtimeslen++;
119+}
120+
121+static struct dirtime *
122+popdirtime(void)
123+{
124+ if (dirtimeslen) {
125+ dirtimeslen--;
126+ return &dirtimes[dirtimeslen];
127+ }
128+ return NULL;
129+}
130+
131+static int
132+comp(int fd, const char *tool, const char *flags)
133+{
134+ int fds[2];
135+
136+ if (pipe(fds) < 0)
137+ eprintf("pipe:");
138+
139+ switch (fork()) {
140+ case -1:
141+ eprintf("fork:");
142+ case 0:
143+ dup2(fd, 1);
144+ dup2(fds[0], 0);
145+ close(fds[0]);
146+ close(fds[1]);
147+
148+ execlp(tool, tool, flags, NULL);
149+ weprintf("execlp %s:", tool);
150+ _exit(1);
151+ }
152+ close(fds[0]);
153+ return fds[1];
154+}
155+
156+static int
157+decomp(int fd, const char *tool, const char *flags)
158+{
159+ int fds[2];
160+
161+ if (pipe(fds) < 0)
162+ eprintf("pipe:");
163+
164+ switch (fork()) {
165+ case -1:
166+ eprintf("fork:");
167+ case 0:
168+ dup2(fd, 0);
169+ dup2(fds[1], 1);
170+ close(fds[0]);
171+ close(fds[1]);
172+
173+ execlp(tool, tool, flags, NULL);
174+ weprintf("execlp %s:", tool);
175+ _exit(1);
176+ }
177+ close(fds[1]);
178+ return fds[0];
179+}
180+
181+static ssize_t
182+eread(int fd, void *buf, size_t n)
183+{
184+ ssize_t r;
185+
186+again:
187+ r = read(fd, buf, n);
188+ if (r < 0) {
189+ if (errno == EINTR)
190+ goto again;
191+ eprintf("read:");
192+ }
193+ return r;
194+}
195+
196+static ssize_t
197+ewrite(int fd, const void *buf, size_t n)
198+{
199+ ssize_t r;
200+
201+ if ((r = write(fd, buf, n)) != n)
202+ eprintf("write:");
203+ return r;
204+}
205+
206+static unsigned
207+chksum(struct header *h)
208+{
209+ unsigned sum, i;
210+
211+ memset(h->chksum, ' ', sizeof(h->chksum));
212+ for (i = 0, sum = 0, assert(BLKSIZ == 512); i < BLKSIZ; i++)
213+ sum += *((unsigned char *)h + i);
214+ return sum;
215+}
216+
217+static void
218+putoctal(char *dst, unsigned num, int size)
219+{
220+ if (snprintf(dst, size, "%.*o", size - 1, num) >= size)
221+ eprintf("putoctal: input number '%o' too large\n", num);
222+}
223+
224+static int
225+archive(const char *path)
226+{
227+ static const struct header blank = {
228+ "././@LongLink", "0000600", "0000000", "0000000", "00000000000",
229+ "00000000000" , " ", AREG , "" , "ustar", "00",
230+ };
231+ char b[BLKSIZ + BLKSIZ], *p;
232+ struct header *h = (struct header *)b;
233+ struct group *gr;
234+ struct passwd *pw;
235+ struct stat st;
236+ ssize_t l, n, r;
237+ int fd = -1;
238+
239+ if (lstat(path, &st) < 0) {
240+ weprintf("lstat %s:", path);
241+ return 0;
242+ } else if (st.st_ino == tarinode && st.st_dev == tardev) {
243+ weprintf("ignoring %s\n", path);
244+ return 0;
245+ }
246+ pw = getpwuid(st.st_uid);
247+ gr = getgrgid(st.st_gid);
248+
249+ *h = blank;
250+ n = strlcpy(h->name, path, sizeof(h->name));
251+ if (n >= sizeof(h->name)) {
252+ *++h = blank;
253+ h->type = 'L';
254+ putoctal(h->size, n, sizeof(h->size));
255+ putoctal(h->chksum, chksum(h), sizeof(h->chksum));
256+ ewrite(tarfd, (char *)h, BLKSIZ);
257+
258+ for (p = (char *)path; n > 0; n -= BLKSIZ, p += BLKSIZ) {
259+ if (n < BLKSIZ) {
260+ p = memcpy(h--, p, n);
261+ memset(p + n, 0, BLKSIZ - n);
262+ }
263+ ewrite(tarfd, p, BLKSIZ);
264+ }
265+ }
266+
267+ putoctal(h->mode, (unsigned)st.st_mode & 0777, sizeof(h->mode));
268+ putoctal(h->uid, (unsigned)st.st_uid, sizeof(h->uid));
269+ putoctal(h->gid, (unsigned)st.st_gid, sizeof(h->gid));
270+ putoctal(h->mtime, (unsigned)st.st_mtime, sizeof(h->mtime));
271+ estrlcpy(h->uname, pw ? pw->pw_name : "", sizeof(h->uname));
272+ estrlcpy(h->gname, gr ? gr->gr_name : "", sizeof(h->gname));
273+
274+ if (S_ISREG(st.st_mode)) {
275+ h->type = REG;
276+ putoctal(h->size, st.st_size, sizeof(h->size));
277+ fd = open(path, O_RDONLY);
278+ if (fd < 0)
279+ eprintf("open %s:", path);
280+ } else if (S_ISDIR(st.st_mode)) {
281+ h->type = DIRECTORY;
282+ } else if (S_ISLNK(st.st_mode)) {
283+ h->type = SYMLINK;
284+ if ((r = readlink(path, h->linkname, sizeof(h->linkname) - 1)) < 0)
285+ eprintf("readlink %s:", path);
286+ h->linkname[r] = '\0';
287+ } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
288+ h->type = S_ISCHR(st.st_mode) ? CHARDEV : BLOCKDEV;
289+ putoctal(h->major, (unsigned)major(st.st_dev), sizeof(h->major));
290+ putoctal(h->minor, (unsigned)minor(st.st_dev), sizeof(h->minor));
291+ } else if (S_ISFIFO(st.st_mode)) {
292+ h->type = FIFO;
293+ }
294+
295+ putoctal(h->chksum, chksum(h), sizeof(h->chksum));
296+ ewrite(tarfd, b, BLKSIZ);
297+
298+ if (fd != -1) {
299+ while ((l = eread(fd, b, BLKSIZ)) > 0) {
300+ if (l < BLKSIZ)
301+ memset(b + l, 0, BLKSIZ - l);
302+ ewrite(tarfd, b, BLKSIZ);
303+ }
304+ close(fd);
305+ }
306+
307+ return 0;
308+}
309+
310+static int
311+unarchive(char *fname, ssize_t l, char b[BLKSIZ])
312+{
313+ struct header *h = (struct header *)b;
314+ struct timespec times[2];
315+ char lname[101], *tmp, *p;
316+ long mode, major, minor, type, mtime, uid, gid;
317+ int fd = -1, lnk = h->type == SYMLINK;
318+
319+ if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0'))
320+ eprintf("strtol %s: invalid mtime\n", h->mtime);
321+ if (strcmp(fname, ".") && strcmp(fname, "./") && remove(fname) < 0)
322+ if (errno != ENOENT) weprintf("remove %s:", fname);
323+
324+ tmp = estrdup(fname);
325+ mkdirp(dirname(tmp), 0777, 0777);
326+ free(tmp);
327+
328+ switch (h->type) {
329+ case REG:
330+ case AREG:
331+ case RESERVED:
332+ if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
333+ eprintf("strtol %s: invalid mode\n", h->mode);
334+#ifdef STD_NON_POSIX
335+ fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT | O_NOFOLLOW, 0600);
336+#else
337+ fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
338+#endif
339+ if (fd < 0)
340+ eprintf("open %s:", fname);
341+ break;
342+ case HARDLINK:
343+ case SYMLINK:
344+ snprintf(lname, sizeof(lname), "%.*s", (int)sizeof(h->linkname),
345+ h->linkname);
346+ if ((lnk ? symlink:link)(lname, fname) < 0)
347+ eprintf("%s %s -> %s:", lnk ? "symlink":"link", fname, lname);
348+ lnk++;
349+ break;
350+ case DIRECTORY:
351+ if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
352+ eprintf("strtol %s: invalid mode\n", h->mode);
353+ if (mkdir(fname, (mode_t)mode) < 0 && errno != EEXIST)
354+ eprintf("mkdir %s:", fname);
355+ pushdirtime(fname, mtime);
356+ break;
357+ case CHARDEV:
358+ case BLOCKDEV:
359+ if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
360+ eprintf("strtol %s: invalid mode\n", h->mode);
361+ if ((major = strtol(h->major, &p, 8)) < 0 || *p != '\0')
362+ eprintf("strtol %s: invalid major device\n", h->major);
363+ if ((minor = strtol(h->minor, &p, 8)) < 0 || *p != '\0')
364+ eprintf("strtol %s: invalid minor device\n", h->minor);
365+ type = (h->type == CHARDEV) ? S_IFCHR : S_IFBLK;
366+ if (mknod(fname, type | mode, makedev(major, minor)) < 0)
367+ eprintf("mknod %s:", fname);
368+ break;
369+ case FIFO:
370+ if ((mode = strtol(h->mode, &p, 8)) < 0 || *p != '\0')
371+ eprintf("strtol %s: invalid mode\n", h->mode);
372+ if (mknod(fname, S_IFIFO | mode, 0) < 0)
373+ eprintf("mknod %s:", fname);
374+ break;
375+ default:
376+ eprintf("unsupported tar-filetype %c\n", h->type);
377+ }
378+
379+ if ((uid = strtol(h->uid, &p, 8)) < 0 || *p != '\0')
380+ eprintf("strtol %s: invalid uid\n", h->uid);
381+ if ((gid = strtol(h->gid, &p, 8)) < 0 || *p != '\0')
382+ eprintf("strtol %s: invalid gid\n", h->gid);
383+
384+ if (fd != -1) {
385+ for (; l > 0; l -= BLKSIZ)
386+ if (eread(tarfd, b, BLKSIZ) > 0)
387+ ewrite(fd, b, MIN(l, BLKSIZ));
388+ close(fd);
389+ }
390+
391+ if (lnk == 1)
392+ return 0;
393+
394+ times[0].tv_sec = times[1].tv_sec = mtime;
395+ times[0].tv_nsec = times[1].tv_nsec = 0;
396+ if (!mflag && utimensat(AT_FDCWD, fname, times, AT_SYMLINK_NOFOLLOW) < 0)
397+ weprintf("utimensat %s:", fname);
398+ if (lnk) {
399+ if (!getuid() && lchown(fname, uid, gid))
400+ weprintf("lchown %s:", fname);
401+ } else {
402+ if (!getuid() && chown(fname, uid, gid))
403+ weprintf("chown %s:", fname);
404+ if (chmod(fname, mode) < 0)
405+ eprintf("fchmod %s:", fname);
406+ }
407+
408+ return 0;
409+}
410+
411+static void
412+skipblk(ssize_t l)
413+{
414+ char b[BLKSIZ];
415+
416+ for (; l > 0; l -= BLKSIZ)
417+ if (!eread(tarfd, b, BLKSIZ))
418+ break;
419+}
420+
421+static int
422+print(char *fname, ssize_t l, char b[BLKSIZ])
423+{
424+ safe_puts(fname);
425+ skipblk(l);
426+ return 0;
427+}
428+
429+static void
430+c(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
431+{
432+ archive(r->path);
433+ if (vflag)
434+ safe_puts(r->path);
435+
436+ if (S_ISDIR(st->st_mode))
437+ recurse(dirfd, name, NULL, r);
438+}
439+
440+static void
441+sanitize(struct header *h)
442+{
443+ size_t i, j, l;
444+ struct {
445+ char *f;
446+ size_t l;
447+ } fields[] = {
448+ { h->mode, sizeof(h->mode) },
449+ { h->uid, sizeof(h->uid) },
450+ { h->gid, sizeof(h->gid) },
451+ { h->size, sizeof(h->size) },
452+ { h->mtime, sizeof(h->mtime) },
453+ { h->chksum, sizeof(h->chksum) },
454+ { h->major, sizeof(h->major) },
455+ { h->minor, sizeof(h->minor) }
456+ };
457+
458+ /* Numeric fields can be terminated with spaces instead of
459+ * NULs as per the ustar specification. Patch all of them to
460+ * use NULs so we can perform string operations on them. */
461+ for (i = 0; i < LEN(fields); i++){
462+ j = 0, l = fields[i].l - 1;
463+ for (; j < l && fields[i].f[j] == ' '; j++);
464+ for (; j <= l; j++)
465+ if (fields[i].f[j] == ' ')
466+ fields[i].f[j] = '\0';
467+ if (fields[i].f[l])
468+ eprintf("numeric field #%d (%.*s) is not null or space terminated\n",
469+ i, l+1, fields[i].f);
470+ }
471+}
472+
473+static void
474+chktar(struct header *h)
475+{
476+ const char *reason;
477+ char tmp[sizeof h->chksum], *err;
478+ long sum, i;
479+
480+ if (h->prefix[0] == '\0' && h->name[0] == '\0') {
481+ reason = "empty filename";
482+ goto bad;
483+ }
484+ if (h->magic[0] && strncmp("ustar", h->magic, 5)) {
485+ reason = "not ustar format";
486+ goto bad;
487+ }
488+ memcpy(tmp, h->chksum, sizeof(tmp));
489+ for (i = sizeof(tmp)-1; i > 0 && tmp[i] == ' '; i--) {
490+ tmp[i] = '\0';
491+ }
492+ sum = strtol(tmp, &err, 8);
493+ if (sum < 0 || sum >= BLKSIZ*256 || *err != '\0') {
494+ reason = "invalid checksum";
495+ goto bad;
496+ }
497+ if (sum != chksum(h)) {
498+ reason = "incorrect checksum";
499+ goto bad;
500+ }
501+ memcpy(h->chksum, tmp, sizeof(tmp));
502+ return;
503+bad:
504+ eprintf("malformed tar archive: %s\n", reason);
505+}
506+
507+static void
508+xt(int argc, char *argv[], int mode)
509+{
510+ long size;
511+ char b[BLKSIZ], fname[PATH_MAX + 1], *p, *q = NULL;
512+ int i, m, n;
513+ int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print;
514+ struct timespec times[2];
515+ struct header *h = (struct header *)b;
516+ struct dirtime *dirtime;
517+
518+ while (eread(tarfd, b, BLKSIZ) > 0 && (h->name[0] || h->prefix[0])) {
519+ chktar(h);
520+ sanitize(h);
521+
522+ if ((size = strtol(h->size, &p, 8)) < 0 || *p != '\0')
523+ eprintf("strtol %s: invalid size\n", h->size);
524+
525+ /* Long file path is read directly into fname*/
526+ if (h->type == 'L' || h->type == 'x' || h->type == 'g') {
527+
528+ /* Read header only up to size of fname buffer */
529+ for (q = fname; q < fname+size; q += BLKSIZ) {
530+ if (q + BLKSIZ >= fname + sizeof fname)
531+ eprintf("name exceeds buffer: %.*s\n", q-fname, fname);
532+ eread(tarfd, q, BLKSIZ);
533+ }
534+
535+ /* Convert pax x header with 'path=' field into L header */
536+ if (h->type == 'x') for (q = fname; q < fname+size-16; q += n) {
537+ if ((n = strtol(q, &p, 10)) < 0 || *p != ' ')
538+ eprintf("strtol %.*s: invalid number\n", p+1-q, q);
539+ if (n && strncmp(p+1, "path=", 5) == 0) {
540+ memmove(fname, p+6, size = q+n - p-6 - 1);
541+ h->type = 'L';
542+ break;
543+ }
544+ }
545+ fname[size] = '\0';
546+
547+ /* Non L-like header (eg. pax 'g') is skipped by setting q=null */
548+ if (h->type != 'L')
549+ q = NULL;
550+ continue;
551+ }
552+
553+ /* Ustar path is copied into fname if no L header (ie: q is NULL) */
554+ if (!q) {
555+ m = sizeof h->prefix, n = sizeof h->name;
556+ p = "/" + !h->prefix[0];
557+ snprintf(fname, sizeof fname, "%.*s%s%.*s", m, h->prefix, p, n, h->name);
558+ }
559+ q = NULL;
560+
561+ /* If argc > 0 then only extract the given files/dirs */
562+ if (argc) {
563+ for (i = 0; i < argc; i++) {
564+ if (strncmp(argv[i], fname, n = strlen(argv[i])) == 0)
565+ if (strchr("/", fname[n]) || argv[i][n-1] == '/')
566+ break;
567+ }
568+ if (i == argc) {
569+ skipblk(size);
570+ continue;
571+ }
572+ }
573+
574+ fn(fname, size, b);
575+ if (vflag && mode != 't')
576+ safe_puts(fname);
577+ }
578+
579+ if (mode == 'x' && !mflag) {
580+ while ((dirtime = popdirtime())) {
581+ times[0].tv_sec = times[1].tv_sec = dirtime->mtime;
582+ times[0].tv_nsec = times[1].tv_nsec = 0;
583+ if (utimensat(AT_FDCWD, dirtime->name, times, 0) < 0)
584+ eprintf("utimensat %s:", fname);
585+ free(dirtime->name);
586+ }
587+ free(dirtimes);
588+ dirtimes = NULL;
589+ }
590+}
591+
592+char **args;
593+int argn;
594+
595+static void
596+usage(void)
597+{
598+ eprintf("usage: %s [x | t | -x | -t] [-C dir] [-J | -Z | -a | -j | -z] [-m] [-p] "
599+ "[-f file] [file ...]\n"
600+ " %s [c | -c] [-C dir] [-J | -Z | -a | -j | -z] [-h] path ... "
601+ "[-f file]\n", argv0, argv0);
602+}
603+
604+int
605+main(int argc, char *argv[])
606+{
607+ struct recursor r = { .fn = c, .follow = 'P', .flags = DIRFIRST };
608+ struct stat st;
609+ char *file = NULL, *dir = ".", mode = '\0';
610+ int fd;
611+
612+ argv0 = argv[0];
613+ if (argc > 1 && strchr("cxt", mode = *argv[1]))
614+ *(argv[1]+1) ? *argv[1] = '-' : (*++argv = argv0, --argc);
615+
616+ ARGBEGIN {
617+ case 'x':
618+ case 'c':
619+ case 't':
620+ mode = ARGC();
621+ break;
622+ case 'C':
623+ dir = EARGF(usage());
624+ break;
625+ case 'f':
626+ file = EARGF(usage());
627+ break;
628+ case 'm':
629+ mflag = 1;
630+ break;
631+ case 'J':
632+ case 'Z':
633+ case 'a':
634+ case 'j':
635+ case 'z':
636+ filtermode = ARGC();
637+ filtertool = filtertools[filtermode];
638+ break;
639+ case 'h':
640+ r.follow = 'L';
641+ break;
642+ case 'v':
643+ vflag = 1;
644+ break;
645+ case 'p':
646+ break; /* Do nothing as already default behaviour */
647+ default:
648+ usage();
649+ } ARGEND
650+
651+ switch (mode) {
652+ case 'c':
653+ if (!argc)
654+ usage();
655+ tarfd = 1;
656+ if (file && *file != '-') {
657+ tarfd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
658+ if (tarfd < 0)
659+ eprintf("open %s:", file);
660+ if (lstat(file, &st) < 0)
661+ eprintf("lstat %s:", file);
662+ tarinode = st.st_ino;
663+ tardev = st.st_dev;
664+ }
665+
666+ if (filtertool)
667+ tarfd = comp(tarfd, filtertool, "-cf");
668+
669+ if (chdir(dir) < 0)
670+ eprintf("chdir %s:", dir);
671+ for (; *argv; argc--, argv++)
672+ recurse(AT_FDCWD, *argv, NULL, &r);
673+ break;
674+ case 't':
675+ case 'x':
676+ tarfd = 0;
677+ if (file && *file != '-') {
678+ tarfd = open(file, O_RDONLY);
679+ if (tarfd < 0)
680+ eprintf("open %s:", file);
681+ }
682+
683+ if (filtertool) {
684+ fd = tarfd;
685+ tarfd = decomp(tarfd, filtertool, "-cdf");
686+ close(fd);
687+ }
688+
689+ if (chdir(dir) < 0)
690+ eprintf("chdir %s:", dir);
691+ xt(argc, argv, mode);
692+ break;
693+ default:
694+ usage();
695+ }
696+
697+ return recurse_status;
698+}
+53,
-0
1@@ -0,0 +1,53 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <fcntl.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <unistd.h>
9+
10+#include "util.h"
11+
12+static void
13+usage(void)
14+{
15+ eprintf("usage: %s [-c] -s size file...\n", argv0);
16+}
17+
18+int
19+main(int argc, char *argv[])
20+{
21+ int cflag = 0, sflag = 0;
22+ int fd, i, ret = 0;
23+ long size = 0;
24+
25+ ARGBEGIN {
26+ case 's':
27+ sflag = 1;
28+ size = estrtol(EARGF(usage()), 10);
29+ break;
30+ case 'c':
31+ cflag = 1;
32+ break;
33+ default:
34+ usage();
35+ } ARGEND;
36+
37+ if (argc < 1 || sflag == 0)
38+ usage();
39+
40+ for (i = 0; i < argc; i++) {
41+ fd = open(argv[i], O_WRONLY | (cflag ? 0 : O_CREAT), 0644);
42+ if (fd < 0) {
43+ weprintf("open: cannot open `%s' for writing:", argv[i]);
44+ ret = 1;
45+ continue;
46+ }
47+ if (ftruncate(fd, size) < 0) {
48+ weprintf("ftruncate: cannot open `%s' for writing:", argv[i]);
49+ ret = 1;
50+ }
51+ close(fd);
52+ }
53+ return ret;
54+}
+58,
-0
1@@ -0,0 +1,58 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <unistd.h>
7+
8+#include "util.h"
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s [-t] [-n interval] command\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+ char cmd[BUFSIZ];
20+ char *end;
21+ useconds_t interval = 2 * 1E6;
22+ float period;
23+ int i;
24+
25+ ARGBEGIN {
26+ case 't':
27+ break;
28+ case 'n':
29+ period = strtof(EARGF(usage()), &end);
30+ if (*end != '\0' || errno != 0)
31+ eprintf("invalid interval\n");
32+ if (period < 0)
33+ period = 0.1f;
34+ interval = period * 1E6;
35+ break;
36+ default:
37+ usage();
38+ } ARGEND;
39+
40+ if (argc < 1)
41+ usage();
42+
43+ if (strlcpy(cmd, argv[0], sizeof(cmd)) >= sizeof(cmd))
44+ eprintf("command too long\n");
45+ for (i = 1; i < argc; i++) {
46+ if (strlcat(cmd, " ", sizeof(cmd)) >= sizeof(cmd))
47+ eprintf("command too long\n");
48+ if (strlcat(cmd, argv[i], sizeof(cmd)) >= sizeof(cmd))
49+ eprintf("command too long\n");
50+ }
51+
52+ for (;;) {
53+ printf("\x1b[2J\x1b[H"); /* clear */
54+ fflush(NULL);
55+ system(cmd);
56+ usleep(interval);
57+ }
58+ return 0;
59+}
+101,
-0
1@@ -0,0 +1,101 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/types.h>
5+
6+#include <fcntl.h>
7+#include <limits.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "util.h"
14+
15+static int aflag;
16+
17+static int
18+canexec(int fd, const char *name)
19+{
20+ struct stat st;
21+
22+ if (fstatat(fd, name, &st, 0) < 0 || !S_ISREG(st.st_mode))
23+ return 0;
24+ return faccessat(fd, name, X_OK, AT_EACCESS) == 0;
25+}
26+
27+static int
28+which(const char *path, const char *name)
29+{
30+ char *ptr, *p;
31+ size_t i, len;
32+ int dirfd, found = 0;
33+
34+ if (strchr(name, '/')) {
35+ found = canexec(AT_FDCWD, name);
36+ if (found)
37+ puts(name);
38+ return found;
39+ }
40+
41+ ptr = p = enstrdup(3, path);
42+ len = strlen(p);
43+ for (i = 0; i < len + 1; i++) {
44+ if (ptr[i] != ':' && ptr[i] != '\0')
45+ continue;
46+ ptr[i] = '\0';
47+ if ((dirfd = open(p, O_RDONLY)) >= 0) {
48+ if (canexec(dirfd, name)) {
49+ found = 1;
50+ fputs(p, stdout);
51+ if (i && ptr[i - 1] != '/')
52+ fputc('/', stdout);
53+ puts(name);
54+ }
55+ close(dirfd);
56+ if (!aflag && found)
57+ break;
58+ }
59+ p = ptr + i + 1;
60+ }
61+ free(ptr);
62+
63+ return found;
64+}
65+
66+static void
67+usage(void)
68+{
69+ eprintf("usage: %s [-a] name ...\n", argv0);
70+}
71+
72+int
73+main(int argc, char *argv[])
74+{
75+ char *path;
76+ int found = 0, foundall = 1;
77+
78+ ARGBEGIN {
79+ case 'a':
80+ aflag = 1;
81+ break;
82+ default:
83+ usage();
84+ } ARGEND
85+
86+ if (!argc)
87+ usage();
88+
89+ if (!(path = getenv("PATH")))
90+ enprintf(3, "$PATH is not set\n");
91+
92+ for (; *argv; argc--, argv++) {
93+ if (which(path, *argv)) {
94+ found = 1;
95+ } else {
96+ weprintf("%s: not an external command\n", *argv);
97+ foundall = 0;
98+ }
99+ }
100+
101+ return found ? foundall ? 0 : 1 : 2;
102+}
+37,
-0
1@@ -0,0 +1,37 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <unistd.h>
6+#include <pwd.h>
7+
8+#include "util.h"
9+
10+static void
11+usage(void)
12+{
13+ eprintf("usage: %s\n", argv0);
14+}
15+
16+int
17+main(int argc, char *argv[])
18+{
19+ uid_t uid;
20+ struct passwd *pw;
21+
22+ argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
23+
24+ if (argc)
25+ usage();
26+
27+ uid = geteuid();
28+ errno = 0;
29+ if (!(pw = getpwuid(uid))) {
30+ if (errno)
31+ eprintf("getpwuid %d:", uid);
32+ else
33+ eprintf("getpwuid %d: no such user\n", uid);
34+ }
35+ puts(pw->pw_name);
36+
37+ return fshut(stdout, "<stdout>");
38+}
+194,
-0
1@@ -0,0 +1,194 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <grp.h>
4+#include <pwd.h>
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <unistd.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <dirent.h>
11+#include <sys/stat.h>
12+#include <sys/wait.h>
13+
14+#include "util.h"
15+
16+static int Dflag = 0;
17+static gid_t group;
18+static uid_t owner;
19+static mode_t mode = 0755;
20+
21+static void
22+make_dir(char *dir, int was_missing)
23+{
24+ if (!mkdir(dir, was_missing ? 0755 : mode)) {
25+ if (!was_missing && (lchown(dir, owner, group) < 0))
26+ eprintf("lchmod %s:", dir);
27+ } else if (errno != EEXIST) {
28+ eprintf("mkdir %s:", dir);
29+ }
30+}
31+
32+static void
33+make_dirs(char *dir, int was_missing)
34+{
35+ char *p;
36+ for (p = strchr(dir + (dir[0] == '/'), '/'); p; p = strchr(p + 1, '/')) {
37+ *p = '\0';
38+ make_dir(dir, was_missing);
39+ *p = '/';
40+ }
41+ make_dir(dir, was_missing);
42+}
43+
44+static int
45+install(const char *s1, const char *s2, int depth)
46+{
47+ int f1, f2;
48+
49+ if ((f1 = open(s1, O_RDONLY)) < 0)
50+ eprintf("open %s:", s1);
51+ if ((f2 = creat(s2, 0600)) < 0) {
52+ if (unlink(s2) < 0 && errno != ENOENT)
53+ eprintf("unlink %s:", s2);
54+ if ((f2 = creat(s2, 0600)) < 0)
55+ eprintf("creat %s:", s2);
56+ }
57+ if (concat(f1, s1, f2, s2) < 0)
58+ goto fail;
59+ if (fchmod(f2, mode) < 0) {
60+ weprintf("fchmod %s:", s2);
61+ goto fail;
62+ }
63+ if (fchown(f2, owner, group) < 0) {
64+ weprintf("fchown %s:", s2);
65+ goto fail;
66+ }
67+
68+ close(f1);
69+ close(f2);
70+
71+ return 0;
72+
73+fail:
74+ unlink(s2);
75+ exit(1);
76+}
77+
78+static void
79+usage(void)
80+{
81+ eprintf("usage: %s [-g group] [-o owner] [-m mode] (-d dir ... | [-D] (-t dest source ... | source ... dest))\n", argv0);
82+}
83+
84+int
85+main(int argc, char *argv[])
86+{
87+ int dflag = 0;
88+ char *gflag = 0;
89+ char *oflag = 0;
90+ char *mflag = 0;
91+ char *tflag = 0;
92+ struct group *gr;
93+ struct passwd *pw;
94+ struct stat st;
95+ char *p;
96+
97+ ARGBEGIN {
98+ case 'c':
99+ /* no-op for compatibility */
100+ break;
101+ case 'd':
102+ dflag = 1;
103+ break;
104+ case 'D':
105+ Dflag = 1;
106+ break;
107+ case 's':
108+ /* no-op for compatibility */
109+ break;
110+ case 'g':
111+ gflag = EARGF(usage());
112+ break;
113+ case 'o':
114+ oflag = EARGF(usage());
115+ break;
116+ case 'm':
117+ mflag = EARGF(usage());
118+ break;
119+ case 't':
120+ tflag = EARGF(usage());
121+ break;
122+ default:
123+ usage();
124+ } ARGEND
125+
126+ if (argc < 1 + (!tflag & !dflag) || dflag & (Dflag | !!tflag))
127+ usage();
128+
129+ if (gflag) {
130+ errno = 0;
131+ gr = getgrnam(gflag);
132+ if (gr) {
133+ group = gr->gr_gid;
134+ } else {
135+ if (errno)
136+ eprintf("getgrnam %s:", gflag);
137+ group = estrtonum(gflag, 0, UINT_MAX);
138+ }
139+ } else {
140+ group = getgid();
141+ }
142+
143+ if (oflag) {
144+ errno = 0;
145+ pw = getpwnam(oflag);
146+ if (pw) {
147+ owner = pw->pw_uid;
148+ } else {
149+ if (errno)
150+ eprintf("getpwnam %s:", oflag);
151+ owner = estrtonum(oflag, 0, UINT_MAX);
152+ }
153+ } else {
154+ owner = getuid();
155+ }
156+
157+ if (mflag)
158+ mode = parsemode(mflag, mode, 0);
159+
160+ if (dflag) {
161+ for (; *argv; argc--, argv++)
162+ make_dirs(*argv, 0);
163+ return 0;
164+ }
165+
166+ if (tflag) {
167+ argv = memmove(argv - 1, argv, argc * sizeof(*argv));
168+ argv[argc++] = tflag;
169+ }
170+ if (tflag || argc > 2) {
171+ if (stat(argv[argc - 1], &st) < 0) {
172+ if ((errno == ENOENT) && Dflag) {
173+ make_dirs(argv[argc - 1], 1);
174+ } else {
175+ eprintf("stat %s:", argv[argc - 1]);
176+ }
177+ } else if (!S_ISDIR(st.st_mode)) {
178+ eprintf("%s: not a directory\n", argv[argc - 1]);
179+ }
180+ }
181+ if (stat(argv[argc - 1], &st) < 0) {
182+ if (errno != ENOENT)
183+ eprintf("stat %s:", argv[argc - 1]);
184+ if (tflag || Dflag || argc > 2) {
185+ if ((p = strrchr(argv[argc - 1], '/')) != NULL) {
186+ *p = '\0';
187+ make_dirs(argv[argc - 1], 1);
188+ *p = '/';
189+ }
190+ }
191+ }
192+ enmasse(argc, argv, install);
193+
194+ return 0;
195+}
+25,
-0
1@@ -0,0 +1,25 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+
5+#include "util.h"
6+
7+static void
8+usage(void)
9+{
10+ eprintf("usage: %s [string]\n", argv0);
11+}
12+
13+int
14+main(int argc, char *argv[])
15+{
16+ const char *s;
17+
18+ ARGBEGIN {
19+ default:
20+ usage();
21+ } ARGEND
22+
23+ s = argc ? argv[0] : "y";
24+ for (;;)
25+ puts(s);
26+}
+72,
-0
1@@ -0,0 +1,72 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+#include <sys/types.h>
5+#ifndef makedev
6+#include <sys/sysmacros.h>
7+#endif
8+
9+#include <fcntl.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+
15+#include "util.h"
16+
17+static void
18+usage(void)
19+{
20+ eprintf("usage: %s [-m mode] name b|c|u major minor\n"
21+ " %s [-m mode] name p\n",
22+ argv0, argv0);
23+}
24+
25+int
26+main(int argc, char *argv[])
27+{
28+ mode_t mode = 0666;
29+ dev_t dev;
30+
31+ ARGBEGIN {
32+ case 'm':
33+ mode = parsemode(EARGF(usage()), mode, umask(0));
34+ break;
35+ default:
36+ usage();
37+ } ARGEND;
38+
39+ if (argc < 2)
40+ usage();
41+
42+ if (strlen(argv[1]) != 1)
43+ goto invalid;
44+ switch (argv[1][0]) {
45+ case 'b':
46+ mode |= S_IFBLK;
47+ break;
48+ case 'u':
49+ case 'c':
50+ mode |= S_IFCHR;
51+ break;
52+ case 'p':
53+ mode |= S_IFIFO;
54+ break;
55+ default:
56+ invalid:
57+ eprintf("invalid type '%s'\n", argv[1]);
58+ }
59+
60+ if (S_ISFIFO(mode)) {
61+ if (argc != 2)
62+ usage();
63+ dev = 0;
64+ } else {
65+ if (argc != 4)
66+ usage();
67+ dev = makedev(estrtonum(argv[2], 0, LLONG_MAX), estrtonum(argv[3], 0, LLONG_MAX));
68+ }
69+
70+ if (mknod(argv[0], mode, dev) == -1)
71+ eprintf("mknod %s:", argv[0]);
72+ return 0;
73+}
+288,
-0
1@@ -0,0 +1,288 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/ioctl.h>
4+#include <sys/stat.h>
5+#include <sys/types.h>
6+#include <sys/syscall.h>
7+
8+#include <errno.h>
9+#include <fcntl.h>
10+#include <limits.h>
11+#include <pwd.h>
12+#include <shadow.h>
13+#include <stdint.h>
14+#include <stdio.h>
15+#include <stdlib.h>
16+#include <string.h>
17+#include <unistd.h>
18+
19+#include "config.h"
20+#include "passwd.h"
21+#include "text.h"
22+#include "util.h"
23+
24+static FILE *
25+spw_get_file(const char *user)
26+{
27+ FILE *fp = NULL;
28+ char file[PATH_MAX];
29+ int r;
30+
31+ r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user);
32+ if (r < 0 || (size_t)r >= sizeof(file))
33+ eprintf("snprintf:");
34+ fp = fopen(file, "r+");
35+ if (!fp)
36+ fp = fopen("/etc/shadow", "r+");
37+ return fp;
38+}
39+
40+static int
41+spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash)
42+{
43+ struct spwd *spwent;
44+ int r = -1, w = 0;
45+ FILE *tfp = NULL;
46+
47+ /* write to temporary file. */
48+ tfp = tmpfile();
49+ if (!tfp) {
50+ weprintf("tmpfile:");
51+ goto cleanup;
52+ }
53+ while ((spwent = fgetspent(fp))) {
54+ /* update entry on name match */
55+ if (strcmp(spwent->sp_namp, spw->sp_namp) == 0) {
56+ spwent->sp_pwdp = pwhash;
57+ w++;
58+ }
59+ errno = 0;
60+ if (putspent(spwent, tfp) == -1) {
61+ weprintf("putspent:");
62+ goto cleanup;
63+ }
64+ }
65+ if (!w) {
66+ weprintf("shadow: no matching entry to write to\n");
67+ goto cleanup;
68+ }
69+ fflush(tfp);
70+
71+ if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
72+ weprintf("fseek:");
73+ goto cleanup;
74+ }
75+
76+ /* write temporary file to (tcb) shadow file */
77+ fconcat(tfp, "tmpfile", fp, "shadow");
78+ ftruncate(fileno(fp), ftell(tfp));
79+
80+ r = 0; /* success */
81+cleanup:
82+ if (tfp)
83+ fclose(tfp);
84+ return r;
85+}
86+
87+static int
88+pw_write_file(FILE *fp, const struct passwd *pw, char *pwhash) {
89+ struct passwd *pwent;
90+ int r = -1, w = 0;
91+ FILE *tfp = NULL;
92+
93+ /* write to temporary file. */
94+ tfp = tmpfile();
95+ if (!tfp) {
96+ weprintf("tmpfile:");
97+ goto cleanup;
98+ }
99+ while ((pwent = fgetpwent(fp))) {
100+ /* update entry on name match */
101+ if (strcmp(pwent->pw_name, pw->pw_name) == 0) {
102+ pwent->pw_passwd = pwhash;
103+ w++;
104+ }
105+ errno = 0;
106+ if (putpwent(pwent, tfp) == -1) {
107+ weprintf("putpwent:");
108+ goto cleanup;
109+ }
110+ }
111+ if (!w) {
112+ weprintf("passwd: no matching entry to write to\n");
113+ goto cleanup;
114+ }
115+ fflush(tfp);
116+
117+ if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
118+ weprintf("fseek:");
119+ goto cleanup;
120+ }
121+
122+ /* write to passwd file. */
123+ fconcat(tfp, "tmpfile", fp, "passwd");
124+ ftruncate(fileno(fp), ftell(tfp));
125+
126+ r = 0; /* success */
127+cleanup:
128+ if (tfp)
129+ fclose(tfp);
130+ return r;
131+}
132+
133+/* generates a random base64-encoded salt string of length 16 */
134+static void
135+gensalt(char *s)
136+{
137+ static const char b64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
138+ uint8_t buf[12];
139+ uint32_t n;
140+ int i;
141+
142+ if (syscall(SYS_getrandom, buf, sizeof(buf), 0) < 0)
143+ eprintf("getrandom:");
144+ for (i = 0; i < 12; i += 3) {
145+ n = buf[i] << 16 | buf[i+1] << 8 | buf[i+2];
146+ *s++ = b64[n%64]; n /= 64;
147+ *s++ = b64[n%64]; n /= 64;
148+ *s++ = b64[n%64]; n /= 64;
149+ *s++ = b64[n];
150+ }
151+ *s++ = '\0';
152+}
153+
154+static void
155+usage(void)
156+{
157+ eprintf("usage: %s [username]\n", argv0);
158+}
159+
160+int
161+main(int argc, char *argv[])
162+{
163+ char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
164+ char *inpass, *p, *prevhash = NULL, salt[sizeof(PW_CIPHER) + 16] = PW_CIPHER;
165+ struct passwd *pw;
166+ struct spwd *spw = NULL;
167+ FILE *fp = NULL;
168+ int r = -1, status = 1;
169+
170+ ARGBEGIN {
171+ default:
172+ usage();
173+ } ARGEND;
174+
175+ pw_init();
176+ umask(077);
177+
178+ errno = 0;
179+ if (argc == 0)
180+ pw = getpwuid(getuid());
181+ else
182+ pw = getpwnam(argv[0]);
183+ if (!pw) {
184+ if (errno)
185+ eprintf("getpwnam: %s:", argv[0]);
186+ else
187+ eprintf("who are you?\n");
188+ }
189+
190+ /* is using shadow entry ? */
191+ if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
192+ errno = 0;
193+ spw = getspnam(pw->pw_name);
194+ if (!spw) {
195+ if (errno)
196+ eprintf("getspnam: %s:", pw->pw_name);
197+ else
198+ eprintf("who are you?\n");
199+ }
200+ }
201+
202+ /* Flush pending input */
203+ ioctl(0, TCFLSH, (void *)0);
204+
205+ if (getuid() == 0) {
206+ goto newpass;
207+ } else {
208+ if (pw->pw_passwd[0] == '!' ||
209+ pw->pw_passwd[0] == '*')
210+ eprintf("denied\n");
211+ if (pw->pw_passwd[0] == '\0') {
212+ goto newpass;
213+ }
214+ if (pw->pw_passwd[0] == 'x' &&
215+ pw->pw_passwd[1] == '\0')
216+ prevhash = spw->sp_pwdp;
217+ else
218+ prevhash = pw->pw_passwd;
219+ }
220+
221+ printf("Changing password for %s\n", pw->pw_name);
222+ inpass = getpass("Old password: ");
223+ if (!inpass)
224+ eprintf("getpass:");
225+ if (inpass[0] == '\0')
226+ eprintf("no password supplied\n");
227+ p = crypt(inpass, prevhash);
228+ if (!p)
229+ eprintf("crypt:");
230+ cryptpass1 = estrdup(p);
231+ if (strcmp(cryptpass1, prevhash) != 0)
232+ eprintf("incorrect password\n");
233+
234+newpass:
235+ inpass = getpass("Enter new password: ");
236+ if (!inpass)
237+ eprintf("getpass:");
238+ if (inpass[0] == '\0')
239+ eprintf("no password supplied\n");
240+
241+ if(prevhash) {
242+ p = crypt(inpass, prevhash);
243+ if (!p)
244+ eprintf("crypt:");
245+ if (cryptpass1 && strcmp(cryptpass1, p) == 0)
246+ eprintf("password left unchanged\n");
247+ }
248+ gensalt(salt + strlen(salt));
249+ p = crypt(inpass, salt);
250+ if (!p)
251+ eprintf("crypt:");
252+ cryptpass2 = estrdup(p);
253+
254+ /* Flush pending input */
255+ ioctl(0, TCFLSH, (void *)0);
256+
257+ inpass = getpass("Retype new password: ");
258+ if (!inpass)
259+ eprintf("getpass:");
260+ if (inpass[0] == '\0')
261+ eprintf("no password supplied\n");
262+ p = crypt(inpass, salt);
263+ if (!p)
264+ eprintf("crypt:");
265+ cryptpass3 = estrdup(p);
266+ if (strcmp(cryptpass2, cryptpass3) != 0)
267+ eprintf("passwords don't match\n");
268+
269+ fp = spw_get_file(pw->pw_name);
270+ if (fp) {
271+ r = spw_write_file(fp, spw, cryptpass3);
272+ } else {
273+ fp = fopen("/etc/passwd", "r+");
274+ if (fp)
275+ r = pw_write_file(fp, pw, cryptpass3);
276+ else
277+ weprintf("fopen:");
278+ }
279+ if (!r)
280+ status = 0;
281+
282+ if (fp)
283+ fclose(fp);
284+ free(cryptpass3);
285+ free(cryptpass2);
286+ free(cryptpass1);
287+
288+ return status;
289+}
+108,
-0
1@@ -0,0 +1,108 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+
5+#include <errno.h>
6+#include <grp.h>
7+#include <pwd.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "passwd.h"
14+#include "util.h"
15+
16+extern char **environ;
17+
18+static int lflag = 0;
19+static int pflag = 0;
20+
21+static void
22+usage(void)
23+{
24+ eprintf("usage: %s [-lp] [username]\n", argv0);
25+}
26+
27+int
28+main(int argc, char *argv[])
29+{
30+ char *usr, *pass;
31+ char *shell, *envshell, *term;
32+ struct passwd *pw;
33+ char *newargv[3];
34+ uid_t uid;
35+
36+ ARGBEGIN {
37+ case 'l':
38+ lflag = 1;
39+ break;
40+ case 'p':
41+ pflag = 1;
42+ break;
43+ default:
44+ usage();
45+ } ARGEND;
46+
47+ if (argc > 1)
48+ usage();
49+ usr = argc > 0 ? argv[0] : "root";
50+
51+ errno = 0;
52+ pw = getpwnam(usr);
53+ if (!pw) {
54+ if (errno)
55+ eprintf("getpwnam: %s:", usr);
56+ else
57+ eprintf("who are you?\n");
58+ }
59+
60+ uid = getuid();
61+ if (uid) {
62+ pass = getpass("Password: ");
63+ if (!pass)
64+ eprintf("getpass:");
65+ if (pw_check(pw, pass) <= 0)
66+ exit(1);
67+ }
68+
69+ if (initgroups(usr, pw->pw_gid) < 0)
70+ eprintf("initgroups:");
71+ if (setgid(pw->pw_gid) < 0)
72+ eprintf("setgid:");
73+ if (setuid(pw->pw_uid) < 0)
74+ eprintf("setuid:");
75+
76+ shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell;
77+ if (lflag) {
78+ term = getenv("TERM");
79+ clearenv();
80+ setenv("HOME", pw->pw_dir, 1);
81+ setenv("SHELL", shell, 1);
82+ setenv("USER", pw->pw_name, 1);
83+ setenv("LOGNAME", pw->pw_name, 1);
84+ setenv("TERM", term ? term : "linux", 1);
85+ if (chdir(pw->pw_dir) < 0)
86+ eprintf("chdir %s:", pw->pw_dir);
87+ newargv[0] = shell;
88+ newargv[1] = "-l";
89+ newargv[2] = NULL;
90+ } else {
91+ if (pflag) {
92+ envshell = getenv("SHELL");
93+ if (envshell && envshell[0] != '\0')
94+ shell = envshell;
95+ } else {
96+ setenv("HOME", pw->pw_dir, 1);
97+ setenv("SHELL", shell, 1);
98+ if (strcmp(pw->pw_name, "root") != 0) {
99+ setenv("USER", pw->pw_name, 1);
100+ setenv("LOGNAME", pw->pw_name, 1);
101+ }
102+ }
103+ newargv[0] = shell;
104+ newargv[1] = NULL;
105+ }
106+ execve(shell, newargv, environ);
107+ weprintf("execve %s:", shell);
108+ return (errno == ENOENT) ? 127 : 126;
109+}
+23,
-0
1@@ -0,0 +1,23 @@
2+VERSION = 2026-06-08T05-53-UTC-03
3+
4+PREFIX = /usr/local
5+MANPREFIX = $(PREFIX)/share/man
6+
7+RANLIB = ranlib
8+AR = ar
9+ARFLAGS = rc
10+
11+CPPFLAGS =\
12+ -Ishared\
13+ -DPREFIX=\"$(PREFIX)\"\
14+ -D_DEFAULT_SOURCE\
15+ -D_GNU_SOURCE\
16+ -D_NETBSD_SOURCE\
17+ -D_BSD_SOURCE\
18+ -D_XOPEN_SOURCE=700\
19+ -D_FILE_OFFSET_BITS=64\
20+ -DSTD_NON_POSIX
21+
22+CFLAGS = -std=c99 -Wall -Wextra -pedantic
23+LDFLAGS =
24+LDLIBS = -lcrypt -lresolv
+218,
-0
1@@ -0,0 +1,218 @@
2+#!/bin/sh
3+
4+ifdef() {
5+ printf 'static const struct var %s[] = {\n' "$1"
6+ awk '{printf("#ifdef %s\n\t{\"%s\",\t%s},\n#endif\n", $2, $1, $2)}'
7+ echo '};'
8+}
9+
10+ifdef confstr_l << EOF
11+PATH _CS_PATH
12+POSIX_V7_ILP32_OFF32_CFLAGS _CS_POSIX_V7_ILP32_OFF32_CFLAGS
13+POSIX_V7_ILP32_OFF32_LDFLAGS _CS_POSIX_V7_ILP32_OFF32_LDFLAGS
14+POSIX_V7_ILP32_OFF32_LIBS _CS_POSIX_V7_ILP32_OFF32_LIBS
15+POSIX_V7_ILP32_OFFBIG_CFLAGS _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS
16+POSIX_V7_ILP32_OFFBIG_LDFLAGS _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS
17+POSIX_V7_ILP32_OFFBIG_LIBS _CS_POSIX_V7_ILP32_OFFBIG_LIBS
18+POSIX_V7_LP64_OFF64_CFLAGS _CS_POSIX_V7_LP64_OFF64_CFLAGS
19+POSIX_V7_LP64_OFF64_LDFLAGS _CS_POSIX_V7_LP64_OFF64_LDFLAGS
20+POSIX_V7_LP64_OFF64_LIBS _CS_POSIX_V7_LP64_OFF64_LIBS
21+POSIX_V7_LPBIG_OFFBIG_CFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS
22+POSIX_V7_LPBIG_OFFBIG_LDFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS
23+POSIX_V7_LPBIG_OFFBIG_LIBS _CS_POSIX_V7_LPBIG_OFFBIG_LIBS
24+POSIX_V7_THREADS_CFLAGS _CS_POSIX_V7_THREADS_CFLAGS
25+POSIX_V7_THREADS_LDFLAGS _CS_POSIX_V7_THREADS_LDFLAGS
26+POSIX_V7_WIDTH_RESTRICTED_ENVS _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
27+V7_ENV _CS_V7_ENV
28+EOF
29+
30+ifdef limits_l << EOF
31+_POSIX_CLOCKRES_MIN _POSIX_CLOCKRES_MIN
32+_POSIX_AIO_LISTIO_MAX _POSIX_AIO_LISTIO_MAX
33+_POSIX_AIO_MAX _POSIX_AIO_MAX
34+_POSIX_ARG_MAX _POSIX_ARG_MAX
35+_POSIX_CHILD_MAX _POSIX_CHILD_MAX
36+_POSIX_DELAYTIMER_MAX _POSIX_DELAYTIMER_MAX
37+_POSIX_HOST_NAME_MAX _POSIX_HOST_NAME_MAX
38+_POSIX_LINK_MAX _POSIX_LINK_MAX
39+_POSIX_LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
40+_POSIX_MAX_CANON _POSIX_MAX_CANON
41+_POSIX_MAX_INPUT _POSIX_MAX_INPUT
42+_POSIX_MQ_OPEN_MAX _POSIX_MQ_OPEN_MAX
43+_POSIX_MQ_PRIO_MAX _POSIX_MQ_PRIO_MAX
44+_POSIX_NAME_MAX _POSIX_NAME_MAX
45+_POSIX_NGROUPS_MAX _POSIX_NGROUPS_MAX
46+_POSIX_OPEN_MAX _POSIX_OPEN_MAX
47+_POSIX_PATH_MAX _POSIX_PATH_MAX
48+_POSIX_PIPE_BUF _POSIX_PIPE_BUF
49+_POSIX_RE_DUP_MAX _POSIX_RE_DUP_MAX
50+_POSIX_RTSIG_MAX _POSIX_RTSIG_MAX
51+_POSIX_SEM_NSEMS_MAX _POSIX_SEM_NSEMS_MAX
52+_POSIX_SEM_VALUE_MAX _POSIX_SEM_VALUE_MAX
53+_POSIX_SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX
54+_POSIX_SSIZE_MAX _POSIX_SSIZE_MAX
55+_POSIX_SS_REPL_MAX _POSIX_SS_REPL_MAX
56+_POSIX_STREAM_MAX _POSIX_STREAM_MAX
57+_POSIX_SYMLINK_MAX _POSIX_SYMLINK_MAX
58+_POSIX_SYMLOOP_MAX _POSIX_SYMLOOP_MAX
59+_POSIX_THREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
60+_POSIX_THREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
61+_POSIX_THREAD_THREADS_MAX _POSIX_THREAD_THREADS_MAX
62+_POSIX_TIMER_MAX _POSIX_TIMER_MAX
63+_POSIX_TTY_NAME_MAX _POSIX_TTY_NAME_MAX
64+_POSIX_TZNAME_MAX _POSIX_TZNAME_MAX
65+_POSIX2_BC_BASE_MAX _POSIX2_BC_BASE_MAX
66+_POSIX2_BC_DIM_MAX _POSIX2_BC_DIM_MAX
67+_POSIX2_BC_SCALE_MAX _POSIX2_BC_SCALE_MAX
68+_POSIX2_BC_STRING_MAX _POSIX2_BC_STRING_MAX
69+_POSIX2_CHARCLASS_NAME_MAX _POSIX2_CHARCLASS_NAME_MAX
70+_POSIX2_COLL_WEIGHTS_MAX _POSIX2_COLL_WEIGHTS_MAX
71+_POSIX2_EXPR_NEST_MAX _POSIX2_EXPR_NEST_MAX
72+_POSIX2_LINE_MAX _POSIX2_LINE_MAX
73+_POSIX2_RE_DUP_MAX _POSIX2_RE_DUP_MAX
74+EOF
75+
76+ifdef sysconf_l << EOF
77+AIO_LISTIO_MAX _SC_AIO_LISTIO_MAX
78+AIO_MAX _SC_AIO_MAX
79+AIO_PRIO_DELTA_MAX _SC_AIO_PRIO_DELTA_MAX
80+ARG_MAX _SC_ARG_MAX
81+ATEXIT_MAX _SC_ATEXIT_MAX
82+BC_BASE_MAX _SC_BC_BASE_MAX
83+BC_DIM_MAX _SC_BC_DIM_MAX
84+BC_SCALE_MAX _SC_BC_SCALE_MAX
85+BC_STRING_MAX _SC_BC_STRING_MAX
86+CHILD_MAX _SC_CHILD_MAX
87+COLL_WEIGHTS_MAX _SC_COLL_WEIGHTS_MAX
88+DELAYTIMER_MAX _SC_DELAYTIMER_MAX
89+EXPR_NEST_MAX _SC_EXPR_NEST_MAX
90+HOST_NAME_MAX _SC_HOST_NAME_MAX
91+IOV_MAX _SC_IOV_MAX
92+LINE_MAX _SC_LINE_MAX
93+LOGIN_NAME_MAX _SC_LOGIN_NAME_MAX
94+NGROUPS_MAX _SC_NGROUPS_MAX
95+MQ_OPEN_MAX _SC_MQ_OPEN_MAX
96+MQ_PRIO_MAX _SC_MQ_PRIO_MAX
97+OPEN_MAX _SC_OPEN_MAX
98+_POSIX_ADVISORY_INFO _SC_ADVISORY_INFO
99+_POSIX_BARRIERS _SC_BARRIERS
100+_POSIX_ASYNCHRONOUS_IO _SC_ASYNCHRONOUS_IO
101+_POSIX_CLOCK_SELECTION _SC_CLOCK_SELECTION
102+_POSIX_CPUTIME _SC_CPUTIME
103+_POSIX_FSYNC _SC_FSYNC
104+_POSIX_IPV6 _SC_IPV6
105+_POSIX_JOB_CONTROL _SC_JOB_CONTROL
106+_POSIX_MAPPED_FILES _SC_MAPPED_FILES
107+_POSIX_MEMLOCK _SC_MEMLOCK
108+_POSIX_MEMLOCK_RANGE _SC_MEMLOCK_RANGE
109+_POSIX_MEMORY_PROTECTION _SC_MEMORY_PROTECTION
110+_POSIX_MESSAGE_PASSING _SC_MESSAGE_PASSING
111+_POSIX_MONOTONIC_CLOCK _SC_MONOTONIC_CLOCK
112+_POSIX_PRIORITIZED_IO _SC_PRIORITIZED_IO
113+_POSIX_PRIORITY_SCHEDULING _SC_PRIORITY_SCHEDULING
114+_POSIX_RAW_SOCKETS _SC_RAW_SOCKETS
115+_POSIX_READER_WRITER_LOCKS _SC_READER_WRITER_LOCKS
116+_POSIX_REALTIME_SIGNALS _SC_REALTIME_SIGNALS
117+_POSIX_REGEXP _SC_REGEXP
118+_POSIX_SAVED_IDS _SC_SAVED_IDS
119+_POSIX_SEMAPHORES _SC_SEMAPHORES
120+_POSIX_SHARED_MEMORY_OBJECTS _SC_SHARED_MEMORY_OBJECTS
121+_POSIX_SHELL _SC_SHELL
122+_POSIX_SPAWN _SC_SPAWN
123+_POSIX_SPIN_LOCKS _SC_SPIN_LOCKS
124+_POSIX_SPORADIC_SERVER _SC_SPORADIC_SERVER
125+_POSIX_SS_REPL_MAX _SC_SS_REPL_MAX
126+_POSIX_SYNCHRONIZED_IO _SC_SYNCHRONIZED_IO
127+_POSIX_THREAD_ATTR_STACKADDR _SC_THREAD_ATTR_STACKADDR
128+_POSIX_THREAD_ATTR_STACKSIZE _SC_THREAD_ATTR_STACKSIZE
129+_POSIX_THREAD_CPUTIME _SC_THREAD_CPUTIME
130+_POSIX_THREAD_PRIO_INHERIT _SC_THREAD_PRIO_INHERIT
131+_POSIX_THREAD_PRIO_PROTECT _SC_THREAD_PRIO_PROTECT
132+_POSIX_THREAD_PRIORITY_SCHEDULING _SC_THREAD_PRIORITY_SCHEDULING
133+_POSIX_THREAD_PROCESS_SHARED _SC_THREAD_PROCESS_SHARED
134+_POSIX_THREAD_ROBUST_PRIO_INHERIT _SC_THREAD_ROBUST_PRIO_INHERIT
135+_POSIX_THREAD_ROBUST_PRIO_PROTECT _SC_THREAD_ROBUST_PRIO_PROTECT
136+_POSIX_THREAD_SAFE_FUNCTIONS _SC_THREAD_SAFE_FUNCTIONS
137+_POSIX_THREAD_SPORADIC_SERVER _SC_THREAD_SPORADIC_SERVER
138+_POSIX_THREADS _SC_THREADS
139+_POSIX_TIMEOUTS _SC_TIMEOUTS
140+_POSIX_TIMERS _SC_TIMERS
141+_POSIX_TRACE _SC_TRACE
142+_POSIX_TRACE_EVENT_FILTER _SC_TRACE_EVENT_FILTER
143+_POSIX_TRACE_EVENT_NAME_MAX _SC_TRACE_EVENT_NAME_MAX
144+_POSIX_TRACE_INHERIT _SC_TRACE_INHERIT
145+_POSIX_TRACE_LOG _SC_TRACE_LOG
146+_POSIX_TRACE_NAME_MAX _SC_TRACE_NAME_MAX
147+_POSIX_TRACE_SYS_MAX _SC_TRACE_SYS_MAX
148+_POSIX_TRACE_USER_EVENT_MAX _SC_TRACE_USER_EVENT_MAX
149+_POSIX_TYPED_MEMORY_OBJECTS _SC_TYPED_MEMORY_OBJECTS
150+_POSIX_VERSION _SC_VERSION
151+_POSIX_V7_ILP32_OFF32 _SC_V7_ILP32_OFF32
152+_POSIX_V7_ILP32_OFFBIG _SC_V7_ILP32_OFFBIG
153+_POSIX_V7_LP64_OFF64 _SC_V7_LP64_OFF64
154+_POSIX_V7_LPBIG_OFFBIG _SC_V7_LPBIG_OFFBIG
155+_POSIX2_C_BIND _SC_2_C_BIND
156+_POSIX2_C_DEV _SC_2_C_DEV
157+_POSIX2_CHAR_TERM _SC_2_CHAR_TERM
158+_POSIX2_FORT_DEV _SC_2_FORT_DEV
159+_POSIX2_FORT_RUN _SC_2_FORT_RUN
160+_POSIX2_LOCALEDEF _SC_2_LOCALEDEF
161+_POSIX2_PBS _SC_2_PBS
162+_POSIX2_PBS_ACCOUNTING _SC_2_PBS_ACCOUNTING
163+_POSIX2_PBS_CHECKPOINT _SC_2_PBS_CHECKPOINT
164+_POSIX2_PBS_LOCATE _SC_2_PBS_LOCATE
165+_POSIX2_PBS_MESSAGE _SC_2_PBS_MESSAGE
166+_POSIX2_PBS_TRACK _SC_2_PBS_TRACK
167+_POSIX2_SW_DEV _SC_2_SW_DEV
168+_POSIX2_UPE _SC_2_UPE
169+_POSIX2_VERSION _SC_2_VERSION
170+PAGE_SIZE _SC_PAGE_SIZE
171+PAGESIZE _SC_PAGESIZE
172+PTHREAD_DESTRUCTOR_ITERATIONS _SC_THREAD_DESTRUCTOR_ITERATIONS
173+PTHREAD_KEYS_MAX _SC_THREAD_KEYS_MAX
174+PTHREAD_STACK_MIN _SC_THREAD_STACK_MIN
175+PTHREAD_THREADS_MAX _SC_THREAD_THREADS_MAX
176+RE_DUP_MAX _SC_RE_DUP_MAX
177+RTSIG_MAX _SC_RTSIG_MAX
178+SEM_NSEMS_MAX _SC_SEM_NSEMS_MAX
179+SEM_VALUE_MAX _SC_SEM_VALUE_MAX
180+SIGQUEUE_MAX _SC_SIGQUEUE_MAX
181+STREAM_MAX _SC_STREAM_MAX
182+SYMLOOP_MAX _SC_SYMLOOP_MAX
183+TIMER_MAX _SC_TIMER_MAX
184+TTY_NAME_MAX _SC_TTY_NAME_MAX
185+TZNAME_MAX _SC_TZNAME_MAX
186+_XOPEN_CRYPT _SC_XOPEN_CRYPT
187+_XOPEN_ENH_I18N _SC_XOPEN_ENH_I18N
188+_XOPEN_REALTIME _SC_XOPEN_REALTIME
189+_XOPEN_REALTIME_THREADS _SC_XOPEN_REALTIME_THREADS
190+_XOPEN_SHM _SC_XOPEN_SHM
191+_XOPEN_STREAMS _SC_XOPEN_STREAMS
192+_XOPEN_UNIX _SC_XOPEN_UNIX
193+_XOPEN_UUCP _SC_XOPEN_UUCP
194+_XOPEN_VERSION _SC_XOPEN_VERSION
195+EOF
196+
197+ifdef pathconf_l << EOF
198+FILESIZEBITS _PC_FILESIZEBITS
199+LINK_MAX _PC_LINK_MAX
200+MAX_CANON _PC_MAX_CANON
201+MAX_INPUT _PC_MAX_INPUT
202+NAME_MAX _PC_NAME_MAX
203+PATH_MAX _PC_PATH_MAX
204+PIPE_BUF _PC_PIPE_BUF
205+POSIX2_SYMLINKS _PC_2_SYMLINKS
206+POSIX_ALLOC_SIZE_MIN _PC_ALLOC_SIZE_MIN
207+POSIX_REC_INCR_XFER_SIZE _PC_REC_INCR_XFER_SIZE
208+POSIX_REC_MAX_XFER_SIZE _PC_REC_MAX_XFER_SIZE
209+POSIX_REC_MIN_XFER_SIZE _PC_REC_MIN_XFER_SIZE
210+POSIX_REC_XFER_ALIGN _PC_REC_XFER_ALIGN
211+SYMLINK_MAX _PC_SYMLINK_MAX
212+_POSIX_CHOWN_RESTRICTED _PC_CHOWN_RESTRICTED
213+_POSIX_NO_TRUNC _PC_NO_TRUNC
214+_POSIX_VDISABLE _PC_VDISABLE
215+_POSIX_ASYNC_IO _PC_ASYNC_IO
216+_POSIX_PRIO_IO _PC_PRIO_IO
217+_POSIX_SYNC_IO _PC_SYNC_IO
218+_POSIX_TIMESTAMP_RESOLUTION _PC_TIMESTAMP_RESOLUTION
219+EOF
+278,
-0
1@@ -0,0 +1,278 @@
2+#!/bin/sh
3+# mkbox - build aruu-box, the aruu multi-call binary
4+#
5+# expects CC CPPFLAGS CFLAGS LDFLAGS LDLIBS OBJCOPY from the environment;
6+# defaults match config.mk but can be overridden
7+#
8+# run from the source root (the Makefile does this automatically)
9+
10+set -e
11+
12+: "${CC:=cc}"
13+: "${CPPFLAGS:=-Ishared -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_NETBSD_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_FILE_OFFSET_BITS=64 -DSTD_NON_POSIX}"
14+: "${CFLAGS:=-std=c99 -Wall -Wextra -pedantic}"
15+: "${LDFLAGS:=}"
16+: "${LDLIBS:=-lcrypt -lresolv}"
17+: "${OBJCOPY:=objcopy}"
18+
19+ROOT=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
20+BDIR="${ROOT}/.box"
21+BOX="${ROOT}/aruu-box"
22+LIBUTIL="${ROOT}/shared/libutil/libutil.a"
23+LIBUTF="${ROOT}/shared/libutf/libutf.a"
24+
25+die() {
26+ printf 'mkbox: %s\n' "$*" >&2
27+ exit 1
28+}
29+
30+# Clean up build directory on exit or signal termination
31+trap 'rm -rf "${BDIR}"' EXIT INT QUIT TERM
32+
33+[ -f "${LIBUTIL}" ] || die "libutil.a not found; run 'make' first"
34+[ -f "${LIBUTF}" ] || die "libutf.a not found; run 'make' first"
35+
36+[ -f "${ROOT}/cmd/posix/getconf.h" ] || {
37+ printf 'mkbox: generating getconf.h\n'
38+ "${ROOT}/scripts/getconf.sh" > "${ROOT}/cmd/posix/getconf.h" ||
39+ die "scripts/getconf.sh failed"
40+}
41+
42+rm -rf "${BDIR}"
43+mkdir -p "${BDIR}"
44+
45+OBJS=""
46+DECL_F="${BDIR}/decls.inc"
47+ENT_F="${BDIR}/entries.inc"
48+: > "${DECL_F}"
49+: > "${ENT_F}"
50+
51+alias_entry() {
52+ printf '\t{ "%s", %s_main, "%s" },\n' "$1" "$2" "$3" >> "${ENT_F}"
53+}
54+
55+compile_tool() {
56+ src="$1"
57+ name="$2"
58+ fn="$3"
59+ catg="$4"
60+ extra="${5:-}"
61+ out="${BDIR}/${fn}.o"
62+ symf="${BDIR}/${fn}.syms"
63+
64+ printf 'mkbox: cc %s\n' "${name}"
65+ eval "${CC} ${CPPFLAGS} ${extra} ${CFLAGS} -c \"\$src\" -o \"\$out\"" ||
66+ die "compile failed: ${src}"
67+ printf 'main %s_main\n' "${fn}" > "${symf}"
68+ ${OBJCOPY} --redefine-syms="${symf}" "${out}" ||
69+ die "objcopy failed: ${name}"
70+ ${OBJCOPY} --keep-global-symbol="${fn}_main" "${out}" ||
71+ die "objcopy localize failed: ${name}"
72+ rm -f "${symf}"
73+ OBJS="${OBJS} ${out}"
74+ printf 'int %s_main(int, char **);\n' "${fn}" >> "${DECL_F}"
75+ printf '\t{ "%s", %s_main, "%s" },\n' "${name}" "${fn}" "${catg}" >> "${ENT_F}"
76+}
77+
78+compile_make() {
79+ mdir="${ROOT}/cmd/posix/make"
80+ symf="${BDIR}/make.syms"
81+ printf 'mkbox: cc make (multi)\n'
82+ make_objs=""
83+ for s in defaults parser posix rules; do
84+ out="${BDIR}/make_${s}.o"
85+ eval "${CC} ${CPPFLAGS} ${CFLAGS} -I\"\$mdir\" -c \"\$mdir/\$s.c\" -o \"\$out\"" ||
86+ die "compile failed: make/${s}.c"
87+ make_objs="${make_objs} ${out}"
88+ done
89+ out_main="${BDIR}/make_main.o"
90+ eval "${CC} ${CPPFLAGS} ${CFLAGS} -I\"\$mdir\" -c \"\$mdir/main.c\" -o \"\${out_main}\"" ||
91+ die "compile failed: make/main.c"
92+ make_objs="${make_objs} ${out_main}"
93+
94+ # Combined incremental link to resolve internal symbols cleanly
95+ combined="${BDIR}/make_combined.o"
96+ ${LD:-ld} -r -o "${combined}" ${make_objs} ||
97+ die "ld -r failed: make"
98+
99+ printf 'main make_main\n' > "${symf}"
100+ ${OBJCOPY} --redefine-syms="${symf}" "${combined}" ||
101+ die "objcopy failed: make"
102+ ${OBJCOPY} --keep-global-symbol=make_main "${combined}" ||
103+ die "objcopy localize failed: make"
104+ rm -f "${symf}" ${make_objs}
105+
106+ OBJS="${OBJS} ${combined}"
107+ printf 'int make_main(int, char **);\n' >> "${DECL_F}"
108+ printf '\t{ "make", make_main, "posix/make" },\n' >> "${ENT_F}"
109+}
110+
111+process_dir() {
112+ dir="$1"
113+ catg="$2"
114+ extra="${3:-}"
115+ for src in "${dir}"/*.c; do
116+ [ -f "${src}" ] || continue
117+ name=${src##*/}
118+ name=${name%.c}
119+ fn=$(printf '%s' "${name}" | tr '.-' '__')
120+ compile_tool "${src}" "${name}" "${fn}" "${catg}" "${extra}"
121+ if [ "${name}" = "test" ]; then
122+ alias_entry "[" "test" "${catg}"
123+ fi
124+ if [ "${name}" = "xinstall" ]; then
125+ alias_entry "install" "xinstall" "${catg}"
126+ fi
127+ done
128+}
129+
130+process_dir "${ROOT}/cmd/posix" "posix"
131+compile_make
132+process_dir "${ROOT}/cmd/linux" "linux"
133+process_dir "${ROOT}/cmd/net" "net"
134+process_dir "${ROOT}/cmd/pseudo" "pseudo"
135+process_dir "${ROOT}/cmd/xsi" "xsi"
136+
137+DISP="${BDIR}/aruu-box.c"
138+printf 'mkbox: generating dispatch\n'
139+
140+cat > "${DISP}" << 'DISPATCH_HEAD'
141+/* This software is released into the public domain, or
142+ registered under the ISC License, see ./LICENSE for details
143+ 2026 xplshn [anto@xplshn.com.ar](mailto:anto@xplshn.com.ar) */
144+
145+/* routes argv[0] to the appropriate tool main */
146+#include "util.h"
147+
148+#include <stdio.h>
149+#include <stdlib.h>
150+#include <string.h>
151+#include <unistd.h>
152+
153+extern char *argv0;
154+
155+DISPATCH_HEAD
156+
157+cat "${DECL_F}" >> "${DISP}"
158+
159+cat >> "${DISP}" << 'DISPATCH_STRUCT'
160+
161+struct Cmd {
162+ const char *name;
163+ int (*fn)(int, char **);
164+ const char *cat;
165+};
166+
167+static struct Cmd cmds[] = {
168+DISPATCH_STRUCT
169+
170+cat "${ENT_F}" >> "${DISP}"
171+
172+cat >> "${DISP}" << 'DISPATCH_TAIL'
173+ { NULL, NULL, NULL }
174+};
175+
176+static void
177+usage(void)
178+{
179+ struct Cmd *c;
180+ const char *last;
181+ int col;
182+
183+ last = NULL;
184+ col = 0;
185+ fprintf(stderr, "usage: %s [-i path] [command [args...]]\n", argv0);
186+ for (c = cmds; c->name; c++) {
187+ if (!last || strcmp(c->cat, last) != 0) {
188+ if (last)
189+ fprintf(stderr, "\n\n");
190+ last = c->cat;
191+ fprintf(stderr, "%s:\n", last);
192+ col = 0;
193+ }
194+ if (col == 0) {
195+ fprintf(stderr, "\t%s", c->name);
196+ col = 8 + strlen(c->name);
197+ } else if (col + 2 + strlen(c->name) >= 78) {
198+ fprintf(stderr, ",\n\t%s", c->name);
199+ col = 8 + strlen(c->name);
200+ } else {
201+ fprintf(stderr, ", %s", c->name);
202+ col += 2 + strlen(c->name);
203+ }
204+ }
205+ if (last)
206+ fputc('\n', stderr);
207+ exit(1);
208+}
209+
210+static void
211+x_install(const char *path)
212+{
213+ struct Cmd *c;
214+ char buf[4096];
215+ int r;
216+
217+ for (c = cmds; c->name; c++) {
218+ r = snprintf(buf, sizeof buf, "%s/%s", path, c->name);
219+ if (r < 0 || r >= (int)sizeof buf)
220+ eprintf("install: '%s/%s': path too long\n", path, c->name);
221+ remove(buf);
222+ if (symlink("aruu-box", buf) < 0)
223+ eprintf("install: symlink '%s':", buf);
224+ }
225+}
226+
227+int
228+main(int argc, char *argv[])
229+{
230+ struct Cmd *c;
231+ char *s;
232+
233+ argv0 = argv[0];
234+
235+ s = strrchr(argv[0], '/');
236+ if (s)
237+ s++;
238+ else
239+ s = argv[0];
240+
241+ if (strcmp(s, "aruu-box") == 0) {
242+ if (argc < 2)
243+ usage();
244+ argc--;
245+ argv++;
246+ if (strcmp(argv[0], "-i") == 0) {
247+ if (argc < 2)
248+ eprintf("usage: aruu-box -i path\n");
249+ x_install(argv[1]);
250+ return 0;
251+ }
252+ s = strrchr(argv[0], '/');
253+ if (s)
254+ s++;
255+ else
256+ s = argv[0];
257+ }
258+ for (c = cmds; c->name; c++) {
259+ if (strcmp(c->name, s) == 0) {
260+ argv0 = (char *)c->name;
261+ argv[0] = (char *)c->name;
262+ return c->fn(argc, argv);
263+ }
264+ }
265+ enprintf(127, "%s: not found\n", s);
266+ return 1;
267+}
268+DISPATCH_TAIL
269+
270+printf 'mkbox: cc dispatch\n'
271+eval "${CC} ${CPPFLAGS} ${CFLAGS} -c \"\$DISP\" -o \"\${BDIR}/aruu-box.o\"" ||
272+ die "compile failed: dispatch"
273+OBJS="${OBJS} ${BDIR}/aruu-box.o"
274+
275+printf 'mkbox: ld aruu-box\n'
276+eval "${CC} ${LDFLAGS} -o \"\$BOX\" \$OBJS \"\$LIBUTIL\" \"\$LIBUTF\" \${LDLIBS}" ||
277+ die "link failed"
278+
279+printf 'mkbox: done => %s\n' "${BOX}"
1@@ -0,0 +1,65 @@
2+/*
3+ * Copy me if you can.
4+ * by 20h
5+ */
6+
7+#ifndef ARG_H__
8+#define ARG_H__
9+
10+extern char *argv0;
11+
12+/* use main(int argc, char *argv[]) */
13+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
14+ argv[0] && argv[0][0] == '-'\
15+ && argv[0][1];\
16+ argc--, argv++) {\
17+ char argc_;\
18+ char **argv_;\
19+ int brk_;\
20+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
21+ argv++;\
22+ argc--;\
23+ break;\
24+ }\
25+ for (brk_ = 0, argv[0]++, argv_ = argv;\
26+ argv[0][0] && !brk_;\
27+ argv[0]++) {\
28+ if (argv_ != argv)\
29+ break;\
30+ argc_ = argv[0][0];\
31+ switch (argc_)
32+
33+/* Handles obsolete -NUM syntax */
34+#define ARGNUM case '0':\
35+ case '1':\
36+ case '2':\
37+ case '3':\
38+ case '4':\
39+ case '5':\
40+ case '6':\
41+ case '7':\
42+ case '8':\
43+ case '9'
44+
45+#define ARGEND }\
46+ }
47+
48+#define ARGC() argc_
49+
50+#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
51+
52+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
53+ ((x), abort(), (char *)0) :\
54+ (brk_ = 1, (argv[0][1] != '\0')?\
55+ (&argv[0][1]) :\
56+ (argc--, argv++, argv[0])))
57+
58+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
59+ (char *)0 :\
60+ (brk_ = 1, (argv[0][1] != '\0')?\
61+ (&argv[0][1]) :\
62+ (argc--, argv++, argv[0])))
63+
64+#define LNGARG() &argv[0][0]
65+
66+#endif
1@@ -0,0 +1,6 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+
5+#ifndef HOST_NAME_MAX
6+#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
7+#endif
1@@ -0,0 +1,10 @@
2+/* See LICENSE file for copyright and license details. */
3+
4+#define ENV_PATH "/bin"
5+#define PW_CIPHER "$6$" /* SHA-512 */
6+#undef UTMP_PATH
7+#define UTMP_PATH "/var/run/utmp"
8+#undef BTMP_PATH
9+#define BTMP_PATH "/var/log/btmp"
10+#undef WTMP_PATH
11+#define WTMP_PATH "/var/log/wtmp"
1@@ -0,0 +1,12 @@
2+/* See LICENSE file for copyright and license details. */
3+struct crypt_ops {
4+ void (*init)(void *);
5+ void (*update)(void *, const void *, unsigned long);
6+ void (*sum)(void *, uint8_t *);
7+ void *s;
8+};
9+
10+int cryptcheck(int, char **, struct crypt_ops *, uint8_t *, size_t);
11+int cryptmain(int, char **, struct crypt_ops *, uint8_t *, size_t);
12+int cryptsum(struct crypt_ops *, int, const char *, uint8_t *);
13+void mdprint(const uint8_t *, const char *, size_t);
1@@ -0,0 +1,47 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <limits.h>
4+#include <sys/stat.h>
5+#include <sys/types.h>
6+
7+struct history {
8+ struct history *prev;
9+ dev_t dev;
10+ ino_t ino;
11+};
12+
13+struct recursor {
14+ void (*fn)(int, const char *, struct stat *, void *, struct recursor *);
15+ char path[PATH_MAX];
16+ size_t pathlen;
17+ struct history *hist;
18+ int depth;
19+ int maxdepth;
20+ int follow;
21+ int flags;
22+};
23+
24+enum {
25+ SAMEDEV = 1 << 0,
26+ DIRFIRST = 1 << 1,
27+ SILENT = 1 << 2,
28+ CONFIRM = 1 << 3,
29+ IGNORE = 1 << 4,
30+};
31+
32+extern int cp_aflag;
33+extern int cp_fflag;
34+extern int cp_iflag;
35+extern int cp_pflag;
36+extern int cp_rflag;
37+extern int cp_vflag;
38+extern int cp_follow;
39+extern int cp_status;
40+
41+extern int rm_status;
42+
43+extern int recurse_status;
44+
45+void recurse(int, const char *, void *, struct recursor *);
46+
47+int cp(const char *, const char *, int);
48+void rm(int, const char *, struct stat *st, void *, struct recursor *);
1@@ -0,0 +1,6 @@
2+AWK = awk
3+UNICODE = http://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
4+
5+default:
6+ @echo Downloading and parsing $(UNICODE)
7+ @curl -\# $(UNICODE) | $(AWK) -f mkrunetype.awk
1@@ -0,0 +1,36 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "../utf.h"
9+
10+int
11+fgetrune(Rune *r, FILE *fp)
12+{
13+ char buf[UTFmax];
14+ int i = 0, c;
15+
16+ while (i < UTFmax && (c = fgetc(fp)) != EOF) {
17+ buf[i++] = c;
18+ if (charntorune(r, buf, i) > 0)
19+ break;
20+ }
21+ if (ferror(fp))
22+ return -1;
23+
24+ return i;
25+}
26+
27+int
28+efgetrune(Rune *r, FILE *fp, const char *file)
29+{
30+ int ret;
31+
32+ if ((ret = fgetrune(r, fp)) < 0) {
33+ fprintf(stderr, "fgetrune %s: %s\n", file, strerror(errno));
34+ exit(1);
35+ }
36+ return ret;
37+}
1@@ -0,0 +1,27 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "../utf.h"
9+
10+int
11+fputrune(const Rune *r, FILE *fp)
12+{
13+ char buf[UTFmax];
14+
15+ return fwrite(buf, runetochar(buf, r), 1, fp);
16+}
17+
18+int
19+efputrune(const Rune *r, FILE *fp, const char *file)
20+{
21+ int ret;
22+
23+ if ((ret = fputrune(r, fp)) < 0) {
24+ fprintf(stderr, "fputrune %s: %s\n", file, strerror(errno));
25+ exit(1);
26+ }
27+ return ret;
28+}
1@@ -0,0 +1,9 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include "../utf.h"
4+#include "runetype.h"
5+
6+int
7+isalnumrune(Rune r)
8+{
9+ return isalpharune(r) || isdigitrune(r);
10+}
1@@ -0,0 +1,830 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune alpha3[][2] = {
9+ { 0x00D6, 0x00D8 },
10+ { 0x00F6, 0x00F8 },
11+ { 0x02EC, 0x02EE },
12+ { 0x0374, 0x0376 },
13+ { 0x037D, 0x037F },
14+ { 0x0386, 0x0388 },
15+ { 0x038A, 0x038E },
16+ { 0x03A1, 0x03A3 },
17+ { 0x03F5, 0x03F7 },
18+ { 0x052F, 0x0531 },
19+ { 0x066F, 0x0671 },
20+ { 0x06D3, 0x06D5 },
21+ { 0x0710, 0x0712 },
22+ { 0x0887, 0x0889 },
23+ { 0x09A8, 0x09AA },
24+ { 0x09B0, 0x09B2 },
25+ { 0x09DD, 0x09DF },
26+ { 0x0A28, 0x0A2A },
27+ { 0x0A30, 0x0A32 },
28+ { 0x0A33, 0x0A35 },
29+ { 0x0A36, 0x0A38 },
30+ { 0x0A5C, 0x0A5E },
31+ { 0x0A8D, 0x0A8F },
32+ { 0x0A91, 0x0A93 },
33+ { 0x0AA8, 0x0AAA },
34+ { 0x0AB0, 0x0AB2 },
35+ { 0x0AB3, 0x0AB5 },
36+ { 0x0B28, 0x0B2A },
37+ { 0x0B30, 0x0B32 },
38+ { 0x0B33, 0x0B35 },
39+ { 0x0B5D, 0x0B5F },
40+ { 0x0B83, 0x0B85 },
41+ { 0x0B90, 0x0B92 },
42+ { 0x0B9A, 0x0B9E },
43+ { 0x0C0C, 0x0C0E },
44+ { 0x0C10, 0x0C12 },
45+ { 0x0C28, 0x0C2A },
46+ { 0x0C8C, 0x0C8E },
47+ { 0x0C90, 0x0C92 },
48+ { 0x0CA8, 0x0CAA },
49+ { 0x0CB3, 0x0CB5 },
50+ { 0x0CDE, 0x0CE0 },
51+ { 0x0D0C, 0x0D0E },
52+ { 0x0D10, 0x0D12 },
53+ { 0x0DB1, 0x0DB3 },
54+ { 0x0DBB, 0x0DBD },
55+ { 0x0E30, 0x0E32 },
56+ { 0x0E82, 0x0E86 },
57+ { 0x0E8A, 0x0E8C },
58+ { 0x0EA3, 0x0EA7 },
59+ { 0x0EB0, 0x0EB2 },
60+ { 0x0EC4, 0x0EC6 },
61+ { 0x0F47, 0x0F49 },
62+ { 0x10C5, 0x10C7 },
63+ { 0x10FA, 0x10FC },
64+ { 0x1248, 0x124A },
65+ { 0x1256, 0x125A },
66+ { 0x1288, 0x128A },
67+ { 0x12B0, 0x12B2 },
68+ { 0x12BE, 0x12C2 },
69+ { 0x12D6, 0x12D8 },
70+ { 0x1310, 0x1312 },
71+ { 0x167F, 0x1681 },
72+ { 0x176C, 0x176E },
73+ { 0x18A8, 0x18AA },
74+ { 0x1CEC, 0x1CEE },
75+ { 0x1CF3, 0x1CF5 },
76+ { 0x1F57, 0x1F5F },
77+ { 0x1FB4, 0x1FB6 },
78+ { 0x1FBC, 0x1FBE },
79+ { 0x1FC4, 0x1FC6 },
80+ { 0x1FF4, 0x1FF6 },
81+ { 0x2113, 0x2115 },
82+ { 0x2124, 0x212A },
83+ { 0x212D, 0x212F },
84+ { 0x2D25, 0x2D27 },
85+ { 0x2DA6, 0x2DA8 },
86+ { 0x2DAE, 0x2DB0 },
87+ { 0x2DB6, 0x2DB8 },
88+ { 0x2DBE, 0x2DC0 },
89+ { 0x2DC6, 0x2DC8 },
90+ { 0x2DCE, 0x2DD0 },
91+ { 0x2DD6, 0x2DD8 },
92+ { 0x309F, 0x30A1 },
93+ { 0x30FA, 0x30FC },
94+ { 0x312F, 0x3131 },
95+ { 0xA7D1, 0xA7D5 },
96+ { 0xA801, 0xA803 },
97+ { 0xA805, 0xA807 },
98+ { 0xA80A, 0xA80C },
99+ { 0xA8FB, 0xA8FD },
100+ { 0xA9E4, 0xA9E6 },
101+ { 0xA9FE, 0xAA00 },
102+ { 0xAA42, 0xAA44 },
103+ { 0xAAAF, 0xAAB1 },
104+ { 0xAAC0, 0xAAC2 },
105+ { 0xAB26, 0xAB28 },
106+ { 0xAB2E, 0xAB30 },
107+ { 0xAB5A, 0xAB5C },
108+ { 0xFB1D, 0xFB1F },
109+ { 0xFB28, 0xFB2A },
110+ { 0xFB36, 0xFB38 },
111+ { 0xFB3C, 0xFB40 },
112+ { 0xFB41, 0xFB43 },
113+ { 0xFB44, 0xFB46 },
114+ { 0xFE74, 0xFE76 },
115+ { 0x1000B, 0x1000D },
116+ { 0x10026, 0x10028 },
117+ { 0x1003A, 0x1003C },
118+ { 0x1003D, 0x1003F },
119+ { 0x10340, 0x10342 },
120+ { 0x1057A, 0x1057C },
121+ { 0x1058A, 0x1058C },
122+ { 0x10592, 0x10594 },
123+ { 0x10595, 0x10597 },
124+ { 0x105A1, 0x105A3 },
125+ { 0x105B1, 0x105B3 },
126+ { 0x105B9, 0x105BB },
127+ { 0x10785, 0x10787 },
128+ { 0x107B0, 0x107B2 },
129+ { 0x10808, 0x1080A },
130+ { 0x10835, 0x10837 },
131+ { 0x108F2, 0x108F4 },
132+ { 0x10A13, 0x10A15 },
133+ { 0x10A17, 0x10A19 },
134+ { 0x10AC7, 0x10AC9 },
135+ { 0x111DA, 0x111DC },
136+ { 0x11211, 0x11213 },
137+ { 0x11286, 0x1128A },
138+ { 0x1128D, 0x1128F },
139+ { 0x1129D, 0x1129F },
140+ { 0x11328, 0x1132A },
141+ { 0x11330, 0x11332 },
142+ { 0x11333, 0x11335 },
143+ { 0x114C5, 0x114C7 },
144+ { 0x11913, 0x11915 },
145+ { 0x11916, 0x11918 },
146+ { 0x1193F, 0x11941 },
147+ { 0x119E1, 0x119E3 },
148+ { 0x11C08, 0x11C0A },
149+ { 0x11D06, 0x11D08 },
150+ { 0x11D09, 0x11D0B },
151+ { 0x11D65, 0x11D67 },
152+ { 0x11D68, 0x11D6A },
153+ { 0x11F02, 0x11F04 },
154+ { 0x11F10, 0x11F12 },
155+ { 0x16FE1, 0x16FE3 },
156+ { 0x1AFF3, 0x1AFF5 },
157+ { 0x1AFFB, 0x1AFFD },
158+ { 0x1AFFE, 0x1B000 },
159+ { 0x1D454, 0x1D456 },
160+ { 0x1D49C, 0x1D49E },
161+ { 0x1D4AC, 0x1D4AE },
162+ { 0x1D4B9, 0x1D4BD },
163+ { 0x1D4C3, 0x1D4C5 },
164+ { 0x1D505, 0x1D507 },
165+ { 0x1D514, 0x1D516 },
166+ { 0x1D51C, 0x1D51E },
167+ { 0x1D539, 0x1D53B },
168+ { 0x1D53E, 0x1D540 },
169+ { 0x1D544, 0x1D546 },
170+ { 0x1D550, 0x1D552 },
171+ { 0x1D6C0, 0x1D6C2 },
172+ { 0x1D6DA, 0x1D6DC },
173+ { 0x1D6FA, 0x1D6FC },
174+ { 0x1D714, 0x1D716 },
175+ { 0x1D734, 0x1D736 },
176+ { 0x1D74E, 0x1D750 },
177+ { 0x1D76E, 0x1D770 },
178+ { 0x1D788, 0x1D78A },
179+ { 0x1D7A8, 0x1D7AA },
180+ { 0x1D7C2, 0x1D7C4 },
181+ { 0x1E7E6, 0x1E7E8 },
182+ { 0x1E7EB, 0x1E7ED },
183+ { 0x1E7EE, 0x1E7F0 },
184+ { 0x1E7FE, 0x1E800 },
185+ { 0x1EE03, 0x1EE05 },
186+ { 0x1EE1F, 0x1EE21 },
187+ { 0x1EE22, 0x1EE24 },
188+ { 0x1EE27, 0x1EE29 },
189+ { 0x1EE32, 0x1EE34 },
190+ { 0x1EE37, 0x1EE3B },
191+ { 0x1EE47, 0x1EE4D },
192+ { 0x1EE4F, 0x1EE51 },
193+ { 0x1EE52, 0x1EE54 },
194+ { 0x1EE57, 0x1EE61 },
195+ { 0x1EE62, 0x1EE64 },
196+ { 0x1EE6A, 0x1EE6C },
197+ { 0x1EE72, 0x1EE74 },
198+ { 0x1EE77, 0x1EE79 },
199+ { 0x1EE7C, 0x1EE80 },
200+ { 0x1EE89, 0x1EE8B },
201+ { 0x1EEA3, 0x1EEA5 },
202+ { 0x1EEA9, 0x1EEAB },
203+};
204+
205+static const Rune alpha2[][2] = {
206+ { 0x0041, 0x005A },
207+ { 0x0061, 0x007A },
208+ { 0x00C0, 0x00D6 },
209+ { 0x00D8, 0x00F6 },
210+ { 0x00F8, 0x02C1 },
211+ { 0x02C6, 0x02D1 },
212+ { 0x02E0, 0x02E4 },
213+ { 0x0370, 0x0374 },
214+ { 0x0376, 0x0377 },
215+ { 0x037A, 0x037D },
216+ { 0x0388, 0x038A },
217+ { 0x038E, 0x03A1 },
218+ { 0x03A3, 0x03F5 },
219+ { 0x03F7, 0x0481 },
220+ { 0x048A, 0x052F },
221+ { 0x0531, 0x0556 },
222+ { 0x0560, 0x0588 },
223+ { 0x05D0, 0x05EA },
224+ { 0x05EF, 0x05F2 },
225+ { 0x0620, 0x064A },
226+ { 0x066E, 0x066F },
227+ { 0x0671, 0x06D3 },
228+ { 0x06E5, 0x06E6 },
229+ { 0x06EE, 0x06EF },
230+ { 0x06FA, 0x06FC },
231+ { 0x0712, 0x072F },
232+ { 0x074D, 0x07A5 },
233+ { 0x07CA, 0x07EA },
234+ { 0x07F4, 0x07F5 },
235+ { 0x0800, 0x0815 },
236+ { 0x0840, 0x0858 },
237+ { 0x0860, 0x086A },
238+ { 0x0870, 0x0887 },
239+ { 0x0889, 0x088E },
240+ { 0x08A0, 0x08C9 },
241+ { 0x0904, 0x0939 },
242+ { 0x0958, 0x0961 },
243+ { 0x0971, 0x0980 },
244+ { 0x0985, 0x098C },
245+ { 0x098F, 0x0990 },
246+ { 0x0993, 0x09A8 },
247+ { 0x09AA, 0x09B0 },
248+ { 0x09B6, 0x09B9 },
249+ { 0x09DC, 0x09DD },
250+ { 0x09DF, 0x09E1 },
251+ { 0x09F0, 0x09F1 },
252+ { 0x0A05, 0x0A0A },
253+ { 0x0A0F, 0x0A10 },
254+ { 0x0A13, 0x0A28 },
255+ { 0x0A2A, 0x0A30 },
256+ { 0x0A32, 0x0A33 },
257+ { 0x0A35, 0x0A36 },
258+ { 0x0A38, 0x0A39 },
259+ { 0x0A59, 0x0A5C },
260+ { 0x0A72, 0x0A74 },
261+ { 0x0A85, 0x0A8D },
262+ { 0x0A8F, 0x0A91 },
263+ { 0x0A93, 0x0AA8 },
264+ { 0x0AAA, 0x0AB0 },
265+ { 0x0AB2, 0x0AB3 },
266+ { 0x0AB5, 0x0AB9 },
267+ { 0x0AE0, 0x0AE1 },
268+ { 0x0B05, 0x0B0C },
269+ { 0x0B0F, 0x0B10 },
270+ { 0x0B13, 0x0B28 },
271+ { 0x0B2A, 0x0B30 },
272+ { 0x0B32, 0x0B33 },
273+ { 0x0B35, 0x0B39 },
274+ { 0x0B5C, 0x0B5D },
275+ { 0x0B5F, 0x0B61 },
276+ { 0x0B85, 0x0B8A },
277+ { 0x0B8E, 0x0B90 },
278+ { 0x0B92, 0x0B95 },
279+ { 0x0B99, 0x0B9A },
280+ { 0x0B9E, 0x0B9F },
281+ { 0x0BA3, 0x0BA4 },
282+ { 0x0BA8, 0x0BAA },
283+ { 0x0BAE, 0x0BB9 },
284+ { 0x0C05, 0x0C0C },
285+ { 0x0C0E, 0x0C10 },
286+ { 0x0C12, 0x0C28 },
287+ { 0x0C2A, 0x0C39 },
288+ { 0x0C58, 0x0C5A },
289+ { 0x0C60, 0x0C61 },
290+ { 0x0C85, 0x0C8C },
291+ { 0x0C8E, 0x0C90 },
292+ { 0x0C92, 0x0CA8 },
293+ { 0x0CAA, 0x0CB3 },
294+ { 0x0CB5, 0x0CB9 },
295+ { 0x0CDD, 0x0CDE },
296+ { 0x0CE0, 0x0CE1 },
297+ { 0x0CF1, 0x0CF2 },
298+ { 0x0D04, 0x0D0C },
299+ { 0x0D0E, 0x0D10 },
300+ { 0x0D12, 0x0D3A },
301+ { 0x0D54, 0x0D56 },
302+ { 0x0D5F, 0x0D61 },
303+ { 0x0D7A, 0x0D7F },
304+ { 0x0D85, 0x0D96 },
305+ { 0x0D9A, 0x0DB1 },
306+ { 0x0DB3, 0x0DBB },
307+ { 0x0DC0, 0x0DC6 },
308+ { 0x0E01, 0x0E30 },
309+ { 0x0E32, 0x0E33 },
310+ { 0x0E40, 0x0E46 },
311+ { 0x0E81, 0x0E82 },
312+ { 0x0E86, 0x0E8A },
313+ { 0x0E8C, 0x0EA3 },
314+ { 0x0EA7, 0x0EB0 },
315+ { 0x0EB2, 0x0EB3 },
316+ { 0x0EC0, 0x0EC4 },
317+ { 0x0EDC, 0x0EDF },
318+ { 0x0F40, 0x0F47 },
319+ { 0x0F49, 0x0F6C },
320+ { 0x0F88, 0x0F8C },
321+ { 0x1000, 0x102A },
322+ { 0x1050, 0x1055 },
323+ { 0x105A, 0x105D },
324+ { 0x1065, 0x1066 },
325+ { 0x106E, 0x1070 },
326+ { 0x1075, 0x1081 },
327+ { 0x10A0, 0x10C5 },
328+ { 0x10D0, 0x10FA },
329+ { 0x10FC, 0x1248 },
330+ { 0x124A, 0x124D },
331+ { 0x1250, 0x1256 },
332+ { 0x125A, 0x125D },
333+ { 0x1260, 0x1288 },
334+ { 0x128A, 0x128D },
335+ { 0x1290, 0x12B0 },
336+ { 0x12B2, 0x12B5 },
337+ { 0x12B8, 0x12BE },
338+ { 0x12C2, 0x12C5 },
339+ { 0x12C8, 0x12D6 },
340+ { 0x12D8, 0x1310 },
341+ { 0x1312, 0x1315 },
342+ { 0x1318, 0x135A },
343+ { 0x1380, 0x138F },
344+ { 0x13A0, 0x13F5 },
345+ { 0x13F8, 0x13FD },
346+ { 0x1401, 0x166C },
347+ { 0x166F, 0x167F },
348+ { 0x1681, 0x169A },
349+ { 0x16A0, 0x16EA },
350+ { 0x16F1, 0x16F8 },
351+ { 0x1700, 0x1711 },
352+ { 0x171F, 0x1731 },
353+ { 0x1740, 0x1751 },
354+ { 0x1760, 0x176C },
355+ { 0x176E, 0x1770 },
356+ { 0x1780, 0x17B3 },
357+ { 0x1820, 0x1878 },
358+ { 0x1880, 0x1884 },
359+ { 0x1887, 0x18A8 },
360+ { 0x18B0, 0x18F5 },
361+ { 0x1900, 0x191E },
362+ { 0x1950, 0x196D },
363+ { 0x1970, 0x1974 },
364+ { 0x1980, 0x19AB },
365+ { 0x19B0, 0x19C9 },
366+ { 0x1A00, 0x1A16 },
367+ { 0x1A20, 0x1A54 },
368+ { 0x1B05, 0x1B33 },
369+ { 0x1B45, 0x1B4C },
370+ { 0x1B83, 0x1BA0 },
371+ { 0x1BAE, 0x1BAF },
372+ { 0x1BBA, 0x1BE5 },
373+ { 0x1C00, 0x1C23 },
374+ { 0x1C4D, 0x1C4F },
375+ { 0x1C5A, 0x1C7D },
376+ { 0x1C80, 0x1C88 },
377+ { 0x1C90, 0x1CBA },
378+ { 0x1CBD, 0x1CBF },
379+ { 0x1CE9, 0x1CEC },
380+ { 0x1CEE, 0x1CF3 },
381+ { 0x1CF5, 0x1CF6 },
382+ { 0x1D00, 0x1DBF },
383+ { 0x1E00, 0x1F15 },
384+ { 0x1F18, 0x1F1D },
385+ { 0x1F20, 0x1F45 },
386+ { 0x1F48, 0x1F4D },
387+ { 0x1F50, 0x1F57 },
388+ { 0x1F5F, 0x1F7D },
389+ { 0x1F80, 0x1FB4 },
390+ { 0x1FB6, 0x1FBC },
391+ { 0x1FC2, 0x1FC4 },
392+ { 0x1FC6, 0x1FCC },
393+ { 0x1FD0, 0x1FD3 },
394+ { 0x1FD6, 0x1FDB },
395+ { 0x1FE0, 0x1FEC },
396+ { 0x1FF2, 0x1FF4 },
397+ { 0x1FF6, 0x1FFC },
398+ { 0x2090, 0x209C },
399+ { 0x210A, 0x2113 },
400+ { 0x2119, 0x211D },
401+ { 0x212A, 0x212D },
402+ { 0x212F, 0x2139 },
403+ { 0x213C, 0x213F },
404+ { 0x2145, 0x2149 },
405+ { 0x2183, 0x2184 },
406+ { 0x2C00, 0x2CE4 },
407+ { 0x2CEB, 0x2CEE },
408+ { 0x2CF2, 0x2CF3 },
409+ { 0x2D00, 0x2D25 },
410+ { 0x2D30, 0x2D67 },
411+ { 0x2D80, 0x2D96 },
412+ { 0x2DA0, 0x2DA6 },
413+ { 0x2DA8, 0x2DAE },
414+ { 0x2DB0, 0x2DB6 },
415+ { 0x2DB8, 0x2DBE },
416+ { 0x2DC0, 0x2DC6 },
417+ { 0x2DC8, 0x2DCE },
418+ { 0x2DD0, 0x2DD6 },
419+ { 0x2DD8, 0x2DDE },
420+ { 0x3005, 0x3006 },
421+ { 0x3031, 0x3035 },
422+ { 0x303B, 0x303C },
423+ { 0x3041, 0x3096 },
424+ { 0x309D, 0x309F },
425+ { 0x30A1, 0x30FA },
426+ { 0x30FC, 0x30FF },
427+ { 0x3105, 0x312F },
428+ { 0x3131, 0x318E },
429+ { 0x31A0, 0x31BF },
430+ { 0x31F0, 0x31FF },
431+ { 0x9FFF, 0xA48C },
432+ { 0xA4D0, 0xA4FD },
433+ { 0xA500, 0xA60C },
434+ { 0xA610, 0xA61F },
435+ { 0xA62A, 0xA62B },
436+ { 0xA640, 0xA66E },
437+ { 0xA67F, 0xA69D },
438+ { 0xA6A0, 0xA6E5 },
439+ { 0xA717, 0xA71F },
440+ { 0xA722, 0xA788 },
441+ { 0xA78B, 0xA7CA },
442+ { 0xA7D0, 0xA7D1 },
443+ { 0xA7D5, 0xA7D9 },
444+ { 0xA7F2, 0xA801 },
445+ { 0xA803, 0xA805 },
446+ { 0xA807, 0xA80A },
447+ { 0xA80C, 0xA822 },
448+ { 0xA840, 0xA873 },
449+ { 0xA882, 0xA8B3 },
450+ { 0xA8F2, 0xA8F7 },
451+ { 0xA8FD, 0xA8FE },
452+ { 0xA90A, 0xA925 },
453+ { 0xA930, 0xA946 },
454+ { 0xA960, 0xA97C },
455+ { 0xA984, 0xA9B2 },
456+ { 0xA9E0, 0xA9E4 },
457+ { 0xA9E6, 0xA9EF },
458+ { 0xA9FA, 0xA9FE },
459+ { 0xAA00, 0xAA28 },
460+ { 0xAA40, 0xAA42 },
461+ { 0xAA44, 0xAA4B },
462+ { 0xAA60, 0xAA76 },
463+ { 0xAA7E, 0xAAAF },
464+ { 0xAAB5, 0xAAB6 },
465+ { 0xAAB9, 0xAABD },
466+ { 0xAADB, 0xAADD },
467+ { 0xAAE0, 0xAAEA },
468+ { 0xAAF2, 0xAAF4 },
469+ { 0xAB01, 0xAB06 },
470+ { 0xAB09, 0xAB0E },
471+ { 0xAB11, 0xAB16 },
472+ { 0xAB20, 0xAB26 },
473+ { 0xAB28, 0xAB2E },
474+ { 0xAB30, 0xAB5A },
475+ { 0xAB5C, 0xAB69 },
476+ { 0xAB70, 0xABE2 },
477+ { 0xD7B0, 0xD7C6 },
478+ { 0xD7CB, 0xD7FB },
479+ { 0xF900, 0xFA6D },
480+ { 0xFA70, 0xFAD9 },
481+ { 0xFB00, 0xFB06 },
482+ { 0xFB13, 0xFB17 },
483+ { 0xFB1F, 0xFB28 },
484+ { 0xFB2A, 0xFB36 },
485+ { 0xFB38, 0xFB3C },
486+ { 0xFB40, 0xFB41 },
487+ { 0xFB43, 0xFB44 },
488+ { 0xFB46, 0xFBB1 },
489+ { 0xFBD3, 0xFD3D },
490+ { 0xFD50, 0xFD8F },
491+ { 0xFD92, 0xFDC7 },
492+ { 0xFDF0, 0xFDFB },
493+ { 0xFE70, 0xFE74 },
494+ { 0xFE76, 0xFEFC },
495+ { 0xFF21, 0xFF3A },
496+ { 0xFF41, 0xFF5A },
497+ { 0xFF66, 0xFFBE },
498+ { 0xFFC2, 0xFFC7 },
499+ { 0xFFCA, 0xFFCF },
500+ { 0xFFD2, 0xFFD7 },
501+ { 0xFFDA, 0xFFDC },
502+ { 0x10000, 0x1000B },
503+ { 0x1000D, 0x10026 },
504+ { 0x10028, 0x1003A },
505+ { 0x1003C, 0x1003D },
506+ { 0x1003F, 0x1004D },
507+ { 0x10050, 0x1005D },
508+ { 0x10080, 0x100FA },
509+ { 0x10280, 0x1029C },
510+ { 0x102A0, 0x102D0 },
511+ { 0x10300, 0x1031F },
512+ { 0x1032D, 0x10340 },
513+ { 0x10342, 0x10349 },
514+ { 0x10350, 0x10375 },
515+ { 0x10380, 0x1039D },
516+ { 0x103A0, 0x103C3 },
517+ { 0x103C8, 0x103CF },
518+ { 0x10400, 0x1049D },
519+ { 0x104B0, 0x104D3 },
520+ { 0x104D8, 0x104FB },
521+ { 0x10500, 0x10527 },
522+ { 0x10530, 0x10563 },
523+ { 0x10570, 0x1057A },
524+ { 0x1057C, 0x1058A },
525+ { 0x1058C, 0x10592 },
526+ { 0x10594, 0x10595 },
527+ { 0x10597, 0x105A1 },
528+ { 0x105A3, 0x105B1 },
529+ { 0x105B3, 0x105B9 },
530+ { 0x105BB, 0x105BC },
531+ { 0x10600, 0x10736 },
532+ { 0x10740, 0x10755 },
533+ { 0x10760, 0x10767 },
534+ { 0x10780, 0x10785 },
535+ { 0x10787, 0x107B0 },
536+ { 0x107B2, 0x107BA },
537+ { 0x10800, 0x10805 },
538+ { 0x1080A, 0x10835 },
539+ { 0x10837, 0x10838 },
540+ { 0x1083F, 0x10855 },
541+ { 0x10860, 0x10876 },
542+ { 0x10880, 0x1089E },
543+ { 0x108E0, 0x108F2 },
544+ { 0x108F4, 0x108F5 },
545+ { 0x10900, 0x10915 },
546+ { 0x10920, 0x10939 },
547+ { 0x10980, 0x109B7 },
548+ { 0x109BE, 0x109BF },
549+ { 0x10A10, 0x10A13 },
550+ { 0x10A15, 0x10A17 },
551+ { 0x10A19, 0x10A35 },
552+ { 0x10A60, 0x10A7C },
553+ { 0x10A80, 0x10A9C },
554+ { 0x10AC0, 0x10AC7 },
555+ { 0x10AC9, 0x10AE4 },
556+ { 0x10B00, 0x10B35 },
557+ { 0x10B40, 0x10B55 },
558+ { 0x10B60, 0x10B72 },
559+ { 0x10B80, 0x10B91 },
560+ { 0x10C00, 0x10C48 },
561+ { 0x10C80, 0x10CB2 },
562+ { 0x10CC0, 0x10CF2 },
563+ { 0x10D00, 0x10D23 },
564+ { 0x10E80, 0x10EA9 },
565+ { 0x10EB0, 0x10EB1 },
566+ { 0x10F00, 0x10F1C },
567+ { 0x10F30, 0x10F45 },
568+ { 0x10F70, 0x10F81 },
569+ { 0x10FB0, 0x10FC4 },
570+ { 0x10FE0, 0x10FF6 },
571+ { 0x11003, 0x11037 },
572+ { 0x11071, 0x11072 },
573+ { 0x11083, 0x110AF },
574+ { 0x110D0, 0x110E8 },
575+ { 0x11103, 0x11126 },
576+ { 0x11150, 0x11172 },
577+ { 0x11183, 0x111B2 },
578+ { 0x111C1, 0x111C4 },
579+ { 0x11200, 0x11211 },
580+ { 0x11213, 0x1122B },
581+ { 0x1123F, 0x11240 },
582+ { 0x11280, 0x11286 },
583+ { 0x1128A, 0x1128D },
584+ { 0x1128F, 0x1129D },
585+ { 0x1129F, 0x112A8 },
586+ { 0x112B0, 0x112DE },
587+ { 0x11305, 0x1130C },
588+ { 0x1130F, 0x11310 },
589+ { 0x11313, 0x11328 },
590+ { 0x1132A, 0x11330 },
591+ { 0x11332, 0x11333 },
592+ { 0x11335, 0x11339 },
593+ { 0x1135D, 0x11361 },
594+ { 0x11400, 0x11434 },
595+ { 0x11447, 0x1144A },
596+ { 0x1145F, 0x11461 },
597+ { 0x11480, 0x114AF },
598+ { 0x114C4, 0x114C5 },
599+ { 0x11580, 0x115AE },
600+ { 0x115D8, 0x115DB },
601+ { 0x11600, 0x1162F },
602+ { 0x11680, 0x116AA },
603+ { 0x11700, 0x1171A },
604+ { 0x11740, 0x11746 },
605+ { 0x11800, 0x1182B },
606+ { 0x118A0, 0x118DF },
607+ { 0x118FF, 0x11906 },
608+ { 0x1190C, 0x11913 },
609+ { 0x11915, 0x11916 },
610+ { 0x11918, 0x1192F },
611+ { 0x119A0, 0x119A7 },
612+ { 0x119AA, 0x119D0 },
613+ { 0x11A0B, 0x11A32 },
614+ { 0x11A5C, 0x11A89 },
615+ { 0x11AB0, 0x11AF8 },
616+ { 0x11C00, 0x11C08 },
617+ { 0x11C0A, 0x11C2E },
618+ { 0x11C72, 0x11C8F },
619+ { 0x11D00, 0x11D06 },
620+ { 0x11D08, 0x11D09 },
621+ { 0x11D0B, 0x11D30 },
622+ { 0x11D60, 0x11D65 },
623+ { 0x11D67, 0x11D68 },
624+ { 0x11D6A, 0x11D89 },
625+ { 0x11EE0, 0x11EF2 },
626+ { 0x11F04, 0x11F10 },
627+ { 0x11F12, 0x11F33 },
628+ { 0x12000, 0x12399 },
629+ { 0x12480, 0x12543 },
630+ { 0x12F90, 0x12FF0 },
631+ { 0x13000, 0x1342F },
632+ { 0x13441, 0x13446 },
633+ { 0x14400, 0x14646 },
634+ { 0x16800, 0x16A38 },
635+ { 0x16A40, 0x16A5E },
636+ { 0x16A70, 0x16ABE },
637+ { 0x16AD0, 0x16AED },
638+ { 0x16B00, 0x16B2F },
639+ { 0x16B40, 0x16B43 },
640+ { 0x16B63, 0x16B77 },
641+ { 0x16B7D, 0x16B8F },
642+ { 0x16E40, 0x16E7F },
643+ { 0x16F00, 0x16F4A },
644+ { 0x16F93, 0x16F9F },
645+ { 0x16FE0, 0x16FE1 },
646+ { 0x18800, 0x18CD5 },
647+ { 0x1AFF0, 0x1AFF3 },
648+ { 0x1AFF5, 0x1AFFB },
649+ { 0x1AFFD, 0x1AFFE },
650+ { 0x1B000, 0x1B122 },
651+ { 0x1B150, 0x1B152 },
652+ { 0x1B164, 0x1B167 },
653+ { 0x1B170, 0x1B2FB },
654+ { 0x1BC00, 0x1BC6A },
655+ { 0x1BC70, 0x1BC7C },
656+ { 0x1BC80, 0x1BC88 },
657+ { 0x1BC90, 0x1BC99 },
658+ { 0x1D400, 0x1D454 },
659+ { 0x1D456, 0x1D49C },
660+ { 0x1D49E, 0x1D49F },
661+ { 0x1D4A5, 0x1D4A6 },
662+ { 0x1D4A9, 0x1D4AC },
663+ { 0x1D4AE, 0x1D4B9 },
664+ { 0x1D4BD, 0x1D4C3 },
665+ { 0x1D4C5, 0x1D505 },
666+ { 0x1D507, 0x1D50A },
667+ { 0x1D50D, 0x1D514 },
668+ { 0x1D516, 0x1D51C },
669+ { 0x1D51E, 0x1D539 },
670+ { 0x1D53B, 0x1D53E },
671+ { 0x1D540, 0x1D544 },
672+ { 0x1D54A, 0x1D550 },
673+ { 0x1D552, 0x1D6A5 },
674+ { 0x1D6A8, 0x1D6C0 },
675+ { 0x1D6C2, 0x1D6DA },
676+ { 0x1D6DC, 0x1D6FA },
677+ { 0x1D6FC, 0x1D714 },
678+ { 0x1D716, 0x1D734 },
679+ { 0x1D736, 0x1D74E },
680+ { 0x1D750, 0x1D76E },
681+ { 0x1D770, 0x1D788 },
682+ { 0x1D78A, 0x1D7A8 },
683+ { 0x1D7AA, 0x1D7C2 },
684+ { 0x1D7C4, 0x1D7CB },
685+ { 0x1DF00, 0x1DF1E },
686+ { 0x1DF25, 0x1DF2A },
687+ { 0x1E030, 0x1E06D },
688+ { 0x1E100, 0x1E12C },
689+ { 0x1E137, 0x1E13D },
690+ { 0x1E290, 0x1E2AD },
691+ { 0x1E2C0, 0x1E2EB },
692+ { 0x1E4D0, 0x1E4EB },
693+ { 0x1E7E0, 0x1E7E6 },
694+ { 0x1E7E8, 0x1E7EB },
695+ { 0x1E7ED, 0x1E7EE },
696+ { 0x1E7F0, 0x1E7FE },
697+ { 0x1E800, 0x1E8C4 },
698+ { 0x1E900, 0x1E943 },
699+ { 0x1EE00, 0x1EE03 },
700+ { 0x1EE05, 0x1EE1F },
701+ { 0x1EE21, 0x1EE22 },
702+ { 0x1EE29, 0x1EE32 },
703+ { 0x1EE34, 0x1EE37 },
704+ { 0x1EE4D, 0x1EE4F },
705+ { 0x1EE51, 0x1EE52 },
706+ { 0x1EE61, 0x1EE62 },
707+ { 0x1EE67, 0x1EE6A },
708+ { 0x1EE6C, 0x1EE72 },
709+ { 0x1EE74, 0x1EE77 },
710+ { 0x1EE79, 0x1EE7C },
711+ { 0x1EE80, 0x1EE89 },
712+ { 0x1EE8B, 0x1EE9B },
713+ { 0x1EEA1, 0x1EEA3 },
714+ { 0x1EEA5, 0x1EEA9 },
715+ { 0x1EEAB, 0x1EEBB },
716+ { 0x2F800, 0x2FA1D },
717+};
718+
719+static const Rune alpha1[] = {
720+ 0x00AA,
721+ 0x00B5,
722+ 0x00BA,
723+ 0x0559,
724+ 0x06FF,
725+ 0x07B1,
726+ 0x07FA,
727+ 0x081A,
728+ 0x0824,
729+ 0x0828,
730+ 0x093D,
731+ 0x0950,
732+ 0x09BD,
733+ 0x09CE,
734+ 0x09FC,
735+ 0x0ABD,
736+ 0x0AD0,
737+ 0x0AF9,
738+ 0x0B3D,
739+ 0x0B71,
740+ 0x0BD0,
741+ 0x0C3D,
742+ 0x0C5D,
743+ 0x0C80,
744+ 0x0CBD,
745+ 0x0D3D,
746+ 0x0D4E,
747+ 0x0EBD,
748+ 0x0F00,
749+ 0x103F,
750+ 0x1061,
751+ 0x108E,
752+ 0x10CD,
753+ 0x17D7,
754+ 0x17DC,
755+ 0x1AA7,
756+ 0x1CFA,
757+ 0x2071,
758+ 0x207F,
759+ 0x2102,
760+ 0x2107,
761+ 0x214E,
762+ 0x2D2D,
763+ 0x2D6F,
764+ 0x2E2F,
765+ 0x3400,
766+ 0x4DBF,
767+ 0x4E00,
768+ 0xA9CF,
769+ 0xAA7A,
770+ 0xAC00,
771+ 0xD7A3,
772+ 0x1083C,
773+ 0x10A00,
774+ 0x10F27,
775+ 0x11075,
776+ 0x11144,
777+ 0x11147,
778+ 0x11176,
779+ 0x1133D,
780+ 0x11350,
781+ 0x11644,
782+ 0x116B8,
783+ 0x11909,
784+ 0x11A00,
785+ 0x11A3A,
786+ 0x11A50,
787+ 0x11A9D,
788+ 0x11C40,
789+ 0x11D46,
790+ 0x11D98,
791+ 0x11FB0,
792+ 0x16F50,
793+ 0x17000,
794+ 0x187F7,
795+ 0x18D00,
796+ 0x18D08,
797+ 0x1B132,
798+ 0x1B155,
799+ 0x1D4A2,
800+ 0x1E14E,
801+ 0x1E94B,
802+ 0x1EE42,
803+ 0x20000,
804+ 0x2A6DF,
805+ 0x2A700,
806+ 0x2B739,
807+ 0x2B740,
808+ 0x2B81D,
809+ 0x2B820,
810+ 0x2CEA1,
811+ 0x2CEB0,
812+ 0x2EBE0,
813+ 0x30000,
814+ 0x3134A,
815+ 0x31350,
816+ 0x323AF,
817+};
818+
819+int
820+isalpharune(Rune r)
821+{
822+ const Rune *match;
823+
824+ if((match = bsearch(&r, alpha3, nelem(alpha3), sizeof *alpha3, &rune2cmp)))
825+ return !((r - match[0]) % 2);
826+ if(bsearch(&r, alpha2, nelem(alpha2), sizeof *alpha2, &rune2cmp))
827+ return 1;
828+ if(bsearch(&r, alpha1, nelem(alpha1), sizeof *alpha1, &rune1cmp))
829+ return 1;
830+ return 0;
831+}
1@@ -0,0 +1,9 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include "../utf.h"
4+#include "runetype.h"
5+
6+int
7+isblankrune(Rune r)
8+{
9+ return r == ' ' || r == '\t';
10+}
1@@ -0,0 +1,18 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune cntrl2[][2] = {
9+ { 0x0000, 0x001F },
10+ { 0x007F, 0x009F },
11+};
12+
13+int
14+iscntrlrune(Rune r)
15+{
16+ if(bsearch(&r, cntrl2, nelem(cntrl2), sizeof *cntrl2, &rune2cmp))
17+ return 1;
18+ return 0;
19+}
1@@ -0,0 +1,80 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune digit2[][2] = {
9+ { 0x0030, 0x0039 },
10+ { 0x0660, 0x0669 },
11+ { 0x06F0, 0x06F9 },
12+ { 0x07C0, 0x07C9 },
13+ { 0x0966, 0x096F },
14+ { 0x09E6, 0x09EF },
15+ { 0x0A66, 0x0A6F },
16+ { 0x0AE6, 0x0AEF },
17+ { 0x0B66, 0x0B6F },
18+ { 0x0BE6, 0x0BEF },
19+ { 0x0C66, 0x0C6F },
20+ { 0x0CE6, 0x0CEF },
21+ { 0x0D66, 0x0D6F },
22+ { 0x0DE6, 0x0DEF },
23+ { 0x0E50, 0x0E59 },
24+ { 0x0ED0, 0x0ED9 },
25+ { 0x0F20, 0x0F29 },
26+ { 0x1040, 0x1049 },
27+ { 0x1090, 0x1099 },
28+ { 0x17E0, 0x17E9 },
29+ { 0x1810, 0x1819 },
30+ { 0x1946, 0x194F },
31+ { 0x19D0, 0x19D9 },
32+ { 0x1A80, 0x1A89 },
33+ { 0x1A90, 0x1A99 },
34+ { 0x1B50, 0x1B59 },
35+ { 0x1BB0, 0x1BB9 },
36+ { 0x1C40, 0x1C49 },
37+ { 0x1C50, 0x1C59 },
38+ { 0xA620, 0xA629 },
39+ { 0xA8D0, 0xA8D9 },
40+ { 0xA900, 0xA909 },
41+ { 0xA9D0, 0xA9D9 },
42+ { 0xA9F0, 0xA9F9 },
43+ { 0xAA50, 0xAA59 },
44+ { 0xABF0, 0xABF9 },
45+ { 0xFF10, 0xFF19 },
46+ { 0x104A0, 0x104A9 },
47+ { 0x10D30, 0x10D39 },
48+ { 0x11066, 0x1106F },
49+ { 0x110F0, 0x110F9 },
50+ { 0x11136, 0x1113F },
51+ { 0x111D0, 0x111D9 },
52+ { 0x112F0, 0x112F9 },
53+ { 0x11450, 0x11459 },
54+ { 0x114D0, 0x114D9 },
55+ { 0x11650, 0x11659 },
56+ { 0x116C0, 0x116C9 },
57+ { 0x11730, 0x11739 },
58+ { 0x118E0, 0x118E9 },
59+ { 0x11950, 0x11959 },
60+ { 0x11C50, 0x11C59 },
61+ { 0x11D50, 0x11D59 },
62+ { 0x11DA0, 0x11DA9 },
63+ { 0x11F50, 0x11F59 },
64+ { 0x16A60, 0x16A69 },
65+ { 0x16AC0, 0x16AC9 },
66+ { 0x16B50, 0x16B59 },
67+ { 0x1D7CE, 0x1D7FF },
68+ { 0x1E140, 0x1E149 },
69+ { 0x1E2F0, 0x1E2F9 },
70+ { 0x1E4F0, 0x1E4F9 },
71+ { 0x1E950, 0x1E959 },
72+ { 0x1FBF0, 0x1FBF9 },
73+};
74+
75+int
76+isdigitrune(Rune r)
77+{
78+ if(bsearch(&r, digit2, nelem(digit2), sizeof *digit2, &rune2cmp))
79+ return 1;
80+ return 0;
81+}
1@@ -0,0 +1,9 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include "../utf.h"
4+#include "runetype.h"
5+
6+int
7+isgraphrune(Rune r)
8+{
9+ return !isspacerune(r) && isprintrune(r);
10+}
1@@ -0,0 +1,10 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include "../utf.h"
4+#include "runetype.h"
5+
6+int
7+isprintrune(Rune r)
8+{
9+ return !iscntrlrune(r) && (r != 0x2028) && (r != 0x2029) &&
10+ ((r < 0xFFF9) || (r > 0xFFFB));
11+}
1@@ -0,0 +1,9 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include "../utf.h"
4+#include "runetype.h"
5+
6+int
7+ispunctrune(Rune r)
8+{
9+ return isgraphrune(r) && !isalnumrune(r);
10+}
1@@ -0,0 +1,31 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune space2[][2] = {
9+ { 0x0009, 0x000D },
10+ { 0x001C, 0x0020 },
11+ { 0x2000, 0x200A },
12+ { 0x2028, 0x2029 },
13+};
14+
15+static const Rune space1[] = {
16+ 0x0085,
17+ 0x00A0,
18+ 0x1680,
19+ 0x202F,
20+ 0x205F,
21+ 0x3000,
22+};
23+
24+int
25+isspacerune(Rune r)
26+{
27+ if(bsearch(&r, space2, nelem(space2), sizeof *space2, &rune2cmp))
28+ return 1;
29+ if(bsearch(&r, space1, nelem(space1), sizeof *space1, &rune1cmp))
30+ return 1;
31+ return 0;
32+}
1@@ -0,0 +1,31 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune title2[][2] = {
9+ { 0x1F88, 0x1F8F },
10+ { 0x1F98, 0x1F9F },
11+ { 0x1FA8, 0x1FAF },
12+};
13+
14+static const Rune title1[] = {
15+ 0x01C5,
16+ 0x01C8,
17+ 0x01CB,
18+ 0x01F2,
19+ 0x1FBC,
20+ 0x1FCC,
21+ 0x1FFC,
22+};
23+
24+int
25+istitlerune(Rune r)
26+{
27+ if(bsearch(&r, title2, nelem(title2), sizeof *title2, &rune2cmp))
28+ return 1;
29+ if(bsearch(&r, title1, nelem(title1), sizeof *title1, &rune1cmp))
30+ return 1;
31+ return 0;
32+}
1@@ -0,0 +1,9 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include "../utf.h"
4+#include "runetype.h"
5+
6+int
7+isxdigitrune(Rune r)
8+{
9+ return (r >= '0' && (r - '0') < 10) || (r >= 'a' && (r - 'a') < 6);
10+}
1@@ -0,0 +1,356 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune lower4[][2] = {
9+ { 0x0101, 0x012F },
10+ { 0x0133, 0x0137 },
11+ { 0x013A, 0x0148 },
12+ { 0x014B, 0x0177 },
13+ { 0x017A, 0x017E },
14+ { 0x0183, 0x0185 },
15+ { 0x01A1, 0x01A5 },
16+ { 0x01B4, 0x01B6 },
17+ { 0x01CE, 0x01DC },
18+ { 0x01DF, 0x01EF },
19+ { 0x01F9, 0x021F },
20+ { 0x0223, 0x0233 },
21+ { 0x0247, 0x024F },
22+ { 0x0371, 0x0373 },
23+ { 0x03D9, 0x03EF },
24+ { 0x0461, 0x0481 },
25+ { 0x048B, 0x04BF },
26+ { 0x04C2, 0x04CE },
27+ { 0x04D1, 0x052F },
28+ { 0x1E01, 0x1E95 },
29+ { 0x1EA1, 0x1EFF },
30+ { 0x2C68, 0x2C6C },
31+ { 0x2C81, 0x2CE3 },
32+ { 0x2CEC, 0x2CEE },
33+ { 0xA641, 0xA66D },
34+ { 0xA681, 0xA69B },
35+ { 0xA723, 0xA72F },
36+ { 0xA733, 0xA76F },
37+ { 0xA77A, 0xA77C },
38+ { 0xA77F, 0xA787 },
39+ { 0xA791, 0xA793 },
40+ { 0xA797, 0xA7A9 },
41+ { 0xA7B5, 0xA7C3 },
42+ { 0xA7C8, 0xA7CA },
43+ { 0xA7D7, 0xA7D9 },
44+};
45+
46+static const Rune lower2[][3] = {
47+ { 0x0061, 0x007A, 0x0041 },
48+ { 0x00E0, 0x00F6, 0x00C0 },
49+ { 0x00F8, 0x00FE, 0x00D8 },
50+ { 0x01AA, 0x01AB, 0x01AA },
51+ { 0x0234, 0x0239, 0x0234 },
52+ { 0x023F, 0x0240, 0x2C7E },
53+ { 0x0256, 0x0257, 0x0189 },
54+ { 0x025D, 0x025F, 0x025D },
55+ { 0x026D, 0x026E, 0x026D },
56+ { 0x0273, 0x0274, 0x0273 },
57+ { 0x0276, 0x027C, 0x0276 },
58+ { 0x027E, 0x027F, 0x027E },
59+ { 0x0284, 0x0286, 0x0284 },
60+ { 0x028A, 0x028B, 0x01B1 },
61+ { 0x028D, 0x0291, 0x028D },
62+ { 0x0295, 0x029C, 0x0295 },
63+ { 0x029F, 0x02AF, 0x029F },
64+ { 0x037B, 0x037D, 0x03FD },
65+ { 0x03AD, 0x03AF, 0x0388 },
66+ { 0x03B1, 0x03C1, 0x0391 },
67+ { 0x03C3, 0x03CB, 0x03A3 },
68+ { 0x03CD, 0x03CE, 0x038E },
69+ { 0x0430, 0x044F, 0x0410 },
70+ { 0x0450, 0x045F, 0x0400 },
71+ { 0x0561, 0x0586, 0x0531 },
72+ { 0x0587, 0x0588, 0x0587 },
73+ { 0x10D0, 0x10FA, 0x1C90 },
74+ { 0x10FD, 0x10FF, 0x1CBD },
75+ { 0x13F8, 0x13FD, 0x13F0 },
76+ { 0x1C83, 0x1C84, 0x0421 },
77+ { 0x1D00, 0x1D2B, 0x1D00 },
78+ { 0x1D6B, 0x1D77, 0x1D6B },
79+ { 0x1D7A, 0x1D7C, 0x1D7A },
80+ { 0x1D7E, 0x1D8D, 0x1D7E },
81+ { 0x1D8F, 0x1D9A, 0x1D8F },
82+ { 0x1E96, 0x1E9A, 0x1E96 },
83+ { 0x1E9C, 0x1E9D, 0x1E9C },
84+ { 0x1F00, 0x1F07, 0x1F08 },
85+ { 0x1F10, 0x1F15, 0x1F18 },
86+ { 0x1F20, 0x1F27, 0x1F28 },
87+ { 0x1F30, 0x1F37, 0x1F38 },
88+ { 0x1F40, 0x1F45, 0x1F48 },
89+ { 0x1F60, 0x1F67, 0x1F68 },
90+ { 0x1F70, 0x1F71, 0x1FBA },
91+ { 0x1F72, 0x1F75, 0x1FC8 },
92+ { 0x1F76, 0x1F77, 0x1FDA },
93+ { 0x1F78, 0x1F79, 0x1FF8 },
94+ { 0x1F7A, 0x1F7B, 0x1FEA },
95+ { 0x1F7C, 0x1F7D, 0x1FFA },
96+ { 0x1F80, 0x1F87, 0x1F88 },
97+ { 0x1F90, 0x1F97, 0x1F98 },
98+ { 0x1FA0, 0x1FA7, 0x1FA8 },
99+ { 0x1FB0, 0x1FB1, 0x1FB8 },
100+ { 0x1FB6, 0x1FB7, 0x1FB6 },
101+ { 0x1FC6, 0x1FC7, 0x1FC6 },
102+ { 0x1FD0, 0x1FD1, 0x1FD8 },
103+ { 0x1FD2, 0x1FD3, 0x1FD2 },
104+ { 0x1FD6, 0x1FD7, 0x1FD6 },
105+ { 0x1FE0, 0x1FE1, 0x1FE8 },
106+ { 0x1FE2, 0x1FE4, 0x1FE2 },
107+ { 0x1FE6, 0x1FE7, 0x1FE6 },
108+ { 0x1FF6, 0x1FF7, 0x1FF6 },
109+ { 0x210E, 0x210F, 0x210E },
110+ { 0x213C, 0x213D, 0x213C },
111+ { 0x2146, 0x2149, 0x2146 },
112+ { 0x2C30, 0x2C5F, 0x2C00 },
113+ { 0x2C77, 0x2C7B, 0x2C77 },
114+ { 0x2D00, 0x2D25, 0x10A0 },
115+ { 0xA730, 0xA731, 0xA730 },
116+ { 0xA771, 0xA778, 0xA771 },
117+ { 0xAB30, 0xAB52, 0xAB30 },
118+ { 0xAB54, 0xAB5A, 0xAB54 },
119+ { 0xAB60, 0xAB68, 0xAB60 },
120+ { 0xAB70, 0xABBF, 0x13A0 },
121+ { 0xFB00, 0xFB06, 0xFB00 },
122+ { 0xFB13, 0xFB17, 0xFB13 },
123+ { 0xFF41, 0xFF5A, 0xFF21 },
124+ { 0x10428, 0x1044F, 0x10400 },
125+ { 0x104D8, 0x104FB, 0x104B0 },
126+ { 0x10597, 0x105A1, 0x10570 },
127+ { 0x105A3, 0x105B1, 0x1057C },
128+ { 0x105B3, 0x105B9, 0x1058C },
129+ { 0x105BB, 0x105BC, 0x10594 },
130+ { 0x10CC0, 0x10CF2, 0x10C80 },
131+ { 0x118C0, 0x118DF, 0x118A0 },
132+ { 0x16E60, 0x16E7F, 0x16E40 },
133+ { 0x1D41A, 0x1D433, 0x1D41A },
134+ { 0x1D44E, 0x1D454, 0x1D44E },
135+ { 0x1D456, 0x1D467, 0x1D456 },
136+ { 0x1D482, 0x1D49B, 0x1D482 },
137+ { 0x1D4B6, 0x1D4B9, 0x1D4B6 },
138+ { 0x1D4BD, 0x1D4C3, 0x1D4BD },
139+ { 0x1D4C5, 0x1D4CF, 0x1D4C5 },
140+ { 0x1D4EA, 0x1D503, 0x1D4EA },
141+ { 0x1D51E, 0x1D537, 0x1D51E },
142+ { 0x1D552, 0x1D56B, 0x1D552 },
143+ { 0x1D586, 0x1D59F, 0x1D586 },
144+ { 0x1D5BA, 0x1D5D3, 0x1D5BA },
145+ { 0x1D5EE, 0x1D607, 0x1D5EE },
146+ { 0x1D622, 0x1D63B, 0x1D622 },
147+ { 0x1D656, 0x1D66F, 0x1D656 },
148+ { 0x1D68A, 0x1D6A5, 0x1D68A },
149+ { 0x1D6C2, 0x1D6DA, 0x1D6C2 },
150+ { 0x1D6DC, 0x1D6E1, 0x1D6DC },
151+ { 0x1D6FC, 0x1D714, 0x1D6FC },
152+ { 0x1D716, 0x1D71B, 0x1D716 },
153+ { 0x1D736, 0x1D74E, 0x1D736 },
154+ { 0x1D750, 0x1D755, 0x1D750 },
155+ { 0x1D770, 0x1D788, 0x1D770 },
156+ { 0x1D78A, 0x1D78F, 0x1D78A },
157+ { 0x1D7AA, 0x1D7C2, 0x1D7AA },
158+ { 0x1D7C4, 0x1D7C9, 0x1D7C4 },
159+ { 0x1DF00, 0x1DF09, 0x1DF00 },
160+ { 0x1DF0B, 0x1DF1E, 0x1DF0B },
161+ { 0x1DF25, 0x1DF2A, 0x1DF25 },
162+ { 0x1E922, 0x1E943, 0x1E900 },
163+};
164+
165+static const Rune lower1[][2] = {
166+ { 0x00B5, 0x039C },
167+ { 0x00DF, 0x00DF },
168+ { 0x00FF, 0x0178 },
169+ { 0x0131, 0x0049 },
170+ { 0x0138, 0x0138 },
171+ { 0x0149, 0x0149 },
172+ { 0x017F, 0x0053 },
173+ { 0x0180, 0x0243 },
174+ { 0x0188, 0x0187 },
175+ { 0x018C, 0x018B },
176+ { 0x018D, 0x018D },
177+ { 0x0192, 0x0191 },
178+ { 0x0195, 0x01F6 },
179+ { 0x0199, 0x0198 },
180+ { 0x019A, 0x023D },
181+ { 0x019B, 0x019B },
182+ { 0x019E, 0x0220 },
183+ { 0x01A8, 0x01A7 },
184+ { 0x01AD, 0x01AC },
185+ { 0x01B0, 0x01AF },
186+ { 0x01B9, 0x01B8 },
187+ { 0x01BA, 0x01BA },
188+ { 0x01BD, 0x01BC },
189+ { 0x01BE, 0x01BE },
190+ { 0x01BF, 0x01F7 },
191+ { 0x01C6, 0x01C4 },
192+ { 0x01C9, 0x01C7 },
193+ { 0x01CC, 0x01CA },
194+ { 0x01DD, 0x018E },
195+ { 0x01F0, 0x01F0 },
196+ { 0x01F3, 0x01F1 },
197+ { 0x01F5, 0x01F4 },
198+ { 0x0221, 0x0221 },
199+ { 0x023C, 0x023B },
200+ { 0x0242, 0x0241 },
201+ { 0x0250, 0x2C6F },
202+ { 0x0251, 0x2C6D },
203+ { 0x0252, 0x2C70 },
204+ { 0x0253, 0x0181 },
205+ { 0x0254, 0x0186 },
206+ { 0x0255, 0x0255 },
207+ { 0x0258, 0x0258 },
208+ { 0x0259, 0x018F },
209+ { 0x025A, 0x025A },
210+ { 0x025B, 0x0190 },
211+ { 0x025C, 0xA7AB },
212+ { 0x0260, 0x0193 },
213+ { 0x0261, 0xA7AC },
214+ { 0x0262, 0x0262 },
215+ { 0x0263, 0x0194 },
216+ { 0x0264, 0x0264 },
217+ { 0x0265, 0xA78D },
218+ { 0x0266, 0xA7AA },
219+ { 0x0267, 0x0267 },
220+ { 0x0268, 0x0197 },
221+ { 0x0269, 0x0196 },
222+ { 0x026A, 0xA7AE },
223+ { 0x026B, 0x2C62 },
224+ { 0x026C, 0xA7AD },
225+ { 0x026F, 0x019C },
226+ { 0x0270, 0x0270 },
227+ { 0x0271, 0x2C6E },
228+ { 0x0272, 0x019D },
229+ { 0x0275, 0x019F },
230+ { 0x027D, 0x2C64 },
231+ { 0x0280, 0x01A6 },
232+ { 0x0281, 0x0281 },
233+ { 0x0282, 0xA7C5 },
234+ { 0x0283, 0x01A9 },
235+ { 0x0287, 0xA7B1 },
236+ { 0x0288, 0x01AE },
237+ { 0x0289, 0x0244 },
238+ { 0x028C, 0x0245 },
239+ { 0x0292, 0x01B7 },
240+ { 0x0293, 0x0293 },
241+ { 0x029D, 0xA7B2 },
242+ { 0x029E, 0xA7B0 },
243+ { 0x0377, 0x0376 },
244+ { 0x0390, 0x0390 },
245+ { 0x03AC, 0x0386 },
246+ { 0x03B0, 0x03B0 },
247+ { 0x03C2, 0x03A3 },
248+ { 0x03CC, 0x038C },
249+ { 0x03D0, 0x0392 },
250+ { 0x03D1, 0x0398 },
251+ { 0x03D5, 0x03A6 },
252+ { 0x03D6, 0x03A0 },
253+ { 0x03D7, 0x03CF },
254+ { 0x03F0, 0x039A },
255+ { 0x03F1, 0x03A1 },
256+ { 0x03F2, 0x03F9 },
257+ { 0x03F3, 0x037F },
258+ { 0x03F5, 0x0395 },
259+ { 0x03F8, 0x03F7 },
260+ { 0x03FB, 0x03FA },
261+ { 0x03FC, 0x03FC },
262+ { 0x04CF, 0x04C0 },
263+ { 0x0560, 0x0560 },
264+ { 0x1C80, 0x0412 },
265+ { 0x1C81, 0x0414 },
266+ { 0x1C82, 0x041E },
267+ { 0x1C85, 0x0422 },
268+ { 0x1C86, 0x042A },
269+ { 0x1C87, 0x0462 },
270+ { 0x1C88, 0xA64A },
271+ { 0x1D79, 0xA77D },
272+ { 0x1D7D, 0x2C63 },
273+ { 0x1D8E, 0xA7C6 },
274+ { 0x1E9B, 0x1E60 },
275+ { 0x1E9F, 0x1E9F },
276+ { 0x1F50, 0x1F50 },
277+ { 0x1F51, 0x1F59 },
278+ { 0x1F52, 0x1F52 },
279+ { 0x1F53, 0x1F5B },
280+ { 0x1F54, 0x1F54 },
281+ { 0x1F55, 0x1F5D },
282+ { 0x1F56, 0x1F56 },
283+ { 0x1F57, 0x1F5F },
284+ { 0x1FB2, 0x1FB2 },
285+ { 0x1FB3, 0x1FBC },
286+ { 0x1FB4, 0x1FB4 },
287+ { 0x1FBE, 0x0399 },
288+ { 0x1FC2, 0x1FC2 },
289+ { 0x1FC3, 0x1FCC },
290+ { 0x1FC4, 0x1FC4 },
291+ { 0x1FE5, 0x1FEC },
292+ { 0x1FF2, 0x1FF2 },
293+ { 0x1FF3, 0x1FFC },
294+ { 0x1FF4, 0x1FF4 },
295+ { 0x210A, 0x210A },
296+ { 0x2113, 0x2113 },
297+ { 0x212F, 0x212F },
298+ { 0x2134, 0x2134 },
299+ { 0x2139, 0x2139 },
300+ { 0x214E, 0x2132 },
301+ { 0x2184, 0x2183 },
302+ { 0x2C61, 0x2C60 },
303+ { 0x2C65, 0x023A },
304+ { 0x2C66, 0x023E },
305+ { 0x2C71, 0x2C71 },
306+ { 0x2C73, 0x2C72 },
307+ { 0x2C74, 0x2C74 },
308+ { 0x2C76, 0x2C75 },
309+ { 0x2CE4, 0x2CE4 },
310+ { 0x2CF3, 0x2CF2 },
311+ { 0x2D27, 0x10C7 },
312+ { 0x2D2D, 0x10CD },
313+ { 0xA78C, 0xA78B },
314+ { 0xA78E, 0xA78E },
315+ { 0xA794, 0xA7C4 },
316+ { 0xA795, 0xA795 },
317+ { 0xA7AF, 0xA7AF },
318+ { 0xA7D1, 0xA7D0 },
319+ { 0xA7D3, 0xA7D3 },
320+ { 0xA7D5, 0xA7D5 },
321+ { 0xA7F6, 0xA7F5 },
322+ { 0xA7FA, 0xA7FA },
323+ { 0xAB53, 0xA7B3 },
324+ { 0x1D4BB, 0x1D4BB },
325+ { 0x1D7CB, 0x1D7CB },
326+};
327+
328+int
329+islowerrune(Rune r)
330+{
331+ const Rune *match;
332+
333+ if((match = bsearch(&r, lower4, nelem(lower4), sizeof *lower4, &rune2cmp)))
334+ return !((r - match[0]) % 2);
335+ if(bsearch(&r, lower2, nelem(lower2), sizeof *lower2, &rune2cmp))
336+ return 1;
337+ if(bsearch(&r, lower1, nelem(lower1), sizeof *lower1, &rune1cmp))
338+ return 1;
339+ return 0;
340+}
341+
342+int
343+toupperrune(Rune r)
344+{
345+ Rune *match;
346+
347+ match = bsearch(&r, lower4, nelem(lower4), sizeof *lower4, &rune2cmp);
348+ if (match)
349+ return ((r - match[0]) % 2) ? r : r - 1;
350+ match = bsearch(&r, lower2, nelem(lower2), sizeof *lower2, &rune2cmp);
351+ if (match)
352+ return match[2] + (r - match[0]);
353+ match = bsearch(&r, lower1, nelem(lower1), sizeof *lower1, &rune1cmp);
354+ if (match)
355+ return match[1];
356+ return r;
357+}
1@@ -0,0 +1,240 @@
2+# See LICENSE file for copyright and license details.
3+
4+BEGIN {
5+ FS = ";"
6+ # set up hexadecimal lookup table
7+ for(i = 0; i < 16; i++)
8+ hex[sprintf("%X",i)] = i;
9+ HEADER = "/* Automatically generated by mkrunetype.awk */\n#include <stdlib.h>\n\n#include \"../utf.h\"\n#include \"runetype.h\"\n"
10+ HEADER_OTHER = "/* Automatically generated by mkrunetype.awk */\n#include \"../utf.h\"\n#include \"runetype.h\"\n"
11+}
12+
13+$3 ~ /^L/ { alphav[alphac++] = $1; }
14+($3 ~ /^Z/) || ($5 == "WS") || ($5 == "S") || ($5 == "B") { spacev[spacec++] = $1; }
15+$3 == "Cc" { cntrlv[cntrlc++] = $1; }
16+$3 == "Lu" { upperv[upperc++] = $1; tolowerv[uppercc++] = ($14 == "") ? $1 : $14; }
17+$3 == "Ll" { lowerv[lowerc++] = $1; toupperv[lowercc++] = ($13 == "") ? $1 : $13; }
18+$3 == "Lt" { titlev[titlec++] = $1; }
19+$3 == "Nd" { digitv[digitc++] = $1; }
20+
21+END {
22+ system("rm -f isalpharune.c isspacerune.c iscntrlrune.c upperrune.c lowerrune.c istitlerune.c isdigitrune.c");
23+
24+ mkis("alpha", alphav, alphac, "isalpharune.c", q, "");
25+ mkis("space", spacev, spacec, "isspacerune.c", q, "");
26+ mkis("cntrl", cntrlv, cntrlc, "iscntrlrune.c", q, "");
27+ mkis("upper", upperv, upperc, "upperrune.c", tolowerv, "lower");
28+ mkis("lower", lowerv, lowerc, "lowerrune.c", toupperv, "upper");
29+ mkis("title", titlev, titlec, "istitlerune.c", q, "");
30+ mkis("digit", digitv, digitc, "isdigitrune.c", q, "");
31+
32+ system("rm -f isalnumrune.c isblankrune.c isprintrune.c isgraphrune.c ispunctrune.c isxdigitrune.c");
33+
34+ otheris();
35+}
36+
37+# parse hexadecimal rune index to int
38+function code(s) {
39+ x = 0;
40+ for(i = 1; i <= length(s); i++) {
41+ c = substr(s, i, 1);
42+ x = (x*16) + hex[c];
43+ }
44+ return x;
45+}
46+
47+# generate 'is<name>rune' unicode lookup function
48+function mkis(name, runev, runec, file, casev, casename) {
49+ rune1c = 0;
50+ rune2c = 0;
51+ rune3c = 0;
52+ rune4c = 0;
53+ mode = 1;
54+
55+ #sort rune groups into singletons, ranges and laces
56+ for(j = 0; j < runec; j++) {
57+ # range
58+ if(code(runev[j+1]) == code(runev[j])+1 && ((length(casev) == 0) ||
59+ code(casev[j+1]) == code(casev[j])+1) && j+1 < runec) {
60+ if (mode == 2) {
61+ continue;
62+ } else if (mode == 3) {
63+ rune3v1[rune3c] = runev[j];
64+ rune3c++;
65+ } else if (mode == 4) {
66+ rune4v1[rune4c] = runev[j];
67+ rune4c++;
68+ }
69+ mode = 2;
70+ rune2v0[rune2c] = runev[j];
71+ if(length(casev) > 0) {
72+ case2v[rune2c] = casev[j];
73+ }
74+ continue;
75+ }
76+ # lace 1
77+ if(code(runev[j+1]) == code(runev[j])+2 && ((length(casev) == 0) ||
78+ (code(casev[j+1]) == code(runev[j+1])+1 && code(casev[j]) == code(runev[j])+1)) &&
79+ j+1 < runec) {
80+ if (mode == 3) {
81+ continue;
82+ } else if (mode == 2) {
83+ rune2v1[rune2c] = runev[j];
84+ rune2c++;
85+ } else if (mode == 4) {
86+ rune4v1[rune2c] = runev[j];
87+ rune4c++;
88+ }
89+ mode = 3;
90+ rune3v0[rune3c] = runev[j];
91+ continue;
92+ }
93+ # lace 2
94+ if(code(runev[j+1]) == code(runev[j])+2 && ((length(casev) == 0) ||
95+ (code(casev[j+1]) == code(runev[j+1])-1 && code(casev[j]) == code(runev[j])-1)) &&
96+ j+1 < runec) {
97+ if (mode == 4) {
98+ continue;
99+ } else if (mode == 2) {
100+ rune2v1[rune2c] = runev[j];
101+ rune2c++;
102+ } else if (mode == 3) {
103+ rune3v1[rune2c] = runev[j];
104+ rune3c++;
105+ }
106+ mode = 4;
107+ rune4v0[rune4c] = runev[j];
108+ continue;
109+ }
110+ # terminating case
111+ if (mode == 1) {
112+ rune1v[rune1c] = runev[j];
113+ if (length(casev) > 0) {
114+ case1v[rune1c] = casev[j];
115+ }
116+ rune1c++;
117+ } else if (mode == 2) {
118+ rune2v1[rune2c] = runev[j];
119+ rune2c++;
120+ } else if (mode == 3) {
121+ rune3v1[rune3c] = runev[j];
122+ rune3c++;
123+ } else { #lace 2
124+ rune4v1[rune4c] = runev[j];
125+ rune4c++;
126+ }
127+ mode = 1;
128+ }
129+ print HEADER > file;
130+
131+ #generate list of laces 1
132+ if(rune3c > 0) {
133+ print "static const Rune "name"3[][2] = {" > file;
134+ for(j = 0; j < rune3c; j++) {
135+ print "\t{ 0x"rune3v0[j]", 0x"rune3v1[j]" }," > file;
136+ }
137+ print "};\n" > file;
138+ }
139+
140+ #generate list of laces 2
141+ if(rune4c > 0) {
142+ print "static const Rune "name"4[][2] = {" > file;
143+ for(j = 0; j < rune4c; j++) {
144+ print "\t{ 0x"rune4v0[j]", 0x"rune4v1[j]" }," > file;
145+ }
146+ print "};\n" > file;
147+ }
148+
149+ # generate list of ranges
150+ if(rune2c > 0) {
151+ if(length(casev) > 0) {
152+ print "static const Rune "name"2[][3] = {" > file;
153+ for(j = 0; j < rune2c; j++) {
154+ print "\t{ 0x"rune2v0[j]", 0x"rune2v1[j]", 0x"case2v[j]" }," > file;
155+ }
156+ } else {
157+ print "static const Rune "name"2[][2] = {" > file
158+ for(j = 0; j < rune2c; j++) {
159+ print "\t{ 0x"rune2v0[j]", 0x"rune2v1[j]" }," > file;
160+ }
161+ }
162+ print "};\n" > file;
163+ }
164+
165+ # generate list of singletons
166+ if(rune1c > 0) {
167+ if(length(casev) > 0) {
168+ print "static const Rune "name"1[][2] = {" > file;
169+ for(j = 0; j < rune1c; j++) {
170+ print "\t{ 0x"rune1v[j]", 0x"case1v[j]" }," > file;
171+ }
172+ } else {
173+ print "static const Rune "name"1[] = {" > file;
174+ for(j = 0; j < rune1c; j++) {
175+ print "\t0x"rune1v[j]"," > file;
176+ }
177+ }
178+ print "};\n" > file;
179+ }
180+ # generate lookup function
181+ print "int\nis"name"rune(Rune r)\n{" > file;
182+ if(rune4c > 0 || rune3c > 0)
183+ print "\tconst Rune *match;\n" > file;
184+ if(rune4c > 0) {
185+ print "\tif((match = bsearch(&r, "name"4, nelem("name"4), sizeof *"name"4, &rune2cmp)))" > file;
186+ print "\t\treturn !((r - match[0]) % 2);" > file;
187+ }
188+ if(rune3c > 0) {
189+ print "\tif((match = bsearch(&r, "name"3, nelem("name"3), sizeof *"name"3, &rune2cmp)))" > file;
190+ print "\t\treturn !((r - match[0]) % 2);" > file;
191+ }
192+ if(rune2c > 0) {
193+ print "\tif(bsearch(&r, "name"2, nelem("name"2), sizeof *"name"2, &rune2cmp))\n\t\treturn 1;" > file;
194+ }
195+ if(rune1c > 0) {
196+ print "\tif(bsearch(&r, "name"1, nelem("name"1), sizeof *"name"1, &rune1cmp))\n\t\treturn 1;" > file;
197+ }
198+ print "\treturn 0;\n}" > file;
199+
200+ # generate case conversion function
201+ if(length(casev) > 0) {
202+ print "\nint\nto"casename"rune(Rune r)\n{\n\tRune *match;\n" > file;
203+ if(rune4c > 0) {
204+ print "\tmatch = bsearch(&r, "name"4, nelem("name"4), sizeof *"name"4, &rune2cmp);" > file;
205+ print "\tif (match)" > file;
206+ print "\t\treturn ((r - match[0]) % 2) ? r : r - 1;" > file;
207+ }
208+ if(rune3c > 0) {
209+ print "\tmatch = bsearch(&r, "name"3, nelem("name"3), sizeof *"name"3, &rune2cmp);" > file;
210+ print "\tif (match)" > file;
211+ print "\t\treturn ((r - match[0]) % 2) ? r : r + 1;" > file;
212+ }
213+ if(rune2c > 0) {
214+ print "\tmatch = bsearch(&r, "name"2, nelem("name"2), sizeof *"name"2, &rune2cmp);" > file;
215+ print "\tif (match)" > file;
216+ print "\t\treturn match[2] + (r - match[0]);" > file;
217+ }
218+ if(rune1c > 0) {
219+ print "\tmatch = bsearch(&r, "name"1, nelem("name"1), sizeof *"name"1, &rune1cmp);" > file;
220+ print "\tif (match)" > file;
221+ print "\t\treturn match[1];" > file;
222+ }
223+ print "\treturn r;\n}" > file;
224+ }
225+}
226+
227+function otheris() {
228+ print HEADER_OTHER > "isalnumrune.c";
229+ print "int\nisalnumrune(Rune r)\n{\n\treturn isalpharune(r) || isdigitrune(r);\n}" > "isalnumrune.c";
230+ print HEADER_OTHER > "isblankrune.c";
231+ print "int\nisblankrune(Rune r)\n{\n\treturn r == ' ' || r == '\\t';\n}" > "isblankrune.c";
232+ print HEADER_OTHER > "isprintrune.c";
233+ print "int\nisprintrune(Rune r)\n{\n\treturn !iscntrlrune(r) && (r != 0x2028) && (r != 0x2029) &&" > "isprintrune.c";
234+ print "\t ((r < 0xFFF9) || (r > 0xFFFB));\n}" > "isprintrune.c";
235+ print HEADER_OTHER > "isgraphrune.c";
236+ print "int\nisgraphrune(Rune r)\n{\n\treturn !isspacerune(r) && isprintrune(r);\n}" > "isgraphrune.c";
237+ print HEADER_OTHER > "ispunctrune.c";
238+ print "int\nispunctrune(Rune r)\n{\n\treturn isgraphrune(r) && !isalnumrune(r);\n}" > "ispunctrune.c";
239+ print HEADER_OTHER > "isxdigitrune.c";
240+ print "int\nisxdigitrune(Rune r)\n{\n\treturn (r >= '0' && (r - '0') < 10) || (r >= 'a' && (r - 'a') < 6);\n}" > "isxdigitrune.c";
241+}
1@@ -0,0 +1,148 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a
5+ * copy of this software and associated documentation files (the "Software"),
6+ * to deal in the Software without restriction, including without limitation
7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+ * and/or sell copies of the Software, and to permit persons to whom the
9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+ * DEALINGS IN THE SOFTWARE.
21+ */
22+#include "../utf.h"
23+
24+#define MIN(x,y) ((x) < (y) ? (x) : (y))
25+
26+#define UTFSEQ(x) ((((x) & 0x80) == 0x00) ? 1 /* 0xxxxxxx */ \
27+ : (((x) & 0xC0) == 0x80) ? 0 /* 10xxxxxx */ \
28+ : (((x) & 0xE0) == 0xC0) ? 2 /* 110xxxxx */ \
29+ : (((x) & 0xF0) == 0xE0) ? 3 /* 1110xxxx */ \
30+ : (((x) & 0xF8) == 0xF0) ? 4 /* 11110xxx */ \
31+ : (((x) & 0xFC) == 0xF8) ? 5 /* 111110xx */ \
32+ : (((x) & 0xFE) == 0xFC) ? 6 /* 1111110x */ \
33+ : 0 )
34+
35+#define BADRUNE(x) ((x) < 0 || (x) > Runemax \
36+ || ((x) & 0xFFFE) == 0xFFFE \
37+ || ((x) >= 0xD800 && (x) <= 0xDFFF) \
38+ || ((x) >= 0xFDD0 && (x) <= 0xFDEF))
39+
40+int
41+runetochar(char *s, const Rune *p)
42+{
43+ Rune r = *p;
44+
45+ switch(runelen(r)) {
46+ case 1: /* 0aaaaaaa */
47+ s[0] = r;
48+ return 1;
49+ case 2: /* 00000aaa aabbbbbb */
50+ s[0] = 0xC0 | ((r & 0x0007C0) >> 6); /* 110aaaaa */
51+ s[1] = 0x80 | (r & 0x00003F); /* 10bbbbbb */
52+ return 2;
53+ case 3: /* aaaabbbb bbcccccc */
54+ s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
55+ s[1] = 0x80 | ((r & 0x000FC0) >> 6); /* 10bbbbbb */
56+ s[2] = 0x80 | (r & 0x00003F); /* 10cccccc */
57+ return 3;
58+ case 4: /* 000aaabb bbbbcccc ccdddddd */
59+ s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
60+ s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
61+ s[2] = 0x80 | ((r & 0x000FC0) >> 6); /* 10cccccc */
62+ s[3] = 0x80 | (r & 0x00003F); /* 10dddddd */
63+ return 4;
64+ default:
65+ return 0; /* error */
66+ }
67+}
68+
69+int
70+chartorune(Rune *p, const char *s)
71+{
72+ return charntorune(p, s, UTFmax);
73+}
74+
75+int
76+charntorune(Rune *p, const char *s, size_t len)
77+{
78+ unsigned int i, n;
79+ Rune r;
80+
81+ if(len == 0) /* can't even look at s[0] */
82+ return 0;
83+
84+ switch((n = UTFSEQ(s[0]))) {
85+ case 1: r = s[0]; break; /* 0xxxxxxx */
86+ case 2: r = s[0] & 0x1F; break; /* 110xxxxx */
87+ case 3: r = s[0] & 0x0F; break; /* 1110xxxx */
88+ case 4: r = s[0] & 0x07; break; /* 11110xxx */
89+ case 5: r = s[0] & 0x03; break; /* 111110xx */
90+ case 6: r = s[0] & 0x01; break; /* 1111110x */
91+ default: /* invalid sequence */
92+ *p = Runeerror;
93+ return 1;
94+ }
95+ /* add values from continuation bytes */
96+ for(i = 1; i < MIN(n, len); i++)
97+ if((s[i] & 0xC0) == 0x80) {
98+ /* add bits from continuation byte to rune value
99+ * cannot overflow: 6 byte sequences contain 31 bits */
100+ r = (r << 6) | (s[i] & 0x3F); /* 10xxxxxx */
101+ }
102+ else { /* expected continuation */
103+ *p = Runeerror;
104+ return i;
105+ }
106+
107+ if(i < n) /* must have reached len limit */
108+ return 0;
109+
110+ /* reject invalid or overlong sequences */
111+ if(BADRUNE(r) || runelen(r) < (int)n)
112+ r = Runeerror;
113+
114+ *p = r;
115+ return n;
116+}
117+
118+int
119+runelen(Rune r)
120+{
121+ if(BADRUNE(r))
122+ return 0; /* error */
123+ else if(r <= 0x7F)
124+ return 1;
125+ else if(r <= 0x07FF)
126+ return 2;
127+ else if(r <= 0xFFFF)
128+ return 3;
129+ else
130+ return 4;
131+}
132+
133+size_t
134+runenlen(const Rune *p, size_t len)
135+{
136+ size_t i, n = 0;
137+
138+ for(i = 0; i < len; i++)
139+ n += runelen(p[i]);
140+ return n;
141+}
142+
143+int
144+fullrune(const char *s, size_t len)
145+{
146+ Rune r;
147+
148+ return charntorune(&r, s, len) > 0;
149+}
1@@ -0,0 +1,41 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ * (c) 2015 Laslo Hunhold <dev@frign.de>
4+ *
5+ * Permission is hereby granted, free of charge, to any person obtaining a
6+ * copy of this software and associated documentation files (the "Software"),
7+ * to deal in the Software without restriction, including without limitation
8+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9+ * and/or sell copies of the Software, and to permit persons to whom the
10+ * Software is furnished to do so, subject to the following conditions:
11+ *
12+ * The above copyright notice and this permission notice shall be included in
13+ * all copies or substantial portions of the Software.
14+ *
15+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+ * DEALINGS IN THE SOFTWARE.
22+ */
23+#include "../utf.h"
24+
25+int
26+rune1cmp(const void *v1, const void *v2)
27+{
28+ Rune r1 = *(Rune *)v1, r2 = *(Rune *)v2;
29+
30+ return r1 - r2;
31+}
32+
33+int
34+rune2cmp(const void *v1, const void *v2)
35+{
36+ Rune r = *(Rune *)v1, *p = (Rune *)v2;
37+
38+ if(r >= p[0] && r <= p[1])
39+ return 0;
40+ else
41+ return r - p[0];
42+}
1@@ -0,0 +1,26 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ * (c) 2015 Laslo Hunhold <dev@frign.de>
4+ *
5+ * Permission is hereby granted, free of charge, to any person obtaining a
6+ * copy of this software and associated documentation files (the "Software"),
7+ * to deal in the Software without restriction, including without limitation
8+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9+ * and/or sell copies of the Software, and to permit persons to whom the
10+ * Software is furnished to do so, subject to the following conditions:
11+ *
12+ * The above copyright notice and this permission notice shall be included in
13+ * all copies or substantial portions of the Software.
14+ *
15+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+ * DEALINGS IN THE SOFTWARE.
22+ */
23+
24+#define nelem(x) (sizeof (x) / sizeof *(x))
25+
26+int rune1cmp(const void *, const void *);
27+int rune2cmp(const void *, const void *);
1@@ -0,0 +1,265 @@
2+/* Automatically generated by mkrunetype.awk */
3+#include <stdlib.h>
4+
5+#include "../utf.h"
6+#include "runetype.h"
7+
8+static const Rune upper3[][2] = {
9+ { 0x0100, 0x012E },
10+ { 0x0132, 0x0136 },
11+ { 0x0139, 0x0147 },
12+ { 0x014A, 0x0176 },
13+ { 0x0179, 0x017D },
14+ { 0x0182, 0x0184 },
15+ { 0x01A0, 0x01A4 },
16+ { 0x01B3, 0x01B5 },
17+ { 0x01CD, 0x01DB },
18+ { 0x01DE, 0x01EE },
19+ { 0x01F8, 0x021E },
20+ { 0x0222, 0x0232 },
21+ { 0x0246, 0x024E },
22+ { 0x0370, 0x0372 },
23+ { 0x03D8, 0x03EE },
24+ { 0x0460, 0x0480 },
25+ { 0x048A, 0x04BE },
26+ { 0x04C1, 0x04CD },
27+ { 0x04D0, 0x052E },
28+ { 0x1E00, 0x1E94 },
29+ { 0x1EA0, 0x1EFE },
30+ { 0x2C67, 0x2C6B },
31+ { 0x2C80, 0x2CE2 },
32+ { 0x2CEB, 0x2CED },
33+ { 0xA640, 0xA66C },
34+ { 0xA680, 0xA69A },
35+ { 0xA722, 0xA72E },
36+ { 0xA732, 0xA76E },
37+ { 0xA779, 0xA77B },
38+ { 0xA77E, 0xA786 },
39+ { 0xA790, 0xA792 },
40+ { 0xA796, 0xA7A8 },
41+ { 0xA7B4, 0xA7C2 },
42+ { 0xA7C7, 0xA7C9 },
43+ { 0xA7D6, 0xA7D8 },
44+};
45+
46+static const Rune upper2[][3] = {
47+ { 0x0041, 0x005A, 0x0061 },
48+ { 0x00C0, 0x00D6, 0x00E0 },
49+ { 0x00D8, 0x00DE, 0x00F8 },
50+ { 0x0189, 0x018A, 0x0256 },
51+ { 0x01B1, 0x01B2, 0x028A },
52+ { 0x0388, 0x038A, 0x03AD },
53+ { 0x038E, 0x038F, 0x03CD },
54+ { 0x0391, 0x03A1, 0x03B1 },
55+ { 0x03A3, 0x03AB, 0x03C3 },
56+ { 0x03D2, 0x03D4, 0x03D2 },
57+ { 0x03FD, 0x03FF, 0x037B },
58+ { 0x0400, 0x040F, 0x0450 },
59+ { 0x0410, 0x042F, 0x0430 },
60+ { 0x0531, 0x0556, 0x0561 },
61+ { 0x10A0, 0x10C5, 0x2D00 },
62+ { 0x13A0, 0x13EF, 0xAB70 },
63+ { 0x13F0, 0x13F5, 0x13F8 },
64+ { 0x1C90, 0x1CBA, 0x10D0 },
65+ { 0x1CBD, 0x1CBF, 0x10FD },
66+ { 0x1F08, 0x1F0F, 0x1F00 },
67+ { 0x1F18, 0x1F1D, 0x1F10 },
68+ { 0x1F28, 0x1F2F, 0x1F20 },
69+ { 0x1F38, 0x1F3F, 0x1F30 },
70+ { 0x1F48, 0x1F4D, 0x1F40 },
71+ { 0x1F68, 0x1F6F, 0x1F60 },
72+ { 0x1FB8, 0x1FB9, 0x1FB0 },
73+ { 0x1FBA, 0x1FBB, 0x1F70 },
74+ { 0x1FC8, 0x1FCB, 0x1F72 },
75+ { 0x1FD8, 0x1FD9, 0x1FD0 },
76+ { 0x1FDA, 0x1FDB, 0x1F76 },
77+ { 0x1FE8, 0x1FE9, 0x1FE0 },
78+ { 0x1FEA, 0x1FEB, 0x1F7A },
79+ { 0x1FF8, 0x1FF9, 0x1F78 },
80+ { 0x1FFA, 0x1FFB, 0x1F7C },
81+ { 0x210B, 0x210D, 0x210B },
82+ { 0x2110, 0x2112, 0x2110 },
83+ { 0x2119, 0x211D, 0x2119 },
84+ { 0x212C, 0x212D, 0x212C },
85+ { 0x2130, 0x2131, 0x2130 },
86+ { 0x213E, 0x213F, 0x213E },
87+ { 0x2C00, 0x2C2F, 0x2C30 },
88+ { 0x2C7E, 0x2C7F, 0x023F },
89+ { 0xFF21, 0xFF3A, 0xFF41 },
90+ { 0x10400, 0x10427, 0x10428 },
91+ { 0x104B0, 0x104D3, 0x104D8 },
92+ { 0x10570, 0x1057A, 0x10597 },
93+ { 0x1057C, 0x1058A, 0x105A3 },
94+ { 0x1058C, 0x10592, 0x105B3 },
95+ { 0x10594, 0x10595, 0x105BB },
96+ { 0x10C80, 0x10CB2, 0x10CC0 },
97+ { 0x118A0, 0x118BF, 0x118C0 },
98+ { 0x16E40, 0x16E5F, 0x16E60 },
99+ { 0x1D400, 0x1D419, 0x1D400 },
100+ { 0x1D434, 0x1D44D, 0x1D434 },
101+ { 0x1D468, 0x1D481, 0x1D468 },
102+ { 0x1D49E, 0x1D49F, 0x1D49E },
103+ { 0x1D4A5, 0x1D4A6, 0x1D4A5 },
104+ { 0x1D4A9, 0x1D4AC, 0x1D4A9 },
105+ { 0x1D4AE, 0x1D4B5, 0x1D4AE },
106+ { 0x1D4D0, 0x1D4E9, 0x1D4D0 },
107+ { 0x1D504, 0x1D505, 0x1D504 },
108+ { 0x1D507, 0x1D50A, 0x1D507 },
109+ { 0x1D50D, 0x1D514, 0x1D50D },
110+ { 0x1D516, 0x1D51C, 0x1D516 },
111+ { 0x1D538, 0x1D539, 0x1D538 },
112+ { 0x1D53B, 0x1D53E, 0x1D53B },
113+ { 0x1D540, 0x1D544, 0x1D540 },
114+ { 0x1D54A, 0x1D550, 0x1D54A },
115+ { 0x1D56C, 0x1D585, 0x1D56C },
116+ { 0x1D5A0, 0x1D5B9, 0x1D5A0 },
117+ { 0x1D5D4, 0x1D5ED, 0x1D5D4 },
118+ { 0x1D608, 0x1D621, 0x1D608 },
119+ { 0x1D63C, 0x1D655, 0x1D63C },
120+ { 0x1D670, 0x1D689, 0x1D670 },
121+ { 0x1D6A8, 0x1D6C0, 0x1D6A8 },
122+ { 0x1D6E2, 0x1D6FA, 0x1D6E2 },
123+ { 0x1D71C, 0x1D734, 0x1D71C },
124+ { 0x1D756, 0x1D76E, 0x1D756 },
125+ { 0x1D790, 0x1D7A8, 0x1D790 },
126+ { 0x1E900, 0x1E921, 0x1E922 },
127+};
128+
129+static const Rune upper1[][2] = {
130+ { 0x0130, 0x0069 },
131+ { 0x0178, 0x00FF },
132+ { 0x0181, 0x0253 },
133+ { 0x0186, 0x0254 },
134+ { 0x0187, 0x0188 },
135+ { 0x018B, 0x018C },
136+ { 0x018E, 0x01DD },
137+ { 0x018F, 0x0259 },
138+ { 0x0190, 0x025B },
139+ { 0x0191, 0x0192 },
140+ { 0x0193, 0x0260 },
141+ { 0x0194, 0x0263 },
142+ { 0x0196, 0x0269 },
143+ { 0x0197, 0x0268 },
144+ { 0x0198, 0x0199 },
145+ { 0x019C, 0x026F },
146+ { 0x019D, 0x0272 },
147+ { 0x019F, 0x0275 },
148+ { 0x01A6, 0x0280 },
149+ { 0x01A7, 0x01A8 },
150+ { 0x01A9, 0x0283 },
151+ { 0x01AC, 0x01AD },
152+ { 0x01AE, 0x0288 },
153+ { 0x01AF, 0x01B0 },
154+ { 0x01B7, 0x0292 },
155+ { 0x01B8, 0x01B9 },
156+ { 0x01BC, 0x01BD },
157+ { 0x01C4, 0x01C6 },
158+ { 0x01C7, 0x01C9 },
159+ { 0x01CA, 0x01CC },
160+ { 0x01F1, 0x01F3 },
161+ { 0x01F4, 0x01F5 },
162+ { 0x01F6, 0x0195 },
163+ { 0x01F7, 0x01BF },
164+ { 0x0220, 0x019E },
165+ { 0x023A, 0x2C65 },
166+ { 0x023B, 0x023C },
167+ { 0x023D, 0x019A },
168+ { 0x023E, 0x2C66 },
169+ { 0x0241, 0x0242 },
170+ { 0x0243, 0x0180 },
171+ { 0x0244, 0x0289 },
172+ { 0x0245, 0x028C },
173+ { 0x0376, 0x0377 },
174+ { 0x037F, 0x03F3 },
175+ { 0x0386, 0x03AC },
176+ { 0x038C, 0x03CC },
177+ { 0x03CF, 0x03D7 },
178+ { 0x03F4, 0x03B8 },
179+ { 0x03F7, 0x03F8 },
180+ { 0x03F9, 0x03F2 },
181+ { 0x03FA, 0x03FB },
182+ { 0x04C0, 0x04CF },
183+ { 0x10C7, 0x2D27 },
184+ { 0x10CD, 0x2D2D },
185+ { 0x1E9E, 0x00DF },
186+ { 0x1F59, 0x1F51 },
187+ { 0x1F5B, 0x1F53 },
188+ { 0x1F5D, 0x1F55 },
189+ { 0x1F5F, 0x1F57 },
190+ { 0x1FEC, 0x1FE5 },
191+ { 0x2102, 0x2102 },
192+ { 0x2107, 0x2107 },
193+ { 0x2115, 0x2115 },
194+ { 0x2124, 0x2124 },
195+ { 0x2126, 0x03C9 },
196+ { 0x2128, 0x2128 },
197+ { 0x212A, 0x006B },
198+ { 0x212B, 0x00E5 },
199+ { 0x2132, 0x214E },
200+ { 0x2133, 0x2133 },
201+ { 0x2145, 0x2145 },
202+ { 0x2183, 0x2184 },
203+ { 0x2C60, 0x2C61 },
204+ { 0x2C62, 0x026B },
205+ { 0x2C63, 0x1D7D },
206+ { 0x2C64, 0x027D },
207+ { 0x2C6D, 0x0251 },
208+ { 0x2C6E, 0x0271 },
209+ { 0x2C6F, 0x0250 },
210+ { 0x2C70, 0x0252 },
211+ { 0x2C72, 0x2C73 },
212+ { 0x2C75, 0x2C76 },
213+ { 0x2CF2, 0x2CF3 },
214+ { 0xA77D, 0x1D79 },
215+ { 0xA78B, 0xA78C },
216+ { 0xA78D, 0x0265 },
217+ { 0xA7AA, 0x0266 },
218+ { 0xA7AB, 0x025C },
219+ { 0xA7AC, 0x0261 },
220+ { 0xA7AD, 0x026C },
221+ { 0xA7AE, 0x026A },
222+ { 0xA7B0, 0x029E },
223+ { 0xA7B1, 0x0287 },
224+ { 0xA7B2, 0x029D },
225+ { 0xA7B3, 0xAB53 },
226+ { 0xA7C4, 0xA794 },
227+ { 0xA7C5, 0x0282 },
228+ { 0xA7C6, 0x1D8E },
229+ { 0xA7D0, 0xA7D1 },
230+ { 0xA7F5, 0xA7F6 },
231+ { 0x1D49C, 0x1D49C },
232+ { 0x1D4A2, 0x1D4A2 },
233+ { 0x1D546, 0x1D546 },
234+ { 0x1D7CA, 0x1D7CA },
235+};
236+
237+int
238+isupperrune(Rune r)
239+{
240+ const Rune *match;
241+
242+ if((match = bsearch(&r, upper3, nelem(upper3), sizeof *upper3, &rune2cmp)))
243+ return !((r - match[0]) % 2);
244+ if(bsearch(&r, upper2, nelem(upper2), sizeof *upper2, &rune2cmp))
245+ return 1;
246+ if(bsearch(&r, upper1, nelem(upper1), sizeof *upper1, &rune1cmp))
247+ return 1;
248+ return 0;
249+}
250+
251+int
252+tolowerrune(Rune r)
253+{
254+ Rune *match;
255+
256+ match = bsearch(&r, upper3, nelem(upper3), sizeof *upper3, &rune2cmp);
257+ if (match)
258+ return ((r - match[0]) % 2) ? r : r + 1;
259+ match = bsearch(&r, upper2, nelem(upper2), sizeof *upper2, &rune2cmp);
260+ if (match)
261+ return match[2] + (r - match[0]);
262+ match = bsearch(&r, upper1, nelem(upper1), sizeof *upper1, &rune1cmp);
263+ if (match)
264+ return match[1];
265+ return r;
266+}
1@@ -0,0 +1,142 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a
5+ * copy of this software and associated documentation files (the "Software"),
6+ * to deal in the Software without restriction, including without limitation
7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+ * and/or sell copies of the Software, and to permit persons to whom the
9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+ * DEALINGS IN THE SOFTWARE.
21+ */
22+#include <string.h>
23+#include "../utf.h"
24+
25+char *
26+utfecpy(char *to, char *end, const char *from)
27+{
28+ Rune r = Runeerror;
29+ size_t i, n;
30+
31+ /* seek through to find final full rune */
32+ for(i = 0; r != '\0' && (n = charntorune(&r, &from[i], end - &to[i])); i += n)
33+ ;
34+ memcpy(to, from, i); /* copy over bytes up to this rune */
35+
36+ if(i > 0 && r != '\0')
37+ to[i] = '\0'; /* terminate if unterminated */
38+ return &to[i];
39+}
40+
41+size_t
42+utflen(const char *s)
43+{
44+ const char *p = s;
45+ size_t i;
46+ Rune r;
47+
48+ for(i = 0; *p != '\0'; i++)
49+ p += chartorune(&r, p);
50+ return i;
51+}
52+
53+size_t
54+utfnlen(const char *s, size_t len)
55+{
56+ const char *p = s;
57+ size_t i;
58+ Rune r;
59+ int n;
60+
61+ for(i = 0; (n = charntorune(&r, p, len-(p-s))) && r != '\0'; i++)
62+ p += n;
63+ return i;
64+}
65+
66+size_t
67+utfmemlen(const char *s, size_t len)
68+{
69+ const char *p = s;
70+ size_t i;
71+ Rune r;
72+ int n;
73+
74+ for(i = 0; (n = charntorune(&r, p, len-(p-s))); i++)
75+ p += n;
76+ return i;
77+}
78+
79+char *
80+utfrune(const char *s, Rune r)
81+{
82+ if(r < Runeself) {
83+ return strchr(s, r);
84+ }
85+ else if(r == Runeerror) {
86+ Rune r0;
87+ int n;
88+
89+ for(; *s != '\0'; s += n) {
90+ n = chartorune(&r0, s);
91+ if(r == r0)
92+ return (char *)s;
93+ }
94+ }
95+ else {
96+ char buf[UTFmax+1];
97+ int n;
98+
99+ if(!(n = runetochar(buf, &r)))
100+ return NULL;
101+ buf[n] = '\0';
102+ return strstr(s, buf);
103+ }
104+ return NULL;
105+}
106+
107+char *
108+utfrrune(const char *s, Rune r)
109+{
110+ const char *p = NULL;
111+ Rune r0;
112+ int n;
113+
114+ if(r < Runeself)
115+ return strrchr(s, r);
116+
117+ for(; *s != '\0'; s += n) {
118+ n = chartorune(&r0, s);
119+ if(r == r0)
120+ p = s;
121+ }
122+ return (char *)p;
123+}
124+
125+char *
126+utfutf(const char *s, const char *t)
127+{
128+ const char *p, *q;
129+ Rune r0, r1, r2;
130+ int n, m;
131+
132+ for(chartorune(&r0, t); (s = utfrune(s, r0)); s++) {
133+ for(p = s, q = t; *q && *p; p += n, q += m) {
134+ n = chartorune(&r1, p);
135+ m = chartorune(&r2, q);
136+ if(r1 != r2)
137+ break;
138+ }
139+ if(!*q)
140+ return (char *)s;
141+ }
142+ return NULL;
143+}
1@@ -0,0 +1,27 @@
2+/* See LICENSE file for copyright and license details. */
3+#include "../utf.h"
4+
5+size_t
6+utftorunestr(const char *str, Rune *r)
7+{
8+ size_t i;
9+ int n;
10+
11+ for (i = 0; (n = chartorune(&r[i], str)) && r[i]; i++)
12+ str += n;
13+
14+ return i;
15+}
16+
17+size_t
18+utfntorunestr(const char *str, size_t len, Rune *r)
19+{
20+ size_t i;
21+ int n;
22+ const char *end = str + len;
23+
24+ for (i = 0; (n = charntorune(&r[i], str, end - str)); i++)
25+ str += n;
26+
27+ return i;
28+}
1@@ -0,0 +1,18 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <unistd.h>
4+
5+#include "../util.h"
6+
7+char *
8+agetcwd(void)
9+{
10+ char *buf;
11+ long size;
12+
13+ apathmax(&buf, &size);
14+ if (!getcwd(buf, size))
15+ eprintf("getcwd:");
16+
17+ return buf;
18+}
19+
1@@ -0,0 +1,13 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "../text.h"
8+#include "../util.h"
9+
10+ssize_t
11+agetline(char **p, size_t *size, FILE *fp)
12+{
13+ return getline(p, size, fp);
14+}
1@@ -0,0 +1,22 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <unistd.h>
7+
8+#include "../util.h"
9+
10+void
11+apathmax(char **p, long *size)
12+{
13+ errno = 0;
14+
15+ if ((*size = pathconf("/", _PC_PATH_MAX)) == -1) {
16+ if (errno == 0) {
17+ *size = BUFSIZ;
18+ } else {
19+ eprintf("pathconf:");
20+ }
21+ }
22+ *p = emalloc(*size);
23+}
1@@ -0,0 +1,23 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <unistd.h>
4+
5+#include "../util.h"
6+
7+int
8+concat(int f1, const char *s1, int f2, const char *s2)
9+{
10+ char buf[BUFSIZ];
11+ ssize_t n;
12+
13+ while ((n = read(f1, buf, sizeof(buf))) > 0) {
14+ if (writeall(f2, buf, n) < 0) {
15+ weprintf("write %s:", s2);
16+ return -2;
17+ }
18+ }
19+ if (n < 0) {
20+ weprintf("read %s:", s1);
21+ return -1;
22+ }
23+ return 0;
24+}
1@@ -0,0 +1,22 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdarg.h>
4+#include <ctype.h>
5+
6+#include "../util.h"
7+
8+int
9+confirm(const char *fmt, ...)
10+{
11+ int c, ans;
12+ va_list ap;
13+
14+ va_start(ap, fmt);
15+ xvprintf(fmt, ap);
16+ va_end(ap);
17+
18+ c = getchar();
19+ ans = (c == 'y' || c == 'Y');
20+ while (c != '\n' && c != EOF)
21+ c = getchar();
22+ return ans;
23+}
1@@ -0,0 +1,176 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <dirent.h>
4+#include <errno.h>
5+#include <fcntl.h>
6+#include <limits.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <sys/stat.h>
11+#include <sys/types.h>
12+#include <unistd.h>
13+#include <utime.h>
14+
15+#include "../fs.h"
16+#include "../util.h"
17+
18+int cp_aflag = 0;
19+int cp_fflag = 0;
20+int cp_iflag = 0;
21+int cp_pflag = 0;
22+int cp_rflag = 0;
23+int cp_vflag = 0;
24+int cp_status = 0;
25+int cp_follow;
26+
27+int
28+cp(const char *s1, const char *s2, int depth)
29+{
30+ DIR *dp;
31+ int f1, f2, flags = 0;
32+ struct dirent *d;
33+ struct stat st;
34+ struct timespec times[2];
35+ ssize_t r;
36+ char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX];
37+
38+ if (cp_follow == 'P' || (cp_follow == 'H' && depth))
39+ flags |= AT_SYMLINK_NOFOLLOW;
40+
41+ if (fstatat(AT_FDCWD, s1, &st, flags) < 0) {
42+ weprintf("stat %s:", s1);
43+ cp_status = 1;
44+ return 0;
45+ }
46+
47+ if (cp_iflag && access(s2, F_OK) == 0) {
48+ if (!confirm("overwrite '%s'? ", s2))
49+ return 0;
50+ }
51+
52+ if (cp_vflag)
53+ printf("%s -> %s\n", s1, s2);
54+
55+ if (S_ISLNK(st.st_mode)) {
56+ if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) {
57+ target[r] = '\0';
58+ if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
59+ weprintf("unlink %s:", s2);
60+ cp_status = 1;
61+ return 0;
62+ } else if (symlink(target, s2) < 0) {
63+ weprintf("symlink %s -> %s:", s2, target);
64+ cp_status = 1;
65+ return 0;
66+ }
67+ }
68+ } else if (S_ISDIR(st.st_mode)) {
69+ if (!cp_rflag) {
70+ weprintf("%s is a directory\n", s1);
71+ cp_status = 1;
72+ return 0;
73+ }
74+ if (!(dp = opendir(s1))) {
75+ weprintf("opendir %s:", s1);
76+ cp_status = 1;
77+ return 0;
78+ }
79+ if (mkdir(s2, st.st_mode) < 0 && errno != EEXIST) {
80+ weprintf("mkdir %s:", s2);
81+ cp_status = 1;
82+ closedir(dp);
83+ return 0;
84+ }
85+
86+ while ((d = readdir(dp))) {
87+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
88+ continue;
89+
90+ estrlcpy(ns1, s1, sizeof(ns1));
91+ if (s1[strlen(s1) - 1] != '/')
92+ estrlcat(ns1, "/", sizeof(ns1));
93+ estrlcat(ns1, d->d_name, sizeof(ns1));
94+
95+ estrlcpy(ns2, s2, sizeof(ns2));
96+ if (s2[strlen(s2) - 1] != '/')
97+ estrlcat(ns2, "/", sizeof(ns2));
98+ estrlcat(ns2, d->d_name, sizeof(ns2));
99+
100+ fnck(ns1, ns2, cp, depth + 1);
101+ }
102+
103+ closedir(dp);
104+ } else if (cp_aflag && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) ||
105+ S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode))) {
106+ if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) {
107+ weprintf("unlink %s:", s2);
108+ cp_status = 1;
109+ return 0;
110+ } else if (mknod(s2, st.st_mode, st.st_rdev) < 0) {
111+ weprintf("mknod %s:", s2);
112+ cp_status = 1;
113+ return 0;
114+ }
115+ } else {
116+ if ((f1 = open(s1, O_RDONLY)) < 0) {
117+ weprintf("open %s:", s1);
118+ cp_status = 1;
119+ return 0;
120+ }
121+ if ((f2 = creat(s2, st.st_mode)) < 0 && cp_fflag) {
122+ if (unlink(s2) < 0 && errno != ENOENT) {
123+ weprintf("unlink %s:", s2);
124+ cp_status = 1;
125+ close(f1);
126+ return 0;
127+ }
128+ f2 = creat(s2, st.st_mode);
129+ }
130+ if (f2 < 0) {
131+ weprintf("creat %s:", s2);
132+ cp_status = 1;
133+ close(f1);
134+ return 0;
135+ }
136+ if (concat(f1, s1, f2, s2) < 0) {
137+ cp_status = 1;
138+ close(f1);
139+ close(f2);
140+ return 0;
141+ }
142+
143+ close(f1);
144+ close(f2);
145+ }
146+
147+ if (cp_aflag || cp_pflag) {
148+ /* atime and mtime */
149+ times[0] = st.st_atim;
150+ times[1] = st.st_mtim;
151+ if (utimensat(AT_FDCWD, s2, times, AT_SYMLINK_NOFOLLOW) < 0) {
152+ weprintf("utimensat %s:", s2);
153+ cp_status = 1;
154+ }
155+
156+ /* owner and mode */
157+ if (!S_ISLNK(st.st_mode)) {
158+ if (chown(s2, st.st_uid, st.st_gid) < 0) {
159+ weprintf("chown %s:", s2);
160+ cp_status = 1;
161+ st.st_mode &= ~(S_ISUID | S_ISGID);
162+ }
163+ if (chmod(s2, st.st_mode) < 0) {
164+ weprintf("chmod %s:", s2);
165+ cp_status = 1;
166+ }
167+ } else {
168+ if (lchown(s2, st.st_uid, st.st_gid) < 0) {
169+ weprintf("lchown %s:", s2);
170+ cp_status = 1;
171+ return 0;
172+ }
173+ }
174+ }
175+
176+ return 0;
177+}
1@@ -0,0 +1,188 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <fcntl.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+#include <unistd.h>
9+
10+#include "../crypt.h"
11+#include "../text.h"
12+#include "../util.h"
13+
14+static int
15+hexdec(int c)
16+{
17+ if (c >= '0' && c <= '9')
18+ return c - '0';
19+ else if (c >= 'A' && c <= 'F')
20+ return c - 'A' + 10;
21+ else if (c >= 'a' && c <= 'f')
22+ return c - 'a' + 10;
23+ return -1; /* unknown character */
24+}
25+
26+static int
27+mdcheckline(const char *s, uint8_t *md, size_t sz)
28+{
29+ size_t i;
30+ int b1, b2;
31+
32+ for (i = 0; i < sz; i++) {
33+ if (!*s || (b1 = hexdec(*s++)) < 0)
34+ return -1; /* invalid format */
35+ if (!*s || (b2 = hexdec(*s++)) < 0)
36+ return -1; /* invalid format */
37+ if ((uint8_t)((b1 << 4) | b2) != md[i])
38+ return 1; /* value mismatch */
39+ }
40+ return (i == sz) ? 0 : 1;
41+}
42+
43+static void
44+mdchecklist(FILE *listfp, struct crypt_ops *ops, uint8_t *md, size_t sz,
45+ int *formatsucks, int *noread, int *nonmatch)
46+{
47+ int fd;
48+ size_t bufsiz = 0;
49+ int r;
50+ char *line = NULL, *file, *p;
51+
52+ while (getline(&line, &bufsiz, listfp) > 0) {
53+ file = strchr(line, ' ');
54+ if (file == NULL || (file[1] != ' ' && file[1] != '*')) {
55+ (*formatsucks)++;
56+ continue;
57+ }
58+ if (file - line != sz * 2) {
59+ (*formatsucks)++; /* checksum length mismatch */
60+ continue;
61+ }
62+ *file = '\0';
63+ file += 2;
64+ for (p = file; *p && *p != '\n' && *p != '\r'; p++); /* strip newline */
65+ *p = '\0';
66+ if ((fd = open(file, O_RDONLY)) < 0) {
67+ weprintf("open %s:", file);
68+ (*noread)++;
69+ continue;
70+ }
71+ if (cryptsum(ops, fd, file, md)) {
72+ (*noread)++;
73+ continue;
74+ }
75+ r = mdcheckline(line, md, sz);
76+ if (r == 0) {
77+ printf("%s: OK\n", file);
78+ } else if (r == 1) {
79+ printf("%s: FAILED\n", file);
80+ (*nonmatch)++;
81+ } else {
82+ (*formatsucks)++;
83+ }
84+ close(fd);
85+ }
86+ free(line);
87+}
88+
89+int
90+cryptcheck(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
91+{
92+ FILE *fp;
93+ int formatsucks = 0, noread = 0, nonmatch = 0, ret = 0;
94+
95+ if (argc == 0) {
96+ mdchecklist(stdin, ops, md, sz, &formatsucks, &noread, &nonmatch);
97+ } else {
98+ for (; *argv; argc--, argv++) {
99+ if ((*argv)[0] == '-' && !(*argv)[1]) {
100+ fp = stdin;
101+ } else if (!(fp = fopen(*argv, "r"))) {
102+ weprintf("fopen %s:", *argv);
103+ ret = 1;
104+ continue;
105+ }
106+ mdchecklist(fp, ops, md, sz, &formatsucks, &noread, &nonmatch);
107+ if (fp != stdin)
108+ fclose(fp);
109+ }
110+ }
111+
112+ if (formatsucks) {
113+ weprintf("%d improperly formatted line%s\n",
114+ formatsucks, formatsucks > 1 ? "s" : "");
115+ ret = 1;
116+ }
117+ if (noread) {
118+ weprintf("%d listed file%s could not be read\n",
119+ noread, noread > 1 ? "s" : "");
120+ ret = 1;
121+ }
122+ if (nonmatch) {
123+ weprintf("%d computed checksum%s did NOT match\n",
124+ nonmatch, nonmatch > 1 ? "s" : "");
125+ ret = 1;
126+ }
127+
128+ return ret;
129+}
130+
131+int
132+cryptmain(int argc, char *argv[], struct crypt_ops *ops, uint8_t *md, size_t sz)
133+{
134+ int fd;
135+ int ret = 0;
136+
137+ if (argc == 0) {
138+ if (cryptsum(ops, 0, "<stdin>", md))
139+ ret = 1;
140+ else
141+ mdprint(md, "<stdin>", sz);
142+ } else {
143+ for (; *argv; argc--, argv++) {
144+ if ((*argv)[0] == '-' && !(*argv)[1]) {
145+ *argv = "<stdin>";
146+ fd = 0;
147+ } else if ((fd = open(*argv, O_RDONLY)) < 0) {
148+ weprintf("open %s:", *argv);
149+ ret = 1;
150+ continue;
151+ }
152+ if (cryptsum(ops, fd, *argv, md))
153+ ret = 1;
154+ else
155+ mdprint(md, *argv, sz);
156+ if (fd != 0)
157+ close(fd);
158+ }
159+ }
160+
161+ return ret;
162+}
163+
164+int
165+cryptsum(struct crypt_ops *ops, int fd, const char *f, uint8_t *md)
166+{
167+ uint8_t buf[BUFSIZ];
168+ ssize_t n;
169+
170+ ops->init(ops->s);
171+ while ((n = read(fd, buf, sizeof(buf))) > 0)
172+ ops->update(ops->s, buf, n);
173+ if (n < 0) {
174+ weprintf("%s: read error:", f);
175+ return 1;
176+ }
177+ ops->sum(ops->s, md);
178+ return 0;
179+}
180+
181+void
182+mdprint(const uint8_t *md, const char *f, size_t len)
183+{
184+ size_t i;
185+
186+ for (i = 0; i < len; i++)
187+ printf("%02x", md[i]);
188+ printf(" %s\n", f);
189+}
1@@ -0,0 +1,88 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdlib.h>
4+#include <string.h>
5+
6+#include "../util.h"
7+
8+void *
9+ecalloc(size_t nmemb, size_t size)
10+{
11+ return encalloc(1, nmemb, size);
12+}
13+
14+void *
15+emalloc(size_t size)
16+{
17+ return enmalloc(1, size);
18+}
19+
20+void *
21+erealloc(void *p, size_t size)
22+{
23+ return enrealloc(1, p, size);
24+}
25+
26+char *
27+estrdup(const char *s)
28+{
29+ return enstrdup(1, s);
30+}
31+
32+char *
33+estrndup(const char *s, size_t n)
34+{
35+ return enstrndup(1, s, n);
36+}
37+
38+void *
39+encalloc(int status, size_t nmemb, size_t size)
40+{
41+ void *p;
42+
43+ p = calloc(nmemb, size);
44+ if (!p)
45+ enprintf(status, "calloc: out of memory\n");
46+ return p;
47+}
48+
49+void *
50+enmalloc(int status, size_t size)
51+{
52+ void *p;
53+
54+ p = malloc(size);
55+ if (!p)
56+ enprintf(status, "malloc: out of memory\n");
57+ return p;
58+}
59+
60+void *
61+enrealloc(int status, void *p, size_t size)
62+{
63+ p = realloc(p, size);
64+ if (!p)
65+ enprintf(status, "realloc: out of memory\n");
66+ return p;
67+}
68+
69+char *
70+enstrdup(int status, const char *s)
71+{
72+ char *p;
73+
74+ p = strdup(s);
75+ if (!p)
76+ enprintf(status, "strdup: out of memory\n");
77+ return p;
78+}
79+
80+char *
81+enstrndup(int status, const char *s, size_t n)
82+{
83+ char *p;
84+
85+ p = strndup(s, n);
86+ if (!p)
87+ enprintf(status, "strndup: out of memory\n");
88+ return p;
89+}
1@@ -0,0 +1,38 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <libgen.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+#include <sys/stat.h>
8+#include <unistd.h>
9+
10+#include "../util.h"
11+
12+void
13+enmasse(int argc, char *argv[], int (*fn)(const char *, const char *, int))
14+{
15+ struct stat st;
16+ char buf[PATH_MAX], *dir;
17+ int i, len;
18+ size_t dlen;
19+
20+ if (argc == 2 && !(stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode))) {
21+ fnck(argv[0], argv[1], fn, 0);
22+ return;
23+ } else {
24+ dir = (argc == 1) ? "." : argv[--argc];
25+ }
26+
27+ for (i = 0; i < argc; i++) {
28+ dlen = strlen(dir);
29+ if (dlen > 0 && dir[dlen - 1] == '/')
30+ len = snprintf(buf, sizeof(buf), "%s%s", dir, basename(argv[i]));
31+ else
32+ len = snprintf(buf, sizeof(buf), "%s/%s", dir, basename(argv[i]));
33+ if (len < 0 || len >= sizeof(buf)) {
34+ eprintf("%s/%s: filename too long\n", dir,
35+ basename(argv[i]));
36+ }
37+ fnck(argv[i], buf, fn, 0);
38+ }
39+}
1@@ -0,0 +1,57 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdarg.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+#include "../util.h"
9+
10+char *argv0;
11+
12+void
13+eprintf(const char *fmt, ...)
14+{
15+ va_list ap;
16+
17+ va_start(ap, fmt);
18+ xvprintf(fmt, ap);
19+ va_end(ap);
20+
21+ exit(1);
22+}
23+
24+void
25+enprintf(int status, const char *fmt, ...)
26+{
27+ va_list ap;
28+
29+ va_start(ap, fmt);
30+ xvprintf(fmt, ap);
31+ va_end(ap);
32+
33+ exit(status);
34+}
35+
36+void
37+weprintf(const char *fmt, ...)
38+{
39+ va_list ap;
40+
41+ va_start(ap, fmt);
42+ xvprintf(fmt, ap);
43+ va_end(ap);
44+}
45+
46+void
47+xvprintf(const char *fmt, va_list ap)
48+{
49+ if (argv0 && strncmp(fmt, "usage", strlen("usage")))
50+ fprintf(stderr, "%s: ", argv0);
51+
52+ vfprintf(stderr, fmt, ap);
53+
54+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
55+ fputc(' ', stderr);
56+ perror(NULL);
57+ }
58+}
1@@ -0,0 +1,27 @@
2+#include <sys/types.h>
3+
4+#include <regex.h>
5+#include <stdio.h>
6+
7+#include "../util.h"
8+
9+int
10+enregcomp(int status, regex_t *preg, const char *regex, int cflags)
11+{
12+ char errbuf[BUFSIZ] = "";
13+ int r;
14+
15+ if ((r = regcomp(preg, regex, cflags)) == 0)
16+ return r;
17+
18+ regerror(r, preg, errbuf, sizeof(errbuf));
19+ enprintf(status, "invalid regex: %s\n", errbuf);
20+
21+ return r;
22+}
23+
24+int
25+eregcomp(regex_t *preg, const char *regex, int cflags)
26+{
27+ return enregcomp(1, preg, regex, cflags);
28+}
1@@ -0,0 +1,18 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+
7+#include "../util.h"
8+
9+double
10+estrtod(const char *s)
11+{
12+ char *end;
13+ double d;
14+
15+ d = strtod(s, &end);
16+ if (end == s || *end != '\0')
17+ eprintf("%s: not a real number\n", s);
18+ return d;
19+}
1@@ -0,0 +1,27 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+
7+#include "../util.h"
8+
9+long
10+estrtol(const char *s, int base)
11+{
12+ char *end;
13+ long n;
14+
15+ errno = 0;
16+ n = strtol(s, &end, base);
17+ if (*end != '\0') {
18+ if (base == 0)
19+ eprintf("%s: not an integer\n", s);
20+ else
21+ eprintf("%s: not a base %d integer\n", s, base);
22+ }
23+ if (errno != 0)
24+ eprintf("%s:", s);
25+
26+ return n;
27+}
28+
1@@ -0,0 +1,26 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <errno.h>
4+#include <stdio.h>
5+#include <stdlib.h>
6+
7+#include "../util.h"
8+
9+unsigned long
10+estrtoul(const char *s, int base)
11+{
12+ char *end;
13+ unsigned long n;
14+
15+ errno = 0;
16+ n = strtoul(s, &end, base);
17+ if (*end != '\0') {
18+ if (base == 0)
19+ eprintf("%s: not an integer\n", s);
20+ else
21+ eprintf("%s: not a base %d integer\n", s, base);
22+ }
23+ if (errno != 0)
24+ eprintf("%s:", s);
25+
26+ return n;
27+}
1@@ -0,0 +1,12 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <string.h>
4+
5+#include "../util.h"
6+
7+static void *(*volatile explicit_memset)(void *, int, size_t) = memset;
8+
9+void
10+explicit_bzero(void *b, size_t len)
11+{
12+ (*explicit_memset)(b, 0, len);
13+}
1@@ -0,0 +1,21 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+
5+#include "../text.h"
6+#include "../util.h"
7+
8+void
9+fconcat(FILE *fp1, const char *s1, FILE *fp2, const char *s2)
10+{
11+ char buf[BUFSIZ];
12+ size_t n;
13+
14+ while ((n = fread(buf, 1, sizeof(buf), fp1)) > 0) {
15+ if (fwrite(buf, 1, n, fp2) != n)
16+ eprintf("%s: write error:", s2);
17+ if (feof(fp1))
18+ break;
19+ }
20+ if (ferror(fp1))
21+ eprintf("%s: read error:", s1);
22+}
1@@ -0,0 +1,22 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include "../util.h"
6+
7+void
8+fnck(const char *a, const char *b,
9+ int (*fn)(const char *, const char *, int), int depth)
10+{
11+ struct stat sta, stb;
12+
13+ if (!stat(a, &sta)
14+ && !stat(b, &stb)
15+ && sta.st_dev == stb.st_dev
16+ && sta.st_ino == stb.st_ino) {
17+ weprintf("%s -> %s: same file\n", a, b);
18+ return;
19+ }
20+
21+ if (fn(a, b, depth) < 0)
22+ eprintf("%s -> %s:", a, b);
23+}
1@@ -0,0 +1,43 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+
6+#include "../util.h"
7+
8+int
9+fshut(FILE *fp, const char *fname)
10+{
11+ int ret = 0;
12+
13+ /* fflush() is undefined for input streams by ISO C,
14+ * but not POSIX 2008 if you ignore ISO C overrides.
15+ * Leave it unchecked and rely on the following
16+ * functions to detect errors.
17+ */
18+ fflush(fp);
19+
20+ if (ferror(fp) && !ret) {
21+ weprintf("ferror %s:", fname);
22+ ret = 1;
23+ }
24+
25+ if (fclose(fp) && !ret) {
26+ weprintf("fclose %s:", fname);
27+ ret = 1;
28+ }
29+
30+ return ret;
31+}
32+
33+void
34+enfshut(int status, FILE *fp, const char *fname)
35+{
36+ if (fshut(fp, fname))
37+ exit(status);
38+}
39+
40+void
41+efshut(FILE *fp, const char *fname)
42+{
43+ enfshut(1, fp, fname);
44+}
1@@ -0,0 +1,32 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+#include "../text.h"
8+#include "../util.h"
9+
10+void
11+getlines(FILE *fp, struct linebuf *b)
12+{
13+ char *line = NULL;
14+ size_t size = 0, linelen = 0;
15+ ssize_t len;
16+
17+ while ((len = getline(&line, &size, fp)) > 0) {
18+ if (++b->nlines > b->capacity) {
19+ b->capacity += 512;
20+ b->lines = ereallocarray(b->lines, b->capacity, sizeof(*b->lines));
21+ }
22+ linelen = len;
23+ b->lines[b->nlines - 1].data = memcpy(emalloc(linelen + 1), line, linelen + 1);
24+ b->lines[b->nlines - 1].len = linelen;
25+ }
26+ free(line);
27+ if (b->lines && b->nlines && linelen && b->lines[b->nlines - 1].data[linelen - 1] != '\n') {
28+ b->lines[b->nlines - 1].data = erealloc(b->lines[b->nlines - 1].data, linelen + 2);
29+ b->lines[b->nlines - 1].data[linelen] = '\n';
30+ b->lines[b->nlines - 1].data[linelen + 1] = '\0';
31+ b->lines[b->nlines - 1].len++;
32+ }
33+}
1@@ -0,0 +1,25 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <string.h>
5+#include <stdint.h>
6+
7+#include "../util.h"
8+
9+char *
10+humansize(off_t n)
11+{
12+ static char buf[16];
13+ const char postfixes[] = "BKMGTPE";
14+ double size;
15+ int i;
16+
17+ for (size = n, i = 0; size >= 1024 && i < strlen(postfixes); i++)
18+ size /= 1024;
19+
20+ if (!i)
21+ snprintf(buf, sizeof(buf), "%ju", (uintmax_t)n);
22+ else
23+ snprintf(buf, sizeof(buf), "%.1f%c", size, postfixes[i]);
24+
25+ return buf;
26+}
1@@ -0,0 +1,17 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+#include <string.h>
5+
6+#include "../text.h"
7+#include "../util.h"
8+
9+int
10+linecmp(struct line *a, struct line *b)
11+{
12+ int res = 0;
13+
14+ if (!(res = memcmp(a->data, b->data, MIN(a->len, b->len))))
15+ res = a->len - b->len;
16+
17+ return res;
18+}
1@@ -0,0 +1,148 @@
2+/* public domain md5 implementation based on rfc1321 and libtomcrypt */
3+#include <stdint.h>
4+#include <string.h>
5+
6+#include "../md5.h"
7+
8+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
9+#define F(x,y,z) (z ^ (x & (y ^ z)))
10+#define G(x,y,z) (y ^ (z & (y ^ x)))
11+#define H(x,y,z) (x ^ y ^ z)
12+#define I(x,y,z) (y ^ (x | ~z))
13+#define FF(a,b,c,d,w,s,t) a += F(b,c,d) + w + t; a = rol(a,s) + b
14+#define GG(a,b,c,d,w,s,t) a += G(b,c,d) + w + t; a = rol(a,s) + b
15+#define HH(a,b,c,d,w,s,t) a += H(b,c,d) + w + t; a = rol(a,s) + b
16+#define II(a,b,c,d,w,s,t) a += I(b,c,d) + w + t; a = rol(a,s) + b
17+
18+static const uint32_t tab[64] = {
19+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
20+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
21+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
22+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
23+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
24+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
25+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
26+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
27+};
28+
29+static void
30+processblock(struct md5 *s, const uint8_t *buf)
31+{
32+ uint32_t i, W[16], a, b, c, d;
33+
34+ for (i = 0; i < 16; i++) {
35+ W[i] = buf[4*i];
36+ W[i] |= (uint32_t)buf[4*i+1]<<8;
37+ W[i] |= (uint32_t)buf[4*i+2]<<16;
38+ W[i] |= (uint32_t)buf[4*i+3]<<24;
39+ }
40+
41+ a = s->h[0];
42+ b = s->h[1];
43+ c = s->h[2];
44+ d = s->h[3];
45+
46+ i = 0;
47+ while (i < 16) {
48+ FF(a,b,c,d, W[i], 7, tab[i]); i++;
49+ FF(d,a,b,c, W[i], 12, tab[i]); i++;
50+ FF(c,d,a,b, W[i], 17, tab[i]); i++;
51+ FF(b,c,d,a, W[i], 22, tab[i]); i++;
52+ }
53+ while (i < 32) {
54+ GG(a,b,c,d, W[(5*i+1)%16], 5, tab[i]); i++;
55+ GG(d,a,b,c, W[(5*i+1)%16], 9, tab[i]); i++;
56+ GG(c,d,a,b, W[(5*i+1)%16], 14, tab[i]); i++;
57+ GG(b,c,d,a, W[(5*i+1)%16], 20, tab[i]); i++;
58+ }
59+ while (i < 48) {
60+ HH(a,b,c,d, W[(3*i+5)%16], 4, tab[i]); i++;
61+ HH(d,a,b,c, W[(3*i+5)%16], 11, tab[i]); i++;
62+ HH(c,d,a,b, W[(3*i+5)%16], 16, tab[i]); i++;
63+ HH(b,c,d,a, W[(3*i+5)%16], 23, tab[i]); i++;
64+ }
65+ while (i < 64) {
66+ II(a,b,c,d, W[7*i%16], 6, tab[i]); i++;
67+ II(d,a,b,c, W[7*i%16], 10, tab[i]); i++;
68+ II(c,d,a,b, W[7*i%16], 15, tab[i]); i++;
69+ II(b,c,d,a, W[7*i%16], 21, tab[i]); i++;
70+ }
71+
72+ s->h[0] += a;
73+ s->h[1] += b;
74+ s->h[2] += c;
75+ s->h[3] += d;
76+}
77+
78+static void
79+pad(struct md5 *s)
80+{
81+ unsigned r = s->len % 64;
82+
83+ s->buf[r++] = 0x80;
84+ if (r > 56) {
85+ memset(s->buf + r, 0, 64 - r);
86+ r = 0;
87+ processblock(s, s->buf);
88+ }
89+ memset(s->buf + r, 0, 56 - r);
90+ s->len *= 8;
91+ s->buf[56] = s->len;
92+ s->buf[57] = s->len >> 8;
93+ s->buf[58] = s->len >> 16;
94+ s->buf[59] = s->len >> 24;
95+ s->buf[60] = s->len >> 32;
96+ s->buf[61] = s->len >> 40;
97+ s->buf[62] = s->len >> 48;
98+ s->buf[63] = s->len >> 56;
99+ processblock(s, s->buf);
100+}
101+
102+void
103+md5_init(void *ctx)
104+{
105+ struct md5 *s = ctx;
106+ s->len = 0;
107+ s->h[0] = 0x67452301;
108+ s->h[1] = 0xefcdab89;
109+ s->h[2] = 0x98badcfe;
110+ s->h[3] = 0x10325476;
111+}
112+
113+void
114+md5_sum(void *ctx, uint8_t md[MD5_DIGEST_LENGTH])
115+{
116+ struct md5 *s = ctx;
117+ int i;
118+
119+ pad(s);
120+ for (i = 0; i < 4; i++) {
121+ md[4*i] = s->h[i];
122+ md[4*i+1] = s->h[i] >> 8;
123+ md[4*i+2] = s->h[i] >> 16;
124+ md[4*i+3] = s->h[i] >> 24;
125+ }
126+}
127+
128+void
129+md5_update(void *ctx, const void *m, unsigned long len)
130+{
131+ struct md5 *s = ctx;
132+ const uint8_t *p = m;
133+ unsigned r = s->len % 64;
134+
135+ s->len += len;
136+ if (r) {
137+ if (len < 64 - r) {
138+ memcpy(s->buf + r, p, len);
139+ return;
140+ }
141+ memcpy(s->buf + r, p, 64 - r);
142+ len -= 64 - r;
143+ p += 64 - r;
144+ processblock(s, s->buf);
145+ }
146+ for (; len >= 64; len -= 64, p += 64)
147+ processblock(s, p);
148+ memcpy(s->buf, p, len);
149+}
1@@ -0,0 +1,66 @@
2+/* $OpenBSD: memmem.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
3+
4+/*
5+ * Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
6+ *
7+ * Redistribution and use in source and binary forms, with or without
8+ * modification, are permitted provided that the following conditions
9+ * are met:
10+ * 1. Redistributions of source code must retain the above copyright
11+ * notice, this list of conditions and the following disclaimer.
12+ * 2. Redistributions in binary form must reproduce the above copyright
13+ * notice, this list of conditions and the following disclaimer in the
14+ * documentation and/or other materials provided with the distribution.
15+ * 3. The name of the author may not be used to endorse or promote
16+ * products derived from this software without specific prior written
17+ * permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29+ * SUCH DAMAGE.
30+ */
31+
32+#include <string.h>
33+
34+#include "../util.h"
35+
36+/*
37+ * Find the first occurrence of the byte string s in byte string l.
38+ */
39+
40+void *
41+memmem(const void *l, size_t l_len, const void *s, size_t s_len)
42+{
43+ const char *cur, *last;
44+ const char *cl = l;
45+ const char *cs = s;
46+
47+ /* a zero length needle should just return the haystack */
48+ if (s_len == 0)
49+ return (void *)cl;
50+
51+ /* "s" must be smaller or equal to "l" */
52+ if (l_len < s_len)
53+ return NULL;
54+
55+ /* special case where s_len == 1 */
56+ if (s_len == 1)
57+ return memchr(l, *cs, l_len);
58+
59+ /* the last position where its possible to find "s" in "l" */
60+ last = cl + l_len - s_len;
61+
62+ for (cur = cl; cur <= last; cur++)
63+ if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
64+ return (void *)cur;
65+
66+ return NULL;
67+}
1@@ -0,0 +1,39 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <limits.h>
7+
8+#include "../util.h"
9+
10+int
11+mkdirp(const char *path, mode_t mode, mode_t pmode)
12+{
13+ char tmp[PATH_MAX], *p;
14+ struct stat st;
15+
16+ if (stat(path, &st) == 0) {
17+ if (S_ISDIR(st.st_mode))
18+ return 0;
19+ errno = ENOTDIR;
20+ weprintf("%s:", path);
21+ return -1;
22+ }
23+
24+ estrlcpy(tmp, path, sizeof(tmp));
25+ for (p = tmp + (tmp[0] == '/'); *p; p++) {
26+ if (*p != '/')
27+ continue;
28+ *p = '\0';
29+ if (mkdir(tmp, pmode) < 0 && errno != EEXIST) {
30+ weprintf("mkdir %s:", tmp);
31+ return -1;
32+ }
33+ *p = '/';
34+ }
35+ if (mkdir(tmp, mode) < 0 && errno != EEXIST) {
36+ weprintf("mkdir %s:", tmp);
37+ return -1;
38+ }
39+ return 0;
40+}
1@@ -0,0 +1,152 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdlib.h>
4+#include <string.h>
5+#include <sys/stat.h>
6+#include <unistd.h>
7+
8+#include "../util.h"
9+
10+mode_t
11+getumask(void)
12+{
13+ mode_t mask = umask(0);
14+ umask(mask);
15+ return mask;
16+}
17+
18+mode_t
19+parsemode(const char *str, mode_t mode, mode_t mask)
20+{
21+ char *end;
22+ const char *p = str;
23+ int octal, op;
24+ mode_t who, perm, clear;
25+
26+ octal = strtol(str, &end, 8);
27+ if (*end == '\0') {
28+ if (octal < 0 || octal > 07777)
29+ eprintf("%s: invalid mode\n", str);
30+ return octal;
31+ }
32+next:
33+ /* first, determine which bits we will be modifying */
34+ for (who = 0; *p; p++) {
35+ switch (*p) {
36+ /* masks */
37+ case 'u':
38+ who |= S_IRWXU|S_ISUID;
39+ continue;
40+ case 'g':
41+ who |= S_IRWXG|S_ISGID;
42+ continue;
43+ case 'o':
44+ who |= S_IRWXO|S_ISVTX;
45+ continue;
46+ case 'a':
47+ who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO|S_ISVTX;
48+ continue;
49+ }
50+ break;
51+ }
52+ if (who) {
53+ clear = who;
54+ } else {
55+ clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
56+ who = ~mask;
57+ }
58+ while (*p) {
59+ switch (*p) {
60+ /* opers */
61+ case '=':
62+ case '+':
63+ case '-':
64+ op = (int)*p;
65+ break;
66+ default:
67+ eprintf("%s: invalid mode\n", str);
68+ }
69+
70+ perm = 0;
71+ switch (*++p) {
72+ /* copy */
73+ case 'u':
74+ if (mode & S_IRUSR)
75+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
76+ if (mode & S_IWUSR)
77+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
78+ if (mode & S_IXUSR)
79+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
80+ if (mode & S_ISUID)
81+ perm |= S_ISUID|S_ISGID;
82+ p++;
83+ break;
84+ case 'g':
85+ if (mode & S_IRGRP)
86+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
87+ if (mode & S_IWGRP)
88+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
89+ if (mode & S_IXGRP)
90+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
91+ if (mode & S_ISGID)
92+ perm |= S_ISUID|S_ISGID;
93+ p++;
94+ break;
95+ case 'o':
96+ if (mode & S_IROTH)
97+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
98+ if (mode & S_IWOTH)
99+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
100+ if (mode & S_IXOTH)
101+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
102+ p++;
103+ break;
104+ default:
105+ for (; *p; p++) {
106+ switch (*p) {
107+ /* modes */
108+ case 'r':
109+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
110+ break;
111+ case 'w':
112+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
113+ break;
114+ case 'x':
115+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
116+ break;
117+ case 'X':
118+ if (S_ISDIR(mode) || mode & (S_IXUSR|S_IXGRP|S_IXOTH))
119+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
120+ break;
121+ case 's':
122+ perm |= S_ISUID|S_ISGID;
123+ break;
124+ case 't':
125+ perm |= S_ISVTX;
126+ break;
127+ default:
128+ goto apply;
129+ }
130+ }
131+ }
132+
133+apply:
134+ /* apply */
135+ switch (op) {
136+ case '=':
137+ mode &= ~clear;
138+ /* fallthrough */
139+ case '+':
140+ mode |= perm & who;
141+ break;
142+ case '-':
143+ mode &= ~(perm & who);
144+ break;
145+ }
146+ /* if we hit a comma, move on to the next clause */
147+ if (*p == ',') {
148+ p++;
149+ goto next;
150+ }
151+ }
152+ return mode & ~S_IFMT;
153+}
1@@ -0,0 +1,61 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <errno.h>
5+#include <inttypes.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "../util.h"
10+
11+off_t
12+parseoffset(const char *str)
13+{
14+ off_t res, scale = 1;
15+ char *end;
16+
17+ /* strictly check what strtol() usually would let pass */
18+ if (!str || !*str || isspace(*str) || *str == '+' || *str == '-') {
19+ weprintf("parseoffset %s: invalid value\n", str);
20+ return -1;
21+ }
22+
23+ errno = 0;
24+ res = strtol(str, &end, 0);
25+ if (errno) {
26+ weprintf("parseoffset %s: invalid value\n", str);
27+ return -1;
28+ }
29+ if (res < 0) {
30+ weprintf("parseoffset %s: negative value\n", str);
31+ return -1;
32+ }
33+
34+ /* suffix */
35+ if (*end) {
36+ switch (toupper((int)*end)) {
37+ case 'B':
38+ scale = 512L;
39+ break;
40+ case 'K':
41+ scale = 1024L;
42+ break;
43+ case 'M':
44+ scale = 1024L * 1024L;
45+ break;
46+ case 'G':
47+ scale = 1024L * 1024L * 1024L;
48+ break;
49+ default:
50+ weprintf("parseoffset %s: invalid suffix '%s'\n", str, end);
51+ return -1;
52+ }
53+ }
54+
55+ /* prevent overflow */
56+ if (res > (SSIZE_MAX / scale)) {
57+ weprintf("parseoffset %s: out of range\n", str);
58+ return -1;
59+ }
60+
61+ return res * scale;
62+}
1@@ -0,0 +1,77 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/resource.h>
4+#include <sys/time.h>
5+
6+#include <errno.h>
7+#include <pwd.h>
8+#include <shadow.h>
9+#include <stdio.h>
10+#include <stdlib.h>
11+#include <string.h>
12+#include <unistd.h>
13+
14+#include "../passwd.h"
15+#include "../text.h"
16+#include "../util.h"
17+
18+/* Returns -1 on error, 0 for incorrect password
19+ * and 1 if all went OK */
20+int
21+pw_check(const struct passwd *pw, const char *pass)
22+{
23+ char *cryptpass, *p;
24+ struct spwd *spw;
25+
26+ p = pw->pw_passwd;
27+ if (p[0] == '!' || p[0] == '*') {
28+ weprintf("denied\n");
29+ return -1;
30+ }
31+
32+ if (pw->pw_passwd[0] == '\0') {
33+ if (pass[0] == '\0')
34+ return 1;
35+ weprintf("incorrect password\n");
36+ return 0;
37+ }
38+
39+ if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
40+ errno = 0;
41+ spw = getspnam(pw->pw_name);
42+ if (!spw) {
43+ if (errno)
44+ weprintf("getspnam: %s:", pw->pw_name);
45+ else
46+ weprintf("who are you?\n");
47+ return -1;
48+ }
49+ p = spw->sp_pwdp;
50+ if (p[0] == '!' || p[0] == '*') {
51+ weprintf("denied\n");
52+ return -1;
53+ }
54+ }
55+
56+ cryptpass = crypt(pass, p);
57+ if (!cryptpass) {
58+ weprintf("crypt:");
59+ return -1;
60+ }
61+ if (strcmp(cryptpass, p) != 0) {
62+ weprintf("incorrect password\n");
63+ return 0;
64+ }
65+ return 1;
66+}
67+
68+int
69+pw_init(void)
70+{
71+ struct rlimit rlim;
72+
73+ rlim.rlim_cur = 0;
74+ rlim.rlim_max = 0;
75+ if (setrlimit(RLIMIT_CORE, &rlim) < 0)
76+ eprintf("setrlimit:");
77+ return 0;
78+}
1@@ -0,0 +1,117 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <limits.h>
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <unistd.h>
12+
13+#include "../proc.h"
14+#include "../util.h"
15+
16+int
17+parsecmdline(pid_t pid, char *buf, size_t siz)
18+{
19+ int fd;
20+ char path[PATH_MAX];
21+ ssize_t n, i;
22+
23+ snprintf(path, sizeof(path), "/proc/%ld/cmdline", (long)pid);
24+ fd = open(path, O_RDONLY);
25+ if (fd < 0)
26+ return -1;
27+ n = read(fd, buf, siz > 0 ? siz - 1 : 0);
28+ if (n < 0) {
29+ weprintf("read %s:", path);
30+ close(fd);
31+ return -1;
32+ }
33+ if (!n) {
34+ close(fd);
35+ return -1;
36+ }
37+ buf[n] = '\0';
38+ for (i = 0; i < n; i++)
39+ if (buf[i] == '\0')
40+ buf[i] = ' ';
41+ close(fd);
42+ return 0;
43+}
44+
45+int
46+parsestat(pid_t pid, struct procstat *ps)
47+{
48+ char path[PATH_MAX];
49+ FILE *fp;
50+ size_t len;
51+
52+ snprintf(path, sizeof(path), "/proc/%d/stat", pid);
53+ if (!(fp = fopen(path, "r")))
54+ return -1;
55+ fscanf(fp, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu",
56+ &ps->pid, ps->comm,
57+ &ps->state, &ps->ppid, &ps->pgrp,
58+ &ps->sid, &ps->tty_nr, &ps->tpgid, &ps->flags,
59+ &ps->minflt, &ps->cminflt, &ps->majflt, &ps->cmajflt,
60+ &ps->utime, &ps->stime);
61+ fscanf(fp, "%ld %ld %ld %ld %ld %ld %llu %lu %ld %ld",
62+ &ps->cutime, &ps->cstime, &ps->priority, &ps->nice,
63+ &ps->num_threads, &ps->itrealvalue, &ps->starttime,
64+ &ps->vsize, &ps->rss, &ps->rsslim);
65+ /* Filter out '(' and ')' from comm */
66+ if ((len = strlen(ps->comm)) > 0)
67+ len--;
68+ ps->comm[len] = '\0';
69+ memmove(ps->comm, ps->comm + 1, len);
70+ fclose(fp);
71+ return 0;
72+}
73+
74+int
75+parsestatus(pid_t pid, struct procstatus *pstatus)
76+{
77+ char path[PATH_MAX];
78+ char buf[BUFSIZ], *off;
79+ int fd;
80+ ssize_t n;
81+
82+ snprintf(path, sizeof(path), "/proc/%d/status", pid);
83+ fd = open(path, O_RDONLY);
84+ if (fd < 0)
85+ return -1;
86+ n = read(fd, buf, sizeof(buf) - 1);
87+ if (n < 0)
88+ eprintf("%s: read error:", path);
89+ if (!n) {
90+ close(fd);
91+ return -1;
92+ }
93+ buf[n] = '\0';
94+ close(fd);
95+ off = strstr(buf, "Uid:");
96+ if (!off)
97+ return -1;
98+ sscanf(off, "Uid: %u %u", &pstatus->uid, &pstatus->euid);
99+ off = strstr(buf, "Gid:");
100+ if (!off)
101+ return -1;
102+ sscanf(off, "Gid: %u %u", &pstatus->gid, &pstatus->egid);
103+ return 0;
104+}
105+
106+int
107+pidfile(const char *file)
108+{
109+ char *end;
110+
111+ errno = 0;
112+ strtol(file, &end, 10);
113+ if (*end != '\0')
114+ return 0;
115+ if (errno != 0)
116+ return 0;
117+ return 1;
118+}
1@@ -0,0 +1,16 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <stdio.h>
4+
5+#include "../util.h"
6+
7+void
8+putword(FILE *fp, const char *s)
9+{
10+ static int first = 1;
11+
12+ if (!first)
13+ fputc(' ', fp);
14+
15+ fputs(s, fp);
16+ first = 0;
17+}
1@@ -0,0 +1,56 @@
2+/*
3+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
4+ *
5+ * Permission to use, copy, modify, and distribute this software for any
6+ * purpose with or without fee is hereby granted, provided that the above
7+ * copyright notice and this permission notice appear in all copies.
8+ *
9+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+ */
17+
18+#include <sys/types.h>
19+#include <errno.h>
20+#include <stdint.h>
21+#include <stdlib.h>
22+
23+#include "../util.h"
24+
25+/*
26+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
27+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
28+ */
29+#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
30+
31+void *
32+reallocarray(void *optr, size_t nmemb, size_t size)
33+{
34+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
35+ nmemb > 0 && SIZE_MAX / nmemb < size) {
36+ errno = ENOMEM;
37+ return NULL;
38+ }
39+ return realloc(optr, size * nmemb);
40+}
41+
42+void *
43+ereallocarray(void *optr, size_t nmemb, size_t size)
44+{
45+ return enreallocarray(1, optr, nmemb, size);
46+}
47+
48+void *
49+enreallocarray(int status, void *optr, size_t nmemb, size_t size)
50+{
51+ void *p;
52+
53+ if (!(p = reallocarray(optr, nmemb, size)))
54+ enprintf(status, "reallocarray: out of memory\n");
55+
56+ return p;
57+}
1@@ -0,0 +1,108 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <dirent.h>
4+#include <errno.h>
5+#include <fcntl.h>
6+#include <limits.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <sys/stat.h>
11+#include <sys/types.h>
12+#include <unistd.h>
13+
14+#include "../fs.h"
15+#include "../util.h"
16+
17+int recurse_status = 0;
18+
19+void
20+recurse(int dirfd, const char *name, void *data, struct recursor *r)
21+{
22+ struct dirent *d;
23+ struct history *new, *h;
24+ struct stat st, dst;
25+ DIR *dp;
26+ int flags = 0, fd;
27+ size_t pathlen = r->pathlen;
28+
29+ if (dirfd == AT_FDCWD)
30+ pathlen = estrlcpy(r->path, name, sizeof(r->path));
31+
32+ if (r->follow == 'P' || (r->follow == 'H' && r->depth))
33+ flags |= AT_SYMLINK_NOFOLLOW;
34+
35+ if (fstatat(dirfd, name, &st, flags) < 0) {
36+ if (!(r->flags & SILENT)) {
37+ weprintf("stat %s:", r->path);
38+ recurse_status = 1;
39+ }
40+ return;
41+ }
42+ if (!S_ISDIR(st.st_mode)) {
43+ r->fn(dirfd, name, &st, data, r);
44+ return;
45+ }
46+
47+ new = emalloc(sizeof(struct history));
48+ new->prev = r->hist;
49+ r->hist = new;
50+ new->dev = st.st_dev;
51+ new->ino = st.st_ino;
52+
53+ for (h = new->prev; h; h = h->prev)
54+ if (h->ino == st.st_ino && h->dev == st.st_dev)
55+ return;
56+
57+ if (!r->depth && (r->flags & DIRFIRST))
58+ r->fn(dirfd, name, &st, data, r);
59+
60+ if (!r->maxdepth || r->depth + 1 < r->maxdepth) {
61+ fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
62+ if (fd < 0) {
63+ weprintf("open %s:", r->path);
64+ recurse_status = 1;
65+ }
66+ if (!(dp = fdopendir(fd))) {
67+ if (!(r->flags & SILENT)) {
68+ weprintf("fdopendir:");
69+ recurse_status = 1;
70+ }
71+ return;
72+ }
73+ if (r->path[pathlen - 1] != '/')
74+ r->path[pathlen++] = '/';
75+ if (r->follow == 'H')
76+ flags |= AT_SYMLINK_NOFOLLOW;
77+ while ((d = readdir(dp))) {
78+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
79+ continue;
80+ r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen);
81+ if (fstatat(fd, d->d_name, &dst, flags) < 0) {
82+ if (!(r->flags & SILENT)) {
83+ weprintf("stat %s:", r->path);
84+ recurse_status = 1;
85+ }
86+ } else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) {
87+ continue;
88+ } else {
89+ r->depth++;
90+ r->fn(fd, d->d_name, &dst, data, r);
91+ r->depth--;
92+ }
93+ }
94+ r->path[pathlen - 1] = '\0';
95+ r->pathlen = pathlen - 1;
96+ closedir(dp);
97+ }
98+
99+ if (!r->depth) {
100+ if (!(r->flags & DIRFIRST))
101+ r->fn(dirfd, name, &st, data, r);
102+
103+ while (r->hist) {
104+ h = r->hist;
105+ r->hist = r->hist->prev;
106+ free(h);
107+ }
108+ }
109+}
1@@ -0,0 +1,42 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <dirent.h>
4+#include <limits.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+#include <sys/stat.h>
9+#include <sys/types.h>
10+#include <unistd.h>
11+
12+#include "../util.h"
13+
14+void
15+recurse_dir(const char *path, void (*fn)(const char *))
16+{
17+ char buf[PATH_MAX];
18+ struct dirent *d;
19+ struct stat st;
20+ DIR *dp;
21+
22+ if (lstat(path, &st) == -1 || S_ISDIR(st.st_mode) == 0)
23+ return;
24+
25+ if (!(dp = opendir(path)))
26+ eprintf("opendir %s:", path);
27+
28+ while ((d = readdir(dp))) {
29+ if (strcmp(d->d_name, ".") == 0 ||
30+ strcmp(d->d_name, "..") == 0)
31+ continue;
32+ if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf))
33+ eprintf("path too long\n");
34+ if (buf[strlen(buf) - 1] != '/')
35+ if (strlcat(buf, "/", sizeof(buf)) >= sizeof(buf))
36+ eprintf("path too long\n");
37+ if (strlcat(buf, d->d_name, sizeof(buf)) >= sizeof(buf))
38+ eprintf("path too long\n");
39+ fn(buf);
40+ }
41+
42+ closedir(dp);
43+}
1@@ -0,0 +1,49 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/stat.h>
4+
5+#include <errno.h>
6+#include <fcntl.h>
7+#include <stdio.h>
8+#include <unistd.h>
9+
10+#include "../fs.h"
11+#include "../util.h"
12+
13+int rm_status = 0;
14+
15+void
16+rm(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
17+{
18+ int quiet, ask, write, flags, ignore;
19+
20+ ignore = r->flags & IGNORE;
21+ quiet = r->flags & SILENT;
22+ ask = r->flags & CONFIRM;
23+ write = S_ISLNK(st->st_mode) || faccessat(dirfd, name, W_OK, 0) == 0;
24+ flags = 0;
25+
26+ if (S_ISDIR(st->st_mode) && r->maxdepth) {
27+ errno = EISDIR;
28+ goto err;
29+ }
30+
31+ if (!quiet && (!write && isatty(0) || ask)) {
32+ if (!confirm("remove file '%s'? ", r->path))
33+ return;
34+ }
35+
36+ if (S_ISDIR(st->st_mode)) {
37+ flags = AT_REMOVEDIR;
38+ recurse(dirfd, name, NULL, r);
39+ }
40+
41+ if (unlinkat(dirfd, name, flags) < 0)
42+ goto err;
43+ return;
44+
45+err:
46+ if (!ignore) {
47+ weprintf("cannot remove '%s':", r->path);
48+ rm_status = 1;
49+ }
50+}
1@@ -0,0 +1,144 @@
2+/* public domain sha1 implementation based on rfc3174 and libtomcrypt */
3+#include <stdint.h>
4+#include <string.h>
5+
6+#include "../sha1.h"
7+
8+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
9+#define F0(b,c,d) (d ^ (b & (c ^ d)))
10+#define F1(b,c,d) (b ^ c ^ d)
11+#define F2(b,c,d) ((b & c) | (d & (b | c)))
12+#define F3(b,c,d) (b ^ c ^ d)
13+#define G0(a,b,c,d,e,i) e += rol(a,5)+F0(b,c,d)+W[i]+0x5A827999; b = rol(b,30)
14+#define G1(a,b,c,d,e,i) e += rol(a,5)+F1(b,c,d)+W[i]+0x6ED9EBA1; b = rol(b,30)
15+#define G2(a,b,c,d,e,i) e += rol(a,5)+F2(b,c,d)+W[i]+0x8F1BBCDC; b = rol(b,30)
16+#define G3(a,b,c,d,e,i) e += rol(a,5)+F3(b,c,d)+W[i]+0xCA62C1D6; b = rol(b,30)
17+
18+static void
19+processblock(struct sha1 *s, const uint8_t *buf)
20+{
21+ uint32_t W[80], a, b, c, d, e;
22+ int i;
23+
24+ for (i = 0; i < 16; i++) {
25+ W[i] = (uint32_t)buf[4*i]<<24;
26+ W[i] |= (uint32_t)buf[4*i+1]<<16;
27+ W[i] |= (uint32_t)buf[4*i+2]<<8;
28+ W[i] |= buf[4*i+3];
29+ }
30+ for (; i < 80; i++)
31+ W[i] = rol(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
32+ a = s->h[0];
33+ b = s->h[1];
34+ c = s->h[2];
35+ d = s->h[3];
36+ e = s->h[4];
37+ for (i = 0; i < 20; ) {
38+ G0(a,b,c,d,e,i++);
39+ G0(e,a,b,c,d,i++);
40+ G0(d,e,a,b,c,i++);
41+ G0(c,d,e,a,b,i++);
42+ G0(b,c,d,e,a,i++);
43+ }
44+ while (i < 40) {
45+ G1(a,b,c,d,e,i++);
46+ G1(e,a,b,c,d,i++);
47+ G1(d,e,a,b,c,i++);
48+ G1(c,d,e,a,b,i++);
49+ G1(b,c,d,e,a,i++);
50+ }
51+ while (i < 60) {
52+ G2(a,b,c,d,e,i++);
53+ G2(e,a,b,c,d,i++);
54+ G2(d,e,a,b,c,i++);
55+ G2(c,d,e,a,b,i++);
56+ G2(b,c,d,e,a,i++);
57+ }
58+ while (i < 80) {
59+ G3(a,b,c,d,e,i++);
60+ G3(e,a,b,c,d,i++);
61+ G3(d,e,a,b,c,i++);
62+ G3(c,d,e,a,b,i++);
63+ G3(b,c,d,e,a,i++);
64+ }
65+ s->h[0] += a;
66+ s->h[1] += b;
67+ s->h[2] += c;
68+ s->h[3] += d;
69+ s->h[4] += e;
70+}
71+
72+static void
73+pad(struct sha1 *s)
74+{
75+ unsigned r = s->len % 64;
76+
77+ s->buf[r++] = 0x80;
78+ if (r > 56) {
79+ memset(s->buf + r, 0, 64 - r);
80+ r = 0;
81+ processblock(s, s->buf);
82+ }
83+ memset(s->buf + r, 0, 56 - r);
84+ s->len *= 8;
85+ s->buf[56] = s->len >> 56;
86+ s->buf[57] = s->len >> 48;
87+ s->buf[58] = s->len >> 40;
88+ s->buf[59] = s->len >> 32;
89+ s->buf[60] = s->len >> 24;
90+ s->buf[61] = s->len >> 16;
91+ s->buf[62] = s->len >> 8;
92+ s->buf[63] = s->len;
93+ processblock(s, s->buf);
94+}
95+
96+void
97+sha1_init(void *ctx)
98+{
99+ struct sha1 *s = ctx;
100+
101+ s->len = 0;
102+ s->h[0] = 0x67452301;
103+ s->h[1] = 0xEFCDAB89;
104+ s->h[2] = 0x98BADCFE;
105+ s->h[3] = 0x10325476;
106+ s->h[4] = 0xC3D2E1F0;
107+}
108+
109+void
110+sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH])
111+{
112+ struct sha1 *s = ctx;
113+ int i;
114+
115+ pad(s);
116+ for (i = 0; i < 5; i++) {
117+ md[4*i] = s->h[i] >> 24;
118+ md[4*i+1] = s->h[i] >> 16;
119+ md[4*i+2] = s->h[i] >> 8;
120+ md[4*i+3] = s->h[i];
121+ }
122+}
123+
124+void
125+sha1_update(void *ctx, const void *m, unsigned long len)
126+{
127+ struct sha1 *s = ctx;
128+ const uint8_t *p = m;
129+ unsigned r = s->len % 64;
130+
131+ s->len += len;
132+ if (r) {
133+ if (len < 64 - r) {
134+ memcpy(s->buf + r, p, len);
135+ return;
136+ }
137+ memcpy(s->buf + r, p, 64 - r);
138+ len -= 64 - r;
139+ p += 64 - r;
140+ processblock(s, s->buf);
141+ }
142+ for (; len >= 64; len -= 64, p += 64)
143+ processblock(s, p);
144+ memcpy(s->buf, p, len);
145+}
1@@ -0,0 +1,26 @@
2+/* public domain sha224 implementation based on fips180-3 */
3+#include <stdint.h>
4+#include "../sha224.h"
5+
6+extern void sha256_sum_n(void *, uint8_t *, int n);
7+
8+void
9+sha224_init(void *ctx)
10+{
11+ struct sha224 *s = ctx;
12+ s->len = 0;
13+ s->h[0] = 0xc1059ed8;
14+ s->h[1] = 0x367cd507;
15+ s->h[2] = 0x3070dd17;
16+ s->h[3] = 0xf70e5939;
17+ s->h[4] = 0xffc00b31;
18+ s->h[5] = 0x68581511;
19+ s->h[6] = 0x64f98fa7;
20+ s->h[7] = 0xbefa4fa4;
21+}
22+
23+void
24+sha224_sum(void *ctx, uint8_t md[SHA224_DIGEST_LENGTH])
25+{
26+ sha256_sum_n(ctx, md, 7);
27+}
1@@ -0,0 +1,154 @@
2+/* public domain sha256 implementation based on fips180-3 */
3+#include <ctype.h>
4+#include <stdint.h>
5+#include <stdio.h>
6+#include <stdlib.h>
7+#include <string.h>
8+
9+#include "../sha256.h"
10+
11+static uint32_t ror(uint32_t n, int k) { return (n >> k) | (n << (32-k)); }
12+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
13+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
14+#define S0(x) (ror(x,2) ^ ror(x,13) ^ ror(x,22))
15+#define S1(x) (ror(x,6) ^ ror(x,11) ^ ror(x,25))
16+#define R0(x) (ror(x,7) ^ ror(x,18) ^ (x>>3))
17+#define R1(x) (ror(x,17) ^ ror(x,19) ^ (x>>10))
18+
19+static const uint32_t K[64] = {
20+0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
21+0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
22+0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
23+0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
24+0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
25+0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
26+0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
27+0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
28+};
29+
30+static void
31+processblock(struct sha256 *s, const uint8_t *buf)
32+{
33+ uint32_t W[64], t1, t2, a, b, c, d, e, f, g, h;
34+ int i;
35+
36+ for (i = 0; i < 16; i++) {
37+ W[i] = (uint32_t)buf[4*i]<<24;
38+ W[i] |= (uint32_t)buf[4*i+1]<<16;
39+ W[i] |= (uint32_t)buf[4*i+2]<<8;
40+ W[i] |= buf[4*i+3];
41+ }
42+ for (; i < 64; i++)
43+ W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
44+ a = s->h[0];
45+ b = s->h[1];
46+ c = s->h[2];
47+ d = s->h[3];
48+ e = s->h[4];
49+ f = s->h[5];
50+ g = s->h[6];
51+ h = s->h[7];
52+ for (i = 0; i < 64; i++) {
53+ t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
54+ t2 = S0(a) + Maj(a,b,c);
55+ h = g;
56+ g = f;
57+ f = e;
58+ e = d + t1;
59+ d = c;
60+ c = b;
61+ b = a;
62+ a = t1 + t2;
63+ }
64+ s->h[0] += a;
65+ s->h[1] += b;
66+ s->h[2] += c;
67+ s->h[3] += d;
68+ s->h[4] += e;
69+ s->h[5] += f;
70+ s->h[6] += g;
71+ s->h[7] += h;
72+}
73+
74+static void
75+pad(struct sha256 *s)
76+{
77+ unsigned r = s->len % 64;
78+
79+ s->buf[r++] = 0x80;
80+ if (r > 56) {
81+ memset(s->buf + r, 0, 64 - r);
82+ r = 0;
83+ processblock(s, s->buf);
84+ }
85+ memset(s->buf + r, 0, 56 - r);
86+ s->len *= 8;
87+ s->buf[56] = s->len >> 56;
88+ s->buf[57] = s->len >> 48;
89+ s->buf[58] = s->len >> 40;
90+ s->buf[59] = s->len >> 32;
91+ s->buf[60] = s->len >> 24;
92+ s->buf[61] = s->len >> 16;
93+ s->buf[62] = s->len >> 8;
94+ s->buf[63] = s->len;
95+ processblock(s, s->buf);
96+}
97+
98+void
99+sha256_init(void *ctx)
100+{
101+ struct sha256 *s = ctx;
102+ s->len = 0;
103+ s->h[0] = 0x6a09e667;
104+ s->h[1] = 0xbb67ae85;
105+ s->h[2] = 0x3c6ef372;
106+ s->h[3] = 0xa54ff53a;
107+ s->h[4] = 0x510e527f;
108+ s->h[5] = 0x9b05688c;
109+ s->h[6] = 0x1f83d9ab;
110+ s->h[7] = 0x5be0cd19;
111+}
112+
113+void
114+sha256_sum_n(void *ctx, uint8_t *md, int n)
115+{
116+ struct sha256 *s = ctx;
117+ int i;
118+
119+ pad(s);
120+ for (i = 0; i < n; i++) {
121+ md[4*i] = s->h[i] >> 24;
122+ md[4*i+1] = s->h[i] >> 16;
123+ md[4*i+2] = s->h[i] >> 8;
124+ md[4*i+3] = s->h[i];
125+ }
126+}
127+
128+void
129+sha256_sum(void *ctx, uint8_t md[SHA256_DIGEST_LENGTH])
130+{
131+ sha256_sum_n(ctx, md, 8);
132+}
133+
134+void
135+sha256_update(void *ctx, const void *m, unsigned long len)
136+{
137+ struct sha256 *s = ctx;
138+ const uint8_t *p = m;
139+ unsigned r = s->len % 64;
140+
141+ s->len += len;
142+ if (r) {
143+ if (len < 64 - r) {
144+ memcpy(s->buf + r, p, len);
145+ return;
146+ }
147+ memcpy(s->buf + r, p, 64 - r);
148+ len -= 64 - r;
149+ p += 64 - r;
150+ processblock(s, s->buf);
151+ }
152+ for (; len >= 64; len -= 64, p += 64)
153+ processblock(s, p);
154+ memcpy(s->buf, p, len);
155+}
1@@ -0,0 +1,26 @@
2+/* public domain sha384 implementation based on fips180-3 */
3+#include <stdint.h>
4+#include "../sha384.h"
5+
6+extern void sha512_sum_n(void *, uint8_t *, int n);
7+
8+void
9+sha384_init(void *ctx)
10+{
11+ struct sha384 *s = ctx;
12+ s->len = 0;
13+ s->h[0] = 0xcbbb9d5dc1059ed8ULL;
14+ s->h[1] = 0x629a292a367cd507ULL;
15+ s->h[2] = 0x9159015a3070dd17ULL;
16+ s->h[3] = 0x152fecd8f70e5939ULL;
17+ s->h[4] = 0x67332667ffc00b31ULL;
18+ s->h[5] = 0x8eb44a8768581511ULL;
19+ s->h[6] = 0xdb0c2e0d64f98fa7ULL;
20+ s->h[7] = 0x47b5481dbefa4fa4ULL;
21+}
22+
23+void
24+sha384_sum(void *ctx, uint8_t md[SHA384_DIGEST_LENGTH])
25+{
26+ sha512_sum_n(ctx, md, 6);
27+}
1@@ -0,0 +1,29 @@
2+/* public domain sha512/224 implementation based on fips180-3 */
3+#include <stdint.h>
4+#include <string.h>
5+#include "../sha512-224.h"
6+
7+extern void sha512_sum_n(void *, uint8_t *, int n);
8+
9+void
10+sha512_224_init(void *ctx)
11+{
12+ struct sha512_224 *s = ctx;
13+ s->len = 0;
14+ s->h[0] = 0x8c3d37c819544da2ULL;
15+ s->h[1] = 0x73e1996689dcd4d6ULL;
16+ s->h[2] = 0x1dfab7ae32ff9c82ULL;
17+ s->h[3] = 0x679dd514582f9fcfULL;
18+ s->h[4] = 0x0f6d2b697bd44da8ULL;
19+ s->h[5] = 0x77e36f7304c48942ULL;
20+ s->h[6] = 0x3f9d85a86a1d36c8ULL;
21+ s->h[7] = 0x1112e6ad91d692a1ULL;
22+}
23+
24+void
25+sha512_224_sum(void *ctx, uint8_t md[SHA512_224_DIGEST_LENGTH])
26+{
27+ uint8_t buf[32];
28+ sha512_sum_n(ctx, buf, 4);
29+ memcpy(md, buf, SHA512_224_DIGEST_LENGTH);
30+}
1@@ -0,0 +1,26 @@
2+/* public domain sha512/256 implementation based on fips180-3 */
3+#include <stdint.h>
4+#include "../sha512-256.h"
5+
6+extern void sha512_sum_n(void *, uint8_t *, int n);
7+
8+void
9+sha512_256_init(void *ctx)
10+{
11+ struct sha512_256 *s = ctx;
12+ s->len = 0;
13+ s->h[0] = 0x22312194fc2bf72cULL;
14+ s->h[1] = 0x9f555fa3c84c64c2ULL;
15+ s->h[2] = 0x2393b86b6f53b151ULL;
16+ s->h[3] = 0x963877195940eabdULL;
17+ s->h[4] = 0x96283ee2a88effe3ULL;
18+ s->h[5] = 0xbe5e1e2553863992ULL;
19+ s->h[6] = 0x2b0199fc2c85b8aaULL;
20+ s->h[7] = 0x0eb72ddc81c52ca2ULL;
21+}
22+
23+void
24+sha512_256_sum(void *ctx, uint8_t md[SHA512_256_DIGEST_LENGTH])
25+{
26+ sha512_sum_n(ctx, md, 4);
27+}
1@@ -0,0 +1,175 @@
2+/* public domain sha256 implementation based on fips180-3 */
3+
4+#include <ctype.h>
5+#include <stdint.h>
6+#include <stdio.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#include "../sha512.h"
11+
12+static uint64_t ror(uint64_t n, int k) { return (n >> k) | (n << (64-k)); }
13+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
14+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
15+#define S0(x) (ror(x,28) ^ ror(x,34) ^ ror(x,39))
16+#define S1(x) (ror(x,14) ^ ror(x,18) ^ ror(x,41))
17+#define R0(x) (ror(x,1) ^ ror(x,8) ^ (x>>7))
18+#define R1(x) (ror(x,19) ^ ror(x,61) ^ (x>>6))
19+
20+static const uint64_t K[80] = {
21+0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
22+0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
23+0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
24+0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
25+0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
26+0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
27+0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
28+0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
29+0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
30+0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
31+0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
32+0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
33+0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
34+0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
35+0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
36+0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
37+0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
38+0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
39+0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
40+0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
41+};
42+
43+static void
44+processblock(struct sha512 *s, const uint8_t *buf)
45+{
46+ uint64_t W[80], t1, t2, a, b, c, d, e, f, g, h;
47+ int i;
48+
49+ for (i = 0; i < 16; i++) {
50+ W[i] = (uint64_t)buf[8*i]<<56;
51+ W[i] |= (uint64_t)buf[8*i+1]<<48;
52+ W[i] |= (uint64_t)buf[8*i+2]<<40;
53+ W[i] |= (uint64_t)buf[8*i+3]<<32;
54+ W[i] |= (uint64_t)buf[8*i+4]<<24;
55+ W[i] |= (uint64_t)buf[8*i+5]<<16;
56+ W[i] |= (uint64_t)buf[8*i+6]<<8;
57+ W[i] |= buf[8*i+7];
58+ }
59+ for (; i < 80; i++)
60+ W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
61+ a = s->h[0];
62+ b = s->h[1];
63+ c = s->h[2];
64+ d = s->h[3];
65+ e = s->h[4];
66+ f = s->h[5];
67+ g = s->h[6];
68+ h = s->h[7];
69+ for (i = 0; i < 80; i++) {
70+ t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
71+ t2 = S0(a) + Maj(a,b,c);
72+ h = g;
73+ g = f;
74+ f = e;
75+ e = d + t1;
76+ d = c;
77+ c = b;
78+ b = a;
79+ a = t1 + t2;
80+ }
81+ s->h[0] += a;
82+ s->h[1] += b;
83+ s->h[2] += c;
84+ s->h[3] += d;
85+ s->h[4] += e;
86+ s->h[5] += f;
87+ s->h[6] += g;
88+ s->h[7] += h;
89+}
90+
91+static void
92+pad(struct sha512 *s)
93+{
94+ unsigned r = s->len % 128;
95+
96+ s->buf[r++] = 0x80;
97+ if (r > 112) {
98+ memset(s->buf + r, 0, 128 - r);
99+ r = 0;
100+ processblock(s, s->buf);
101+ }
102+ memset(s->buf + r, 0, 120 - r);
103+ s->len *= 8;
104+ s->buf[120] = s->len >> 56;
105+ s->buf[121] = s->len >> 48;
106+ s->buf[122] = s->len >> 40;
107+ s->buf[123] = s->len >> 32;
108+ s->buf[124] = s->len >> 24;
109+ s->buf[125] = s->len >> 16;
110+ s->buf[126] = s->len >> 8;
111+ s->buf[127] = s->len;
112+ processblock(s, s->buf);
113+}
114+
115+void
116+sha512_init(void *ctx)
117+{
118+ struct sha512 *s = ctx;
119+ s->len = 0;
120+ s->h[0] = 0x6a09e667f3bcc908ULL;
121+ s->h[1] = 0xbb67ae8584caa73bULL;
122+ s->h[2] = 0x3c6ef372fe94f82bULL;
123+ s->h[3] = 0xa54ff53a5f1d36f1ULL;
124+ s->h[4] = 0x510e527fade682d1ULL;
125+ s->h[5] = 0x9b05688c2b3e6c1fULL;
126+ s->h[6] = 0x1f83d9abfb41bd6bULL;
127+ s->h[7] = 0x5be0cd19137e2179ULL;
128+}
129+
130+void
131+sha512_sum_n(void *ctx, uint8_t *md, int n)
132+{
133+ struct sha512 *s = ctx;
134+ int i;
135+
136+ pad(s);
137+ for (i = 0; i < n; i++) {
138+ md[8*i] = s->h[i] >> 56;
139+ md[8*i+1] = s->h[i] >> 48;
140+ md[8*i+2] = s->h[i] >> 40;
141+ md[8*i+3] = s->h[i] >> 32;
142+ md[8*i+4] = s->h[i] >> 24;
143+ md[8*i+5] = s->h[i] >> 16;
144+ md[8*i+6] = s->h[i] >> 8;
145+ md[8*i+7] = s->h[i];
146+ }
147+}
148+
149+void
150+sha512_sum(void *ctx, uint8_t md[SHA512_DIGEST_LENGTH])
151+{
152+ sha512_sum_n(ctx, md, 8);
153+}
154+
155+void
156+sha512_update(void *ctx, const void *m, unsigned long len)
157+{
158+ struct sha512 *s = ctx;
159+ const uint8_t *p = m;
160+ unsigned r = s->len % 128;
161+
162+ s->len += len;
163+ if (r) {
164+ if (len < 128 - r) {
165+ memcpy(s->buf + r, p, len);
166+ return;
167+ }
168+ memcpy(s->buf + r, p, 128 - r);
169+ len -= 128 - r;
170+ p += 128 - r;
171+ processblock(s, s->buf);
172+ }
173+ for (; len >= 128; len -= 128, p += 128)
174+ processblock(s, p);
175+ memcpy(s->buf, p, len);
176+}
1@@ -0,0 +1,38 @@
2+/*
3+ * Copyright 2005-2014 Rich Felker, et al.
4+ *
5+ * Permission is hereby granted, free of charge, to any person obtaining
6+ * a copy of this software and associated documentation files (the
7+ * "Software"), to deal in the Software without restriction, including
8+ * without limitation the rights to use, copy, modify, merge, publish,
9+ * distribute, sublicense, and/or sell copies of the Software, and to
10+ * permit persons to whom the Software is furnished to do so, subject to
11+ * the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be
14+ * included in all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+*/
24+#include <string.h>
25+#include <strings.h>
26+
27+#include "../util.h"
28+
29+char *
30+strcasestr(const char *h, const char *n)
31+{
32+ size_t l = strlen(n);
33+
34+ for (; *h; h++)
35+ if (!strncasecmp(h, n, l))
36+ return (char *)h;
37+
38+ return 0;
39+}
1@@ -0,0 +1,63 @@
2+/*
3+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
4+ *
5+ * Permission to use, copy, modify, and distribute this software for any
6+ * purpose with or without fee is hereby granted, provided that the above
7+ * copyright notice and this permission notice appear in all copies.
8+ *
9+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+ */
17+
18+#include <string.h>
19+#include <sys/types.h>
20+
21+#include "../util.h"
22+
23+/*
24+ * Appends src to string dst of size siz (unlike strncat, siz is the
25+ * full size of dst, not space left). At most siz-1 characters
26+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
27+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
28+ * If retval >= siz, truncation occurred.
29+ */
30+size_t
31+strlcat(char *dst, const char *src, size_t siz)
32+{
33+ char *d = dst;
34+ const char *s = src;
35+ size_t n = siz;
36+ size_t dlen;
37+ /* Find the end of dst and adjust bytes left but don't go past end */
38+ while (n-- != 0 && *d != '\0')
39+ d++;
40+ dlen = d - dst;
41+ n = siz - dlen;
42+ if (n == 0)
43+ return(dlen + strlen(s));
44+ while (*s != '\0') {
45+ if (n != 1) {
46+ *d++ = *s;
47+ n--;
48+ }
49+ s++;
50+ }
51+ *d = '\0';
52+ return(dlen + (s - src)); /* count does not include NUL */
53+}
54+
55+size_t
56+estrlcat(char *dst, const char *src, size_t siz)
57+{
58+ size_t ret;
59+
60+ if ((ret = strlcat(dst, src, siz)) >= siz)
61+ eprintf("strlcat: input string too long\n");
62+
63+ return ret;
64+}
1@@ -0,0 +1,59 @@
2+/*
3+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
4+ *
5+ * Permission to use, copy, modify, and distribute this software for any
6+ * purpose with or without fee is hereby granted, provided that the above
7+ * copyright notice and this permission notice appear in all copies.
8+ *
9+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+ */
17+
18+#include <string.h>
19+#include <sys/types.h>
20+
21+#include "../util.h"
22+
23+/*
24+ * Copy src to string dst of size siz. At most siz-1 characters
25+ * will be copied. Always NUL terminates (unless siz == 0).
26+ * Returns strlen(src); if retval >= siz, truncation occurred.
27+ */
28+size_t
29+strlcpy(char *dst, const char *src, size_t siz)
30+{
31+ char *d = dst;
32+ const char *s = src;
33+ size_t n = siz;
34+ /* Copy as many bytes as will fit */
35+ if (n != 0) {
36+ while (--n != 0) {
37+ if ((*d++ = *s++) == '\0')
38+ break;
39+ }
40+ }
41+ /* Not enough room in dst, add NUL and traverse rest of src */
42+ if (n == 0) {
43+ if (siz != 0)
44+ *d = '\0'; /* NUL-terminate dst */
45+ while (*s++)
46+ ;
47+ }
48+ return(s - src - 1); /* count does not include NUL */
49+}
50+
51+size_t
52+estrlcpy(char *dst, const char *src, size_t siz)
53+{
54+ size_t ret;
55+
56+ if ((ret = strlcpy(dst, src, siz)) >= siz)
57+ eprintf("strlcpy: input string too long\n");
58+
59+ return ret;
60+}
1@@ -0,0 +1,61 @@
2+/*
3+ * Copyright (c) 2002 J. Mallett. All rights reserved.
4+ * You may do whatever you want with this file as long as
5+ * the above copyright and this notice remain intact, along
6+ * with the following statement:
7+ * For the man who taught me vi, and who got too old, too young.
8+ */
9+
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+
14+#include "../util.h"
15+
16+/*
17+ * Replaces str with a string consisting of str with match replaced with
18+ * replstr as many times as can be done before the constructed string is
19+ * maxsize bytes large. It does not free the string pointed to by str, it
20+ * is up to the calling program to be sure that the original contents of
21+ * str as well as the new contents are handled in an appropriate manner.
22+ * If replstr is NULL, then that internally is changed to a nil-string, so
23+ * that we can still pretend to do somewhat meaningful substitution.
24+ * No value is returned.
25+ */
26+void
27+strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
28+{
29+ char *s1, *s2, *this;
30+ size_t matchlen, s2len;
31+ int n;
32+
33+ if ((s1 = *str) == NULL)
34+ return;
35+ s2 = emalloc(maxsize);
36+
37+ if (replstr == NULL)
38+ replstr = "";
39+
40+ if (match == NULL || *match == '\0' || strlen(s1) >= maxsize) {
41+ strlcpy(s2, s1, maxsize);
42+ goto done;
43+ }
44+
45+ *s2 = '\0';
46+ s2len = 0;
47+ matchlen = strlen(match);
48+ for (;;) {
49+ if ((this = strstr(s1, match)) == NULL)
50+ break;
51+ n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s",
52+ (int)(this - s1), s1, replstr);
53+ if (n == -1 || n + s2len + strlen(this + matchlen) >= maxsize)
54+ break; /* out of room */
55+ s2len += n;
56+ s1 = this + matchlen;
57+ }
58+ strlcpy(s2 + s2len, s1, maxsize - s2len);
59+done:
60+ *str = s2;
61+ return;
62+}
1@@ -0,0 +1,37 @@
2+/*
3+ * Copyright 2005-2014 Rich Felker, et al.
4+ *
5+ * Permission is hereby granted, free of charge, to any person obtaining
6+ * a copy of this software and associated documentation files (the
7+ * "Software"), to deal in the Software without restriction, including
8+ * without limitation the rights to use, copy, modify, merge, publish,
9+ * distribute, sublicense, and/or sell copies of the Software, and to
10+ * permit persons to whom the Software is furnished to do so, subject to
11+ * the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be
14+ * included in all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+*/
24+#include <string.h>
25+
26+#include "../util.h"
27+
28+char *
29+strsep(char **str, const char *sep)
30+{
31+ char *s = *str, *end;
32+ if (!s) return NULL;
33+ end = s + strcspn(s, sep);
34+ if (*end) *end++ = 0;
35+ else end = 0;
36+ *str = end;
37+ return s;
38+}
1@@ -0,0 +1,85 @@
2+/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
3+
4+/*
5+ * Copyright (c) 2004 Ted Unangst and Todd Miller
6+ * All rights reserved.
7+ *
8+ * Permission to use, copy, modify, and distribute this software for any
9+ * purpose with or without fee is hereby granted, provided that the above
10+ * copyright notice and this permission notice appear in all copies.
11+ *
12+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19+ */
20+
21+#include <errno.h>
22+#include <limits.h>
23+#include <stdlib.h>
24+
25+#include "../util.h"
26+
27+#define INVALID 1
28+#define TOOSMALL 2
29+#define TOOLARGE 3
30+
31+long long
32+strtonum(const char *numstr, long long minval, long long maxval,
33+ const char **errstrp)
34+{
35+ long long ll = 0;
36+ int error = 0;
37+ char *ep;
38+ struct errval {
39+ const char *errstr;
40+ int err;
41+ } ev[4] = {
42+ { NULL, 0 },
43+ { "invalid", EINVAL },
44+ { "too small", ERANGE },
45+ { "too large", ERANGE },
46+ };
47+
48+ ev[0].err = errno;
49+ errno = 0;
50+ if (minval > maxval) {
51+ error = INVALID;
52+ } else {
53+ ll = strtoll(numstr, &ep, 10);
54+ if (numstr == ep || *ep != '\0')
55+ error = INVALID;
56+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
57+ error = TOOSMALL;
58+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
59+ error = TOOLARGE;
60+ }
61+ if (errstrp != NULL)
62+ *errstrp = ev[error].errstr;
63+ errno = ev[error].err;
64+ if (error)
65+ ll = 0;
66+
67+ return (ll);
68+}
69+
70+long long
71+enstrtonum(int status, const char *numstr, long long minval, long long maxval)
72+{
73+ const char *errstr;
74+ long long ll;
75+
76+ ll = strtonum(numstr, minval, maxval, &errstr);
77+ if (errstr)
78+ enprintf(status, "strtonum %s: %s\n", numstr, errstr);
79+ return ll;
80+}
81+
82+long long
83+estrtonum(const char *numstr, long long minval, long long maxval)
84+{
85+ return enstrtonum(1, numstr, minval, maxval);
86+}
1@@ -0,0 +1,98 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/sysmacros.h>
4+#include <sys/types.h>
5+#include <sys/stat.h>
6+
7+#include <fcntl.h>
8+#include <dirent.h>
9+#include <limits.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+
15+#include "../util.h"
16+
17+void
18+devtotty(int dev, int *tty_maj, int *tty_min)
19+{
20+ *tty_maj = (dev >> 8) & 0xfff;
21+ *tty_min = (dev & 0xff) | ((dev >> 12) & 0xfff00);
22+}
23+
24+int
25+ttytostr(int tty_maj, int tty_min, char *str, size_t n)
26+{
27+ struct stat sb;
28+ struct dirent *dp;
29+ DIR *dirp;
30+ char path[PATH_MAX];
31+ int fd;
32+ int r = 0;
33+
34+ switch (tty_maj) {
35+ case 136:
36+ snprintf(str, n, "pts/%d", tty_min);
37+ return 0;
38+ case 4:
39+ snprintf(str, n, "tty%d", tty_min);
40+ return 0;
41+ default:
42+ str[0] = '?';
43+ str[1] = '\0';
44+ break;
45+ }
46+
47+ dirp = opendir("/dev");
48+ if (!dirp) {
49+ weprintf("opendir /dev:");
50+ return -1;
51+ }
52+
53+ while ((dp = readdir(dirp))) {
54+ if (!strcmp(dp->d_name, ".") ||
55+ !strcmp(dp->d_name, ".."))
56+ continue;
57+
58+ if (strlcpy(path, "/dev/", sizeof(path)) >= sizeof(path)) {
59+ weprintf("path too long\n");
60+ r = -1;
61+ goto err0;
62+ }
63+ if (strlcat(path, dp->d_name, sizeof(path)) >= sizeof(path)) {
64+ weprintf("path too long\n");
65+ r = -1;
66+ goto err0;
67+ }
68+
69+ if (stat(path, &sb) < 0) {
70+ weprintf("stat %s:", path);
71+ r = -1;
72+ goto err0;
73+ }
74+
75+ if ((int)major(sb.st_rdev) == tty_maj &&
76+ (int)minor(sb.st_rdev) == tty_min) {
77+ fd = open(path, O_RDONLY | O_NONBLOCK);
78+ if (fd < 0)
79+ continue;
80+ if (isatty(fd)) {
81+ strlcpy(str, dp->d_name, n);
82+ close(fd);
83+ break;
84+ } else {
85+ close(fd);
86+ r = -1;
87+ goto err0;
88+ }
89+ }
90+ }
91+
92+err0:
93+ if (closedir(dirp) < 0) {
94+ weprintf("closedir /dev:");
95+ r = -1;
96+ }
97+
98+ return r;
99+}
1@@ -0,0 +1,58 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <ctype.h>
4+#include <string.h>
5+
6+#include "../util.h"
7+
8+#define is_odigit(c) ('0' <= c && c <= '7')
9+
10+size_t
11+unescape(char *s)
12+{
13+ static const char escapes[256] = {
14+ ['"'] = '"',
15+ ['\''] = '\'',
16+ ['\\'] = '\\',
17+ ['a'] = '\a',
18+ ['b'] = '\b',
19+ ['E'] = 033,
20+ ['e'] = 033,
21+ ['f'] = '\f',
22+ ['n'] = '\n',
23+ ['r'] = '\r',
24+ ['t'] = '\t',
25+ ['v'] = '\v'
26+ };
27+ size_t m, q;
28+ char *r, *w;
29+
30+ for (r = w = s; *r;) {
31+ if (*r != '\\') {
32+ *w++ = *r++;
33+ continue;
34+ }
35+ r++;
36+ if (!*r) {
37+ eprintf("null escape sequence\n");
38+ } else if (escapes[(unsigned char)*r]) {
39+ *w++ = escapes[(unsigned char)*r++];
40+ } else if (is_odigit(*r)) {
41+ for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
42+ q = q * 8 + (*r - '0');
43+ *w++ = MIN(q, 255);
44+ } else if (*r == 'x' && isxdigit(r[1])) {
45+ r++;
46+ for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
47+ if (isdigit(*r))
48+ q = q * 16 + (*r - '0');
49+ else
50+ q = q * 16 + (tolower(*r) - 'a' + 10);
51+ *w++ = q;
52+ } else {
53+ eprintf("invalid escape sequence '\\%c'\n", *r);
54+ }
55+ }
56+ *w = '\0';
57+
58+ return w - s;
59+}
1@@ -0,0 +1,21 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <unistd.h>
4+
5+#include "../util.h"
6+
7+ssize_t
8+writeall(int fd, const void *buf, size_t len)
9+{
10+ const char *p = buf;
11+ ssize_t n;
12+
13+ while (len) {
14+ n = write(fd, p, len);
15+ if (n <= 0)
16+ return n;
17+ p += n;
18+ len -= n;
19+ }
20+
21+ return p - (const char *)buf;
22+}
1@@ -0,0 +1,18 @@
2+/* public domain md5 implementation based on rfc1321 and libtomcrypt */
3+
4+struct md5 {
5+ uint64_t len; /* processed message length */
6+ uint32_t h[4]; /* hash state */
7+ uint8_t buf[64]; /* message block buffer */
8+};
9+
10+enum { MD5_DIGEST_LENGTH = 16 };
11+
12+/* reset state */
13+void md5_init(void *ctx);
14+/* process message */
15+void md5_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void md5_sum(void *ctx, uint8_t md[MD5_DIGEST_LENGTH]);
1@@ -0,0 +1,4 @@
2+/* See LICENSE file for copyright and license details. */
3+/* passwd.c */
4+int pw_check(const struct passwd *, const char *);
5+int pw_init(void);
1@@ -0,0 +1,42 @@
2+/* See LICENSE file for copyright and license details. */
3+struct procstat {
4+ int pid;
5+ char comm[PATH_MAX + 2]; /* + 2 for '(' and ')' */
6+ unsigned char state;
7+ int ppid;
8+ int pgrp;
9+ int sid;
10+ int tty_nr;
11+ int tpgid;
12+ unsigned flags;
13+ unsigned long minflt;
14+ unsigned long cminflt;
15+ unsigned long majflt;
16+ unsigned long cmajflt;
17+ unsigned long utime;
18+ unsigned long stime;
19+ long cutime;
20+ long cstime;
21+ long priority;
22+ long nice;
23+ long num_threads;
24+ long itrealvalue;
25+ unsigned long long starttime;
26+ unsigned long vsize;
27+ long rss;
28+ long rsslim;
29+};
30+
31+struct procstatus {
32+ uid_t uid;
33+ uid_t euid;
34+ gid_t gid;
35+ gid_t egid;
36+};
37+
38+int parsecmdline(pid_t pid, char *buf, size_t siz);
39+int parsestat(pid_t pid, struct procstat *ps);
40+int parsestatus(pid_t pid, struct procstatus *pstatus);
41+int proceuid(pid_t pid, uid_t *euid);
42+int procuid(pid_t pid, uid_t *euid);
43+int pidfile(const char *file);
1@@ -0,0 +1,648 @@
2+/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
3+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
4+
5+/*
6+ * Copyright (c) 1991, 1993
7+ * The Regents of the University of California. All rights reserved.
8+ *
9+ * Redistribution and use in source and binary forms, with or without
10+ * modification, are permitted provided that the following conditions
11+ * are met:
12+ * 1. Redistributions of source code must retain the above copyright
13+ * notice, this list of conditions and the following disclaimer.
14+ * 2. Redistributions in binary form must reproduce the above copyright
15+ * notice, this list of conditions and the following disclaimer in the
16+ * documentation and/or other materials provided with the distribution.
17+ * 3. Neither the name of the University nor the names of its contributors
18+ * may be used to endorse or promote products derived from this software
19+ * without specific prior written permission.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31+ * SUCH DAMAGE.
32+ *
33+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
34+ */
35+
36+#ifndef _SYS_QUEUE_H_
37+#define _SYS_QUEUE_H_
38+
39+/*
40+ * This file defines five types of data structures: singly-linked lists,
41+ * lists, simple queues, tail queues, and circular queues.
42+ *
43+ *
44+ * A singly-linked list is headed by a single forward pointer. The elements
45+ * are singly linked for minimum space and pointer manipulation overhead at
46+ * the expense of O(n) removal for arbitrary elements. New elements can be
47+ * added to the list after an existing element or at the head of the list.
48+ * Elements being removed from the head of the list should use the explicit
49+ * macro for this purpose for optimum efficiency. A singly-linked list may
50+ * only be traversed in the forward direction. Singly-linked lists are ideal
51+ * for applications with large datasets and few or no removals or for
52+ * implementing a LIFO queue.
53+ *
54+ * A list is headed by a single forward pointer (or an array of forward
55+ * pointers for a hash table header). The elements are doubly linked
56+ * so that an arbitrary element can be removed without a need to
57+ * traverse the list. New elements can be added to the list before
58+ * or after an existing element or at the head of the list. A list
59+ * may only be traversed in the forward direction.
60+ *
61+ * A simple queue is headed by a pair of pointers, one the head of the
62+ * list and the other to the tail of the list. The elements are singly
63+ * linked to save space, so elements can only be removed from the
64+ * head of the list. New elements can be added to the list before or after
65+ * an existing element, at the head of the list, or at the end of the
66+ * list. A simple queue may only be traversed in the forward direction.
67+ *
68+ * A tail queue is headed by a pair of pointers, one to the head of the
69+ * list and the other to the tail of the list. The elements are doubly
70+ * linked so that an arbitrary element can be removed without a need to
71+ * traverse the list. New elements can be added to the list before or
72+ * after an existing element, at the head of the list, or at the end of
73+ * the list. A tail queue may be traversed in either direction.
74+ *
75+ * A circle queue is headed by a pair of pointers, one to the head of the
76+ * list and the other to the tail of the list. The elements are doubly
77+ * linked so that an arbitrary element can be removed without a need to
78+ * traverse the list. New elements can be added to the list before or after
79+ * an existing element, at the head of the list, or at the end of the list.
80+ * A circle queue may be traversed in either direction, but has a more
81+ * complex end of list detection.
82+ *
83+ * For details on the use of these macros, see the queue(3) manual page.
84+ */
85+
86+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
87+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
88+#else
89+#define _Q_INVALIDATE(a)
90+#endif
91+
92+/*
93+ * Singly-linked List definitions.
94+ */
95+#define SLIST_HEAD(name, type) \
96+struct name { \
97+ struct type *slh_first; /* first element */ \
98+}
99+
100+#define SLIST_HEAD_INITIALIZER(head) \
101+ { NULL }
102+
103+#define SLIST_ENTRY(type) \
104+struct { \
105+ struct type *sle_next; /* next element */ \
106+}
107+
108+/*
109+ * Singly-linked List access methods.
110+ */
111+#define SLIST_FIRST(head) ((head)->slh_first)
112+#define SLIST_END(head) NULL
113+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
114+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
115+
116+#define SLIST_FOREACH(var, head, field) \
117+ for((var) = SLIST_FIRST(head); \
118+ (var) != SLIST_END(head); \
119+ (var) = SLIST_NEXT(var, field))
120+
121+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
122+ for ((var) = SLIST_FIRST(head); \
123+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); \
124+ (var) = (tvar))
125+
126+/*
127+ * Singly-linked List functions.
128+ */
129+#define SLIST_INIT(head) { \
130+ SLIST_FIRST(head) = SLIST_END(head); \
131+}
132+
133+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
134+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
135+ (slistelm)->field.sle_next = (elm); \
136+} while (0)
137+
138+#define SLIST_INSERT_HEAD(head, elm, field) do { \
139+ (elm)->field.sle_next = (head)->slh_first; \
140+ (head)->slh_first = (elm); \
141+} while (0)
142+
143+#define SLIST_REMOVE_AFTER(elm, field) do { \
144+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
145+} while (0)
146+
147+#define SLIST_REMOVE_HEAD(head, field) do { \
148+ (head)->slh_first = (head)->slh_first->field.sle_next; \
149+} while (0)
150+
151+#define SLIST_REMOVE(head, elm, type, field) do { \
152+ if ((head)->slh_first == (elm)) { \
153+ SLIST_REMOVE_HEAD((head), field); \
154+ } else { \
155+ struct type *curelm = (head)->slh_first; \
156+ \
157+ while (curelm->field.sle_next != (elm)) \
158+ curelm = curelm->field.sle_next; \
159+ curelm->field.sle_next = \
160+ curelm->field.sle_next->field.sle_next; \
161+ _Q_INVALIDATE((elm)->field.sle_next); \
162+ } \
163+} while (0)
164+
165+/*
166+ * List definitions.
167+ */
168+#define LIST_HEAD(name, type) \
169+struct name { \
170+ struct type *lh_first; /* first element */ \
171+}
172+
173+#define LIST_HEAD_INITIALIZER(head) \
174+ { NULL }
175+
176+#define LIST_ENTRY(type) \
177+struct { \
178+ struct type *le_next; /* next element */ \
179+ struct type **le_prev; /* address of previous next element */ \
180+}
181+
182+/*
183+ * List access methods
184+ */
185+#define LIST_FIRST(head) ((head)->lh_first)
186+#define LIST_END(head) NULL
187+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
188+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
189+
190+#define LIST_FOREACH(var, head, field) \
191+ for((var) = LIST_FIRST(head); \
192+ (var)!= LIST_END(head); \
193+ (var) = LIST_NEXT(var, field))
194+
195+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
196+ for ((var) = LIST_FIRST(head); \
197+ (var) && ((tvar) = LIST_NEXT(var, field), 1); \
198+ (var) = (tvar))
199+
200+/*
201+ * List functions.
202+ */
203+#define LIST_INIT(head) do { \
204+ LIST_FIRST(head) = LIST_END(head); \
205+} while (0)
206+
207+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
208+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
209+ (listelm)->field.le_next->field.le_prev = \
210+ &(elm)->field.le_next; \
211+ (listelm)->field.le_next = (elm); \
212+ (elm)->field.le_prev = &(listelm)->field.le_next; \
213+} while (0)
214+
215+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
216+ (elm)->field.le_prev = (listelm)->field.le_prev; \
217+ (elm)->field.le_next = (listelm); \
218+ *(listelm)->field.le_prev = (elm); \
219+ (listelm)->field.le_prev = &(elm)->field.le_next; \
220+} while (0)
221+
222+#define LIST_INSERT_HEAD(head, elm, field) do { \
223+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
224+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
225+ (head)->lh_first = (elm); \
226+ (elm)->field.le_prev = &(head)->lh_first; \
227+} while (0)
228+
229+#define LIST_REMOVE(elm, field) do { \
230+ if ((elm)->field.le_next != NULL) \
231+ (elm)->field.le_next->field.le_prev = \
232+ (elm)->field.le_prev; \
233+ *(elm)->field.le_prev = (elm)->field.le_next; \
234+ _Q_INVALIDATE((elm)->field.le_prev); \
235+ _Q_INVALIDATE((elm)->field.le_next); \
236+} while (0)
237+
238+#define LIST_REPLACE(elm, elm2, field) do { \
239+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
240+ (elm2)->field.le_next->field.le_prev = \
241+ &(elm2)->field.le_next; \
242+ (elm2)->field.le_prev = (elm)->field.le_prev; \
243+ *(elm2)->field.le_prev = (elm2); \
244+ _Q_INVALIDATE((elm)->field.le_prev); \
245+ _Q_INVALIDATE((elm)->field.le_next); \
246+} while (0)
247+
248+/*
249+ * Simple queue definitions.
250+ */
251+#define SIMPLEQ_HEAD(name, type) \
252+struct name { \
253+ struct type *sqh_first; /* first element */ \
254+ struct type **sqh_last; /* addr of last next element */ \
255+}
256+
257+#define SIMPLEQ_HEAD_INITIALIZER(head) \
258+ { NULL, &(head).sqh_first }
259+
260+#define SIMPLEQ_ENTRY(type) \
261+struct { \
262+ struct type *sqe_next; /* next element */ \
263+}
264+
265+/*
266+ * Simple queue access methods.
267+ */
268+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
269+#define SIMPLEQ_END(head) NULL
270+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
271+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
272+
273+#define SIMPLEQ_FOREACH(var, head, field) \
274+ for((var) = SIMPLEQ_FIRST(head); \
275+ (var) != SIMPLEQ_END(head); \
276+ (var) = SIMPLEQ_NEXT(var, field))
277+
278+#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
279+ for ((var) = SIMPLEQ_FIRST(head); \
280+ (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
281+ (var) = (tvar))
282+
283+/*
284+ * Simple queue functions.
285+ */
286+#define SIMPLEQ_INIT(head) do { \
287+ (head)->sqh_first = NULL; \
288+ (head)->sqh_last = &(head)->sqh_first; \
289+} while (0)
290+
291+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
292+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
293+ (head)->sqh_last = &(elm)->field.sqe_next; \
294+ (head)->sqh_first = (elm); \
295+} while (0)
296+
297+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
298+ (elm)->field.sqe_next = NULL; \
299+ *(head)->sqh_last = (elm); \
300+ (head)->sqh_last = &(elm)->field.sqe_next; \
301+} while (0)
302+
303+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
304+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
305+ (head)->sqh_last = &(elm)->field.sqe_next; \
306+ (listelm)->field.sqe_next = (elm); \
307+} while (0)
308+
309+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
310+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
311+ (head)->sqh_last = &(head)->sqh_first; \
312+} while (0)
313+
314+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
315+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
316+ == NULL) \
317+ (head)->sqh_last = &(elm)->field.sqe_next; \
318+} while (0)
319+
320+/*
321+ * XOR Simple queue definitions.
322+ */
323+#define XSIMPLEQ_HEAD(name, type) \
324+struct name { \
325+ struct type *sqx_first; /* first element */ \
326+ struct type **sqx_last; /* addr of last next element */ \
327+ unsigned long sqx_cookie; \
328+}
329+
330+#define XSIMPLEQ_ENTRY(type) \
331+struct { \
332+ struct type *sqx_next; /* next element */ \
333+}
334+
335+/*
336+ * XOR Simple queue access methods.
337+ */
338+#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
339+ (unsigned long)(ptr)))
340+#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
341+#define XSIMPLEQ_END(head) NULL
342+#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
343+#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
344+
345+
346+#define XSIMPLEQ_FOREACH(var, head, field) \
347+ for ((var) = XSIMPLEQ_FIRST(head); \
348+ (var) != XSIMPLEQ_END(head); \
349+ (var) = XSIMPLEQ_NEXT(head, var, field))
350+
351+#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
352+ for ((var) = XSIMPLEQ_FIRST(head); \
353+ (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
354+ (var) = (tvar))
355+
356+/*
357+ * XOR Simple queue functions.
358+ */
359+#define XSIMPLEQ_INIT(head) do { \
360+ arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
361+ (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
362+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
363+} while (0)
364+
365+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
366+ if (((elm)->field.sqx_next = (head)->sqx_first) == \
367+ XSIMPLEQ_XOR(head, NULL)) \
368+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
369+ (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
370+} while (0)
371+
372+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
373+ (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
374+ *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
375+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
376+} while (0)
377+
378+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
379+ if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
380+ XSIMPLEQ_XOR(head, NULL)) \
381+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
382+ (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
383+} while (0)
384+
385+#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
386+ if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
387+ (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
388+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
389+} while (0)
390+
391+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
392+ if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
393+ (elm)->field.sqx_next)->field.sqx_next) \
394+ == XSIMPLEQ_XOR(head, NULL)) \
395+ (head)->sqx_last = \
396+ XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
397+} while (0)
398+
399+
400+/*
401+ * Tail queue definitions.
402+ */
403+#define TAILQ_HEAD(name, type) \
404+struct name { \
405+ struct type *tqh_first; /* first element */ \
406+ struct type **tqh_last; /* addr of last next element */ \
407+}
408+
409+#define TAILQ_HEAD_INITIALIZER(head) \
410+ { NULL, &(head).tqh_first }
411+
412+#define TAILQ_ENTRY(type) \
413+struct { \
414+ struct type *tqe_next; /* next element */ \
415+ struct type **tqe_prev; /* address of previous next element */ \
416+}
417+
418+/*
419+ * tail queue access methods
420+ */
421+#define TAILQ_FIRST(head) ((head)->tqh_first)
422+#define TAILQ_END(head) NULL
423+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
424+#define TAILQ_LAST(head, headname) \
425+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
426+/* XXX */
427+#define TAILQ_PREV(elm, headname, field) \
428+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
429+#define TAILQ_EMPTY(head) \
430+ (TAILQ_FIRST(head) == TAILQ_END(head))
431+
432+#define TAILQ_FOREACH(var, head, field) \
433+ for((var) = TAILQ_FIRST(head); \
434+ (var) != TAILQ_END(head); \
435+ (var) = TAILQ_NEXT(var, field))
436+
437+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
438+ for ((var) = TAILQ_FIRST(head); \
439+ (var) != TAILQ_END(head) && \
440+ ((tvar) = TAILQ_NEXT(var, field), 1); \
441+ (var) = (tvar))
442+
443+
444+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
445+ for((var) = TAILQ_LAST(head, headname); \
446+ (var) != TAILQ_END(head); \
447+ (var) = TAILQ_PREV(var, headname, field))
448+
449+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
450+ for ((var) = TAILQ_LAST(head, headname); \
451+ (var) != TAILQ_END(head) && \
452+ ((tvar) = TAILQ_PREV(var, headname, field), 1); \
453+ (var) = (tvar))
454+
455+/*
456+ * Tail queue functions.
457+ */
458+#define TAILQ_INIT(head) do { \
459+ (head)->tqh_first = NULL; \
460+ (head)->tqh_last = &(head)->tqh_first; \
461+} while (0)
462+
463+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
464+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
465+ (head)->tqh_first->field.tqe_prev = \
466+ &(elm)->field.tqe_next; \
467+ else \
468+ (head)->tqh_last = &(elm)->field.tqe_next; \
469+ (head)->tqh_first = (elm); \
470+ (elm)->field.tqe_prev = &(head)->tqh_first; \
471+} while (0)
472+
473+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
474+ (elm)->field.tqe_next = NULL; \
475+ (elm)->field.tqe_prev = (head)->tqh_last; \
476+ *(head)->tqh_last = (elm); \
477+ (head)->tqh_last = &(elm)->field.tqe_next; \
478+} while (0)
479+
480+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
481+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
482+ (elm)->field.tqe_next->field.tqe_prev = \
483+ &(elm)->field.tqe_next; \
484+ else \
485+ (head)->tqh_last = &(elm)->field.tqe_next; \
486+ (listelm)->field.tqe_next = (elm); \
487+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
488+} while (0)
489+
490+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
491+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
492+ (elm)->field.tqe_next = (listelm); \
493+ *(listelm)->field.tqe_prev = (elm); \
494+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
495+} while (0)
496+
497+#define TAILQ_REMOVE(head, elm, field) do { \
498+ if (((elm)->field.tqe_next) != NULL) \
499+ (elm)->field.tqe_next->field.tqe_prev = \
500+ (elm)->field.tqe_prev; \
501+ else \
502+ (head)->tqh_last = (elm)->field.tqe_prev; \
503+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
504+ _Q_INVALIDATE((elm)->field.tqe_prev); \
505+ _Q_INVALIDATE((elm)->field.tqe_next); \
506+} while (0)
507+
508+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
509+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
510+ (elm2)->field.tqe_next->field.tqe_prev = \
511+ &(elm2)->field.tqe_next; \
512+ else \
513+ (head)->tqh_last = &(elm2)->field.tqe_next; \
514+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
515+ *(elm2)->field.tqe_prev = (elm2); \
516+ _Q_INVALIDATE((elm)->field.tqe_prev); \
517+ _Q_INVALIDATE((elm)->field.tqe_next); \
518+} while (0)
519+
520+/*
521+ * Circular queue definitions.
522+ */
523+#define CIRCLEQ_HEAD(name, type) \
524+struct name { \
525+ struct type *cqh_first; /* first element */ \
526+ struct type *cqh_last; /* last element */ \
527+}
528+
529+#define CIRCLEQ_HEAD_INITIALIZER(head) \
530+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
531+
532+#define CIRCLEQ_ENTRY(type) \
533+struct { \
534+ struct type *cqe_next; /* next element */ \
535+ struct type *cqe_prev; /* previous element */ \
536+}
537+
538+/*
539+ * Circular queue access methods
540+ */
541+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
542+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
543+#define CIRCLEQ_END(head) ((void *)(head))
544+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
545+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
546+#define CIRCLEQ_EMPTY(head) \
547+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
548+
549+#define CIRCLEQ_FOREACH(var, head, field) \
550+ for((var) = CIRCLEQ_FIRST(head); \
551+ (var) != CIRCLEQ_END(head); \
552+ (var) = CIRCLEQ_NEXT(var, field))
553+
554+#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
555+ for ((var) = CIRCLEQ_FIRST(head); \
556+ (var) != CIRCLEQ_END(head) && \
557+ ((tvar) = CIRCLEQ_NEXT(var, field), 1); \
558+ (var) = (tvar))
559+
560+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
561+ for((var) = CIRCLEQ_LAST(head); \
562+ (var) != CIRCLEQ_END(head); \
563+ (var) = CIRCLEQ_PREV(var, field))
564+
565+#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
566+ for ((var) = CIRCLEQ_LAST(head, headname); \
567+ (var) != CIRCLEQ_END(head) && \
568+ ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
569+ (var) = (tvar))
570+
571+/*
572+ * Circular queue functions.
573+ */
574+#define CIRCLEQ_INIT(head) do { \
575+ (head)->cqh_first = CIRCLEQ_END(head); \
576+ (head)->cqh_last = CIRCLEQ_END(head); \
577+} while (0)
578+
579+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
580+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
581+ (elm)->field.cqe_prev = (listelm); \
582+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
583+ (head)->cqh_last = (elm); \
584+ else \
585+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
586+ (listelm)->field.cqe_next = (elm); \
587+} while (0)
588+
589+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
590+ (elm)->field.cqe_next = (listelm); \
591+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
592+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
593+ (head)->cqh_first = (elm); \
594+ else \
595+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
596+ (listelm)->field.cqe_prev = (elm); \
597+} while (0)
598+
599+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
600+ (elm)->field.cqe_next = (head)->cqh_first; \
601+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
602+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
603+ (head)->cqh_last = (elm); \
604+ else \
605+ (head)->cqh_first->field.cqe_prev = (elm); \
606+ (head)->cqh_first = (elm); \
607+} while (0)
608+
609+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
610+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
611+ (elm)->field.cqe_prev = (head)->cqh_last; \
612+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
613+ (head)->cqh_first = (elm); \
614+ else \
615+ (head)->cqh_last->field.cqe_next = (elm); \
616+ (head)->cqh_last = (elm); \
617+} while (0)
618+
619+#define CIRCLEQ_REMOVE(head, elm, field) do { \
620+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
621+ (head)->cqh_last = (elm)->field.cqe_prev; \
622+ else \
623+ (elm)->field.cqe_next->field.cqe_prev = \
624+ (elm)->field.cqe_prev; \
625+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
626+ (head)->cqh_first = (elm)->field.cqe_next; \
627+ else \
628+ (elm)->field.cqe_prev->field.cqe_next = \
629+ (elm)->field.cqe_next; \
630+ _Q_INVALIDATE((elm)->field.cqe_prev); \
631+ _Q_INVALIDATE((elm)->field.cqe_next); \
632+} while (0)
633+
634+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
635+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
636+ CIRCLEQ_END(head)) \
637+ (head)->cqh_last = (elm2); \
638+ else \
639+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
640+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
641+ CIRCLEQ_END(head)) \
642+ (head)->cqh_first = (elm2); \
643+ else \
644+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
645+ _Q_INVALIDATE((elm)->field.cqe_prev); \
646+ _Q_INVALIDATE((elm)->field.cqe_next); \
647+} while (0)
648+
649+#endif /* !_SYS_QUEUE_H_ */
1@@ -0,0 +1,32 @@
2+/*
3+ * Magic values required to use _reboot() system call.
4+ */
5+
6+#define LINUX_REBOOT_MAGIC1 0xfee1dead
7+#define LINUX_REBOOT_MAGIC2 672274793
8+#define LINUX_REBOOT_MAGIC2A 85072278
9+#define LINUX_REBOOT_MAGIC2B 369367448
10+#define LINUX_REBOOT_MAGIC2C 537993216
11+
12+
13+/*
14+ * Commands accepted by the _reboot() system call.
15+ *
16+ * RESTART Restart system using default command and mode.
17+ * HALT Stop OS and give system control to ROM monitor, if any.
18+ * CAD_ON Ctrl-Alt-Del sequence causes RESTART command.
19+ * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task.
20+ * POWER_OFF Stop OS and remove all power from system, if possible.
21+ * RESTART2 Restart system using given command string.
22+ * SW_SUSPEND Suspend system using software suspend if compiled in.
23+ * KEXEC Restart system using a previously loaded Linux kernel
24+ */
25+
26+#define LINUX_REBOOT_CMD_RESTART 0x01234567
27+#define LINUX_REBOOT_CMD_HALT 0xCDEF0123
28+#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF
29+#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
30+#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
31+#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
32+#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2
33+#define LINUX_REBOOT_CMD_KEXEC 0x45584543
1@@ -0,0 +1,20 @@
2+/*
3+ * The struct used to pass data via the following ioctl. Similar to the
4+ * struct tm in <time.h>, but it needs to be here so that the kernel
5+ * source is self contained, allowing cross-compiles, etc. etc.
6+ */
7+
8+struct rtc_time {
9+ int tm_sec;
10+ int tm_min;
11+ int tm_hour;
12+ int tm_mday;
13+ int tm_mon;
14+ int tm_year;
15+ int tm_wday;
16+ int tm_yday;
17+ int tm_isdst;
18+};
19+
20+#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */
21+#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */
1@@ -0,0 +1,18 @@
2+/* public domain sha1 implementation based on rfc3174 and libtomcrypt */
3+
4+struct sha1 {
5+ uint64_t len; /* processed message length */
6+ uint32_t h[5]; /* hash state */
7+ uint8_t buf[64]; /* message block buffer */
8+};
9+
10+enum { SHA1_DIGEST_LENGTH = 20 };
11+
12+/* reset state */
13+void sha1_init(void *ctx);
14+/* process message */
15+void sha1_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void sha1_sum(void *ctx, uint8_t md[SHA1_DIGEST_LENGTH]);
1@@ -0,0 +1,16 @@
2+/* public domain sha224 implementation based on fips180-3 */
3+
4+#include "sha256.h"
5+
6+#define sha224 sha256 /*struct*/
7+
8+enum { SHA224_DIGEST_LENGTH = 28 };
9+
10+/* reset state */
11+void sha224_init(void *ctx);
12+/* process message */
13+#define sha224_update sha256_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha224_sum(void *ctx, uint8_t md[SHA224_DIGEST_LENGTH]);
1@@ -0,0 +1,18 @@
2+/* public domain sha256 implementation based on fips180-3 */
3+
4+struct sha256 {
5+ uint64_t len; /* processed message length */
6+ uint32_t h[8]; /* hash state */
7+ uint8_t buf[64]; /* message block buffer */
8+};
9+
10+enum { SHA256_DIGEST_LENGTH = 32 };
11+
12+/* reset state */
13+void sha256_init(void *ctx);
14+/* process message */
15+void sha256_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void sha256_sum(void *ctx, uint8_t md[SHA256_DIGEST_LENGTH]);
1@@ -0,0 +1,16 @@
2+/* public domain sha512 implementation based on fips180-3 */
3+
4+#include "sha512.h"
5+
6+#define sha384 sha512 /*struct*/
7+
8+enum { SHA384_DIGEST_LENGTH = 48 };
9+
10+/* reset state */
11+void sha384_init(void *ctx);
12+/* process message */
13+#define sha384_update sha512_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha384_sum(void *ctx, uint8_t md[SHA384_DIGEST_LENGTH]);
1@@ -0,0 +1,16 @@
2+/* public domain sha512/224 implementation based on fips180-3 */
3+
4+#include "sha512.h"
5+
6+#define sha512_224 sha512 /*struct*/
7+
8+enum { SHA512_224_DIGEST_LENGTH = 28 };
9+
10+/* reset state */
11+void sha512_224_init(void *ctx);
12+/* process message */
13+#define sha512_224_update sha512_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha512_224_sum(void *ctx, uint8_t md[SHA512_224_DIGEST_LENGTH]);
1@@ -0,0 +1,16 @@
2+/* public domain sha512/256 implementation based on fips180-3 */
3+
4+#include "sha512.h"
5+
6+#define sha512_256 sha512 /*struct*/
7+
8+enum { SHA512_256_DIGEST_LENGTH = 32 };
9+
10+/* reset state */
11+void sha512_256_init(void *ctx);
12+/* process message */
13+#define sha512_256_update sha512_update
14+/* get message digest */
15+/* state is ruined after sum, keep a copy if multiple sum is needed */
16+/* part of the message might be left in s, zero it if secrecy is needed */
17+void sha512_256_sum(void *ctx, uint8_t md[SHA512_256_DIGEST_LENGTH]);
1@@ -0,0 +1,18 @@
2+/* public domain sha512 implementation based on fips180-3 */
3+
4+struct sha512 {
5+ uint64_t len; /* processed message length */
6+ uint64_t h[8]; /* hash state */
7+ uint8_t buf[128]; /* message block buffer */
8+};
9+
10+enum { SHA512_DIGEST_LENGTH = 64 };
11+
12+/* reset state */
13+void sha512_init(void *ctx);
14+/* process message */
15+void sha512_update(void *ctx, const void *m, unsigned long len);
16+/* get message digest */
17+/* state is ruined after sum, keep a copy if multiple sum is needed */
18+/* part of the message might be left in s, zero it if secrecy is needed */
19+void sha512_sum(void *ctx, uint8_t md[SHA512_DIGEST_LENGTH]);
1@@ -0,0 +1,19 @@
2+/* See LICENSE file for copyright and license details. */
3+
4+struct line {
5+ char *data;
6+ size_t len;
7+};
8+
9+struct linebuf {
10+ struct line *lines;
11+ size_t nlines;
12+ size_t capacity;
13+};
14+#define EMPTY_LINEBUF {NULL, 0, 0,}
15+void getlines(FILE *, struct linebuf *);
16+
17+int linecmp(struct line *, struct line *);
18+
19+ssize_t agetline(char **, size_t *, FILE *);
20+void fconcat(FILE *, const char *, FILE *, const char *);
1@@ -0,0 +1,69 @@
2+/* MIT/X Consortium Copyright (c) 2012 Connor Lane Smith <cls@lubutu.com>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a
5+ * copy of this software and associated documentation files (the "Software"),
6+ * to deal in the Software without restriction, including without limitation
7+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+ * and/or sell copies of the Software, and to permit persons to whom the
9+ * Software is furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+ * DEALINGS IN THE SOFTWARE.
21+ */
22+#include <stdio.h>
23+
24+typedef int Rune;
25+
26+enum {
27+ UTFmax = 6, /* maximum bytes per rune */
28+ Runeself = 0x80, /* rune and utf are equal (<) */
29+ Runeerror = 0xFFFD, /* decoding error in utf */
30+ Runemax = 0x10FFFF /* maximum rune value */
31+};
32+
33+int runetochar(char *, const Rune *);
34+int chartorune(Rune *, const char *);
35+int charntorune(Rune *, const char *, size_t);
36+int runelen(Rune);
37+size_t runenlen(const Rune *, size_t);
38+int fullrune(const char *, size_t);
39+char *utfecpy(char *, char *, const char *);
40+size_t utflen(const char *);
41+size_t utfnlen(const char *, size_t);
42+size_t utfmemlen(const char *, size_t);
43+char *utfrune(const char *, Rune);
44+char *utfrrune(const char *, Rune);
45+char *utfutf(const char *, const char *);
46+
47+int isalnumrune(Rune);
48+int isalpharune(Rune);
49+int isblankrune(Rune);
50+int iscntrlrune(Rune);
51+int isdigitrune(Rune);
52+int isgraphrune(Rune);
53+int islowerrune(Rune);
54+int isprintrune(Rune);
55+int ispunctrune(Rune);
56+int isspacerune(Rune);
57+int istitlerune(Rune);
58+int isupperrune(Rune);
59+int isxdigitrune(Rune);
60+
61+Rune tolowerrune(Rune);
62+Rune toupperrune(Rune);
63+
64+size_t utftorunestr(const char *, Rune *);
65+size_t utfntorunestr(const char *, size_t, Rune *);
66+
67+int fgetrune(Rune *, FILE *);
68+int efgetrune(Rune *, FILE *, const char *);
69+int fputrune(const Rune *, FILE *);
70+int efputrune(const Rune *, FILE *, const char *);
1@@ -0,0 +1,108 @@
2+/* See LICENSE file for copyright and license details. */
3+#include <sys/types.h>
4+
5+#include <regex.h>
6+#include <stddef.h>
7+#include <stdio.h>
8+#include <stdarg.h>
9+
10+#include "arg.h"
11+#include "compat.h"
12+
13+#define UTF8_POINT(c) (((c) & 0xc0) != 0x80)
14+
15+#undef MIN
16+#define MIN(x,y) ((x) < (y) ? (x) : (y))
17+#undef MAX
18+#define MAX(x,y) ((x) > (y) ? (x) : (y))
19+#undef LIMIT
20+#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
21+
22+#define LEN(x) (sizeof (x) / sizeof *(x))
23+
24+extern char *argv0;
25+
26+void *ecalloc(size_t, size_t);
27+void *emalloc(size_t);
28+void *erealloc(void *, size_t);
29+#undef reallocarray
30+void *reallocarray(void *, size_t, size_t);
31+void *ereallocarray(void *, size_t, size_t);
32+char *estrdup(const char *);
33+char *estrndup(const char *, size_t);
34+void *encalloc(int, size_t, size_t);
35+void *enmalloc(int, size_t);
36+void *enrealloc(int, void *, size_t);
37+void *enreallocarray(int, void *, size_t, size_t);
38+char *enstrdup(int, const char *);
39+char *enstrndup(int, const char *, size_t);
40+
41+void enfshut(int, FILE *, const char *);
42+void efshut(FILE *, const char *);
43+int fshut(FILE *, const char *);
44+
45+void enprintf(int, const char *, ...);
46+void eprintf(const char *, ...);
47+void weprintf(const char *, ...);
48+void xvprintf(const char *, va_list);
49+
50+int confirm(const char*, ...);
51+
52+double estrtod(const char *);
53+
54+#undef strcasestr
55+#define strcasestr xstrcasestr
56+char *strcasestr(const char *, const char *);
57+
58+#undef strlcat
59+#define strlcat xstrlcat
60+size_t strlcat(char *, const char *, size_t);
61+size_t estrlcat(char *, const char *, size_t);
62+#undef strlcpy
63+#define strlcpy xstrlcpy
64+size_t strlcpy(char *, const char *, size_t);
65+size_t estrlcpy(char *, const char *, size_t);
66+
67+#undef strsep
68+#define strsep xstrsep
69+char *strsep(char **, const char *);
70+
71+void strnsubst(char **, const char *, const char *, size_t);
72+
73+/* regex */
74+int enregcomp(int, regex_t *, const char *, int);
75+int eregcomp(regex_t *, const char *, int);
76+
77+/* io */
78+ssize_t writeall(int, const void *, size_t);
79+int concat(int, const char *, int, const char *);
80+
81+/* misc */
82+void enmasse(int, char **, int (*)(const char *, const char *, int));
83+void fnck(const char *, const char *, int (*)(const char *, const char *, int), int);
84+mode_t getumask(void);
85+char *humansize(off_t);
86+mode_t parsemode(const char *, mode_t, mode_t);
87+off_t parseoffset(const char *);
88+void putword(FILE *, const char *);
89+#undef strtonum
90+#define strtonum xstrtonum
91+long long strtonum(const char *, long long, long long, const char **);
92+long long enstrtonum(int, const char *, long long, long long);
93+long long estrtonum(const char *, long long, long long);
94+size_t unescape(char *);
95+int mkdirp(const char *, mode_t, mode_t);
96+#undef memmem
97+#define memmem xmemmem
98+void *memmem(const void *, size_t, const void *, size_t);
99+
100+/* ubase functions */
101+char *agetcwd(void);
102+void apathmax(char **, long *);
103+long estrtol(const char *, int);
104+unsigned long estrtoul(const char *, int);
105+#undef explicit_bzero
106+void explicit_bzero(void *, size_t);
107+void recurse_dir(const char *, void (*)(const char *));
108+void devtotty(int, int *, int *);
109+int ttytostr(int, int, char *, size_t);