Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions atopacct.service
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
95 changes: 59 additions & 36 deletions atopacctd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

/*
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -377,8 +396,7 @@ main(int argc, char *argv[])
if ( (nfd = netlink_open()) == -1)
{
(void) unlink(accountpath);
kill(parentpid, SIGTERM);
exit(5);
exit(6);
}

/*
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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
Expand Down
9 changes: 6 additions & 3 deletions netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ netlink_open(void)
&cpudef, strlen(cpudef)+1) == -1)
{
fprintf(stderr, "register cpumask failed\n");
close(nlsock);
return -1;
}

Expand Down Expand Up @@ -108,17 +109,18 @@ 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);
}

if (msg.n.nlmsg_type == NLMSG_ERROR || !NLMSG_OK(&msg.n, len))
{
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);
}

Expand Down Expand Up @@ -152,6 +154,7 @@ nlsock_open(void)
== -1)
{
perror("set length receive buffer");
close(nlsock);
exit(1);
}

Expand Down