Chapter 14. Creating a user Layer

This chapter explains some of the internals of the FFIO system and explains the ways in which you can put together a user or site layer. “user Layer Example”, is an example of a user layer.

Internal Functions

The FFIO system has an internal model of data that maps to any given actual logical file type based on the following concepts:

  • Data is a stream of bits. Layers must declare their granularity by using the fffcntl(3c) call.

  • Record marks are boundaries between logical records.

  • End-of-file marks (EOF) are a special type of record that exists in some file structures.

  • End-of-data (EOD) is a point immediately beyond the last data bit, EOR, or EOF in the file. You cannot read past or write after an EOD. In a case when a file is positioned after an EOD, a write operation (if valid) immediately moves the EOD to a point after the last data bit, end-of-record (EOR), or EOF produced by the write.

All files are streams that contain zero or more data bits that may contain record or file marks.

No inherent hierarchy or ordering is imposed on the file structures. Any number of data bits or EOR and EOF marks may appear in any order. The EOD, if present, is by definition last. Given the EOR, EOF, and EOD return statuses from read operations, only EOR may be returned along with data. When data bits are immediately followed by EOF, the record is terminated implicitly.

Individual layers can impose restrictions for specific file structures that are more restrictive than the preceding rules. For instance, in COS blocked files, an EOR always immediately precedes an EOF.

Successful mappings were used for all logical file types supported, except formats that have more than one type of partitioning for files (such as end-of-group or more than one level of EOF). For example, some CDC file formats have level numbers in the partitions. FFIO and CDC map level 017 to an EOF. No other handling is provided for these level numbers.

Internally, there are two main protocol components: the operations and the stat structure.

The Operations Structure

Many of the operations try to mimic system calls. In the man pages for ffread(3c), ffwrite(3c), and others, the calls can be made without the optional parameters and appear like the system calls. Internally, all parameters are required.

The following list is a brief synopsis of the interface routines that are supported at the user level. Each of these ff entry points checks the parameters and issues the corresponding internal call. Each interface routine provides defaults and dummy arguments for those optional arguments that the user does not provide.

Each layer must have an internal entry point for all of these operations; although in some cases, the entry point may simply issue an error or do nothing. For example, the syscall layer uses _ff_noop for the ffflush entry point because it has no buffer to flush, and it uses _ff_err2 for the ffweof entry point because it has no representation for EOF. No optional parameters for calls to the internal entry points exist. All arguments are required.

A list of operations called as functions from a C program follows:

fd = ffopen(file, flags, mode, stat);
nb = ffread(fd, buf, nb, stat, fulp, &ubc);
opos = ffseek(fd, pos, whence, stat);
nb = ffreada(fd, buf, nb, stat, fulp, &ubc);
ret = ffpos(fd,cmd, argp, len,  stat)
ret = fffcntl(fd, cmd, arg, stat);
nb = ffwritea(fd, buf, nb, stat, fulp, &ubc);

The following are the variables for the internal entry points and the variable definitions. An internal entry point must be provided for all of these operations:

Variable

Definition

fd

The FFIO pointer (struct fdinfo *)fd.

file

A char* file.

flags

File status flag for open, such as O_RDONLY.

buf

Bit pointer to the user data.

nb

Number of bytes.

ret

The status returned; >=0 is valid, <0 is error.

stat

A pointer to the status structure.

fulp

The value FULL or PARTIAL defined in ffio.h for full or partial-record mode.

&ubc

A pointer to the unused bit count; this ranges from 0 to 7 and represents the bits not used in the last byte of the operation. It is used for both input and output.

pos

A byte position in the file.

opos

The old position of the file, just like the system call.

whence

The same as the syscall.

cmd

The command request to the fffcntl (3c) call.

arg

A generic pointer to the fffcntl argument.

mode

Bit pattern denoting file's access permissions.

argp

A pointer to the input or output data.

len

The length of the space available at argp. It is used primarily on output to avoid overwriting the available memory.

FFIO and the Stat Structure

The stat structure contains four fields in the current implementation. They mimic the iosw structure of the ASYNC syscalls to the extent possible. All operations are expected to update the stat structure on each call. The SETSTAT and ERETURN macros are provided in ffio.h for this purpose.

