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