root/tools/perf/util/namespaces.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perf_ns__name
  2. namespaces__new
  3. namespaces__free
  4. nsinfo__init
  5. nsinfo__new
  6. nsinfo__copy
  7. nsinfo__delete
  8. nsinfo__get
  9. nsinfo__put
  10. nsinfo__mountns_enter
  11. nsinfo__mountns_exit
  12. nsinfo__realpath

   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 
  23 static 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 
  33 const 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 
  40 struct 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 
  58 void namespaces__free(struct namespaces *namespaces)
  59 {
  60         free(namespaces);
  61 }
  62 
  63 int 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 
 122 out:
 123         if (f != NULL)
 124                 (void) fclose(f);
 125         free(statln);
 126         free(newns);
 127         return rv;
 128 }
 129 
 130 struct 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 
 156 struct 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 
 182 void nsinfo__delete(struct nsinfo *nsi)
 183 {
 184         zfree(&nsi->mntns_path);
 185         free(nsi);
 186 }
 187 
 188 struct nsinfo *nsinfo__get(struct nsinfo *nsi)
 189 {
 190         if (nsi)
 191                 refcount_inc(&nsi->refcnt);
 192         return nsi;
 193 }
 194 
 195 void nsinfo__put(struct nsinfo *nsi)
 196 {
 197         if (nsi && refcount_dec_and_test(&nsi->refcnt))
 198                 nsinfo__delete(nsi);
 199 }
 200 
 201 void 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 
 241 errout:
 242         free(oldcwd);
 243         if (oldns > -1)
 244                 close(oldns);
 245         if (newns > -1)
 246                 close(newns);
 247 }
 248 
 249 void 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 
 272 char *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 }

/* [<][>][^][v][top][bottom][index][help] */