0001
0002
0003
0004
0005
0006
0007 #include "namespaces.h"
0008 #include "event.h"
0009 #include "get_current_dir_name.h"
0010 #include <sys/types.h>
0011 #include <sys/stat.h>
0012 #include <fcntl.h>
0013 #include <limits.h>
0014 #include <sched.h>
0015 #include <stdlib.h>
0016 #include <stdio.h>
0017 #include <string.h>
0018 #include <unistd.h>
0019 #include <asm/bug.h>
0020 #include <linux/kernel.h>
0021 #include <linux/zalloc.h>
0022
0023 static const char *perf_ns__names[] = {
0024 [NET_NS_INDEX] = "net",
0025 [UTS_NS_INDEX] = "uts",
0026 [IPC_NS_INDEX] = "ipc",
0027 [PID_NS_INDEX] = "pid",
0028 [USER_NS_INDEX] = "user",
0029 [MNT_NS_INDEX] = "mnt",
0030 [CGROUP_NS_INDEX] = "cgroup",
0031 };
0032
0033 const char *perf_ns__name(unsigned int id)
0034 {
0035 if (id >= ARRAY_SIZE(perf_ns__names))
0036 return "UNKNOWN";
0037 return perf_ns__names[id];
0038 }
0039
0040 struct namespaces *namespaces__new(struct perf_record_namespaces *event)
0041 {
0042 struct namespaces *namespaces;
0043 u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
0044 sizeof(struct perf_ns_link_info));
0045
0046 namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
0047 if (!namespaces)
0048 return NULL;
0049
0050 namespaces->end_time = -1;
0051
0052 if (event)
0053 memcpy(namespaces->link_info, event->link_info, link_info_size);
0054
0055 return namespaces;
0056 }
0057
0058 void namespaces__free(struct namespaces *namespaces)
0059 {
0060 free(namespaces);
0061 }
0062
0063 static int nsinfo__get_nspid(struct nsinfo *nsi, const char *path)
0064 {
0065 FILE *f = NULL;
0066 char *statln = NULL;
0067 size_t linesz = 0;
0068 char *nspid;
0069
0070 f = fopen(path, "r");
0071 if (f == NULL)
0072 return -1;
0073
0074 while (getline(&statln, &linesz, f) != -1) {
0075
0076 if (strstr(statln, "Tgid:") != NULL) {
0077 nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
0078 NULL, 10);
0079 nsi->nstgid = nsinfo__tgid(nsi);
0080 }
0081
0082 if (strstr(statln, "NStgid:") != NULL) {
0083 nspid = strrchr(statln, '\t');
0084 nsi->nstgid = (pid_t)strtol(nspid, NULL, 10);
0085
0086
0087
0088
0089 nsi->in_pidns = (statln + sizeof("NStgid:") - 1) != nspid;
0090 break;
0091 }
0092 }
0093
0094 fclose(f);
0095 free(statln);
0096 return 0;
0097 }
0098
0099 int nsinfo__init(struct nsinfo *nsi)
0100 {
0101 char oldns[PATH_MAX];
0102 char spath[PATH_MAX];
0103 char *newns = NULL;
0104 struct stat old_stat;
0105 struct stat new_stat;
0106 int rv = -1;
0107
0108 if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
0109 return rv;
0110
0111 if (asprintf(&newns, "/proc/%d/ns/mnt", nsinfo__pid(nsi)) == -1)
0112 return rv;
0113
0114 if (stat(oldns, &old_stat) < 0)
0115 goto out;
0116
0117 if (stat(newns, &new_stat) < 0)
0118 goto out;
0119
0120
0121
0122
0123 if (old_stat.st_ino != new_stat.st_ino) {
0124 nsi->need_setns = true;
0125 nsi->mntns_path = newns;
0126 newns = NULL;
0127 }
0128
0129
0130
0131
0132 if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsinfo__pid(nsi)) >= PATH_MAX)
0133 goto out;
0134
0135 rv = nsinfo__get_nspid(nsi, spath);
0136
0137 out:
0138 free(newns);
0139 return rv;
0140 }
0141
0142 struct nsinfo *nsinfo__new(pid_t pid)
0143 {
0144 struct nsinfo *nsi;
0145
0146 if (pid == 0)
0147 return NULL;
0148
0149 nsi = calloc(1, sizeof(*nsi));
0150 if (nsi != NULL) {
0151 nsi->pid = pid;
0152 nsi->tgid = pid;
0153 nsi->nstgid = pid;
0154 nsi->need_setns = false;
0155 nsi->in_pidns = false;
0156
0157
0158
0159
0160 if (nsinfo__init(nsi) == -1)
0161 nsi->need_setns = false;
0162
0163 refcount_set(&nsi->refcnt, 1);
0164 }
0165
0166 return nsi;
0167 }
0168
0169 struct nsinfo *nsinfo__copy(const struct nsinfo *nsi)
0170 {
0171 struct nsinfo *nnsi;
0172
0173 if (nsi == NULL)
0174 return NULL;
0175
0176 nnsi = calloc(1, sizeof(*nnsi));
0177 if (nnsi != NULL) {
0178 nnsi->pid = nsinfo__pid(nsi);
0179 nnsi->tgid = nsinfo__tgid(nsi);
0180 nnsi->nstgid = nsinfo__nstgid(nsi);
0181 nnsi->need_setns = nsinfo__need_setns(nsi);
0182 nnsi->in_pidns = nsinfo__in_pidns(nsi);
0183 if (nsi->mntns_path) {
0184 nnsi->mntns_path = strdup(nsi->mntns_path);
0185 if (!nnsi->mntns_path) {
0186 free(nnsi);
0187 return NULL;
0188 }
0189 }
0190 refcount_set(&nnsi->refcnt, 1);
0191 }
0192
0193 return nnsi;
0194 }
0195
0196 static void nsinfo__delete(struct nsinfo *nsi)
0197 {
0198 zfree(&nsi->mntns_path);
0199 free(nsi);
0200 }
0201
0202 struct nsinfo *nsinfo__get(struct nsinfo *nsi)
0203 {
0204 if (nsi)
0205 refcount_inc(&nsi->refcnt);
0206 return nsi;
0207 }
0208
0209 void nsinfo__put(struct nsinfo *nsi)
0210 {
0211 if (nsi && refcount_dec_and_test(&nsi->refcnt))
0212 nsinfo__delete(nsi);
0213 }
0214
0215 bool nsinfo__need_setns(const struct nsinfo *nsi)
0216 {
0217 return nsi->need_setns;
0218 }
0219
0220 void nsinfo__clear_need_setns(struct nsinfo *nsi)
0221 {
0222 nsi->need_setns = false;
0223 }
0224
0225 pid_t nsinfo__tgid(const struct nsinfo *nsi)
0226 {
0227 return nsi->tgid;
0228 }
0229
0230 pid_t nsinfo__nstgid(const struct nsinfo *nsi)
0231 {
0232 return nsi->nstgid;
0233 }
0234
0235 pid_t nsinfo__pid(const struct nsinfo *nsi)
0236 {
0237 return nsi->pid;
0238 }
0239
0240 pid_t nsinfo__in_pidns(const struct nsinfo *nsi)
0241 {
0242 return nsi->in_pidns;
0243 }
0244
0245 void nsinfo__mountns_enter(struct nsinfo *nsi,
0246 struct nscookie *nc)
0247 {
0248 char curpath[PATH_MAX];
0249 int oldns = -1;
0250 int newns = -1;
0251 char *oldcwd = NULL;
0252
0253 if (nc == NULL)
0254 return;
0255
0256 nc->oldns = -1;
0257 nc->newns = -1;
0258
0259 if (!nsi || !nsi->need_setns)
0260 return;
0261
0262 if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
0263 return;
0264
0265 oldcwd = get_current_dir_name();
0266 if (!oldcwd)
0267 return;
0268
0269 oldns = open(curpath, O_RDONLY);
0270 if (oldns < 0)
0271 goto errout;
0272
0273 newns = open(nsi->mntns_path, O_RDONLY);
0274 if (newns < 0)
0275 goto errout;
0276
0277 if (setns(newns, CLONE_NEWNS) < 0)
0278 goto errout;
0279
0280 nc->oldcwd = oldcwd;
0281 nc->oldns = oldns;
0282 nc->newns = newns;
0283 return;
0284
0285 errout:
0286 free(oldcwd);
0287 if (oldns > -1)
0288 close(oldns);
0289 if (newns > -1)
0290 close(newns);
0291 }
0292
0293 void nsinfo__mountns_exit(struct nscookie *nc)
0294 {
0295 if (nc == NULL || nc->oldns == -1 || nc->newns == -1 || !nc->oldcwd)
0296 return;
0297
0298 setns(nc->oldns, CLONE_NEWNS);
0299
0300 if (nc->oldcwd) {
0301 WARN_ON_ONCE(chdir(nc->oldcwd));
0302 zfree(&nc->oldcwd);
0303 }
0304
0305 if (nc->oldns > -1) {
0306 close(nc->oldns);
0307 nc->oldns = -1;
0308 }
0309
0310 if (nc->newns > -1) {
0311 close(nc->newns);
0312 nc->newns = -1;
0313 }
0314 }
0315
0316 char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
0317 {
0318 char *rpath;
0319 struct nscookie nsc;
0320
0321 nsinfo__mountns_enter(nsi, &nsc);
0322 rpath = realpath(path, NULL);
0323 nsinfo__mountns_exit(&nsc);
0324
0325 return rpath;
0326 }
0327
0328 int nsinfo__stat(const char *filename, struct stat *st, struct nsinfo *nsi)
0329 {
0330 int ret;
0331 struct nscookie nsc;
0332
0333 nsinfo__mountns_enter(nsi, &nsc);
0334 ret = stat(filename, st);
0335 nsinfo__mountns_exit(&nsc);
0336
0337 return ret;
0338 }
0339
0340 bool nsinfo__is_in_root_namespace(void)
0341 {
0342 struct nsinfo nsi;
0343
0344 memset(&nsi, 0x0, sizeof(nsi));
0345 nsinfo__get_nspid(&nsi, "/proc/self/status");
0346 return !nsi.in_pidns;
0347 }