The fields in the stat structure are as follows:

Status field 

Description

stat.sw_flag 

0 indicates outstanding; 1 indicates I/O complete.

stat.sw_error 

0 indicates no error; otherwise, the error number.

stat.sw_count 

Number of bytes transferred in this request. This number is rounded up to the next integral value if a partial byte is transferred.

stat.sw_stat 

This tells the status of the I/O operation. The FFSTAT(stat) macro accesses this field. The following are the possible values:

FFBOD: At beginning-of-data (BOD).

FFCNT: Request terminated by count (either the count of bytes before EOF or EOD in the file or the count of the request).

FFEOR: Request termination by EOR or a full record mode read was processed.

FFEOF: EOF encountered.

FFEOD: EOD encountered.

FFERR: Error encountered.

If count is satisfied simultaneously with EOR, the FFEOR is returned.

The EOF and EOD status values must never be returned with data. This means that if a byte-stream file is being traversed and the file contains 100 bytes and then an EOD, a read of 500 bytes will return with a stat value of FFCNT and a return byte count of 100. The next read operation returns FFEOD and a count of 0.

A FFEOF or FFEOD status is always returned with a zero-byte transfer count.

user Layer Example

This section gives a complete and working user layer. It traces I/O at a given level. All operations are passed through to the next lower-level layer, and a trace record is sent to the trace file.

The first step in generating a user layer is to create a table that contains the addresses for the routines which fulfill the required functions described in “The Operations Structure”, and “FFIO and the Stat Structure”. The format of the table can be found in struct xtr_s, which is found in the <ffio.h> file. No restriction is placed on the names of the routines, but the table must be called _usr_ffvect for it to be recognized as a user layer. In the example, the declaration of the table can be found with the code in the _usr_open routine.

To use this layer, you must take advantage of the soft external files in the library.

On IRIX systems, to build for the n32 ABI on MIPS3 architectures:

cc -c  -n32 -mips3 usr*.c -D_LIB_INTERNAL 
f90 -n32 -mips3 usr*.o main.f -o abs 
assign -F user,others... fort.1
./abs

static char USMID[] = "@(#)code/usrbksp.c       1.0    ";
/*   COPYRIGHT SGI
*    UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
*    THE COPYRIGHT LAWS OF THE UNITED STATES.
*/
#include <ffio.h>
#include "usrio.h"
/*
*    trace backspace requests
*/
int
_usr_bksp(struct fdinfo *fio, struct ffsw *stat)
     {
     struct fdinfo *llfio;
     int ret;

     llfio = fio->fioptr;
     _usr_enter(fio, TRC_BKSP);
     _usr_pr_2p(fio, stat);
     ret = XRCALL(llfio, backrtn) llfio, stat);
     _usr_exit(fio, ret, stat);
    return(0);
    }

 static char USMID[] = "@(#)code.usrclose.c     1.0    ";
/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */
#include <stdio.h>
#include <malloc.h>
#include <ffio.h>
#include "usrio.h"
/*
 *  trace close requests
 */
int
_usr_close(struct fdinfo *fio, struct ffsw *stat)
        {
        struct fdinfo *llfio;
        struct trace_f *pinfo;
        int ret;
        llfio = fio->fioptr;
/*
 *  lyr_info is a place in the fdinfo block that holds
 *  a pointer to the layer's private information.
 */
        pinfo = (struct trace_f *)fio->lyr_info;

        _usr_enter(fio, TRC_CLOSE);
        _usr_pr_2p(fio, stat);
/*
 *  close file
 */
        ret = XRCALL(llfio, closertn) llfio, stat);
/*
 *  It is the layer's responsibility to clean up its mess.
 */
        free(pinfo->name);
        pinfo->name = NULL;
        free(pinfo);
        _usr_exit(fio, ret, stat);
        (void) close(pinfo->usrfd);
        return(0);
        }

