~noskcaj/ubuntu/saucy/xinetd/2.3.15

« back to all changes in this revision

Viewing changes to libs/src/sio/siosup.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Seyrat
  • Date: 2004-04-18 13:33:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040418133357-czeqeju37433xvdd
Tags: upstream-2.3.13
ImportĀ upstreamĀ versionĀ 2.3.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
 
3
 * All rights reserved.  The file named COPYRIGHT specifies the terms 
 
4
 * and conditions for redistribution.
 
5
 */
 
6
 
 
7
 
 
8
#include "config.h"
 
9
#include <sys/types.h>
 
10
#include <sys/stat.h>
 
11
#include <fcntl.h>
 
12
#include <stdlib.h>
 
13
#include <unistd.h>
 
14
#include <syslog.h>
 
15
 
 
16
#ifdef _APPLE_
 
17
#undef HAVE_MMAP
 
18
#endif
 
19
 
 
20
#include "impl.h"
 
21
#include "sio.h"
 
22
 
 
23
int __sio_n_descriptors = 0 ;
 
24
__sio_descriptor_t *__sio_descriptors = NULL ;
 
25
 
 
26
static sio_status_e setup_read_buffer( __sio_id_t *idp, unsigned buf_size );
 
27
 
 
28
#ifndef MAP_FAILED
 
29
#define MAP_FAILED ((void *)-1)
 
30
#endif
 
31
 
 
32
/*
 
33
 * Code for finalization
 
34
 */
 
35
#ifdef HAVE_FINALIZATION_FUNCTION
 
36
static int finalizer_installed ;
 
37
 
 
38
SIO_DEFINE_FIN( sio_cleanup )
 
39
{
 
40
   (void) Sflush( SIO_FLUSH_ALL ) ;
 
41
}
 
42
#endif /* HAVE_FINALIZATION_FUNCTION */
 
43
 
 
44
 
 
45
 
 
46
#ifdef HAVE_MMAP
 
47
 
 
48
#define CHAR_NULL            ((char *)0)
 
49
 
 
50
/*
 
51
 * PAGES_MAPPED gives the size of each map unit in pages
 
52
 */
 
53
#define PAGES_MAPPED            2
 
54
 
 
55
static size_t map_unit_size = 0 ;         /* bytes */
 
56
static size_t page_size = 0 ;               /* bytes */
 
57
 
 
58
static mapd_s *mmap_descriptors = NULL ;
 
59
 
 
60
#define MDP( fd )            ( mmap_descriptors + (fd) )
 
61
 
 
62
 
 
63
/*
 
64
 * NOTES ON MEMORY MAPPING:
 
65
 *
 
66
 *    1. Memory mapping works only for file descriptors opened for input
 
67
 *   2. Mapping an object to a part of the address space where another
 
68
 *   object is mapped will cause the old mapping to disappear (i.e. mmap
 
69
 *   will not fail)
 
70
 *
 
71
 * Memory mapping interface:
 
72
 *      SIO_MMAP : maps a file into a portion of the address space.
 
73
 *      SIO_MUNMAP: unmap a portion of the address space
 
74
 *      SIO_MNEED: indicate to the OS that we will need a portion of
 
75
 *                   our address space.
 
76
 *
 
77
 * The map_unit_size variable defines how much of the file is mapped at
 
78
 * a time. It is a multiple of the operating system page size. It is
 
79
 * not less than SIO_BUFFER_SIZE unless SIO_BUFFER_SIZE is not a
 
80
 * multiple of the page size (so the SIO_BUFFER_SIZE overrides
 
81
 * PAGES_MAPPED).
 
82
 *
 
83
 * NOTE: All memory mapping code is in this file only
 
84
 */
 
85
 
 
86
 
 
87
/*
 
88
 * Macros used by the memory mapping code
 
89
 */
 
90
#define FIRST_TIME( dp )      ( dp->buf == NULL )
 
91
 
 
92
/*
 
93
 * Functions to support memory mapping:
 
94
 *
 
95
 *         try_memory_mapping
 
96
 *         buffer_setup
 
97
 *         __sio_switch
 
98
 *         initial_map
 
99
 *         map_unit
 
100
 */
 
101
 
 
102
/*
 
103
 * try_memory_mapping attempts to setup the specified descriptor
 
104
 * for memory mapping. 
 
105
 * It returns FAILURE if it fails and SUCCESS if it is successful.
 
106
 * If HAVE_MMAP is not defined, the function is defined to be FAILURE.
 
107
 *
 
108
 * Sets fields:
 
109
 *      memory_mapped:          TRUE or FALSE
 
110
 *      
 
111
 * Also sets the following fields if memory_mapped is TRUE:
 
112
 *    file_offset, file_size, buffer_size
 
113
 *
 
114
 */
 
