Skip to content

Commit 7838d54

Browse files
committed
Prevent race condition when last atop stops and new one is started
When the last atop incarnation terminates, the atopacctd issues a cleanup of all accounting files and writes a new'current' file. When a new atop is started meanwhile, a race condition might be introduced, which is prevented by a semaphore.
1 parent 19b0d7c commit 7838d54

2 files changed

Lines changed: 83 additions & 47 deletions

File tree

acctproc.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,13 @@ struct pacctadm {
180180
#define ATOPACCTKEY 3121959
181181
#define ATOPACCTTOT 100
182182

183-
struct sembuf semclaim = {0, -1, SEM_UNDO},
184-
semrelse = {0, +1, SEM_UNDO},
185-
semdecre = {1, -1, SEM_UNDO},
186-
semincre = {1, +1, SEM_UNDO};
183+
struct sembuf semclaim = {0, -1, SEM_UNDO},
184+
semrelse = {0, +1, SEM_UNDO},
185+
semdecre = {1, -1, SEM_UNDO},
186+
semincre = {1, +1, SEM_UNDO};
187+
188+
struct sembuf semreglock[] = {{0, -1, SEM_UNDO}, {1, -1, SEM_UNDO}},
189+
semunlock = {1, +1, SEM_UNDO};
187190

188191
/*
189192
** switch on the process-accounting mechanism
@@ -250,7 +253,7 @@ acctswon(void)
250253
** when the atopacctd daemon is active on this system,
251254
** it should be the preferred way to read the accounting records
252255
*/
253-
if ( (sempacctpubid = semget(PACCTPUBKEY, 0, 0)) != -1)
256+
if ( (sempacctpubid = semget(PACCTPUBKEY, 2, 0)) != -1)
254257
{
255258
FILE *cfp;
256259
char shadowpath[128];
@@ -259,14 +262,14 @@ acctswon(void)
259262
if (! droprootprivs() )
260263
mcleanstop(42, "failed to drop root privs\n");
261264

262-
(void) semop(sempacctpubid, &semclaim, 1);
265+
(void) semop(sempacctpubid, semreglock, 2);
263266

264267
snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s",
265268
pacctdir, PACCTSHADOWD, PACCTSHADOWC);
266269

267270
if ( (cfp = fopen(shadowpath, "r")) )
268271
{
269-
if (fscanf(cfp, "%ld/%lu",
272+
if (fscanf(cfp, "%ld/%ld",
270273
&curshadowseq, &maxshadowrec) == 2)
271274
{
272275
fclose(cfp);
@@ -297,6 +300,8 @@ acctswon(void)
297300

298301
semop(sempacctpubid,
299302
&semrelse, 1);
303+
semop(sempacctpubid,
304+
&semunlock, 1);
300305

301306
regainrootprivs();
302307
return 1;
@@ -316,20 +321,30 @@ acctswon(void)
316321
{
317322
supportflags |= ACCTACTIVE;
318323
regainrootprivs();
324+
semop(sempacctpubid,
325+
&semunlock, 1);
319326
return 0;
320327
}
321328

322329
(void) close(acctfd);
323330
}
331+
else
332+
{
333+
perror("open shadowpath");
334+
abort();
335+
}
324336
}
325337
else
326338
{
339+
fprintf(stderr,
340+
"fscanf failed on shadow currency\n");
327341
fclose(cfp);
328342
maxshadowrec = 0;
329343
}
330344
}
331345

332346
(void) semop(sempacctpubid, &semrelse, 1);
347+
(void) semop(sempacctpubid, &semunlock, 1);
333348
}
334349

335350
/*
@@ -868,7 +883,8 @@ acctphotoproc(struct tstat *accproc, int nrprocs)
868883
api->mem.majflt = acctexp(acctrec.ac_majflt);
869884
api->dsk.rio = acctexp(acctrec.ac_rw);
870885

871-
strcpy(api->gen.name, acctrec.ac_comm);
886+
strncpy(api->gen.name, acctrec.ac_comm, PNAMLEN);
887+
api->gen.name[PNAMLEN] = '\0';
872888
break;
873889

874890
case 3:
@@ -895,7 +911,8 @@ acctphotoproc(struct tstat *accproc, int nrprocs)
895911
api->mem.majflt = acctexp(acctrec_v3.ac_majflt);
896912
api->dsk.rio = acctexp(acctrec_v3.ac_rw);
897913

898-
strcpy(api->gen.name, acctrec_v3.ac_comm);
914+
strncpy(api->gen.name, acctrec_v3.ac_comm, PNAMLEN);
915+
api->gen.name[PNAMLEN] = '\0';
899916
break;
900917
}
901918
}

atopacctd.c

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,33 @@
7474
/*
7575
** Semaphore-handling
7676
**
77-
** Two semaphore groups are created with one semaphore each.
77+
** Two semaphore groups are created:
7878
**
7979
** The private semaphore (group) specifies the number of atopacctd processes
8080
** running (to be sure that only one daemon is active at the time).
8181
**
82-
** The public semaphore (group) reflects the number of processes using
83-
** the process accounting shadow files, i.e. the number of clients. This
84-
** semaphore starts at a high value and should be decremented whenever a
85-
** client starts using the shadow files and incremented again whenever that
86-
** client terminates.
82+
** The public semaphore group contains two semaphores:
83+
**
84+
** 0: the number of processes using the process accounting shadow files,
85+
** i.e. the number of (atop) clients. This semaphore starts at a high
86+
** value and should be decremented by every (atop) client that starts
87+
** using the shadow files and incremented again whenever that (atop)
88+
** client terminates.
89+
**
90+
** 1: binary semphore that has to be claimed before using/modifying
91+
** semaphore 0 in this group.
8792
*/
8893
static int semprv;
94+
95+
8996
static int sempub;
9097
#define SEMTOTAL 100
9198
#define NUMCLIENTS (SEMTOTAL - semctl(sempub, 0, GETVAL, 0))
9299

100+
struct sembuf semlocknowait = {1, -1, SEM_UNDO|IPC_NOWAIT},
101+
semunlock = {1, +1, SEM_UNDO};
102+
103+
93104
static char atopacctdversion[] = ATOPVERS;
94105
static char atopacctddate[] = ATOPDATE;
95106

@@ -248,18 +259,20 @@ main(int argc, char *argv[])
248259
}
249260
}
250261

