home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / OS9_Unix.lzh / RSHSRC / rmt.c < prev    next >
C/C++ Source or Header  |  1992-10-01  |  11KB  |  439 lines

  1. /*
  2.  * rmt - remote tape server
  3.  *    osk'ed by ip <pczip@chem.nott.ac.uk>
  4.  *    Oct 1992
  5.  */
  6. /*
  7.  * Copyright (c) 1983 Regents of the University of California.
  8.  * All rights reserved.
  9.  *
  10.  * Redistribution and use in source and binary forms are permitted
  11.  * provided that the above copyright notice and this paragraph are
  12.  * duplicated in all such forms and that any documentation,
  13.  * advertising materials, and other materials related to such
  14.  * distribution and use acknowledge that the software was developed
  15.  * by the University of California, Berkeley.  The name of the
  16.  * University may not be used to endorse or promote products derived
  17.  * from this software without specific prior written permission.
  18.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21.  */
  22.  
  23. #ifndef lint
  24. char copyright[] =
  25. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  26.  All rights reserved.\n\
  27.  Additional material  Copyright (c) 1992 Ivan Powis\n";
  28. #endif /* not lint */
  29.  
  30. #ifndef lint
  31. static char sccsid[] = "@(#)rmt.c    5.4 (Berkeley) 6/29/88";
  32. #endif /* not lint */
  33.  
  34. /*
  35.  * rmt daemon.
  36.  */
  37.  
  38. #include    <stdio.h>
  39. #include    <sys/types.h>
  40. #include    <inet/socket.h>
  41. #include    <sys/mtio.h>
  42. #include    <errno.h>
  43. #include    <sg_codes.h>
  44. #include    <modes.h>
  45. extern int    errno;
  46.  
  47. int    tapefd = -1;        /* file descriptor for tape device */
  48.  
  49. char    *record = NULL;        /* pointer to our malloc'ed buffer */
  50.  
  51. #define    MAXSTRING    64
  52. char    device[MAXSTRING];    /* device/filename to open */
  53. char    count[MAXSTRING];    /* count for read(2) and write(2) and others */
  54. char    offset[MAXSTRING];    /* offset for lseek(2) */
  55. char    whence[MAXSTRING];    /* whence for lseek(2) */
  56. char    mode[MAXSTRING];    /* mode for open(2) */
  57. char    op[MAXSTRING];        /* operation for mt ioctl */
  58.  
  59. char    respstr[BUFSIZ];    /* response string we send back to client */
  60.  
  61. long    lseek();
  62. long    atol();
  63. char    *malloc();
  64. char    *checkbuf();        /* our function, at end of file */
  65.  
  66. FILE    *debug;
  67. #define    DEBUG(f)    if (debug) fprintf(debug, f)
  68. #define    DEBUG1(f,a)    if (debug) fprintf(debug, f, a)
  69. #define    DEBUG2(f,a1,a2)    if (debug) fprintf(debug, f, a1, a2)
  70.  
  71. main(argc, argv)
  72. int    argc;
  73. char    **argv;
  74. {
  75.     int        n, i, cc, respval;
  76.     long        lrespval;
  77.     char        c;
  78.     struct mtop    mtop;
  79.     struct mtget    mtget;
  80.  
  81.     argc--, argv++;
  82.     if (argc > 0) {
  83.         /*
  84.          * If a command line argument is specified, take that as the
  85.          * name of a file to write debugging information into.
  86.          */
  87.  
  88.         if ( (debug = fopen(*argv, "w")) == NULL)
  89.             exit(1);
  90.         setbuf(debug, NULL);    /* completely unbuffered */
  91.     }
  92.  
  93.     /*
  94.      * We communicate with the client on descriptors 0 and 1.
  95.      * Since we're invoked by rshd, both are set to the stream socket
  96.      * that inetd accepts from the client.
  97.      * We read from fd 0 and write to fd 1, so that for testing we can
  98.      * just invoke this program interactively and it'll work with
  99.      * stdin and stdout.
  100.      */
  101. top:
  102.     errno   = 0;        /* Unix errno, clear before every operation */
  103.  
  104.     if (read(0, &c, 1) != 1)
  105.         exit(0);    /* EOF (normal way to end) or error */
  106.  
  107.     switch (c) {
  108.  
  109.     case 'O':                        /* open */
  110.         if (tapefd >= 0)
  111.             close(tapefd);    /* implies a close of currently-open
  112.                        device */
  113.         get_string(device);
  114.         get_string(mode);
  115.         DEBUG2("rmtd: O %s %s\n", device, mode);
  116.  
  117.         if(strncmp(device,"/dev",4) == 0) strcpy(device,device+4);
  118.             /* if /dev/mt??? convert to /mt??? */
  119.         if ( (tapefd = open(device, os9mode(atoi(mode)))) < 0)
  120.             resp_ioerr(errno);
  121.         else
  122.             resp_val((long) 0);
  123.         break;
  124.  
  125.     case 'C':                        /* close */
  126.         DEBUG("rmtd: C\n");
  127.         get_string(device);        /* required, but ignored */
  128.  
  129.         if (close(tapefd) < 0)
  130.             resp_ioerr(errno);
  131.         else
  132.             resp_val((long) 0);
  133.  
  134.         tapefd = -1;    /* will force any i/o operations to generate
  135.                    an error, until another device is opened */
  136.         break;
  137.  
  138.     case 'L':                        /* lseek */
  139.         get_string(offset);
  140.         get_string(whence);
  141.         DEBUG2("rmtd: L %s %s\n", offset, whence);
  142.  
  143.         if ( (lrespval = lseek(tapefd, atol(offset), atoi(whence))) < 0)
  144.             resp_ioerr(errno);
  145.         else
  146.             resp_val(lrespval);    /* lseek return value */
  147.         break;
  148.  
  149.     case 'W':                        /* write */
  150.         get_string(count);
  151.         DEBUG1("rmtd: W %s\n", count);
  152.  
  153.         n = atoi(count);
  154.         record = checkbuf(record, n, SO_RCVBUF);
  155.  
  156.         /*
  157.          * We have to loop, to read a record of the specified size
  158.          * from the socket.
  159.          */
  160.  
  161.         for (i = 0; i < n; i += cc) {
  162.             if ( (cc = read(0, &record[i], n - i)) <= 0) {
  163.                 DEBUG("rmtd: premature eof\n");
  164.                 exit(2);
  165.             }
  166.         }
  167.  
  168.         /*
  169.          * Write a single tape record.  Note that we don't respond to
  170.          * the client until the write(2) system call returns.
  171.          */
  172.  
  173.         if ( (respval = write(tapefd, record, n)) < 0)
  174.             resp_ioerr(errno);
  175.         else
  176.             resp_val((long) respval);    /* #bytes written */
  177.         break;
  178.  
  179.     case 'R':                        /* read */
  180.         get_string(count);
  181.         DEBUG1("rmtd: R %s\n", count);
  182.  
  183.         n = atoi(count);
  184.         record = checkbuf(record, n, SO_SNDBUF);
  185.  
  186.         if ( (respval = read(tapefd, record, n)) < 0)
  187.             resp_ioerr(errno);
  188.         else {
  189.             resp_val((long) respval);    /* #bytes */
  190.             resp_buff(record, respval);    /* the actual data */
  191.         }
  192.         break;
  193.  
  194.     case 'I':                        /* MT ioctl */
  195.         get_string(op);
  196.         get_string(count);
  197.         DEBUG2("rmtd: I %s %s\n", op, count);
  198.  
  199.         mtop.mt_op    = atoi(op);
  200.         mtop.mt_count = atoi(count);
  201.         if (ioctl(tapefd, MTIOCTOP, (char *) &mtop) < 0)
  202.             resp_ioerr(errno);
  203.         else
  204.             resp_val((long) mtop.mt_count);
  205.         break;
  206.  
  207.     case 'S':                        /* MT status */
  208.         DEBUG("rmtd: S\n");
  209.  
  210.         if (ioctl(tapefd, MTIOCGET, (char *) &mtget) < 0)
  211.             resp_ioerr(errno);
  212.         else {
  213.             resp_val((long) sizeof(mtget));
  214.             resp_buff((char *) &mtget, sizeof(mtget));
  215.         }
  216.         break;
  217.  
  218.     default:
  219.         DEBUG1("rmtd: garbage command %c\n", c);
  220.         exit(3);
  221.     }
  222.     goto top;
  223. }
  224.  
  225. /*
  226.  * Send a normal response to the client.
  227.  */
  228.  
  229. resp_val(lval)
  230. long    lval;        /* has to be a long, for lseek() return value */
  231. {
  232.     register int    n;
  233.  
  234.     DEBUG1("rmtd: A %ld\n", lval);
  235.  
  236.     sprintf(respstr, "A%ld\l", lval);
  237.     n = strlen(respstr);
  238.     if (write(1, respstr, n) != n) {
  239.         DEBUG("rmtd: resp_val: write error\n");
  240.         exit(5);
  241.     }
  242. }
  243.  
  244. /*
  245.  * Send a response buffer to the client.
  246.  */
  247.  
  248. resp_buff(buff, nbytes)
  249. char    *buff;
  250. int    nbytes;
  251. {
  252.     if (write(1, buff, nbytes) != nbytes) {
  253.         DEBUG("rmtd: resp_buff: write error\n");
  254.         exit(6);
  255.     }
  256. }
  257.  
  258. /*
  259.  * Send an error response to the client.
  260.  * Notice that we send the error string associated with "errno" to the
  261.  * client, not just the errno value, since if it is a different flavor
  262.  * of Unix (or not even Unix at all) the errno values may not be
  263.  * meaningful.
  264.  */
  265.  
  266. resp_ioerr(errnum)
  267. int    errnum;        /* the Unix errno */
  268. {
  269.     char        msgstr[100];
  270.     extern int    sys_nerr;
  271.     extern char    *sys_errlist[];
  272.  
  273.     if (errnum > 0 && errnum < sys_nerr)
  274.         sprintf(msgstr, "%s", sys_errlist[errnum]);
  275.     else
  276.         sprintf(msgstr, "errno = %d", errnum);
  277.  
  278.     DEBUG2("rmtd: E %d (%s)\n", errnum, msgstr);
  279.     sprintf(respstr, "E%d\l%s\l", errnum, msgstr);
  280.     resp_buff(respstr, strlen(respstr));
  281. }
  282.  
  283. /*
  284.  * Get a string from the command line (the socket).
  285.  */
  286.  
  287. get_string(bp)
  288. char    *bp;        /* string gets stored here by us */
  289. {
  290.     register int    i;
  291.     register char    *cp;
  292.  
  293.     cp = bp;
  294.     for (i = 0; i < (MAXSTRING - 1); i++) {
  295.         /*
  296.          * Read one byte at a time, looking for the newline.
  297.          * Note that this differs from the rmt(8C) man page.
  298.          * Commands with multiple arguments (such as 'O') require
  299.          * a newline between the arguments.  Also, we do not skip
  300.          * over any leading white space, so the command character
  301.          * must be immediately followed by the first argument.
  302.          */
  303.  
  304.         if (read(0, cp+i, 1) != 1)
  305.             exit(0);
  306.  
  307.         if (cp[i] == '\l')
  308.             break;
  309.     }
  310.     cp[i] = '\0';
  311. }
  312.  
  313. /*
  314.  * The following function is called before every record is written or read
  315.  * to or from the tape.  Since we have to read or write every tape record
  316.  * with a single read(2) or write(2) system call, we have to assure
  317.  * we have a buffer that is big enough.
  318.  * What we do is keep track of the largest record we've seen so far, and
  319.  * whenever a larger record is required, we free(3) the old buffer and
  320.  * malloc(3) a new one.
  321.  *
  322.  * Additionally, when we malloc a buffer, we set the socket's buffer size
  323.  * to the new size (or as close to it as possible).
  324.  */
  325.  
  326. static int    maxrecsize = -1;    /* largest record we've seen so far */
  327.  
  328. char *            /* return pointer to buffer to use */
  329. checkbuf(ptr, size, option)
  330. char    *ptr;        /* pointer to current buffer */
  331. int    size;        /* size of current buffer */
  332. int    option;        /* for setsockopt: SO_SNDBUF or SO_RCVBUF */
  333. {
  334.  
  335.     if (size <= maxrecsize)
  336.         return(ptr);        /* current buffer is big enough */
  337.  
  338.     if (ptr != NULL)
  339.         free(ptr);        /* first free the existing buffer */
  340.                     /* then malloc a new buffer */
  341.     if ( (ptr = malloc(size)) == NULL) {
  342.         DEBUG("rmtd: cannot allocate buffer space\n");
  343.         exit(4);
  344.     }
  345.  
  346.     maxrecsize = size;        /* remember new buffer size */
  347.  
  348. /* Current ISP libraries only support a limited range of socket options
  349.  * and bomb in a bad way on some others. So for now forget this bit !
  350.  */
  351. #ifdef NEW_ISP
  352.     while ((size > 1024) &&
  353.            (setsockopt(0, SOL_SOCKET, option, (char *) &size,
  354.                 sizeof(size)) < 0))
  355.         size -= 1024;
  356. #else
  357.     size= 1+((size-1)%1024);
  358. #endif
  359.     return(ptr);        /* return pointer to the new buffer */
  360. }
  361.  
  362. /*------------------------------------------------------------------------*/
  363. int os9mode(mode)
  364. int mode;
  365. {
  366.     switch(mode&3){
  367.         case 0:        /*UNIX O_RDONLY*/
  368.             return S_IREAD;
  369.         case 1:        /*UNIX O_WRONLY*/
  370.             return S_IWRITE;
  371.         default:
  372.         case 2:        /*UNIX O_RDWR*/
  373.             return S_IREAD|S_IWRITE;
  374.     }
  375. }
  376.  
  377. int ioctl(fd, code, arg)
  378. int fd, code;
  379. char *arg;
  380. {
  381.     /* Restricted ioctl - only does MT stuff */
  382.     struct mtop *op;
  383.     struct mtget *gt;
  384.     int count;
  385.  
  386.     switch (code) {
  387.         case MTIOCTOP:        /* do command */
  388.             op=(struct mtop *) arg;
  389.             count=op->mt_count;
  390.             switch(op->mt_op){
  391.                 case MTWEOF:
  392.                     return(_ss_stat(fd,SS_WFM,count));
  393.                 case MTBSF:
  394.                     count=-count;
  395.                 case MTFSF:
  396.                     return(_ss_stat(fd,SS_RFM,count));
  397.                 case MTBSR:
  398.                     count=-count;
  399.                 case MTFSR:
  400.                     return(_ss_stat(fd,SS_Skip,count));
  401.                 case MTREW:
  402.                     return(_ss_stat(fd,SS_Reset,count));
  403.                 case MTOFFL:
  404.                     if(_ss_stat(fd,SS_Reset,count) ==-1) return (-1);
  405.                     return(_ss_stat(fd,SS_SQD,count));
  406.                 case MTNOP:
  407.                     return (0);
  408.                 default:
  409.                     errno= EINVAL;
  410.                     return (-1);
  411.             }
  412.             break;
  413.         case MTIOCGET:
  414.             gt=(struct mtget *) arg;
  415.             gt->mt_type=MT_ISSTREAM;
  416.             gt->mt_resid=0;
  417.             gt->mt_dsreg1=0;
  418.             gt->mt_dsreg2=0;
  419.             gt->mt_gstat=GMT_ONLINE(-1);
  420.             return 0;
  421.         default:
  422.             errno=EINVAL;
  423.             return (-1);
  424.     }
  425. }
  426.  
  427. #asm
  428. _ss_stat:
  429.     movem.l    d2,-(sp)
  430.     move.l    8(sp),d2
  431.     os9    I$SetStt
  432.     bcs.s    notgood
  433.     clr.l    d1
  434. notgood
  435.     move.l    d1,d0
  436.     movem.l    (sp)+,d2
  437.     rts
  438. #endasm
  439.