static char USMID[] = "@(#)code/usrfcntl.c       1.0    ";
/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */
#include <ffio.h>
#include "usrio.h"
/*
 *  trace fcntl requests
 *
 *  Parameters:
 *   fd      - fdinfo pointer
 *   cmd     - command code
 *   arg     - command specific parameter
 *   stat    - pointer to status return word
 *
 * This fcntl routine passes the request down to the next lower
 * layer, so it provides nothing of its own.
 *
 * When writing a user layer, the fcntl routine must be provided,
 * and must provide correct responses to one essential function and
 * two desirable functions.
 *
 *  FC_GETINFO: (essential)
 *  If the 'cmd' argument is FC_GETINFO, the fields of the 'arg' is
 *  considered a pointer to an ffc_info_s structure, and the fields
 *  must be filled. The most important of these is the ffc_flags
 *  field, whose bits are defined in <ffio.h>.(Look for FFC_STRM
 *  through FFC_NOTRN)
 *  FC_STAT: (desirable)
 *  FC_RECALL: (desirable)
 */
int
_usr_fcntl(struct fdinfo *fio, int cmd, void *arg, struct ffsw *stat)
        {
        struct fdinfo *llfio;
        struct trace_f *pinfo;
        int ret;

        llfio = fio->fioptr;
        pinfo = (struct trace_f *)fio->lyr_info;
        _usr_enter(fio, TRC_FCNTL);
        _usr_info(fio, "cmd=%d ", cmd);
        ret = XRCALL(llfio, fcntlrtn) llfio, cmd, arg, stat);
        _usr_exit(fio, ret, stat);
        return(ret);
        }

static char USMID[] = "@(#)code/usropen.c       1.0    ";

/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */
#include <stdio.h>
#include <fcntl.h>
#include <malloc.h>
#include <ffio.h>
#include "usrio.h"
#define SUFFIX      ".trc"

/*
 * trace open requests;
 * The following routines compose the user layer. They are declared
 * in "usrio.h"
 */

/*
 * Create the _usr_ffvect structure.  Note the _ff_err inclusion to
 * account for the listiortn, which is not supported by this user
 * layer
 */
struct xtr_s _usr_ffvect =
  {
  _usr_open,   _usr_read,   _usr_reada,   _usr_readc,
  _usr_write,  _usr_writea, _usr_writec,  _usr_close,
  _usr_flush,  _usr_weof,   _usr_weod,    _usr_seek,
  _usr_bksp,   _usr_pos,    _usr_err,     _usr_fcntl
   };

_ffopen_t
_usr_open(
         const char *name,
         int flags, 
         mode_t mode,
         struct fdinfo * fio,
         union spec_u *spec,
         struct ffsw *stat,
         long cbits,
         int cblks,
         struct gl_o_inf *oinf)
         {
         union spec_u *nspec;
         struct fdinfo *llfio;
         struct trace_f *pinfo;
         char *ptr = NULL;
         int  namlen, usrfd;
         _ffopen_t nextfio;
         char buf[256];

         namlen = strlen(name);
         ptr = malloc(namlen + strlen(SUFFIX) + 1);
         if (ptr == NULL) goto badopen;
         pinfo = (struct trace_f *)malloc(sizeof(struct trace_f));
         if (pinfo == NULL) goto badopen;

         fio->lyr_info = (char *)pinfo;
/*
 *  Now, build the name of the trace info file, and open it.
 */
         strcpy(ptr, name);
         strcat(ptr, SUFFIX);
         usrfd = open(ptr, O_WRONLY | O_APPEND | O_CREAT, 0666);
/*
 *  Put the file info into the private data area.
 */
         pinfo->name = ptr;
         pinfo->usrfd = usrfd;
         ptr[namlen] = '\0';
/*
 *  Log the open call
 */
         _usr_enter(fio, TRC_OPEN);
         sprintf(buf,"(\"%s\", %o, %o...);\n", name, flags, mode);
         _usr_info(fio, buf, 0);
/*
 *  Now, open the lower layers
 */
         nspec = spec;
         NEXT_SPEC(nspec);
         nextfio = _ffopen(name, flags, mode, nspec, stat, cbits, cblks,
		                  NULL, oinf);
         _usr_exit_ff(fio, nextfio, stat);
         if (nextfio != _FFOPEN_ERR)
                {
                DUMP_IOB(fio); /* debugging only */
                return(nextfio);
                }
/*
 *  End up here only on an error
 *
 */

badopen:
        if(ptr != NULL) free(ptr);
        if (fio->lyr_info != NULL) free(fio->lyr_info);
        _SETERROR(stat, FDC_ERR_NOMEM, 0);
	        return(_FFOPEN_ERR);
        }
        _usr_err(struct fdinfo *fio)
        {
	        _usr_info(fio,"ERROR: not expecting this routine\n",0);
	        return(0);
        }

