Whamcloud - gitweb
tst_libext2fs: Avoid multiple definition of global variables
[tools/e2fsprogs.git] / lib / ext2fs / atexit.c
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
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  */
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. */
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 }