/*
   Kermit's privileged services.

   These services include the setting of the baudrate of a port,
   and the retrieval of the number of free blocks on the specified
   device. This is done by means of a privileged server task, which
   does the dirty work. We talk to this task with two pipes.
*/

#include "ufk.h"

prv_init()
{
   int pid,
       in,
       out,
       p;
   char c,
        *prm[2];
   static char *tname = { "kermit_support" };

   if (prvsetdone)                      /* If setup already done... */
      return;                           /* then get the hell out of here */

   in = 0;
   out = 1;
   prm[0] = tname;
   prm[1] = 0;

   if ((pipe(pd1) == ERROR) ||          /* Create input pipe */
       (pipe(pd2) == ERROR) ||          /* Create output pipe */
       ((pid = fork()) == ERROR))       /* Create child process */
   {
      prterr(ER_PRIVSERVER);            /* Something wrong */
      kerm_exit();
   }
   if (!pid)
   {                                    /* child process */
      close(pd1[READ]);                 /* Close one side for read */
      close(pd2[WRITE]);                /* and the other side for write */
      dup2(pd2[READ],in);               /* Copy to stdin */
      dup2(pd1[WRITE],out);             /* and to stdout */
      for (c=2; c < 10; c++)
         close(c);                      /* close all files */

      execv(PRIVTASK,prm);              /* Try to start the support task */
      c = 0;                            /* Too bad if we come here */
      write(out,&c,1);                  /* Send error to parent */
      exit(1);                          /* Error exit for child */
   }
   close(pd1[WRITE]);                   /* Close one side for write */
   close(pd2[READ]);                    /* and the other side for read */

   pread(&c,1);                  /* Get acknowledge from server or child */
   if (c == 0)                          /* If false then the support task */
   {                                    /* did not run */
      prterr(ER_PRIVSERVER);            /* Something wrong */
      kerm_exit();
   }
   prvsetdone = TRUE;                   /* setup ok */
   if (c < PROTOCOL_VERSION)            /* Check for correct protocol */
   {
      prterr(ER_PRIVPROT);              /* Invalid protocol */
      kerm_exit();
   }
}

baud(dev,rate)
char *dev;
int rate;
{
   int len,
       stat;

   prv_init();                          /* Do the necessary setup */

   len = strlen(dev) + 1;               /* must send terminator as well */
   pwrite("b",1);                       /* 'baudrate' command */
   pwrite(&len,2);                      /* length of device name */
   pwrite(dev,len);                     /* device name */
   pwrite(&rate,2);                     /* baudrate */
   pwrite(&maskflag,1);                 /* mask flag for RTS & DCD */
   pread(&stat,2);                      /* read status */
   if (stat)
   {
      sup_error();                      /* get and print support task error */
      return TRUE;
   }
   return FALSE;
}

do_break(dev)
char *dev;
{
   int len,
       stat;

   prv_init();                          /* Do the necessary setup */

   len = strlen(dev) + 1;               /* must send terminator as well */
   pwrite("w",1);                       /* 'break' command */
   pwrite(&len,2);                      /* length of device name */
   pwrite(dev,len);                     /* device name */
   pread(&stat,2);                      /* read status */
   if (stat)
   {
      sup_error();                      /* get and print support task error */
      return TRUE;
   }
   return FALSE;
}

fset_date(file,date)
char *file;
long date;
{
   int len,
       stat;

   prv_init();                          /* Do the necessary setup */

   len = strlen(file) + 1;              /* must send terminator as well */
   pwrite("d",1);                       /* 'date' command */
   pwrite(&len,2);                      /* length of file name */
   pwrite(file,len);                    /* file name */
   pwrite(&date,4);                     /* date */
   pread(&stat,2);                      /* read status */
   if (stat)
   {
      sup_error();                      /* get and print support task error */
      return TRUE;
   }
   return FALSE;
}

set_dir(dir)
char *dir;
{
   int len,
       stat;

   prv_init();                          /* Do the necessary setup */

   len = strlen(dir) + 1;               /* must send terminator as well */
   pwrite("s",1);                       /* 'date' command */
   pwrite(&len,2);                      /* length of file name */
   pwrite(dir,len);                     /* file name */
   pread(&stat,2);                      /* read status */
   if (stat)
   {
      sup_error();                      /* get and print support task error */
      return TRUE;
   }
   return FALSE;
}

long get_free(dev)
char *dev;
{
   int len;
   long size;

   prv_init();                          /* Do the necessary setup */

   len = strlen(dev) + 1;               /* must send terminator as well */
   pwrite("f",1);                       /* 'free blocks' command */
   pwrite(&len,2);                      /* device name length */
   pwrite(dev,len);                     /* device name itself */
   pread(&size,4);                      /* Get size */
   if (size == -1l)                     /* error ? */
      sup_error();                      /* get and print support task error */
   return size;
}

sup_exit()
{
   if (prvsetdone)                      /* If setup done... */
      pwrite("e",1);                    /* 'exit' command */
}

sup_error()
{
   int len;
   char data[100];

   pread(&len,2);                       /* get length of error string */
   pread(data,len);                     /* get error string */
   fprintf(stderr,"%s\n",data);
}
