This patch was sent to me by Antti Kettunen <ank@iki.fi>
Details
- Reviewers
jilles mjg feld - Group Reviewers
manpages - Commits
- rS307769: daemon: Allow logging daemon stdout/stderr to file or syslog.
Diff Detail
- Repository
- rS FreeBSD src repository - subversion
- Lint
Lint Skipped - Unit
Tests Skipped
Event Timeline
usr.sbin/daemon/daemon.8 | ||
---|---|---|
66 | Use the serial comma: facility, priority, and tag, respectively. | |
68 | 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 | 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 | Please start new sentences on new lines. | |
119 | Please start new sentences on new lines. | |
123 | Again, this is not a path, and seems redundant. Just Log the output of the daemonized process to syslog. | |
125 | Please avoid "the following", especially when the subject is immediately following: These priorities are accepted: emerg, alert, crit, err, warning, |
usr.sbin/daemon/daemon.8 | ||
---|---|---|
75 | The default is 3, since neither the shell nor daemon(8) normally recognize things like STDOUT_FILENO. | |
197 | appending | |
usr.sbin/daemon/daemon.c | ||
52 | This is 4 more than 2**13. Is there a reason for this? | |
75 | 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. | |
114 | If you #define SYSLOG_NAMES, <syslog.h> provides similar tables so you don't need to duplicate code. | |
244 | Please keep the spaces here. | |
293 | 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. | |
337 | 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. | |
479 | Perhaps, output should be collected into lines here. | |
484 | Hmm, making outfile a file descriptor would lead to slightly less code. | |
515 | 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 ...) |
usr.sbin/daemon/daemon.c | ||
---|---|---|
52 | Memory failure, corrected to an exact exponent. | |
114 | Thanks, noted. I gave a look for this, because it felt like replication, but clearly didn't look hard enough. | |
293 | Noted, hopefully correctly. | |
337 | Noted, hopefully correctly. | |
479 | Noted as well. I'd appreciate a careful review of the coming changes which implement this. | |
515 | Noted. Kept this at waitpid(-1, ...) but now reaping until pid or error is seen. |
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 | ||
---|---|---|
478 | 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 | ||
---|---|---|
492 | Would make much more sense to assert(len < LBUF_SIZE);. It's unlikely that the buffer size would exceed INT_MAX. | |
551 | 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 | ||
---|---|---|
327 | 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. | |
422 | Common style is strcmp(...) == 0. | |
448 | 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. | |
452 | An initializer is unnecessary here, and { 0 } might (wrongly) cause compiler warnings. | |
489 | It would be wrong to retry after unknown errors, since the error would likely occur again immediately. | |
511 | If the signal handler only switches between two different code paths, why not simply use one signal handler per signal? :) | |
551 | Perhaps leave signals blocked during that time so there is never any question of races with pid. |
usr.sbin/daemon/daemon.c | ||
---|---|---|
327 | Noted, thanks. |
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 | But the second sentence is still on the same line... |
usr.sbin/daemon/daemon.c | ||
---|---|---|
204 | 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 | 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). |
usr.sbin/daemon/daemon.8 | ||
---|---|---|
65 | Thank you for noticing, I fumbled. | |
usr.sbin/daemon/daemon.c | ||
204 | 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. |
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
My apologies for the late addition. One more mistake fixed:
- Do not leak the log file descriptor to child by setting FD_CLOEXEC
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.
usr.sbin/daemon/daemon.c | ||
---|---|---|
174–175 | Oops, this is quite important. It can be done more easily using the open flag O_CLOEXEC. |
usr.sbin/daemon/daemon.c | ||
---|---|---|
173 | Why does this exit here as opposed to doing goto exit? Should the file be unlinked on failure of daemon(3)? |
usr.sbin/daemon/daemon.c | ||
---|---|---|
173 | Please not the above. |
usr.sbin/daemon/daemon.c | ||
---|---|---|
173 | 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 | Yep, open() is easier and saves us the trouble of separately handling the possible (unlikely?) fcntl() failure. |
usr.sbin/daemon/daemon.c | ||
---|---|---|
173 | 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. |
usr.sbin/daemon/daemon.c | ||
---|---|---|
173 | Ah, that's exactly right. It would be better to attempt the log open() before opening the pid files. |