Fix UB: Make read_int() follow SEI CERT INT13-C and INT34-C.
[metastore.git] / src / utils.c
blob99a0f13d9300e3303a3243e23697c660295f16b4
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Main functions of the program.
5 * Copyright (C) 2007-2008 David Härdeman <david@hardeman.nu>
6 * Copyright (C) 2015-2018 Przemyslaw Pawelczyk <przemoc@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; only version 2 of the License is applicable.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #define _BSD_SOURCE
22 #define _DEFAULT_SOURCE
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdint.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <grp.h>
33 #include <pwd.h>
35 #include "utils.h"
37 /* Controls the verbosity level for msg() */
38 static int verbosity = 0;
40 /* Adjusts the verbosity level for msg() */
41 void
42 adjust_verbosity(int adj)
44 verbosity += adj;
48 * Prints messages to console according to the current verbosity
49 * - see utils.h for level defines
51 int
52 msg(int level, const char *fmt, ...)
54 int ret;
55 va_list ap;
57 if (level > verbosity)
58 return 0;
60 va_start(ap, fmt);
62 if (level < MSG_QUIET)
63 ret = vfprintf(stderr, fmt, ap);
64 else
65 ret = vfprintf(stdout, fmt, ap);
67 va_end(ap);
68 return ret;
71 /* Malloc which either succeeds or exits */
72 void *
73 xmalloc(size_t size)
75 void *result = malloc(size);
76 if (!result) {
77 msg(MSG_CRITICAL, "Failed to malloc %zu bytes\n", size);
78 exit(EXIT_FAILURE);
80 return result;
83 /* Ditto for strdup */
84 char *
85 xstrdup(const char *s)
87 char *result = strdup(s);
88 if (!result) {
89 msg(MSG_CRITICAL, "Failed to strdup %zu bytes\n", strlen(s));
90 exit(EXIT_FAILURE);
92 return result;
95 /* Human-readable printout of binary data */
96 void
97 binary_print(const char *s, ssize_t len)
99 ssize_t i;
101 for (i = 0; i < len; i++) {
102 if (isprint(s[i]))
103 msg(MSG_DEBUG, "%c", s[i]);
104 else
105 msg(MSG_DEBUG, "0x%02X", (int)s[i]);
109 /* Writes data to a file or exits on failure */
110 void
111 xfwrite(const void *ptr, size_t size, FILE *stream)
113 if (size && fwrite(ptr, size, 1, stream) != 1) {
114 msg(MSG_CRITICAL, "Failed to write to file: %s\n",
115 strerror(errno));
116 exit(EXIT_FAILURE);
120 /* Writes an int to a file, using len bytes, in little-endian order */
121 void
122 write_int(uint64_t value, size_t len, FILE *to)
124 char buf[sizeof(value)];
125 size_t i;
127 for (i = 0; i < len; i++)
128 buf[i] = ((value >> (8 * i)) & 0xff);
129 xfwrite(buf, len, to);
132 /* Writes a binary string to a file */
133 void
134 write_binary_string(const char *string, size_t len, FILE *to)
136 xfwrite(string, len, to);
139 /* Writes a normal C string to a file */
140 void
141 write_string(const char *string, FILE *to)
143 xfwrite(string, strlen(string) + 1, to);
146 /* Reads an int from a file, using len bytes, in little-endian order */
147 uint64_t
148 read_int(char **from, size_t len, const char *max)
150 uint64_t result = 0;
151 size_t i;
153 if (*from + len > max) {
154 msg(MSG_CRITICAL,
155 "Attempt to read beyond end of file, corrupt file?\n");
156 exit(EXIT_FAILURE);
159 for (i = 0; i < len; i++)
160 result += (((uint64_t)(*from)[i] & 0xff) << (8 * i));
161 *from += len;
162 return result;
165 /* Reads a binary string from a file */
166 char *
167 read_binary_string(char **from, size_t len, const char *max)
169 char *result;
171 if (*from + len > max) {
172 msg(MSG_CRITICAL,
173 "Attempt to read beyond end of file, corrupt file?\n");
174 exit(EXIT_FAILURE);
177 result = xmalloc(len);
178 memcpy(result, *from, len);
179 *from += len;
180 return result;
183 /* Reads a normal C string from a file */
184 char *
185 read_string(char **from, const char *max)
187 return read_binary_string(from, strlen(*from) + 1, max);
190 /* For group caching */
191 static struct group *gtable = NULL;
193 /* Initial setup of the gid table */
194 static void
195 create_group_table(void)
197 struct group *tmp;
198 int count, index;
200 for (count = 0; getgrent(); count++) /* Do nothing */;
202 gtable = xmalloc(sizeof(struct group) * (count + 1));
203 memset(gtable, 0, sizeof(struct group) * (count + 1));
204 setgrent();
206 for (index = 0; (tmp = getgrent()) && index < count; index++) {
207 gtable[index].gr_gid = tmp->gr_gid;
208 gtable[index].gr_name = xstrdup(tmp->gr_name);
211 endgrent();
214 /* Caching version of getgrnam */
215 struct group *
216 xgetgrnam(const char *name)
218 int i;
220 if (!gtable)
221 create_group_table();
223 for (i = 0; gtable[i].gr_name; i++) {
224 if (!strcmp(name, gtable[i].gr_name))
225 return &(gtable[i]);
228 return NULL;
231 /* Caching version of getgrgid */
232 struct group *
233 xgetgrgid(gid_t gid)
235 int i;
237 if (!gtable)
238 create_group_table();
240 for (i = 0; gtable[i].gr_name; i++) {
241 if (gtable[i].gr_gid == gid)
242 return &(gtable[i]);
245 return NULL;
248 /* For user caching */
249 static struct passwd *ptable = NULL;
251 /* Initial setup of the passwd table */
252 static void
253 create_passwd_table(void)
255 struct passwd *tmp;
256 int count, index;
258 for (count = 0; getpwent(); count++) /* Do nothing */;
260 ptable = xmalloc(sizeof(struct passwd) * (count + 1));
261 memset(ptable, 0, sizeof(struct passwd) * (count + 1));
262 setpwent();
264 for (index = 0; (tmp = getpwent()) && index < count; index++) {
265 ptable[index].pw_uid = tmp->pw_uid;
266 ptable[index].pw_name = xstrdup(tmp->pw_name);
269 endpwent();
272 /* Caching version of getpwnam */
273 struct passwd *
274 xgetpwnam(const char *name)
276 int i;
278 if (!ptable)
279 create_passwd_table();
281 for (i = 0; ptable[i].pw_name; i++) {
282 if (!strcmp(name, ptable[i].pw_name))
283 return &(ptable[i]);
286 return NULL;
289 /* Caching version of getpwuid */
290 struct passwd *
291 xgetpwuid(uid_t uid)
293 int i;
295 if (!ptable)
296 create_passwd_table();
298 for (i = 0; ptable[i].pw_name; i++) {
299 if (ptable[i].pw_uid == uid)
300 return &(ptable[i]);
303 return NULL;