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