115
static sio_status_e try_memory_mapping( int fd, __sio_id_t *idp, const struct stat *stp )
 
116
{
 
117
   int access_f ;
 
118
 
 
119
   /*
 
120
    * Do not try memory mapping if:
 
121
    *      1) The file is not a regular file
 
122
    *      2) The file is a regular file but has zero-length
 
123
    *      3) The file pointer is not positioned at the beginning of the file
 
124
    *      4) The fcntl to obtain the file descriptor flags fails
 
125
    *      5) The access mode is not O_RDONLY or O_RDWR
 
126
    *
 
127
    * The operations are done in this order to avoid the system calls
 
128
    * if possible.
 
129
    */
 
130
   if ( ( ( stp->st_mode & S_IFMT ) != S_IFREG ) ||
 
131
        ( stp->st_size == 0 ) ||
 
132
        ( lseek( fd, (long)0, 1 ) != 0 ) ||
 
133
        ( ( access_f = fcntl( fd, F_GETFL, 0 ) ) == -1 ) ||
 
134
        ( ( access_f &= 0x3 ) != O_RDONLY && access_f != O_RDWR ) )
 
135
   {
 
136
      idp->memory_mapped = FALSE ;
 
137
      return( FAILURE ) ;
 
138
   }
 
139
 
 
140
   /*
 
141
    * Determine page_size and map_unit_size.
 
142
    * Note that the code works even if PAGES_MAPPED is 0.
 
143
    */
 
144
   if ( page_size == 0 )
 
145
   {
 
146
      page_size = getpagesize() ;
 
147
      map_unit_size = page_size * PAGES_MAPPED ;
 
148
      if ( map_unit_size < SIO_BUFFER_SIZE )
 
149
      {
 
150
         if ( map_unit_size != 0 && SIO_BUFFER_SIZE % map_unit_size == 0 )
 
151
            map_unit_size = SIO_BUFFER_SIZE ;
 
152
         else
 
153
            map_unit_size = page_size ;
 
154
      }
 
155
   }
 
156
   
 
157
   MDP(fd)->file_offset = 0 ;
 
158
   MDP(fd)->file_size = stp->st_size ;
 
159
   idp->buffer_size = map_unit_size ;
 
160
   idp->buf = CHAR_NULL ;
 
161
   idp->memory_mapped = TRUE ;
 
162
 
 
163
   return( SUCCESS ) ;
 
164
}
 
165
 
 
166
 
 
167
/*
 
168
 * Copy the current_unit to the primary buffer
 
169
 *
 
170
 * Sets fields: start, end, nextb
 
171
 * Also sets the file pointer
 
172
 */
 
173
static void buffer_setup( __sio_id_t *idp, int fd, const struct map_unit *mu_cur, const struct map_unit *mu_next )
 
174
{
 
175
   off_t new_offset ;
 
176
 
 
177
   sio_memcopy( mu_cur->addr, idp->buf, mu_cur->valid_bytes ) ;
 
178
   idp->start = idp->buf ;
 
179
   idp->end = idp->buf + mu_cur->valid_bytes ;
 
180
   idp->nextb = idp->buf + ( idp->nextb - mu_cur->addr ) ;
 
181
 
 
182
   if ( mu_next->addr != CHAR_NULL )
 
183
      new_offset = MDP(fd)->file_offset - mu_next->valid_bytes ;
 
184
   else
 
185
      new_offset = MDP(fd)->file_offset ;
 
186
   (void) lseek( fd, new_offset, 0 ) ;
 
187
}
 
188
 
 
189
/*
 
190
 * Switch from memory mapping to buffered I/O
 
191
 * If any mapping has occurred, then the current unit is
 
192
 * copied into the buffer that is allocated.
 
193
 * Any data in the next unit is ignored.
 
194
 * We rely on idp->buf to identify the current unit (so it
 
195
 * better be equal to the address of one of the units).
 
196
 *
 
197
 * Sets fields:
 
198
 *         start, end, nextb
 
199
 */
 
200
sio_status_e __sio_switch( __sio_id_t *idp, int fd )
 
