2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
9 #include "namespaces.h"
12 #include <sys/types.h>
22 struct namespaces
*namespaces__new(struct namespaces_event
*event
)
24 struct namespaces
*namespaces
;
25 u64 link_info_size
= ((event
? event
->nr_namespaces
: NR_NAMESPACES
) *
26 sizeof(struct perf_ns_link_info
));
28 namespaces
= zalloc(sizeof(struct namespaces
) + link_info_size
);
32 namespaces
->end_time
= -1;
35 memcpy(namespaces
->link_info
, event
->link_info
, link_info_size
);
40 void namespaces__free(struct namespaces
*namespaces
)
45 int nsinfo__init(struct nsinfo
*nsi
)
57 if (snprintf(oldns
, PATH_MAX
, "/proc/self/ns/mnt") >= PATH_MAX
)
60 if (asprintf(&newns
, "/proc/%d/ns/mnt", nsi
->pid
) == -1)
63 if (stat(oldns
, &old_stat
) < 0)
66 if (stat(newns
, &new_stat
) < 0)
69 /* Check if the mount namespaces differ, if so then indicate that we
70 * want to switch as part of looking up dso/map data.
72 if (old_stat
.st_ino
!= new_stat
.st_ino
) {
73 nsi
->need_setns
= true;
74 nsi
->mntns_path
= newns
;
78 /* If we're dealing with a process that is in a different PID namespace,
79 * attempt to work out the innermost tgid for the process.
81 if (snprintf(spath
, PATH_MAX
, "/proc/%d/status", nsi
->pid
) >= PATH_MAX
)
84 f
= fopen(spath
, "r");
88 while (getline(&statln
, &linesz
, f
) != -1) {
89 /* Use tgid if CONFIG_PID_NS is not defined. */
90 if (strstr(statln
, "Tgid:") != NULL
) {
91 nsi
->tgid
= (pid_t
)strtol(strrchr(statln
, '\t'),
93 nsi
->nstgid
= nsi
->tgid
;
96 if (strstr(statln
, "NStgid:") != NULL
) {
97 nsi
->nstgid
= (pid_t
)strtol(strrchr(statln
, '\t'),
112 struct nsinfo
*nsinfo__new(pid_t pid
)
119 nsi
= calloc(1, sizeof(*nsi
));
124 nsi
->need_setns
= false;
125 /* Init may fail if the process exits while we're trying to look
126 * at its proc information. In that case, save the pid but
127 * don't try to enter the namespace.
129 if (nsinfo__init(nsi
) == -1)
130 nsi
->need_setns
= false;
132 refcount_set(&nsi
->refcnt
, 1);
138 struct nsinfo
*nsinfo__copy(struct nsinfo
*nsi
)
142 nnsi
= calloc(1, sizeof(*nnsi
));
144 nnsi
->pid
= nsi
->pid
;
145 nnsi
->tgid
= nsi
->tgid
;
146 nnsi
->nstgid
= nsi
->nstgid
;
147 nnsi
->need_setns
= nsi
->need_setns
;
148 if (nsi
->mntns_path
) {
149 nnsi
->mntns_path
= strdup(nsi
->mntns_path
);
150 if (!nnsi
->mntns_path
) {
155 refcount_set(&nnsi
->refcnt
, 1);
161 void nsinfo__delete(struct nsinfo
*nsi
)
163 zfree(&nsi
->mntns_path
);
167 struct nsinfo
*nsinfo__get(struct nsinfo
*nsi
)
170 refcount_inc(&nsi
->refcnt
);
174 void nsinfo__put(struct nsinfo
*nsi
)
176 if (nsi
&& refcount_dec_and_test(&nsi
->refcnt
))
180 void nsinfo__mountns_enter(struct nsinfo
*nsi
,
183 char curpath
[PATH_MAX
];
193 if (!nsi
|| !nsi
->need_setns
)
196 if (snprintf(curpath
, PATH_MAX
, "/proc/self/ns/mnt") >= PATH_MAX
)
199 oldns
= open(curpath
, O_RDONLY
);
203 newns
= open(nsi
->mntns_path
, O_RDONLY
);
207 if (setns(newns
, CLONE_NEWNS
) < 0)
221 void nsinfo__mountns_exit(struct nscookie
*nc
)
223 if (nc
== NULL
|| nc
->oldns
== -1 || nc
->newns
== -1)
226 setns(nc
->oldns
, CLONE_NEWNS
);
228 if (nc
->oldns
> -1) {
233 if (nc
->newns
> -1) {
239 char *nsinfo__realpath(const char *path
, struct nsinfo
*nsi
)
244 nsinfo__mountns_enter(nsi
, &nsc
);
245 rpath
= realpath(path
, NULL
);
246 nsinfo__mountns_exit(&nsc
);