source: rtems/cpukit/libcsupport/src/libio.c @ 8f367d6b

4.104.114.84.95
Last change on this file since 8f367d6b was 8f367d6b, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 19, 1997 at 6:31:05 PM

Bug fix from Eric Norum:

After weeks of trying to figure why my RTEMS/KASQ server crashes now
and then I found a nasty bug I introduced in adding multiple-driver
support to libio. The bug only affects `add-on' driver classes (like
the networking code). Old-style file descriptors were not affected.

The bug cleared 32 bytes of memory (unspecified location) whenever a
`close' of a socket was performed! I was clearing an IOP I hadn't
allocated -- and the pointer wasn't initiallized, either!

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 *  Provide UNIX/POSIX-like io system calls for RTEMS using the
3 *  RTEMS IO manager
4 *
5 *  $Id$
6 */
7
8#include <rtems.h>
9#include <rtems/assoc.h>                /* assoc.h not included by rtems.h */
10
11#include <stdio.h>                      /* O_RDONLY, et.al. */
12#include <fcntl.h>                      /* O_RDONLY, et.al. */
13#include <assert.h>
14
15#if ! defined(O_NDELAY)
16# if defined(solaris2)
17#  define O_NDELAY O_NONBLOCK
18# elif defined(RTEMS_NEWLIB)
19#  define O_NDELAY _FNBIO
20# endif
21#endif
22
23
24#include <errno.h>
25#include <string.h>                     /* strcmp */
26#include <unistd.h>
27#include <stdlib.h>                     /* calloc() */
28
29#include "libio.h"                      /* libio.h not pulled in by rtems */
30
31/*
32 * Semaphore to protect the io table
33 */
34
35Objects_Id rtems_libio_semaphore;
36
37#define RTEMS_LIBIO_SEM         rtems_build_name('L', 'B', 'I', 'O')
38#define RTEMS_LIBIO_IOP_SEM(n)  rtems_build_name('L', 'B', 'I', n)
39
40unsigned32     rtems_libio_number_iops;
41rtems_libio_t *rtems_libio_iops;
42rtems_libio_t *rtems_libio_last_iop;
43
44#define rtems_libio_iop(fd)    ((((unsigned32)(fd)) < rtems_libio_number_iops) ? \
45                                       &rtems_libio_iops[fd] : 0)
46
47#define rtems_libio_check_fd(fd) \
48    do { \
49        if ((unsigned32) (fd) >= rtems_libio_number_iops) \
50        { \
51            errno = EBADF; \
52            return -1; \
53        } \
54    } while (0)
55
56#define rtems_libio_check_buffer(buffer) \
57    do { \
58        if ((buffer) == 0) \
59        { \
60            errno = EINVAL; \
61            return -1; \
62        } \
63    } while (0)
64
65#define rtems_libio_check_count(count) \
66    do { \
67        if ((count) == 0) \
68        { \
69            return 0; \
70        } \
71    } while (0)
72
73#define rtems_libio_check_permissions(iop, flag) \
74    do { \
75        if (((iop)->flags & (flag)) == 0) \
76        { \
77              errno = EINVAL; \
78              return -1; \
79        } \
80    } while (0)
81
82/*
83 * External I/O handlers
84 *
85 * Space for all possible handlers is preallocated
86 * to speed up dispatch to external handlers.
87 */
88
89static rtems_libio_handler_t handlers[15];
90
91void
92rtems_register_libio_handler(
93    int                         handler_flag,
94    const rtems_libio_handler_t *handler
95)
96{
97  int handler_index = rtems_file_descriptor_type_index(handler_flag);
98
99  if ((handler_index < 0) || (handler_index >= 15))
100    rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
101  handlers[handler_index] = *handler;
102}
103
104
105void
106rtems_libio_config(
107    rtems_configuration_table *config,
108    unsigned32                 max_fds
109)
110{
111    rtems_libio_number_iops = max_fds;
112
113    /*
114     * tweak config to reflect # of semaphores we will need
115     */
116
117    /* one for iop table */
118    config->RTEMS_api_configuration->maximum_semaphores += 1; 
119    config->RTEMS_api_configuration->maximum_semaphores += max_fds;
120}
121
122/*
123 * Called by bsp startup code to init the libio area.
124 */
125
126void
127rtems_libio_init(void)
128{
129    rtems_status_code rc;
130
131    if (rtems_libio_number_iops > 0)
132    {
133        rtems_libio_iops = (rtems_libio_t *) calloc(rtems_libio_number_iops,
134                                                    sizeof(rtems_libio_t));
135        if (rtems_libio_iops == NULL)
136            rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
137
138        rtems_libio_last_iop = rtems_libio_iops + (rtems_libio_number_iops - 1);
139    }
140
141    rc = rtems_semaphore_create(
142      RTEMS_LIBIO_SEM,
143      1,
144      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
145      RTEMS_NO_PRIORITY,
146      &rtems_libio_semaphore
147    );
148    if (rc != RTEMS_SUCCESSFUL)
149        rtems_fatal_error_occurred(rc);
150}
151
152/*
153 * Convert RTEMS status to a UNIX errno
154 */
155
156rtems_assoc_t errno_assoc[] = {
157    { "OK",                 RTEMS_SUCCESSFUL,                0 },
158    { "TIMEOUT",            RTEMS_TIMEOUT,                   ETIME },
159    { "NO MEMORY",          RTEMS_NO_MEMORY,                 ENOMEM },
160    { "NO DEVICE",          RTEMS_UNSATISFIED,               ENOSYS },
161    { "INVALID NUMBER",     RTEMS_INVALID_NUMBER,            EBADF},
162    { "NOT RESOURCE OWNER", RTEMS_NOT_OWNER_OF_RESOURCE,     EPERM},
163    { "IO ERROR",           RTEMS_IO_ERROR,                  EIO},
164    { 0, 0, 0 },
165};
166
167static unsigned32
168rtems_libio_errno(rtems_status_code code)
169{
170    int rc;
171   
172    if ((rc = rtems_assoc_remote_by_local(errno_assoc, (unsigned32) code)))
173    {
174        errno = rc;
175        return -1;
176    }
177    return -1;
178}
179
180/*
181 * Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand
182 */
183
184rtems_assoc_t access_modes_assoc[] = {
185    { "READ",       LIBIO_FLAGS_READ,  O_RDONLY },
186    { "WRITE",      LIBIO_FLAGS_WRITE, O_WRONLY },
187    { "READ/WRITE", LIBIO_FLAGS_READ_WRITE, O_RDWR },
188    { 0, 0, 0 },
189};
190
191rtems_assoc_t status_flags_assoc[] = {
192    { "NO DELAY",  LIBIO_FLAGS_NO_DELAY,  O_NDELAY },
193    { "APPEND",    LIBIO_FLAGS_APPEND,    O_APPEND },
194    { "CREATE",    LIBIO_FLAGS_CREATE,    O_CREAT },
195    { 0, 0, 0 },
196};
197
198static unsigned32
199rtems_libio_fcntl_flags(unsigned32 fcntl_flags)
200{
201    unsigned32 flags = 0;
202    unsigned32 access_modes;
203
204    /*
205     * Access mode is a small integer
206     */
207   
208    access_modes = fcntl_flags & O_ACCMODE;
209    fcntl_flags &= ~O_ACCMODE;
210    flags = rtems_assoc_local_by_remote(access_modes_assoc, access_modes);
211
212    /*
213     * Everything else is single bits
214     */
215
216    flags |= rtems_assoc_local_by_remote_bitfield(status_flags_assoc, fcntl_flags);
217    return flags;
218}
219
220
221static rtems_libio_t *
222rtems_libio_allocate(void)
223{
224    rtems_libio_t *iop;
225    rtems_status_code rc;
226   
227    rtems_semaphore_obtain(rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
228
229    for (iop = rtems_libio_iops; iop <= rtems_libio_last_iop; iop++)
230        if ((iop->flags & LIBIO_FLAGS_OPEN) == 0)
231        {
232            /*
233             * Got one; create a semaphore for it
234             */
235
236            rc = rtems_semaphore_create(
237              RTEMS_LIBIO_IOP_SEM(iop - rtems_libio_iops),
238              1,
239              RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
240              RTEMS_NO_PRIORITY,
241              &iop->sem
242            );
243            if (rc != RTEMS_SUCCESSFUL)
244                goto failed;
245           
246            iop->flags = LIBIO_FLAGS_OPEN;
247            goto done;
248        }
249   
250failed:
251    iop = 0;
252   
253done:
254    rtems_semaphore_release(rtems_libio_semaphore);
255    return iop;
256}
257
258static void
259rtems_libio_free(rtems_libio_t *iop)
260{
261    rtems_semaphore_obtain(rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
262
263    if (iop->sem)
264        rtems_semaphore_delete(iop->sem);
265    (void) memset(iop, 0, sizeof(*iop));
266
267    rtems_semaphore_release(rtems_libio_semaphore);
268}
269
270int
271__rtems_open(
272    const char   *pathname,
273    unsigned32    flag,
274    unsigned32    mode)
275{
276    rtems_status_code rc;
277    rtems_libio_t *iop = 0;
278    rtems_driver_name_t *np;
279    rtems_libio_open_close_args_t args;
280
281    /*
282     * Additional external I/O handlers would be supported by
283     * adding code to pick apart the pathname appropriately.
284     * The networking code does not require changes here since
285     * network file descriptors are obtained using socket(), not
286     * open().
287     */
288
289    if ((rc = rtems_io_lookup_name(pathname, &np)) != RTEMS_SUCCESSFUL)
290        goto done;
291
292    iop = rtems_libio_allocate();
293    if (iop == 0)
294    {
295        rc = RTEMS_TOO_MANY;
296        goto done;
297    }
298   
299    iop->driver = np;
300    iop->pathname = (char *) pathname;
301    iop->flags |= rtems_libio_fcntl_flags(flag);
302
303    args.iop = iop;
304    args.flags = iop->flags;
305    args.mode = mode;
306
307    rc = rtems_io_open(np->major, np->minor, (void *) &args);
308   
309done:
310 
311    if (rc != RTEMS_SUCCESSFUL)
312    {
313        if (iop)
314            rtems_libio_free(iop);
315        return rtems_libio_errno(rc);
316    }
317   
318    return iop - rtems_libio_iops;
319}
320   
321int
322__rtems_close(
323    int  fd
324  )   
325{
326    rtems_status_code rc;
327    rtems_driver_name_t *np;
328    rtems_libio_t *iop;
329    rtems_libio_open_close_args_t args;
330    int status;
331
332    if (rtems_file_descriptor_type(fd)) {
333        int (*fp)(int fd);
334
335        fp = handlers[rtems_file_descriptor_type_index(fd)].close;
336        if (fp == NULL) {
337            errno = EBADF;
338            return -1;
339        }
340        status = (*fp)(fd);
341        return status;
342    }
343    iop = rtems_libio_iop(fd);
344    rtems_libio_check_fd(fd);
345
346    np = iop->driver;
347
348    args.iop = iop;
349    args.flags = 0;
350    args.mode = 0;
351   
352    rc = rtems_io_close(np->major, np->minor, (void *) &args);
353
354    rtems_libio_free(iop);
355
356    if (rc != RTEMS_SUCCESSFUL)
357        return rtems_libio_errno(rc);
358    return 0;
359}
360   
361int
362__rtems_read(
363    int       fd,
364    void *    buffer,
365    unsigned32 count
366  )
367{
368    rtems_status_code rc;
369    rtems_driver_name_t *np;
370    rtems_libio_t *iop;
371    rtems_libio_rw_args_t args;
372
373    if (rtems_file_descriptor_type(fd)) {
374        int (*fp)(int fd, void *buffer, unsigned32 count);
375
376        fp = handlers[rtems_file_descriptor_type_index(fd)].read;
377        if (fp == NULL) {
378            errno = EBADF;
379            return -1;
380        }
381        return (*fp)(fd, buffer, count);
382    }
383    iop = rtems_libio_iop(fd);
384    rtems_libio_check_fd(fd);
385    rtems_libio_check_buffer(buffer);
386    rtems_libio_check_count(count);
387    rtems_libio_check_permissions(iop, LIBIO_FLAGS_READ);
388
389    np = iop->driver;
390
391    args.iop = iop;
392    args.offset = iop->offset;
393    args.buffer = buffer;
394    args.count = count;
395    args.flags = iop->flags;
396    args.bytes_moved = 0;
397
398    rc = rtems_io_read(np->major, np->minor, (void *) &args);
399
400    iop->offset += args.bytes_moved;
401
402    if (rc != RTEMS_SUCCESSFUL)
403        return rtems_libio_errno(rc);
404
405    return args.bytes_moved;
406}
407
408int
409__rtems_write(
410    int         fd,
411    const void *buffer,
412    unsigned32  count
413  )
414{
415    rtems_status_code rc;
416    rtems_driver_name_t *np;
417    rtems_libio_t *iop;
418    rtems_libio_rw_args_t args;
419
420    if (rtems_file_descriptor_type(fd)) {
421        int (*fp)(int fd, const void *buffer, unsigned32 count);
422
423        fp = handlers[rtems_file_descriptor_type_index(fd)].write;
424        if (fp == NULL) {
425            errno = EBADF;
426            return -1;
427        }
428        return (*fp)(fd, buffer, count);
429    }
430    iop = rtems_libio_iop(fd);
431    rtems_libio_check_fd(fd);
432    rtems_libio_check_buffer(buffer);
433    rtems_libio_check_count(count);
434    rtems_libio_check_permissions(iop, LIBIO_FLAGS_WRITE);
435
436    np = iop->driver;
437
438    args.iop = iop;
439    args.offset = iop->offset;
440    args.buffer = (void *) buffer;
441    args.count = count;
442    args.flags = iop->flags;
443    args.bytes_moved = 0;
444
445    rc = rtems_io_write(np->major, np->minor, (void *) &args);
446
447    iop->offset += args.bytes_moved;
448
449    if (rc != RTEMS_SUCCESSFUL)
450        return rtems_libio_errno(rc);
451
452    return args.bytes_moved;
453}
454
455int
456__rtems_ioctl(
457    int         fd,
458    unsigned32  command,
459    void *      buffer)
460{
461    rtems_status_code rc;
462    rtems_driver_name_t *np;
463    rtems_libio_t *iop;
464    rtems_libio_ioctl_args_t args;
465
466    if (rtems_file_descriptor_type(fd)) {
467        int (*fp)(int fd, unsigned32 command, void *buffer);
468
469        fp = handlers[rtems_file_descriptor_type_index(fd)].ioctl;
470        if (fp == NULL) {
471            errno = EBADF;
472            return -1;
473        }
474        return (*fp)(fd, command, buffer);
475    }
476    iop = rtems_libio_iop(fd);
477    rtems_libio_check_fd(fd);
478
479    np = iop->driver;
480
481    args.iop = iop;
482    args.command = command;
483    args.buffer = buffer;
484
485    rc = rtems_io_control(np->major, np->minor, (void *) &args);
486
487    if (rc != RTEMS_SUCCESSFUL)
488        return rtems_libio_errno(rc);
489
490    return args.ioctl_return;
491}
492   
493/*
494 * internal only??
495 */
496
497
498int
499__rtems_lseek(
500    int                  fd,
501    rtems_libio_offset_t offset,
502    int                  whence
503  )   
504{
505    rtems_libio_t *iop;
506
507    if (rtems_file_descriptor_type(fd)) {
508        int (*fp)(int fd, rtems_libio_offset_t offset, int whence);
509
510        fp = handlers[rtems_file_descriptor_type_index(fd)].lseek;
511        if (fp == NULL) {
512            errno = EBADF;
513            return -1;
514        }
515        return (*fp)(fd, offset, whence);
516    }
517    iop = rtems_libio_iop(fd);
518    rtems_libio_check_fd(fd);
519
520    switch (whence)
521    {
522        case SEEK_SET:
523            iop->offset = offset;
524            break;
525
526        case SEEK_CUR:
527            iop->offset += offset;
528            break;
529
530        case SEEK_END:
531            iop->offset = iop->size - offset;
532            break;
533
534        default:
535            errno = EINVAL;
536            return -1;
537    }
538    return 0;
539}
Note: See TracBrowser for help on using the repository browser.