201
{
 
202
   mapd_s *mdp = MDP( fd ) ;
 
203
   struct map_unit *mu_cur, *mu_next ;
 
204
   unsigned buffer_size = idp->buffer_size ;
 
205
   char *buf_addr = idp->buf ;
 
206
   int first_time = FIRST_TIME( idp ) ;
 
207
 
 
208
   /*
 
209
    * Initialize stream for buffering
 
210
    */
 
211
   if ( setup_read_buffer( idp, buffer_size ) == FAILURE )
 
212
      return( FAILURE ) ;
 
213
 
 
214
   if ( ! first_time )
 
215
   {
 
216
      /*
 
217
       * Find current, next unit
 
218
       */
 
219
      if ( buf_addr == mdp->first_unit.addr )
 
220
      {
 
221
         mu_cur = &mdp->first_unit ;
 
222
         mu_next = &mdp->second_unit ;
 
223
      }
 
224
      else
 
225
      {
 
226
         mu_cur = &mdp->second_unit ;
 
227
         mu_next = &mdp->first_unit ;
 
228
      }
 
229
 
 
230
      buffer_setup( idp, fd, mu_cur, mu_next ) ;
 
231
      /*
 
232
       * Destroy all mappings
 
233
       */
 
234
      (void) SIO_MUNMAP( mu_cur->addr, mu_cur->mapped_bytes ) ;
 
235
      if ( mu_next->addr != NULL )
 
236
         (void) SIO_MUNMAP( mu_next->addr, mu_next->mapped_bytes ) ;
 
237
   }
 
238
   else
 
239
      idp->start = idp->end = idp->nextb = idp->buf ;
 
240
 
 
241
   idp->memory_mapped = FALSE ;
 
242
   return( SUCCESS ) ;
 
243
}
 
244
 
 
245
 
 
246
/*
 
247
 * initial_map does the first memory map on the file descriptor.
 
248
 * It attempts to map both units.
 
249
 * The mapping always starts at file offset 0.
 
250
 *
 
251
 * SETS FIELDS:
 
252
 *         first_unit.*, second_unit.*
 
253
 *         file_offset
 
254
 *
 
255
 * Returns: 
 
256
 *         number of bytes mapped in first_unit
 
257
 *    or
 
258
 *         0 to indicate that mmap failed.
 
259
 */
 
260
static int initial_map( mapd_s *mdp, int fd )
 
261
{
 
262
   caddr_t addr ;
 
263
   size_t requested_length = 2 * map_unit_size ;
 
264
   size_t mapped_length = MIN( (size_t)mdp->file_size, requested_length ) ;
 
265
   size_t bytes_left ;
 
266
   size_t bytes_in_unit ;
 
267
 
 
268
   addr = SIO_MMAP( CHAR_NULL, mapped_length, fd, 0 ) ;
 
269
   if ( addr == MAP_FAILED )
 
270
      return( 0 ) ;
 
271
 
 
272
   SIO_MNEED( addr, mapped_length ) ;
 
273
 
 
274
   /*
 
275
    * Map as much as possible in the first unit
 
276
    */
 
277
   bytes_in_unit = MIN( mapped_length, map_unit_size ) ;
 
278
   mdp->first_unit.addr          = addr ;
 
279
   mdp->first_unit.mapped_bytes    = bytes_in_unit ;
 
280
   mdp->first_unit.valid_bytes    = bytes_in_unit ;
 
281
 
 
282
   /*
 
283
    * If there is more, map it in the second unit.
 
284
    */
 
285
   bytes_left = mapped_length - bytes_in_unit ;
 
286
   if ( bytes_left != 0 )
 
287
   {
 
288
      mdp->second_unit.addr          = addr + bytes_in_unit ;
 
289
      mdp->second_unit.mapped_bytes = bytes_left ;
 
290
      mdp->second_unit.valid_bytes    = bytes_left ;
 
291
   }
 
292
   else
 
293
      mdp->second_unit.addr          = CHAR_NULL ;
 
294
 
 
295
   mdp->file_offset = mapped_length ;
 
296
 
 
297
   return( mdp->first_unit.valid_bytes ) ;
 
298
}
 
299
 
 
300
 
 
301
/*
 
302
 * ALGORITHM:
 
303
 *
 
304
 *      if ( there are more bytes in the file )
 
305
 *      {
 
306
 *         map them at the given unit
 
307
 *         update offset
 
308
 *         issue SIO_MNEED()
 
309
 *      }
 
310
 *      else
 
311
 *         unmap the unit
 
312
 */
 
313
static sio_status_e map_unit( mapd_s *mdp, int fd, struct map_unit *mup )
 
