text: /*
   * Steven Schultz - sms@moe.2bsd.com
   *
   *      @(#)ctimed.c    1.0 (2.11BSD) 1996/6/25
   *
   * ctimed - the daemon that supports the ctime() and getpw*() stubs
   *          in 'libcstubs.a'.
  */
  
  #include        <signal.h>
  #include        <stdio.h>
  #include        <setjmp.h>
  #include        <sys/ioctl.h>
  #include        <sys/types.h>
  #include        <sys/time.h>
  #include        <pwd.h>
  #include        <utmp.h>
  
  /*
   * These should probably be placed in an include file.  If you add anything
   * here then you will also have to modify /usr/src/usr.lib/libstubs/stubs.c
   * (if for no other reason than to add the stub code).
  */
  
  #define CTIME   1
  #define ASCTIME 2
  #define TZSET   3
  #define LOCALTIME 4
  #define GMTIME  5
  #define OFFTIME 6
  
  #define GETPWENT        7
  #define GETPWNAM        8
  #define GETPWUID        9
  #define SETPASSENT      10
  #define ENDPWENT        11
  
  extern  struct  tm      *offtime();
  
          jmp_buf env;
          char    *cp;
          char    junk[256 + sizeof (struct passwd) + 4];
          long    off;
          time_t  l;
          void    timeout(), checkppid();
          struct  tm      tmtmp, *tp;
  
  main()
          {
          register int i;
          register struct passwd *pw;
          struct  itimerval it;
          u_char  c, xxx;
          int     len, tosslen;
          uid_t   uid;
  
          signal(SIGPIPE, SIG_DFL);
          for     (i = getdtablesize(); --i > 2; )
                  close(i);
  /*
   * Need a timer running while we disassociate from the control terminal
   * in case of a modem line which has lost carrier.
  */
          timerclear(&it.it_interval);
          it.it_value.tv_sec = 5;
          it.it_value.tv_usec = 0;
          signal(SIGALRM, timeout);
          setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
          if      (setjmp(env) == 0)
                  {
                  i = open("/dev/tty", 0);
                  if      (i >= 0)
                          {
                          ioctl(i, TIOCNOTTY, NULL);
                          close(i);
                          }
                  }
  /*
   * Now start a timer with one minute refresh.  In the signal service
   * routine, check the parent process id to see if this process has
   * been orphaned and if so exit.  This is primarily aimed at removing
   * the 'ctimed' process left behind by 'sendmail's multi-fork startup
   * but may prove useful in preventing accumulation of 'ctimed' processes
   * in other circumstances as well.  Normally this process is short
   * lived.
  */
          it.it_interval.tv_sec = 60;
          it.it_interval.tv_usec = 0;
          it.it_value.tv_sec = 60;
          it.it_value.tv_usec = 0;
          signal(SIGALRM, checkppid);
          setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
  
          while   (read(fileno(stdin), &c, 1) == 1)
                  {
                  switch  (c)
                          {
                          case    CTIME:
                                  l = 0L;
                                  getb(fileno(stdin), &l, sizeof l);
                                  cp = ctime(&l);
                                  write(fileno(stdout), cp, 26);
                                  break;
                          case    ASCTIME:
                                  getb(fileno(stdin), &tmtmp, sizeof tmtmp);
                                  cp = asctime(&tmtmp);
                                  write(fileno(stdout), cp, 26);
                                  break;
                          case    TZSET:
                                  (void) tzset();
                                  break;
                          case    LOCALTIME:
                                  l = 0L;
                                  getb(fileno(stdin), &l, sizeof l);
                                  tp = localtime(&l);
                                  write(fileno(stdout), tp, sizeof (*tp));
                                  strcpy(junk, tp->tm_zone);
                                  junk[24] = '\0';
                                  write(fileno(stdout), junk, 24);
                                  break;
                          case    GMTIME:
                                  l = 0L;
                                  getb(fileno(stdin), &l, sizeof l);
                                  tp = gmtime(&l);
                                  write(fileno(stdout), tp, sizeof (*tp));
                                  strcpy(junk, tp->tm_zone);
                                  junk[24] = '\0';
                                  write(fileno(stdout), junk, 24);
                                  break;
                          case    OFFTIME:
                                  getb(fileno(stdin), &l, sizeof l);
                                  getb(fileno(stdin), &off, sizeof off);
  #ifdef  __bsdi__
                                  l += off;
                                  tp = localtime(&l);
  #else
                                  tp = offtime(&l, off);
  #endif
                                  write(fileno(stdout), tp, sizeof (*tp));
                                  break;
                          case    GETPWENT:
                                  pw = getpwent();
                                  do_pw(pw);
                                  break;
                          case    GETPWNAM:
                                  getb(fileno(stdin), &len, sizeof (int));
                                  if      (len > UT_NAMESIZE)
                                          {
                                          tosslen = len - UT_NAMESIZE;
                                          len = UT_NAMESIZE;
                                          }
                                  else
                                          tosslen = 0;
                                  getb(fileno(stdin), junk, len);
                                  for     (;tosslen; tosslen--)
                                          getb(fileno(stdin), &xxx, 1);
                                  junk[len] = '\0';
                                  pw = getpwnam(junk);
                                  do_pw(pw);
                                  break;
                          case    GETPWUID:
                                  getb(fileno(stdin), &uid, sizeof (uid_t));
                                  pw = getpwuid(uid);
                                  do_pw(pw);
                                  break;
                          case    SETPASSENT:
                                  getb(fileno(stdin), &len, sizeof (int));
                                  if      (setpassent(len))
                                          len = 1;
                                  else
                                          len = 0;
                                  write(fileno(stdout), &len, sizeof (int));
                                  break;
                          case    ENDPWENT:
                                  endpwent();
                                  break;
                          default:
                                  abort("switch");
                          }
                  }
          }
  
  getb(f, p, n)
          int     f;
          register char   *p;
          register int    n;
          {
          register int    i;
  
          while   (n)
                  {
                  i = read(f, p, n);
                  if      (i <= 0)
                          return;
                  p += i;
                  n -= i;
                  }
          }
  
  void
  timeout()
          {
  
          longjmp(env, 1);
          }
  
  void
  checkppid()
          {
  
          if      (getppid() == 1)
                  exit(0);
          }
  
  do_pw(pw)
          struct passwd *pw;
          {
          int     len;
  
          if      (!pw)
                  {
                  len = 0;
                  write(fileno(stdout), &len, sizeof (int));
                  return;
                  }
          len = packpwtobuf(pw, junk);
          write(fileno(stdout), &len, sizeof (int));
          write(fileno(stdout), pw, sizeof (*pw));
          write(fileno(stdout), junk, len);
          return;
          }
  
  packpwtobuf(pw, buf)
          register struct passwd *pw;
          char    *buf;
          {
          register char *cp = buf;
          register char *dp;
  
          dp = pw->pw_name;
          pw->pw_name = (char*) 0;
          while   (*cp++ = *dp++)
                  ;
          dp = pw->pw_passwd;
          pw->pw_passwd = (char*) (cp - buf);
          while   (*cp++ = *dp++)
                  ;
          dp = pw->pw_class;
          pw->pw_class = (char*) (cp - buf);
          while   (*cp++ = *dp++)
                  ;
          dp = pw->pw_gecos;
          pw->pw_gecos = (char*) (cp - buf);
          while   (*cp++ = *dp++)
                  ;
          dp = pw->pw_dir;
          pw->pw_dir = (char*) (cp - buf);
          while   (*cp++ = *dp++)
                  ;
          dp = pw->pw_shell;
          pw->pw_shell = (char*) (cp - buf);
          while   (*cp++ = *dp++)
                  ;
          return(cp - buf);
          }
  