xfstests updates - rework build to be like other xfs packages, revive some old fs...
[xfstests-dev.git] / lib / tlibio.c
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  * 
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * 
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  * 
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  * 
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  * 
26  * http://www.sgi.com 
27  * 
28  * For further information regarding this notice, see: 
29  * 
30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31  */
32 /*
33  *
34  * Lib i/o
35  *
36  * This file contains several functions to doing reads and writes.
37  * It was written so that a single function could be called in a test
38  * program and only a io type field value would have to change to
39  * do different types of io.  There is even a couple of functions that
40  * will allow you to parse a string to determine the iotype.
41  *
42  * This file contains functions for writing/reading to/from open files
43  * Prototypes:
44  *
45  * Functions declared in this module - see individual function code for
46  * usage comments:
47  *
48  *  int  stride_bounds(int offset, int stride, int nstrides,
49  *                    int bytes_per_stride, int *min, int *max);
50
51  *  int  lio_write_buffer(int fd, int method, char *buffer, int size,
52  *                                              char **errmsg, long wrd);
53  *  int  lio_read_buffer(int fd, int method, char *buffer, int size,
54  *                                              char **errmsg, long wrd);
55  *
56  *  #ifdef CRAY
57  *  int  lio_wait4asyncio(int method, int fd, struct iosw **statptr)
58  *  int  lio_check_asyncio(char *io_type, int size, struct iosw *status)
59  *  #endif
60  *  #ifdef sgi
61  *  int  lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
62  *  int  lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
63  *  #endif
64  *
65  *  int  lio_parse_io_arg1(char *string)
66  *  void lio_help1(char *prefix);
67  *
68  *  int  lio_parse_io_arg2(char *string, char **badtoken)
69  *  void lio_help2(char *prefix);
70  *
71  *  int  lio_set_debug(int level);
72  *
73  *  char Lio_SysCall[];
74  *  struct lio_info_type Lio_info1[];
75  *  struct lio_info_type Lio_info2[];
76  *
77  *  Author : Richard Logan
78  *
79  */
80
81 #include <stdio.h>
82 #include <ctype.h>
83 #include <fcntl.h>
84 #include <unistd.h>
85 #include <sys/types.h>
86 #include <sys/stat.h>
87 #include <sys/time.h>          
88 #include <sys/param.h>
89 #include <errno.h>
90 #include <sys/types.h>
91 #include <sys/file.h>
92 #include <signal.h>
93 #ifdef CRAY
94 #include <sys/secparm.h>
95 #include <sys/iosw.h>
96 #include <sys/listio.h>
97 #else
98 /* for linux or sgi */
99 #include <sys/uio.h> /* readv(2)/writev(2) */
100 #include <string.h>  /* bzero */
101 #endif
102 #ifdef sgi
103 #include <aio.h>
104 #endif
105 #include <stdlib.h> /* atoi, abs */
106
107 #include "tlibio.h"             /* defines LIO* marcos */
108
109 #ifndef PATH_MAX
110 #define PATH_MAX        MAXPATHLEN
111 #endif
112
113 #if 0 /* disabled until it's needed -- roehrich 6/11/97 */
114 #define BUG1_workaround 1 /* Work around a condition where aio_return gives
115                            * a value of zero but there is no errno followup
116                            * and the read/write operation actually did its
117                            * job.   spr/pv 705244
118                            */
119 #endif
120
121
122 #ifndef linux
123 static void lio_async_signal_handler();
124 #endif
125 #ifdef sgi
126 static void lio_async_callback_handler();
127 #endif
128
129 /*
130  * Define the structure as used in lio_parse_arg1 and lio_help1
131  */
132 struct lio_info_type  Lio_info1[] = {
133     { "s", LIO_IO_SYNC, "sync i/o" },
134     { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
135     { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
136     { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
137 #ifdef sgi
138     { "r", 
139         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random sync i/o types and wait methods" },
140     { "R", 
141         LIO_RANDOM|LIO_IO_ATYPES|LIO_WAIT_ATYPES, "random i/o types and wait methods" },
142 #else
143     { "r", 
144         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
145     { "R", 
146         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
147 #endif
148     { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
149     { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
150     { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
151     { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
152     { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
153 };
154
155 /*
156  * Define the structure used by lio_parse_arg2 and lio_help2
157  */
158 struct lio_info_type  Lio_info2[] = {
159     { "sync",      LIO_IO_SYNC,         "sync i/o (read/write)"},
160     { "async",     LIO_IO_ASYNC,        "async i/o (reada/writea/aio_read/aio_write)" },
161     { "slistio",   LIO_IO_SLISTIO,      "single stride sync listio" },
162     { "alistio",   LIO_IO_ALISTIO,      "single stride async listio" },
163     { "syncv",     LIO_IO_SYNCV,        "single buffer sync readv/writev"},
164     { "syncp",     LIO_IO_SYNCP,        "pread/pwrite"},
165     { "active",    LIO_WAIT_ACTIVE,     "spin on status/control values" },
166     { "recall",    LIO_WAIT_RECALL,     "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
167     { "sigactive", LIO_WAIT_SIGACTIVE,  "spin waiting for signal" },
168     { "sigpause",  LIO_WAIT_SIGPAUSE,   "call pause(2) to wait for signal" },
169 /* nowait is a touchy thing, it's an accident that this implementation worked at all.  6/27/97 roehrich */
170 /*    { "nowait",    LIO_WAIT_NONE,     "do not wait for async io to complete" },*/
171     { "random",    LIO_RANDOM,          "set random bit" },
172     { "randomall", 
173         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, 
174         "all random i/o types and wait methods (except nowait)" },
175 };
176
177 char Lio_SysCall[PATH_MAX];     /* string containing last i/o system call */
178
179 static volatile int Received_signal = 0;        /* number of signals received */
180 static volatile int Rec_signal;
181 #ifdef sgi
182 static volatile int Received_callback = 0;      /* number of callbacks received */
183 static volatile int Rec_callback;
184 #endif
185 static char Errormsg[500];
186 static int Debug_level = 0;
187
188
189
190 /***********************************************************************
191  * stride_bounds()
192  *
193  * Determine the bounds of a strided request, normalized to offset.  Returns
194  * the number of bytes needed to satisfy the request, and optionally sets
195  * *min and *max to the mininum and maximum bytes referenced, normalized 
196  * around offset.
197  *
198  * Returns -1 on error - the only possible error conditions are illegal values
199  * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
200  *
201  * (maule, 11/16/95)
202  ***********************************************************************/
203
204 int
205 stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
206 int     offset;
207 int     stride;
208 int     nstrides;
209 int     bytes_per_stride;
210 int     *min;
211 int     *max;
212 {
213         int     nbytes, min_byte, max_byte;
214
215         /*
216          * sanity checks ...
217          */
218
219         if (nstrides < 0 || bytes_per_stride < 0) {
220                 return -1;
221         }
222
223         if (stride == 0) {
224                 stride = bytes_per_stride;
225         }
226
227         /*
228          * Determine the # of bytes needed to satisfy the request.  This
229          * value, along with the offset argument, determines the min and max
230          * bytes referenced.
231          */
232
233
234         nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
235
236         if (stride < 0) {
237                 max_byte = offset + bytes_per_stride - 1;
238                 min_byte = max_byte - nbytes + 1;
239         } else {
240                 min_byte = offset;
241                 max_byte = min_byte + nbytes - 1;
242         }
243         
244         if (min != NULL) {
245                 *min = min_byte;
246         }
247         
248         if (max != NULL) {
249                 *max = max_byte;
250         }
251
252         return nbytes;
253 }
254
255 /***********************************************************************
256  * This function will allow someone to set the debug level.
257  ***********************************************************************/
258 int
259 lio_set_debug(level)
260 {
261     int old;
262
263     old = Debug_level;
264     Debug_level = level;
265     return old;
266 }
267
268 /***********************************************************************
269  * This function will parse a string and return desired io-method.
270  * Only the first character of the string is used.
271  *
272  * This function does not provide for meaningful option arguments,
273  * but it supports current growfiles/btlk interface.
274  *
275  *  (rrl 04/96)
276  ***********************************************************************/
277 int
278 lio_parse_io_arg1(char *string)
279 {
280     int ind;
281     int found=0;
282     int mask=0;
283
284     /*
285      * Determine if token is a valid string.
286      */
287     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
288         if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
289             mask |= Lio_info1[ind].bits;
290             found = 1;
291             break;
292         }
293     }
294
295     if ( found == 0 ) {
296         return -1;
297     }
298
299     return mask;
300
301 }
302
303 /***********************************************************************
304  * This function will print a help message describing the characters
305  * that can be parsed by lio_parse_io_arg1().
306  * They will be printed one per line.
307  *  (rrl 04/96)
308  ***********************************************************************/
309 void
310 lio_help1(char *prefix)
311 {
312     int ind;
313
314     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
315         printf("%s %s : %s\n", prefix,
316             Lio_info1[ind].token, Lio_info1[ind].desc);
317     }
318
319     return;
320 }
321
322 /***********************************************************************
323  * This function will parse a string and return the desired io-method.
324  * This function will take a comma separated list of io type and wait
325  * method tokens as defined in Lio_info2[].  If a token does not match
326  * any of the tokens in Lio_info2[], it will be coverted to a number.
327  * If it was a number, those bits are also set.
328  * 
329  *  (rrl 04/96)
330  ***********************************************************************/
331 int
332 lio_parse_io_arg2(char *string, char **badtoken)
333 {
334    char *token = string;
335    char *cc = token;
336    char savecc;
337    int found;
338    int mask=0;
339
340    int tmp;
341    int ind;
342    char chr;
343
344    if ( token == NULL )
345         return -1;
346
347    for (;;) {
348         for (; ((*cc != ',') && (*cc != '\0')); cc++);
349         savecc = *cc;
350         *cc = '\0';
351
352         found = 0; 
353
354         /*
355          * Determine if token is a valid string or number and if
356          * so, add the bits to the mask.
357           */
358         for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
359             if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
360                 mask |= Lio_info2[ind].bits;
361                 found = 1;
362                 break;
363             }
364         }
365
366         /*
367          * If token does not match one of the defined tokens, determine
368          * if it is a number, if so, add the bits.
369          */
370         if ( !found ) {
371             if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
372                 mask |= tmp;
373                 found=1;
374             }
375         }
376
377         *cc = savecc;
378
379         if (!found) {  /* token is not valid */
380             if ( badtoken != NULL)
381                 *badtoken = token;
382             return(-1);
383         }
384
385         if (savecc == '\0')
386             break;
387
388         token = ++cc;
389     }
390
391     return mask;
392 }
393
394 /***********************************************************************
395  * This function will print a help message describing the tokens
396  * that can be parsed by lio_parse_io_arg2().
397  * It will print them one per line.
398  *
399  * (rrl 04/96)
400  ***********************************************************************/
401 void
402 lio_help2(char *prefix)
403 {
404     int ind;
405
406     for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
407         printf("%s %s : %s\n", prefix,
408             Lio_info2[ind].token, Lio_info2[ind].desc);
409     }
410     return;
411 }
412
413 #ifndef linux
414 /***********************************************************************
415  * This is an internal signal handler.
416  * If the handler is called, it will increment the Received_signal
417  * global variable.
418  ***********************************************************************/
419 static void
420 lio_async_signal_handler(int sig)
421 {
422         if ( Debug_level )
423             printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
424                 __FILE__, __LINE__, sig, Received_signal+1);
425
426         Received_signal++;
427
428         return;
429 }
430 #endif
431
432 #ifdef sgi
433 /***********************************************************************
434  * This is an internal callback handler.
435  * If the handler is called, it will increment the Received_callback
436  * global variable.
437  ***********************************************************************/
438 static void
439 lio_async_callback_handler(sigval_t sigval)
440 {
441         if ( Debug_level )
442             printf("DEBUG %s/%d: received callback, nbytes=%ld, a callback called %d times\n",
443                 __FILE__, __LINE__, sigval.sival_int, Received_callback+1);
444
445         Received_callback++;
446
447         return;
448 }
449 #endif /* sgi */
450
451 /***********************************************************************
452  * lio_random_methods
453  * This function will randomly choose an io type and wait method
454  * from set of io types and wait methods.  Since this information
455  * is stored in a bitmask, it randomly chooses an io type from
456  * the io type bits specified and does the same for wait methods.
457  *
458  * Return Value
459  * This function will return a value with all non choosen io type
460  * and wait method bits cleared.  The LIO_RANDOM bit is also 
461  * cleared.  All other bits are left unchanged.
462  *
463  * (rrl 04/96)
464  ***********************************************************************/
465 int
466 lio_random_methods(long curr_mask)
467 {
468     int mask=0;
469     long random_bit();
470
471     /* remove random select, io type, and wait method bits from curr_mask */
472     mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
473
474     /* randomly select io type from specified io types */
475     mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
476
477     /* randomly select wait methods  from specified wait methods */
478     mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
479
480     return mask;
481 }
482
483 /***********************************************************************
484  * Generic write function 
485  * This function can be used to do a write using write(2), writea(2),
486  * aio_write(3), writev(2), pwrite(2),
487  * or single stride listio(2)/lio_listio(3).
488  * By setting the desired bits in the method
489  * bitmask, the caller can control the type of write and the wait method
490  * that will be used.  If no io type bits are set, write will be used.
491  *
492  * If async io was attempted and no wait method bits are set then the
493  * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
494  * aio_write(3) and lio_listio(3).
495  *
496  * If multiple wait methods are specified, 
497  * only one wait method will be used. The order is predetermined.
498  *
499  * If the call specifies a signal and one of the two signal wait methods,
500  * a signal handler for the signal is set.  This will reset an already
501  * set handler for this signal. 
502  *
503  * If the LIO_RANDOM method bit is set, this function will randomly
504  * choose a io type and wait method from bits in the method argument.
505  *
506  * If an error is encountered, an error message will be generated
507  * in a internal static buffer.  If errmsg is not NULL, it will
508  * be updated to point to the static buffer, allowing the caller
509  * to print the error message.
510  *
511  * Return Value
512  *   If a system call fails, -errno is returned.
513  *   If LIO_WAIT_NONE bit is set, the return value is the return value
514  *   of the system call.
515  *   If the io did not fail, the amount of data written is returned.
516  *      If the size the system call say was written is different
517  *      then what was asked to be written, errmsg is updated for
518  *      this error condition.  The return value is still the amount
519  *      the system call says was written.  
520  *
521  * (rrl 04/96)
522  ***********************************************************************/
523 int
524 lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
525 int fd;         /* open file descriptor */
526 int method;     /* contains io type and wait method bitmask */
527 char *buffer;   /* pointer to buffer */
528 int size;       /* the size of the io */
529 int sig;        /* signal to use if async io */
530 char **errmsg;  /* char pointer that will be updated to point to err message */
531 long wrd;       /* to allow future features, use zero for now */
532 {
533     int ret = 0;        /* syscall return or used to get random method */
534     char *io_type;              /* Holds string of type of io */
535 #ifndef linux
536     int omethod = method;
537     int listio_cmd;             /* Holds the listio/lio_listio cmd */
538 #endif
539 #ifdef  CRAY
540     struct listreq request;     /* Used when a listio is wanted */
541     struct iosw status, *statptr[1];  
542 #else
543     /* for linux or sgi */
544     struct iovec iov;   /* iovec for writev(2) */
545 #endif
546 #ifdef sgi
547     aiocb_t aiocbp;     /* POSIX aio control block */
548     aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
549     off64_t poffset;    /* pwrite(2) offset */
550 #endif
551
552     /*
553      * If LIO_RANDOM bit specified, get new method randomly.
554      */
555     if ( method & LIO_RANDOM ) {
556         if( Debug_level > 3 )
557                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
558         method = lio_random_methods(method);
559         if ( Debug_level > 2 )
560             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
561     }
562
563     if ( errmsg != NULL )
564         *errmsg = Errormsg;
565
566     Rec_signal=Received_signal; /* get the current number of signals received */
567 #ifdef sgi
568     Rec_callback=Received_callback;     /* get the current number of callbacks received */
569 #endif
570
571 #ifdef  CRAY
572     bzero(&status, sizeof(struct iosw));
573     bzero(&request, sizeof(struct listreq));
574     statptr[0] = &status;
575 #else
576     /* for linux or sgi */
577     bzero(&iov, sizeof(struct iovec));
578     iov.iov_base = buffer;
579     iov.iov_len = size;
580 #endif
581 #ifdef sgi
582     bzero(&aiocbp, sizeof(aiocb_t));
583     aiocbp.aio_fildes = fd;
584     aiocbp.aio_nbytes = size;
585     aiocbp.aio_buf = buffer;
586 /*    aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
587     aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
588     aiocbp.aio_sigevent.sigev_signo = 0;
589     aiocbp.aio_sigevent.sigev_func = NULL;
590     aiocbp.aio_sigevent.sigev_value.sival_int = 0;
591     aiolist[0] = &aiocbp;
592
593     if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
594         ret = 0;
595         /* If there is an error and it is not ESPIPE then kick out the error.
596          * If the fd is a fifo then we have to make sure that
597          * lio_random_methods() didn't select pwrite/pread; if it did then
598          * switch to write/read.
599          */
600         if( errno == ESPIPE ){
601                 if( method & LIO_IO_SYNCP ){
602                         if( omethod & LIO_RANDOM ){
603                                 method &= ~LIO_IO_SYNCP;
604                                 method |= LIO_IO_SYNC;
605                                 if( Debug_level > 2 )
606                                         printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
607                         }
608                         else if( Debug_level ){
609                                 printf("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n",
610                                        __FILE__, __LINE__ );
611                         }
612                 }
613                 /* else: let it ride */
614         }
615         else{
616                 sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d  %s",
617                         __FILE__, __LINE__, fd, errno, strerror(errno));
618                 return -errno;
619         }
620     }
621     poffset = (off64_t)ret;
622     aiocbp.aio_offset = ret;
623
624 #endif
625
626     /*
627      * If the LIO_USE_SIGNAL bit is not set, only use the signal
628      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
629      * Otherwise there is not necessary a signal handler to trap
630      * the signal.
631      */
632     if ( sig && !(method & LIO_USE_SIGNAL) && 
633         ! (method & LIO_WAIT_SIGTYPES) ){
634
635         sig=0;  /* ignore signal parameter */
636     }
637
638 #ifdef sgi
639     if ( sig && (method & LIO_WAIT_CBTYPES) )
640         sig=0; /* ignore signal parameter */
641 #endif
642
643     /*
644      * only setup signal hander if sig was specified and
645      * a sig wait method was specified.
646      * Doing this will change the handler for this signal.  The
647      * old signal handler will not be restored.
648      *** restoring the signal handler could be added ***
649      */
650
651     if ( sig &&  (method & LIO_WAIT_SIGTYPES) ){
652 #ifdef CRAY
653         sigctl(SCTL_REG, sig, lio_async_signal_handler);
654 #endif
655 #ifdef sgi
656         aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
657         aiocbp.aio_sigevent.sigev_signo = sig;
658         sigset(sig, lio_async_signal_handler);
659 #endif /* sgi */
660     }
661 #ifdef sgi
662     else if( method & LIO_WAIT_CBTYPES ){
663         /* sival_int just has to be something that I can use
664          * to identify the callback, and "size" happens to be handy...
665          */
666         aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
667         aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
668         aiocbp.aio_sigevent.sigev_value.sival_int = size;
669     }
670 #endif
671
672     /*
673      * Determine the system call that will be called and produce
674      * the string of the system call and place it in Lio_SysCall.
675      * Also update the io_type char pointer to give brief description
676      * of system call.  Execute the system call and check for
677      * system call failure.  If sync i/o, return the number of
678      * bytes written/read.
679      */
680      
681     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
682         /*
683          * write(2) is used if LIO_IO_SYNC bit is set or not none
684          * of the LIO_IO_TYPES bits are set (default).
685          */
686
687         sprintf(Lio_SysCall,
688             "write(%d, buf, %d)", fd, size);
689         io_type="write";
690
691         if ( Debug_level ) {
692             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
693         }
694
695         if ((ret = write(fd, buffer, size)) == -1) {
696             sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
697                 __FILE__, __LINE__,
698                 fd, size, errno, strerror(errno));
699             return -errno;
700         }
701
702         if ( ret != size ) {
703             sprintf(Errormsg,
704                 "%s/%d write(%d, buf, %d) returned=%d",
705                     __FILE__, __LINE__,
706                     fd, size, ret);
707         }
708         else if ( Debug_level > 1 )
709             printf("DEBUG %s/%d: write completed without error (ret %d)\n",
710                 __FILE__, __LINE__, ret);
711
712         return ret;
713
714     }
715
716     else if ( method & LIO_IO_ASYNC ) {
717 #ifdef CRAY
718         sprintf(Lio_SysCall,
719             "writea(%d, buf, %d, &status, %d)", fd, size, sig);
720         io_type="writea";
721
722         if ( Debug_level ) {
723             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
724         }
725
726         sigoff();
727         if ((ret = writea(fd, buffer, size, &status, sig)) == -1) {
728             sprintf(Errormsg,
729                 "%s/%d writea(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
730                     __FILE__, __LINE__,
731                 fd, size, sig, errno, strerror(errno));
732             sigon();
733             return -errno;
734         }
735 #endif
736 #ifdef sgi
737         sprintf(Lio_SysCall,
738             "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
739         io_type="aio_write";
740
741         if ( Debug_level ) {
742             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
743         }
744
745         if( sig )
746                 sighold( sig );
747         if ((ret = aio_write(&aiocbp)) == -1) {
748             sprintf(Errormsg,
749                 "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
750                     __FILE__, __LINE__,
751                 fd, size, sig, errno, strerror(errno));
752             if( sig )
753                 sigrelse( sig );
754             return -errno;
755         }
756 #endif
757     } /* LIO_IO_ASYNC */
758
759     else if ( method & LIO_IO_SLISTIO ) {
760 #ifdef CRAY
761         request.li_opcode = LO_WRITE;
762         request.li_fildes = fd;
763         request.li_buf = buffer;
764         request.li_nbyte = size;
765         request.li_status = &status;
766         request.li_signo = sig;
767         request.li_nstride = 0;
768         request.li_filstride = 0;
769         request.li_memstride = 0;
770
771         listio_cmd=LC_WAIT;
772         io_type="listio(2) sync write";
773
774         sprintf(Lio_SysCall, 
775                 "listio(LC_WAIT, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
776                 fd, size);
777
778         if ( Debug_level ) {
779             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
780         }
781
782         sigoff();
783         if ( listio(listio_cmd, &request, 1) == -1 ) {
784             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
785                     __FILE__, __LINE__,
786                 Lio_SysCall, fd, size, errno, strerror(errno));
787             sigon();
788             return -errno;
789         }
790
791         if ( Debug_level > 1 )
792             printf("DEBUG %s/%d: %s did not return -1\n",
793                 __FILE__, __LINE__, Lio_SysCall);
794
795         ret=lio_check_asyncio(io_type, size,  &status);
796         return ret;
797
798 #endif
799 #ifdef sgi
800
801         aiocbp.aio_lio_opcode = LIO_WRITE;
802         listio_cmd=LIO_WAIT;
803         io_type="lio_listio(3) sync write";
804
805         sprintf(Lio_SysCall,
806                 "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d",
807                 fd, size, sig );
808
809         if ( Debug_level ) {
810             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
811         }
812
813         if( sig )
814             sighold( sig );
815         if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
816             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
817                     __FILE__, __LINE__,
818                 Lio_SysCall, fd, size, errno, strerror(errno));
819             if( sig )
820                 sigrelse( sig );
821             return -errno;
822         }
823
824         if ( Debug_level > 1 )
825             printf("DEBUG %s/%d: %s did not return -1\n",
826                 __FILE__, __LINE__, Lio_SysCall);
827
828         ret=lio_check_asyncio(io_type, size,  &aiocbp, method);
829         return ret;
830 #endif
831     } /* LIO_IO_SLISTIO */
832
833     else if ( method & LIO_IO_ALISTIO ) {
834 #ifdef CRAY
835         request.li_opcode = LO_WRITE;
836         request.li_fildes = fd;
837         request.li_buf = buffer;
838         request.li_nbyte = size;
839         request.li_status = &status;
840         request.li_signo = sig;
841         request.li_nstride = 0;
842         request.li_filstride = 0;
843         request.li_memstride = 0;
844
845         listio_cmd=LC_START;
846         io_type="listio(2) async write";
847
848         sprintf(Lio_SysCall, 
849                 "listio(LC_START, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
850                 fd, size);
851
852         if ( Debug_level ) {
853             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
854         }
855
856         sigoff();
857         if ( listio(listio_cmd, &request, 1) == -1 ) {
858             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
859                     __FILE__, __LINE__,
860                 Lio_SysCall, fd, size, errno, strerror(errno));
861             sigon();
862             return -errno;
863         }
864 #endif
865 #ifdef sgi
866         aiocbp.aio_lio_opcode = LIO_WRITE;
867         listio_cmd=LIO_NOWAIT;
868         io_type="lio_listio(3) async write";
869
870         sprintf(Lio_SysCall,
871                 "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d",
872                 fd, size);
873
874         if ( Debug_level ) {
875             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
876         }
877
878         if( sig )
879                 sighold( sig );
880         if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
881             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
882                     __FILE__, __LINE__,
883                 Lio_SysCall, fd, size, errno, strerror(errno));
884             if( sig )
885                 sigrelse( sig );
886             return -errno;
887         }
888 #endif
889     }/* LIO_IO_ALISTIO */
890
891 #ifndef CRAY
892     else if ( method & LIO_IO_SYNCV ) {
893         io_type="writev(2)";
894
895         sprintf(Lio_SysCall, 
896                 "writev(%d, &iov, 1) nbyte:%d", fd, size);
897
898         if ( Debug_level ) {
899             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
900         }
901         if ((ret = writev(fd, &iov, 1)) == -1) {
902             sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
903                     __FILE__, __LINE__,
904                 fd, size, errno, strerror(errno));
905             return -errno;
906         }
907
908         if ( ret != size ) {
909             sprintf(Errormsg,
910                 "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
911                     __FILE__, __LINE__,
912                     fd, size, ret);
913         }
914         else if ( Debug_level > 1 )
915             printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
916                 __FILE__, __LINE__, ret);
917
918         return ret;
919     } /* LIO_IO_SYNCV */
920 #endif
921
922 #ifdef sgi
923     else if ( method & LIO_IO_SYNCP ) {
924         io_type="pwrite(2)";
925
926         sprintf(Lio_SysCall, 
927                 "pwrite(%d, buf, %d, %lld)", fd, size, poffset);
928
929         if ( Debug_level ) {
930             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
931         }
932         if ((ret = pwrite(fd, buffer, size, poffset)) == -1) {
933             sprintf(Errormsg, "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s",
934                     __FILE__, __LINE__,
935                 fd, size, poffset, errno, strerror(errno));
936             return -errno;
937         }
938
939         if ( ret != size ) {
940             sprintf(Errormsg,
941                 "%s/%d pwrite(%d, buf, %d, %lld) returned=%d",
942                     __FILE__, __LINE__,
943                     fd, size, poffset, ret);
944         }
945         else if ( Debug_level > 1 )
946             printf("DEBUG %s/%d: pwrite completed without error (ret %d)\n",
947                 __FILE__, __LINE__, ret);
948
949         return ret;
950     } /* LIO_IO_SYNCP */
951 #endif
952
953     else {
954         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
955         return -1;
956     }
957
958     /*
959      * wait for async io to complete.
960      */
961 #ifdef CRAY
962     ret=lio_wait4asyncio(method, fd, statptr);
963 #endif
964 #ifdef sgi
965     ret=lio_wait4asyncio(method, fd, &aiocbp);
966 #endif
967
968     /*
969      * If there was an error waiting for async i/o to complete,
970      * return the error value (errno) to the caller.
971      * Note: Errormsg should already have been updated.
972      */
973     if ( ret < 0 ) {
974         return ret;
975     }
976
977     /*
978      * If i/o was not waited for (may not have been completed at this time),
979      * return the size that was requested.
980      */
981     if ( ret == 1 )
982         return size;
983
984     /*
985      * check that async io was successful.
986      * Note:  if the there was an system call failure, -errno
987      * was returned and Errormsg should already have been updated.
988      * If amount i/o was different than size, Errormsg should already 
989      * have been updated but the actual i/o size if returned.
990      */
991     
992 #ifdef CRAY
993     ret=lio_check_asyncio(io_type, size, &status);
994 #endif
995 #ifdef sgi
996     ret=lio_check_asyncio(io_type, size, &aiocbp, method);
997 #endif
998
999     return ret;
1000 }       /* end of lio_write_buffer */
1001
1002 /***********************************************************************
1003  * Generic read function 
1004  * This function can be used to do a read using read(2), reada(2),
1005  * aio_read(3), readv(2), pread(2),
1006  * or single stride listio(2)/lio_listio(3).
1007  * By setting the desired bits in the method
1008  * bitmask, the caller can control the type of read and the wait method
1009  * that will be used.  If no io type bits are set, read will be used.
1010  *
1011  * If async io was attempted and no wait method bits are set then the
1012  * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
1013  * aio_read(3) and lio_listio(3).
1014  *
1015  * If multiple wait methods are specified, 
1016  * only one wait method will be used. The order is predetermined.
1017  *
1018  * If the call specifies a signal and one of the two signal wait methods,
1019  * a signal handler for the signal is set.  This will reset an already
1020  * set handler for this signal. 
1021  *
1022  * If the LIO_RANDOM method bit is set, this function will randomly
1023  * choose a io type and wait method from bits in the method argument.
1024  *
1025  * If an error is encountered, an error message will be generated
1026  * in a internal static buffer.  If errmsg is not NULL, it will
1027  * be updated to point to the static buffer, allowing the caller
1028  * to print the error message.
1029  *
1030  * Return Value
1031  *   If a system call fails, -errno is returned.
1032  *   If LIO_WAIT_NONE bit is set, the return value is the return value
1033  *   of the system call.
1034  *   If the io did not fail, the amount of data written is returned.
1035  *      If the size the system call say was written is different
1036  *      then what was asked to be written, errmsg is updated for
1037  *      this error condition.  The return value is still the amount
1038  *      the system call says was written.  
1039  *
1040  * (rrl 04/96)
1041  ***********************************************************************/
1042 int
1043 lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
1044 int fd;         /* open file descriptor */
1045 int method;     /* contains io type and wait method bitmask */
1046 char *buffer;   /* pointer to buffer */
1047 int size;       /* the size of the io */
1048 int sig;        /* signal to use if async io */
1049 char **errmsg;  /* char pointer that will be updated to point to err message */
1050 long wrd;       /* to allow future features, use zero for now */
1051 {
1052     int ret = 0;        /* syscall return or used to get random method */
1053     char *io_type;              /* Holds string of type of io */
1054 #ifndef linux
1055     int listio_cmd;             /* Holds the listio/lio_listio cmd */
1056     int omethod = method;
1057 #endif
1058 #ifdef  CRAY
1059     struct listreq request;     /* Used when a listio is wanted */
1060     struct iosw status, *statptr[1];  
1061 #else
1062     /* for linux or sgi */
1063     struct iovec iov; /* iovec for readv(2) */
1064 #endif
1065 #ifdef sgi
1066     aiocb_t aiocbp;     /* POSIX aio control block */
1067     aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
1068     off64_t poffset;    /* pread(2) offset */
1069 #endif
1070
1071     /*
1072      * If LIO_RANDOM bit specified, get new method randomly.
1073      */
1074     if ( method & LIO_RANDOM ) {
1075         if( Debug_level > 3 )
1076                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
1077         method = lio_random_methods(method);
1078         if ( Debug_level > 2 )
1079             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
1080     }
1081
1082     if ( errmsg != NULL )
1083         *errmsg = Errormsg;
1084
1085     Rec_signal=Received_signal; /* get the current number of signals received */
1086 #ifdef sgi
1087     Rec_callback=Received_callback;     /* get the current number of callbacks received */
1088 #endif
1089
1090 #ifdef  CRAY
1091     bzero(&status, sizeof(struct iosw));
1092     bzero(&request, sizeof(struct listreq));
1093     statptr[0] = &status;
1094 #else
1095     /* for linux or sgi */
1096     bzero(&iov, sizeof(struct iovec));
1097     iov.iov_base = buffer;
1098     iov.iov_len = size;
1099 #endif
1100 #ifdef sgi
1101     bzero(&aiocbp, sizeof(aiocb_t));
1102     aiocbp.aio_fildes = fd;
1103     aiocbp.aio_nbytes = size;
1104     aiocbp.aio_buf = buffer;
1105 /*    aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
1106     aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
1107     aiocbp.aio_sigevent.sigev_signo = 0;
1108     aiocbp.aio_sigevent.sigev_func = NULL;
1109     aiocbp.aio_sigevent.sigev_value.sival_int = 0;
1110     aiolist[0] = &aiocbp;
1111
1112     if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
1113         ret = 0;
1114         /* If there is an error and it is not ESPIPE then kick out the error.
1115          * If the fd is a fifo then we have to make sure that
1116          * lio_random_methods() didn't select pwrite/pread; if it did then
1117          * switch to write/read.
1118          */
1119         if( errno == ESPIPE ){
1120                 if( method & LIO_IO_SYNCP ){
1121                         if( omethod & LIO_RANDOM ){
1122                                 method &= ~LIO_IO_SYNCP;
1123                                 method |= LIO_IO_SYNC;
1124                                 if( Debug_level > 2 )
1125                                         printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
1126                         }
1127                         else if( Debug_level ){
1128                                 printf("DEBUG %s/%d: pread will fail when it reads from a fifo\n",
1129                                        __FILE__, __LINE__ );
1130                         }
1131                 }
1132                 /* else: let it ride */
1133         }
1134         else{
1135                 sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d  %s",
1136                         __FILE__, __LINE__, fd, errno, strerror(errno));
1137                 return -errno;
1138         }
1139     }
1140     poffset = (off64_t)ret;
1141     aiocbp.aio_offset = ret;
1142
1143 #endif
1144
1145     /*
1146      * If the LIO_USE_SIGNAL bit is not set, only use the signal
1147      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
1148      * Otherwise there is not necessarily a signal handler to trap
1149      * the signal.
1150      */
1151     if ( sig && !(method & LIO_USE_SIGNAL) &&
1152         ! (method & LIO_WAIT_SIGTYPES) ){
1153
1154         sig=0;  /* ignore signal parameter */
1155     }
1156
1157 #ifdef sgi
1158     if ( sig && (method & LIO_WAIT_CBTYPES) )
1159         sig=0; /* ignore signal parameter */
1160 #endif
1161
1162     /*
1163      * only setup signal hander if sig was specified and
1164      * a sig wait method was specified.
1165      * Doing this will change the handler for this signal.  The
1166      * old signal handler will not be restored.
1167      *** restoring the signal handler could be added ***
1168      */
1169
1170     if ( sig &&  (method & LIO_WAIT_SIGTYPES) ){
1171 #ifdef CRAY
1172             sigctl(SCTL_REG, sig, lio_async_signal_handler);
1173 #endif
1174 #ifdef sgi
1175             aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
1176             aiocbp.aio_sigevent.sigev_signo = sig;
1177             sigset(sig, lio_async_signal_handler);
1178 #endif /* CRAY */
1179     }
1180 #ifdef sgi
1181     else if( method & LIO_WAIT_CBTYPES ){
1182             aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
1183             aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
1184             /* sival_int just has to be something that I can use
1185              * to identify the callback, and "size" happens to be handy...
1186              */
1187             aiocbp.aio_sigevent.sigev_value.sival_int = size;
1188     }
1189 #endif
1190
1191     /*
1192      * Determine the system call that will be called and produce
1193      * the string of the system call and place it in Lio_SysCall.
1194      * Also update the io_type char pointer to give brief description
1195      * of system call.  Execute the system call and check for
1196      * system call failure.  If sync i/o, return the number of
1197      * bytes written/read.
1198      */
1199      
1200     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
1201         /*
1202          * read(2) is used if LIO_IO_SYNC bit is set or not none
1203          * of the LIO_IO_TYPES bits are set (default).
1204          */
1205
1206         sprintf(Lio_SysCall,
1207             "read(%d, buf, %d)", fd, size);
1208         io_type="read";
1209
1210         if ( Debug_level ) {
1211             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1212         }
1213
1214         if ((ret = read(fd, buffer, size)) == -1) {
1215             sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
1216                     __FILE__, __LINE__,
1217                 fd, size, errno, strerror(errno));
1218             return -errno;
1219         }
1220
1221         if ( ret != size ) {
1222             sprintf(Errormsg,
1223                 "%s/%d read(%d, buf, %d) returned=%d",
1224                     __FILE__, __LINE__,
1225                     fd, size, ret);
1226         }
1227         else if ( Debug_level > 1 )
1228             printf("DEBUG %s/%d: read completed without error (ret %d)\n",
1229                 __FILE__, __LINE__, ret);
1230
1231         return ret;
1232
1233     }
1234
1235     else if ( method & LIO_IO_ASYNC ) {
1236 #ifdef CRAY
1237         sprintf(Lio_SysCall,
1238             "reada(%d, buf, %d, &status, %d)", fd, size, sig);
1239         io_type="reada";
1240
1241         if ( Debug_level ) {
1242             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1243         }
1244
1245         sigoff();
1246         if ((ret = reada(fd, buffer, size, &status, sig)) == -1) {
1247             sprintf(Errormsg,
1248                 "%s/%d reada(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
1249                     __FILE__, __LINE__,
1250                 fd, size, sig, errno, strerror(errno));
1251             sigon();
1252             return -errno;
1253         }
1254 #endif
1255 #ifdef sgi
1256         sprintf(Lio_SysCall,
1257             "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
1258         io_type="aio_read";
1259
1260         if ( Debug_level ) {
1261             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1262         }
1263
1264         if( sig )
1265                 sighold( sig );
1266         if ((ret = aio_read(&aiocbp)) == -1) {
1267             sprintf(Errormsg,
1268                 "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
1269                     __FILE__, __LINE__,
1270                 fd, size, sig, errno, strerror(errno));
1271             if( sig )
1272                 sigrelse( sig );
1273             return -errno;
1274         }
1275 #endif
1276     } /* LIO_IO_ASYNC */
1277
1278     else if ( method & LIO_IO_SLISTIO ) {
1279 #ifdef CRAY
1280         request.li_opcode = LO_READ;
1281         request.li_fildes = fd;
1282         request.li_buf = buffer;
1283         request.li_nbyte = size;
1284         request.li_status = &status;
1285         request.li_signo = sig;
1286         request.li_nstride = 0;
1287         request.li_filstride = 0;
1288         request.li_memstride = 0;
1289
1290         listio_cmd=LC_WAIT;
1291         io_type="listio(2) sync read";
1292
1293         sprintf(Lio_SysCall, 
1294                 "listio(LC_WAIT, &req, 1) LO_READ, fd:%d, nbyte:%d",
1295                 fd, size);
1296
1297         if ( Debug_level ) {
1298             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1299         }
1300
1301         sigoff();
1302         if ( listio(listio_cmd, &request, 1) == -1 ) {
1303             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1304                     __FILE__, __LINE__,
1305                 Lio_SysCall, fd, size, errno, strerror(errno));
1306             sigon();
1307             return -errno;
1308         }
1309
1310         if ( Debug_level > 1 )
1311             printf("DEBUG %s/%d: %s did not return -1\n",
1312                 __FILE__, __LINE__, Lio_SysCall);
1313
1314         ret=lio_check_asyncio(io_type, size,  &status);
1315         return ret;
1316 #endif
1317 #ifdef sgi
1318         aiocbp.aio_lio_opcode = LIO_READ;
1319         listio_cmd=LIO_WAIT;
1320         io_type="lio_listio(3) sync read";
1321
1322         sprintf(Lio_SysCall, 
1323                 "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
1324                 fd, size);
1325
1326         if ( Debug_level ) {
1327             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1328         }
1329
1330         if( sig )
1331                 sighold( sig );
1332         if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
1333             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1334                     __FILE__, __LINE__,
1335                 Lio_SysCall, fd, size, errno, strerror(errno));
1336             if( sig )
1337                 sigrelse( sig );
1338             return -errno;
1339         }
1340
1341         if ( Debug_level > 1 )
1342             printf("DEBUG %s/%d: %s did not return -1\n",
1343                 __FILE__, __LINE__, Lio_SysCall);
1344
1345         ret=lio_check_asyncio(io_type, size,  &aiocbp, method);
1346         return ret;
1347 #endif
1348     }/* LIO_IO_SLISTIO */
1349
1350     else if ( method & LIO_IO_ALISTIO ) {
1351 #ifdef CRAY
1352         request.li_opcode = LO_READ;
1353         request.li_fildes = fd;
1354         request.li_buf = buffer;
1355         request.li_nbyte = size;
1356         request.li_status = &status;
1357         request.li_signo = sig;
1358         request.li_nstride = 0;
1359         request.li_filstride = 0;
1360         request.li_memstride = 0;
1361
1362         listio_cmd=LC_START;
1363         io_type="listio(2) async read";
1364
1365         sprintf(Lio_SysCall, 
1366                 "listio(LC_START, &req, 1) LO_READ, fd:%d, nbyte:%d",
1367                 fd, size);
1368
1369         if ( Debug_level ) {
1370             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1371         }
1372
1373         sigoff();
1374         if ( listio(listio_cmd, &request, 1) == -1 ) {
1375             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1376                     __FILE__, __LINE__,
1377                 Lio_SysCall, fd, size, errno, strerror(errno));
1378             sigon();
1379             return -errno;
1380         }
1381 #endif
1382 #ifdef sgi
1383         aiocbp.aio_lio_opcode = LIO_READ;
1384         listio_cmd=LIO_NOWAIT;
1385         io_type="lio_listio(3) async read";
1386
1387         sprintf(Lio_SysCall, 
1388                 "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
1389                 fd, size);
1390
1391         if ( Debug_level ) {
1392             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1393         }
1394
1395         if( sig )
1396                 sighold( sig );
1397         if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
1398             sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1399                     __FILE__, __LINE__,
1400                 Lio_SysCall, fd, size, errno, strerror(errno));
1401             if( sig )
1402                 sigrelse( sig );
1403             return -errno;
1404         }
1405 #endif
1406     } /* LIO_IO_ALISTIO */
1407
1408 #ifndef CRAY
1409     else if ( method & LIO_IO_SYNCV ) {
1410         io_type="readv(2)";
1411
1412         sprintf(Lio_SysCall, 
1413                 "readv(%d, &iov, 1) nbyte:%d", fd, size);
1414
1415         if ( Debug_level ) {
1416             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1417         }
1418         if ((ret = readv(fd, &iov, 1)) == -1) {
1419             sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
1420                     __FILE__, __LINE__,
1421                 fd, size, errno, strerror(errno));
1422             return -errno;
1423         }
1424
1425         if ( ret != size ) {
1426             sprintf(Errormsg,
1427                 "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
1428                     __FILE__, __LINE__,
1429                     fd, size, ret);
1430         }
1431         else if ( Debug_level > 1 )
1432             printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
1433                 __FILE__, __LINE__, ret);
1434
1435         return ret;
1436     } /* LIO_IO_SYNCV */
1437 #endif
1438
1439 #ifdef sgi
1440     else if ( method & LIO_IO_SYNCP ) {
1441         io_type="pread(2)";
1442
1443         sprintf(Lio_SysCall, 
1444                 "pread(%d, buf, %d, %lld)", fd, size, poffset);
1445
1446         if ( Debug_level ) {
1447             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1448         }
1449         if ((ret = pread(fd, buffer, size, poffset)) == -1) {
1450             sprintf(Errormsg, "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s",
1451                     __FILE__, __LINE__,
1452                 fd, size, poffset, errno, strerror(errno));
1453             return -errno;
1454         }
1455
1456         if ( ret != size ) {
1457             sprintf(Errormsg,
1458                 "%s/%d pread(%d, buf, %d, %lld) returned=%d",
1459                     __FILE__, __LINE__,
1460                     fd, size, poffset, ret);
1461         }
1462         else if ( Debug_level > 1 )
1463             printf("DEBUG %s/%d: pread completed without error (ret %d)\n",
1464                 __FILE__, __LINE__, ret);
1465
1466         return ret;
1467     } /* LIO_IO_SYNCP */
1468 #endif
1469
1470     else {
1471         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
1472         return -1;
1473     }
1474
1475     /*
1476      * wait for async io to complete.
1477      * Note: Sync io should have returned prior to getting here.
1478      */
1479 #ifdef CRAY
1480     ret=lio_wait4asyncio(method, fd, statptr);
1481 #endif
1482 #ifdef sgi
1483     ret=lio_wait4asyncio(method, fd, &aiocbp);
1484 #endif
1485
1486     /*
1487      * If there was an error waiting for async i/o to complete,
1488      * return the error value (errno) to the caller.
1489      * Note: Errormsg should already have been updated.
1490      */
1491     if ( ret < 0 ) {
1492         return ret;
1493     }
1494
1495     /*
1496      * If i/o was not waited for (may not have been completed at this time),
1497      * return the size that was requested.
1498      */
1499     if ( ret == 1 )
1500         return size;
1501
1502     /*
1503      * check that async io was successful.
1504      * Note:  if the there was an system call failure, -errno
1505      * was returned and Errormsg should already have been updated.
1506      * If amount i/o was different than size, Errormsg should already 
1507      * have been updated but the actual i/o size if returned.
1508      */
1509     
1510 #ifdef CRAY
1511     ret=lio_check_asyncio(io_type, size, &status);
1512 #endif
1513 #ifdef sgi
1514     ret=lio_check_asyncio(io_type, size, &aiocbp, method);
1515 #endif
1516
1517     return ret;
1518 }       /* end of lio_read_buffer */
1519
1520
1521 #ifndef linux
1522 /***********************************************************************
1523  * This function will check that async io was successful.
1524  * It can also be used to check sync listio since it uses the
1525  * same method.
1526  *
1527  * Return Values
1528  *  If status.sw_error is set, -status.sw_error is returned.
1529  *  Otherwise sw_count's field value is returned.
1530  *
1531  * (rrl 04/96)
1532  ***********************************************************************/
1533 int
1534 #ifdef CRAY
1535 lio_check_asyncio(char *io_type, int size, struct iosw *status)
1536 #else
1537 lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
1538 #endif
1539 {
1540     int ret;
1541
1542 #ifdef CRAY
1543     if ( status->sw_error ) {
1544         sprintf(Errormsg,
1545             "%s/%d %s, sw_error set = %d %s, sw_count = %d",
1546                 __FILE__, __LINE__, io_type,
1547             status->sw_error, strerror(status->sw_error), status->sw_count);
1548         return -status->sw_error;
1549     }
1550     else if ( status->sw_count != size ) {
1551         sprintf(Errormsg,
1552             "%s/%d %s, sw_count not as expected(%d), but actual:%d",
1553                 __FILE__, __LINE__, io_type,
1554             size, status->sw_count);
1555     }
1556     else if ( Debug_level > 1 ) {
1557         printf("DEBUG %s/%d: %s completed without error (sw_error == 0, sw_count == %d)\n",
1558             __FILE__, __LINE__, io_type, status->sw_count);
1559     }
1560
1561     return status->sw_count;
1562
1563 #else
1564
1565     int cnt = 1;
1566
1567     /* The I/O may have been synchronous with signal completion.  It doesn't
1568      * make sense, but the combination could be generated.  Release the
1569      * completion signal here otherwise it'll hang around and bite us
1570      * later.
1571      */
1572     if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
1573         sigrelse( aiocbp->aio_sigevent.sigev_signo );
1574
1575     ret = aio_error( aiocbp );
1576
1577     while( ret == EINPROGRESS ){
1578         ret = aio_error( aiocbp );
1579         ++cnt;
1580     }
1581     if( cnt > 1 ){
1582         sprintf(Errormsg,
1583                 "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
1584                 __FILE__, __LINE__, io_type, cnt, method,
1585                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
1586                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
1587                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
1588                  "unknown") );
1589         return -ret;
1590     }
1591
1592     if( ret != 0 ){
1593         sprintf(Errormsg,
1594                 "%s/%d %s, aio_error = %d %s; random method %#o",
1595                 __FILE__, __LINE__, io_type,
1596                 ret, strerror(ret),
1597                 method );
1598         return -ret;
1599     }
1600     ret = aio_return( aiocbp );
1601     if( ret != size ){
1602         sprintf(Errormsg,
1603                 "%s/%d %s, aio_return not as expected(%d), but actual:%d",
1604                 __FILE__, __LINE__, io_type,
1605                 size, ret);
1606
1607 #ifdef BUG1_workaround
1608         if( ret == 0 ){
1609                 ret = size;
1610                 if( Debug_level > 1 ){
1611                         printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
1612                                __FILE__, __LINE__, io_type, ret);
1613                 }
1614         }
1615 #endif /* BUG1_workaround */
1616
1617     }
1618     else if( Debug_level > 1 ){
1619         printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
1620             __FILE__, __LINE__, io_type, ret);
1621     }
1622
1623     return ret;
1624
1625 #endif
1626
1627 } /* end of lio_check_asyncio */
1628
1629
1630 /***********************************************************************
1631  *
1632  * This function will wait for async io to complete.
1633  * If multiple wait methods are specified, the order is predetermined
1634  * to LIO_WAIT_RECALL,
1635  * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
1636  * then LIO_WAIT_NONE.
1637  *
1638  * If no wait method was specified the default wait method is: recall(2)
1639  * or aio_suspend(3), as appropriate.
1640  *
1641  * Return Values
1642  *      <0: errno of failed recall
1643  *      0 : async io was completed
1644  *      1 : async was not waited for, io may not have completed.
1645  *
1646  * (rrl 04/96)
1647  ***********************************************************************/
1648 int
1649 #ifdef CRAY
1650 lio_wait4asyncio(int method, int fd, struct iosw **statptr)
1651 #else
1652 lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
1653 #endif
1654 {
1655     int cnt;
1656 #ifdef sgi
1657     int ret;
1658     const aiocb_t *aioary[1]; 
1659 #endif
1660
1661     if ( (method & LIO_WAIT_RECALL)
1662 #ifdef sgi
1663         || (method & LIO_WAIT_CBSUSPEND) 
1664         || (method & LIO_WAIT_SIGSUSPEND) 
1665 #endif
1666         || ((method & LIO_WAIT_TYPES) == 0) ){
1667         /*
1668          * If method has LIO_WAIT_RECALL bit set or method does
1669          * not have any wait method bits set (default), use recall/aio_suspend.
1670          */
1671 #ifdef CRAY
1672         if ( Debug_level > 2 )
1673             printf("DEBUG %s/%d: wait method : recall\n", __FILE__, __LINE__);
1674         sigon();
1675         if ( recall(fd, 1, statptr) ) {
1676             sprintf(Errormsg, "%s/%d recall(%d, 1, stat) failed, errno:%d %s",
1677                     __FILE__, __LINE__,
1678                 fd, errno, strerror(errno));
1679             return -errno;
1680         }
1681 #else
1682         if ( Debug_level > 2 )
1683             printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
1684                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
1685                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
1686                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
1687                  "unknown") );
1688
1689         aioary[0] = aiocbp;
1690         ret = aio_suspend( aioary, 1, NULL );
1691         if( (ret == -1) && (errno == EINTR) ){
1692                 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
1693                         if( Debug_level > 2 ){
1694                                 printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
1695                                        __FILE__, __LINE__ );
1696                         }
1697                 }
1698                 else {
1699                         sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
1700                                 __FILE__, __LINE__,
1701                                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
1702                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
1703                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
1704                                  "unknown") );
1705                         return -errno;
1706                 }
1707         }
1708         else if ( ret ) {
1709             sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
1710                     __FILE__, __LINE__,
1711                 fd, errno, strerror(errno));
1712             return -errno;
1713         }
1714 #endif
1715
1716     } else if ( method & LIO_WAIT_ACTIVE ) {
1717         if ( Debug_level > 2 )
1718             printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
1719 #ifdef CRAY
1720         sigon();
1721         /* 
1722          * loop until sw_flag, sw_count or sw_error field elements
1723          * change to non-zero.
1724          */
1725         cnt=0;
1726         while ( (*statptr)->sw_flag == 0 && 
1727                 (*statptr)->sw_count == 0 &&
1728                 (*statptr)->sw_error == 0 ) {
1729            cnt++;
1730         }
1731 #else
1732         /* loop while aio_error() returns EINPROGRESS */
1733         cnt=0;
1734         while(1){
1735                 ret = aio_error( aiocbp );
1736                 if( (ret == 0) || (ret != EINPROGRESS) ){
1737                         break;
1738                 }
1739                 ++cnt;
1740         }
1741
1742 #endif
1743         if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
1744                 printf("DEBUG %s/%d: wait active cnt = %d\n",
1745                     __FILE__, __LINE__, cnt);
1746
1747     } else if ( method & LIO_WAIT_SIGPAUSE ) {
1748         if ( Debug_level > 2 )
1749             printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
1750 #ifdef sgi
1751         /* note: don't do the sigon() for CRAY in this case.  why? -- roehrich 6/11/97 */
1752         if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
1753                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1754         else {
1755                 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
1756                 return -1;
1757         }
1758 #endif
1759         pause();
1760
1761     } else if ( method & LIO_WAIT_SIGACTIVE ) {
1762         if ( Debug_level > 2 )
1763             printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
1764 #ifdef CRAY
1765         sigon();
1766 #else
1767         if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
1768                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1769         else {
1770                 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
1771                 return -1;
1772         }
1773 #endif
1774         /* loop waiting for signal */
1775         while ( Received_signal == Rec_signal ){
1776 #ifdef CRAY
1777                 sigon();
1778 #else
1779                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1780 #endif
1781         }
1782
1783     } else if ( method & LIO_WAIT_NONE ) {
1784         if ( Debug_level > 2 )
1785             printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
1786         /* It's broken because the aiocb/iosw is an automatic variable in
1787          * lio_{read,write}_buffer, so when the function returns and the
1788          * I/O completes there will be nowhere to write the I/O status.
1789          * It doesn't cause a problem on unicos--probably because of some
1790          * compiler quirk, or an accident.  It causes POSIX async I/O
1791          * to core dump some threads.   spr/pv 705909.  6/27/97 roehrich
1792          */
1793         sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
1794                 __FILE__, __LINE__ );
1795 #ifdef CRAY
1796         sigon();
1797 #endif
1798 /*        return 1;*/
1799         return -1;
1800     }
1801     else {
1802         if( Debug_level > 2 )
1803             printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
1804         return -1;
1805     }
1806
1807     return 0;
1808
1809 } /* end of lio_wait4asyncio */
1810
1811 #endif /* ifndef linux */
1812
1813 #if UNIT_TEST
1814 /***********************************************************************
1815  * The following code is provided as unit test.
1816  * Just define add "-DUNIT_TEST=1" to the cc line.
1817  * 
1818  * (rrl 04/96)
1819  ***********************************************************************/
1820 struct unit_info_t {
1821     int method;
1822     int sig;
1823     char *str;
1824 }  Unit_info[] = {
1825     { LIO_IO_SYNC, 0, "sync io" },
1826     { LIO_IO_SYNCV, 0, "sync readv/writev" },
1827     { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
1828     { LIO_IO_ASYNC, 0, "async io, def wait" },
1829     { LIO_IO_SLISTIO,     0, "sync listio" },
1830     { LIO_IO_ALISTIO,     0, "async listio, def wait" },
1831     { LIO_IO_ASYNC|LIO_WAIT_ACTIVE,     0, "async active" },
1832     { LIO_IO_ASYNC|LIO_WAIT_RECALL,     0, "async recall/suspend" },
1833     { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE,   SIGUSR1, "async sigpause" },
1834     { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async sigactive" },
1835     { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE,     0, "async listio active" },
1836     { LIO_IO_ALISTIO|LIO_WAIT_RECALL,     0, "async listio recall" },
1837     { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async listio sigactive" },
1838     { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE,  SIGUSR1, "async listio sigpause" },
1839     { LIO_IO_ASYNC,     SIGUSR2, "async io, def wait, sigusr2" },
1840     { LIO_IO_ALISTIO,   SIGUSR2, "async listio, def wait, sigusr2" },
1841 };
1842
1843 int
1844 main(argc, argv)
1845 int argc;
1846 char **argv;
1847 {
1848     extern char *optarg;
1849     extern int optind;
1850
1851     int fd;
1852     char *err;
1853     char buffer[4096];
1854     int size=4096;
1855     int ret;
1856     int ind;
1857     int iter=3;
1858     int method;
1859     int exit_status = 0;
1860     int c;
1861     int i;
1862     char *symbols = NULL;
1863     int die_on_err = 0;
1864
1865     while( (c = getopt(argc,argv,"s:di:")) != -1 ){
1866         switch(c){
1867         case 's': symbols = optarg; break;
1868         case 'd': ++die_on_err; break;
1869         case 'i': iter = atoi(optarg); break;
1870         }
1871     }
1872
1873     if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
1874         perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
1875         exit(1);
1876     }
1877
1878     Debug_level=9;
1879
1880     if ( symbols != NULL ) {
1881         if ( (method=lio_parse_io_arg2(symbols,  &err)) == -1 ){
1882             printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
1883             symbols, err);
1884             if( die_on_err )
1885                 exit(1);
1886         }
1887         else
1888             printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
1889
1890         exit_status = 0;
1891         for(ind=0; ind < iter; ind++ ) {
1892           memset( buffer, 'A', 4096 );
1893           if( lseek(fd, 0, 0) == -1 ){
1894                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1895                        __LINE__, errno );
1896                 ++exit_status;
1897           }
1898           if ((ret=lio_write_buffer(fd, method, buffer,
1899                         size, SIGUSR1, &err, 0)) != size ) {
1900             printf("lio_write_buffer returned -1, err = %s\n", err);
1901           } else
1902             printf("lio_write_buffer returned %d\n", ret);
1903
1904           memset( buffer, 'B', 4096 );
1905           if( lseek(fd, 0, 0) == -1 ){
1906                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1907                        __LINE__, errno );
1908                 ++exit_status;
1909           }
1910           if ((ret=lio_read_buffer(fd, method, buffer,
1911                         size, SIGUSR2, &err, 0)) != size ) {
1912             printf("lio_read_buffer returned -1, err = %s\n", err);
1913           } else
1914             printf("lio_read_buffer returned %d\n", ret);
1915
1916           for( i = 0; i < 4096; ++i ){
1917                 if( buffer[i] != 'A' ){
1918                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1919                         ++exit_status;
1920                         break;
1921                 }
1922           }
1923
1924           if( exit_status )
1925                 exit(exit_status);
1926
1927         }
1928
1929         unlink("unit_test_file");
1930         exit(0);
1931     }
1932
1933     for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
1934
1935         printf("\n********* write %s ***************\n", Unit_info[ind].str);
1936         if( lseek(fd, 0, 0) == -1 ){
1937                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1938                        __LINE__, errno );
1939                 ++exit_status;
1940         }
1941
1942         memset( buffer, 'A', 4096 );
1943         if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
1944                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1945             printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1946                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1947             ++exit_status;
1948             if( die_on_err )
1949                 exit(exit_status);
1950         } else{
1951             printf("lio_write_buffer returned %d\n", ret);
1952         }
1953
1954         printf("\n********* read %s ***************\n", Unit_info[ind].str);
1955         if( lseek(fd, 0, 0) == -1 ){
1956                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1957                        __LINE__, errno );
1958                 ++exit_status;
1959         }
1960         memset( buffer, 'B', 4096 );
1961         if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
1962                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1963             printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1964                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1965             ++exit_status;
1966             if( die_on_err )
1967                 exit(exit_status);
1968         } else {
1969             printf("lio_read_buffer returned %d\n", ret);
1970         }
1971
1972           for( i = 0; i < 4096; ++i ){
1973                 if( buffer[i] != 'A' ){
1974                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1975                         ++exit_status;
1976                         if( die_on_err )
1977                                 exit(exit_status);
1978                         break;
1979                 }
1980           }
1981
1982         fflush(stdout);
1983         fflush(stderr);
1984         sleep(1);
1985
1986     }
1987
1988     unlink("unit_test_file");
1989
1990     exit(exit_status);
1991 }
1992 #endif