314
{
 
315
   size_t bytes_left = mdp->file_size - mdp->file_offset ;
 
316
   size_t bytes_to_map = MIN( bytes_left, map_unit_size ) ;
 
317
 
 
318
   if ( bytes_to_map != 0 )
 
319
   {
 
320
      if ( SIO_MMAP( mup->addr, bytes_to_map,
 
321
                                             fd, mdp->file_offset ) == MAP_FAILED )
 
322
         return( FAILURE ) ;         /* XXX: need to do more ? */
 
323
      
 
324
      mup->valid_bytes = bytes_to_map ;
 
325
      ASSERT( mup->valid_bytes <= mup->mapped_bytes ) ;
 
326
      mdp->file_offset += bytes_to_map ;
 
327
      SIO_MNEED( mup->addr, mup->valid_bytes ) ;
 
328
   }
 
329
   else
 
330
   {
 
331
      (void) SIO_MUNMAP( mup->addr, mup->mapped_bytes ) ;
 
332
      mup->addr = CHAR_NULL ;
 
333
   }
 
334
   return( SUCCESS ) ;
 
335
}
 
336
 
 
337
#else
 
338
 
 
339
#define try_memory_mapping( x, y, z )            FAILURE
 
340
 
 
341
#endif /* HAVE_MMAP */
 
342
 
 
343
 
 
344
static sio_status_e setup_read_buffer( __sio_id_t *idp, unsigned buf_size )
 
345
{
 
346
   char *buf ;
 
347
 
 
348
   /*
 
349
    * First allocate space for 2 buffers: primary and auxiliary
 
350
    */
 
351
   buf = malloc( buf_size * 2 ) ;
 
352
   if ( buf == NULL )
 
353
      return( FAILURE ) ;
 
354
 
 
355
   /*
 
356
    * The descriptor buf field should point to the start of the main buffer
 
357
    */
 
358
   idp->buf = buf + buf_size ;
 
359
   idp->buffer_size = buf_size ;
 
360
   return( SUCCESS ) ;
 
361
}
 
362
 
 
363
 
 
364
static sio_status_e init_input_stream( __sio_id_t *idp, int fd, const struct stat *stp )
 
365
{
 
366
   /*
 
367
    * First initialize the fields relevant to buffering: buf, buffer_size
 
368
    */
 
369
   if ( try_memory_mapping( fd, idp, stp ) == FAILURE )
 
370
   {
 
371
      /*
 
372
       * Try to use normal buffering
 
373
       */
 
374
      unsigned buf_size = (unsigned)
 
375
                     ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
 
376
      
 
377
      if ( setup_read_buffer( idp, buf_size ) == FAILURE )
 
378
         return( FAILURE ) ;
 
379
   }
 
380
 
 
381
    /*
 
382
    * Initialize remaining descriptor fields
 
383
    */
 
384
   idp->max_line_length = 2 * idp->buffer_size - 1 ;
 
385
   idp->start = idp->end = idp->nextb = idp->buf ;
 
386
   idp->tied_fd = SIO_NO_TIED_FD ;
 
387
 
 
388
   return( SUCCESS ) ;
 
389
}
 
390
 
 
391
 
 
392
static sio_status_e init_output_stream( __sio_od_t *odp, int fd, 
 
393
        const struct stat *stp )
 
394
{
 
395
   unsigned buf_size ;
 
396
   char *buf ;
 
397
 
 
398
   buf_size = (unsigned)
 
399
                  ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
 
400
   buf = malloc( buf_size ) ;
 
401
   if ( buf == NULL )
 
402
      return( FAILURE ) ;
 
403
   
 
404
   /*
 
405
    * Initialize buffering fields
 
406
    */
 
407
   odp->buf = buf ;
 
408
   odp->buffer_size = buf_size ;
 
409
   odp->buf_end = odp->buf + buf_size ;
 
410
 
 
411
   /*
 
412
    * Initialize remaining fields
 
413
    */
 
414
   odp->start = odp->nextb = odp->buf ;
 
415
   if ( isatty( fd ) )
 
416
      odp->buftype = SIO_LINEBUF ;
 
417
 
 
418
   if ( fd == 2 )
 
419
      odp->buftype = SIO_NOBUF ;
 
420
 
 
421
   return( SUCCESS ) ;
 
422
}
 
423
 
 
424
 
 
425
#ifndef HAVE_ISATTY
 
426
 
 
427
#ifdef HAVE_SYSVTTY
 
428
 
 
429
#include <termio.h>
 
430
 
 
431
static int isatty( int fd )
 
432
{
 
433
   struct termio t ;
 
434
 
 
435
   if ( ioctl( fd, TCGETA, &t ) == -1 && errno == ENOTTY )
 
436
      return( FALSE ) ;
 
437
   else
 
438
      return( TRUE ) ;
 
439
}
 
440
#endif   /* HAVE_SYSVTTY */
 
