OSDN Git Service

ba8fee35ae9710270d0f5de01502fb338ca91e09
[android-x86/external-efivar.git] / src / util.h
1 /*
2  * Copyright 2011-2014 Red Hat, Inc.
3  * All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2.1 of the
8  * License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * Author(s): Peter Jones <pjones@redhat.com>
20  */
21 #ifndef EFIVAR_UTIL_H
22 #define EFIVAR_UTIL_H 1
23
24 #include <alloca.h>
25 #include <endian.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <limits.h>
29 #include <sched.h>
30 #include <stdarg.h>
31 #include <stdbool.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/ioctl.h>
37 #include <sys/mount.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <tgmath.h>
41 #include <unistd.h>
42
43 #define UNUSED __attribute__((__unused__))
44 #define HIDDEN __attribute__((__visibility__ ("hidden")))
45 #define PUBLIC __attribute__((__visibility__ ("default")))
46 #define DESTRUCTOR __attribute__((destructor))
47 #define CONSTRUCTOR __attribute__((constructor))
48 #define ALIAS(x) __attribute__((weak, alias (#x)))
49 #define NONNULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
50 #define PRINTF(...) __attribute__((__format__(printf, __VA_ARGS__)))
51 #define FLATTEN __attribute__((__flatten__))
52 #define PACKED __attribute__((__packed__))
53 #define VERSION(sym, ver) __asm__(".symver " # sym "," # ver)
54
55 #define __branch_check__(x, expect, is_constant) \
56         __builtin_expect(!!(x), expect)
57 #ifndef likely
58 #define likely(x) (__branch_check__(x, 1, __builtin_constant_p(x)))
59 #endif
60 #ifndef unlikely
61 #define unlikely(x) (__branch_check__(x, 0, __builtin_constant_p(x)))
62 #endif
63
64 /*
65  * I'm not actually sure when these appear, but they're present in the
66  * version in front of me.
67  */
68 #if defined(__GNUC__) && defined(__GNUC_MINOR__)
69 #if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
70 #define int_add(a, b, c) __builtin_add_overflow(a, b, c)
71 #define long_add(a, b, c) __builtin_add_overflow(a, b, c)
72 #define long_mult(a, b, c) __builtin_mul_overflow(a, b, c)
73 #define ulong_add(a, b, c) __builtin_add_overflow(a, b, c)
74 #define ulong_mult(a, b, c) __builtin_mul_overflow(a, b, c)
75 #endif
76 #endif
77 #ifndef int_add
78 #define int_add(a, b, c) ({                                             \
79                 const int _limit = INT_MAX;                             \
80                 int _ret;                                               \
81                 _ret = _limit - ((unsigned long long)a) >               \
82                           ((unsigned long long)b);                      \
83                 if (!_ret)                                              \
84                         *(c) = ((a) + (b));                             \
85                 _ret;                                                   \
86         })
87 #endif
88 #ifndef long_add
89 #define long_add(a, b, c) ({                                            \
90                 const long _limit = LONG_MAX;                           \
91                 int _ret;                                               \
92                 _ret = _limit - ((unsigned long long)a) >               \
93                            ((unsigned long long)b);                     \
94                 if (!_ret)                                              \
95                         *(c) = ((a) + (b));                             \
96                 _ret;                                                   \
97         })
98 #endif
99 #ifndef long_mult
100 #define long_mult(a, b, c) ({                                           \
101                 const long _limit = LONG_MAX;                           \
102                 int _ret = 1;                                           \
103                 if ((a) == 0 || (b) == 0)                               \
104                         _ret = 0;                                       \
105                 else                                                    \
106                         _ret = _limit / (a) < (b);                      \
107                 if (!_ret)                                              \
108                         *(c) = ((a) * (b));                             \
109                 _ret;                                                   \
110         })
111 #endif
112 #ifndef ulong_add
113 #define ulong_add(a, b, c) ({                                           \
114                 const unsigned long _limit = ULONG_MAX;                 \
115                 int _ret;                                               \
116                 _ret = _limit - ((unsigned long long)a) >               \
117                             ((unsigned long long)b);                    \
118                 if (!_ret)                                              \
119                         *(c) = ((a) + (b));                             \
120                 _ret;                                                   \
121         })
122 #endif
123 #ifndef ulong_mult
124 #define ulong_mult(a, b, c) ({                                          \
125                 const unsigned long _limit = ULONG_MAX;                 \
126                 int _ret = 1;                                           \
127                 if ((a) == 0 || (b) == 0)                               \
128                         _ret = 0;                                       \
129                 else                                                    \
130                         _ret = _limit / (a) < (b);                      \
131                 if (!_ret)                                              \
132                         *(c) = ((a) * (b));                             \
133                 _ret;                                                   \
134         })
135 #endif
136
137 #if defined(__GNUC__) && defined(__GNUC_MINOR__)
138 #if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
139 #define add(a, b, c) _Generic((c),                                      \
140                               int *: int_add(a,b,c),                    \
141                               long *: long_add(a,b,c),                  \
142                               unsigned long *: ulong_add(a,b,c))
143 #define mult(a, b, c) _Generic((c),                                     \
144                               long *: long_mult(a,b,c),                 \
145                               unsigned long *: ulong_mult(a,b,c))
146 #endif
147 #endif
148
149 #ifndef add
150 #define add(a, b, c) ({                                                 \
151                 (*(c)) = ((a) + (b));                                   \
152                 })
153 #endif
154 #ifndef mult
155 #define mult(a, b, c) ({                                                \
156                 (*(c)) = ((a) * (b));                                   \
157                 })
158 #endif
159
160 static inline int UNUSED
161 read_file(int fd, uint8_t **result, size_t *bufsize)
162 {
163         uint8_t *p;
164         size_t size = 4096;
165         size_t filesize = 0;
166         ssize_t s = 0;
167         uint8_t *buf, *newbuf;
168
169         if (!(newbuf = calloc(size, sizeof (uint8_t)))) {
170                 efi_error("could not allocate memory");
171                 *result = buf = NULL;
172                 *bufsize = 0;
173                 return -1;
174         }
175         buf = newbuf;
176
177         do {
178                 p = buf + filesize;
179                 /* size - filesize shouldn't exceed SSIZE_MAX because we're
180                  * only allocating 4096 bytes at a time and we're checking that
181                  * before doing so. */
182                 s = read(fd, p, size - filesize);
183                 if (s < 0 && errno == EAGAIN) {
184                         /*
185                          * if we got EAGAIN, there's a good chance we've hit
186                          * the kernel rate limiter.  Doing more reads is just
187                          * going to make it worse, so instead, give it a rest.
188                          */
189                         sched_yield();
190                         continue;
191                 } else if (s < 0) {
192                         int saved_errno = errno;
193                         free(buf);
194                         *result = buf = NULL;
195                         *bufsize = 0;
196                         errno = saved_errno;
197                         efi_error("could not read from file");
198                         return -1;
199                 }
200                 filesize += s;
201                 /* only exit for empty reads */
202                 if (s == 0)
203                         break;
204                 if (filesize >= size) {
205                         /* See if we're going to overrun and return an error
206                          * instead. */
207                         if (size > (size_t)-1 - 4096) {
208                                 free(buf);
209                                 *result = buf = NULL;
210                                 *bufsize = 0;
211                                 errno = ENOMEM;
212                                 efi_error("could not read from file");
213                                 return -1;
214                         }
215                         newbuf = realloc(buf, size + 4096);
216                         if (newbuf == NULL) {
217                                 int saved_errno = errno;
218                                 free(buf);
219                                 *result = buf = NULL;
220                                 *bufsize = 0;
221                                 errno = saved_errno;
222                                 efi_error("could not allocate memory");
223                                 return -1;
224                         }
225                         buf = newbuf;
226                         memset(buf + size, '\0', 4096);
227                         size += 4096;
228                 }
229         } while (1);
230
231         newbuf = realloc(buf, filesize+1);
232         if (!newbuf) {
233                 free(buf);
234                 *result = buf = NULL;
235                 efi_error("could not allocate memory");
236                 return -1;
237         }
238         newbuf[filesize] = '\0';
239         *result = newbuf;
240         *bufsize = filesize+1;
241         return 0;
242 }
243
244 static inline uint64_t UNUSED
245 lcm(uint64_t x, uint64_t y)
246 {
247         uint64_t m = x, n = y, o;
248         while ((o = m % n)) {
249                 m = n;
250                 n = o;
251         }
252         return (x / n) * y;
253 }
254
255 #ifndef strndupa
256 #define strndupa(s, l)                                                  \
257        (__extension__ ({                                                \
258                 const char *__in = (s);                                 \
259                 size_t __len = strnlen (__in, (l));                     \
260                 char *__out = (char *) alloca (__len + 1);              \
261                 strncpy(__out, __in, __len);                            \
262                 __out[__len] = '\0';                                    \
263                 __out;                                                  \
264         }))
265 #endif
266
267 #define asprintfa(str, fmt, args...)                                    \
268         ({                                                              \
269                 char *_tmp = NULL;                                      \
270                 int _rc;                                                \
271                 *(str) = NULL;                                          \
272                 _rc = asprintf((str), (fmt), ## args);                  \
273                 if (_rc > 0) {                                          \
274                         _tmp = strdupa(*(str));                         \
275                         if (!_tmp) {                                    \
276                                 _rc = -1;                               \
277                         } else {                                        \
278                                 free(*(str));                           \
279                                 *(str) = _tmp;                          \
280                         }                                               \
281                 } else {                                                \
282                         _rc = -1;                                       \
283                 }                                                       \
284                 _rc;                                                    \
285         })
286
287 #define vasprintfa(str, fmt, ap)                                        \
288         ({                                                              \
289                 char *_tmp = NULL;                                      \
290                 int _rc;                                                \
291                 *(str) = NULL;                                          \
292                 _rc = vasprintf((str), (fmt), (ap));                    \
293                 if (_rc > 0) {                                          \
294                         _tmp = strdupa(*(str));                         \
295                         if (!_tmp) {                                    \
296                                 _rc = -1;                               \
297                         } else {                                        \
298                                 free(*(str));                           \
299                                 *(str) = _tmp;                          \
300                         }                                               \
301                 } else {                                                \
302                         _rc = -1;                                       \
303                 }                                                       \
304                 _rc;                                                    \
305         })
306
307 static inline ssize_t
308 get_file(uint8_t **result, const char * const fmt, ...)
309 {
310         char *path;
311         uint8_t *buf = NULL;
312         size_t bufsize = 0;
313         ssize_t rc;
314         va_list ap;
315         int error;
316         int fd;
317
318         if (result == NULL) {
319                 efi_error("invalid parameter 'result'");
320                 return -1;
321         }
322
323         va_start(ap, fmt);
324         rc = vasprintfa(&path, fmt, ap);
325         va_end(ap);
326         if (rc < 0) {
327                 efi_error("could not allocate memory");
328                 return -1;
329         }
330
331         fd = open(path, O_RDONLY);
332         if (fd < 0) {
333                 efi_error("could not open file \"%s\" for reading",
334                           path);
335                 return -1;
336         }
337
338         rc = read_file(fd, &buf, &bufsize);
339         error = errno;
340         close(fd);
341         errno = error;
342
343         if (rc < 0 || bufsize < 1) {
344                 /*
345                  * I don't think this can happen, but I can't convince
346                  * cov-scan
347                  */
348                 if (buf)
349                         free(buf);
350                 *result = NULL;
351                 efi_error("could not read file \"%s\"", path);
352                 return -1;
353         }
354
355         *result = buf;
356         return bufsize;
357 }
358
359 static inline void UNUSED
360 swizzle_guid_to_uuid(efi_guid_t *guid)
361 {
362         uint32_t *u32;
363         uint16_t *u16;
364
365         u32 = (uint32_t *)guid;
366         u32[0] = __builtin_bswap32(u32[0]);
367         u16 = (uint16_t *)&u32[1];
368         u16[0] = __builtin_bswap16(u16[0]);
369         u16[1] = __builtin_bswap16(u16[1]);
370 }
371
372 #define log_(file, line, func, level, fmt, args...)                     \
373         ({                                                              \
374                 if (efi_get_verbose() >= level) {                       \
375                         FILE *logfile_ = efi_get_logfile();             \
376                         int len_ = strlen(fmt);                         \
377                         fprintf(logfile_, "%s:%d %s(): ",               \
378                                 file, line, func);                      \
379                         fprintf(logfile_, fmt, ## args);                \
380                         if (!len_ || fmt[len_ - 1] != '\n')             \
381                                 fprintf(logfile_, "\n");                \
382                 }                                                       \
383         })
384
385 #define LOG_VERBOSE 0
386 #define LOG_DEBUG 1
387 #ifdef log
388 #undef log
389 #endif
390 #define log(level, fmt, args...) log_(__FILE__, __LINE__, __func__, level, fmt, ## args)
391 #define arrow(l,b,o,p,n,m) ({if(n==m){char c_=b[p+1]; b[o]='^'; b[p+o]='^';b[p+o+1]='\0';log(l,"%s",b);b[o]=' ';b[p+o]=' ';b[p+o+1]=c_;}})
392 #define debug(fmt, args...) log(LOG_DEBUG, fmt, ## args)
393
394 #endif /* EFIVAR_UTIL_H */