static char USMID[] = "@(#)code/usrpos.c       1.1    ";

/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */

#include <ffio.h>
#include "usrio.h"

/*
 *  trace positioning requests
 */

_ffseek_t
_usr_pos(struct fdinfo *fio, int cmd, void *arg, int len, struct ffsw *stat)
   {
   struct fdinfo *llfio;
   struct trace_f *usr_info;
   _ffseek_t ret;

   llfio = fio->fioptr;
   usr_info = (struct trace_f *)fio->lyr_info;

   _usr_enter(fio,TRC_POS);
   _usr_info(fio, " ", 0);
   ret = XRCALL(llfio, posrtn) llfio, cmd, arg, len, stat);
   _usr_exit_sk(fio, ret, stat);
   return(ret);
   }

static char USMID[] = "@(#)code/usrprint.c       1.1    ";

/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */
#include <stdio.h>
#include <ffio.h>
#include "usrio.h"

static char *name_tab[] =
                        {
                        "???",
                        "ffopen",
                        "ffread",
                        "ffreada",
                        "ffreadc",
                        "ffwrite",
                        "ffwritea",
                        "ffwritec",
                        "ffclose",
                        "ffflush",
                        "ffweof",
                        "ffweod",
                        "ffseek",
                        "ffbksp",
                        "ffpos",
                        "fflistio",
                        "fffcntl",
                        };

/*
 * trace printing stuff
 */
int
_usr_enter(struct fdinfo *fio, int opcd)
                {
                char buf[256], *op;
                struct trace_f *usr_info;

                op = name_tab[opcd];
                usr_info = (struct trace_f *)fio->lyr_info;
                sprintf(buf, "TRCE: %s ",op);
                write(usr_info->usrfd, buf, strlen(buf));
                return(0);
                }

void
_usr_info(struct fdinfo *fio, char *str, int arg1)
       {
       char buf[256];
       struct trace_f *usr_info;

       usr_info = (struct trace_f *)fio->lyr_info;
       sprintf(buf, str, arg1);
       write(usr_info->usrfd, buf, strlen(buf));
       }

