1 /*
2 * atexit.c --- Clean things up when we exit normally.
3 *
4 * Copyright Oracle, 2014
5 * Author Darrick J. Wong <darrick.wong@oracle.com>
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Library
9 * General Public License, version 2.
10 * %End-Header%
11 */
12
13 #ifndef _LARGEFILE_SOURCE
14 #define _LARGEFILE_SOURCE
15 #endif
16 #ifndef _LARGEFILE64_SOURCE
17 #define _LARGEFILE64_SOURCE
18 #endif
19
20 #include "config.h"
21 #include <stdlib.h>
22
23 #include "ext2_fs.h"
24 #include "ext2fs.h"
25 #include "ext2fsP.h"
26
27 struct exit_data {
28 ext2_exit_fn func;
29 void *data;
30 };
31
32 static struct exit_data *items;
33 static size_t nr_items;
34
handle_exit(void)35 static void handle_exit(void)
36 {
37 struct exit_data *ed;
38
39 for (ed = items + nr_items - 1; ed >= items; ed--) {
40 if (ed->func == NULL)
41 continue;
42 ed->func(ed->data);
43 }
44
45 ext2fs_free_mem(&items);
46 nr_items = 0;
47 }
48
49 /*
50 * Schedule a function to be called at (normal) program termination.
51 * If you want this to be called during a signal exit, you must capture
52 * the signal and call exit() yourself!
53 */
ext2fs_add_exit_fn(ext2_exit_fn func,void * data)54 errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data)
55 {
56 struct exit_data *ed, *free_ed = NULL;
57 size_t x;
58 errcode_t ret;
59
60 if (func == NULL)
61 return EXT2_ET_INVALID_ARGUMENT;
62
63 for (x = 0, ed = items; x < nr_items; x++, ed++) {
64 if (ed->func == func && ed->data == data)
65 return EXT2_ET_FILE_EXISTS;
66 if (ed->func == NULL)
67 free_ed = ed;
68 }
69
70 if (free_ed) {
71 free_ed->func = func;
72 free_ed->data = data;
73 return 0;
74 }
75
76 if (nr_items == 0) {
77 ret = atexit(handle_exit);
78 if (ret)
79 return ret;
80 }
81
82 ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data),
83 &items);
84 if (ret)
85 return ret;
86
87 items[nr_items].func = func;
88 items[nr_items].data = data;
89 nr_items++;
90
91 return 0;
92 }
93
94 /* Remove a function from the exit cleanup list. */
ext2fs_remove_exit_fn(ext2_exit_fn func,void * data)95 errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data)
96 {
97 struct exit_data *ed;
98 size_t x;
99
100 if (func == NULL)
101 return EXT2_ET_INVALID_ARGUMENT;
102
103 for (x = 0, ed = items; x < nr_items; x++, ed++) {
104 if (ed->func == NULL)
105 return 0;
106 if (ed->func == func && ed->data == data) {
107 size_t sz = (nr_items - (x + 1)) *
108 sizeof(struct exit_data);
109 memmove(ed, ed + 1, sz);
110 memset(items + nr_items - 1, 0,
111 sizeof(struct exit_data));
112 }
113 }
114
115 return 0;
116 }
117