1 /* @(#)procnameat.c 1.3 18/07/16 Copyright 2011-2018 J. Schilling */
2 /*
3 * Return a path name for a /proc related access to fd/name if possible.
4 *
5 * We need to test this at runtime in order to avoid incorrect behavior
6 * from running a program on a newer OS that it has been compiled for.
7 * There are also platforms like FreeBSD where mounting /proc is optioonal.
8 *
9 **************
10 * NOTE: The entries /proc/self/{fd|path}/%d are symlinks and thus do
11 * not allow to access paths of unlimited length as possible
12 * with a real openat(fd, name, flags) call.
13 **************
14 *
15 * If our caller falls back to the fchdir() method, e.g. because we
16 * did not detect /proc, or because /proc/self/{fd|path}/%d results
17 * in ENAMETOOLONG, the resulting code is no longer MT-safe.
18 *
19 * Copyright (c) 2011-2018 J. Schilling
20 */
21 /*
22 * The contents of this file are subject to the terms of the
23 * Common Development and Distribution License, Version 1.0 only
24 * (the "License"). You may not use this file except in compliance
25 * with the License.
26 *
27 * See the file CDDL.Schily.txt in this distribution for details.
28 * A copy of the CDDL is also available via the Internet at
29 * http://www.opensource.org/licenses/cddl1.txt
30 *
31 * When distributing Covered Code, include this CDDL HEADER in each
32 * file and include the License file CDDL.Schily.txt from this distribution.
33 */
34
35 #include <schily/unistd.h>
36 #include <schily/types.h>
37 #include <schily/fcntl.h>
38 #include <schily/maxpath.h>
39 #include <schily/errno.h>
40 #include <schily/standard.h>
41 #include <schily/schily.h>
42 #include "at-defs.h"
43
44 #ifndef ENAMETOOLONG
45 #define ENAMETOOLONG EINVAL
46 #endif
47
48 #define PROC_SELF_PATH_FORMAT "/proc/self/path/%d/%s" /* Newer procfs */
49 #define PROC_SELF_FD_FORMAT "/proc/self/fd/%d/%s" /* Older procfs */
50 #define PROC_PID_FD_FORMAT "/proc/%ld/fd/%d/%s" /* AIX has no self */
51
52 #define PT_SELF_PATH 1
53 #define PT_SELF_FD 2
54 #define PT_PID_FD 3
55
56 char *
proc_fd2name(buf,fd,name)57 proc_fd2name(buf, fd, name)
58 char *buf;
59 int fd;
60 const char *name;
61 {
62 static int proc_type;
63
64 if (proc_type == 0) {
65 int proc_fd;
66
67 /*
68 * First test the newer feature as the older /proc/self/fd/%d
69 * feature is still available on newer systems.
70 */
71 proc_fd = open("/proc/self/path", O_SEARCH);
72 if (proc_fd >= 0) {
73 proc_type = PT_SELF_PATH;
74 close(proc_fd);
75 } else {
76 proc_fd = open("/proc/self/fd", O_SEARCH);
77 if (proc_fd >= 0) {
78 proc_type = PT_SELF_FD;
79 close(proc_fd);
80 } else {
81 js_snprintf(buf, PATH_MAX,
82 "/proc/%ld/fd", (long)getpid());
83 proc_fd = open(buf, O_SEARCH);
84 if (proc_fd >= 0) {
85 proc_type = PT_PID_FD;
86 close(proc_fd);
87 } else {
88 /*
89 * No /proc fs found
90 */
91 proc_type = -1;
92 seterrno(0);
93 return ((char *)0);
94 }
95 }
96 }
97 } else if (proc_type < 0) {
98 /*
99 * No /proc fs found
100 */
101 seterrno(0);
102 return ((char *)0);
103 }
104 if (proc_type == PT_PID_FD) {
105 if (js_snprintf(buf, PATH_MAX,
106 PROC_PID_FD_FORMAT,
107 (long)getpid(), fd, name) >= PATH_MAX) {
108 seterrno(ENAMETOOLONG);
109 return (NULL);
110 }
111 } else if (js_snprintf(buf, PATH_MAX,
112 proc_type == PT_SELF_PATH ?
113 PROC_SELF_PATH_FORMAT :
114 PROC_SELF_FD_FORMAT,
115 fd, name) >= PATH_MAX) {
116 seterrno(ENAMETOOLONG);
117 return (NULL);
118 }
119 return (buf);
120 }
121