Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *
  4 * Copyright (C) 2017 Hari Bathini, IBM Corporation
  5 */
  6
  7#include "namespaces.h"
  8#include "event.h"
  9#include "get_current_dir_name.h"
 10#include <sys/types.h>
 11#include <sys/stat.h>
 12#include <fcntl.h>
 13#include <limits.h>
 14#include <sched.h>
 15#include <stdlib.h>
 16#include <stdio.h>
 17#include <string.h>
 18#include <unistd.h>
 19#include <asm/bug.h>
 20#include <linux/kernel.h>
 21#include <linux/zalloc.h>
 22
 23static const char *perf_ns__names[] = {
 24	[NET_NS_INDEX]		= "net",
 25	[UTS_NS_INDEX]		= "uts",
 26	[IPC_NS_INDEX]		= "ipc",
 27	[PID_NS_INDEX]		= "pid",
 28	[USER_NS_INDEX]		= "user",
 29	[MNT_NS_INDEX]		= "mnt",
 30	[CGROUP_NS_INDEX]	= "cgroup",
 31};
 32
 33const char *perf_ns__name(unsigned int id)
 34{
 35	if (id >= ARRAY_SIZE(perf_ns__names))
 36		return "UNKNOWN";
 37	return perf_ns__names[id];
 38}
 39
 40struct namespaces *namespaces__new(struct perf_record_namespaces *event)
 41{
 42	struct namespaces *namespaces;
 43	u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
 44			      sizeof(struct perf_ns_link_info));
 45
 46	namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
 47	if (!namespaces)
 48		return NULL;
 49
 50	namespaces->end_time = -1;
 51
 52	if (event)
 53		memcpy(namespaces->link_info, event->link_info, link_info_size);
 54
 55	return namespaces;
 56}
 57
 58void namespaces__free(struct namespaces *namespaces)
 59{
 60	free(namespaces);
 61}
 62
 63int nsinfo__init(struct nsinfo *nsi)
 64{
 65	char oldns[PATH_MAX];
 66	char spath[PATH_MAX];
 67	char *newns = NULL;
 68	char *statln = NULL;
 69	struct stat old_stat;
 70	struct stat new_stat;
 71	FILE *f = NULL;
 72	size_t linesz = 0;
 73	int rv = -1;
 74
 75	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
 76		return rv;
 77
 78	if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
 79		return rv;
 80
 81	if (stat(oldns, &old_stat) < 0)
 82		goto out;
 83
 84	if (stat(newns, &new_stat) < 0)
 85		goto out;
 86
 87	/* Check if the mount namespaces differ, if so then indicate that we
 88	 * want to switch as part of looking up dso/map data.
 89	 */
 90	if (old_stat.st_ino != new_stat.st_ino) {
 91		nsi->need_setns = true;
 92		nsi->mntns_path = newns;
 93		newns = NULL;
 94	}
 95
 96	/* If we're dealing with a process that is in a different PID namespace,
 97	 * attempt to work out the innermost tgid for the process.
 98	 */
 99	if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsi->pid) >= PATH_MAX)
