]> git.proxmox.com Git - mirror_lxcfs.git/blame - utils.c
utils: split helpers from bindings.c into utils.{c,h}
[mirror_lxcfs.git] / utils.c
CommitLineData
1d81c6a6
CB
1#define __STDC_FORMAT_MACROS
2#include <errno.h>
3#include <fcntl.h>
4#include <inttypes.h>
5#include <sched.h>
6#include <stdarg.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/stat.h>
13#include <sys/types.h>
14#include <unistd.h>
15
16#include "config.h"
17#include "macro.h"
18#include "memory_utils.h"
19#include "utils.h"
20
21/*
22 * append the given formatted string to *src.
23 * src: a pointer to a char* in which to append the formatted string.
24 * sz: the number of characters printed so far, minus trailing \0.
25 * asz: the allocated size so far
26 * format: string format. See printf for details.
27 * ...: varargs. See printf for details.
28 */
29void must_strcat(char **src, size_t *sz, size_t *asz, const char *format, ...)
30{
31 char tmp[BUF_RESERVE_SIZE];
32 va_list args;
33
34 va_start (args, format);
35 int tmplen = vsnprintf(tmp, BUF_RESERVE_SIZE, format, args);
36 va_end(args);
37
38 if (!*src || tmplen + *sz + 1 >= *asz) {
39 char *tmp;
40 do {
41 tmp = realloc(*src, *asz + BUF_RESERVE_SIZE);
42 } while (!tmp);
43 *src = tmp;
44 *asz += BUF_RESERVE_SIZE;
45 }
46 memcpy((*src) +*sz , tmp, tmplen+1); /* include the \0 */
47 *sz += tmplen;
48}
49
50/**
51 * in_same_namespace - Check whether two processes are in the same namespace.
52 * @pid1 - PID of the first process.
53 * @pid2 - PID of the second process.
54 * @ns - Name of the namespace to check. Must correspond to one of the names
55 * for the namespaces as shown in /proc/<pid/ns/
56 *
57 * If the two processes are not in the same namespace returns an fd to the
58 * namespace of the second process identified by @pid2. If the two processes are
59 * in the same namespace returns -EINVAL, -1 if an error occurred.
60 */
61static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
62{
63 __do_close_prot_errno int ns_fd1 = -1, ns_fd2 = -1;
64 int ret = -1;
65 struct stat ns_st1, ns_st2;
66
67 ns_fd1 = preserve_ns(pid1, ns);
68 if (ns_fd1 < 0) {
69 /* The kernel does not support this namespace. This is not an
70 * error.
71 */
72 if (errno == ENOENT)
73 return -EINVAL;
74
75 return -1;
76 }
77
78 ns_fd2 = preserve_ns(pid2, ns);
79 if (ns_fd2 < 0)
80 return -1;
81
82 ret = fstat(ns_fd1, &ns_st1);
83 if (ret < 0)
84 return -1;
85
86 ret = fstat(ns_fd2, &ns_st2);
87 if (ret < 0)
88 return -1;
89
90 /* processes are in the same namespace */
91 if ((ns_st1.st_dev == ns_st2.st_dev) && (ns_st1.st_ino == ns_st2.st_ino))
92 return -EINVAL;
93
94 /* processes are in different namespaces */
95 return move_fd(ns_fd2);
96}
97
98bool is_shared_pidns(pid_t pid)
99{
100 if (pid != 1)
101 return false;
102
103 if (in_same_namespace(pid, getpid(), "pid") == -EINVAL)
104 return true;
105
106 return false;
107}
108
109int preserve_ns(const int pid, const char *ns)
110{
111 int ret;
112/* 5 /proc + 21 /int_as_str + 3 /ns + 20 /NS_NAME + 1 \0 */
113#define __NS_PATH_LEN 50
114 char path[__NS_PATH_LEN];
115
116 /* This way we can use this function to also check whether namespaces
117 * are supported by the kernel by passing in the NULL or the empty
118 * string.
119 */
120 ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
121 !ns || strcmp(ns, "") == 0 ? "" : "/",
122 !ns || strcmp(ns, "") == 0 ? "" : ns);
123 if (ret < 0 || (size_t)ret >= __NS_PATH_LEN) {
124 errno = EFBIG;
125 return -1;
126 }
127
128 return open(path, O_RDONLY | O_CLOEXEC);
129}