void
_usr_exit(struct fdinfo *fio, int ret, struct ffsw *stat)
        {
        char buf[256];
        struct trace_f *usr_info;

        usr_info = (struct trace_f *)fio->lyr_info;
        fio->ateof = fio->fioptr->ateof;
        fio->ateod = fio->fioptr->ateod;
        sprintf(buf, "TRCX:   ret=%d, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
        write(usr_info->usrfd, buf, strlen(buf));
        }

void
_usr_exit_ss(struct fdinfo *fio, ssize_t ret, struct ffsw *stat)
        {
        char buf[256];
        struct trace_f *usr_info;

        usr_info = (struct trace_f *)fio->lyr_info;
        fio->ateof = fio->fioptr->ateof;
        fio->ateod = fio->fioptr->ateod;
#ifdef __mips
#if (_MIPS_SZLONG== 32)
        sprintf(buf, "TRCX:   ret=%lld, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#else
        sprintf(buf, "TRCX:   ret=%ld, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#endif
#else
        sprintf(buf, "TRCX:   ret=%d, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#endif
        write(usr_info->usrfd, buf, strlen(buf));
        }

void
_usr_exit_ff(struct fdinfo *fio, _ffopen_t ret, struct ffsw *stat)
        {
        char buf[256];
        struct trace_f *usr_info;

        usr_info = (struct trace_f *)fio->lyr_info;
#ifdef __mips
        sprintf(buf, "TRCX:   ret=%lx, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#else
        sprintf(buf, "TRCX:   ret=%d, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#endif
        write(usr_info->usrfd, buf, strlen(buf));
	}
void
_usr_exit_sk(struct fdinfo *fio, _ffseek_t ret, struct ffsw *stat)
        {
        char buf[256];
        struct trace_f *usr_info;
        usr_info = (struct trace_f *)fio->lyr_info;
        fio->ateof = fio->fioptr->ateof;
        fio->ateod = fio->fioptr->ateod;
#ifdef __mips
#if (_MIPS_SZLONG== 32)
        sprintf(buf, "TRCX:   ret=%lld, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#else
        sprintf(buf, "TRCX:   ret=%ld, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#endif
#else
        sprintf(buf, "TRCX:   ret=%d, stat=%d, err=%d\n",
             ret, stat->sw_stat, stat->sw_error);
#endif
        write(usr_info->usrfd, buf, strlen(buf));
        }
void
_usr_pr_rwc(
struct fdinfo *fio, 
bitptr bufptr, 
size_t nbytes,
struct ffsw *stat, 
int fulp)
        {
        char buf[256];
        struct trace_f *usr_info;

        usr_info = (struct trace_f *)fio->lyr_info;
#ifdef __mips
#if (_MIPS_SZLONG == 64) && (_MIPS_SZPTR == 64)
        sprintf(buf,"(fd / %lx */, &memc[%lx], %ld, &statw[%lx], ",
             fio, BPTR2CP(bufptr), nbytes, stat);
#else if (_MIPS_SZLONG == 32) && (_MIPS_SZPTR == 32)
        sprintf(buf,"(fd / %lx */, &memc[%lx], %lld, &statw[%lx], ",
		          fio, BPTR2CP(bufptr), nbytes, stat);
#endif
#else
        sprintf(buf,"(fd / %x */, &memc[%x], %d, &statw[%x], ",
             fio, BPTR2CP(bufptr), nbytes, stat);
#endif
        write(usr_info->usrfd, buf, strlen(buf));
        if (fulp == FULL)
	             sprintf(buf,"FULL");
	      else
               sprintf(buf,"PARTIAL");
               write(usr_info->usrfd, buf, strlen(buf));
        }
void
_usr_pr_rww(
struct fdinfo *fio, 
bitptr bufptr, 
size_t nbytes,
struct ffsw *stat, 
int fulp, 
int *ubc)
        {
        char buf[256];
        struct trace_f *usr_info;

        usr_info = (struct trace_f *)fio->lyr_info;
#ifdef __mips
#if (_MIPS_SZLONG == 64) && (_MIPS_SZPTR == 64)
        sprintf(buf,"(fd / %lx */, &memc[%lx], %ld, &statw[%lx], ",
             fio, BPTR2CP(bufptr), nbytes, stat);
#else if (_MIPS_SZLONG == 32) && (_MIPS_SZPTR == 32)
        sprintf(buf,"(fd / %lx */, &memc[%lx], %lld, &statw[%lx], ",
             fio, BPTR2CP(bufptr), nbytes, stat);
#endif
#else
        sprintf(buf,"(fd / %x */, &memc[%x], %d, &statw[%x], ",
             fio, BPTR2CP(bufptr), nbytes, stat);
#endif
        write(usr_info->usrfd, buf, strlen(buf));
        if (fulp == FULL)
	            sprintf(buf,"FULL");
       	else
	       sprintf(buf,"PARTIAL");
        write(usr_info->usrfd, buf, strlen(buf));
        sprintf(buf,", &conubc[%d]; ", *ubc);
        write(usr_info->usrfd, buf, strlen(buf));
        }
void
_usr_pr_2p(struct fdinfo *fio, struct ffsw *stat)
        {
        char buf[256];
        struct trace_f *usr_info;

        usr_info = (struct trace_f *)fio->lyr_info;
#ifdef __mips
#if (_MIPS_SZLONG == 64) && (_MIPS_SZPTR == 64)
        sprintf(buf,"(fd / %lx */,  &statw[%lx], ",
             fio,  stat);
#else if (_MIPS_SZLONG == 32) && (_MIPS_SZPTR == 32)
         sprintf(buf,"(fd / %lx */, &statw[%lx], ",
              fio,  stat);
#endif
#else
         sprintf(buf,"(fd / %x */, &statw[%x], ",
              fio,  stat);
#endif
         write(usr_info->usrfd, buf, strlen(buf));
         }

 static char USMID[] = "@(#)code/usrread.c       1.0    ";
/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */

#include <ffio.h>
#include "usrio.h"

/*
 * trace read requests
 *
 * Parameters:
 *  fio     - Pointer to fdinfo block
 *  bufptr  - bit pointer to where data is to go.
 *  nbytes  - Number of bytes to be read
 *  stat    - pointer to status return word
 *  fulp    - full or partial read mode flag
 *  ubc     - pointer to unused bit count
 */
ssize_t
_usr_read(
struct fdinfo *fio,
bitptr bufptr,
size_t nbytes, 
struct ffsw *stat,
int fulp,
int *ubc)
     {
     struct fdinfo *llfio;
     char *str;
     ssize_t ret;
     llfio = fio->fioptr;
     _usr_enter(fio, TRC_READ);
     _usr_pr_rww(fio, bufptr, nbytes, stat, fulp, ubc);
     ret = XRCALL(llfio, readrtn) llfio, bufptr, nbytes, stat,
          fulp, ubc);
     _usr_exit_ss(fio, ret, stat);
     return(ret);
     }

/*
 * trace reada (asynchronous read) requests
 *
 * Parameters:
 *  fio     - Pointer to fdinfo block
 *  bufptr  - bit pointer to where data is to go.
 *  nbytes  - Number of bytes to be read
 *  stat    - pointer to status return word
 *  fulp    - full or partial read mode flag
 *  ubc     - pointer to unused bit count
 */
ssize_t
_usr_reada(
struct fdinfo *fio,
bitptr bufptr, 
size_t nbytes,
struct ffsw *stat, 
int fulp, 
int *ubc)
    {
    struct fdinfo *llfio;
    char *str;
    ssize_t ret;

    llfio = fio->fioptr;
    _usr_enter(fio, TRC_READA);
    _usr_pr_rww(fio, bufptr, nbytes, stat, fulp, ubc);
    ret = XRCALL(llfio,readartn)llfio,bufptr,nbytes,stat,fulp,ubc);
    _usr_exit_ss(fio, ret, stat);
    return(ret);
    }

/*
* trace readc requests
*
* Parameters:
*  fio     - Pointer to fdinfo block
*  bufptr  - bit pointer to where data is to go.
*  nbytes  - Number of bytes to be read
*  stat    - pointer to status return word
*  fulp    - full or partial read mode flag
*/
ssize_t
_usr_readc(
struct fdinfo *fio,
bitptr bufptr,
size_t nbytes, 
struct ffsw *stat, 
int fulp)
     {
     struct fdinfo *llfio;
     char *str;
     ssize_t ret;
     llfio = fio->fioptr;
     _usr_enter(fio, TRC_READC);
     _usr_pr_rwc(fio, bufptr, nbytes, stat, fulp);
     ret = XRCALL(llfio, readcrtn)llfio, bufptr, nbytes, stat,
         fulp);
     _usr_exit_ss(fio, ret, stat);
     return(ret);
        }

/*
* _usr_seek()
*
* The user seek call should mimic the lseek system call as
* much as possible.
*/
_ffseek_t
_usr_seek(
struct fdinfo *fio, 
off_t pos, 
int whence,
struct ffsw *stat)
        {
        struct fdinfo *llfio;
        _ffseek_t ret;
        char buf[256];

        llfio = fio->fioptr;
        _usr_enter(fio, TRC_SEEK);
#ifdef __mips
#if (_MIPS_SZLONG == 64)
        sprintf(buf,"pos %ld, whence %d\n", pos, whence);
#else
        sprintf(buf,"pos %lld, whence %d\n", pos, whence);
#endif
#else
        sprintf(buf,"pos %d, whence %d\n", pos, whence);
#endif
        _usr_info(fio, buf, 0);
        ret = XRCALL(llfio, seekrtn) llfio, pos, whence, stat);
        _usr_exit_sk(fio, ret, stat);
        return(ret);
        }

static char USMID[] = "@(#)code/usrwrite.c       1.0    ";

/*  COPYRIGHT SGI
*  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
*  THE COPYRIGHT LAWS OF THE UNITED STATES.
*/

#include <ffio.h>
#include "usrio.h"

/*
* trace write requests
*
* Parameters:
*  fio     - Pointer to fdinfo block
*  bufptr  - bit pointer to where data is to go.
*  nbytes  - Number of bytes to be written
*  stat    - pointer to status return word
*  fulp    - full or partial write mode flag
*  ubc     - pointer to unused bit count (not used for IBM)
*/
ssize_t
_usr_write(
struct fdinfo *fio, 
bitptr bufptr, 
size_t nbytes, 
struct ffsw *stat, 
int fulp, 
int *ubc)
     {
     struct fdinfo *llfio;
     ssize_t ret;

     llfio = fio->fioptr;
     _usr_enter(fio, TRC_WRITE);
     _usr_pr_rww(fio, bufptr, nbytes, stat, fulp, ubc);
     ret = XRCALL(llfio, writertn) llfio, bufptr, nbytes, stat,
          fulp,ubc);
     _usr_exit_ss(fio, ret, stat);
     return(ret);
     }

/*
* trace writea requests
*
* Parameters:
*  fio     - Pointer to fdinfo block
*  bufptr  - bit pointer to where data is to go.
*  nbytes  - Number of bytes to be written
*  stat    - pointer to status return word
*  fulp    - full or partial write mode flag
*  ubc     - pointer to unused bit count (not used for IBM)
*/
ssize_t
_usr_writea(
struct fdinfo *fio, 
bitptr bufptr,
size_t nbytes, 
struct ffsw *stat, 
int fulp, 
int *ubc)
    {
    struct fdinfo *llfio;
    ssize_t ret;

    llfio = fio->fioptr;
    _usr_enter(fio, TRC_WRITEA);
    _usr_pr_rww(fio, bufptr, nbytes, stat, fulp, ubc);
    ret = XRCALL(llfio, writeartn) llfio, bufptr, nbytes, stat,
        fulp,ubc);
    _usr_exit_ss(fio, ret, stat);
    return(ret);
    }

/*
* trace writec requests
*
* Parameters:
*  fio     - Pointer to fdinfo block
*  bufptr  - bit pointer to where data is to go.
*  nbytes  - Number of bytes to be written
*  stat    - pointer to status return word
*  fulp    - full or partial write mode flag
*/

ssize_t
_usr_writec(
struct fdinfo *fio, 
bitptr bufptr, 
size_t nbytes, 
struct ffsw *stat, 
int fulp)
        {
        struct fdinfo *llfio;
        ssize_t ret;

        llfio = fio->fioptr;
        _usr_enter(fio, TRC_WRITEC);
        _usr_pr_rwc(fio, bufptr, nbytes, stat, fulp);
        ret = XRCALL(llfio, writecrtn)llfio,bufptr, nbytes, stat,
           fulp);
        _usr_exit_ss(fio, ret, stat);
        return(ret);
        }
/*
* Flush the buffer and clean up
* This routine should return 0, or -1 on error.
*/
int
_usr_flush(struct fdinfo *fio, struct ffsw *stat)
        {
        struct fdinfo *llfio;
        int ret;
        llfio = fio->fioptr;

        _usr_enter(fio, TRC_FLUSH);
        _usr_info(fio, "\n",0);
        ret = XRCALL(llfio, flushrtn) llfio, stat);
        _usr_exit(fio, ret, stat);
        return(ret);
        }