100		goto out;
101
102	f = fopen(spath, "r");
103	if (f == NULL)
104		goto out;
105
106	while (getline(&statln, &linesz, f) != -1) {
107		/* Use tgid if CONFIG_PID_NS is not defined. */
108		if (strstr(statln, "Tgid:") != NULL) {
109			nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
110						     NULL, 10);
111			nsi->nstgid = nsi->tgid;
112		}
113
114		if (strstr(statln, "NStgid:") != NULL) {
115			nsi->nstgid = (pid_t)strtol(strrchr(statln, '\t'),
116						     NULL, 10);
117			break;
118		}
119	}
120	rv = 0;
121
122out:
123	if (f != NULL)
124		(void) fclose(f);
125	free(statln);
126	free(newns);
127	return rv;
128}
129
130struct nsinfo *nsinfo__new(pid_t pid)
131{
132	struct nsinfo *nsi;
133
134	if (pid == 0)
135		return NULL;
136
137	nsi = calloc(1, sizeof(*nsi));
138	if (nsi != NULL) {
139		nsi->pid = pid;
140		nsi->tgid = pid;
141		nsi->nstgid = pid;
142		nsi->need_setns = false;
143		/* Init may fail if the process exits while we're trying to look
144		 * at its proc information.  In that case, save the pid but
145		 * don't try to enter the namespace.
146		 */
147		if (nsinfo__init(nsi) == -1)
148			nsi->need_setns = false;
149
150		refcount_set(&nsi->refcnt, 1);
151	}
152
153	return nsi;
154}
155
156struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
157{
158	struct nsinfo *nnsi;
159
160	if (nsi == NULL)
161		return NULL;
162
163	nnsi = calloc(1, sizeof(*nnsi));
164	if (nnsi != NULL) {
165		nnsi->pid = nsi->pid;
166		nnsi->tgid = nsi->tgid;
167		nnsi->nstgid = nsi->nstgid;
168		nnsi->need_setns = nsi->need_setns;
169		if (nsi->mntns_path) {
170			nnsi->mntns_path = strdup(nsi->mntns_path);
171			if (!nnsi->mntns_path) {
172				free(nnsi);
173				return NULL;
174			}
175		}
176		refcount_set(&nnsi->refcnt, 1);
177	}
178
179	return nnsi;
180}
181
182void nsinfo__delete(struct nsinfo *nsi)
183{
184	zfree(&nsi->mntns_path);
185	free(nsi);
186}
187
188struct nsinfo *nsinfo__get(struct nsinfo *nsi)
189{
190	if (nsi)
191		refcount_inc(&nsi->refcnt);
192	return nsi;
193}
194
195void nsinfo__put(struct nsinfo *nsi)
196{
197	if (nsi && refcount_dec_and_test(&nsi->refcnt))
198		nsinfo__delete(nsi);
199}
200
201void nsinfo__mountns_enter(struct nsinfo *nsi,
202				  struct nscookie *nc)
203{
204	char curpath[PATH_MAX];
205	int oldns = -1;
206	int newns = -1;
207	char *oldcwd = NULL;
208
209	if (nc == NULL)
210		return;
211
212	nc->oldns = -1;
213	nc->newns = -1;
214
215	if (!nsi || !nsi->need_setns)
216		return;
217
218	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
219		return;
220
221	oldcwd = get_current_dir_name();
222	if (!oldcwd)
223		return;
224
225	oldns = open(curpath, O_RDONLY);
226	if (oldns < 0)
227		goto errout;
228
229	newns = open(nsi->mntns_path, O_RDONLY);
230	if (newns < 0)
231		goto errout;
232
233	if (setns(newns, CLONE_NEWNS) < 0)
234		goto errout;
235
236	nc->oldcwd = oldcwd;
237	nc->oldns = oldns;
238	nc->newns = newns;
239	return;
240
241errout:
242	free(oldcwd);
243	if (oldns > -1)
244		close(oldns);
245	if (newns > -1)
246		close(newns);
247}
248
249void nsinfo__mountns_exit(struct nscookie *nc)
250{
251	if (nc == NULL || nc->oldns == -1 || nc->newns == -1 || !nc->oldcwd)
252		return;
253
254	setns(nc->oldns, CLONE_NEWNS);
255
256	if (nc->oldcwd) {
257		WARN_ON_ONCE(chdir(nc->oldcwd));
258		zfree(&nc->oldcwd);
259	}
260
261	if (nc->oldns > -1) {
262		close(nc->oldns);
263		nc->oldns = -1;
264	}
265
266	if (nc->newns > -1) {
267		close(nc->newns);
268		nc->newns = -1;
269	}
270}
271
272char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
273{
274	char *rpath;
275	struct nscookie nsc;
276
277	nsinfo__mountns_enter(nsi, &nsc);
278	rpath = realpath(path, NULL);
279	nsinfo__mountns_exit(&nsc);
280
281	return rpath;
282}