Line data Source code
1 : /* Create /proc/self/fd-related names for subfiles of open directories.
2 :
3 : Copyright (C) 2006 Free Software Foundation, Inc.
4 :
5 : This program is free software: you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as published by
7 : the Free Software Foundation; either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 :
18 : /* Written by Paul Eggert. */
19 :
20 : #include <config.h>
21 :
22 : #include "openat-priv.h"
23 :
24 : #include <sys/types.h>
25 : #include <sys/stat.h>
26 : #include <fcntl.h>
27 :
28 : #include <stdio.h>
29 : #include <string.h>
30 :
31 : #include "dirname.h"
32 : #include "intprops.h"
33 : #include "same-inode.h"
34 : #include "xalloc.h"
35 :
36 : /* The results of open() in this file are not used with fchdir,
37 : therefore save some unnecessary work in fchdir.c. */
38 : #undef open
39 : #undef close
40 :
41 : #define PROC_SELF_FD_FORMAT "/proc/self/fd/%d/%s"
42 :
43 : #define PROC_SELF_FD_NAME_SIZE_BOUND(len) \
44 : (sizeof PROC_SELF_FD_FORMAT - sizeof "%d%s" \
45 : + INT_STRLEN_BOUND (int) + (len) + 1)
46 :
47 :
48 : /* Set BUF to the expansion of PROC_SELF_FD_FORMAT, using FD and FILE
49 : respectively for %d and %s. If successful, return BUF if the
50 : result fits in BUF, dynamically allocated memory otherwise. But
51 : return NULL if /proc is not reliable. */
52 : char *
53 133378 : openat_proc_name (char buf[OPENAT_BUFFER_SIZE], int fd, char const *file)
54 : {
55 : static int proc_status = 0;
56 :
57 133378 : if (! proc_status)
58 : {
59 : /* Set PROC_STATUS to a positive value if /proc/self/fd is
60 : reliable, and a negative value otherwise. Solaris 10
61 : /proc/self/fd mishandles "..", and any file name might expand
62 : to ".." after symbolic link expansion, so avoid /proc/self/fd
63 : if it mishandles "..". Solaris 10 has openat, but this
64 : problem is exhibited on code that built on Solaris 8 and
65 : running on Solaris 10. */
66 :
67 1 : int proc_self_fd = open ("/proc/self/fd", O_RDONLY);
68 1 : if (proc_self_fd < 0)
69 0 : proc_status = -1;
70 : else
71 : {
72 : struct stat proc_self_fd_dotdot_st;
73 : struct stat proc_self_st;
74 : char dotdot_buf[PROC_SELF_FD_NAME_SIZE_BOUND (sizeof ".." - 1)];
75 1 : sprintf (dotdot_buf, PROC_SELF_FD_FORMAT, proc_self_fd, "..");
76 1 : proc_status =
77 1 : ((stat (dotdot_buf, &proc_self_fd_dotdot_st) == 0
78 1 : && stat ("/proc/self", &proc_self_st) == 0
79 1 : && SAME_INODE (proc_self_fd_dotdot_st, proc_self_st))
80 2 : ? 1 : -1);
81 1 : close (proc_self_fd);
82 : }
83 : }
84 :
85 133378 : if (proc_status < 0)
86 0 : return NULL;
87 : else
88 : {
89 133378 : size_t bufsize = PROC_SELF_FD_NAME_SIZE_BOUND (strlen (file));
90 133378 : char *result = (bufsize < OPENAT_BUFFER_SIZE ? buf : xmalloc (bufsize));
91 133378 : sprintf (result, PROC_SELF_FD_FORMAT, fd, file);
92 133378 : return result;
93 : }
94 : }
|