/*
* trace WEOF calls
*
* The EOF is a very specific concept.   Don't confuse it with the
* EOF, or the trunc(2) system call.
*/
int
_usr_weof(struct fdinfo *fio, struct ffsw *stat)
        {
        struct fdinfo *llfio;
        int ret;

        llfio = fio->fioptr;
        _usr_enter(fio, TRC_WEOF);
        _usr_info(fio, "\n",0);
        ret = XRCALL(llfio, weofrtn) llfio, stat);
        _usr_exit(fio, ret, stat);
        return(ret);
        }

/*
* trace WEOD calls
*
* The EOD is a specific concept.  Don't confuse it with the 
*  EOF.  It is usually mapped to the trunc(2) system call.
*/
int
_usr_weod(struct fdinfo *fio, struct ffsw *stat)
        {
        struct fdinfo *llfio;
        int ret;

        llfio = fio->fioptr;
        _usr_enter(fio, TRC_WEOD);
        _usr_info(fio, "\n",0);
        ret = XRCALL(llfio, weodrtn) llfio, stat);
        _usr_exit(fio, ret, stat);
        return(ret);
        }


/* USMID @(#)code/usrio.h       1.1    */

/*  COPYRIGHT SGI
 *  UNPUBLISHED -- ALL RIGHTS RESERVED UNDER
 *  THE COPYRIGHT LAWS OF THE UNITED STATES.
 */

