lib/tlibio: Fix a build warning
[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  *  int  lio_parse_io_arg1(char *string)
42  *  void lio_help1(char *prefix);
43  *
44  *  int  lio_parse_io_arg2(char *string, char **badtoken)
45  *  void lio_help2(char *prefix);
46  *
47  *  int  lio_set_debug(int level);
48  *
49  *  char Lio_SysCall[];
50  *  struct lio_info_type Lio_info1[];
51  *  struct lio_info_type Lio_info2[];
52  *
53  *  Author : Richard Logan
54  *
55  */
56
57 #include <stdio.h>
58 #include <ctype.h>
59 #include <fcntl.h>
60 #include <unistd.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/time.h>          
64 #include <sys/param.h>
65 #include <errno.h>
66 #include <sys/types.h>
67 #include <sys/file.h>
68 #include <signal.h>
69 #include <sys/uio.h> /* readv(2)/writev(2) */
70 #include <string.h>
71 #include <strings.h>
72 #include <stdlib.h> /* atoi, abs */
73
74 #include "tlibio.h"             /* defines LIO* marcos */
75
76 #ifndef PATH_MAX
77 #define PATH_MAX        MAXPATHLEN
78 #endif
79
80 #if 0 /* disabled until it's needed -- roehrich 6/11/97 */
81 #define BUG1_workaround 1 /* Work around a condition where aio_return gives
82                            * a value of zero but there is no errno followup
83                            * and the read/write operation actually did its
84                            * job.   spr/pv 705244
85                            */
86 #endif
87
88
89 #ifndef linux
90 static void lio_async_signal_handler();
91 #endif
92
93 /*
94  * Define the structure as used in lio_parse_arg1 and lio_help1
95  */
96 struct lio_info_type  Lio_info1[] = {
97     { "s", LIO_IO_SYNC, "sync i/o" },
98     { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
99     { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
100     { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
101     { "r", 
102         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
103     { "R", 
104         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
105     { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
106     { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
107     { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
108     { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
109     { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
110 };
111
112 /*
113  * Define the structure used by lio_parse_arg2 and lio_help2
114  */
115 struct lio_info_type  Lio_info2[] = {
116     { "sync",      LIO_IO_SYNC,         "sync i/o (read/write)"},
117     { "async",     LIO_IO_ASYNC,        "async i/o (reada/writea/aio_read/aio_write)" },
118     { "slistio",   LIO_IO_SLISTIO,      "single stride sync listio" },
119     { "alistio",   LIO_IO_ALISTIO,      "single stride async listio" },
120     { "syncv",     LIO_IO_SYNCV,        "single buffer sync readv/writev"},
121     { "syncp",     LIO_IO_SYNCP,        "pread/pwrite"},
122     { "active",    LIO_WAIT_ACTIVE,     "spin on status/control values" },
123     { "recall",    LIO_WAIT_RECALL,     "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
124     { "sigactive", LIO_WAIT_SIGACTIVE,  "spin waiting for signal" },
125     { "sigpause",  LIO_WAIT_SIGPAUSE,   "call pause(2) to wait for signal" },
126 /* nowait is a touchy thing, it's an accident that this implementation worked at all.  6/27/97 roehrich */
127 /*    { "nowait",    LIO_WAIT_NONE,     "do not wait for async io to complete" },*/
128     { "random",    LIO_RANDOM,          "set random bit" },
129     { "randomall", 
130         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, 
131         "all random i/o types and wait methods (except nowait)" },
132 };
133
134 char Lio_SysCall[PATH_MAX];     /* string containing last i/o system call */
135
136 static volatile int Received_signal = 0;        /* number of signals received */
137 static volatile int Rec_signal;
138 static char Errormsg[500];
139 static int Debug_level = 0;
140
141
142
143 /***********************************************************************
144  * stride_bounds()
145  *
146  * Determine the bounds of a strided request, normalized to offset.  Returns
147  * the number of bytes needed to satisfy the request, and optionally sets
148  * *min and *max to the mininum and maximum bytes referenced, normalized 
149  * around offset.
150  *
151  * Returns -1 on error - the only possible error conditions are illegal values
152  * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
153  *
154  * (maule, 11/16/95)
155  ***********************************************************************/
156
157 int
158 stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
159 int     offset;
160 int     stride;
161 int     nstrides;
162 int     bytes_per_stride;
163 int     *min;
164 int     *max;
165 {
166         int     nbytes, min_byte, max_byte;
167
168         /*
169          * sanity checks ...
170          */
171
172         if (nstrides < 0 || bytes_per_stride < 0) {
173                 return -1;
174         }
175
176         if (stride == 0) {
177                 stride = bytes_per_stride;
178         }
179
180         /*
181          * Determine the # of bytes needed to satisfy the request.  This
182          * value, along with the offset argument, determines the min and max
183          * bytes referenced.
184          */
185
186
187         nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
188
189         if (stride < 0) {
190                 max_byte = offset + bytes_per_stride - 1;
191                 min_byte = max_byte - nbytes + 1;
192         } else {
193                 min_byte = offset;
194                 max_byte = min_byte + nbytes - 1;
195         }
196         
197         if (min != NULL) {
198                 *min = min_byte;
199         }
200         
201         if (max != NULL) {
202                 *max = max_byte;
203         }
204
205         return nbytes;
206 }
207
208 /***********************************************************************
209  * This function will allow someone to set the debug level.
210  ***********************************************************************/
211 int
212 lio_set_debug(int level)
213 {
214     int old;
215
216     old = Debug_level;
217     Debug_level = level;
218     return old;
219 }
220
221 /***********************************************************************
222  * This function will parse a string and return desired io-method.
223  * Only the first character of the string is used.
224  *
225  * This function does not provide for meaningful option arguments,
226  * but it supports current growfiles/btlk interface.
227  *
228  *  (rrl 04/96)
229  ***********************************************************************/
230 int
231 lio_parse_io_arg1(char *string)
232 {
233     int ind;
234     int found=0;
235     int mask=0;
236
237     /*
238      * Determine if token is a valid string.
239      */
240     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
241         if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
242             mask |= Lio_info1[ind].bits;
243             found = 1;
244             break;
245         }
246     }
247
248     if ( found == 0 ) {
249         return -1;
250     }
251
252     return mask;
253
254 }
255
256 /***********************************************************************
257  * This function will print a help message describing the characters
258  * that can be parsed by lio_parse_io_arg1().
259  * They will be printed one per line.
260  *  (rrl 04/96)
261  ***********************************************************************/
262 void
263 lio_help1(char *prefix)
264 {
265     int ind;
266
267     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
268         printf("%s %s : %s\n", prefix,
269             Lio_info1[ind].token, Lio_info1[ind].desc);
270     }
271
272     return;
273 }
274
275 /***********************************************************************
276  * This function will parse a string and return the desired io-method.
277  * This function will take a comma separated list of io type and wait
278  * method tokens as defined in Lio_info2[].  If a token does not match
279  * any of the tokens in Lio_info2[], it will be coverted to a number.
280  * If it was a number, those bits are also set.
281  * 
282  *  (rrl 04/96)
283  ***********************************************************************/
284 int
285 lio_parse_io_arg2(char *string, char **badtoken)
286 {
287    char *token = string;
288    char *cc = token;
289    char savecc;
290    int found;
291    int mask=0;
292
293    int tmp;
294    int ind;
295    char chr;
296
297    if ( token == NULL )
298         return -1;
299
300    for (;;) {
301         for (; ((*cc != ',') && (*cc != '\0')); cc++);
302         savecc = *cc;
303         *cc = '\0';
304
305         found = 0; 
306
307         /*
308          * Determine if token is a valid string or number and if
309          * so, add the bits to the mask.
310           */
311         for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
312             if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
313                 mask |= Lio_info2[ind].bits;
314                 found = 1;
315                 break;
316             }
317         }
318
319         /*
320          * If token does not match one of the defined tokens, determine
321          * if it is a number, if so, add the bits.
322          */
323         if ( !found ) {
324             if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
325                 mask |= tmp;
326                 found=1;
327             }
328         }
329
330         *cc = savecc;
331
332         if (!found) {  /* token is not valid */
333             if ( badtoken != NULL)
334                 *badtoken = token;
335             return(-1);
336         }
337
338         if (savecc == '\0')
339             break;
340
341         token = ++cc;
342     }
343
344     return mask;
345 }
346
347 /***********************************************************************
348  * This function will print a help message describing the tokens
349  * that can be parsed by lio_parse_io_arg2().
350  * It will print them one per line.
351  *
352  * (rrl 04/96)
353  ***********************************************************************/
354 void
355 lio_help2(char *prefix)
356 {
357     int ind;
358
359     for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
360         printf("%s %s : %s\n", prefix,
361             Lio_info2[ind].token, Lio_info2[ind].desc);
362     }
363     return;
364 }
365
366 #ifndef linux
367 /***********************************************************************
368  * This is an internal signal handler.
369  * If the handler is called, it will increment the Received_signal
370  * global variable.
371  ***********************************************************************/
372 static void
373 lio_async_signal_handler(int sig)
374 {
375         if ( Debug_level )
376             printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
377                 __FILE__, __LINE__, sig, Received_signal+1);
378
379         Received_signal++;
380
381         return;
382 }
383 #endif
384
385 /***********************************************************************
386  * lio_random_methods
387  * This function will randomly choose an io type and wait method
388  * from set of io types and wait methods.  Since this information
389  * is stored in a bitmask, it randomly chooses an io type from
390  * the io type bits specified and does the same for wait methods.
391  *
392  * Return Value
393  * This function will return a value with all non choosen io type
394  * and wait method bits cleared.  The LIO_RANDOM bit is also 
395  * cleared.  All other bits are left unchanged.
396  *
397  * (rrl 04/96)
398  ***********************************************************************/
399 int
400 lio_random_methods(long curr_mask)
401 {
402     int mask=0;
403     long random_bit(long);
404
405     /* remove random select, io type, and wait method bits from curr_mask */
406     mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
407
408     /* randomly select io type from specified io types */
409     mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
410
411     /* randomly select wait methods  from specified wait methods */
412     mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
413
414     return mask;
415 }
416
417 /***********************************************************************
418  * Generic write function 
419  * This function can be used to do a write using write(2), writea(2),
420  * aio_write(3), writev(2), pwrite(2),
421  * or single stride listio(2)/lio_listio(3).
422  * By setting the desired bits in the method
423  * bitmask, the caller can control the type of write and the wait method
424  * that will be used.  If no io type bits are set, write will be used.
425  *
426  * If async io was attempted and no wait method bits are set then the
427  * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
428  * aio_write(3) and lio_listio(3).
429  *
430  * If multiple wait methods are specified, 
431  * only one wait method will be used. The order is predetermined.
432  *
433  * If the call specifies a signal and one of the two signal wait methods,
434  * a signal handler for the signal is set.  This will reset an already
435  * set handler for this signal. 
436  *
437  * If the LIO_RANDOM method bit is set, this function will randomly
438  * choose a io type and wait method from bits in the method argument.
439  *
440  * If an error is encountered, an error message will be generated
441  * in a internal static buffer.  If errmsg is not NULL, it will
442  * be updated to point to the static buffer, allowing the caller
443  * to print the error message.
444  *
445  * Return Value
446  *   If a system call fails, -errno is returned.
447  *   If LIO_WAIT_NONE bit is set, the return value is the return value
448  *   of the system call.
449  *   If the io did not fail, the amount of data written is returned.
450  *      If the size the system call say was written is different
451  *      then what was asked to be written, errmsg is updated for
452  *      this error condition.  The return value is still the amount
453  *      the system call says was written.  
454  *
455  * (rrl 04/96)
456  ***********************************************************************/
457 int
458 lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
459 int fd;         /* open file descriptor */
460 int method;     /* contains io type and wait method bitmask */
461 char *buffer;   /* pointer to buffer */
462 int size;       /* the size of the io */
463 int sig;        /* signal to use if async io */
464 char **errmsg;  /* char pointer that will be updated to point to err message */
465 long wrd;       /* to allow future features, use zero for now */
466 {
467     int ret = 0;        /* syscall return or used to get random method */
468 #ifndef linux
469     int omethod = method;
470     int listio_cmd;             /* Holds the listio/lio_listio cmd */
471 #endif
472     struct iovec iov;   /* iovec for writev(2) */
473
474     /*
475      * If LIO_RANDOM bit specified, get new method randomly.
476      */
477     if ( method & LIO_RANDOM ) {
478         if( Debug_level > 3 )
479                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
480         method = lio_random_methods(method);
481         if ( Debug_level > 2 )
482             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
483     }
484
485     if ( errmsg != NULL )
486         *errmsg = Errormsg;
487
488     Rec_signal=Received_signal; /* get the current number of signals received */
489     bzero(&iov, sizeof(struct iovec));
490     iov.iov_base = buffer;
491     iov.iov_len = size;
492
493     /*
494      * If the LIO_USE_SIGNAL bit is not set, only use the signal
495      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
496      * Otherwise there is not necessary a signal handler to trap
497      * the signal.
498      */
499     if ( sig && !(method & LIO_USE_SIGNAL) && 
500         ! (method & LIO_WAIT_SIGTYPES) ){
501
502         sig=0;  /* ignore signal parameter */
503     }
504
505     /*
506      * only setup signal hander if sig was specified and
507      * a sig wait method was specified.
508      * Doing this will change the handler for this signal.  The
509      * old signal handler will not be restored.
510      *** restoring the signal handler could be added ***
511      */
512
513     /*
514      * Determine the system call that will be called and produce
515      * the string of the system call and place it in Lio_SysCall.
516      * Execute the system call and check for system call failure.
517      * If sync i/o, return the number of bytes written/read.
518      */
519      
520     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
521         /*
522          * write(2) is used if LIO_IO_SYNC bit is set or not none
523          * of the LIO_IO_TYPES bits are set (default).
524          */
525
526         sprintf(Lio_SysCall,
527             "write(%d, buf, %d)", fd, size);
528
529         if ( Debug_level ) {
530             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
531         }
532
533         if ((ret = write(fd, buffer, size)) == -1) {
534             sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
535                 __FILE__, __LINE__,
536                 fd, size, errno, strerror(errno));
537             return -errno;
538         }
539
540         if ( ret != size ) {
541             sprintf(Errormsg,
542                 "%s/%d write(%d, buf, %d) returned=%d",
543                     __FILE__, __LINE__,
544                     fd, size, ret);
545         }
546         else if ( Debug_level > 1 )
547             printf("DEBUG %s/%d: write completed without error (ret %d)\n",
548                 __FILE__, __LINE__, ret);
549
550         return ret;
551
552     }
553
554     else if ( method & LIO_IO_SYNCV ) {
555
556         sprintf(Lio_SysCall, 
557                 "writev(%d, &iov, 1) nbyte:%d", fd, size);
558
559         if ( Debug_level ) {
560             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
561         }
562         if ((ret = writev(fd, &iov, 1)) == -1) {
563             sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
564                     __FILE__, __LINE__,
565                 fd, size, errno, strerror(errno));
566             return -errno;
567         }
568
569         if ( ret != size ) {
570             sprintf(Errormsg,
571                 "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
572                     __FILE__, __LINE__,
573                     fd, size, ret);
574         }
575         else if ( Debug_level > 1 )
576             printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
577                 __FILE__, __LINE__, ret);
578
579         return ret;
580     } /* LIO_IO_SYNCV */
581
582     else {
583         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
584         return -1;
585     }
586
587     /*
588      * If there was an error waiting for async i/o to complete,
589      * return the error value (errno) to the caller.
590      * Note: Errormsg should already have been updated.
591      */
592     if ( ret < 0 ) {
593         return ret;
594     }
595
596     /*
597      * If i/o was not waited for (may not have been completed at this time),
598      * return the size that was requested.
599      */
600     if ( ret == 1 )
601         return size;
602
603     /*
604      * check that async io was successful.
605      * Note:  if the there was an system call failure, -errno
606      * was returned and Errormsg should already have been updated.
607      * If amount i/o was different than size, Errormsg should already 
608      * have been updated but the actual i/o size if returned.
609      */
610     
611     return ret;
612 }       /* end of lio_write_buffer */
613
614 /***********************************************************************
615  * Generic read function 
616  * This function can be used to do a read using read(2), reada(2),
617  * aio_read(3), readv(2), pread(2),
618  * or single stride listio(2)/lio_listio(3).
619  * By setting the desired bits in the method
620  * bitmask, the caller can control the type of read and the wait method
621  * that will be used.  If no io type bits are set, read will be used.
622  *
623  * If async io was attempted and no wait method bits are set then the
624  * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
625  * aio_read(3) and lio_listio(3).
626  *
627  * If multiple wait methods are specified, 
628  * only one wait method will be used. The order is predetermined.
629  *
630  * If the call specifies a signal and one of the two signal wait methods,
631  * a signal handler for the signal is set.  This will reset an already
632  * set handler for this signal. 
633  *
634  * If the LIO_RANDOM method bit is set, this function will randomly
635  * choose a io type and wait method from bits in the method argument.
636  *
637  * If an error is encountered, an error message will be generated
638  * in a internal static buffer.  If errmsg is not NULL, it will
639  * be updated to point to the static buffer, allowing the caller
640  * to print the error message.
641  *
642  * Return Value
643  *   If a system call fails, -errno is returned.
644  *   If LIO_WAIT_NONE bit is set, the return value is the return value
645  *   of the system call.
646  *   If the io did not fail, the amount of data written is returned.
647  *      If the size the system call say was written is different
648  *      then what was asked to be written, errmsg is updated for
649  *      this error condition.  The return value is still the amount
650  *      the system call says was written.  
651  *
652  * (rrl 04/96)
653  ***********************************************************************/
654 int
655 lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
656 int fd;         /* open file descriptor */
657 int method;     /* contains io type and wait method bitmask */
658 char *buffer;   /* pointer to buffer */
659 int size;       /* the size of the io */
660 int sig;        /* signal to use if async io */
661 char **errmsg;  /* char pointer that will be updated to point to err message */
662 long wrd;       /* to allow future features, use zero for now */
663 {
664     int ret = 0;        /* syscall return or used to get random method */
665 #ifndef linux
666     int listio_cmd;             /* Holds the listio/lio_listio cmd */
667     int omethod = method;
668 #endif
669     struct iovec iov; /* iovec for readv(2) */
670
671     /*
672      * If LIO_RANDOM bit specified, get new method randomly.
673      */
674     if ( method & LIO_RANDOM ) {
675         if( Debug_level > 3 )
676                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
677         method = lio_random_methods(method);
678         if ( Debug_level > 2 )
679             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
680     }
681
682     if ( errmsg != NULL )
683         *errmsg = Errormsg;
684
685     Rec_signal=Received_signal; /* get the current number of signals received */
686     bzero(&iov, sizeof(struct iovec));
687     iov.iov_base = buffer;
688     iov.iov_len = size;
689
690     /*
691      * If the LIO_USE_SIGNAL bit is not set, only use the signal
692      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
693      * Otherwise there is not necessarily a signal handler to trap
694      * the signal.
695      */
696     if ( sig && !(method & LIO_USE_SIGNAL) &&
697         ! (method & LIO_WAIT_SIGTYPES) ){
698
699         sig=0;  /* ignore signal parameter */
700     }
701
702     /*
703      * only setup signal hander if sig was specified and
704      * a sig wait method was specified.
705      * Doing this will change the handler for this signal.  The
706      * old signal handler will not be restored.
707      *** restoring the signal handler could be added ***
708      */
709
710     /*
711      * Determine the system call that will be called and produce
712      * the string of the system call and place it in Lio_SysCall.
713      * Execute the system call and check for system call failure.
714      * If sync i/o, return the number of bytes written/read.
715      */
716      
717     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
718         /*
719          * read(2) is used if LIO_IO_SYNC bit is set or not none
720          * of the LIO_IO_TYPES bits are set (default).
721          */
722
723         sprintf(Lio_SysCall,
724             "read(%d, buf, %d)", fd, size);
725
726         if ( Debug_level ) {
727             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
728         }
729
730         if ((ret = read(fd, buffer, size)) == -1) {
731             sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
732                     __FILE__, __LINE__,
733                 fd, size, errno, strerror(errno));
734             return -errno;
735         }
736
737         if ( ret != size ) {
738             sprintf(Errormsg,
739                 "%s/%d read(%d, buf, %d) returned=%d",
740                     __FILE__, __LINE__,
741                     fd, size, ret);
742         }
743         else if ( Debug_level > 1 )
744             printf("DEBUG %s/%d: read completed without error (ret %d)\n",
745                 __FILE__, __LINE__, ret);
746
747         return ret;
748
749     }
750
751     else if ( method & LIO_IO_SYNCV ) {
752
753         sprintf(Lio_SysCall, 
754                 "readv(%d, &iov, 1) nbyte:%d", fd, size);
755
756         if ( Debug_level ) {
757             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
758         }
759         if ((ret = readv(fd, &iov, 1)) == -1) {
760             sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
761                     __FILE__, __LINE__,
762                 fd, size, errno, strerror(errno));
763             return -errno;
764         }
765
766         if ( ret != size ) {
767             sprintf(Errormsg,
768                 "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
769                     __FILE__, __LINE__,
770                     fd, size, ret);
771         }
772         else if ( Debug_level > 1 )
773             printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
774                 __FILE__, __LINE__, ret);
775
776         return ret;
777     } /* LIO_IO_SYNCV */
778
779     else {
780         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
781         return -1;
782     }
783
784     /*
785      * If there was an error waiting for async i/o to complete,
786      * return the error value (errno) to the caller.
787      * Note: Errormsg should already have been updated.
788      */
789     if ( ret < 0 ) {
790         return ret;
791     }
792
793     /*
794      * If i/o was not waited for (may not have been completed at this time),
795      * return the size that was requested.
796      */
797     if ( ret == 1 )
798         return size;
799
800     /*
801      * check that async io was successful.
802      * Note:  if the there was an system call failure, -errno
803      * was returned and Errormsg should already have been updated.
804      * If amount i/o was different than size, Errormsg should already 
805      * have been updated but the actual i/o size if returned.
806      */
807     
808     return ret;
809 }       /* end of lio_read_buffer */
810
811
812 #ifndef linux
813 /***********************************************************************
814  * This function will check that async io was successful.
815  * It can also be used to check sync listio since it uses the
816  * same method.
817  *
818  * Return Values
819  *  If status.sw_error is set, -status.sw_error is returned.
820  *  Otherwise sw_count's field value is returned.
821  *
822  * (rrl 04/96)
823  ***********************************************************************/
824 int
825 lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
826 {
827     int ret;
828     int cnt = 1;
829
830     /* The I/O may have been synchronous with signal completion.  It doesn't
831      * make sense, but the combination could be generated.  Release the
832      * completion signal here otherwise it'll hang around and bite us
833      * later.
834      */
835     if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
836         sigrelse( aiocbp->aio_sigevent.sigev_signo );
837
838     ret = aio_error( aiocbp );
839
840     while( ret == EINPROGRESS ){
841         ret = aio_error( aiocbp );
842         ++cnt;
843     }
844     if( cnt > 1 ){
845         sprintf(Errormsg,
846                 "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
847                 __FILE__, __LINE__, io_type, cnt, method,
848                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
849                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
850                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
851                  "unknown") );
852         return -ret;
853     }
854
855     if( ret != 0 ){
856         sprintf(Errormsg,
857                 "%s/%d %s, aio_error = %d %s; random method %#o",
858                 __FILE__, __LINE__, io_type,
859                 ret, strerror(ret),
860                 method );
861         return -ret;
862     }
863     ret = aio_return( aiocbp );
864     if( ret != size ){
865         sprintf(Errormsg,
866                 "%s/%d %s, aio_return not as expected(%d), but actual:%d",
867                 __FILE__, __LINE__, io_type,
868                 size, ret);
869
870 #ifdef BUG1_workaround
871         if( ret == 0 ){
872                 ret = size;
873                 if( Debug_level > 1 ){
874                         printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
875                                __FILE__, __LINE__, io_type, ret);
876                 }
877         }
878 #endif /* BUG1_workaround */
879
880     }
881     else if( Debug_level > 1 ){
882         printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
883             __FILE__, __LINE__, io_type, ret);
884     }
885
886     return ret;
887
888 } /* end of lio_check_asyncio */
889
890
891 /***********************************************************************
892  *
893  * This function will wait for async io to complete.
894  * If multiple wait methods are specified, the order is predetermined
895  * to LIO_WAIT_RECALL,
896  * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
897  * then LIO_WAIT_NONE.
898  *
899  * If no wait method was specified the default wait method is: recall(2)
900  * or aio_suspend(3), as appropriate.
901  *
902  * Return Values
903  *      <0: errno of failed recall
904  *      0 : async io was completed
905  *      1 : async was not waited for, io may not have completed.
906  *
907  * (rrl 04/96)
908  ***********************************************************************/
909 int
910 lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
911 {
912     int cnt;
913
914     if ( (method & LIO_WAIT_RECALL)
915         || ((method & LIO_WAIT_TYPES) == 0) ){
916         /*
917          * If method has LIO_WAIT_RECALL bit set or method does
918          * not have any wait method bits set (default), use recall/aio_suspend.
919          */
920         if ( Debug_level > 2 )
921             printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
922                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
923                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
924                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
925                  "unknown") );
926
927         aioary[0] = aiocbp;
928         ret = aio_suspend( aioary, 1, NULL );
929         if( (ret == -1) && (errno == EINTR) ){
930                 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
931                         if( Debug_level > 2 ){
932                                 printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
933                                        __FILE__, __LINE__ );
934                         }
935                 }
936                 else {
937                         sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
938                                 __FILE__, __LINE__,
939                                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
940                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
941                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
942                                  "unknown") );
943                         return -errno;
944                 }
945         }
946         else if ( ret ) {
947             sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
948                     __FILE__, __LINE__,
949                 fd, errno, strerror(errno));
950             return -errno;
951         }
952     } else if ( method & LIO_WAIT_ACTIVE ) {
953         if ( Debug_level > 2 )
954             printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
955
956         /* loop while aio_error() returns EINPROGRESS */
957         cnt=0;
958         while(1){
959                 ret = aio_error( aiocbp );
960                 if( (ret == 0) || (ret != EINPROGRESS) ){
961                         break;
962                 }
963                 ++cnt;
964         }
965
966         if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
967                 printf("DEBUG %s/%d: wait active cnt = %d\n",
968                     __FILE__, __LINE__, cnt);
969
970     } else if ( method & LIO_WAIT_SIGPAUSE ) {
971         if ( Debug_level > 2 )
972             printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
973         pause();
974
975     } else if ( method & LIO_WAIT_SIGACTIVE ) {
976         if ( Debug_level > 2 )
977             printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
978         if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
979                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
980         else {
981                 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
982                 return -1;
983         }
984         /* loop waiting for signal */
985         while ( Received_signal == Rec_signal ){
986                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
987         }
988
989     } else if ( method & LIO_WAIT_NONE ) {
990         if ( Debug_level > 2 )
991             printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
992         /* It's broken because the aiocb/iosw is an automatic variable in
993          * lio_{read,write}_buffer, so when the function returns and the
994          * I/O completes there will be nowhere to write the I/O status.
995          * It doesn't cause a problem on unicos--probably because of some
996          * compiler quirk, or an accident.  It causes POSIX async I/O
997          * to core dump some threads.   spr/pv 705909.  6/27/97 roehrich
998          */
999         sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
1000                 __FILE__, __LINE__ );
1001         return -1;
1002     }
1003     else {
1004         if( Debug_level > 2 )
1005             printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
1006         return -1;
1007     }
1008
1009     return 0;
1010
1011 } /* end of lio_wait4asyncio */
1012
1013 #endif /* ifndef linux */
1014
1015 #if UNIT_TEST
1016 /***********************************************************************
1017  * The following code is provided as unit test.
1018  * Just define add "-DUNIT_TEST=1" to the cc line.
1019  * 
1020  * (rrl 04/96)
1021  ***********************************************************************/
1022 struct unit_info_t {
1023     int method;
1024     int sig;
1025     char *str;
1026 }  Unit_info[] = {
1027     { LIO_IO_SYNC, 0, "sync io" },
1028     { LIO_IO_SYNCV, 0, "sync readv/writev" },
1029     { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
1030     { LIO_IO_ASYNC, 0, "async io, def wait" },
1031     { LIO_IO_SLISTIO,     0, "sync listio" },
1032     { LIO_IO_ALISTIO,     0, "async listio, def wait" },
1033     { LIO_IO_ASYNC|LIO_WAIT_ACTIVE,     0, "async active" },
1034     { LIO_IO_ASYNC|LIO_WAIT_RECALL,     0, "async recall/suspend" },
1035     { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE,   SIGUSR1, "async sigpause" },
1036     { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async sigactive" },
1037     { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE,     0, "async listio active" },
1038     { LIO_IO_ALISTIO|LIO_WAIT_RECALL,     0, "async listio recall" },
1039     { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async listio sigactive" },
1040     { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE,  SIGUSR1, "async listio sigpause" },
1041     { LIO_IO_ASYNC,     SIGUSR2, "async io, def wait, sigusr2" },
1042     { LIO_IO_ALISTIO,   SIGUSR2, "async listio, def wait, sigusr2" },
1043 };
1044
1045 int
1046 main(argc, argv)
1047 int argc;
1048 char **argv;
1049 {
1050     extern char *optarg;
1051     extern int optind;
1052
1053     int fd;
1054     char *err;
1055     char buffer[4096];
1056     int size=4096;
1057     int ret;
1058     int ind;
1059     int iter=3;
1060     int method;
1061     int exit_status = 0;
1062     int c;
1063     int i;
1064     char *symbols = NULL;
1065     int die_on_err = 0;
1066
1067     while( (c = getopt(argc,argv,"s:di:")) != -1 ){
1068         switch(c){
1069         case 's': symbols = optarg; break;
1070         case 'd': ++die_on_err; break;
1071         case 'i': iter = atoi(optarg); break;
1072         }
1073     }
1074
1075     if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
1076         perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
1077         exit(1);
1078     }
1079
1080     Debug_level=9;
1081
1082     if ( symbols != NULL ) {
1083         if ( (method=lio_parse_io_arg2(symbols,  &err)) == -1 ){
1084             printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
1085             symbols, err);
1086             if( die_on_err )
1087                 exit(1);
1088         }
1089         else
1090             printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
1091
1092         exit_status = 0;
1093         for(ind=0; ind < iter; ind++ ) {
1094           memset( buffer, 'A', 4096 );
1095           if( lseek(fd, 0, 0) == -1 ){
1096                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1097                        __LINE__, errno );
1098                 ++exit_status;
1099           }
1100           if ((ret=lio_write_buffer(fd, method, buffer,
1101                         size, SIGUSR1, &err, 0)) != size ) {
1102             printf("lio_write_buffer returned -1, err = %s\n", err);
1103           } else
1104             printf("lio_write_buffer returned %d\n", ret);
1105
1106           memset( buffer, 'B', 4096 );
1107           if( lseek(fd, 0, 0) == -1 ){
1108                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1109                        __LINE__, errno );
1110                 ++exit_status;
1111           }
1112           if ((ret=lio_read_buffer(fd, method, buffer,
1113                         size, SIGUSR2, &err, 0)) != size ) {
1114             printf("lio_read_buffer returned -1, err = %s\n", err);
1115           } else
1116             printf("lio_read_buffer returned %d\n", ret);
1117
1118           for( i = 0; i < 4096; ++i ){
1119                 if( buffer[i] != 'A' ){
1120                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1121                         ++exit_status;
1122                         break;
1123                 }
1124           }
1125
1126           if( exit_status )
1127                 exit(exit_status);
1128
1129         }
1130
1131         unlink("unit_test_file");
1132         exit(0);
1133     }
1134
1135     for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
1136
1137         printf("\n********* write %s ***************\n", Unit_info[ind].str);
1138         if( lseek(fd, 0, 0) == -1 ){
1139                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1140                        __LINE__, errno );
1141                 ++exit_status;
1142         }
1143
1144         memset( buffer, 'A', 4096 );
1145         if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
1146                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1147             printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1148                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1149             ++exit_status;
1150             if( die_on_err )
1151                 exit(exit_status);
1152         } else{
1153             printf("lio_write_buffer returned %d\n", ret);
1154         }
1155
1156         printf("\n********* read %s ***************\n", Unit_info[ind].str);
1157         if( lseek(fd, 0, 0) == -1 ){
1158                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1159                        __LINE__, errno );
1160                 ++exit_status;
1161         }
1162         memset( buffer, 'B', 4096 );
1163         if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
1164                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1165             printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1166                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1167             ++exit_status;
1168             if( die_on_err )
1169                 exit(exit_status);
1170         } else {
1171             printf("lio_read_buffer returned %d\n", ret);
1172         }
1173
1174           for( i = 0; i < 4096; ++i ){
1175                 if( buffer[i] != 'A' ){
1176                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1177                         ++exit_status;
1178                         if( die_on_err )
1179                                 exit(exit_status);
1180                         break;
1181                 }
1182           }
1183
1184         fflush(stdout);
1185         fflush(stderr);
1186         sleep(1);
1187
1188     }
1189
1190     unlink("unit_test_file");
1191
1192     exit(exit_status);
1193 }
1194 #endif