1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Utility functions for the 'fsverity' program
4 *
5 * Copyright (C) 2018 Google LLC
6 *
7 * Written by Eric Biggers.
8 */
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <limits.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19
20 #include "util.h"
21
22 /* ========== Memory allocation ========== */
23
xmalloc(size_t size)24 void *xmalloc(size_t size)
25 {
26 void *p = malloc(size);
27
28 if (!p)
29 fatal_error("out of memory");
30 return p;
31 }
32
xzalloc(size_t size)33 void *xzalloc(size_t size)
34 {
35 return memset(xmalloc(size), 0, size);
36 }
37
xmemdup(const void * mem,size_t size)38 void *xmemdup(const void *mem, size_t size)
39 {
40 return memcpy(xmalloc(size), mem, size);
41 }
42
xstrdup(const char * s)43 char *xstrdup(const char *s)
44 {
45 return xmemdup(s, strlen(s) + 1);
46 }
47
48 /* ========== Error messages and assertions ========== */
49
do_error_msg(const char * format,va_list va,int err)50 void do_error_msg(const char *format, va_list va, int err)
51 {
52 fputs("ERROR: ", stderr);
53 vfprintf(stderr, format, va);
54 if (err)
55 fprintf(stderr, ": %s", strerror(err));
56 putc('\n', stderr);
57 }
58
error_msg(const char * format,...)59 void error_msg(const char *format, ...)
60 {
61 va_list va;
62
63 va_start(va, format);
64 do_error_msg(format, va, 0);
65 va_end(va);
66 }
67
error_msg_errno(const char * format,...)68 void error_msg_errno(const char *format, ...)
69 {
70 va_list va;
71
72 va_start(va, format);
73 do_error_msg(format, va, errno);
74 va_end(va);
75 }
76
fatal_error(const char * format,...)77 __noreturn void fatal_error(const char *format, ...)
78 {
79 va_list va;
80
81 va_start(va, format);
82 do_error_msg(format, va, 0);
83 va_end(va);
84 abort();
85 }
86
assertion_failed(const char * expr,const char * file,int line)87 __noreturn void assertion_failed(const char *expr, const char *file, int line)
88 {
89 fatal_error("Assertion failed: %s at %s:%d", expr, file, line);
90 }
91
92 /* ========== File utilities ========== */
93
open_file(struct filedes * file,const char * filename,int flags,int mode)94 bool open_file(struct filedes *file, const char *filename, int flags, int mode)
95 {
96 file->fd = open(filename, flags, mode);
97 if (file->fd < 0) {
98 error_msg_errno("can't open '%s' for %s", filename,
99 (flags & O_ACCMODE) == O_RDONLY ? "reading" :
100 (flags & O_ACCMODE) == O_WRONLY ? "writing" :
101 "reading and writing");
102 return false;
103 }
104 file->name = xstrdup(filename);
105 return true;
106 }
107
get_file_size(struct filedes * file,u64 * size_ret)108 bool get_file_size(struct filedes *file, u64 *size_ret)
109 {
110 struct stat stbuf;
111
112 if (fstat(file->fd, &stbuf) != 0) {
113 error_msg_errno("can't stat file '%s'", file->name);
114 return false;
115 }
116 *size_ret = stbuf.st_size;
117 return true;
118 }
119
full_read(struct filedes * file,void * buf,size_t count)120 bool full_read(struct filedes *file, void *buf, size_t count)
121 {
122 while (count) {
123 int n = read(file->fd, buf, min(count, INT_MAX));
124
125 if (n < 0) {
126 error_msg_errno("reading from '%s'", file->name);
127 return false;
128 }
129 if (n == 0) {
130 error_msg("unexpected end-of-file on '%s'", file->name);
131 return false;
132 }
133 buf += n;
134 count -= n;
135 }
136 return true;
137 }
138
full_write(struct filedes * file,const void * buf,size_t count)139 bool full_write(struct filedes *file, const void *buf, size_t count)
140 {
141 while (count) {
142 int n = write(file->fd, buf, min(count, INT_MAX));
143
144 if (n < 0) {
145 error_msg_errno("writing to '%s'", file->name);
146 return false;
147 }
148 buf += n;
149 count -= n;
150 }
151 return true;
152 }
153
filedes_close(struct filedes * file)154 bool filedes_close(struct filedes *file)
155 {
156 int res;
157
158 if (file->fd < 0)
159 return true;
160 res = close(file->fd);
161 if (res != 0)
162 error_msg_errno("closing '%s'", file->name);
163 file->fd = -1;
164 free(file->name);
165 file->name = NULL;
166 return res == 0;
167 }
168
169 /* ========== String utilities ========== */
170
hex2bin_char(char c)171 static int hex2bin_char(char c)
172 {
173 if (c >= '0' && c <= '9')
174 return c - '0';
175 if (c >= 'a' && c <= 'f')
176 return 10 + (c - 'a');
177 if (c >= 'A' && c <= 'F')
178 return 10 + (c - 'A');
179 return -1;
180 }
181
hex2bin(const char * hex,u8 * bin,size_t bin_len)182 bool hex2bin(const char *hex, u8 *bin, size_t bin_len)
183 {
184 if (strlen(hex) != 2 * bin_len)
185 return false;
186
187 while (bin_len--) {
188 int hi = hex2bin_char(*hex++);
189 int lo = hex2bin_char(*hex++);
190
191 if (hi < 0 || lo < 0)
192 return false;
193 *bin++ = (hi << 4) | lo;
194 }
195 return true;
196 }
197
bin2hex_char(u8 nibble)198 static char bin2hex_char(u8 nibble)
199 {
200 ASSERT(nibble <= 0xf);
201
202 if (nibble < 10)
203 return '0' + nibble;
204 return 'a' + (nibble - 10);
205 }
206
bin2hex(const u8 * bin,size_t bin_len,char * hex)207 void bin2hex(const u8 *bin, size_t bin_len, char *hex)
208 {
209 while (bin_len--) {
210 *hex++ = bin2hex_char(*bin >> 4);
211 *hex++ = bin2hex_char(*bin & 0xf);
212 bin++;
213 }
214 *hex = '\0';
215 }
216