Page MenuHomeFreeBSD

daemon(8): Alternate approach for logging via syslog
ClosedPublic

Authored by ank_iki.fi on Sep 21 2016, 7:42 PM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Dec 18, 10:15 PM
Unknown Object (File)
Wed, Dec 4, 12:33 PM
Unknown Object (File)
Nov 14 2024, 8:08 PM
Unknown Object (File)
Nov 8 2024, 5:57 AM
Unknown Object (File)
Oct 18 2024, 12:17 AM
Unknown Object (File)
Oct 4 2024, 11:44 PM
Unknown Object (File)
Oct 3 2024, 10:31 PM
Unknown Object (File)
Oct 2 2024, 8:30 PM

Details

Summary

This patch was sent to me by Antti Kettunen <ank@iki.fi>

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
usr.sbin/daemon/daemon.8
66 ↗(On Diff #20591)

Use the serial comma:

facility, priority, and tag, respectively.
68 ↗(On Diff #20591)

Why include the complexity of the and/or statement? That is not really relevant to this flag, which controls where the output goes, not which output. So maybe just

Redirect output from the daemonized process to
73 ↗(On Diff #20591)

This is not a path (.Pa), but also seems unnecessarily redundant. The sentence can end after (0) and this part can be deleted:

or neither (0).
74 ↗(On Diff #20591)

Please start new sentences on new lines.

119 ↗(On Diff #20591)

Please start new sentences on new lines.
s/Default/The default/

126 ↗(On Diff #20591)

Again, this is not a path, and seems redundant. Just

Log the output of the daemonized process to syslog.
128 ↗(On Diff #20591)

Please avoid "the following", especially when the subject is immediately following:

These priorities are accepted: emerg, alert, crit, err, warning,
jilles added inline comments.
usr.sbin/daemon/daemon.8
75 ↗(On Diff #20591)

The default is 3, since neither the shell nor daemon(8) normally recognize things like STDOUT_FILENO.

204 ↗(On Diff #20591)

appending

usr.sbin/daemon/daemon.c
51 ↗(On Diff #20591)

This is 4 more than 2**13. Is there a reason for this?

67 ↗(On Diff #20591)

POSIX is clear that variables to communicate with asynchronous signal handlers should be volatile sig_atomic_t, not just sig_atomic_t.

However, if you restore the masking, normal variables will do.

106 ↗(On Diff #20591)

If you #define SYSLOG_NAMES, <syslog.h> provides similar tables so you don't need to duplicate code.

244 ↗(On Diff #20591)

Please keep the spaces here.

284 ↗(On Diff #20591)

This can be made to work in the (admittedly unlikely) case that fd 1 and 2 are not open by closing pfd[0] before any dup2 and only closing pfd[1] if it is not equal to something it is to be dup2'ed to.

325 ↗(On Diff #20591)

This wakes up every second for no reason, which the old version did not do. Keeping the signal masking from the old version and unmasking around async-signal safe read() allows using sigsuspend() or sigwait() here.

430 ↗(On Diff #20591)

Perhaps, output should be collected into lines here.

435 ↗(On Diff #20591)

Hmm, making outfile a file descriptor would lead to slightly less code.

466 ↗(On Diff #20591)

The old code is not confused by unknown child processes but leaves them as zombies. I think the change to waitpid(-1 is good but successful return values other than pid should be ignored.

Example: (sleep 10 & exec daemon ...)

ank_iki.fi marked 34 inline comments as done.
ank_iki.fi added inline comments.
usr.sbin/daemon/daemon.c
51 ↗(On Diff #20591)

Memory failure, corrected to an exact exponent.

106 ↗(On Diff #20591)

Thanks, noted. I gave a look for this, because it felt like replication, but clearly didn't look hard enough.

284 ↗(On Diff #20591)

Noted, hopefully correctly.

325 ↗(On Diff #20591)

Noted, hopefully correctly.

430 ↗(On Diff #20591)

Noted as well. I'd appreciate a careful review of the coming changes which implement this.

466 ↗(On Diff #20591)

Noted. Kept this at waitpid(-1, ...) but now reaping until pid or error is seen.

ank_iki.fi edited edge metadata.
ank_iki.fi removed rS FreeBSD src repository - subversion as the repository for this revision.
ank_iki.fi marked 6 inline comments as done.

Addressed the review comments. Attempted to treat the documentation mishaps, signal handling, child-waiting, and dividing logging output into carriage return-separated lines. The last should be most beneficial for syslog purposes.

usr.sbin/daemon/daemon.c
471 ↗(On Diff #20686)

Needs bytes_read to be zeroed.

When updating the patch, I probably missed something so apparently linting and the compile test didn't run. Perhaps I should've manually added the source repository as rS FreeBSD src repository when submitting the updated revision and/or done something else?

usr.sbin/daemon/daemon.c
485 ↗(On Diff #20686)

Would make much more sense to assert(len < LBUF_SIZE);. It's unlikely that the buffer size would exceed INT_MAX.

519 ↗(On Diff #20686)

Probably we need to be extra careful here, because pid is -1 before forking. We wouldn't want to do kill(-1, SIGTERM)...

I think this is quite nice.

usr.sbin/daemon/daemon.c
302 ↗(On Diff #20686)

I think this can certainly be improved (e.g. optionally using procctl(PROC_REAP_ACQUIRE) and friends) but that should be in a later commit.

395 ↗(On Diff #20686)

Common style is strcmp(...) == 0.

422 ↗(On Diff #20686)

The latter four arguments pertain to where logs are going, and could be grouped into a structure to avoid dragging them along a few times.

426 ↗(On Diff #20686)

An initializer is unnecessary here, and { 0 } might (wrongly) cause compiler warnings.

463 ↗(On Diff #20686)

It would be wrong to retry after unknown errors, since the error would likely occur again immediately.

504 ↗(On Diff #20686)

If the signal handler only switches between two different code paths, why not simply use one signal handler per signal? :)

519 ↗(On Diff #20686)

Perhaps leave signals blocked during that time so there is never any question of races with pid.

ank_iki.fi marked 14 inline comments as done.
ank_iki.fi added inline comments.
usr.sbin/daemon/daemon.c
302 ↗(On Diff #20686)

Noted, thanks.

ank_iki.fi edited edge metadata.
ank_iki.fi marked an inline comment as done.

Fixes for the latest round of review

  • Split signal handler
  • Block SIGTERM until we have forked - currently we don't reblock it after the first fork
  • Some style(9) issues
  • Deliver logging parameters inside of a struct
  • assert more sensibly
  • Zero the read buffer counter when EOF flushing
usr.sbin/daemon/daemon.8
65 ↗(On Diff #20591)

But the second sentence is still on the same line...

usr.sbin/daemon/daemon.c
204 ↗(On Diff #20720)

The two handlers do indeed interfere, since calling waitpid() from the SIGCHLD handler invalidates the pid used by the SIGTERM handler (you'll get [ESRCH] or kill an unrelated process). The SIGTERM handler doesn't check for this yet (child_gone, probably, together with blocking SIGTERM before goto restart).

Note that this kind of PID reuse bug is inherent to the concept of pidfiles, but in this case it can be avoided.

296 ↗(On Diff #20720)

Looks good. I don't care about the case where someone wants to pass through a closed fd 1 log what's written to fd 2 (in that case fd 1 will also be a copy of the pipe).

ank_iki.fi marked 6 inline comments as done.
ank_iki.fi added inline comments.
usr.sbin/daemon/daemon.8
65 ↗(On Diff #20591)

Thank you for noticing, I fumbled.

usr.sbin/daemon/daemon.c
204 ↗(On Diff #20720)

Thank you again for the keen eye. I now explicitly block the opposites, and SIGTERM is blocked after leaving the handling loop. I suppose this still leaves a small window for a short-lived fork if we happen to block a SIGTERM just before the restart.

ank_iki.fi edited edge metadata.
ank_iki.fi marked 2 inline comments as done.

Adjusted the previous patch according to the received comments:

  • Fixed a man page issue
  • Explicitly block SIGTERM when handling SIGCHLD and vice versa
  • Block SIGTERM harder & observe child_gone to avoid signaling an already departed/nonexistent child

Additionally the following was done:

  • terminate = 1 is now done unconditionally when handling SIGTERM
  • Some clarifications to the man page to more coherently explain the meaning of and interplay of different options
  • Minor style issues were adjusted
  • Removed the remaining XXX comments after addressing the concerns

Man page looks okay to me. Thank you!

jilles edited edge metadata.
This revision is now accepted and ready to land.Oct 7 2016, 3:40 PM
ank_iki.fi edited edge metadata.

My apologies for the late addition. One more mistake fixed:

  • Do not leak the log file descriptor to child by setting FD_CLOEXEC
This revision now requires review to proceed.Oct 11 2016, 1:28 AM

Is this version now accepted? If so, can one of the technical reviewers commit it? If one of the reviewers approves I could commit it as well.

jilles requested changes to this revision.Oct 11 2016, 7:15 PM
jilles edited edge metadata.
jilles added inline comments.
usr.sbin/daemon/daemon.c
174–175 ↗(On Diff #21238)

Oops, this is quite important.

It can be done more easily using the open flag O_CLOEXEC.

This revision now requires changes to proceed.Oct 11 2016, 7:15 PM
usr.sbin/daemon/daemon.c
173 ↗(On Diff #21238)

Why does this exit here as opposed to doing goto exit?

Should the file be unlinked on failure of daemon(3)?

ank_iki.fi edited edge metadata.
  • Use O_CLOEXEC on log file open instead of explicit fcntl(...) call
usr.sbin/daemon/daemon.c
173 ↗(On Diff #21238)

Please not the above.

ank_iki.fi added inline comments.
usr.sbin/daemon/daemon.c
173 ↗(On Diff #21238)

If the fcntl() call failed, then we would have left a potentially empty file hanging around. Perhaps the users wouldn't expect this. There might have been a scenario, where we succesfully open() a log file for appending with some previous contents or append to a file, where something else is also writing. In these cases at least, I would definitely avoid unlinking. I suppose by handling the FD leak prevention through open(... O_CLOEXEC) we don't have to worry about this, but please correct me if I'm wrong.

174–175 ↗(On Diff #21238)

Yep, open() is easier and saves us the trouble of separately handling the possible (unlikely?) fcntl() failure.

usr.sbin/daemon/daemon.c
173 ↗(On Diff #21238)

The unlink was a minor point. I gave an example when it matters; daemon(3) call failing.

The actual point was the call to err as opposed to doing goto exit, which fails to clean up pidfiles.

ank_iki.fi added inline comments.
usr.sbin/daemon/daemon.c
173 ↗(On Diff #21238)

Ah, that's exactly right. It would be better to attempt the log open() before opening the pid files.

ank_iki.fi edited edge metadata.
  • Attempt the log file open() before trying to handle pid files
jilles edited edge metadata.
This revision is now accepted and ready to land.Oct 11 2016, 10:13 PM
This revision was automatically updated to reflect the committed changes.