rajachan
rajachan

Reputation: 795

getutent and Linux timer issues

I have a problem running the below code , which invokes getutent() to count the total number of users currently logged in to the system. The timer will be invoked every 1sec and will set the boolean named "isSigAlrmOccured" to true and exit.The main function checks whether the timer signal is delivered by checking this boolen and monitor the number of loggedin users. Unfortunately, the timer signal is delivered to the main program only two times correctly and I don't get any further signals after that. The pause function call doesn't get interrupted after the first two signals.

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <utmp.h>
#include <errno.h>

static int isSigAlrmOccured;

void alarm_handler (int signo)
{
  static int i=1;
  printf("\n Signal Occurred %d times\n",i++);
  isSigAlrmOccured = 1;

}

int main (int argc, char *argv[]) {
   struct itimerval delay;
   struct utmp *utmpstruct;
   int numuser;


   int ret;
   signal (SIGALRM, alarm_handler);
   delay.it_value.tv_sec = 1;
   delay.it_value.tv_usec = 0;
   delay.it_interval.tv_sec = 1;
   delay.it_interval.tv_usec = 0;
   ret = setitimer (ITIMER_REAL, &delay, NULL);
   if (ret) {
     perror ("setitimer");
     return 0;
   }
   for (;;) {
       pause ( );
       /* count the number of users */
       if ( (errno == EINTR) && (isSigAlrmOccured) ) {
           isSigAlrmOccured = 0;
           setutent();
           while ((utmpstruct = getutent())) {
           if ((utmpstruct->ut_type == USER_PROCESS) &&
               (utmpstruct->ut_name[0] != '\0'))
               numuser++;
           }
           endutent();
       }
   }
   return 0;
}

Output:

Signal Occurred 1 times

Signal Occurred 2 times

Upvotes: 2

Views: 1223

Answers (2)

codeDr
codeDr

Reputation: 1684

The implementation of *utent() is using alarm() and is reseting your alarm.
You'll have to do something else.

strace ttest ( some lines removed for brevity )
[...]
pause()
--- SIGALRM (Alarm clock) @ 0 (0) ---
write(1, " Signal Occurred 1 times\n", 25 Signal Occurred 1 times) = 25
open("/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
alarm(0) = 5
rt_sigaction(SIGALRM, {0x7f52580a91c0, [], SA_RESTORER, 0x7f5257fd46e0}, {0x40075c, [ALRM], SA_RESTORER|SA_RESTART, 0x7f5257fd46e0}, 8) = 0
alarm(1) = 0

Example code which only sets the alarm during the sleep period.

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <utmp.h>
#include <errno.h>

static int isSigAlrmOccured;

void alarm_handler (int signo)
{
  static int i=1;
  printf("\n Signal Occurred %d times\n",i++);
  isSigAlrmOccured = 1;

}

int main (int argc, char *argv[]) {
   struct itimerval delay;
   struct utmp *utmpstruct;
   int numuser;
   int ret;

   for (;;) {
   signal (SIGALRM, alarm_handler);
       alarm(1);       /* wake me later */
       pause ( );
       /* count the number of users */
       if ( (errno == EINTR) && (isSigAlrmOccured) ) {
       signal (SIGALRM, SIG_DFL);
           isSigAlrmOccured = 0;
           numuser = 0;
           setutent();
           while ((utmpstruct = getutent())) {
           if ((utmpstruct->ut_type == USER_PROCESS) &&
               (utmpstruct->ut_name[0] != '\0'))
               numuser++;
           }
           endutent();
           printf("found %d users\n", numuser);
       }
   }
   return 0;
}

Upvotes: 7

unwind
unwind

Reputation: 399823

This page lists the set of functions that are "safe" to call from a signal handler. If you call some other function, the behavior is undefined. I notice that setutent() doesn't seem to be on the lest, for starters ...

Upvotes: 1

Related Questions