diff --git a/atopacct.service b/atopacct.service index 1f51ec41..9065ada0 100644 --- a/atopacct.service +++ b/atopacct.service @@ -5,6 +5,11 @@ Conflicts=psacct.service After=syslog.target Before=atop.service +# Let's skip on containers here, at least for now. +# Currently, Linux Containers don't support process accounting +# (and failed services are painful for Debian-style packages). +ConditionVirtualization=!container + [Service] Type=forking PIDFile=/var/run/atopacctd.pid diff --git a/atopacctd.c b/atopacctd.c index a0c7f441..63bce347 100644 --- a/atopacctd.c +++ b/atopacctd.c @@ -119,11 +119,12 @@ int netlink_recv(int, int); // from netlink.c int main(int argc, char *argv[]) { - int i, nfd, afd, sfd; - int parentpid; + int i, rv, nfd, afd, sfd; struct stat dirstat; struct rlimit rlim; FILE *pidf; + int readypipe[2]; + int8_t ready; struct sembuf semincr = {0, +1, SEM_UNDO}; @@ -261,37 +262,59 @@ main(int argc, char *argv[]) } } - /* - ** prepare cleanup signal handler - */ - memset(&sigcleanup, 0, sizeof sigcleanup); - sigcleanup.sa_handler = cleanup; - sigemptyset(&sigcleanup.sa_mask); - /* ** daemonize this process ** i.e. be sure that the daemon is no session leader (any more) ** and get rid of a possible bad context that might have been ** inherited from ancestors */ - parentpid = getpid(); // to be killed when initialized - (void) sigaction(SIGTERM, &sigcleanup, (struct sigaction *)0); + if ( pipe(readypipe) == -1) + { + perror("cannot create readiness pipe"); + exit(4); + } + + rv = fork(); - if ( fork() ) // implicitly switch to background - { + if (rv == -1) + { + perror("cannot create process"); + exit(4); + } + + if (rv > 0) + { /* - ** parent after forking first child: - ** wait for signal 15 from child before terminating - ** because systemd expects parent to terminate whenever - ** service is up and running + ** parent after forking first child: + ** wait for message from child before terminating + ** because dependent services need parent to terminate + ** whenever service is up and running */ - pause(); // wait for signal from child - exit(0); // finish parent + + (void) close(readypipe[1]); // close write end of pipe + + rv = read(readypipe[0], &ready, sizeof(ready)); + + if (rv == sizeof(ready)) + exit(0); // service is ready now + else + exit(4); // service exited } + (void) close(readypipe[0]); // close read end of pipe + readypipe[0] = -1; + setsid(); // become session leader to lose ctty - if ( fork() ) // finish parent; continue in child + rv = fork(); // finish parent; continue in child + + if (rv == -1) + { + perror("cannot create process"); + exit(4); + } + + if (rv > 0) exit(0); // --> no session leader, no ctty getrlimit(RLIMIT_NOFILE, &rlim); @@ -312,8 +335,7 @@ main(int argc, char *argv[]) if ( semop(semprv, &semincr, 1) == -1) { perror("cannot increment private semaphore"); - kill(parentpid, SIGTERM); - exit(4); + exit(5); } /* @@ -327,8 +349,7 @@ main(int argc, char *argv[]) if ( (afd = creat(accountpath, 0600)) == -1) { perror(accountpath); - kill(parentpid, SIGTERM); - exit(5); + exit(6); } (void) close(afd); @@ -339,20 +360,18 @@ main(int argc, char *argv[]) if ( (afd = open(accountpath, O_RDONLY)) == -1) { perror(accountpath); - kill(parentpid, SIGTERM); - exit(5); + exit(6); } /* - ** create directory to store the shadow files + ** create directory to store the shadow files */ snprintf(shadowdir, sizeof shadowdir, "%s/%s", pacctdir, PACCTSHADOWD); - if ( mkdir(shadowdir, 0755) == -1) + if ( mkdir(shadowdir, 0755) == -1 && errno != EEXIST) { perror(shadowdir); - kill(parentpid, SIGTERM); - exit(5); + exit(6); } sfd = createshadow(curshadow); @@ -377,8 +396,7 @@ main(int argc, char *argv[]) if ( (nfd = netlink_open()) == -1) { (void) unlink(accountpath); - kill(parentpid, SIGTERM); - exit(5); + exit(6); } /* @@ -387,8 +405,7 @@ main(int argc, char *argv[]) if ( swonpacct(afd, accountpath) == -1) { (void) unlink(accountpath); - kill(parentpid, SIGTERM); - exit(6); + exit(7); } syslog(LOG_INFO, "accounting to %s", accountpath); @@ -398,6 +415,10 @@ main(int argc, char *argv[]) */ (void) signal(SIGHUP, SIG_IGN); + memset(&sigcleanup, 0, sizeof sigcleanup); + sigcleanup.sa_handler = cleanup; + sigemptyset(&sigcleanup.sa_mask); + (void) sigaction(SIGINT, &sigcleanup, (struct sigaction *)0); (void) sigaction(SIGQUIT, &sigcleanup, (struct sigaction *)0); (void) sigaction(SIGTERM, &sigcleanup, (struct sigaction *)0); @@ -412,9 +433,11 @@ main(int argc, char *argv[]) } /* - ** terminate parent: service initialized + ** notify parent: service initialized */ - kill(parentpid, SIGTERM); + ready = 1; + (void) write(readypipe[1], &ready, sizeof(ready)); + (void) close(readypipe[1]); /* ** main loop diff --git a/netlink.c b/netlink.c index 6f84978e..55477b22 100644 --- a/netlink.c +++ b/netlink.c @@ -68,6 +68,7 @@ netlink_open(void) &cpudef, strlen(cpudef)+1) == -1) { fprintf(stderr, "register cpumask failed\n"); + close(nlsock); return -1; } @@ -108,7 +109,7 @@ nlsock_getfam(int nlsock) if ( (len = recv(nlsock, &msg, sizeof msg, 0)) == -1) { - perror("receive NETLINK family"); + perror("receive NETLINK family for taskstats"); exit(1); } @@ -116,9 +117,10 @@ nlsock_getfam(int nlsock) { struct nlmsgerr *err = NLMSG_DATA(&msg); - fprintf(stderr, "receive NETLINK family, errno %d\n", - err->error); + /* nlmsgerr holds a negative errno */ + errno = -err->error; + perror("get NETLINK family for taskstats"); exit(1); } @@ -152,6 +154,7 @@ nlsock_open(void) == -1) { perror("set length receive buffer"); + close(nlsock); exit(1); }