441
 
 
442
#ifdef HAVE_BSDTTY
 
443
 
 
444
#include <sgtty.h>
 
445
 
 
446
static int isatty( int fd )
 
447
{
 
448
   struct sgttyb s ;
 
449
 
 
450
   if ( ioctl( fd, TIOCGETP, &s ) == -1 && errno == ENOTTY )
 
451
      return( FALSE ) ;
 
452
   else
 
453
      return( TRUE ) ;
 
454
}
 
455
#endif   /* HAVE_BSDTTY */
 
456
 
 
457
#endif   /* ! HAVE_ISATTY */
 
458
 
 
459
 
 
460
/*
 
461
 * Initialize stream I/O for a file descriptor.
 
462
 *
 
463
 * Arguments:
 
464
 *      fd:            file descriptor
 
465
 *      dp:            descriptor pointer
 
466
 *      stream_type:    either __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
 
467
 *
 
468
 * Returns
 
469
 *      0          if successful
 
470
 *     SIO_ERR   if the file descriptor is not valid (sets errno)
 
471
 *   exits      if stream_type is not __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
 
472
 */
 
473
int __sio_init( __sio_descriptor_t *dp, int fd, enum __sio_stream stream_type )
 
474
{
 
475
   struct stat st ;
 
476
 
 
477
   memset(dp, 0, sizeof(__sio_descriptor_t));
 
478
   if ( fd >= __sio_n_descriptors )
 
479
   {
 
480
      errno = EBADF ;
 
481
      return( SIO_ERR ) ;
 
482
   }
 
483
 
 
484
   if ( fstat( fd, &st ) == -1 )
 
485
      return( SIO_ERR ) ;
 
486
   
 
487
   switch ( stream_type )
 
488
   {
 
489
      case __SIO_INPUT_STREAM:
 
490
         if ( init_input_stream( IDP( dp ), fd, &st ) == FAILURE )
 
491
            return( SIO_ERR ) ;
 
492
         break ;
 
493
 
 
494
      case __SIO_OUTPUT_STREAM:
 
495
         if ( init_output_stream( ODP( dp ), fd, &st ) == FAILURE )
 
496
            return( SIO_ERR ) ;
 
497
         break ;
 
498
         
 
499
      default:
 
500
         terminate( "SIO __sio_init: bad stream type (internal error).\n" ) ;
 
501
         /* NOTREACHED */
 
502
   }
 
503
   dp->stream_type = stream_type ;
 
504
   dp->initialized = TRUE ;
 
505
 
 
506
#ifdef HAVE_FINALIZATION_FUNCTION
 
507
   if ( ! finalizer_installed )
 
508
   {
 
509
      if ( ! SIO_FINALIZE( sio_cleanup ) )
 
510
      {
 
511
         char *s = "SIO __sio_init: finalizer installation failed\n" ;
 
512
 
 
513
         (void) write( 2, s, strlen( s ) ) ;
 
514
      }
 
515
      else
 
516
         finalizer_installed = TRUE ;
 
517
   }
 
518
#endif /* HAVE_FINALIZATION_FUNCTION */
 
519
 
 
520
   return( 0 ) ;
 
521
}
 
522
 
 
523
 
 
524
/*
 
525
 * __sio_writef writes the data in the buffer to the file descriptor.
 
526
 *
 
527
 * It tries to write as much data as possible until either all data
 
528
 * are written or an error occurs. EINTR is the only error that is
 
529
 * ignored.
 
530
 * In case an error occurs but some data were written, that number
 
531
 * is returned instead of SIO_ERR.
 
532
 *
 
533
 * Fields modified:
 
534
 *      When successful: start, nextb
 
535
 *      When not successful: start
 
536
 *
 
537
 * Return value:
 
538
 *      Number of bytes written
 
539
 *      SIO_ERR, if write(2) fails and no data were written
 
540
 */ 
 
541
int __sio_writef( __sio_od_t *odp, int fd )
 
