1 /*	$Id$ */
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 #include "config.h"
18 
19 #include <sys/param.h>
20 
21 #include <assert.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 
26 #include "extern.h"
27 
28 /*
29  * Allocate space for a readlink(2) invocation.
30  * Returns NULL on failure or a buffer otherwise.
31  * The buffer must be passed to free() by the caller.
32  */
33 char *
symlink_read(const char * path)34 symlink_read(const char *path)
35 {
36 	char	*buf = NULL;
37 	size_t	 sz;
38 	ssize_t	 nsz = 0;
39 	void	*pp;
40 
41 	for (sz = MAXPATHLEN; ; sz *= 2) {
42 		if ((pp = realloc(buf, sz + 1)) == NULL) {
43 			ERR("realloc");
44 			free(buf);
45 			return NULL;
46 		}
47 		buf = pp;
48 
49 		if ((nsz = readlink(path, buf, sz)) == -1) {
50 			ERR("%s: readlink", path);
51 			free(buf);
52 			return NULL;
53 		} else if (nsz == 0) {
54 			ERRX("%s: empty link", path);
55 			free(buf);
56 			return NULL;
57 		} else if ((size_t)nsz < sz)
58 			break;
59 	}
60 
61 	assert(buf != NULL);
62 	assert(nsz > 0);
63 	buf[nsz] = '\0';
64 	return buf;
65 }
66 
67 /*
68  * Allocate space for a readlinkat(2) invocation.
69  * Returns NULL on failure or a buffer otherwise.
70  * The buffer must be passed to free() by the caller.
71  */
72 char *
symlinkat_read(int fd,const char * path)73 symlinkat_read(int fd, const char *path)
74 {
75 	char	*buf = NULL;
76 	size_t	 sz;
77 	ssize_t	 nsz = 0;
78 	void	*pp;
79 
80 	for (sz = MAXPATHLEN; ; sz *= 2) {
81 		if ((pp = realloc(buf, sz + 1)) == NULL) {
82 			ERR("realloc");
83 			free(buf);
84 			return NULL;
85 		}
86 		buf = pp;
87 
88 		if ((nsz = readlinkat(fd, path, buf, sz)) == -1) {
89 			ERR("%s: readlinkat", path);
90 			free(buf);
91 			return NULL;
92 		} else if (nsz == 0) {
93 			ERRX("%s: empty link", path);
94 			free(buf);
95 			return NULL;
96 		} else if ((size_t)nsz < sz)
97 			break;
98 	}
99 
100 	assert(buf != NULL);
101 	assert(nsz > 0);
102 	buf[nsz] = '\0';
103 	return buf;
104 }
105