Re-organized sub-directory by category
[staging/basesystem.git] / service / native / common_library / client / src / cl_process.c
1 /*
2  * @copyright Copyright (c) 2016-2020 TOYOTA MOTOR CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <errno.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <sched.h>
26 #include <semaphore.h>
27 #include <pthread.h>
28 #include <limits.h>
29 #include <sys/prctl.h>
30 #include <sys/signalfd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 #include <sys/syscall.h>
35 #include <sys/time.h>
36 #include <sys/resource.h>
37
38 #include <native_service/cl_process.h>
39 #include "cl_process_internal.h"
40 #include "cl_error.h"
41 #include "cl_cgroup.h"
42 #include "cl_monitor_internal.h"
43
44 #define assert_static(e) \
45   do { \
46     enum { assert_static__ = 1/(e) }; \
47   } while (0)
48
49 struct linux_dirent64 {
50   ino64_t        d_ino;
51   off64_t        d_off;
52   unsigned short d_reclen;
53   unsigned char  d_type;
54   char           d_name[];
55 };
56
57 /*
58  * Initialize the process
59  */
60 int CL_ProcessInit(void) {
61   int sfd = -1;
62   char *name;
63   sigset_t mask;
64
65   assert_static(sizeof(CL_ProcessAttr_t) == sizeof(CL_ProcessAttrInternal_t));
66
67   name = getenv(CL_PROCESS_NAME_ENV);
68   if (name != NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getenv
69     if (prctl(PR_SET_NAME, name) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getenv
70       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
71
72       CL_PERROR("prctl"); // LCOV_EXCL_LINE 5: fail safe for libc getenv
73       goto exit; // LCOV_EXCL_LINE 5: fail safe for libc getenv
74     }
75   }
76
77   if (sigemptyset(&mask) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigemptyset
78     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
79
80     CL_PERROR("sigemptyset"); // LCOV_EXCL_LINE 5: fail safe for libc sigemptyset
81     goto exit;                // LCOV_EXCL_LINE 5: fail safe for libc sigemptyset
82   }
83   if (sigaddset(&mask, SIGCHLD) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigaddset
84     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
85
86     CL_PERROR("sigaddset");   // LCOV_EXCL_LINE 5: fail safe for libc sigaddset
87     goto exit;                // LCOV_EXCL_LINE 5: fail safe for libc sigaddset
88   }
89   if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sigprocmask
90     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
91
92     CL_PERROR("sigprocmask"); // LCOV_EXCL_LINE 5: fail safe for libc sigprocmask
93     goto exit;                // LCOV_EXCL_LINE 5: fail safe for libc sigprocmask
94   }
95
96   if ((sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC)) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc signalfd
97     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
98
99     CL_PERROR("signalfd");    // LCOV_EXCL_LINE 5: fail safe for libc signalfd
100     goto exit;                // LCOV_EXCL_LINE 5: fail safe for libc signalfd
101   }
102
103 exit:
104   return sfd;
105 }
106
107 /*
108  * start of the functions to be executed from fork to exec
109  */
110 static void cl_process_pf_err(char no) {
111   char errorstr[17] = "err:post_fork:0\n";
112
113   errorstr[14] = no;
114   while (1) {
115     if (write(STDERR_FILENO, errorstr, 16) == -1 && errno == EINTR) { // LCOV_EXCL_BR_LINE 5: fail safe for libc write
116       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
117       continue; // LCOV_EXCL_LINE 5: fail safe for libc write
118     }
119     break;
120   }
121 }
122
123 static inline int cl_process_pf_set_schedule(const CL_ProcessAttrInternal_t *ia) {
124   int ret = -1;
125   struct sched_param param;
126   int policy;
127
128   switch (ia->sched_policy) {
129     case CL_PROCESS_SCHED_POLICY_RR:
130       policy = SCHED_RR;
131       param.sched_priority = ia->sched_priority;
132       break;
133     case CL_PROCESS_SCHED_POLICY_FIFO:
134       param.sched_priority = ia->sched_priority;
135       policy = SCHED_FIFO;
136       break;
137     default:
138       param.sched_priority = 0;
139       policy = SCHED_OTHER;
140       break;
141   }
142   if (sched_setscheduler(getpid(), policy, &param) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function sched_setscheduler
143     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
144     cl_process_pf_err('3');// LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
145     goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
146   }
147   if (ia->sched_policy == CL_PROCESS_SCHED_POLICY_OTHER) {
148     if (setpriority(PRIO_PROCESS, (__id_t)getpid(), ia->sched_priority) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setpriority
149       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
150
151       cl_process_pf_err('4');// LCOV_EXCL_LINE 5: fail safe for glibc function setpriority
152       goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function setpriority
153     }
154   }
155   ret = 0;
156
157 exit:
158   return ret;
159 }
160
161 static inline int cl_process_pf_check_close_fd(int check_fd, int dirfd, int hold_fds_num, const int *hold_fds) {
162   int i;
163
164   if (check_fd < 3 || check_fd == dirfd) {
165     return 0;
166   }
167
168   for (i = 0; i < hold_fds_num; i++) {
169     if (check_fd == *(hold_fds + i)) {
170       return 0;
171     }
172   }
173
174   return 1;
175 }
176
177 static inline int cl_process_pf_fname2fd(const char *s) {
178   int result = 0;
179   for (; *s != '\0'; s++) {
180     result = result * 10 + (*s - '0');
181   }
182   return result;
183 }
184
185 static inline int cl_process_pf_cleanup_fds(const CL_ProcessAttrInternal_t *ia) {
186   int ret = -1;
187   int dfd;
188 #define BUF_SIZE 128
189   char buf[BUF_SIZE];
190   struct linux_dirent64 *d;
191   int hold_fds_num, i;
192
193   for (i = 0; i < CL_PROCESSS_ATTR_HOLD_FDS_NUM; i++) {
194     if (ia->hold_fds[i] == 0) {
195       break;
196     }
197   }
198   hold_fds_num = i;
199
200   if ((dfd = open("/proc/self/fd/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function open
201     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
202
203     cl_process_pf_err('8');// LCOV_EXCL_LINE 5: fail safe for glibc function open
204     goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function open
205   }
206
207   while (1) {
208     long nread;
209     int fd;
210     int bpos;
211
212     nread = syscall(SYS_getdents64, dfd, buf, sizeof(buf));
213     if (nread == -1) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function syscall
214       // LCOV_EXCL_START 5: fail safe for glibc function syscall
215
216       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
217
218       cl_process_pf_err('9');
219       close(dfd);
220       goto exit;
221     }
222     // LCOV_EXCL_STOP
223
224     if (nread == 0) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function syscall
225       break;
226     }
227
228     for (bpos = 0; bpos < nread;) {
229       d = (struct linux_dirent64 *)(buf + bpos);
230       fd = cl_process_pf_fname2fd(d->d_name);
231       if (cl_process_pf_check_close_fd(fd, dfd, hold_fds_num, ia->hold_fds)) {
232         close(fd);
233       }
234       bpos += d->d_reclen;
235     }
236   }
237   close(dfd);
238   ret = 0;
239
240 exit:
241   return ret;
242 }
243
244 static void cl_process_post_fork(const char *file, char *const argv[], char *const envp[],
245                                  const CL_ProcessAttrInternal_t *ia) {
246   int intfy_fd;
247   char intfy_fname[32] = "/tmp/intfy_00000";
248   pid_t pid = getpid();
249
250   intfy_fname[11] = (char)(intfy_fname[11] + (pid / 10000));
251   intfy_fname[12] = (char)(intfy_fname[12] + ((pid / 1000) % 10));
252   intfy_fname[13] = (char)(intfy_fname[13] + ((pid / 100) % 10));
253   intfy_fname[14] = (char)(intfy_fname[14] + ((pid / 10) % 10));
254   intfy_fname[15] = (char)(intfy_fname[15] + (pid % 10));
255
256   unlink(intfy_fname);
257   if ((intfy_fd = open(intfy_fname, O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666)) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function open
258     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
259     cl_process_pf_err('0'); // LCOV_EXCL_LINE 5:libc fail safe for open
260     goto exit;              // LCOV_EXCL_LINE 5:libc fail safe for open
261   }
262   if (close(intfy_fd) < 0) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function close
263     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
264     cl_process_pf_err('1');  // LCOV_EXCL_LINE 5:libc fail safe for close
265     goto exit;  // LCOV_EXCL_LINE 5:libc fail safe for close
266   }
267
268   // Process group
269   if (ia->create_group) {
270     if (setpgid(getpid(), getpid()) < 0) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setpgid
271       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
272       cl_process_pf_err('2');  // LCOV_EXCL_LINE 5: fail safe for glibc function setpgid
273       goto exit;  // LCOV_EXCL_LINE 5: fail safe for glibc function setpgid
274     }
275   }
276
277   // Scheduling Policy/Priority
278   if (cl_process_pf_set_schedule(ia) < 0) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function sched_setscheduler
279     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
280     goto exit;  // LCOV_EXCL_LINE 5: fail safe for glibc function sched_setscheduler
281   }
282
283   // UID/GID
284   if (ia->gid) {
285     if (setgid(ia->gid) < 0) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function setgid
286       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
287       cl_process_pf_err('5');  // LCOV_EXCL_LINE 5: fail safe for glibc function setgid
288       goto exit;  // LCOV_EXCL_LINE 5: fail safe for glibc function setgid
289     }
290   }
291
292   if (ia->uid) {
293     uid_t uid = (ia->uid == UINT_MAX) ? 0 : ia->uid;
294     if (setuid(uid) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function setuid
295       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
296       cl_process_pf_err('6');// LCOV_EXCL_LINE 5: fail safe for glibc function setuid
297       goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function setuid
298     }
299   }
300
301   // stack size
302   if (ia->stack_size) {
303     struct rlimit rlim;
304     getrlimit(RLIMIT_STACK, &rlim);
305     rlim.rlim_cur = (rlim_t)ia->stack_size;
306     if (setrlimit(RLIMIT_STACK, &rlim) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function setrlimit
307       AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
308
309       cl_process_pf_err('7');// LCOV_EXCL_LINE 5: fail safe for glibc function setrlimit
310     }
311   }
312
313   // cleanup fds
314   if (ia->disable_close_fds == 0) {
315     if (cl_process_pf_cleanup_fds(ia) < 0) {
316       goto exit;
317     }
318   }
319
320   // exec
321   if (execve(file, argv, envp) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function execve
322     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
323     cl_process_pf_err('A');// LCOV_EXCL_LINE 5: fail safe for glibc function execve
324   }
325
326 exit:
327   return;
328 }
329 /*
330  * end of the functions to be executed from fork to exec
331  */
332
333 static int cl_process_pre_fork(char *const envp[], char ***new_env, const CL_ProcessAttrInternal_t *ia) {
334   int i;
335   size_t envlen = 0;
336   char **e;
337   char *b;
338   int new_env_count;
339   size_t name_env_len = strlen(CL_PROCESS_NAME_ENV);
340   int last_name_env_pos = -1;
341
342   if (envp == NULL) {
343     e = environ;
344   } else {
345     e = (char **)envp;
346   }
347
348   for (i = 0; e[i] != NULL; i++) {
349     if (strncmp(e[i], CL_PROCESS_NAME_ENV, name_env_len) == 0) {
350       last_name_env_pos = i;
351     } else {
352       envlen += strlen(e[i]) + 1;
353     }
354   }
355
356   if (ia->name[0] != 0) {
357     envlen += strlen(CL_PROCESS_NAME_ENV) + 1 + strlen(ia->name) + 1;
358     i++;
359   }
360
361   if ((b = malloc(envlen)) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
362     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
363     CL_ERR_PRINT("malloc fail"); // LCOV_EXCL_LINE 5: fail safe for libc malloc
364     errno = EFAULT;              // LCOV_EXCL_LINE 5: fail safe for libc malloc
365     goto error;                  // LCOV_EXCL_LINE 5: fail safe for libc malloc
366   }
367   memset(b, 0, envlen);
368
369   if ((*new_env = malloc(sizeof(char *) * (size_t)(i + 1))) == NULL) {    // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
370     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
371     free(b);                      // LCOV_EXCL_LINE 5: fail safe for libc malloc
372     CL_ERR_PRINT("malloc fail");  // LCOV_EXCL_LINE 5: fail safe for libc malloc
373     errno = EFAULT;               // LCOV_EXCL_LINE 5: fail safe for libc malloc
374     goto error;                   // LCOV_EXCL_LINE 5: fail safe for libc malloc
375   }
376   memset(*new_env, 0, sizeof(char *) * (size_t)(i + 1));
377
378   new_env_count = 0;
379   for (i = 0; e[i] != NULL; i++) {
380     if (i == last_name_env_pos) {
381       continue;
382     }
383     strcpy(b, e[i]);
384     *(*new_env + i) = b;
385     b += strlen(e[i]) + 1;
386     new_env_count++;
387   }
388
389   if (ia->name[0] != 0) {
390     *(*new_env + new_env_count) = b;
391     b += sprintf(b, "%s=%s", CL_PROCESS_NAME_ENV, ia->name);
392     b++;
393     new_env_count++;
394   }
395
396   return 0;
397
398 error:
399   return -1;
400 }
401
402 /*
403  * Create process
404  */
405 int CL_ProcessCreate(const char *file, char *const argv[], char *const envp[], const CL_ProcessAttr_t *attr) {
406   const CL_ProcessAttrInternal_t *ia = (const CL_ProcessAttrInternal_t *)attr;
407   pid_t childpid;
408   char intfy_fname[32];
409   char **new_env;
410   int ret;
411   int retry;
412   int i = 0;
413
414   if (file == NULL || argv == NULL || attr == NULL) {
415     errno = EINVAL;
416     return -1;
417   }
418
419   if (cl_process_pre_fork(envp, &new_env, ia) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc function malloc
420     return -1;
421   }
422
423   childpid = fork();
424   switch (childpid) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function fork
425     case 0: /* child process */
426       cl_process_post_fork(file, argv, new_env, ia);
427       _exit(CL_PROCESS_EXIT_INTERNAL);
428       break;
429
430     case -1: /* error */
431       goto exit;
432
433     default: /* parent process */
434       break;
435   }
436
437   if (ia->cpu_assign != 0) {
438     cpu_set_t set;
439     CPU_ZERO(&set);
440     for (i = 0; i < (sizeof(ia->cpu_assign) * 8); i++) {
441       if ((ia->cpu_assign >> i) & 0x1) {
442         CPU_SET(i, &set);
443       }
444     }
445     // LCOV_EXCL_BR_START 5: fail safe for libc sched_setaffinity
446     if (sched_setaffinity(childpid, sizeof(set), &set) < 0) {
447       // LCOV_EXCL_BR_STOP
448       int last_errno = errno;
449       CL_PERROR("sched_setaffinity");
450       errno = last_errno;
451       childpid = -1;
452       goto exit;
453     }
454   }
455
456   ret = snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, childpid);
457   if (ret < 0 || ret > sizeof(intfy_fname)) {// LCOV_EXCL_BR_LINE 5: fail safe for libc snprintf
458     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
459     CL_ERR_PRINT("snprintf fail:%d", ret);  // LCOV_EXCL_LINE 5: fail safe for libc snprintf
460     childpid = -1;                          // LCOV_EXCL_LINE 5: fail safe for libc snprintf
461     goto exit;                              // LCOV_EXCL_LINE 5: fail safe for libc snprintf
462   }
463
464   if (ia->cgroup_name[0] != '\0') {
465     if (cl_cgroup_exist(CL_CGROUP_CPU, ia->cgroup_name) == 0) {
466       if (cl_cgroup_set_num(CL_CGROUP_CPU, ia->cgroup_name, "tasks", childpid) < 0) {
467         int last_errno = errno;
468         CL_PERROR("cl_cgroup_set_num");
469         errno = last_errno;
470         childpid = -1;
471         goto exit;
472       }
473     }
474     // LCOV_EXCL_BR_START 5: fail safe for glibc function access
475     if (cl_cgroup_exist(CL_CGROUP_MEMORY, ia->cgroup_name) == 0) {
476       // LCOV_EXCL_BR_STOP
477       if (cl_cgroup_set_num(CL_CGROUP_MEMORY, ia->cgroup_name, "tasks", childpid) < 0) {
478         int last_errno = errno;
479         CL_PERROR("cl_cgroup_set_num");
480         errno = last_errno;
481         childpid = -1;
482         goto exit;
483       }
484     }
485   }
486
487   for (retry = 100; retry >= 0; retry--) {
488     if (access(intfy_fname, F_OK) == 0) {  // LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
489       break;
490     }
491     usleep(100);
492   }
493
494 exit:
495   free(new_env[0]);
496   free(new_env);
497
498   return childpid;
499 }
500
501 /*
502  * Initialize process attribute
503  */
504 int CL_ProcessCreateAttrInit(CL_ProcessAttr_t *attr) {
505   if (attr == NULL) {
506     errno = EINVAL;
507     return -1;
508   }
509
510   memset(attr, 0, sizeof(CL_ProcessAttr_t));
511   return 0;
512 }
513
514 /*
515  * Set process attribute (process name)
516  */
517 int CL_ProcessCreateAttrSetName(CL_ProcessAttr_t *attr, const char *name) {
518   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
519
520   if (attr == NULL || name == NULL) {
521     errno = EINVAL;
522     return -1;
523   }
524
525   strncpy(ia->name, name, 16);
526   ia->name[15] = 0;
527
528   return 0;
529 }
530
531 /*
532  * Set process attribute (user ID)
533  */
534 int CL_ProcessCreateAttrSetUid(CL_ProcessAttr_t *attr, uid_t uid) {
535   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
536
537   if (attr == NULL) {
538     errno = EINVAL;
539     return -1;
540   }
541
542   ia->uid = uid;
543
544   return 0;
545 }
546
547 /*
548  * Set process attribute (group ID)
549  */
550 int CL_ProcessCreateAttrSetGid(CL_ProcessAttr_t *attr, gid_t gid) {
551   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
552
553   if (attr == NULL) {
554     errno = EINVAL;
555     return -1;
556   }
557
558   ia->gid = gid;
559
560   return 0;
561 }
562
563 /*
564  * Set process attribute (schedule policy and priority)
565  */
566 int CL_ProcessCreateAttrSetSchedule(CL_ProcessAttr_t *attr, CL_ProcessSchedPolicy_t policy, int priority) {
567   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
568
569   if (attr == NULL) {
570     errno = EINVAL;
571     return -1;
572   }
573
574   if (policy == CL_PROCESS_SCHED_POLICY_RR || policy == CL_PROCESS_SCHED_POLICY_FIFO) {
575     if (priority < 1 || priority > 99) {
576       errno = EINVAL;
577       return -1;
578     }
579   } else if (policy == CL_PROCESS_SCHED_POLICY_OTHER) {
580     if (priority < -20 || priority > 19) {
581       CL_ERR_PRINT("Invlid SCHED_OTHER priority:%d", priority);
582     }
583   } else {
584     errno = EINVAL;
585     return -1;
586   }
587
588   ia->sched_policy = policy;
589   ia->sched_priority = priority;
590
591   return 0;
592 }
593
594 /*
595  * Set process attribute (process group)
596  */
597 int CL_ProcessCreateAttrSetGroup(CL_ProcessAttr_t *attr, int create) {
598   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
599
600   if (attr == NULL) {
601     errno = EINVAL;
602     return -1;
603   }
604
605   if (create < 0 || create > 1) {
606     errno = EINVAL;
607     return -1;
608   }
609
610   ia->create_group = create;
611
612   return 0;
613 }
614
615 static int32_t CL_CpuAssignMsbCpu(int cpu_assign) {
616   int32_t i;
617   int32_t ret = 0;
618
619   for (i = 0; i < (sizeof(cpu_assign) * 8); i++) {
620     if ((cpu_assign >> i) & 0x1)
621       ret = i;
622   }
623
624   return ret;
625 }
626
627 /**
628  * Set process attribute (CPU Assign)
629  */
630 int CL_ProcessCreateAttrSetCpuAssign(CL_ProcessAttr_t *attr, int cpu_assign) {
631   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
632
633   if (attr == NULL) {
634     errno = EINVAL;
635     return -1;
636   }
637
638   if (cpu_assign < 0) {
639     errno = EINVAL;
640     return -1;
641   }
642
643   if (CL_CpuAssignMsbCpu(cpu_assign) >= sysconf(_SC_NPROCESSORS_CONF)) {
644     errno = EINVAL;
645     return -1;
646   }
647
648   ia->cpu_assign = cpu_assign;
649
650   return 0;
651 }
652
653 /*
654  * Set process attribute (Stack Size)
655  */
656 int CL_ProcessCreateAttrSetStackSize(CL_ProcessAttr_t *attr, int stack_size) {
657   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
658
659   if (attr == NULL) {
660     errno = EINVAL;
661     return -1;
662   }
663
664   ia->stack_size = stack_size;
665
666   return 0;
667 }
668
669 /*
670  * Set process attribute (FD to maintain)
671  */
672 int CL_ProcessCreateAttrSetHoldFds(CL_ProcessAttr_t *attr, int hold_fds[]) {
673   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
674
675   if (attr == NULL || hold_fds == NULL) {
676     errno = EINVAL;
677     return -1;
678   }
679
680   memcpy(ia->hold_fds, hold_fds, sizeof(ia->hold_fds));
681
682   return 0;
683 }
684
685 /*
686  * Set process attribute (to suspend forced FD close)
687  */
688 int CL_ProcessCreateAttrSetDisableCloseFds(CL_ProcessAttr_t *attr) {
689   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
690
691   if (attr == NULL) {
692     errno = EINVAL;
693     return -1;
694   }
695
696   ia->disable_close_fds = 1;
697
698   return 0;
699 }
700
701 /*
702  * Set process attribute (Cgroup)
703  */
704 int CL_ProcessCreateAttrSetCgroup(CL_ProcessAttr_t *attr, const char *cgroup_name) {
705   CL_ProcessAttrInternal_t *ia = (CL_ProcessAttrInternal_t *)attr;
706
707   if (attr == NULL || cgroup_name  == NULL) {
708     errno = EINVAL;
709     return -1;
710   }
711
712   if (strlen(cgroup_name) >= sizeof(ia->cgroup_name)) {
713     errno = EINVAL;
714     return -1;
715   }
716
717   strcpy(ia->cgroup_name, cgroup_name);
718
719   return 0;
720 }
721
722 /*
723  * Kill process
724  */
725 int CL_ProcessTerminate(pid_t pid) {
726   return kill(pid, SIGKILL);
727 }
728
729 /*
730  * Kill process group
731  */
732 int CL_ProcessTerminateGroup(pid_t pid) {
733   return killpg(pid, SIGKILL);
734 }
735
736 /**
737  * Forced process termination
738  */
739 int CL_ProcessAbort(pid_t pid) {
740   return kill(pid, SIGABRT);
741 }
742
743 /**
744  * Forced process group termination
745  */
746 int CL_ProcessAbortGroup(pid_t pid) {
747   return killpg(pid, SIGABRT);
748 }
749
750 /**
751  * Euthanize process group
752  */
753 int CL_ProcessEuthanizeGroup(pid_t pid) {
754   usleep(10 * 1000);
755   return killpg(pid, SIGKILL);
756 }
757
758 /*
759  * Collect child process
760  */
761 int CL_ProcessCleanup(int sigchld_fd, CL_ProcessCleanupInfo_t *cleanup_info) {
762   struct signalfd_siginfo fdsi;
763   ssize_t s;
764   siginfo_t info;
765   int ret;
766   char intfy_fname[32];
767
768   if (cleanup_info == NULL) {
769     errno = EINVAL;
770     return -1;
771   }
772
773   while (1) {
774     s = read(sigchld_fd, &fdsi, sizeof(struct signalfd_siginfo));
775     if (s !=  sizeof(struct signalfd_siginfo)) {
776       if (s == -1 && errno == EINTR) {
777         continue;
778       }
779       break;
780     }
781   }
782
783   info.si_pid = 0;
784   while (1) {
785     ret = waitid(P_ALL, 0, &info, WEXITED | WNOHANG);
786     if (ret == -1) {
787       return -1;
788     } else if (ret == 0 && info.si_pid == 0) {
789       errno = ECHILD;
790       return -1;
791     }
792     break;
793   }
794
795   cleanup_info->pid = info.si_pid;
796   cleanup_info->code = info.si_code;
797   cleanup_info->status = info.si_status;
798
799   cl_monitor_cleanup(info.si_pid);
800
801   ret = snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, info.si_pid);
802
803   if (ret < 0 || ret > sizeof(intfy_fname)) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function snprintf
804     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
805     CL_ERR_PRINT("snprintf fail:%d\n", ret);// LCOV_EXCL_LINE 5: fail safe for glibc function snprintf
806     goto exit;// LCOV_EXCL_LINE 5: fail safe for glibc function snprintf
807   }
808   if (unlink(intfy_fname) < 0) {
809     CL_PERROR("unlink");
810   }
811
812 exit:
813   info.si_pid = 0;
814   ret = waitid(P_ALL, 0, &info, WEXITED | WNOWAIT | WNOHANG);
815   if (ret == 0 && info.si_pid != 0) {
816     return 1;
817   } else if (ret == -1 && errno != ECHILD) {
818     return -1;
819   }
820   return 0;
821 }
822
823 typedef struct {
824   sem_t sem;
825   CL_ThreadAttrInternal_t *ia;
826   void *(*start_routine)(void *);
827   void *start_arg;
828 } create_thread_arg_t;
829
830 static void *thread_start_func(void *arg) {
831   create_thread_arg_t *p = (create_thread_arg_t *)arg;
832   void *(*start_routine)(void *) = p->start_routine;
833   void *start_arg = p->start_arg;
834
835   prctl(PR_SET_NAME, p->ia->name != 0 ? p->ia->name : NULL);
836
837   if (sem_post(&p->sem) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc sem_post
838     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
839     CL_PERROR("sem_post"); // LCOV_EXCL_LINE 5: fail safe for libc sem_post
840   }
841
842   return (*start_routine)(start_arg);
843 }
844
845 /*
846  * Create thread
847  */
848 int CL_ThreadCreate(pthread_t *thread, pthread_attr_t *attr, CL_ThreadAttr_t *cl_attr, void *(*start_routine)(void *),
849                     void *arg) {
850   int ret;
851   create_thread_arg_t cr_arg = { .ia = (CL_ThreadAttrInternal_t *)cl_attr,
852                                  .start_routine = start_routine,
853                                  .start_arg = arg
854                                };
855
856   if (thread == NULL || cl_attr == NULL || start_routine == NULL) {
857     errno = EINVAL;
858     return -1;
859   }
860
861   if (sem_init(&cr_arg.sem, 0, 0) < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sem_init
862     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
863
864     return -1;  // LCOV_EXCL_LINE 5: fail safe for libc sem_init
865   }
866
867   // LCOV_EXCL_BR_START 5: fail safe for libc pthread_create
868   if ((ret = pthread_create(thread, attr, thread_start_func, &cr_arg)) != 0) {
869     // LCOV_EXCL_BR_STOP
870
871     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
872
873     errno = ret; // LCOV_EXCL_LINE 5: fail safe for libc pthread_create
874     return -1;   // LCOV_EXCL_LINE 5: fail safe for libc pthread_create
875   }
876
877   if (sem_wait(&cr_arg.sem) < 0) {// LCOV_EXCL_BR_LINE 5: fail safe for libc sem_wait
878     AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
879
880     return -1;  // LCOV_EXCL_LINE 5: fail safe for libc sem_wait
881   }
882
883   return 0;
884 }
885
886 /*
887  * Initialize CommonLibrary extension thread attribute
888  */
889 int CL_ThreadCreateAttrInit(CL_ThreadAttr_t *attr) {
890   assert_static(sizeof(CL_ThreadAttr_t) == sizeof(CL_ThreadAttrInternal_t));
891
892   if (attr == NULL) {
893     errno = EINVAL;
894     return -1;
895   }
896
897   memset(attr, 0, sizeof(CL_ThreadAttr_t));
898   return 0;
899 }
900
901 /*
902  * Set CommonLibrary extension thread attribute (thread name)
903  */
904 int CL_ThreadCreateAttrSetName(CL_ThreadAttr_t *attr, const char *name) {
905   CL_ThreadAttrInternal_t *ia = (CL_ThreadAttrInternal_t *)attr;
906
907   if (attr == NULL || name == NULL) {
908     errno = EINVAL;
909     return -1;
910   }
911
912   strncpy(ia->name, name, 16);
913   ia->name[15] = 0;
914
915   return 0;
916 }
917
918 /*
919  * Create Cgroup
920  */
921 int CL_ProcessCreateCgroupCreate(const char *cgroup_name, CL_ProcessCreateCgroupAttr_t *attr) {
922   CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
923   CL_ProcessCreateCgroupAttrInternal_t cmp;
924
925   if (cgroup_name == NULL || attr == NULL) {
926     errno = EINVAL;
927     return -1;
928   }
929
930   memset(&cmp, 0, sizeof(CL_ProcessCreateCgroupAttrInternal_t));
931   if (memcmp(ia, &cmp, sizeof(CL_ProcessCreateCgroupAttrInternal_t)) == 0) {
932     errno = EINVAL;
933     return -1;
934   }
935
936   if (ia->rt_runtime_us || ia->cfs_quota_us || ia->cpu_shares) {
937     // LCOV_EXCL_BR_START 5: fail safe for glibc function mkdir
938     if (cl_cgroup_make(CL_CGROUP_CPU, cgroup_name) < 0) {
939       // LCOV_EXCL_BR_STOP
940       return -1;
941     }
942
943     if (ia->rt_runtime_us) {
944       // LCOV_EXCL_BR_START 5: fail safe for glibc function write
945       if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.rt_runtime_us", ia->rt_runtime_us) < 0) {
946         // LCOV_EXCL_BR_STOP
947
948         AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
949
950         return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
951       }
952     }
953
954     if (ia->cfs_quota_us) {
955       // LCOV_EXCL_BR_START 5: fail safe for glibc function write
956       if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.cfs_quota_us", ia->cfs_quota_us) < 0) {
957         // LCOV_EXCL_BR_STOP
958
959         AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
960
961         return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
962       }
963     }
964
965     if (ia->cpu_shares) {
966       // LCOV_EXCL_BR_START 5: fail safe for glibc function write
967       if (cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "cpu.shares", ia->cpu_shares) < 0) {
968         // LCOV_EXCL_BR_STOP
969         AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
970         return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
971       }
972     }
973   }
974
975   if (ia->memory_limit || ia->usage_in_bytes || ia->event_fd) {
976     // LCOV_EXCL_BR_START 5: fail safe for glibc function mkdir
977     if (cl_cgroup_make(CL_CGROUP_MEMORY, cgroup_name) < 0) {
978       // LCOV_EXCL_BR_STOP
979       return -1;
980     }
981
982     if (ia->memory_limit) {
983       // LCOV_EXCL_BR_START 5: fail safe for glibc function write
984       if (cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "memory.limit_in_bytes", ia->memory_limit) < 0) {
985         // LCOV_EXCL_BR_STOP
986         return -1;
987       }
988
989       if (cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "memory.memsw.limit_in_bytes", ia->memory_limit) < 0) {
990         return -1;
991       }
992
993     }
994
995     if (ia->usage_in_bytes || ia->event_fd) {
996       int checkfd;
997       char setstr[64];
998
999       // LCOV_EXCL_BR_START 5: fail safe for glibc function open
1000       if ( (checkfd = cl_cgroup_open(CL_CGROUP_MEMORY, cgroup_name, "memory.memsw.usage_in_bytes", O_RDONLY)) < 0) {
1001         // LCOV_EXCL_BR_STOP
1002         AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
1003         return -1;  // LCOV_EXCL_LINE 5: fail safe for glibc function open
1004       }
1005
1006       snprintf(setstr, sizeof(setstr), "%d %d %d", ia->event_fd, checkfd, ia->usage_in_bytes);
1007       // LCOV_EXCL_BR_START 5: fail safe for glibc function write
1008       if (cl_cgroup_set_string(CL_CGROUP_MEMORY, cgroup_name, "cgroup.event_control", setstr) < 0) {
1009         // LCOV_EXCL_BR_STOP
1010
1011         AGL_ASSERT_NOT_TESTED();  // LCOV_EXCL_LINE 200: test assert
1012
1013         return -1;// LCOV_EXCL_LINE 5: fail safe for glibc function write
1014       }
1015     }
1016   }
1017
1018   return 0;
1019 }
1020
1021 /*
1022  * Initialize Cgroup attribute
1023  */
1024 int CL_ProcessCreateCgroupAttrInit(CL_ProcessCreateCgroupAttr_t *attr) {
1025   assert_static(sizeof(CL_ProcessCreateCgroupAttr_t) == sizeof(CL_ProcessCreateCgroupAttrInternal_t));
1026
1027   if (attr == NULL) {
1028     errno = EINVAL;
1029     return -1;
1030   }
1031
1032   memset(attr, 0, sizeof(CL_ProcessCreateCgroupAttr_t));
1033   return 0;
1034 }
1035
1036 /*
1037  * Set Cgroup attribute (RT Throttling)
1038  */
1039 int CL_ProcessCreateCgroupAttrSetRtThrottling(CL_ProcessCreateCgroupAttr_t *attr, int runtime_us) {
1040   CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1041
1042   if (attr == NULL) {
1043     errno = EINVAL;
1044     return -1;
1045   }
1046
1047   ia->rt_runtime_us = runtime_us;
1048
1049   return 0;
1050 }
1051
1052 /*
1053  * Set Cgroup attribute (CFS Bandwidth Control)
1054  */
1055 int CL_ProcessCreateCgroupAttrSetCfsBandwidthControl(CL_ProcessCreateCgroupAttr_t *attr, int cfs_quota_us) {
1056   CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1057
1058   if (attr == NULL) {
1059     errno = EINVAL;
1060     return -1;
1061   }
1062
1063   ia->cfs_quota_us = cfs_quota_us;
1064
1065   return 0;
1066 }
1067
1068 /*
1069  * Set Cgroup attribute (CPU Shares)
1070  */
1071 int CL_ProcessCreateCgroupAttrSetCpuShares(CL_ProcessCreateCgroupAttr_t *attr, int cpu_shares) {
1072   CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1073
1074   if (attr == NULL) {
1075     errno = EINVAL;
1076     return -1;
1077   }
1078
1079   ia->cpu_shares = cpu_shares;
1080
1081   return 0;
1082 }
1083
1084 /*
1085  * Set Cgroup attribute (Memory Limit)
1086  */
1087 int CL_ProcessCreateCgroupAttrSetMemoryLimit(CL_ProcessCreateCgroupAttr_t *attr, int memory_limit) {
1088   CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1089
1090   if (attr == NULL) {
1091     errno = EINVAL;
1092     return -1;
1093   }
1094
1095   ia->memory_limit = memory_limit;
1096
1097   return 0;
1098 }
1099
1100 /*
1101  * Set Cgroup attribute (Memory Usage Notification)
1102  */
1103 int CL_ProcessCreateCgroupAttrSetMemoryUsageNotification(CL_ProcessCreateCgroupAttr_t *attr, int usage_in_bytes,
1104                                                          int event_fd) {
1105   CL_ProcessCreateCgroupAttrInternal_t *ia = (CL_ProcessCreateCgroupAttrInternal_t *)attr;
1106
1107   if (attr == NULL) {
1108     errno = EINVAL;
1109     return -1;
1110   }
1111
1112   if (event_fd < 0) {
1113     errno = EINVAL;
1114     return -1;
1115   }
1116
1117   ia->usage_in_bytes = usage_in_bytes;
1118   ia->event_fd = event_fd;
1119
1120   return 0;
1121 }
1122
1123 /*
1124  * Delete Cgroup
1125  */
1126 int CL_ProcessCreateCgroupDelete(const char *cgroup_name) {
1127   int mem_ret = 1, mem_err;
1128   int cpu_ret = 1, cpu_err;
1129
1130   if (cgroup_name == NULL) {
1131     errno = EINVAL;
1132     return -1;
1133   }
1134   // LCOV_EXCL_BR_START 5: fail safe for glibc function access
1135   if (cl_cgroup_exist(CL_CGROUP_MEMORY, cgroup_name) == 0) {
1136     // LCOV_EXCL_BR_STOP
1137     mem_ret = cl_cgroup_remove(CL_CGROUP_MEMORY, cgroup_name);
1138     mem_err = errno;
1139   }
1140
1141   // LCOV_EXCL_BR_START 5: fail safe for glibc function access
1142   if (cl_cgroup_exist(CL_CGROUP_CPU, cgroup_name) == 0) {
1143     // LCOV_EXCL_BR_STOP
1144     cpu_ret = cl_cgroup_remove(CL_CGROUP_CPU, cgroup_name);
1145     cpu_err = errno;
1146   }
1147
1148   if (mem_ret == 1 && cpu_ret == 1) {
1149     errno = ENOENT;
1150     return -1;
1151   } else if (mem_ret < 0) {
1152     errno = mem_err;
1153     return -1;
1154   } else if (cpu_ret < 0) {
1155     errno = cpu_err;
1156     return -1;
1157   }
1158
1159   return 0;
1160 }
1161
1162 /*
1163  * Move process to the Cgroup
1164  */
1165 int CL_ProcessCreateCgroupClassify(const char *cgroup_name, pid_t pid) {
1166   int mem_ret = 1, mem_err;
1167   int cpu_ret = 1, cpu_err;
1168
1169   if (cgroup_name == NULL) {
1170     errno = EINVAL;
1171     return -1;
1172   }
1173
1174   if (cl_cgroup_exist(CL_CGROUP_MEMORY, cgroup_name) == 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
1175     mem_ret = cl_cgroup_set_num(CL_CGROUP_MEMORY, cgroup_name, "tasks", pid);
1176     mem_err = errno;
1177   }
1178
1179   if (cl_cgroup_exist(CL_CGROUP_CPU, cgroup_name) == 0) {// LCOV_EXCL_BR_LINE 5: fail safe for glibc function access
1180     cpu_ret = cl_cgroup_set_num(CL_CGROUP_CPU, cgroup_name, "tasks", pid);
1181     cpu_err = errno;
1182   }
1183
1184   if (mem_ret == 1 && cpu_ret == 1) {
1185     errno = ENOENT;
1186     return -1;
1187   } else if (mem_ret < 0) {
1188     errno = mem_err;
1189     return -1;
1190   } else if (cpu_ret < 0) {
1191     errno = cpu_err;
1192     return -1;
1193   }
1194
1195   return 0;
1196 }
1197
1198 /* vim:set ts=8 sts=2 sw=2: */