542
{
 
543
   int b_in_buffer ;
 
544
   int cc_total = 0 ;
 
545
 
 
546
   /*
 
547
    * Make sure we don't exceed the buffer limits
 
548
    *   Maybe we should log this ?         XXX
 
549
    */
 
550
   if ( odp->nextb > odp->buf_end )
 
551
      odp->nextb = odp->buf_end ;
 
552
 
 
553
   b_in_buffer = odp->nextb - odp->start ;
 
554
 
 
555
   if ( b_in_buffer == 0 )
 
556
      return( 0 ) ;
 
557
   
 
558
   for ( ;; )
 
559
   {
 
560
      int cc ;
 
561
 
 
562
      cc = write( fd, odp->start, b_in_buffer ) ;
 
563
      if ( cc == b_in_buffer )
 
564
      {
 
565
         odp->start = odp->nextb = odp->buf ;
 
566
         cc_total += cc ;
 
567
         break ;
 
568
      }
 
569
      else if ( cc == -1 )
 
570
      {
 
571
         if ( errno == EINTR )
 
572
            continue ;
 
573
         else
 
574
            /*
 
575
             * If some bytes were written, return that number, otherwise
 
576
             * return SIO_ERR
 
577
             */
 
578
            return( ( cc_total != 0 ) ? cc_total : SIO_ERR ) ;
 
579
      }
 
580
      else         /* some bytes were written */
 
581
      {
 
582
         odp->start += cc ;         /* advance start of buffer */
 
583
         b_in_buffer -= cc ;         /* decrease number bytes left in buffer */
 
584
         cc_total += cc ;            /* count the bytes that were written */
 
585
      }
 
586
   }
 
587
   return( cc_total ) ;
 
588
}
 
589
 
 
590
 
 
591
/*
 
592
 * __sio_readf reads data from the file descriptor into the buffer.
 
593
 * Unlike __sio_writef it does NOT try to read as much data as will fit
 
594
 * in the buffer. It ignores EINTR.
 
595
 *
 
596
 * Returns: # of bytes read or SIO_ERR
 
597
 *
 
598
 * Fields set:
 
599
 *       If it does not return SIO_ERR, it sets start, nextb, end
 
600
 *         If it returns SIO_ERR, it does not change anything
 
601
 */
 
602
static int __sio_readf( __sio_id_t *idp, int fd )
 
603
{
 
604
   int cc ;
 
605
 
 
606
   /*
 
607
    * First check for a tied fd and flush the stream if necessary
 
608
    *
 
609
    *       XXX   the return value of __sio_writef is not checked.
 
610
    *               Is that right ?
 
611
    */
 
612
   if ( idp->tied_fd != SIO_NO_TIED_FD )
 
613
      (void) __sio_writef( &__SIO_OD( idp->tied_fd ), idp->tied_fd ) ;
 
614
 
 
615
#ifdef HAVE_MMAP
 
616
   if ( idp->memory_mapped )
 
617
   {
 
618
      mapd_s *mdp = MDP( fd ) ;
 
619
 
 
620
      /*
 
621
       * The functions initial_map and map_unit may fail.
 
622
       * In either case, we switch to buffered I/O.
 
623
       * If initial_map fails, we have read no data, so we
 
624
       * should perform a read(2).
 
625
       * If map_unit fails (for the next unit), we still have
 
626
       * the data in the current unit, so we can return.
 
627
       */
 
628
      if ( FIRST_TIME( idp ) )
 
629
      {
 
630
         cc = initial_map( mdp, fd ) ;
 
631
         if ( cc > 0 )
 
632
            idp->buf = mdp->first_unit.addr ;
 
633
         else
 
634
         {
 
635
            if ( __sio_switch( idp, fd ) == FAILURE )
 
636
               return( SIO_ERR ) ;
 
637
            cc = -1 ;
 
638
         }
 
639
      }
 
640
      else
 
641
      {
 
642
         struct map_unit *mu_cur, *mu_next ;
 
643
 
 
644
         if ( idp->buf == mdp->first_unit.addr )
 
645
         {
 
646
            mu_cur = &mdp->first_unit ;
 
647
            mu_next = &mdp->second_unit ;
 
648
         }
 
649
         else
 
650
         {
 
651
            mu_cur = &mdp->second_unit ;
 
652
            mu_next = &mdp->first_unit ;
 
653
         }
 
654
 
 
655
         if ( mu_next->addr != NULL )
 
656
         {
 
657
            idp->buf = mu_next->addr ;
 
658
            cc = mu_next->valid_bytes ;
 
659
            /*
 
660
             * XXX:  Here we may return SIO_ERR even though there
 
661
             *         are data in the current unit because the switch
 
662
             *         fails (possibly because malloc failed).
 
663
             */
 
664
            if ( map_unit( mdp, fd, mu_cur ) == FAILURE &&
 
665
                              __sio_switch( idp, fd ) == FAILURE )
 
666
               return( SIO_ERR ) ;
 
667
         }
 
668
         else
 
669
            cc = 0 ;
 
670
      }
 
671
      if ( cc >= 0 )
 
672
      {
 
673
         idp->end = idp->buf + cc ;
 
674
         idp->start = idp->nextb = idp->buf ;
 
675
         return( cc ) ;
 
676
      }
 
677
   }
 
678
#endif /* HAVE_MMAP */
 
679
 
 
680
   for ( ;; )
 
681
   {
 
682
      cc = read( fd, idp->buf, (int) idp->buffer_size ) ;
 
683
      if ( cc == -1 )
 
684
         if ( errno == EINTR )
 
685
            continue ;
 
686
         else
 
687
            return( SIO_ERR ) ;
 
688
      else
 
689
         break ;
 
690
   }
 
691
 
 
692
   idp->end = idp->buf + cc ;
 
693
   idp->start = idp->nextb = idp->buf ;
 
694
   return( cc ) ;
 
695
}
 
