Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  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.
  5 *
  6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
  7 */
  8
  9#include "namespaces.h"
 10#include "util.h"
 11#include "event.h"
 12#include <sys/types.h>
 13#include <sys/stat.h>
 14#include <fcntl.h>
 15#include <limits.h>
 16#include <sched.h>
 17#include <stdlib.h>
 18#include <stdio.h>
 19#include <string.h>
 20#include <unistd.h>
 21
 22struct namespaces *namespaces__new(struct namespaces_event *event)
 23{
 24	struct namespaces *namespaces;
 25	u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
 26			      sizeof(struct perf_ns_link_info));
 27
 28	namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
 29	if (!namespaces)
 30		return NULL;
 31
 32	namespaces->end_time = -1;
 33
 34	if (event)
 35		memcpy(namespaces->link_info, event->link_info, link_info_size);
 36
 37	return namespaces;
 38}
 39
 40void namespaces__free(struct namespaces *namespaces)
 41{
 42	free(namespaces);
 43}
 44
 45int nsinfo__init(struct nsinfo *nsi)
 46{
 47	char oldns[PATH_MAX];
 48	char spath[PATH_MAX];
 49	char *newns = NULL;
 50	char *statln = NULL;
 51	struct stat old_stat;
 52	struct stat new_stat;
 53	FILE *f = NULL;
 54	size_t linesz = 0;
 55	int rv = -1;
 56
 57	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
 58		return rv;
 59
 60	if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
 61		return rv;
 62
 63	if (stat(oldns, &old_stat) < 0)
 64		goto out;
 65
 66	if (stat(newns, &new_stat) < 0)
 67		goto out;
 68
 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.
 71	 */
 72	if (old_stat.st_ino != new_stat.st_ino) {
 73		nsi->need_setns = true;
 74		nsi->mntns_path = newns;
 75		newns = NULL;
 76	}
 77
 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.
 80	 */
 81	if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsi->pid) >= PATH_MAX)
 82		goto out;
 83
 84	f = fopen(spath, "r");
 85	if (f == NULL)
 86		goto out;
 87
 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'),
 92						     NULL, 10);
 93			nsi->nstgid = nsi->tgid;
 94		}
 95
 96		if (strstr(statln, "NStgid:") != NULL) {
 97			nsi->nstgid = (pid_t)strtol(strrchr(statln, '\t'),
 98						     NULL, 10);
 99			break;
100		}
101	}
102	rv = 0;
103
104out:
105	if (f != NULL)
106		(void) fclose(f);
107	free(statln);
108	free(newns);
109	return rv;
110}
111
112struct nsinfo *nsinfo__new(pid_t pid)
113{
114	struct nsinfo *nsi;
115
116	if (pid == 0)
117		return NULL;
118
119	nsi = calloc(1, sizeof(*nsi));
120	if (nsi != NULL) {
121		nsi->pid = pid;
122		nsi->tgid = pid;
123		nsi->nstgid = pid;
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.
128		 */
129		if (nsinfo__init(nsi) == -1)
130			nsi->need_setns = false;
131
132		refcount_set(&nsi->refcnt, 1);
133	}
134
135	return nsi;
136}
137
138struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
139{
140	struct nsinfo *nnsi;
141
142	nnsi = calloc(1, sizeof(*nnsi));
143	if (nnsi != NULL) {
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) {
151				free(nnsi);
152				return NULL;
153			}
154		}
155		refcount_set(&nnsi->refcnt, 1);
156	}
157
158	return nnsi;
159}
160
161void nsinfo__delete(struct nsinfo *nsi)
162{
163	zfree(&nsi->mntns_path);
164	free(nsi);
165}
166
167struct nsinfo *nsinfo__get(struct nsinfo *nsi)
168{
169	if (nsi)
170		refcount_inc(&nsi->refcnt);
171	return nsi;
172}
173
174void nsinfo__put(struct nsinfo *nsi)
175{
176	if (nsi && refcount_dec_and_test(&nsi->refcnt))
177		nsinfo__delete(nsi);
178}
179
180void nsinfo__mountns_enter(struct nsinfo *nsi,
181				  struct nscookie *nc)
182{
183	char curpath[PATH_MAX];
184	int oldns = -1;
185	int newns = -1;
186
187	if (nc == NULL)
188		return;
189
190	nc->oldns = -1;
191	nc->newns = -1;
192
193	if (!nsi || !nsi->need_setns)
194		return;
195
196	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
197		return;
198
199	oldns = open(curpath, O_RDONLY);
200	if (oldns < 0)
201		return;
202
203	newns = open(nsi->mntns_path, O_RDONLY);
204	if (newns < 0)
205		goto errout;
206
207	if (setns(newns, CLONE_NEWNS) < 0)
208		goto errout;
209
210	nc->oldns = oldns;
211	nc->newns = newns;
212	return;
213
214errout:
215	if (oldns > -1)
216		close(oldns);
217	if (newns > -1)
218		close(newns);
219}
220
221void nsinfo__mountns_exit(struct nscookie *nc)
222{
223	if (nc == NULL || nc->oldns == -1 || nc->newns == -1)
224		return;
225
226	setns(nc->oldns, CLONE_NEWNS);
227
228	if (nc->oldns > -1) {
229		close(nc->oldns);
230		nc->oldns = -1;
231	}
232
233	if (nc->newns > -1) {
234		close(nc->newns);
235		nc->newns = -1;
236	}
237}
238
239char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
240{
241	char *rpath;
242	struct nscookie nsc;
243
244	nsinfo__mountns_enter(nsi, &nsc);
245	rpath = realpath(path, NULL);
246	nsinfo__mountns_exit(&nsc);
247
248	return rpath;
249}