1 /*
2  * Copyright 2014-2017 Frank Hunleth
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef UTIL_H
18 #define UTIL_H
19 
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <sys/types.h>
24 #include "config.h"
25 
26 // Global options
27 extern bool fwup_verbose;
28 extern bool fwup_framing;
29 extern bool fwup_unsafe;
30 extern bool fwup_handshake_on_exit;
31 
32 struct tm;
33 
34 int timestamp_to_tm(const char *timestamp, struct tm *tmp);
35 void time_t_to_string(time_t t, char *str, size_t len);
36 const char *get_creation_timestamp();
37 time_t get_creation_time_t();
38 
39 void set_last_error(const char *fmt, ...);
40 const char *last_error();
41 
42 int hex_to_bytes(const char *str, uint8_t *bytes, size_t numbytes);
43 int bytes_to_hex(const uint8_t *bytes, char *str, size_t byte_count);
44 
45 int archive_filename_to_resource(const char *name, char *result, size_t maxlength);
46 
47 bool will_be_regular_file(const char *path);
48 bool file_exists(const char *path);
49 bool is_regular_file(const char *path);
50 
51 #define NUM_ELEMENTS(X) (sizeof(X) / sizeof(X[0]))
52 
53 #define ERR_CLEANUP() do { rc = -1; goto cleanup; } while (0)
54 #define ERR_CLEANUP_MSG(MSG, ...) do { set_last_error(MSG, ## __VA_ARGS__); rc = -1; goto cleanup; } while (0)
55 
56 #define OK_OR_CLEANUP(WORK) do { if ((WORK) < 0) ERR_CLEANUP(); } while (0)
57 #define OK_OR_CLEANUP_MSG(WORK, MSG, ...) do { if ((WORK) < 0) ERR_CLEANUP_MSG(MSG, ## __VA_ARGS__); } while (0)
58 
59 #define ERR_RETURN(MSG, ...) do { set_last_error(MSG, ## __VA_ARGS__); return -1; } while (0)
60 #define OK_OR_RETURN(WORK) do { if ((WORK) < 0) return -1; } while (0)
61 #define OK_OR_RETURN_MSG(WORK, MSG, ...) do { if ((WORK) < 0) ERR_RETURN(MSG, ## __VA_ARGS__); } while (0)
62 
63 #define OK_OR_FAIL(WORK) do { if ((WORK) < 0) fwup_err(EXIT_FAILURE, "Unexpected error at %s:%d", __FILE__, __LINE__); } while (0)
64 
65 #define INFO(MSG, ...) do { if (fwup_verbose) fwup_warnx(MSG, ## __VA_ARGS__); } while (0)
66 
67 #define FWUP_BLOCK_SIZE (512)
68 
69 // See wikipedia for the drama behind the IEC prefixes if this
70 // bothers you.
71 
72 // Power of 2 units
73 #define ONE_KiB  (1024LL)
74 #define ONE_MiB  (1024 * ONE_KiB)
75 #define ONE_GiB  (1024 * ONE_MiB)
76 #define ONE_TiB  (1024 * ONE_GiB)
77 
78 // Power of 10 units
79 #define ONE_KB  (1000LL)
80 #define ONE_MB  (1000 * ONE_KB)
81 #define ONE_GB  (1000 * ONE_MB)
82 #define ONE_TB  (1000 * ONE_GB)
83 
84 // Pretty printing numbers
85 int format_pretty_auto(off_t amount, char *out, size_t out_size);
86 int format_pretty(off_t amount, off_t units, char *out, size_t out_size);
87 const char *units_to_string(off_t units);
88 off_t find_natural_units(off_t amount);
89 
90 // This checks that the argument can be converted to a uint. It handles
91 // a few things:
92 //   1. Is this a non-empty string?
93 //   2. Was the string fully converted?
94 //   3. Did something cause strtoull set errno?
95 //   4. It discards the return value without triggering a compiler warning.
96 #define CHECK_ARG_UINT64(ARG, MSG) do { errno=0; const char *nptr = ARG; char *endptr; unsigned long long int _ = strtoull(nptr, &endptr, 0); (void) _; if (errno != 0 || *nptr == '\0' || *endptr != '\0') ERR_RETURN(MSG); } while (0)
97 #define CHECK_ARG_UINT64_RANGE(ARG, MIN_VAL, MAX_VAL, MSG) do { errno=0; const char *nptr = ARG; char *endptr; unsigned long long int val = strtoull(nptr, &endptr, 0); if (errno != 0 || val > (MAX_VAL) || val < (MIN_VAL) || *nptr == '\0' || *endptr != '\0') ERR_RETURN(MSG); } while (0)
98 
99 #ifdef __GNUC__
100 #define FWUP_ERR_ATTRS __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)))
101 #define FWUP_WARN_ATTRS __attribute__ ((__format__ (__printf__, 1, 2)))
102 #define FWUP_EXIT_ATTRS __attribute__ ((__noreturn__))
103 #else
104 #define FWUP_ERR_ATTRS
105 #define FWUP_WARN_ATTRS
106 #define FWUP_EXIT_ATTRS
107 #endif
108 
109 // These are similar to functions provided by err.h, but they output in the framed
110 // format when the user specifies --framing.
111 void fwup_err(int status, const char *format, ...) FWUP_ERR_ATTRS;
112 void fwup_errx(int status, const char *format, ...) FWUP_ERR_ATTRS;
113 void fwup_warnx(const char *format, ...) FWUP_WARN_ATTRS;
114 void fwup_exit(int status) FWUP_EXIT_ATTRS;
115 
116 #define FWUP_MAX_PUBLIC_KEYS 10
117 
118 #ifndef HAVE_STRPTIME
119 // Provide a prototype for strptime if using the version in the 3rdparty directory.
120 char* strptime(const char *buf, const char *fmt, struct tm *tm);
121 #endif
122 
123 #ifdef _WIN32
124 // Assume that all windows platforms are little endian
125 #define TO_BIGENDIAN16(X) _byteswap_ushort(X)
126 #define FROM_BIGENDIAN16(X) _byteswap_ushort(X)
127 #define TO_BIGENDIAN32(X) _byteswap_ulong(X)
128 #define FROM_BIGENDIAN32(X) _byteswap_ulong(X)
129 #else
130 // Other platforms have htons and ntohs without pulling in another library
131 #include <arpa/inet.h>
132 #define TO_BIGENDIAN16(X) htons(X)
133 #define FROM_BIGENDIAN16(X) ntohs(X)
134 #define TO_BIGENDIAN32(X) htonl(X)
135 #define FROM_BIGENDIAN32(X) ntohl(X)
136 #endif
137 
138 #define FRAMING_TYPE_SUCCESS  "OK"
139 #define FRAMING_TYPE_ERROR    "ER"
140 #define FRAMING_TYPE_WARNING  "WN"
141 #define FRAMING_TYPE_PROGRESS "PR"
142 
143 // Send output to the terminal based on the framing options
144 void fwup_output(const char *type, uint16_t code, const char *str);
145 
146 #ifndef HAVE_PREAD
147 ssize_t pread(int fd, void *buf, size_t count, off_t offset);
148 #endif
149 
150 #ifndef HAVE_PWRITE
151 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
152 #endif
153 
154 #ifndef HAVE_STRNDUP
155 char *strndup(const char *s, size_t n);
156 #endif
157 
158 #ifndef HAVE_MEMMEM
159 void *memmem(const void *haystack, size_t haystacklen,
160              const void *needle, size_t needlelen);
161 #endif
162 
163 // Getting and setting the environment
164 
165 // Ideally setenv() is available. If not, provide an implementation.
166 #define get_environment getenv
167 #ifdef HAVE_SETENV
168 // If setenv is available, use getenv/setenv to manage variables
169 // The "1" means to update the VALUE if NAME is already in the environment.
170 #define set_environment(NAME, VALUE) setenv(NAME, VALUE, 1)
171 #else
172 int set_environment(const char *key, const char *value);
173 #endif
174 
175 // On Win32, if open(2) isn't called with O_BINARY, the results are very
176 // unintuitive for anyone used to Linux development.
177 #ifdef _WIN32
178 #define O_WIN32_BINARY O_BINARY
179 #else
180 #define O_WIN32_BINARY 0
181 #endif
182 
183 // Page aligned memory allocation
184 void alloc_page_aligned(void **memptr, size_t size);
185 void free_page_aligned(void *memptr);
186 
187 int update_relative_path(const char *from_file, const char *filename, char **newpath);
188 
189 // UUIDs
190 #define UUID_LENGTH 16
191 #define UUID_STR_LENGTH 37 /* Includes NULL terminator */
192 
193 void uuid_to_string(const uint8_t uuid[UUID_LENGTH], char *uuid_str);
194 int string_to_uuid_me(const char *uuid_str, uint8_t uuid[UUID_LENGTH]);
195 void calculate_fwup_uuid(const char *data, off_t data_size, char *uuid);
196 
197 // Endian conversion
198 void ascii_to_utf16le(const char *input, char *output, size_t len);
199 void copy_le64(uint8_t *output, uint64_t v);
200 void copy_le32(uint8_t *output, uint32_t v);
201 void copy_le16(uint8_t *output, uint16_t v);
202 
203 // Crypto
204 #define FWUP_PUBLIC_KEY_LEN 32
205 #define FWUP_PRIVATE_KEY_LEN 32
206 #define FWUP_SIGNATURE_LEN 64
207 #define FWUP_BLAKE2b_256_LEN 32
208 #define FWUP_BLAKE2b_512_LEN 64
209 
210 #ifndef FWUP_APPLY_ONLY
211 int get_random(uint8_t *buf, size_t len);
212 #endif
213 
214 #endif // UTIL_H
215