os_unix.c (4786B)
1 /* See LICENSE for license details. */ 2 #include "util.h" 3 4 #include <dlfcn.h> 5 #include <fcntl.h> 6 #include <poll.h> 7 #include <sys/mman.h> 8 #include <sys/stat.h> 9 #include <unistd.h> 10 11 static PLATFORM_WRITE_FILE_FN(os_write_file) 12 { 13 while (raw.len) { 14 size r = write(file, raw.data, raw.len); 15 if (r < 0) return 0; 16 raw = s8_cut_head(raw, r); 17 } 18 return 1; 19 } 20 21 static void 22 os_write_err_msg(s8 msg) 23 { 24 os_write_file(STDERR_FILENO, msg); 25 } 26 27 static void __attribute__((noreturn)) 28 os_fatal(s8 msg) 29 { 30 os_write_err_msg(msg); 31 _exit(1); 32 unreachable(); 33 } 34 35 static PLATFORM_ALLOC_ARENA_FN(os_alloc_arena) 36 { 37 Arena result; 38 size pagesize = sysconf(_SC_PAGESIZE); 39 if (capacity % pagesize != 0) 40 capacity += pagesize - capacity % pagesize; 41 42 size oldsize = old.end - old.beg; 43 if (oldsize > capacity) 44 return old; 45 46 if (old.beg) 47 munmap(old.beg, oldsize); 48 49 result.beg = mmap(0, capacity, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 50 if (result.beg == MAP_FAILED) 51 os_fatal(s8("os_alloc_arena: couldn't allocate memory\n")); 52 result.end = result.beg + capacity; 53 return result; 54 } 55 56 static PLATFORM_CLOSE_FN(os_close) 57 { 58 close(file); 59 } 60 61 static PLATFORM_OPEN_FOR_WRITE_FN(os_open_for_write) 62 { 63 iptr result = open(fname, O_WRONLY|O_TRUNC); 64 if (result == -1) 65 result = INVALID_FILE; 66 return result; 67 } 68 69 static s8 70 os_read_file(Arena *a, char *fname, size fsize) 71 { 72 if (fsize < 0) 73 return (s8){.len = -1}; 74 75 i32 fd = open(fname, O_RDONLY); 76 if (fd < 0) 77 return (s8){.len = -1}; 78 79 s8 ret = s8alloc(a, fsize); 80 size rlen = read(fd, ret.data, ret.len); 81 close(fd); 82 83 if (rlen != ret.len) 84 return (s8){.len = -1}; 85 86 return ret; 87 } 88 89 static PLATFORM_WRITE_NEW_FILE_FN(os_write_new_file) 90 { 91 iptr fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600); 92 if (fd == INVALID_FILE) 93 return 0; 94 b32 ret = os_write_file(fd, raw); 95 close(fd); 96 return ret; 97 } 98 99 static FileStats 100 os_get_file_stats(char *fname) 101 { 102 struct stat st; 103 104 if (stat(fname, &st) < 0) { 105 return ERROR_FILE_STATS; 106 } 107 108 return (FileStats){ 109 .filesize = st.st_size, 110 .timestamp = st.st_mtim.tv_sec + st.st_mtim.tv_nsec * 1e9, 111 }; 112 } 113 114 static Pipe 115 os_open_named_pipe(char *name) 116 { 117 mkfifo(name, 0660); 118 return (Pipe){.file = open(name, O_RDONLY|O_NONBLOCK), .name = name}; 119 } 120 121 static void 122 os_close_named_pipe(Pipe p) 123 { 124 close(p.file); 125 unlink(p.name); 126 } 127 128 static PLATFORM_POLL_PIPE_FN(os_poll_pipe) 129 { 130 struct pollfd pfd = {.fd = p.file, .events = POLLIN}; 131 poll(&pfd, 1, 0); 132 return !!(pfd.revents & POLLIN); 133 } 134 135 static PLATFORM_READ_PIPE_FN(os_read_pipe) 136 { 137 size r = 0, total_read = 0; 138 do { 139 if (r != -1) 140 total_read += r; 141 r = read(pipe, buf + total_read, len - total_read); 142 } while (r); 143 return total_read; 144 } 145 146 static void * 147 os_open_shared_memory_area(char *name, size cap) 148 { 149 i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 150 if (fd == -1) 151 return NULL; 152 153 if (ftruncate(fd, cap) == -1) { 154 close(fd); 155 return NULL; 156 } 157 158 void *new = mmap(NULL, cap, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 159 close(fd); 160 161 if (new == MAP_FAILED) 162 return NULL; 163 164 return new; 165 } 166 167 static void 168 os_remove_shared_memory(char *name) 169 { 170 shm_unlink(name); 171 } 172 173 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */ 174 static b32 175 os_copy_file(char *name, char *new) 176 { 177 b32 result = 0; 178 struct stat sb; 179 if (stat(name, &sb) < 0) 180 return 0; 181 182 i32 fd_old = open(name, O_RDONLY); 183 i32 fd_new = open(new, O_WRONLY|O_TRUNC, sb.st_mode); 184 185 if (fd_old < 0 || fd_new < 0) 186 goto ret; 187 u8 buf[4096]; 188 size copied = 0; 189 while (copied != sb.st_size) { 190 size r = read(fd_old, buf, ARRAY_COUNT(buf)); 191 if (r < 0) goto ret; 192 size w = write(fd_new, buf, r); 193 if (w < 0) goto ret; 194 copied += w; 195 } 196 result = 1; 197 ret: 198 if (fd_old != -1) close(fd_old); 199 if (fd_new != -1) close(fd_new); 200 return result; 201 } 202 203 static void * 204 os_load_library(char *name, char *temp_name, Stream *e) 205 { 206 if (temp_name) { 207 if (os_copy_file(name, temp_name)) 208 name = temp_name; 209 } 210 void *res = dlopen(name, RTLD_NOW|RTLD_LOCAL); 211 if (!res && e) { 212 s8 errs[] = {s8("WARNING: os_load_library("), cstr_to_s8(name), s8("): "), 213 cstr_to_s8(dlerror()), s8("\n")}; 214 stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); 215 os_write_err_msg(stream_to_s8(e)); 216 e->widx = 0; 217 } 218 219 if (temp_name) 220 unlink(temp_name); 221 222 return res; 223 } 224 225 static void * 226 os_lookup_dynamic_symbol(void *h, char *name, Stream *e) 227 { 228 if (!h) 229 return 0; 230 void *res = dlsym(h, name); 231 if (!res && e) { 232 s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), cstr_to_s8(name), s8("): "), 233 cstr_to_s8(dlerror()), s8("\n")}; 234 stream_append_s8_array(e, errs, ARRAY_COUNT(errs)); 235 os_write_err_msg(stream_to_s8(e)); 236 e->widx = 0; 237 } 238 239 return res; 240 } 241 242 static void 243 os_unload_library(void *h) 244 { 245 /* NOTE: glibc is buggy gnuware so we need to check this */ 246 if (h) 247 dlclose(h); 248 }