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>
23 struct namespaces
*namespaces__new(struct namespaces_event
*event
)
25 struct namespaces
*namespaces
;
26 u64 link_info_size
= ((event
? event
->nr_namespaces
: NR_NAMESPACES
) *
27 sizeof(struct perf_ns_link_info
));
29 namespaces
= zalloc(sizeof(struct namespaces
) + link_info_size
);
33 namespaces
->end_time
= -1;
36 memcpy(namespaces
->link_info
, event
->link_info
, link_info_size
);
41 void namespaces__free(struct namespaces
*namespaces
)
46 int nsinfo__init(struct nsinfo
*nsi
)
58 if (snprintf(oldns
, PATH_MAX
, "/proc/self/ns/mnt") >= PATH_MAX
)
61 if (asprintf(&newns
, "/proc/%d/ns/mnt", nsi
->pid
) == -1)
64 if (stat(oldns
, &old_stat
) < 0)
67 if (stat(newns
, &new_stat
) < 0)
70 /* Check if the mount namespaces differ, if so then indicate that we
71 * want to switch as part of looking up dso/map data.
73 if (old_stat
.st_ino
!= new_stat
.st_ino
) {
74 nsi
->need_setns
= true;
75 nsi
->mntns_path
= newns
;
79 /* If we're dealing with a process that is in a different PID namespace,
80 * attempt to work out the innermost tgid for the process.
82 if (snprintf(spath
, PATH_MAX
, "/proc/%d/status", nsi
->pid
) >= PATH_MAX
)
85 f
= fopen(spath
, "r");
89 while (getline(&statln
, &linesz
, f
) != -1) {
90 /* Use tgid if CONFIG_PID_NS is not defined. */
91 if (strstr(statln
, "Tgid:") != NULL
) {
92 nsi
->tgid
= (pid_t
)strtol(strrchr(statln
, '\t'),
94 nsi
->nstgid
= nsi
->tgid
;
97 if (strstr(statln
, "NStgid:") != NULL
) {
98 nsi
->nstgid
= (pid_t
)strtol(strrchr(statln
, '\t'),
113 struct nsinfo
*nsinfo__new(pid_t pid
)
120 nsi
= calloc(1, sizeof(*nsi
));
125 nsi
->need_setns
= false;
126 /* Init may fail if the process exits while we're trying to look
127 * at its proc information. In that case, save the pid but
128 * don't try to enter the namespace.
130 if (nsinfo__init(nsi
) == -1)
131 nsi
->need_setns
= false;
133 refcount_set(&nsi
->refcnt
, 1);
139 struct nsinfo
*nsinfo__copy(struct nsinfo
*nsi
)
146 nnsi
= calloc(1, sizeof(*nnsi
));
148 nnsi
->pid
= nsi
->pid
;
149 nnsi
->tgid
= nsi
->tgid
;
150 nnsi
->nstgid
= nsi
->nstgid
;
151 nnsi
->need_setns
= nsi
->need_setns
;
152 if (nsi
->mntns_path
) {
153 nnsi
->mntns_path
= strdup(nsi
->mntns_path
);
154 if (!nnsi
->mntns_path
) {
159 refcount_set(&nnsi
->refcnt
, 1);
165 void nsinfo__delete(struct nsinfo
*nsi
)
167 zfree(&nsi
->mntns_path
);
171 struct nsinfo
*nsinfo__get(struct nsinfo
*nsi
)
174 refcount_inc(&nsi
->refcnt
);
178 void nsinfo__put(struct nsinfo
*nsi
)
180 if (nsi
&& refcount_dec_and_test(&nsi
->refcnt
))
184 void nsinfo__mountns_enter(struct nsinfo
*nsi
,
187 char curpath
[PATH_MAX
];
198 if (!nsi
|| !nsi
->need_setns
)
201 if (snprintf(curpath
, PATH_MAX
, "/proc/self/ns/mnt") >= PATH_MAX
)
204 oldcwd
= get_current_dir_name();
208 oldns
= open(curpath
, O_RDONLY
);
212 newns
= open(nsi
->mntns_path
, O_RDONLY
);
216 if (setns(newns
, CLONE_NEWNS
) < 0)
232 void nsinfo__mountns_exit(struct nscookie
*nc
)
234 if (nc
== NULL
|| nc
->oldns
== -1 || nc
->newns
== -1 || !nc
->oldcwd
)
237 setns(nc
->oldns
, CLONE_NEWNS
);
240 WARN_ON_ONCE(chdir(nc
->oldcwd
));
244 if (nc
->oldns
> -1) {
249 if (nc
->newns
> -1) {
255 char *nsinfo__realpath(const char *path
, struct nsinfo
*nsi
)
260 nsinfo__mountns_enter(nsi
, &nsc
);
261 rpath
= realpath(path
, NULL
);
262 nsinfo__mountns_exit(&nsc
);