source: rtems/c/src/lib/libc/libio.c @ 78d87bd

4.104.114.84.95
Last change on this file since 78d87bd was 78d87bd, checked in by Joel Sherrill <joel.sherrill@…>, on 08/22/97 at 19:16:47

Fixed iop/memory leak bug reported by Dan Dickey.

  • Property mode set to 100644
File size: 12.0 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    { 0, 0, 0 },
162};
163
164static unsigned32
165rtems_libio_errno(rtems_status_code code)
166{
167    int rc;
168   
169    if ((rc = rtems_assoc_remote_by_local(errno_assoc, (unsigned32) code)))
170    {
171        errno = rc;
172        return -1;
173    }
174    return 0;
175}
176
177/*
178 * Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand
179 */
180
181rtems_assoc_t access_modes_assoc[] = {
182    { "READ",     LIBIO_FLAGS_READ,  O_RDONLY },
183    { "WRITE",    LIBIO_FLAGS_WRITE, O_WRONLY },
184    { "READ/WRITE", LIBIO_FLAGS_READ_WRITE, O_RDWR },
185    { 0, 0, 0 },
186};
187
188rtems_assoc_t status_flags_assoc[] = {
189    { "NO DELAY",  LIBIO_FLAGS_NO_DELAY,  O_NDELAY },
190    { "APPEND",    LIBIO_FLAGS_APPEND,    O_APPEND },
191    { "CREATE",    LIBIO_FLAGS_CREATE,    O_CREAT },
192    { 0, 0, 0 },
193};
194
195static unsigned32
196rtems_libio_fcntl_flags(unsigned32 fcntl_flags)
197{
198    unsigned32 flags = 0;
199    unsigned32 access_modes;
200
201    /*
202     * Access mode is a small integer
203     */
204   
205    access_modes = fcntl_flags & O_ACCMODE;
206    fcntl_flags &= ~O_ACCMODE;
207    flags = rtems_assoc_local_by_remote(access_modes_assoc, access_modes);
208
209    /*
210     * Everything else is single bits
211     */
212
213    flags |= rtems_assoc_local_by_remote_bitfield(status_flags_assoc, fcntl_flags);
214    return flags;
215}
216
217
218static rtems_libio_t *
219rtems_libio_allocate(void)
220{
221    rtems_libio_t *iop;
222    rtems_status_code rc;
223   
224    rtems_semaphore_obtain(rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
225
226    for (iop = rtems_libio_iops; iop <= rtems_libio_last_iop; iop++)
227        if ((iop->flags & LIBIO_FLAGS_OPEN) == 0)
228        {
229            /*
230             * Got one; create a semaphore for it
231             */
232
233            rc = rtems_semaphore_create(
234              RTEMS_LIBIO_IOP_SEM(iop - rtems_libio_iops),
235              1,
236              RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
237              RTEMS_NO_PRIORITY,
238              &iop->sem
239            );
240            if (rc != RTEMS_SUCCESSFUL)
241                goto failed;
242           
243            iop->flags = LIBIO_FLAGS_OPEN;
244            goto done;
245        }
246   
247failed:
248    iop = 0;
249   
250done:
251    rtems_semaphore_release(rtems_libio_semaphore);
252    return iop;
253}
254
255static void
256rtems_libio_free(rtems_libio_t *iop)
257{
258    rtems_semaphore_obtain(rtems_libio_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
259
260    if (iop->sem)
261        rtems_semaphore_delete(iop->sem);
262    (void) memset(iop, 0, sizeof(*iop));
263
264    rtems_semaphore_release(rtems_libio_semaphore);
265}
266
267int
268__rtems_open(
269    const char   *pathname,
270    unsigned32    flag,
271    unsigned32    mode)
272{
273    rtems_status_code rc;
274    rtems_libio_t *iop = 0;
275    rtems_driver_name_t *np;
276    rtems_libio_open_close_args_t args;
277
278    /*
279     * Additional external I/O handlers would be supported by
280     * adding code to pick apart the pathname appropriately.
281     * The networking code does not require changes here since
282     * network file descriptors are obtained using socket(), not
283     * open().
284     */
285
286    if ((rc = rtems_io_lookup_name(pathname, &np)) != RTEMS_SUCCESSFUL)
287        goto done;
288
289    iop = rtems_libio_allocate();
290    if (iop == 0)
291    {
292        rc = RTEMS_TOO_MANY;
293        goto done;
294    }
295   
296    iop->driver = np;
297    iop->pathname = (char *) pathname;
298    iop->flags |= rtems_libio_fcntl_flags(flag);
299
300    args.iop = iop;
301    args.flags = iop->flags;
302    args.mode = mode;
303
304    rc = rtems_io_open(np->major, np->minor, (void *) &args);
305   
306done:
307 
308    if (rc != RTEMS_SUCCESSFUL)
309    {
310        if (iop)
311            rtems_libio_free(iop);
312        return rtems_libio_errno(rc);
313    }
314   
315    return iop - rtems_libio_iops;
316}
317   
318int
319__rtems_close(
320    int  fd
321  )   
322{
323    rtems_status_code rc;
324    rtems_driver_name_t *np;
325    rtems_libio_t *iop;
326    rtems_libio_open_close_args_t args;
327    int status;
328
329    if (rtems_file_descriptor_type(fd)) {
330        int (*fp)(int fd);
331
332        fp = handlers[rtems_file_descriptor_type_index(fd)].close;
333        if (fp == NULL) {
334            errno = EBADF;
335            return -1;
336        }
337        status = (*fp)(fd);
338        rtems_libio_free(iop);
339        return status;
340    }
341    iop = rtems_libio_iop(fd);
342    rtems_libio_check_fd(fd);
343
344    np = iop->driver;
345
346    args.iop = iop;
347    args.flags = 0;
348    args.mode = 0;
349   
350    rc = rtems_io_close(np->major, np->minor, (void *) &args);
351
352    rtems_libio_free(iop);
353
354    if (rc != RTEMS_SUCCESSFUL)
355        return rtems_libio_errno(rc);
356    return 0;
357}
358   
359int
360__rtems_read(
361    int       fd,
362    void *    buffer,
363    unsigned32 count
364  )
365{
366    rtems_status_code rc;
367    rtems_driver_name_t *np;
368    rtems_libio_t *iop;
369    rtems_libio_rw_args_t args;
370
371    if (rtems_file_descriptor_type(fd)) {
372        int (*fp)(int fd, void *buffer, unsigned32 count);
373
374        fp = handlers[rtems_file_descriptor_type_index(fd)].read;
375        if (fp == NULL) {
376            errno = EBADF;
377            return -1;
378        }
379        return (*fp)(fd, buffer, count);
380    }
381    iop = rtems_libio_iop(fd);
382    rtems_libio_check_fd(fd);
383    rtems_libio_check_buffer(buffer);
384    rtems_libio_check_count(count);
385    rtems_libio_check_permissions(iop, LIBIO_FLAGS_READ);
386
387    np = iop->driver;
388
389    args.iop = iop;
390    args.offset = iop->offset;
391    args.buffer = buffer;
392    args.count = count;
393    args.flags = iop->flags;
394    args.bytes_moved = 0;
395
396    rc = rtems_io_read(np->major, np->minor, (void *) &args);
397
398    iop->offset += args.bytes_moved;
399
400    if (rc != RTEMS_SUCCESSFUL)
401        return rtems_libio_errno(rc);
402
403    return args.bytes_moved;
404}
405
406int
407__rtems_write(
408    int         fd,
409    const void *buffer,
410    unsigned32  count
411  )
412{
413    rtems_status_code rc;
414    rtems_driver_name_t *np;
415    rtems_libio_t *iop;
416    rtems_libio_rw_args_t args;
417
418    if (rtems_file_descriptor_type(fd)) {
419        int (*fp)(int fd, const void *buffer, unsigned32 count);
420
421        fp = handlers[rtems_file_descriptor_type_index(fd)].write;
422        if (fp == NULL) {
423            errno = EBADF;
424            return -1;
425        }
426        return (*fp)(fd, buffer, count);
427    }
428    iop = rtems_libio_iop(fd);
429    rtems_libio_check_fd(fd);
430    rtems_libio_check_buffer(buffer);
431    rtems_libio_check_count(count);
432    rtems_libio_check_permissions(iop, LIBIO_FLAGS_WRITE);
433
434    np = iop->driver;
435
436    args.iop = iop;
437    args.offset = iop->offset;
438    args.buffer = (void *) buffer;
439    args.count = count;
440    args.flags = iop->flags;
441    args.bytes_moved = 0;
442
443    rc = rtems_io_write(np->major, np->minor, (void *) &args);
444
445    iop->offset += args.bytes_moved;
446
447    if (rc != RTEMS_SUCCESSFUL)
448        return rtems_libio_errno(rc);
449
450    return args.bytes_moved;
451}
452
453int
454__rtems_ioctl(
455    int         fd,
456    unsigned32  command,
457    void *      buffer)
458{
459    rtems_status_code rc;
460    rtems_driver_name_t *np;
461    rtems_libio_t *iop;
462    rtems_libio_ioctl_args_t args;
463
464    if (rtems_file_descriptor_type(fd)) {
465        int (*fp)(int fd, unsigned32 command, void *buffer);
466
467        fp = handlers[rtems_file_descriptor_type_index(fd)].ioctl;
468        if (fp == NULL) {
469            errno = EBADF;
470            return -1;
471        }
472        return (*fp)(fd, command, buffer);
473    }
474    iop = rtems_libio_iop(fd);
475    rtems_libio_check_fd(fd);
476
477    np = iop->driver;
478
479    args.iop = iop;
480    args.command = command;
481    args.buffer = buffer;
482
483    rc = rtems_io_control(np->major, np->minor, (void *) &args);
484
485    if (rc != RTEMS_SUCCESSFUL)
486        return rtems_libio_errno(rc);
487
488    return args.ioctl_return;
489}
490   
491/*
492 * internal only??
493 */
494
495
496int
497__rtems_lseek(
498    int                  fd,
499    rtems_libio_offset_t offset,
500    int                  whence
501  )   
502{
503    rtems_libio_t *iop;
504
505    if (rtems_file_descriptor_type(fd)) {
506        int (*fp)(int fd, rtems_libio_offset_t offset, int whence);
507
508        fp = handlers[rtems_file_descriptor_type_index(fd)].lseek;
509        if (fp == NULL) {
510            errno = EBADF;
511            return -1;
512        }
513        return (*fp)(fd, offset, whence);
514    }
515    iop = rtems_libio_iop(fd);
516    rtems_libio_check_fd(fd);
517
518    switch (whence)
519    {
520        case SEEK_SET:
521            iop->offset = offset;
522            break;
523
524        case SEEK_CUR:
525            iop->offset += offset;
526            break;
527
528        case SEEK_END:
529            iop->offset = iop->size - offset;
530            break;
531
532        default:
533            errno = EINVAL;
534            return -1;
535    }
536    return 0;
537}
Note: See TracBrowser for help on using the repository browser.