696
 
 
697
 
 
698
/*
 
699
 * __sio_extend_buffer is used by Srdline to extend the buffer
 
700
 * If successful, it returns the number of bytes that have been read.
 
701
 * If it fails (because of end-of-file or I/O error), it returns 0 or -1.
 
702
 *
 
703
 * Fields modified:
 
704
 *    idp->start points to the start of the buffer area (which is in the
 
705
 *    auxiliary buffer)
 
706
 *      Also, if successful, idp->nextb is set to idp->buf, idp->end is modified.
 
707
 */
 
708
int __sio_extend_buffer( __sio_id_t *idp, int fd, int b_left )
 
709
{
 
710
   int b_read ;
 
711
 
 
712
   /*
 
713
    * copy to auxiliary buffer
 
714
    */
 
715
   if ( b_left )
 
716
      sio_memcopy( idp->nextb, idp->buf - b_left, b_left ) ;
 
717
   b_read = __sio_readf( idp, fd ) ;
 
718
   idp->start = idp->buf - b_left ;
 
719
   return( b_read ) ;
 
720
}
 
721
 
 
722
 
 
723
/*
 
724
 * __sio_more tries to read more data from the given file descriptor iff
 
725
 * there is free space in the buffer.
 
726
 * __sio_more is used only by Srdline and only AFTER __sio_extend_buffer
 
727
 * has been called. This implies that 
 
728
 *      a) this is not a memory mapped file
 
729
 *      b) __sio_readf has been called (so we don't need to check for tied fd's
 
730
 *
 
731
 * Fields modified (only if successful):
 
732
 *         idp->end
 
733
 *
 
734
 * Return value: the number of bytes read.
 
735
 */
 
736
int __sio_more( __sio_id_t *idp, int fd )
 
737
{
 
738
   int b_left = &idp->buf[ idp->buffer_size ] - idp->end ;
 
739
   int cc ;
 
740
 
 
741
   if ( b_left <= 0 )
 
742
      return( 0 ) ;
 
743
   
 
744
   for ( ;; )
 
745
   {
 
746
      cc = read( fd, idp->end, b_left ) ;
 
747
      if ( cc >= 0 )
 
748
      {
 
749
         idp->end += cc ;
 
750
         return( cc ) ;
 
751
      }
 
752
      else
 
753
         if ( errno == EINTR )
 
754
            continue ;
 
755
         else
 
756
            return( SIO_ERR ) ;
 
757
   }
 
758
}
 
759
 
 
760
 
 
761
/*
 
762
 * Finalize a buffer by unmapping the file or freeing the malloc'ed memory.
 
763
 * This function is only called by Sclose. We always free memory even if
 
764
 * SIO_ERR is returned as long as the descriptor was initialized.
 
765
 */
 
766
int Sdone( int fd )
 
