xref: /openbsd-src/libexec/ld.so/dl_dirname.c (revision b722ba42570161220f25c5d789b5bec8a0166743)
1 /*	$OpenBSD: dl_dirname.c,v 1.4 2022/01/08 06:49:41 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 1997, 2004 Todd C. Miller <millert@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <limits.h>
21 
22 #include "util.h"
23 
24 /*
25  * This file was copied from libc/stdlib/realpath.c and modified for ld.so's
26  * syscall method which returns -errno.
27  */
28 
29 char *
_dl_dirname(const char * path)30 _dl_dirname(const char *path)
31 {
32 	static char dname[PATH_MAX];
33 	size_t len;
34 	const char *endp;
35 
36 	/* Empty or NULL string gets treated as "." */
37 	if (path == NULL || *path == '\0') {
38 		dname[0] = '.';
39 		dname[1] = '\0';
40 		return (dname);
41 	}
42 
43 	/* Strip any trailing slashes */
44 	endp = path + strlen(path) - 1;
45 	while (endp > path && *endp == '/')
46 		endp--;
47 
48 	/* Find the start of the dir */
49 	while (endp > path && *endp != '/')
50 		endp--;
51 
52 	/* Either the dir is "/" or there are no slashes */
53 	if (endp == path) {
54 		dname[0] = *endp == '/' ? '/' : '.';
55 		dname[1] = '\0';
56 		return (dname);
57 	} else {
58 		/* Move forward past the separating slashes */
59 		do {
60 			endp--;
61 		} while (endp > path && *endp == '/');
62 	}
63 
64 	len = endp - path + 1;
65 	if (len >= sizeof(dname)) {
66 		return (NULL);
67 	}
68 	_dl_bcopy(path, dname, len);
69 	dname[len] = '\0';
70 	return (dname);
71 }
72