#define TRC_OPEN 1
#define TRC_READ 2
#define TRC_READA 3
#define TRC_READC 4
#define TRC_WRITE 5
#define TRC_WRITEA 6
#define TRC_WRITEC 7
#define TRC_CLOSE 8
#define TRC_FLUSH 9
#define TRC_WEOF 10
#define TRC_WEOD 11
#define TRC_SEEK 12
#define TRC_BKSP 13
#define TRC_POS 14
#define TRC_UNUSED 15
#define TRC_FCNTL 16

struct trace_f
        {
        char    *name;          /* name of the file */
        int   usrfd;            /* file descriptor of trace file */
        };
/*
 * Prototypes
 */
extern int _usr_bksp(struct fdinfo *fio, struct ffsw *stat);
extern int _usr_close(struct fdinfo *fio, struct ffsw *stat);
extern int _usr_fcntl(struct fdinfo *fio, int cmd, void *arg,
           struct ffsw *stat);
extern _ffopen_t _usr_open(const char *name, int flags, 
           mode_t mode, struct fdinfo * fio, union spec_u *spec, 
           struct ffsw *stat, long cbits, int cblks, 
           struct gl_o_inf *oinf);
extern int _usr_flush(struct fdinfo *fio, struct ffsw *stat);
extern _ffseek_t _usr_pos(struct fdinfo *fio, int cmd, void *arg,
	          int len, struct ffsw *stat);
