wsh/
wsh/binsrc/
wsh/docs/help/
wsh/docs/old/
wsh/etc/
wsh/src/util/
/* See the file wizshell.c, wizshell.h or the files in docs/ for information */

#include <time.h>
#include <signal.h>
#include "wizshell.h"

/* to make a new one */
#define MK_WLIST(wlist) {if((wlist=(who_t *) MALLOC(sizeof(who_t)))==NULL) \
                     FATAL("Could not allocate memory for who list") \
                     wlist->next=NULL;}

/* inserts line in utmp of the form: "pid:tty:who:real name:access:login@" */
/* also, inserts line in wtmp of the form: "who:access:ip:login@" */
/* can't do ip_number yet.. */
/* Assumes that there are no ":" in any of these fields */
/* Assumes that if there is no $NETHOST then it must be localhost */
void add_uwtmp() {
  pid_t p;
  time_t t;
  FILE *fp;
  char *ip;
  struct stat status;
  int size,removed=0;

  p=getpid();
  time(&t);

  if(!(fp=fopen(UTMP_FILE,"a"))) {
    fprintf(stderr,"Could not open utmp file: %s\n",UTMP_FILE);
    fprintf(stderr,"Not adding to 'who' list.\n");
  } else {
    fprintf(fp,"%d:%s:%s:%s:%s:%d:%d\n",
         p,ttyname(0),envir.login,envir.access,envir.real_name,t,envir.mesg);
    fclose(fp);
  }

  if(!stat(WTMP_FILE,&status)) size=status.st_size;
  else size=0;
  if(size>(MAX_WTMP_SIZE*1024)) {
    removed=1;
    unlink(WTMP_FILE);
  }

  if(!(fp=fopen(WTMP_FILE,"a"))) {
    fprintf(stderr,"Could not open wtmp file: %s\n",WTMP_FILE);
    fprintf(stderr,"Not adding to 'last' list.\n");
  } else {
    if(removed)
       fprintf(fp,"old wtmp file removed (over %dKb) on %s\n",
                  MAX_WTMP_SIZE,ctime(&t));
    if(!(ip=getenv("NETHOST"))) ip="127.0.0.1";
    fprintf(fp,"%-15.15s %-10.10s %-26.26s %s",
               envir.login,envir.access,ip,ctime(&t));
    fclose(fp);
  }
}


/*rewrite is used for if we changed our envir.mesg setting and need to save it*/
who_t *read_utmp(rewrite)
  int rewrite;
{
  FILE *fp;
  pid_t p;
  time_t t;
  char buf[MAX_BUF],*tp;
  who_t *wlist,*t1,*t2;
  int changed=rewrite,c;

  if(!(fp=fopen(UTMP_FILE,"r"))) {
    MK_WLIST(wlist)
    return wlist;
  }
  rewind(fp);
  if(rewrite) tp=ttyname(0);  /* so we know which is ours */
  MK_WLIST(wlist)
  t1=wlist;
  while(!feof(fp)) {
    MK_WLIST(t2)

    /* process id */
    get_field(fp,buf);
    if(buf[0]) t2->num1=atol(buf);
    if(!t2->num1) { FREE(t2); continue; }
    if(kill(t2->num1,0)==-1) {
/*    fprintf(stderr,"Process: %d doesn't exist anymore\n",t2->num1); */
      changed++;
      while((c=fgetc(fp))!=EOF && c!='\n') ;
      FREE(t2);
      continue;
    }

    /* ttyname */
    get_field(fp,buf);
    MK_STR(t2->str1,strlen(buf)+1)
    strcpy(t2->str1,buf);

    /* login name */
    get_field(fp,buf);
    MK_STR(t2->str2,strlen(buf)+1)
    strcpy(t2->str2,buf);

    /* access type */
    get_field(fp,buf);
    MK_STR(t2->str3,strlen(buf)+1)
    strcpy(t2->str3,buf);

    /* real name */
    get_field(fp,buf);
    MK_STR(t2->str4,strlen(buf)+1)
    strcpy(t2->str4,buf);

    /* login time */
    get_field(fp,buf);
    if(buf[0]) t2->num2=atol(buf);

    /* mesg setting */
    get_field(fp,buf);
    if(buf[0]) t2->num3=atol(buf);

    if(rewrite && !strcmp(t2->str1,tp))   /* if rewrite and this is ours */
      t2->num3=envir.mesg;

    t1->next=t2;
    t1=t2;
  }
  fclose(fp);
  /* This could cause a problem if someone calls add_uwtmp between
   * the reading of the utmp file and this write to utmp -oh well
   * maybe I'll make a lockfile for it later -- semaphores are difficult
   * (the worst case is that someone will be logged in without being in 'who')
   */
  if(changed) write_utmp(wlist);
  return wlist;
}

#ifdef MAX_USERS
int count_users(who)
  who_t *who;
{
  int i;

  i=0;
  who=read_utmp(0);
  who=who->next;
  while(who && who->num1) {
    i++;
    who=who->next;
  }
  return i;
}
#endif

void write_utmp(who)
  who_t *who;
{
  FILE *fp;
  who_t *t;

  if(!(fp=fopen(UTMP_FILE,"w"))) {
    fprintf(stderr,"Couldn't find utmp file: %s\n",UTMP_FILE);
    return;
  }
  rewind(fp);

  t=who->next;
  while(t && t->num1) {
    fprintf(fp,"%d:%s:%s:%s:%s:%d:%d\n",
            t->num1,t->str1,t->str2,t->str3,t->str4,t->num2,t->num3);
    t=t->next;
  }
  fclose(fp);
}

/* How long before we actually print the idle time (seconds) */
#define IDLE 30
/* returns 'who' so you can free_who(print_utmp(read_utmp())) ;-) */
who_t *print_utmp(who,args)
  who_t *who;
  char *args;  /* currently ignored */
{
  who_t *t;
  int i=0;
  struct stat status;
  time_t now;
  int idle;

  time(&now);

  t=who->next;
  fprintf(stdout,
     "login         tty        acc    real name            mesg      idle\n");

  while(t && t->num1) {
    i++;
    fprintf(stdout,
            "%-13.13s %-10.10s %-6.6s %-23.23s %c",
            t->str2,t->str1+5,t->str3,t->str4,(t->num3?'y':'n'),
            ctime((time_t *) &(t->num2)) );   /* not used by format string */

    if(stat(t->str1,&status)==-1) {
      fprintf(stdout,"  error  ");
    } else {
      idle=now-status.st_atime;
      if(!stat(t->str1,&status)) idle=now-status.st_atime;
      else idle=0;
      if(idle<IDLE) idle=0;
      if(idle>60*60) {
        fprintf(stdout,"%2dh",idle/(60*60));
        idle=idle%(60*60);
      } else fprintf(stdout,"   ");
      if(idle>60) {
        fprintf(stdout,"%2dm",idle/60);
        idle=idle%60;
      } else fprintf(stdout,"   ");
      if(idle>0) fprintf(stdout,"%2ds",idle);
     else fprintf(stdout,"   ");
fprintf(stdout,"\n");
    }

    t=t->next;
  }
  fprintf(stdout,"Number of users: %d\n",i);
  return who;
}

void free_who(who)
  who_t *who;
{
  who_t *t;

  while(who) {
    t=who->next;
    FREE(who->str1);
    FREE(who->str2);
    FREE(who->str3);
    FREE(who);
    who=t;
  }
}