I've been wanting to do this for a while now, as tar(1) used to
be one of messiest and cruftiest tools.
First off, before walking through the audit, I'll talk about
what the DIRFIRST-flag for recurse() does.
It basically calls fn() on the first-level-dir before calling
it's subentries. It's necessary here, because else the order
of the tar-files would've been wrong (it would try to create
dir/file before creating dir/).
Now, to the audit:
1) Update manpage, fix mistake that compression is also available
for compressing. It's only available for extracting.
2) Define the major, minor and makedev macros from glibc by ourselves.
No need to rely on them, as they are common sense.
decomp()
3) Simple refactorization.
putoctal()
4) Add a truncation check for snprintf().
archive()
5) BUGFIX: Add checks to any checkable function, don't blindly call
them, this is harmful and there are 100 ways to exploit that.
6) Use estrlcpy() instead of snprintf() wherever possible, fix
alignment.
7) BUGFIX: Terminate the result-buffer of readlink(), check if
it even succeeded.
8) Fix sizeof()-formatting.
unarchive()
9) BUGFIX: Add checks to any checkable function, don't blindly call
them, this is harmful and there are 100 ways to exploit that.
10) BUGFIX: strtoul can happily return negative numbers. Add checks
for that and also if the full string has been processed.
11) Remove calls to perror(). We have eprintf, use it.
12) BUGFIX: "minor = strtoul(h->mode, 0, 8);". We need h->minor of
course.
13) Fix typo "usupported", remove fprintf-call.
print()
14) Check fread().
xt()
15) Get rid of snprintf-magic. Use estrlcat().
16) BUGFIX: check for ferror() on the tarfile.
usage()
17) Update it. The old usage() was like 1000 years old.
main()
18) Add DIRFIRST-flag to the recursor.
19) Don't print usage() when a mode is re-set. We allow this in
general.
20) Add function checks and fix error messages.
21) Add tarfilename-global for proper error-messages.
1) Properly document e, f and m-flags in the manpage.
2) Clear up the code for the m-flag-handling. Add idiomatic
'/'-path-traversal as already seen in mkdir(1).
3) Unwrap the SWAP_BUF()-macro.
4) BUGFIX: Actually handle the f-flag properly. Only resolve
the dirname and append the basename later.
5) Use fputs() instead of printf("%s", ...).
Add "none" to ls, as all pending flags are optional.
sed is feature-complete, so I marked it like that. It needs an audit
though.
seq is implicitly UTF-8-ready, will be audited later.
I marked out -m, -s and -x, because they are either visual flags
for interactive mode, which are better solved with tools made for this
job, or superfluous in another sense.
For example, -s basically "steals" the job from du.
In general, some of these options might still be easy to implement.
The options -S and -f are important though, as they are sorting-options
with real use.
Only add empty lines before returns, everything else is ok.
Also add the STANDARDS-section to the manpage, which was only
present as a heading until now.
1) Specify default in manpage under flag.
2) Boolean and return value style fixes.
3) argv-argc-centric loop.
4) No need to check for argc == 1 before the fflag-subroutine.
5) Remove indentation.
6) Empty line before return.
1) Add usage().
2) Idiomatic argv0-setter. We don't use arg.h, as we do not process
flags or arguments.
3) Remove program-name from eprintf-call. This is done in the eprintf-
function itself when the DEBUG-define is set.
We'll activate it by default later.
4) Add empty line before return.
1) Refactor the manpage with num-options, optimize wording to be more
concise and to the point, pid also specifies process groups.
2) Make int sig const.
3) Remove prototypes.
4) /* not reached */ consistency.
5) Refactor usage() with eprintf.
6) Refactor arg-parser with a switch, use estrtonum
7) Use return instead of exit() in main()
8) argc-argv-correctness.
1) Use num-wording in the manpage, remove offensive remark against
the beloved -num-syntax <3.
2) Style changes.
3) Report errors of getline.
4) argv-argc-centric argument loop.
5) Rename r to ret for consistency.
1) Remove the return-value-enum, which is not necessary for a simple
program like this.
2) Don't disallow both l and s to be specified. This is undefined
behaviour defined by POSIX, so we don't start demanding things
from the user.
3) Replace exit() with return (we are in main).
4) Refactor main loop to never return in the loop, but actually
set the same-value and break, which increases readability.
5) Remove the final fclose()'s. The OS will take care of them, no
need to become cleansy here.
6) Use idiomatic return-value using same. This concludes the
increase of readability in the main-loop.
1) Reorder local variables.
2) Cleanup error messages, use %zu for size_t.
3) combine putchar(' ') and fputs to substitute printf(" %s", s).
4) Fix usage().
5) argv-argc-usage-fix.
6) Add empty line before return.
Similar to the chgrp(1)-audit:
1) Refactor manpage so it's actually fun to read
2) BUGFIX: Call (l)chown properly when the H-flag is specified
(only when depth > 0)
3) BUGFIX: Call (l)chown properly when the h-flag is specified
(only when depth = 0).
4) BUGFIX: Only recurse() in chgrp() when the initial chownf()
succeeds.
5) Style fixes, argv-basing.
6) Rename status to ret for consistency.
7) Add blank line before return.
1) Refactor manpage so it's actually fun to read.
2) BUGFIX: Call (l)chown properly when the H-flag is specified
(only when depth > 0).
3) BUGFIX: Call (l)chown properly when the h-flag is specified
(only when depth = 0).
4) BUGFIX: Only recurse() in chgrp() when the initial chownf()
succeeds.
5) Style fixes, argv-basing.
6) Rename status to ret for consistency.
7) Add blank line before return.
1) Update manpage with the num-syntax.
2) Use size_t for years and derivatives.
3) Use putchar instead of printf wherever possible.
4) Update usage().
5) Style changes.
1) Refactor manpage.
2) De-globalize local values.
3) update usage().
4) sort local variable declarations.
5) fix wrong argument in strtonum (3 -> 1).
6) argc-argv style, boolean style.
7) check bytes > 0 before accessing b.lines[i][bytes - 1]
relying on len only makes sense but let's not push it.
7) don't break on maxlen > (chars - 1) / 2. This didn't even
make sense.
8) _correctly_ calculate cols and rows in a readable way.
9) Rewrite loop over rows and cols in a readable way and
using putchar in a loop instead of printf-magic or fputs
where not necessary.
1) Clarify behaviour when the f-flag is given and a target is in its
own way.
2) Fix usage()-style.
3) Group local variable declarations.
4) reorder args
5) argc style, other boolean style changes
6) improve error messages
7) set argv[argc - 1] to NULL to allow argv-centric loop later
8) BUGFIX: POSIX specifies that when with the f-flag there's a
situation where a file stands in its own way for linking it
should be ignored.
9) Add weprintf() where possible, so we don't pussy out when there's
a small issue. This is sbase ffs!
1) Update manpage, refactor the HLP-section and other wordings.
2) BUGFIX: If chmod() fails, don't recurse.
3) Rewrite the arg-loop, fixing several issues:
BUGFIX: Handle multi-flags (e.g. -RH)
BUGFIX: Properly handle the termination flag --, error on e.g. --x
BUGFIX: Error out on an empty flag -.
4) Refactor logic after the arg-loop, which is now simpler thanks
to argv-incremention.
1) No need for strchr() in mkdirp or a while-loop. Rewrite it in
a sane and readable way.
2) fix usage according to the manpage.
3) order includes, don't align local variables.
4) argc-style-fix.
5) BUGFIX: Don't try to chmod() *argv when mkdir() / mkdirp() failed.
6) Add newline before return in two places.
1) Use (s)size_t in head().
2) BUGFIX: only check buf[len - 1] when len > 0, else there would
be an overflow when getline returns 0 (which can happen) and a
very potential segmentation fault.
3) fix error-messages.
4) update usage().
5) argv-argc-style.
6) clear up the main loop with if (newline).
7) add newline before return.
1) Make argument-naming consistent with other tools (cp(1), ...)
2) style fixes
3) usage() fix
4) BUGFIX: Probably from the old non-arg.h days, the directory-
check was only done when argc > 3, but with arg.h, this ignores
the case when 3 arguments were given.
This is actually a pretty serious issue and I'm glad it's fixed.
5) Moreover, be more verbose when stat() fails and make it clearer
what the hell is going on at this checkpoint.
1) "duplicate" implies that you can only specify two outputs,
"multiply" is a better word describing the functionality.
2) fix other wording in the manpage
3) fix usage()
4) reorder local variables
5) fix sizeof() style
6) we need argv later, don't increment argv and rather iterate
over argc.
7) Improve error messages, print the filename which the write
failed to instead of printing the buffer itself (how much
sense does that make, printing 1024 Bytes of garbage?).
Also, give the name of the function which failed.
1) no need to include sys/stat.h
2) remove the enum which just added a layer too thick on this simple
program
3) argc-style, other style
4) weprintf instead of enprintf, then save the error-message of
execvp before and return the proper status.
5) write consistent "not reached" comment.