Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / tests / all-symbols-test.c
1 /*
2  * Test utility checking symbol versions in libcryptsetup.
3  *
4  * Copyright (C) 2021-2023 Red Hat, Inc. All rights reserved.
5  *
6  * This file is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This file is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <dlfcn.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #define UNUSED(expr) do { (void)(expr); } while (0)
28
29 static int _debug;
30 static const char *libfile = "libcryptsetup.so.12";
31
32 #define LOG_MAX_LEN 256
33
34 #define LOG_DEBUG  1
35 #define LOG_NORMAL 2
36 #define LOG_ERROR  3
37
38 __attribute__((format(printf, 2, 3)))
39 static void test_logf(int level, const char *format, ...)
40 {
41         va_list argp;
42         char target[LOG_MAX_LEN + 2];
43         int len;
44
45         va_start(argp, format);
46
47         len = vsnprintf(&target[0], LOG_MAX_LEN, format, argp);
48         if (len > 0 && len < LOG_MAX_LEN) {
49                 switch (level) {
50                 case LOG_DEBUG:
51                         if (!_debug)
52                                 break;
53                 /* fall through */
54                 case LOG_NORMAL:
55                         fprintf(stdout, "%s", target);
56                         break;
57                 case LOG_ERROR:
58                         fflush(stdout);
59                         strcat(target, "\n");
60                         fprintf(stderr, "%s", target);
61                 }
62         }
63
64         va_end(argp);
65 }
66
67 #define log_dbg(x...) test_logf(LOG_DEBUG, x)
68 #define log_std(x...) test_logf(LOG_NORMAL, x)
69 #define log_err(x...) test_logf(LOG_ERROR, x)
70
71 static int check_dlvsym(void *h, const char *symbol, const char *version)
72 {
73 #ifdef HAVE_DLVSYM
74         void *sym;
75         char *err;
76
77         log_dbg("Checking %s@%s...", symbol, version);
78         sym = dlvsym(h, symbol, version);
79         UNUSED(sym);
80         err = dlerror();
81
82         if (err) {
83                 log_err("%s.", err);
84                 return 1;
85         }
86
87         log_dbg("OK\n");
88 #endif
89         return 0;
90 }
91
92 static int check_dlsym(void *h, const char *symbol)
93 {
94         void *sym;
95         char *err;
96
97         log_dbg("Checking %s...", symbol);
98         sym = dlsym(h, symbol);
99         UNUSED(sym);
100         err = dlerror();
101
102         if (err) {
103                 log_err("%s", err);
104                 return 1;
105         }
106
107         log_dbg("OK\n");
108         return 0;
109 }
110
111 static int check_all_symbols(void *h)
112 {
113         unsigned scount = 0;
114
115 #define CHECK_SYMBOL(SYM, VER)                  \
116 do {                                            \
117         if (check_dlvsym(h, #SYM, #VER))        \
118                 return 1;                       \
119         if (check_dlsym(h, #SYM))               \
120                 return 1;                       \
121         scount++;                               \
122 } while (0);
123
124 #include "test-symbols-list.h"
125 #undef CHECK_SYMBOL
126
127         if (!scount) {
128                 log_err("test-symbols-list.h file is probably empty.");
129                 return 1;
130         }
131
132         log_std("Performed %u symbol checks in total.\n", scount);
133
134         return 0;
135 }
136
137 static void usage(const char *app)
138 {
139         log_std("usage:\n\t%s [-v|--verbose|--debug] [optional path to library so file]\n", app);
140
141         exit(EXIT_FAILURE);
142 }
143
144 int main(int argc, char **argv)
145 {
146         int i, r;
147         void *h;
148
149         for (i = 1; i < argc; i++) {
150                 if (*argv[i] != '-')
151                         libfile = argv[i];
152                 else if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i]) ||
153                          !strcmp("--debug", argv[i]))
154                         _debug = 1;
155                 else if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]))
156                         usage(argv[0]);
157         }
158
159         log_std("Checking dlopen(%s)...", libfile);
160
161         h = dlopen(libfile, RTLD_NOW);
162         if (!h) {
163                 log_err("dlopen(): %s.", dlerror());
164                 return EXIT_FAILURE;
165         }
166         dlerror();
167         log_std("OK\n");
168
169         r = check_all_symbols(h);
170
171         if (dlclose(h)) {
172                 log_err("Failed to dlclose %s: %s.", libfile, dlerror());
173                 return EXIT_FAILURE;
174         }
175
176         return r ? EXIT_FAILURE : EXIT_SUCCESS;
177 }