source: rtems-libbsd/rtemsbsd/rtems/rtems-bsd-program.c @ 87d0cda

4.11
Last change on this file since 87d0cda was 87d0cda, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/14/16 at 09:01:43

rtemsbsd: Add wrapper for open, fopen, malloc, ...

Add the following rtems_bsd_program_... wrapper:

  • rtems_bsd_program_open
  • rtems_bsd_program_socket
  • rtems_bsd_program_close
  • rtems_bsd_program_fopen
  • rtems_bsd_program_fclose
  • rtems_bsd_program_malloc
  • rtems_bsd_program_calloc
  • rtems_bsd_program_realloc
  • rtems_bsd_program_free
  • rtems_bsd_program_strdup
  • rtems_bsd_program_vasprintf
  • rtems_bsd_program_asprintf
  • Property mode set to 100644
File size: 14.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#include <machine/rtems-bsd-kernel-space.h>
41#include <machine/rtems-bsd-thread.h>
42
43#include <rtems/bsd/sys/param.h>
44#include <rtems/bsd/sys/types.h>
45#include <sys/types.h>
46#include <sys/socket.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/proc.h>
50#include <sys/malloc.h>
51#include <rtems/bsd/sys/lock.h>
52#include <sys/mutex.h>
53
54#include <fcntl.h>
55#include <setjmp.h>
56#include <stdlib.h>
57#include <string.h>
58#include <syslog.h>
59
60#undef printf
61#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
62#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
63#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
64#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
65#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
66#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
67#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
68#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
69#define RTEMS_BSD_PROGRAM_NO_STRDUP_WRAP
70#define RTEMS_BSD_PROGRAM_NO_VASPRINTF_WRAP
71#define RTEMS_BSD_PROGRAM_NO_ASPRINTF_WRAP
72#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
73#include <machine/rtems-bsd-program.h>
74
75struct rtems_bsd_program_control {
76        void *context;
77        int exit_code;
78        const char *name;
79        jmp_buf return_context;
80        LIST_HEAD(, rtems_bsd_fd_list) open_fd;
81        LIST_HEAD(, rtems_bsd_file_list) open_file;
82        LIST_HEAD(, rtems_bsd_allocmem_list) allocated_mem;
83};
84
85struct rtems_bsd_fd_list {
86        int     fd;
87        LIST_ENTRY(rtems_bsd_fd_list) entries;
88};
89
90struct rtems_bsd_file_list {
91        FILE    *file;
92        LIST_ENTRY(rtems_bsd_file_list) entries;
93};
94
95struct rtems_bsd_allocmem_list {
96        void    *ptr;
97        LIST_ENTRY(rtems_bsd_allocmem_list) entries;
98};
99
100enum rtems_bsd_alloc_type {
101        RTEMS_BSD_ALLOC_CALL_MALLOC,
102        RTEMS_BSD_ALLOC_CALL_CALLOC,
103        RTEMS_BSD_ALLOC_CALL_REALLOC,
104        RTEMS_BSD_ALLOC_CALL_STRDUP,
105};
106
107static struct rtems_bsd_program_control *
108rtems_bsd_program_get_cur_prog_ctrl_or_null(void)
109{
110        struct rtems_bsd_program_control *prog_ctrl = NULL;
111        struct thread *td = rtems_bsd_get_curthread_or_null();
112
113        if (td != NULL) {
114                prog_ctrl = td->td_prog_ctrl;
115
116                if (prog_ctrl == NULL) {
117                        panic("unexpected BSD program state");
118                }
119        } else {
120                errno = ENOMEM;
121        }
122
123        return prog_ctrl;
124}
125
126static int
127fd_remove(struct rtems_bsd_program_control *prog_ctrl, int fd)
128{
129        struct rtems_bsd_fd_list *current;
130        int rv = -1;
131
132        for(current = prog_ctrl->open_fd.lh_first;
133            current != NULL;
134            current = current->entries.le_next) {
135                if(current->fd == fd) {
136                        LIST_REMOVE(current, entries);
137                        free(current, M_TEMP);
138                        rv = 0;
139                        break;
140                }
141        }
142
143        return rv;
144}
145
146static int
147fd_close_remove(struct rtems_bsd_program_control *prog_ctrl, int fd)
148{
149        int rv = -1;
150
151        rv = fd_remove(prog_ctrl, fd);
152        if(rv == 0) {
153                rv = close(fd);
154        }
155
156        return rv;
157}
158
159static void
160fd_close_all(struct rtems_bsd_program_control *prog_ctrl)
161{
162        while(prog_ctrl->open_fd.lh_first != NULL) {
163                struct rtems_bsd_fd_list *current;
164                int fd;
165                int rv;
166
167                current = prog_ctrl->open_fd.lh_first;
168                fd = current->fd;
169
170                rv = fd_close_remove(prog_ctrl, fd);
171                if(rv != 0) {
172                        syslog(LOG_ERR,
173                            "BSD Program: Could not close file %d or could not remove it from list of open files",
174                            fd);
175                }
176        }
177}
178
179static int
180file_remove(struct rtems_bsd_program_control *prog_ctrl, FILE *file)
181{
182        struct rtems_bsd_file_list *current;
183        int rv = EOF;
184
185        for(current = prog_ctrl->open_file.lh_first;
186            current != NULL;
187            current = current->entries.le_next) {
188                if(current->file == file) {
189                        LIST_REMOVE(current, entries);
190                        free(current, M_TEMP);
191                        rv = 0;
192                        break;
193                }
194        }
195
196        return rv;
197}
198
199static int
200file_close_remove(struct rtems_bsd_program_control *prog_ctrl, FILE *file)
201{
202        int rv = EOF;
203
204        rv = file_remove(prog_ctrl, file);
205        if(rv == 0) {
206                rv = fclose(file);
207        }
208
209        return rv;
210}
211
212static void
213file_close_all(struct rtems_bsd_program_control *prog_ctrl)
214{
215        while(prog_ctrl->open_file.lh_first != NULL) {
216                struct rtems_bsd_file_list *current;
217                FILE *file;
218                int rv;
219
220                current = prog_ctrl->open_file.lh_first;
221                file = current->file;
222
223                rv = file_close_remove(prog_ctrl, file);
224                if(rv != 0) {
225                        syslog(LOG_ERR,
226                            "BSD Program: Could not close stream %p or could not remove it from list of open streams",
227                            file);
228                }
229        }
230}
231
232static int
233allocmem_remove(struct rtems_bsd_program_control *prog_ctrl, void *ptr)
234{
235        struct rtems_bsd_allocmem_list *current;
236        int rv = -1;
237
238        for(current = prog_ctrl->allocated_mem.lh_first;
239            current != NULL;
240            current = current->entries.le_next) {
241                if(current->ptr == ptr) {
242                        LIST_REMOVE(current, entries);
243                        rv = 0;
244                        break;
245                }
246        }
247
248        return rv;
249}
250
251static int
252allocmem_free_remove(struct rtems_bsd_program_control *prog_ctrl, void *ptr)
253{
254        int rv = -1;
255
256        rv = allocmem_remove(prog_ctrl, ptr);
257        if(rv == 0) {
258                free(ptr, M_TEMP);
259        }
260
261        return rv;
262}
263
264static void
265allocmem_free_all(struct rtems_bsd_program_control *prog_ctrl)
266{
267        while(prog_ctrl->allocated_mem.lh_first != NULL) {
268                struct rtems_bsd_allocmem_list *current;
269                void *ptr;
270                int rv;
271
272                current = prog_ctrl->allocated_mem.lh_first;
273                ptr = current->ptr;
274
275                rv = allocmem_free_remove(prog_ctrl, ptr);
276                if(rv != 0) {
277                        /* This should never happen. It would mean that someone
278                         * changed the allocmem list while we are removing the
279                         * element. */
280                        syslog(LOG_ERR,
281                            "BSD Program: Could not remove %p from list of allocated memory",
282                            ptr);
283                }
284        }
285}
286
287int
288rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context)
289{
290        struct thread *td = rtems_bsd_get_curthread_or_null();
291        int exit_code = EXIT_FAILURE;
292
293        if (td != NULL) {
294                struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
295
296                if (prog_ctrl == NULL) {
297                        prog_ctrl = malloc(sizeof(*prog_ctrl), M_TEMP, 0);
298
299                        if (prog_ctrl != NULL) {
300                                td->td_prog_ctrl = prog_ctrl;
301
302                                prog_ctrl->context = context;
303                                prog_ctrl->name = name;
304                                prog_ctrl->exit_code = exit_code;
305
306                                LIST_INIT(&(prog_ctrl->open_fd));
307                                LIST_INIT(&(prog_ctrl->open_file));
308                                LIST_INIT(&(prog_ctrl->allocated_mem));
309
310                                if (setjmp(prog_ctrl->return_context) == 0) {
311                                        exit_code = (*prog)(context);
312                                } else {
313                                        exit_code = prog_ctrl->exit_code;
314                                }
315
316                                fd_close_all(prog_ctrl);
317                                file_close_all(prog_ctrl);
318                                allocmem_free_all(prog_ctrl);
319
320                                td->td_prog_ctrl = NULL;
321                                free(prog_ctrl, M_TEMP);
322                        } else {
323                                errno = ENOMEM;
324                        }
325                } else {
326                        panic("unexpected BSD program state");
327                }
328        } else {
329                errno = ENOMEM;
330        }
331
332        return exit_code;
333}
334
335void
336rtems_bsd_program_exit(int exit_code)
337{
338        struct thread *td = rtems_bsd_get_curthread_or_null();
339
340        if (td != NULL) {
341                struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
342
343                if (prog_ctrl != NULL) {
344                        prog_ctrl->exit_code = exit_code;
345                        longjmp(prog_ctrl->return_context, 1);
346                }
347        }
348
349        panic("unexpected BSD program exit");
350}
351
352void
353rtems_bsd_program_error(const char *fmt, ...)
354{
355        va_list list;
356        va_start(list, fmt);
357        vfprintf(stderr, fmt, list);
358        fprintf(stderr, "\n");
359        va_end(list);
360        rtems_bsd_program_exit(1);
361}
362
363const char *
364rtems_bsd_program_get_name(void)
365{
366        struct thread *td = rtems_bsd_get_curthread_or_null();
367        const char *name = "?";
368
369        if (td != NULL) {
370                struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
371
372                if (prog_ctrl != NULL) {
373                        name = prog_ctrl->name;
374                }
375        }
376
377        return name;
378}
379
380void *
381rtems_bsd_program_get_context(void)
382{
383        struct thread *td = rtems_bsd_get_curthread_or_null();
384        void *context = NULL;
385
386        if (td != NULL) {
387                struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
388
389                if (prog_ctrl != NULL) {
390                        context = prog_ctrl->context;
391                }
392        }
393
394        return context;
395}
396
397struct main_context {
398        int argc;
399        char **argv;
400        int (*main)(int, char **);
401};
402
403static int
404call_main(void *ctx)
405{
406        const struct main_context *mc = ctx;
407
408        return (*mc->main)(mc->argc, mc->argv);
409}
410
411int
412rtems_bsd_program_call_main(const char *name, int (*main)(int, char **),
413    int argc, char **argv)
414{
415        struct main_context mc = {
416                .argc = argc,
417                .argv = argv,
418                .main = main
419        };
420        int exit_code;
421
422        if (argv[argc] == NULL) {
423                exit_code = rtems_bsd_program_call(name, call_main, &mc);
424        } else {
425                errno = EFAULT;
426                exit_code = EXIT_FAILURE;
427        }
428
429        return exit_code;
430}
431
432int
433rtems_bsd_program_call_main_with_data_restore(const char *name,
434    int (*main)(int, char **), int argc, char **argv,
435    void *data_buf, const size_t data_size)
436{
437        int exit_code = EXIT_FAILURE;
438        void *savebuf;
439
440        savebuf = malloc(data_size, M_TEMP, 0);
441        if(savebuf == NULL) {
442                errno = ENOMEM;
443                exit_code = EXIT_FAILURE;
444        } else {
445                memcpy(savebuf, data_buf, data_size);
446                exit_code = rtems_bsd_program_call_main(name, main, argc,
447                    argv);
448                memcpy(data_buf, savebuf, data_size);
449                free(savebuf, M_TEMP);
450        }
451
452        return exit_code;
453}
454
455static struct mtx program_mtx;
456
457MTX_SYSINIT(rtems_bsd_program, &program_mtx, "BSD program", MTX_DEF);
458
459void
460rtems_bsd_program_lock(void)
461{
462        mtx_lock(&program_mtx);
463}
464
465void
466rtems_bsd_program_unlock(void)
467{
468        mtx_unlock(&program_mtx);
469}
470
471int
472rtems_bsd_program_open(const char *path, int oflag, ...)
473{
474        struct rtems_bsd_program_control *prog_ctrl =
475            rtems_bsd_program_get_cur_prog_ctrl_or_null();
476        va_list list;
477        mode_t mode = 0;
478        int fd = -1;
479
480        if (prog_ctrl != NULL) {
481                struct rtems_bsd_fd_list *new =
482                    malloc(sizeof(struct rtems_bsd_fd_list), M_TEMP, 0);
483
484                if(new != NULL) {
485                        va_start(list, oflag);
486                        mode = va_arg(list, mode_t);
487
488                        fd = open(path, oflag, mode);
489
490                        va_end(list);
491
492                        if(fd != -1) {
493                                new->fd = fd;
494                                LIST_INSERT_HEAD(&(prog_ctrl->open_fd),
495                                    new, entries);
496                        } else {
497                                free(new, M_TEMP);
498                        }
499                } else {
500                        errno = ENOMEM;
501                }
502        }
503
504        return fd;
505}
506
507int
508rtems_bsd_program_socket(int domain, int type, int protocol)
509{
510        struct rtems_bsd_program_control *prog_ctrl =
511            rtems_bsd_program_get_cur_prog_ctrl_or_null();
512        int fd = -1;
513
514        if (prog_ctrl != NULL) {
515                struct rtems_bsd_fd_list *new =
516                    malloc(sizeof(struct rtems_bsd_fd_list), M_TEMP, 0);
517
518                if(new != NULL) {
519                        /* FIXME: Why is there an implicit declaration warning?
520                         */
521                        fd = socket(domain, type, protocol);
522
523                        if(fd != -1) {
524                                new->fd = fd;
525                                LIST_INSERT_HEAD(&(prog_ctrl->open_fd),
526                                    new, entries);
527                        } else {
528                                free(new, M_TEMP);
529                        }
530                } else {
531                        errno = ENOMEM;
532                }
533        }
534
535        return fd;
536}
537
538int
539rtems_bsd_program_close(int fd)
540{
541        struct rtems_bsd_program_control *prog_ctrl =
542            rtems_bsd_program_get_cur_prog_ctrl_or_null();
543        int rv = -1;
544
545        if (prog_ctrl != NULL) {
546                rv = fd_close_remove(prog_ctrl, fd);
547        }
548
549        return rv;
550}
551
552FILE *
553rtems_bsd_program_fopen(const char *restrict filename,
554    const char *restrict mode)
555{
556        FILE *file = NULL;
557        struct rtems_bsd_program_control *prog_ctrl =
558            rtems_bsd_program_get_cur_prog_ctrl_or_null();
559
560        if (prog_ctrl != NULL) {
561                struct rtems_bsd_file_list *new =
562                    malloc(sizeof(struct rtems_bsd_file_list), M_TEMP, 0);
563
564                if(new != NULL) {
565                        file = fopen(filename, mode);
566
567                        if(file != NULL) {
568                                new->file = file;
569                                LIST_INSERT_HEAD(
570                                    &(prog_ctrl->open_file), new,
571                                    entries);
572                        } else {
573                                free(new, M_TEMP);
574                        }
575                } else {
576                        errno = ENOMEM;
577                }
578        }
579
580        return file;
581}
582
583int
584rtems_bsd_program_fclose(FILE *file)
585{
586        struct rtems_bsd_program_control *prog_ctrl =
587            rtems_bsd_program_get_cur_prog_ctrl_or_null();
588        int rv = EOF;
589
590        if (prog_ctrl != NULL) {
591                rv = file_close_remove(prog_ctrl, file);
592        }
593
594        return rv;
595}
596
597static void *
598rtems_bsd_program_alloc(size_t size, void *org_ptr)
599{
600        struct rtems_bsd_program_control *prog_ctrl =
601            rtems_bsd_program_get_cur_prog_ctrl_or_null();
602        void *ptr = NULL;
603        size_t size_with_list;
604        size_t size_alligned;
605
606        if (prog_ctrl != NULL) {
607                /* align the end to the next word address */
608                size_alligned = size;
609                if((size_alligned & 0x3) != 0) {
610                        size_alligned = (size_alligned | 0x03) + 1;
611                }
612                size_with_list = size_alligned +
613                    sizeof(struct rtems_bsd_allocmem_list);
614
615                if(org_ptr != NULL) {
616                        /* It's a reallocation. So first remove the old pointer
617                         * from the list */
618                        allocmem_remove(prog_ctrl, org_ptr);
619                }
620
621                ptr = realloc(org_ptr, size_with_list, M_TEMP, 0);
622
623                if(ptr != NULL) {
624                        struct rtems_bsd_allocmem_list *listele;
625                        listele = ptr + size_alligned;
626                        listele->ptr = ptr;
627                        LIST_INSERT_HEAD(&(prog_ctrl->allocated_mem),
628                            listele, entries);
629                }
630        }
631
632        return ptr;
633}
634
635void *
636rtems_bsd_program_malloc(size_t size)
637{
638        return rtems_bsd_program_alloc(size, NULL);
639}
640
641void *
642rtems_bsd_program_calloc(size_t nelem, size_t elsize)
643{
644        void *ptr;
645        size_t size = elsize * nelem;
646
647        ptr = rtems_bsd_program_alloc(size, NULL);
648        if(ptr != NULL) {
649                memset(ptr, 0, size);
650        }
651
652        return ptr;
653}
654
655void *
656rtems_bsd_program_realloc(void *ptr, size_t size)
657{
658        return rtems_bsd_program_alloc(size, ptr);
659}
660
661char *
662rtems_bsd_program_strdup(const char *s1)
663{
664        size_t size = strlen(s1) + 1; /* add one for null termination */
665        char *new;
666
667        new = rtems_bsd_program_alloc(size, NULL);
668
669        if(new != NULL) {
670                memcpy(new, s1, size);
671        }
672
673        return new;
674}
675
676int
677rtems_bsd_program_vasprintf(char **strp, const char *fmt, va_list ap)
678{
679        va_list aq;
680        int size;
681        int rv = -1;
682
683        va_copy(aq, ap);
684        size = vsnprintf(NULL, 0, fmt, aq);
685        va_end(aq);
686
687        size += 1; /* Add space for terminating null byte */
688        *strp = rtems_bsd_program_alloc(size, NULL);
689
690        if(*strp != NULL) {
691                rv = vsnprintf(*strp, size, fmt, ap);
692        }
693
694        return rv;
695}
696
697int
698rtems_bsd_program_asprintf(char **strp, const char *fmt, ...)
699{
700        va_list ap;
701        int rv;
702
703        va_start(ap, fmt);
704
705        rv = rtems_bsd_program_vasprintf(strp, fmt, ap);
706
707        va_end(ap);
708
709        return rv;
710}
711
712void
713rtems_bsd_program_free(void *ptr)
714{
715        if(ptr != NULL) {
716                struct rtems_bsd_program_control *prog_ctrl =
717                    rtems_bsd_program_get_cur_prog_ctrl_or_null();
718
719                if (prog_ctrl != NULL) {
720                        int rv = allocmem_free_remove(prog_ctrl, ptr);
721                        if(rv != 0) {
722                                panic("unexpected BSD program state: could not find pointer to free");
723                        }
724                } else {
725                        /* Outside of program context. Just free it. */
726                        free(ptr, M_TEMP);
727                }
728        }
729}
Note: See TracBrowser for help on using the repository browser.