source: rtems/c/src/lib/libc/libio.c @ 9646d5be

4.104.114.84.95
Last change on this file since 9646d5be was 9646d5be, checked in by Joel Sherrill <joel.sherrill@…>, on 02/17/98 at 18:46:38

Patch from Eric Norum <eric@…>:

I've gone through and cleaned up the TFTP driver so that it fits
into the libio system. Here's the comment from the new driver:

/*

  • Usage: *
  • To open /bootfiles/image' on hostname' for reading:
  • fd = open ("/TFTP/hostname/bootfiles/image", O_RDONLY); *
  • The `hostname' can be a symbolic name or four
  • dot-separated decimal values. *
  • To open a file on the host which supplied the BOOTP
  • information just leave the `hostname' part empty:
  • fd = open ("/TFTPbootfiles/image", O_RDONLY); * */

You can `fopen' TFTP files the same way:

fp = fopen (fullname, "r");
nread = fread (cbuf, sizeof cbuf[0], sizeof cbuf, fp);

The diff's are included below. I've also modified the TFTP demo
program and the bootstrap PROM example. They should be on my ftp
site `soon'.

The one thing I don't like is the way I had to do an end-run on the
libio routines to get errno passed back from my driver to the
application (since there are some errno codes that don't map to RTEMS
status codes). My approach was to set errno in the driver and have
the driver routine return an RTEMS status code that I `know' isn't in
the errno_assoc[] in libio.c.

Perhaps there should be an RTEMS_TRANPARENT_ERRNO status code (or
something similar) which driver routines could return to indicate
that the driver routine has set errno and that the libio routines
shouldn't attempt to map the returned status code to errno.

Actually, I think the entire I/O system needs looking at -- as
you've already mentioned. The hacks I've dropped in to syscalls.c to
make fstat work, for example, are *not* shining examples of good
code......

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