1 /*
2 * Copyright (C) Andrew Clayton
3 * Copyright (C) F5, Inc.
4 */
5
6 #include <nxt_main.h>
7
8 #include <nxt_cgroup.h>
9
10
11 static int nxt_mk_cgpath_relative(nxt_task_t *task, const char *dir,
12 char *cgpath);
13 static nxt_int_t nxt_mk_cgpath(nxt_task_t *task, const char *dir,
14 char *cgpath);
15
16
17 nxt_int_t
nxt_cgroup_proc_add(nxt_task_t * task,nxt_process_t * process)18 nxt_cgroup_proc_add(nxt_task_t *task, nxt_process_t *process)
19 {
20 int len;
21 char cgprocs[NXT_MAX_PATH_LEN];
22 FILE *fp;
23 nxt_int_t ret;
24
25 if (task->thread->runtime->type != NXT_PROCESS_MAIN
26 || nxt_process_type(process) != NXT_PROCESS_PROTOTYPE
27 || process->isolation.cgroup.path == NULL)
28 {
29 return NXT_OK;
30 }
31
32 ret = nxt_mk_cgpath(task, process->isolation.cgroup.path, cgprocs);
33 if (nxt_slow_path(ret == NXT_ERROR)) {
34 return NXT_ERROR;
35 }
36
37 ret = nxt_fs_mkdir_all((const u_char *) cgprocs, 0777);
38 if (nxt_slow_path(ret == NXT_ERROR)) {
39 return NXT_ERROR;
40 }
41
42 len = strlen(cgprocs);
43
44 len = snprintf(cgprocs + len, NXT_MAX_PATH_LEN - len, "/cgroup.procs");
45 if (nxt_slow_path(len >= NXT_MAX_PATH_LEN - len)) {
46 nxt_errno = ENAMETOOLONG;
47 return NXT_ERROR;
48 }
49
50 fp = nxt_file_fopen(task, cgprocs, "we");
51 if (nxt_slow_path(fp == NULL)) {
52 return NXT_ERROR;
53 }
54
55 setvbuf(fp, NULL, _IONBF, 0);
56 len = fprintf(fp, "%d\n", process->pid);
57 nxt_file_fclose(task, fp);
58
59 if (nxt_slow_path(len < 0)) {
60 return NXT_ERROR;
61 }
62
63 return NXT_OK;
64 }
65
66
67 void
nxt_cgroup_cleanup(nxt_task_t * task,const nxt_process_t * process)68 nxt_cgroup_cleanup(nxt_task_t *task, const nxt_process_t *process)
69 {
70 char *ptr;
71 char cgroot[NXT_MAX_PATH_LEN], cgpath[NXT_MAX_PATH_LEN];
72 nxt_int_t ret;
73
74 ret = nxt_mk_cgpath(task, "", cgroot);
75 if (nxt_slow_path(ret == NXT_ERROR)) {
76 return;
77 }
78
79 ret = nxt_mk_cgpath(task, process->isolation.cgroup.path, cgpath);
80 if (nxt_slow_path(ret == NXT_ERROR)) {
81 return;
82 }
83
84 while (*cgpath != '\0' && strcmp(cgroot, cgpath) != 0) {
85 rmdir(cgpath);
86 ptr = strrchr(cgpath, '/');
87 *ptr = '\0';
88 }
89 }
90
91
92 static int
nxt_mk_cgpath_relative(nxt_task_t * task,const char * dir,char * cgpath)93 nxt_mk_cgpath_relative(nxt_task_t *task, const char *dir, char *cgpath)
94 {
95 int i, len;
96 char *buf, *ptr;
97 FILE *fp;
98 size_t size;
99 ssize_t nread;
100 nxt_bool_t found;
101
102 fp = nxt_file_fopen(task, "/proc/self/cgroup", "re");
103 if (nxt_slow_path(fp == NULL)) {
104 return -1;
105 }
106
107 len = -1;
108 buf = NULL;
109 found = 0;
110 while ((nread = getline(&buf, &size, fp)) != -1) {
111 if (strncmp(buf, "0::", 3) == 0) {
112 found = 1;
113 break;
114 }
115 }
116
117 nxt_file_fclose(task, fp);
118
119 if (!found) {
120 nxt_errno = ENODATA;
121 goto out_free_buf;
122 }
123
124 buf[nread - 1] = '\0'; /* lose the trailing '\n' */
125 ptr = buf;
126 for (i = 0; i < 2; i++) {
127 ptr = strchr(ptr, ':');
128 if (ptr == NULL) {
129 nxt_errno = ENODATA;
130 goto out_free_buf;
131 }
132
133 ptr++;
134 }
135
136 len = snprintf(cgpath, NXT_MAX_PATH_LEN, NXT_CGROUP_ROOT "%s/%s",
137 ptr, dir);
138
139 out_free_buf:
140
141 nxt_free(buf);
142
143 return len;
144 }
145
146
147 static nxt_int_t
nxt_mk_cgpath(nxt_task_t * task,const char * dir,char * cgpath)148 nxt_mk_cgpath(nxt_task_t *task, const char *dir, char *cgpath)
149 {
150 int len;
151
152 /*
153 * If the path from the config is relative, we need to make
154 * the cgroup path include the main unit processes cgroup. I.e
155 *
156 * NXT_CGROUP_ROOT/<main process cgroup>/<cgroup path>
157 */
158 if (dir[0] != '/') {
159 len = nxt_mk_cgpath_relative(task, dir, cgpath);
160 } else {
161 len = snprintf(cgpath, NXT_MAX_PATH_LEN, NXT_CGROUP_ROOT "%s", dir);
162 }
163
164 if (len == -1) {
165 return NXT_ERROR;
166 }
167
168 if (len >= NXT_MAX_PATH_LEN) {
169 nxt_errno = ENAMETOOLONG;
170 return NXT_ERROR;
171 }
172
173 return NXT_OK;
174 }
175