source: rtems-libbsd/rtemsbsd/rtems/rtems-program.c @ eae664e

55-freebsd-126-freebsd-12
Last change on this file since eae664e was 632e278, checked in by Christian Mauderer <Christian.Mauderer@…>, on 10/21/16 at 09:05:29

rtemsbsd: Add reallocf to rtems_bsd_program.

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2013, 2016 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 <sys/types.h>
41
42#include <assert.h>
43#include <errno.h>
44#include <fcntl.h>
45#include <stdarg.h>
46#include <stdlib.h>
47#include <string.h>
48#include <syslog.h>
49#include <unistd.h>
50
51#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
52#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
53#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
54#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
55#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
56#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
57#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
58#define RTEMS_BSD_PROGRAM_NO_STRDUP_WRAP
59#define RTEMS_BSD_PROGRAM_NO_VASPRINTF_WRAP
60#define RTEMS_BSD_PROGRAM_NO_ASPRINTF_WRAP
61#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
62#include <machine/rtems-bsd-program.h>
63
64#include "program-internal.h"
65
66static int
67fd_remove(struct rtems_bsd_program_control *prog_ctrl, int fd)
68{
69        struct program_fd_item *current;
70        int rv = -1;
71
72        for (current = prog_ctrl->open_fd.lh_first;
73            current != NULL;
74            current = current->entries.le_next) {
75                if (current->fd == fd) {
76                        LIST_REMOVE(current, entries);
77                        free(current);
78                        rv = 0;
79                        break;
80                }
81        }
82
83        return rv;
84}
85
86static int
87fd_close_remove(struct rtems_bsd_program_control *prog_ctrl, int fd)
88{
89        int rv = -1;
90
91        rv = fd_remove(prog_ctrl, fd);
92        if (rv == 0) {
93                rv = close(fd);
94        }
95
96        return rv;
97}
98
99static void
100fd_close_all(struct rtems_bsd_program_control *prog_ctrl)
101{
102        while(prog_ctrl->open_fd.lh_first != NULL) {
103                struct program_fd_item *current;
104                int fd;
105                int rv;
106
107                current = prog_ctrl->open_fd.lh_first;
108                fd = current->fd;
109
110                rv = fd_close_remove(prog_ctrl, fd);
111                if (rv != 0) {
112                        syslog(LOG_ERR,
113                            "BSD Program: Could not close file %d or could not remove it from list of open files",
114                            fd);
115                }
116        }
117}
118
119static int
120file_remove(struct rtems_bsd_program_control *prog_ctrl, FILE *file)
121{
122        struct program_file_item *current;
123        int rv = EOF;
124
125        for (current = prog_ctrl->open_file.lh_first;
126            current != NULL;
127            current = current->entries.le_next) {
128                if (current->file == file) {
129                        LIST_REMOVE(current, entries);
130                        free(current);
131                        rv = 0;
132                        break;
133                }
134        }
135
136        return rv;
137}
138
139static int
140file_close_remove(struct rtems_bsd_program_control *prog_ctrl, FILE *file)
141{
142        int rv = EOF;
143
144        rv = file_remove(prog_ctrl, file);
145        if (rv == 0) {
146                rv = fclose(file);
147        }
148
149        return rv;
150}
151
152static void
153file_close_all(struct rtems_bsd_program_control *prog_ctrl)
154{
155        while(prog_ctrl->open_file.lh_first != NULL) {
156                struct program_file_item *current;
157                FILE *file;
158                int rv;
159
160                current = prog_ctrl->open_file.lh_first;
161                file = current->file;
162
163                rv = file_close_remove(prog_ctrl, file);
164                if (rv != 0) {
165                        syslog(LOG_ERR,
166                            "BSD Program: Could not close stream %p or could not remove it from list of open streams",
167                            file);
168                }
169        }
170}
171
172static int
173allocmem_remove(struct rtems_bsd_program_control *prog_ctrl, void *ptr)
174{
175        struct program_allocmem_item *current;
176        int rv = -1;
177
178        for (current = prog_ctrl->allocated_mem.lh_first;
179            current != NULL;
180            current = current->entries.le_next) {
181                if (current->ptr == ptr) {
182                        LIST_REMOVE(current, entries);
183                        rv = 0;
184                        break;
185                }
186        }
187
188        return rv;
189}
190
191static int
192allocmem_free_remove(struct rtems_bsd_program_control *prog_ctrl, void *ptr)
193{
194        int rv = -1;
195
196        rv = allocmem_remove(prog_ctrl, ptr);
197        if (rv == 0) {
198                free(ptr);
199        }
200
201        return rv;
202}
203
204static void
205allocmem_free_all(struct rtems_bsd_program_control *prog_ctrl)
206{
207        while(prog_ctrl->allocated_mem.lh_first != NULL) {
208                struct program_allocmem_item *current;
209                void *ptr;
210                int rv;
211
212                current = prog_ctrl->allocated_mem.lh_first;
213                ptr = current->ptr;
214
215                rv = allocmem_free_remove(prog_ctrl, ptr);
216                if (rv != 0) {
217                        /* This should never happen. It would mean that someone
218                         * changed the allocmem list while we are removing the
219                         * element. */
220                        syslog(LOG_ERR,
221                            "BSD Program: Could not remove %p from list of allocated memory",
222                            ptr);
223                }
224        }
225}
226
227int
228rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context)
229{
230        struct rtems_bsd_program_control *prog_ctrl;
231        int error;
232        int exit_code;
233
234        prog_ctrl = calloc(1, sizeof(*prog_ctrl));
235        if (prog_ctrl == NULL) {
236                errno = ENOMEM;
237                return (EXIT_FAILURE);
238        }
239
240        error = rtems_bsd_program_set_control(prog_ctrl);
241        if (error != 0) {
242                free(prog_ctrl);
243                errno = error;
244                return (EXIT_FAILURE);
245        }
246
247        prog_ctrl->context = context;
248        prog_ctrl->name = name;
249        prog_ctrl->exit_code = EXIT_FAILURE;
250
251        LIST_INIT(&prog_ctrl->open_fd);
252        LIST_INIT(&prog_ctrl->open_file);
253        LIST_INIT(&prog_ctrl->allocated_mem);
254
255        if (setjmp(prog_ctrl->return_context) == 0) {
256                exit_code = (*prog)(context);
257        } else {
258                exit_code = prog_ctrl->exit_code;
259        }
260
261        rtems_bsd_program_set_control(NULL);
262        fd_close_all(prog_ctrl);
263        file_close_all(prog_ctrl);
264        allocmem_free_all(prog_ctrl);
265        free(prog_ctrl);
266        return (exit_code);
267}
268
269void
270rtems_bsd_program_exit(int exit_code)
271{
272        struct rtems_bsd_program_control *prog_ctrl =
273            rtems_bsd_program_get_control_or_null();
274
275        if (prog_ctrl != NULL) {
276                prog_ctrl->exit_code = exit_code;
277                longjmp(prog_ctrl->return_context, 1);
278        }
279
280        assert(0);
281}
282
283void
284rtems_bsd_program_error(const char *fmt, ...)
285{
286        va_list list;
287        va_start(list, fmt);
288        vfprintf(stderr, fmt, list);
289        fprintf(stderr, "\n");
290        va_end(list);
291        rtems_bsd_program_exit(1);
292}
293
294const char *
295rtems_bsd_program_get_name(void)
296{
297        struct rtems_bsd_program_control *prog_ctrl =
298            rtems_bsd_program_get_control_or_null();
299        const char *name = "?";
300
301        if (prog_ctrl != NULL) {
302                name = prog_ctrl->name;
303        }
304
305        return name;
306}
307
308void *
309rtems_bsd_program_get_context(void)
310{
311        struct rtems_bsd_program_control *prog_ctrl =
312            rtems_bsd_program_get_control_or_null();
313        void *context = NULL;
314
315        if (prog_ctrl != NULL) {
316                context = prog_ctrl->context;
317        }
318
319        return context;
320}
321
322struct main_context {
323        int argc;
324        char **argv;
325        int (*main)(int, char **);
326};
327
328static int
329call_main(void *ctx)
330{
331        const struct main_context *mc = ctx;
332
333        return (*mc->main)(mc->argc, mc->argv);
334}
335
336int
337rtems_bsd_program_call_main(const char *name, int (*main)(int, char **),
338    int argc, char **argv)
339{
340        struct main_context mc = {
341                .argc = argc,
342                .argv = argv,
343                .main = main
344        };
345        int exit_code;
346
347        if (argv[argc] == NULL) {
348                exit_code = rtems_bsd_program_call(name, call_main, &mc);
349        } else {
350                errno = EFAULT;
351                exit_code = EXIT_FAILURE;
352        }
353
354        return exit_code;
355}
356
357int
358rtems_bsd_program_call_main_with_data_restore(const char *name,
359    int (*main)(int, char **), int argc, char **argv,
360    void *data_buf, const size_t data_size)
361{
362        int exit_code = EXIT_FAILURE;
363        void *savebuf;
364
365        savebuf = malloc(data_size);
366        if (savebuf == NULL) {
367                errno = ENOMEM;
368                exit_code = EXIT_FAILURE;
369        } else {
370                memcpy(savebuf, data_buf, data_size);
371                exit_code = rtems_bsd_program_call_main(name, main, argc,
372                    argv);
373                memcpy(data_buf, savebuf, data_size);
374                free(savebuf);
375        }
376
377        return exit_code;
378}
379
380int
381rtems_bsd_program_open(const char *path, int oflag, ...)
382{
383        struct rtems_bsd_program_control *prog_ctrl =
384            rtems_bsd_program_get_control_or_null();
385        va_list list;
386        mode_t mode = 0;
387        int fd = -1;
388
389        if (prog_ctrl != NULL) {
390                struct program_fd_item *item =
391                    malloc(sizeof(*item));
392
393                if (item != NULL) {
394                        va_start(list, oflag);
395                        mode = va_arg(list, mode_t);
396
397                        fd = open(path, oflag, mode);
398
399                        va_end(list);
400
401                        if (fd != -1) {
402                                item->fd = fd;
403                                LIST_INSERT_HEAD(&(prog_ctrl->open_fd),
404                                    item, entries);
405                        } else {
406                                free(item);
407                        }
408                } else {
409                        errno = ENOMEM;
410                }
411        }
412
413        return fd;
414}
415
416int
417rtems_bsd_program_close(int fd)
418{
419        struct rtems_bsd_program_control *prog_ctrl =
420            rtems_bsd_program_get_control_or_null();
421        int rv = -1;
422
423        if (prog_ctrl != NULL) {
424                rv = fd_close_remove(prog_ctrl, fd);
425        }
426
427        return rv;
428}
429
430FILE *
431rtems_bsd_program_fopen(const char *restrict filename,
432    const char *restrict mode)
433{
434        FILE *file = NULL;
435        struct rtems_bsd_program_control *prog_ctrl =
436            rtems_bsd_program_get_control_or_null();
437
438        if (prog_ctrl != NULL) {
439                struct program_file_item *item = malloc(sizeof(*item));
440
441                if (item != NULL) {
442                        file = fopen(filename, mode);
443
444                        if (file != NULL) {
445                                item->file = file;
446                                LIST_INSERT_HEAD(
447                                    &(prog_ctrl->open_file), item,
448                                    entries);
449                        } else {
450                                free(item);
451                        }
452                } else {
453                        errno = ENOMEM;
454                }
455        }
456
457        return file;
458}
459
460int
461rtems_bsd_program_fclose(FILE *file)
462{
463        struct rtems_bsd_program_control *prog_ctrl =
464            rtems_bsd_program_get_control_or_null();
465        int rv = EOF;
466
467        if (prog_ctrl != NULL) {
468                rv = file_close_remove(prog_ctrl, file);
469        }
470
471        return rv;
472}
473
474static void *
475rtems_bsd_program_alloc(size_t size, void *org_ptr)
476{
477        struct rtems_bsd_program_control *prog_ctrl =
478            rtems_bsd_program_get_control_or_null();
479        void *ptr = NULL;
480        size_t size_with_list;
481        size_t size_alligned;
482
483        if (prog_ctrl != NULL) {
484                /* align the end to the next word address */
485                size_alligned = size;
486                if ((size_alligned & 0x3) != 0) {
487                        size_alligned = (size_alligned | 0x03) + 1;
488                }
489                size_with_list = size_alligned +
490                    sizeof(struct program_allocmem_item);
491
492                if (org_ptr != NULL) {
493                        /* It's a reallocation. So first remove the old pointer
494                         * from the list */
495                        allocmem_remove(prog_ctrl, org_ptr);
496                }
497
498                ptr = realloc(org_ptr, size_with_list);
499
500                if (ptr != NULL) {
501                        struct program_allocmem_item *item;
502                        item = ptr + size_alligned;
503                        item->ptr = ptr;
504                        LIST_INSERT_HEAD(&(prog_ctrl->allocated_mem),
505                            item, entries);
506                }
507        }
508
509        return ptr;
510}
511
512void *
513rtems_bsd_program_malloc(size_t size)
514{
515        return rtems_bsd_program_alloc(size, NULL);
516}
517
518void *
519rtems_bsd_program_calloc(size_t nelem, size_t elsize)
520{
521        void *ptr;
522        size_t size = elsize * nelem;
523
524        ptr = rtems_bsd_program_alloc(size, NULL);
525        if (ptr != NULL) {
526                memset(ptr, 0, size);
527        }
528
529        return ptr;
530}
531
532void *
533rtems_bsd_program_realloc(void *ptr, size_t size)
534{
535        return rtems_bsd_program_alloc(size, ptr);
536}
537
538void *
539rtems_bsd_program_reallocf(void *ptr, size_t size)
540{
541        void *ret = rtems_bsd_program_alloc(size, ptr);
542        if (ret == NULL) {
543                free(ptr);
544        }
545        return ret;
546}
547
548char *
549rtems_bsd_program_strdup(const char *s1)
550{
551        size_t size = strlen(s1) + 1; /* add one for null termination */
552        char *item;
553
554        item = rtems_bsd_program_alloc(size, NULL);
555
556        if (item != NULL) {
557                memcpy(item, s1, size);
558        }
559
560        return item;
561}
562
563int
564rtems_bsd_program_vasprintf(char **strp, const char *fmt, va_list ap)
565{
566        va_list aq;
567        int size;
568        int rv = -1;
569
570        va_copy(aq, ap);
571        size = vsnprintf(NULL, 0, fmt, aq);
572        va_end(aq);
573
574        size += 1; /* Add space for terminating null byte */
575        *strp = rtems_bsd_program_alloc(size, NULL);
576
577        if (*strp != NULL) {
578                rv = vsnprintf(*strp, size, fmt, ap);
579        }
580
581        return rv;
582}
583
584int
585rtems_bsd_program_asprintf(char **strp, const char *fmt, ...)
586{
587        va_list ap;
588        int rv;
589
590        va_start(ap, fmt);
591
592        rv = rtems_bsd_program_vasprintf(strp, fmt, ap);
593
594        va_end(ap);
595
596        return rv;
597}
598
599void
600rtems_bsd_program_free(void *ptr)
601{
602        if (ptr != NULL) {
603                struct rtems_bsd_program_control *prog_ctrl =
604                    rtems_bsd_program_get_control_or_null();
605
606                if (prog_ctrl != NULL) {
607                        int rv = allocmem_free_remove(prog_ctrl, ptr);
608                        assert(rv == 0);
609                } else {
610                        /* Outside of program context. Just free it. */
611                        free(ptr);
612                }
613        }
614}
Note: See TracBrowser for help on using the repository browser.