home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / uniflex.zip / ufksup.c < prev    next >
C/C++ Source or Header  |  1993-08-23  |  15KB  |  487 lines

  1. /*
  2.   Uniflex Kermit's support task.
  3.  
  4.   This privileged task accounts for the following functions:
  5.  
  6.   1. Set the baudrate of any terminal with that possibility.
  7.   2. Get the number of free blocks from the current device.
  8.   3. Set the specified date on a specified file.
  9.   4. Set the default directory (to keep track with the caller).
  10.   5. Send a break to the specified device.
  11.  
  12.   This program reads stdin (normally a pipe) to get the function.
  13.   Current functions are:
  14.  
  15.   1. 'b' - set the baudrate on the specified device
  16.   2. 'd' - set the specified date on the specified file
  17.   3. 'f' - get number of free blocks on the specified device
  18.   4. 's' - set the default directory
  19.   5. 'w' - send 'break' to the specified device
  20.   6. 'e' - exit the support task
  21.  
  22. */
  23.  
  24. #asm
  25.  info UniFLEX Kermit's support task
  26.  info Author: Jur van der Burg
  27.  info Nettelhorst 56
  28.  info 2402 LS  Alphen aan den Rijn
  29.  info The Netherlands
  30.  info Version: V 1.2
  31. #endasm
  32.  
  33. #define  PROTOCOL_VERSION   2
  34.  
  35. #include <stdio.h>
  36. #include <stat.h>
  37. #include <modes.h>
  38. #include <signal.h>
  39. #include <sys/dir.h>
  40. #include <setjmp.h>
  41.  
  42. #define  chtim   touch          /* other name in my library */
  43.  
  44. #define  TRUE  1
  45. #define  FALSE 0
  46. #define  IN    0
  47. #define  OUT   1
  48. #define  BAUD  0
  49. #define  BREAK 1
  50. #define  ERROR (-1)
  51.  
  52. #define  TIMBYTE 0x2b
  53.  
  54. main()
  55. {
  56.    char command,
  57.         mask,
  58.         errmsg[128],
  59.         device[30],
  60.         file[128];
  61.    int  status,
  62.         len,
  63.         owner,
  64.         perms;
  65.    unsigned int baudrate;
  66.    struct stat buf;
  67.    long get_freedisk(),
  68.         free_blks,
  69.         date;
  70.  
  71.    fstat(0,&buf);                       /* check standard input */
  72.    if (buf.st_nlink != 0)               /* input must come from a pipe */
  73.       exit(0);                          /* bye bye, leave him in confusion */
  74.  
  75.    signal(SIGTERM,SIG_IGN);             /* Ignore this signals */
  76.    signal(SIGHUP,SIG_IGN);
  77.    signal(SIGQUIT,SIG_IGN);
  78.    signal(SIGINT,SIG_IGN);
  79.    command = PROTOCOL_VERSION;
  80.    write(OUT,&command,1);               /* Send acknowledge to parent */
  81.    while (TRUE)                         /* Keep looking for commands */
  82.    {
  83.       if (read(IN,&command,1) <= 0)     /* Get command byte */
  84.          exit(1);                       /* Read error */
  85.       switch(command)
  86.       {
  87.           case 'b':                     /* Set device baudrate */
  88.                 read(IN,&len,2);        /* Get device name length */
  89.                 read(IN,device,len);    /* Get device name */
  90.                 read(IN,&baudrate,2);   /* Get the baudrate */
  91.                 read(IN,&mask,1);       /* Get the mask */
  92.                 status = set_dev(device,baudrate,mask,errmsg,BAUD); /* Set */
  93.                 write(OUT,&status,2);   /* Return status */
  94.                 if (status)
  95.                    send_error(errmsg);  /* Send error message */
  96.                 break;
  97.  
  98.           case 'w':                     /* Send break to device */
  99.                 read(IN,&len,2);        /* Get device name length */
  100.                 read(IN,device,len);    /* Get device name */
  101.                 status = set_dev(device,0,0,errmsg,BREAK); /* Send it */
  102.                 write(OUT,&status,2);   /* Return status */
  103.                 if (status)
  104.                    send_error(errmsg);  /* Send error message */
  105.                 break;
  106.  
  107.           case 'd':
  108.                 read(IN,&len,2);        /* Get file name length */
  109.                 read(IN,file,len);      /* Get file name */
  110.                 read(IN,&date,4);       /* Get the date */
  111.                 status = set_date(file,date,errmsg); /* Set it */
  112.                 write(OUT,&status,2);   /* Return status */
  113.                 if (status)
  114.                    send_error(errmsg);  /* Send error message */
  115.                 break;
  116.  
  117.           case 'f':
  118.                 read(IN,&len,2);        /* Get device name length */
  119.                 read(IN,device,len);    /* Get device name */
  120.                 free_blks = get_freedisk(device,errmsg);/* Get # of blocks */
  121.                 write(OUT,&free_blks,4); /* Send to parent */
  122.                 if (free_blks == (long) ERROR)
  123.                    send_error(errmsg);   /* Send error message */
  124.                 break;
  125.  
  126.           case 's':
  127.                 read(IN,&len,2);        /* Get directory name length */
  128.                 read(IN,device,len);    /* Get directory name */
  129.                 status = set_dir(device,errmsg); /* Set it */
  130.                 write(OUT,&status,2);   /* Return status */
  131.                 if (status)
  132.                    send_error(errmsg);  /* Send error message */
  133.                 break;
  134.  
  135.           case 'e':
  136.                 exit(0);                /* bye bye */
  137.  
  138.           default:
  139.                 break;                  /* Ignore unknown command */
  140.       }
  141.    }
  142. }
  143.  
  144. send_error(msg)
  145. char *msg;
  146. {
  147.    int length;
  148.  
  149.    length = strlen(msg) + 1;            /* Must send terminator as well */
  150.    write(OUT,&length,2);                /* Send length */
  151.    write(OUT,msg,length);               /* Send message */
  152. }
  153.  
  154. /*
  155.   Routine to set the baudrate of a port, or to send a break to it.
  156.  
  157.   The user must either be the owner or have read and write
  158.   access to the selected device. A check will be made if the
  159.   system consists of new hardware. In the case of old hardware
  160.   the baudrate is not under program control.
  161. */
  162.  
  163. #define P_TTY  0x5c             /* Pointer to tty structure */
  164. #define P_NTTY 0x5008           /* Pointer to number of tty's */
  165.  
  166. int valid_speed[] = {           /* Table containing valid speed's */
  167.    75,0xff,
  168.   150,0xee,
  169.   300,0xdd,
  170.   600,0xcc,
  171.  1200,0xbb,
  172.  2400,0xaa,
  173.  4800,0x99,
  174.  9600,0x88,
  175.     0
  176.       };
  177.  
  178. struct ttydef {                 /* Internal UniFLEX tty structure definition */
  179.        char *rawq,
  180.             *canq,
  181.             *outq;
  182.        unsigned int devadr;
  183.        char flags,
  184.             delay,
  185.             major,
  186.             minor,
  187.             delcnt,
  188.             col,
  189.             kill,
  190.             erase,
  191.             speed,
  192.             type,
  193.             state,
  194.             xstate };
  195.  
  196. #define  ISOPEN  0x04           /* Current state */
  197.  
  198. jmp_buf env;
  199.  
  200. set_dev(dev,speed,mask,errmsg,what)
  201. char *dev;
  202. unsigned int speed;
  203. char *errmsg;
  204. char mask,
  205.      what;
  206. {
  207.    int *fp,
  208.        *fp1,
  209.        *p,
  210.        i,
  211.        timeout();
  212.    char found,
  213.         speed_val,
  214.         n_tty;
  215.    unsigned int c,
  216.                 np;
  217.    struct stat buf;
  218.    struct ttydef tt_dsc;
  219.    struct ttydef *sp;
  220.  
  221.    if (stat(dev,&buf))                        /* Get device parameters */
  222.       return(prterr("Invalid device specified",errmsg));
  223.  
  224.    if ((buf.st_mode & S_IFMT) != S_IFCHR) /* Check for a character device */
  225.       return(prterr("Not a character device",errmsg));
  226.    buf.st_mode &= S_IPRM;                 /* Mask type bits */
  227.    if (!((buf.st_mode & S_IOREAD) &&      /* Check for read and write */
  228.          (buf.st_mode & S_IOWRITE)))      /* access for others */
  229.       if (buf.st_uid != getuid())         /* No access, check if he owns */
  230.                                           /* the device */
  231.          return(prterr("Don't own device",errmsg));
  232.  
  233.    if (what == BAUD)
  234.    {
  235.       found = FALSE;
  236.       p = valid_speed;
  237.       while (*p)
  238.       {
  239.          if (speed == *p++)               /* Compare against table */
  240.          {
  241.             speed_val = *p;               /* Got it ! */
  242.             found = TRUE;
  243.             break;
  244.          }
  245.          p++;                             /* Point to next entry */
  246.       }
  247.       if (!found)
  248.          return(prterr("Invalid speed specified",errmsg));
  249.       if (mask)
  250.          speed_val &= 0x77;               /* Mask RTS and DCD */
  251.    }
  252.  
  253. /*
  254.    The following piece of code ensures that a device address will
  255.    be available in the internal data structures for the specified
  256.    device. This is simply done by opening the device. In case it's
  257.    not ready (modem for example) a timeout has been setup to allow
  258.    the program to continue.
  259. */
  260.  
  261.    signal(SIGALRM,timeout);               /* Catch the timeout trap */
  262.    alarm(1);                              /* One second timeout */
  263.    if (!setjmp(env))                      /* If for the first time */
  264.       fp = open(dev,2);                   /* Open the port */
  265.    alarm(0);                              /* Reset timer */
  266.    close(fp);
  267.  
  268.    if ((fp = open("/dev/smem",2)) == ERROR) /* Must open this one */
  269.       return(prterr("Error opening '/dev/smem'",errmsg));
  270.    readat(fp,P_NTTY,&np,2);               /* Get pointer to number of tty's */
  271.    readat(fp,np,&n_tty,1);                /* Get number of tty's */
  272.    readat(fp,P_TTY,&sp,2);                /* Get pointer to TTY structure */
  273.    found = FALSE;
  274.    for (i = 0; i < n_tty; i++)
  275.    {
  276.       readat(fp,sp++,&tt_dsc,sizeof(struct ttydef));/* Read total structure */
  277.       if (tt_dsc.devadr == 0)             /* Skip on zero device address */
  278.          continue;
  279.  
  280.       if ((tt_dsc.major == ((int)(buf.st_size >> 16) & 0xff)) &&
  281.           (tt_dsc.minor == ((int)buf.st_size & 0xff))) /* Chk maj + min id */
  282.       {
  283.          readat(fp,tt_dsc.devadr + 2,&c,2); /* Get speed register */
  284.          if ((c == 0xffff) || (what == BREAK)) /* Should read as 'ffff' */
  285.             found = TRUE;
  286.          else
  287.             return(prterr("Baudrate not programmable",errmsg));
  288.          break;
  289.       }
  290.    }
  291.    if (found)
  292.    {
  293.       setuid(0);                          /* Make sure we've got the priv's */
  294.       if (what == BAUD)
  295.          writeat(fp,tt_dsc.devadr + 2,&speed_val,1); /* Update speed */
  296.       else if (what == BREAK)
  297.          poke_tty(fp,&tt_dsc,--sp);
  298.    }
  299.    else
  300.       return(prterr("Unable to set baudrate",errmsg));
  301.    close(fp);
  302.    return(NULL);
  303. }
  304.  
  305. poke_tty(fp,tt_dsc,sp)
  306. int *fp;
  307. struct ttydef *tt_dsc,
  308.               *sp;
  309. {
  310.    char break_val,
  311.         org_value,
  312.         new_speed;
  313.  
  314.    org_value = (tt_dsc->speed & ~0x1c) | 0x81; /* Current characteristics */
  315.    if (!(tt_dsc->state & ISOPEN))              /* RTS high if port closed */
  316.       org_value |= 0x40;
  317.    break_val = org_value | 0x60;            /* Add 'break' bits */
  318.    new_speed = tt_dsc->speed | 0x60;
  319.    writeat(fp,&sp->speed,&new_speed,1);     /* break will not be terminated */
  320.    writeat(fp,tt_dsc->devadr,&break_val,1); /* if new char is received */
  321.    short_delay(fp,3);                       /* 300 Ms delay */
  322.    writeat(fp,&sp->speed,&tt_dsc->speed,1);
  323.    writeat(fp,tt_dsc->devadr,&org_value,1);
  324. }
  325.  
  326. readat(fp,address,value,count)
  327. int *fp;
  328. unsigned int address;
  329. char *value;
  330. int count;
  331. {
  332.    lseek(fp, (unsigned long)address, 0);
  333.    read (fp, value, count);
  334. }
  335.  
  336. writeat(fp,address,value,count)
  337. int *fp;
  338. unsigned int address;
  339. char *value;
  340. int count;
  341. {
  342.    lseek(fp, (unsigned long)address, 0);
  343.    write(fp, value, count);
  344. }
  345.  
  346. short_delay(fp,time)
  347. int *fp, time;
  348. {
  349.    int i;
  350.    char n,
  351.         m;
  352.  
  353.    n = m = -1;
  354.    for (i = 0; i < time + 1; i++)
  355.    {
  356.       while (n == m)
  357.       {
  358.          lseek(fp, (long)TIMBYTE, 0);          /* Position to time byute */
  359.          read(fp,&m,1);                        /* Read current value */
  360.       }
  361.       n = m;
  362.    }
  363. }
  364.  
  365.  
  366. timeout()
  367. {
  368.    longjmp(env,TRUE);                     /* Return after timeout */
  369. }
  370.  
  371. prterr(str,errstr)
  372. char *str,
  373.      *errstr;
  374. {
  375.    sprintf(errstr,"%s",str);
  376.    return(ERROR);
  377. }
  378.  
  379. /*
  380.   This routine returns the number of free blocks on the specified device
  381.   or directory. The real device is found by searching for it in the '/dev'
  382.   directory, and comparing the major and minor id of the device with the
  383.   device number of the specified directory. If the device name is found,
  384.   a 'sync' is done to be sure that the information on the disk is current.
  385.   Then the SIR is read and the number of free blocks is retrieved from that.
  386. */
  387.  
  388. long get_freedisk(indev,errstr)
  389. char *indev,
  390.      *errstr;
  391. {
  392.    struct stat statbuf;
  393.    struct direct dirptr;
  394.    int device,
  395.        status,
  396.        fpt;
  397.    unsigned int mode;
  398.    char found,
  399.         filename[20];
  400.    long freeblks,
  401.         get_disk();
  402.  
  403.    fpt = ERROR;
  404.    found = FALSE;                       /* Loop end indicator */
  405.    strcpy(filename,"/dev/");
  406.    if (!stat(indev,&statbuf))           /* Get stat of specified directory */
  407.    {
  408.       device = statbuf.st_dev;          /* Save device major and minor */
  409.       mode = statbuf.st_mode & S_IFMT;  /* mask for file type */
  410.       if (mode == S_IFCHR)              /* Character device not allowed */
  411.          return(prterr("Invalid device or file specified",errstr));
  412.       else if (mode == S_IFBLK)         /* already a block device ? */
  413.       {
  414.          strcpy(filename,indev);        /* supply device name */
  415.          found = TRUE;
  416.       }
  417.       if ((fpt = open("/dev",0)) != ERROR)
  418.          while (!found)                 /* Until we're done... */
  419.          {
  420.             status = read(fpt,&dirptr,sizeof(struct direct)); /* Get entry */
  421.             if ((status == ERROR) || (status == NULL))/* Quit on err or EOF */
  422.                break;
  423.             if (dirptr.d_ino)                  /* If not deleted */
  424.             {
  425.                strcpy(&filename[5],dirptr.d_name);
  426.                if (stat(filename,&statbuf))     /* Get status */
  427.                   break;
  428.                else
  429.                {
  430.                   statbuf.st_mode &= S_IFMT;    /* Mask file type bits */
  431.                   if ((statbuf.st_mode == S_IFBLK) && /* block type device */
  432.                       (statbuf.st_size == device)) /* Maj. and Min. match ? */
  433.                      found = TRUE;                 /* Yes, return name */
  434.                }
  435.             }
  436.          }
  437.    }
  438.    else
  439.       return(prterr("Invalid  device or file specified",errstr));
  440.  
  441.    if (fpt != ERROR)
  442.       close(fpt);                        /* We're done with it */
  443.    if (found)
  444.       if ((freeblks = get_disk(filename)) != ERROR) /* Get the data */
  445.          return(freeblks);
  446.    return(prterr("Disk read error",errstr));
  447. }
  448.  
  449. long get_disk(name)
  450. char *name;
  451. {
  452.    int dpt;
  453.    unsigned char freeb[3];
  454.    long size;
  455.  
  456.    size = ERROR;                        /* assume error */
  457.    if ((dpt = open(name,0)) == ERROR)   /* Open the block device */
  458.       return(ERROR);
  459.    sync();                              /* Make sure count is up to date */
  460.    if (lseek(dpt,(long) 512 + 21, 0) != ERROR) /* Position in SIR */
  461.       if (read(dpt,freeb,3) != ERROR)   /* Get the three bytes */
  462.          l3tol(&size,freeb,1);          /* Convert to long int */
  463.    close(dpt);
  464.    return (size);
  465. }
  466.  
  467. set_date(filename,filedate,errmsg)
  468. char *filename,
  469.      *errmsg;
  470. long filedate;
  471. {
  472.    if (chtim(filename,filedate) == ERROR) /* change the date */
  473.       return(prterr("Error setting file date",errmsg));
  474.    else
  475.       return(NULL);
  476. }
  477.  
  478. set_dir(directory,errmsg)
  479. char *directory,
  480.      *errmsg;
  481. {
  482.    if (chdir(directory) == ERROR)
  483.       return(prterr("Error setting directory",errmsg));
  484.    else
  485.       return NULL;
  486. }
  487.