1 /* SPDX-License-Identifier: GPL-3.0-only */
7 int atoi64(const char *str, int64_t *value)
12 errno = 0; /* To distinguish success/failure after call */
13 tmp = strtoll(str, &endptr, 10);
14 if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN))
15 return -E_ATOI_OVERFLOW;
17 * If there were no digits at all, strtoll() stores the original value
21 return -E_ATOI_NO_DIGITS;
23 * The implementation may also set errno and return 0 in case no
24 * conversion was performed.
26 if (errno != 0 && tmp == 0)
27 return -E_ATOI_NO_DIGITS;
28 if (*endptr != '\0') /* Further characters after number */
29 return -E_ATOI_JUNK_AT_END;
34 __attribute__ ((warn_unused_result))
35 void *xrealloc(void *p, size_t size)
38 * No need to check for NULL pointers: If p is NULL, the call
39 * to realloc is equivalent to malloc(size)
42 if (!(p = realloc(p, size))) {
43 EMERG_LOG("realloc failed (size = %zu), aborting\n", size);
49 __attribute__ ((warn_unused_result))
50 void *xmalloc(size_t size)
52 return xrealloc(NULL, size);
55 __attribute__ ((warn_unused_result))
56 void *xcalloc(size_t size)
58 void *p = xmalloc(size);
63 __attribute__ ((warn_unused_result))
64 char *xstrdup(const char *str)
66 char *p = strdup(str);
70 EMERG_LOG("strdup failed, aborting\n");
75 * Get the home directory of the current user. Returns a dynamically allocated
76 * string that must be freed by the caller.
78 __attribute__ ((warn_unused_result))
79 char *get_homedir(void)
81 struct passwd *pw = getpwuid(getuid());
84 EMERG_LOG("could not get home directory: %s\n",
88 return xstrdup(pw->pw_dir);
92 * Print a formated message to a dynamically allocated string.
94 * This function is similar to vasprintf(), a GNU extension which is not in C
95 * or POSIX. It allocates a string large enough to hold the output including
96 * the terminating null byte. The allocated string is returned via the first
97 * argument and must be freed by the caller. However, unlike vasprintf(), this
98 * function calls exit() if insufficient memory is available, while vasprintf()
99 * returns -1 in this case.
101 * It returns the number of bytes written, not including the terminating \p
104 __attribute__ ((format (printf, 2, 0)))
105 unsigned xvasprintf(char **result, const char *fmt, va_list ap)
111 *result = xmalloc(size + 1);
113 ret = vsnprintf(*result, size, fmt, aq);
116 if ((size_t)ret < size)
119 *result = xrealloc(*result, size);
121 ret = vsnprintf(*result, size, fmt, aq);
123 assert(ret >= 0 && (size_t)ret < size);
127 __attribute__ ((format (printf, 2, 3)))
128 /* Print to a dynamically allocated string, variable number of arguments. */
129 unsigned xasprintf(char **result, const char *fmt, ...)
135 ret = xvasprintf(result, fmt, ap);
141 * Compile a regular expression.
143 * This simple wrapper calls regcomp(3) and logs a message on errors.
145 int xregcomp(regex_t *preg, const char *regex, int cflags)
149 int ret = regcomp(preg, regex, cflags);
153 size = regerror(ret, preg, NULL, 0);
155 regerror(ret, preg, buf, size);
156 ERROR_LOG("%s\n", buf);
161 /* Write input from fd to dynamically allocated buffer. */
162 int fd2buf(int fd, struct iovec *result)
164 const size_t max_size = 32 * 1024;
169 iov.iov_len = 100; /* guess that's sufficient */
170 iov.iov_base = xmalloc(iov.iov_len);
172 ret = read(fd, iov.iov_base + loaded, iov.iov_len - loaded);
174 ret = -ERRNO_TO_TF_ERROR(errno);
178 if (loaded >= iov.iov_len) {
180 ret = -ERRNO_TO_TF_ERROR(EOVERFLOW);
181 if (iov.iov_len >= max_size)
183 iov.iov_base = xrealloc(iov.iov_base, iov.iov_len);
188 result->iov_base = NULL;
192 iov.iov_len = loaded;
193 iov.iov_base = xrealloc(iov.iov_base, loaded + 1);
194 *((char *)iov.iov_base + loaded) = '\0';
199 __attribute__ ((format (printf, 2, 3)))
200 void tf_log(int ll, const char* fmt,...)
203 if (ll < loglevel_arg_val)
206 vfprintf(stderr, fmt, argp);
210 struct regfile_iter {
213 struct dirent *entry;
217 void regfile_iter_next(struct regfile_iter *iter)
220 iter->entry = readdir(iter->dir);
223 if (!strcmp(iter->entry->d_name, "."))
225 if (!strcmp(iter->entry->d_name, ".."))
227 if (fstatat(iter->dfd, iter->entry->d_name, &iter->stat, 0) == -1)
229 if (!S_ISREG(iter->stat.st_mode))
231 if (iter->stat.st_size == 0) /* skip over empty files */
237 void regfile_iter_new(const char *dirname, struct regfile_iter **result)
239 struct regfile_iter *iter = xmalloc(sizeof(*iter));
241 iter->dir = opendir(dirname);
243 EMERG_LOG("opendir %s: %s\n", dirname, strerror(errno));
246 iter->dfd = dirfd(iter->dir);
247 assert(iter->dfd >= 0);
248 regfile_iter_next(iter);
252 static void *xmmap(size_t sz, int fd, const char *path)
254 void *result = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fd, 0);
256 if (result == MAP_FAILED) {
257 EMERG_LOG("mmap %s: %s\n", path, strerror(errno));
263 void mmap_file(const char *path, struct iovec *iov)
269 EMERG_LOG("could not open %s: %s\n", path, strerror(errno));
273 iov->iov_len = lseek(fd, 0, SEEK_END);
274 if (iov->iov_len == (size_t)(off_t)-1) {
275 EMERG_LOG("lseek %s: %s\n", path, strerror(errno));
278 iov->iov_base = xmmap(iov->iov_len, fd, path);
282 bool regfile_iter_map(const struct regfile_iter *iter, struct iovec *result)
290 path = iter->entry->d_name;
291 ret = openat(iter->dfd, path, O_RDONLY, 0);
293 EMERG_LOG("could not open %s: %s\n", path, strerror(errno));
297 map = xmmap(iter->stat.st_size, fd, path);
299 result->iov_len = iter->stat.st_size;
300 result->iov_base = map;
304 const char *regfile_iter_basename(const struct regfile_iter *iter)
308 return iter->entry->d_name;
311 const struct stat *regfile_iter_stat(const struct regfile_iter *iter)
316 void regfile_iter_free(struct regfile_iter *iter)