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