1 /* $OpenBSD: symlinks.c,v 1.7 2021/09/02 21:06:06 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <assert.h> 19 #include <stdint.h> 20 #include <stdlib.h> 21 #include <limits.h> 22 #include <unistd.h> 23 24 #include "extern.h" 25 26 /* 27 * Allocate space for a readlink(2) invocation. 28 * Returns NULL on failure or a buffer otherwise. 29 * The buffer must be passed to free() by the caller. 30 */ 31 char * 32 symlink_read(const char *path) 33 { 34 char *buf = NULL; 35 size_t sz; 36 ssize_t nsz = 0; 37 void *pp; 38 39 for (sz = PATH_MAX; ; sz *= 2) { 40 if ((pp = realloc(buf, sz + 1)) == NULL) { 41 ERR("realloc"); 42 free(buf); 43 return NULL; 44 } 45 buf = pp; 46 47 if ((nsz = readlink(path, buf, sz)) == -1) { 48 ERR("%s: readlink", path); 49 free(buf); 50 return NULL; 51 } else if (nsz == 0) { 52 ERRX("%s: empty link", path); 53 free(buf); 54 return NULL; 55 } else if ((size_t)nsz < sz) 56 break; 57 } 58 59 assert(buf != NULL); 60 assert(nsz > 0); 61 buf[nsz] = '\0'; 62 return buf; 63 } 64 65 /* 66 * Allocate space for a readlinkat(2) invocation. 67 * Returns NULL on failure or a buffer otherwise. 68 * The buffer must be passed to free() by the caller. 69 */ 70 char * 71 symlinkat_read(int fd, const char *path) 72 { 73 char *buf = NULL; 74 size_t sz; 75 ssize_t nsz = 0; 76 void *pp; 77 78 for (sz = PATH_MAX; ; sz *= 2) { 79 if ((pp = realloc(buf, sz + 1)) == NULL) { 80 ERR("realloc"); 81 free(buf); 82 return NULL; 83 } 84 buf = pp; 85 86 if ((nsz = readlinkat(fd, path, buf, sz)) == -1) { 87 ERR("%s: readlinkat", path); 88 free(buf); 89 return NULL; 90 } else if (nsz == 0) { 91 ERRX("%s: empty link", path); 92 free(buf); 93 return NULL; 94 } else if ((size_t)nsz < sz) 95 break; 96 } 97 98 assert(buf != NULL); 99 assert(nsz > 0); 100 buf[nsz] = '\0'; 101 return buf; 102 } 103