251-
if ( (sempub = semget(PACCTPUBKEY, 0, 0)) == -1) // not existing?
262+
// create new semaphore group
263+
//
264+
if ( (sempub = semget(PACCTPUBKEY, 0, 0)) != -1) // existing?
265+
(void) semctl(sempub, 0, IPC_RMID, 0);
266+
267+
if ( (sempub = semget(PACCTPUBKEY, 2, 0666|IPC_CREAT|IPC_EXCL)) >= 0)
252268
{
253-
if ( (sempub = semget(PACCTPUBKEY, 1,
254-
0666|IPC_CREAT|IPC_EXCL)) >= 0)
255-
{
256-
(void) semctl(sempub, 0, SETVAL, SEMTOTAL);
257-
}
258-
else
259-
{
260-
perror("cannot create public semaphore");
261-
exit(3);
262-
}
269+
(void) semctl(sempub, 0, SETVAL, SEMTOTAL);
270+
(void) semctl(sempub, 1, SETVAL, 1);
271+
}
272+
else
273+
{
274+
perror("cannot create public semaphore");
275+
exit(3);
263276
}
264277

265278
/*
@@ -676,33 +689,39 @@ awaitprocterm(int nfd, int afd, int sfd, char *accountpath,
676689
** have been using the shadow files till now and
677690
** cleanup has to be performed
678691
*/
679-
if (NUMCLIENTS == 0)
692+
if (semop(sempub, &semlocknowait, 1) == 0) // lock succeeded?
680693
{
681-
/*
682-
** did last client just disappeared?
683-
*/
684-
if (*shadowbusyp)
694+
if (NUMCLIENTS == 0)
685695
{
686696
/*
687-
** remove all shadow files
697+
** did last client just disappear?
688698
*/
689-
gcshadows(oldshadowp, (*curshadowp)+1);
690-
*oldshadowp = 0;
691-
*curshadowp = 0;
692-
stotsize = 0;
693-
694-
/*
695-
** create new file with sequence 0
696-
*/
697-
(void) close(sfd);
698-
699-
sfd = createshadow(*curshadowp);
700-
setcurrent(*curshadowp);
701-
702-
*shadowbusyp = 0;
699+
if (*shadowbusyp)
700+
{
701+
/*
702+
** remove all shadow files
703+
*/
704+
gcshadows(oldshadowp, (*curshadowp)+1);
705+
*oldshadowp = 0;
706+
*curshadowp = 0;
707+
stotsize = 0;
708+
709+
/*
710+
** create new file with sequence 0
711+
*/
712+
(void) close(sfd);
713+
714+
sfd = createshadow(*curshadowp);
715+
setcurrent(*curshadowp);
716+
717+
*shadowbusyp = 0;
718+
}
719+
720+
(void) semop(sempub, &semunlock, 1);
721+
return 1;
703722
}
704723

705-
return 1;
724+
(void) semop(sempub, &semunlock, 1);
706725
}
707726

708727
*shadowbusyp = 1;

0 commit comments

Comments
 (0)