767
{
 
768
   __sio_descriptor_t *dp ;
 
769
   int ret_val = 0;
 
770
 
 
771
   if ( fd < 0 || fd >= __sio_n_descriptors )
 
772
   {
 
773
      errno = EBADF ;
 
774
      return( SIO_ERR ) ;
 
775
   }
 
776
 
 
777
   dp = &__sio_descriptors[ fd ] ;
 
778
   if ( ! DESCRIPTOR_INITIALIZED( dp ) )
 
779
   {
 
780
      errno = EBADF ;
 
781
      return( SIO_ERR ) ;
 
782
   }
 
783
 
 
784
   switch ( dp->stream_type )
 
785
   {
 
786
      case __SIO_INPUT_STREAM:
 
787
         {
 
788
            __sio_id_t *idp = IDP( dp ) ;
 
789
 
 
790
#ifdef HAVE_MMAP
 
791
            if ( idp->memory_mapped )
 
792
            {
 
793
               mapd_s *mdp = MDP( fd ) ;
 
794
 
 
795
               if ( mdp->first_unit.addr != CHAR_NULL )
 
796
                  (void) SIO_MUNMAP( mdp->first_unit.addr,
 
797
                                          mdp->first_unit.mapped_bytes ) ;
 
798
               if ( mdp->second_unit.addr != CHAR_NULL )
 
799
                  (void) SIO_MUNMAP( mdp->second_unit.addr,
 
800
                                          mdp->second_unit.mapped_bytes ) ;
 
801
               idp->memory_mapped = FALSE ;
 
802
            }
 
803
            else
 
804
#endif   /* HAVE_MMAP */
 
805
               free( idp->buf - idp->buffer_size ) ;
 
806
               idp->nextb = idp->end = NULL ;
 
807
         }
 
808
         break ;
 
809
      
 
810
      case __SIO_OUTPUT_STREAM:
 
811
         {
 
812
            __sio_od_t *odp = ODP( dp ) ;
 
813
 
 
814
            if ( Sflush( fd ) == SIO_ERR )
 
815
               ret_val = SIO_ERR;
 
816
            free( odp->buf ) ;
 
817
            odp->nextb = odp->buf_end = NULL ;
 
818
         }
 
819
         break ;
 
820
      
 
821
      default:
 
822
         terminate( "SIO Sdone: bad stream type\n" ) ;
 
823
   }
 
824
 
 
825
   memset( dp, 0, sizeof(__sio_descriptor_t) );
 
826
   dp->initialized = FALSE ;
 
827
   return ret_val;
 
828
}
 
829
 
 
830
 
 
831
static char *sioexpand( char *area, unsigned old_size, unsigned new_size, int is_static )
 
832
{
 
833
   char *new_area ;
 
834
 
 
835
   if ( is_static )
 
836
   {
 
837
      if ( ( new_area = malloc( new_size ) ) == NULL )
 
838
         return( NULL ) ;
 
839
      sio_memcopy( area, new_area, old_size ) ;
 
840
   }
 
841
   else
 
842
      if ( ( new_area = realloc( area, new_size ) ) == NULL )
 
843
         return( NULL ) ;
 
844
      
 
845
   return( new_area ) ;
 
846
}
 
847
 
 
848
 
 
849
/*
 
850
 * Expand the descriptor array (and if we use memory mapping the
 
851
 * memory mapping descriptors). We first expand the memory mapping
 
852
 * descriptors.
 
853
 * There is no problem if the expansion of the SIO descriptors fails
 
854
 * (i.e. there is no need to undo anything).
 
855
 */
 
856
int Smorefds(int fd)
 
857
{
 
858
   char *p ;
 
859
   int is_static ;
 
860
   unsigned new_size, old_size ;
 
861
   int n_fds = 4; /* Let's bump 4 at a time for hysteresis */
 
862
 
 
863
   /* If the fd is out of range of the proposed size, make n_fds big enough */
 
864
   if (fd >= (__sio_n_descriptors+n_fds))
 
865
      n_fds += fd - __sio_n_descriptors;
 
866
 
 
867
#ifdef HAVE_MMAP
 
868
   old_size = __sio_n_descriptors * sizeof( mapd_s ) ;
 
869
   new_size = n_fds * sizeof( mapd_s ) ;
 
870
   new_size += old_size;
 
871
   is_static = ( mmap_descriptors == NULL ) ;
 
872
   p = sioexpand( (char *)mmap_descriptors, old_size, new_size, is_static ) ;
 
873
   if ( p == NULL )
 
874
      return( SIO_ERR ) ;
 
875
   memset(p+old_size, 0, new_size-old_size);
 
876
   mmap_descriptors = (mapd_s *) p ;
 
877
#endif   /* HAVE_MMAP */
 
878
   
 
879
   old_size = __sio_n_descriptors * sizeof( __sio_descriptor_t ) ;
 
880
   new_size = n_fds * sizeof( __sio_descriptor_t ) ;
 
881
   new_size += old_size;
 
882
   is_static =  ( __sio_descriptors == NULL ) ;
 
883
   p = sioexpand( (char *)__sio_descriptors, old_size, new_size, is_static ) ;
 
884
   if ( p == NULL )
 
885
      return( SIO_ERR ) ;
 
886
   memset(p+old_size, 0, new_size-old_size);
 
887
   __sio_descriptors = (__sio_descriptor_t *) p ;
 
888
 
 
889
   __sio_n_descriptors += n_fds ;
 
890
   return( 0 ) ;
 
891
}
 
892
 
 
893
void terminate(const char *msg)
 
894
{
 
895
      syslog(LOG_CRIT, "%s", msg);
 
896
      (void) abort() ;
 
897
      _exit( 1 ) ;      /* NOT REACHED */
 
898
}
 
899