extern ssize_t _usr_read(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp, int *ubc);
extern ssize_t _usr_reada(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp, int *ubc);
extern ssize_t _usr_readc(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp);
extern _ffseek_t _usr_seek(struct fdinfo *fio, off_t pos, int whence,
           struct ffsw *stat);
extern ssize_t _usr_write(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp, int *ubc);
extern ssize_t _usr_writea(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp, int *ubc);
extern ssize_t _usr_writec(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp);
extern int _usr_weod(struct fdinfo *fio, struct ffsw *stat);
extern int _usr_weof(struct fdinfo *fio, struct ffsw *stat);
extern int _usr_err();

/* 
 * Prototypes for routines that are used by the user layer.
 */
extern int _usr_enter(struct fdinfo *fio, int opcd);
extern void _usr_info(struct fdinfo *fio, char *str, int arg1);
extern void _usr_exit(struct fdinfo *fio, int ret, struct ffsw *stat);
extern void _usr_exit_ss(struct fdinfo *fio, ssize_t ret, 
           struct ffsw *stat);
extern void _usr_exit_ff(struct fdinfo *fio, _ffopen_t ret, 
           struct ffsw *stat);
extern void _usr_exit_sk(struct fdinfo *fio, _ffseek_t ret, 
           struct ffsw *stat);
extern void _usr_pr_rww(struct fdinfo *fio, bitptr bufptr, 
           size_t nbytes, struct ffsw *stat, int fulp, int *ubc);
extern void _usr_pr_2p(struct fdinfo *fio, struct ffsw *stat);