Wrapper: send/recv socket fd - based on public domain code
[platform/core/security/vasum.git] / wrapper / wrapper-compatibility.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Dynowski <k.dynowski@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19
20 /**
21  * @file
22  * @author  Krzysztof Dynowski (k.dynowski@samsung.com)
23  * @brief   Vasum old API compatibility functions
24  */
25
26 #include "wrapper-compatibility.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <regex.h>
34 #include <limits.h>
35 #include <dirent.h>
36 #include <stdarg.h>
37 #include <pthread.h>
38 #include <inttypes.h> //PRIx64
39 #include <sys/mount.h>
40 #include <sys/xattr.h>
41 #include <sys/wait.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/socket.h>
45 #include <asm/unistd.h>
46 #include <linux/un.h>
47
48 #include "logger/logger.hpp"
49 #include "logger/logger-scope.hpp"
50
51 #define UNUSED(x) ((void)(x))
52
53 extern "C" {
54
55 // find_container_by_pid
56 API char *find_container_by_pid(pid_t  /*pid*/) {
57     LOGS("");
58     return NULL;
59 }
60 // get_domain_pid
61 API pid_t get_domain_pid(const char * /*name*/, const char * /*target*/) {
62     LOGS("");
63     return -1;
64 }
65
66 // sock_close_socket
67 API int sock_close_socket(int fd) {
68     LOGS("");
69     struct sockaddr_un addr;
70     socklen_t addrlen = sizeof(addr);
71
72     if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) && addr.sun_path[0]) {
73         unlink(addr.sun_path);
74     }
75
76     close(fd);
77
78     return 0;
79 }
80 // sock_connect
81 API int sock_connect(const char *path) {
82     LOGS("");
83     size_t len;
84     int fd, idx = 0;
85     struct sockaddr_un addr;
86
87     fd = socket(PF_UNIX, SOCK_STREAM, 0);
88     if (fd < 0) {
89         return -1;
90     }
91
92     memset(&addr, 0, sizeof(addr));
93
94     addr.sun_family = AF_UNIX;
95
96     /* Is it abstract address */
97     if (path[0] == '\0') {
98         idx++;
99     }
100     LOGD("socket path=" << &path[idx]);
101     len = strlen(&path[idx]) + idx;
102     if (len >= sizeof(addr.sun_path)) {
103         close(fd);
104         errno = ENAMETOOLONG;
105         return -1;
106     }
107
108     strncpy(&addr.sun_path[idx], &path[idx], strlen(&path[idx]));
109     if (connect
110         (fd, (struct sockaddr *)&addr,
111          offsetof(struct sockaddr_un, sun_path) + len)) {
112         close(fd);
113         return -1;
114     }
115
116     return fd;
117 }
118
119 // sock_create_socket
120 API int sock_create_socket(const char *path, int type, int flags) {
121     LOGS("");
122     size_t len;
123     int fd, idx = 0;
124     struct sockaddr_un addr;
125
126     if (!path)
127         return -1;
128
129     if (flags & O_TRUNC)
130         unlink(path);
131
132     fd = socket(PF_UNIX, type, 0);
133     if (fd < 0) {
134         return -1;
135     }
136
137     memset(&addr, 0, sizeof(addr));
138
139     addr.sun_family = AF_UNIX;
140
141     /* Is it abstract address */
142     if (path[0] == '\0') {
143         idx++;
144     }
145     LOGD("socket path=" << &path[idx]);
146     len = strlen(&path[idx]) + idx;
147     if (len >= sizeof(addr.sun_path)) {
148         close(fd);
149         errno = ENAMETOOLONG;
150         return -1;
151     }
152
153     strncpy(&addr.sun_path[idx], &path[idx], strlen(&path[idx]));
154
155     if (bind (fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len)) {
156         close(fd);
157         return -1;
158     }
159
160     if (type == SOCK_STREAM && listen(fd, 100)) {
161         close(fd);
162         return -1;
163     }
164
165     return fd;
166 }
167
168 // "Fowler–Noll–Vo hash function" implementation (taken from old API source)
169 #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
170 static uint64_t hash_fnv_64a(void *buf, size_t len, uint64_t hval)
171 {
172     unsigned char *bp;
173
174     for (bp = (unsigned char *)buf; bp < (unsigned char *)buf + len; bp++) {
175         hval ^= (uint64_t) * bp;
176         hval += (hval << 1) + (hval << 4) + (hval << 5) +
177             (hval << 7) + (hval << 8) + (hval << 40);
178     }
179
180     return hval;
181 }
182
183 // sock_monitor_address
184 API int sock_monitor_address(char *buffer, int len, const char *lxcpath) {
185     LOGS("");
186     int ret;
187     uint64_t hash;
188     char *sockname;
189     char path[PATH_MAX];
190
191     memset(buffer, 0, len);
192     sockname = &buffer[1];
193
194     ret = snprintf(path, sizeof(path), "lxc/%s/monitor-sock", lxcpath);
195     if (ret < 0) {
196         errno = ENAMETOOLONG;
197         return -1;
198     }
199
200     hash = hash_fnv_64a(path, ret, FNV1A_64_INIT);
201     ret = snprintf(sockname, len, "lxc/%016" PRIx64 "/%s", hash, lxcpath);
202     if (ret < 0) {
203         errno = ENAMETOOLONG;
204         return -1;
205     }
206
207     return 0;
208 }
209 // sock_recv_fd (intern)
210 API int sock_recv_fd(int fd, int *recvfd, void *data, size_t size) {
211     LOGS("");
212     struct msghdr msg;
213     struct iovec iov;
214     int ret;
215     union {
216         struct cmsghdr cm;
217         char control[CMSG_SPACE(sizeof(int))];
218     } control_un;
219     struct cmsghdr *cmsg;
220     char dummy=1;
221
222     memset(&msg, 0, sizeof(msg));
223     msg.msg_name = NULL;
224     msg.msg_namelen = 0;
225
226     msg.msg_control = control_un.control;
227     msg.msg_controllen = sizeof(control_un.control);
228
229     iov.iov_base = data ? data : &dummy;
230     iov.iov_len = data ? size : sizeof(dummy);
231     msg.msg_iov = &iov;
232     msg.msg_iovlen = 1;
233
234     ret = recvmsg(fd, &msg, 0);
235     if (ret <= 0)
236         return ret;
237
238     cmsg = CMSG_FIRSTHDR(&msg);
239     if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
240         cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
241         *recvfd = *((int *)CMSG_DATA(cmsg));
242     }
243     else
244         *recvfd = -1;
245
246     return ret;
247 }
248 // sock_send_fd
249 API int sock_send_fd(int fd, int sendfd, void *data, size_t size) {
250     LOGS("");
251     struct msghdr msg;
252     struct iovec iov;
253     union {
254         struct cmsghdr cm;
255         char control[CMSG_SPACE(sizeof(int))];
256     } control_un;
257     struct cmsghdr *cmsg;
258     char dummy=1;
259
260     memset(&msg, 0, sizeof(msg));
261     msg.msg_control = control_un.control;
262     msg.msg_controllen = sizeof(control_un.control);
263
264     cmsg = CMSG_FIRSTHDR(&msg);
265     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
266     cmsg->cmsg_level = SOL_SOCKET;
267     cmsg->cmsg_type = SCM_RIGHTS;
268     *((int *)CMSG_DATA(cmsg)) = sendfd;
269
270     msg.msg_name = NULL;
271     msg.msg_namelen = 0;
272
273     iov.iov_base = data ? data : &dummy;
274     iov.iov_len = data ? size : sizeof(dummy);
275     msg.msg_iov = &iov;
276     msg.msg_iovlen = 1;
277
278     return sendmsg(fd, &msg, MSG_NOSIGNAL);
279 }
280 // vasum_log
281 API void vasum_log(int type, const char *tag, const char *fmt, ...) {
282     va_list arg_ptr;
283     char buf[255];
284     LOGS("type=" << type << " tag=" << tag);
285     va_start(arg_ptr, fmt);
286     vsnprintf(buf, sizeof(buf), fmt, arg_ptr);
287     va_end(arg_ptr);
288     buf[sizeof(buf)-1]=0;
289     LOGD("msg=" << buf);
290 }
291
292 #define MAX_ERROR_MSG    0x1000
293 #define BUF_SIZE    4096
294
295 #define SMACK_LABEL_LEN 8
296 #define ERROR(...) do{}while(0)
297 #define WARN(...) do{}while(0)
298 #define DEBUG(...) do{}while(0)
299 #define INFO(...) do{}while(0)
300
301 // lib/utils.c
302 const char *const fso_type_strtab[] = {
303     "Directory",
304     "Regular file",
305     "FIFO",
306     "Socket",
307     "Device node"
308 };
309
310 API const char *fso_type_to_string(vsm_fso_type_t fso)
311 {
312     LOGS("");
313     if (fso < 0 || fso > VSM_FSO_MAX_TYPE) {
314         return NULL;
315     }
316
317     return fso_type_strtab[fso];
318 }
319
320 API int wait_for_pid_status(pid_t pid)
321 {
322     LOGS("");
323     int status, ret;
324
325  again:
326     ret = waitpid(pid, &status, 0);
327     if (ret == -1) {
328         if (errno == EINTR) {
329             goto again;
330         } else {
331             ERROR("waitpid pid : %d error : %s", pid, strerror(errno));
332             return -1;
333         }
334     }
335     if (ret != pid)
336         goto again;
337     return status;
338 }
339
340 API vsm_fso_type_t fso_string_to_type(char *str)
341 {
342     LOGS("");
343     int len;
344     int i;
345     for (i = 0; i <= VSM_FSO_MAX_TYPE; i++) {
346         len = strlen(fso_type_strtab[i]);
347         if (strncmp(str, fso_type_strtab[i], len) == 0)
348             return static_cast<vsm_fso_type_t>(i);
349     }
350
351     return static_cast<vsm_fso_type_t>(-1);
352 }
353
354 API int mkdir_p(const char *dir, mode_t mode)
355 {
356     LOGS("");
357     const char *tmp = dir;
358     const char *orig = dir;
359     char *makeme;
360
361     do {
362         dir = tmp + strspn(tmp, "/");
363         tmp = dir + strcspn(dir, "/");
364         makeme = strndup(orig, dir - orig);
365         if (*makeme) {
366             if (mkdir(makeme, mode) && errno != EEXIST) {
367                 free(makeme);
368                 return -1;
369             }
370         }
371         free(makeme);
372     } while (tmp != dir);
373
374     return 0;
375 }
376
377 API int lock_fd(int fd, int wait)
378 {
379     LOGS("");
380     int ret;
381     struct flock f;
382
383     while (1) {
384         f.l_type = F_WRLCK;
385         f.l_whence = SEEK_SET;
386         f.l_start = 0;
387         f.l_len = 0;
388
389         if (wait)
390             ret = fcntl(fd, F_SETLKW, &f);
391         else
392             ret = fcntl(fd, F_SETLK, &f);
393         if (ret != -1)
394             return 0;
395         if (errno == EINTR)
396             continue;
397         return -1;
398     }
399 }
400
401 API int unlock_fd(int fd)
402 {
403     LOGS("");
404     struct flock f;
405     f.l_type = F_UNLCK;
406     f.l_whence = SEEK_SET;
407     f.l_start = 0;
408     f.l_len = 0;
409     return fcntl(fd, F_SETLKW, &f);
410 }
411
412 API int copy_smacklabel(const char * /*source*/, const char * /*dest*/)
413 {
414     LOGS("");
415     return 0;
416 }
417
418 API int remove_file(char *path)
419 {
420     LOGS("");
421     struct stat path_stat;
422     DIR *dp;
423     struct dirent *d;
424     int status = 0;
425
426     if (lstat(path, &path_stat) < 0) {
427         if (errno != ENOENT) {
428             ERROR("Unable to stat : %s");
429             return -1;
430         }
431     }
432
433     if (S_ISDIR(path_stat.st_mode)) {
434         if ((dp = opendir(path)) == NULL) {
435             ERROR("Unable to opendir %s", path);
436             return -1;
437         }
438
439         while ((d = readdir(dp)) != NULL) {
440             char new_path[PATH_MAX];
441             if (strcmp(d->d_name, ".") == 0 ||
442                 strcmp(d->d_name, "..") == 0)
443                 continue;
444
445             snprintf(new_path, PATH_MAX, "%s/%s", path, d->d_name);
446             if (remove_file(new_path) < 0)
447                 status = -1;
448         }
449
450         if (closedir(dp) < 0) {
451             ERROR("Unable to close dp : %s", path);
452             return -1;
453         }
454
455         if (rmdir(path) < 0) {
456             ERROR("Failed to remove dir : %s, cause: %s", path,
457                   strerror(errno));
458             return -1;
459         }
460
461     } else {
462         if (unlink(path) < 0) {
463             ERROR("Unable to remove %s", path);
464             return -1;
465         }
466     }
467
468     return status;
469 }
470
471 API int copy_file(const char *source, const char *dest, int /*flags*/)
472 {
473     LOGS("");
474     int ret;
475     FILE *sfp, *dfp;
476     size_t nread, nwritten, size = BUF_SIZE;
477     char buffer[BUF_SIZE];
478
479     if ((sfp = fopen(source, "r")) == NULL) {
480         ERROR("Unable to open source : %s", source);
481         return -1;
482     }
483
484     if ((dfp = fopen(dest, "w+")) == NULL) {
485         ERROR("Unable to open destination : %s", dest);
486         fclose(sfp);
487         return -1;
488     }
489
490     while (1) {
491         nread = fread(buffer, 1, size, sfp);
492
493         if (nread != size && ferror(sfp)) {
494             ERROR("Read failed");
495             return -1;
496         } else if (nread == 0) {
497             break;
498         }
499
500         nwritten = fwrite(buffer, 1, nread, dfp);
501
502         if (nwritten != nread) {
503             if (ferror(dfp))
504                 ERROR("write fail");
505             else
506                 ERROR("Unable to write all data");
507             return -1;
508         }
509     }
510
511     fclose(sfp);
512     fclose(dfp);
513
514     ret = copy_smacklabel(source, dest);
515     if (ret != 0) {
516         ERROR("Unable to setting smack lable");
517         return -1;
518     }
519     return 0;
520 }
521
522 API int regex_compile(regex_t * r, const char *regex_text)
523 {
524     LOGS("");
525     int status = regcomp(r, regex_text, REG_EXTENDED | REG_NEWLINE);
526
527     if (status != 0) {
528         char error_message[MAX_ERROR_MSG];
529
530         regerror(status, r, error_message, MAX_ERROR_MSG);
531         DEBUG("Regex error compiling '%s': %s\n",
532               regex_text, error_message);
533         return 1;
534     }
535
536     return 0;
537 }
538
539 API int regex_match(regex_t * r, const char *to_match)
540 {
541     LOGS("");
542     const char *p = to_match;
543     const int n_matches = 10;
544     regmatch_t m[n_matches];
545
546     while (1) {
547         int i = 0;
548         int nomatch = regexec(r, p, n_matches, m, 0);
549
550         if (nomatch) {
551             DEBUG("No more matches.\n");
552             return nomatch;
553         }
554
555         for (i = 0; i < n_matches; i++) {
556             int start;
557             int finish;
558             UNUSED(start);
559             UNUSED(finish);
560
561             if (m[i].rm_so == -1) {
562                 break;
563             }
564
565             start = m[i].rm_so + (p - to_match);
566             finish = m[i].rm_eo + (p - to_match);
567             if (i == 0) {
568                 INFO("$& is ");
569             } else {
570                 INFO("$%d is ", i);
571             }
572
573             INFO("'%.*s' (bytes %d:%d)\n", (finish - start),
574                  to_match + start, start, finish);
575         }
576
577         p += m[0].rm_eo;
578     }
579
580     return 0;
581 }
582
583 API int get_peer_pid(int fd)
584 {
585     LOGS("");
586     struct ucred cred;
587     socklen_t cr_len = sizeof(cred);
588     if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cr_len) < 0) {
589         return -1;
590     }
591     return cred.pid;
592 }
593
594 API pid_t gettid(void)
595 {
596     LOGS("");
597     return syscall(__NR_gettid);
598 }
599
600 API int set_smacklabel_fd(int fd, const char *xattr_name, const char *label)
601 {
602     LOGS("");
603     size_t len;
604     int ret;
605
606     if (fd < 0)
607         return -1;
608
609     len = strnlen(label, SMACK_LABEL_LEN + 1);
610     if (len > SMACK_LABEL_LEN)
611         return -1;
612
613     ret = fsetxattr(fd, xattr_name, label, len + 1, 0);
614     if (ret != 0) {
615         ERROR("Set Smack lable error : %s", strerror(errno));
616     }
617     return ret;
618 }
619
620 API int set_smacklabel(const char *path, const char *xattr_name, const char *label)
621 {
622     LOGS("");
623     size_t len;
624     int ret;
625
626     if (path == NULL)
627         return -1;
628
629     len = strnlen(label, SMACK_LABEL_LEN + 1);
630     if (len > SMACK_LABEL_LEN)
631         return -1;
632
633     ret = lsetxattr(path, xattr_name, label, len + 1, 0);
634     if (ret != 0) {
635         ERROR("Set Smack lable error : %s", strerror(errno));
636     }
637     return ret;
638 }
639 API char *get_self_smacklabel(void)
640 {
641     LOGS("");
642     int ret;
643     int fd;
644     const char *attr_path = "/proc/self/attr/current";
645     char buffer[SMACK_LABEL_LEN + 1];
646
647     bzero(buffer, SMACK_LABEL_LEN + 1);
648
649     fd = open(attr_path, O_RDONLY);
650     if (fd < 0) {
651         return NULL;
652     }
653
654     ret = read(fd, buffer, SMACK_LABEL_LEN + 1);
655     close(fd);
656     if (ret < 0) {
657         return NULL;
658     }
659
660     if (ret > SMACK_LABEL_LEN) {
661         //return NULL;
662     }
663     buffer[SMACK_LABEL_LEN] = 0;
664
665     return strdup(buffer);
666 }
667
668 API int get_self_cpuset(char *name, int buf_sz)
669 {
670     LOGS("");
671     int fd;
672     int lxc_len, ret;
673     char cpuset_path[] = "/proc/self/cpuset";
674     char current_name[NAME_MAX];
675
676     fd = open(cpuset_path, O_RDONLY);
677     if (fd < 0) {
678         return 0;
679     }
680
681     ret = read(fd, current_name, NAME_MAX - 1);
682     if (ret < 0) {
683         close(fd);
684         return -1;
685     }
686
687     current_name[ret - 1] = '\0';
688     close(fd);
689
690     lxc_len = sizeof("/lxc");
691     if (ret < lxc_len) {
692         name[0] = '/';
693         name[1] = 0;
694         return 1;
695     } else {
696         char *p;
697         p = current_name + lxc_len;
698
699         while (*p != '\0') {
700             if (*p == '/') {
701                 *p = '\0';
702                 break;
703             }
704             p++;
705         }
706         snprintf(name, buf_sz, "%s", current_name + lxc_len);
707     }
708
709     return ret - lxc_len;
710 }
711
712
713 API char * get_pid_cpuset(int pid)
714 {
715     LOGS("");
716     int fd;
717     int ret;
718     char cpuset_path[PATH_MAX];
719     char current_name[NAME_MAX];
720
721     snprintf(cpuset_path, PATH_MAX, "/proc/%d/cpuset", pid);
722
723     ret = access(cpuset_path, F_OK | R_OK);
724     if (ret != 0)
725         return NULL;
726
727     fd = open(cpuset_path, O_RDONLY);
728     if (fd < 0) {
729         return NULL;
730     }
731
732     ret = read(fd, current_name, NAME_MAX - 1);
733     if (ret < 0) {
734         close(fd);
735         return NULL;
736     }
737
738     current_name[ret - 1] = 0;
739     close(fd);
740
741     INFO("cpuset path : %s, value : %s", cpuset_path, current_name);
742
743     return strdup(current_name);
744 }
745
746 API char * read_namespace_link(const char *ns, int pid)
747 {
748     LOGS("");
749     char ns_path[PATH_MAX];
750     char buf[NAME_MAX];
751     int ret;
752
753     snprintf(ns_path, PATH_MAX, "/proc/%d/ns/%s", pid, ns);
754
755     ret = access(ns_path, F_OK);
756     if (ret != 0)
757         return NULL;
758
759     ret = readlink(ns_path, buf, NAME_MAX);
760     if (ret == -1) {
761         ERROR("Failed to readlink ns file - [%s]", ns_path);
762         return NULL;
763     }
764
765     buf[ret] = 0;
766
767     INFO("Read ns link data -pid : %d data : %s", pid, buf);
768
769     return strdup(buf);
770 }
771
772 // libs/device.c
773 #define DEV_ITERATE_CONTINUE    0
774 API int dev_enumerate_nodes(const char *cname, dev_enumerator enumerator,
775             void *data)
776 {
777     LOGS("");
778     int ret;
779     FILE *fp;;
780     char path[PATH_MAX], entry[64];
781
782     ret = snprintf(path, sizeof(path),
783                "/sys/fs/cgroup/devices/lxc/%s/devices.list", cname);
784
785     if (ret < 0) {
786         ERROR("Failed to make pathname");
787         return -1;
788     }
789
790     fp = fopen(path, "r");
791     if (fp == NULL) {
792         ERROR("File open failed: %s(%s)", path, strerror(errno));
793         return -1;
794     }
795
796     while (fgets(entry, sizeof(entry), fp) != NULL) {
797         int major, minor;
798         char *next, *ptr = &entry[2];
799
800         major = strtol(ptr, &next, 10);
801         minor = strtol(++next, (char **)NULL, 10);
802
803         ret = enumerator(entry[0], major, minor, data);
804         if (ret != DEV_ITERATE_CONTINUE)
805             break;
806     }
807
808     fclose(fp);
809
810     return ret;
811 }
812
813 API int dev_terminal_enumerator(int type, int major, int minor, void *data)
814 {
815     LOGS("");
816     int *dev = (int*)data;
817
818     *dev = minor;
819     UNUSED(type);
820     UNUSED(major);
821
822     INFO("Matched device: %c, %d, %d\n", type, major, minor);
823
824     return 1;
825 }
826
827 // libs/namespace.c
828 API pid_t get_init_pid(const char *name)
829 {
830     LOGS("");
831     char filename[PATH_MAX];
832     FILE *fp;
833     pid_t ret = -1;
834
835     snprintf(filename, sizeof(filename),
836             "/sys/fs/cgroup/devices/lxc/%s/cgroup.procs", name);
837
838     fp = fopen(filename, "r");
839
840     if (fp != NULL) {
841         if (fscanf(fp, "%d", &ret) < 0) {
842             ERROR("Failed to read %s\n", filename);
843             ret = -2;
844         }
845         fclose(fp);
846     } else {
847         INFO("Unable to access %s\n", filename);
848         ret = errno;
849     }
850
851     return ret;
852 }
853
854
855 API pid_t get_zone_pid(const char *name, const char *target)
856 {
857     LOGS("");
858     char path[PATH_MAX];
859     char cmd[PATH_MAX];
860     int res = 0, len;
861     pid_t ret = -1;
862     FILE *fp;
863
864     char *line = NULL;
865     size_t line_len;
866
867     snprintf(path, PATH_MAX,
868          "/sys/fs/cgroup/cpuset/lxc/%s/cgroup.procs", name);
869
870     res = access(path, F_OK | R_OK);
871     if (res != 0) {
872         ERROR("Failed to acess zone cgroup file: %s", path);
873         return -EINVAL;
874     }
875
876     if (target == NULL) {
877         ERROR("Failed to lookup cmdline in zone proc");
878         return -EINVAL;
879     } else {
880         len = strlen(target);
881     }
882
883     fp = fopen(path, "r");
884     if (fp == NULL) {
885         ERROR("Failed to open zone cgroup");
886         return -1;
887     }
888
889     while (getline(&line, &line_len, fp) != -1) {
890         int res;
891         pid_t pid;
892         FILE *cmdfp;
893         char cmdpath[PATH_MAX];
894
895         res = sscanf(line, "%d", &pid);
896         if (res != 1) {
897             ERROR("Failed to read %s\n", path);
898             res = -1;
899             goto out;
900         }
901
902         if (pid < 0)
903             continue;
904
905         snprintf(cmdpath, PATH_MAX, "/proc/%d/cmdline", pid);
906
907         if (access(cmdpath, F_OK | R_OK) != 0)
908             continue;
909
910         cmdfp = fopen(cmdpath, "r");
911         if (cmdfp == NULL) {
912             ERROR("Unable to access %s\n", cmdpath);
913             continue;
914         }
915
916         if (fscanf(cmdfp, "%s", cmd) < 0) {
917             ERROR("Failed to read cmdline - pid : %d\n", pid);
918             continue;
919         }
920
921         fclose(cmdfp);
922
923         if (strncmp(cmd, target, len) == 0) {
924             ret = pid;
925             break;
926         }
927     }
928  out:
929     fclose(fp);
930     return ret;
931 }
932
933 API int open_ns(pid_t pid, const char *name)
934 {
935     LOGS("");
936     int fd, ret;
937     char path[PATH_MAX];
938
939     ret = snprintf(path, PATH_MAX, "/proc/%d/ns/%s", pid, name);
940     if (ret < 0 || ret >= PATH_MAX) {
941         ERROR("Failed to namespace - pid %d, ns: %s ", pid, name);
942         return -EINVAL;
943     }
944
945     fd = open(path, O_RDONLY);
946     if (fd < 0) {
947         ERROR("failed to open %s\n", path);
948         return -errno;
949     }
950
951     return fd;
952 }
953
954 // vasum/libs/vt.c
955 #include <linux/kd.h>
956 #include <linux/vt.h>
957 static int is_console(int fd)
958 {
959     LOGS("");
960     char arg;
961
962     return (isatty(fd) &&
963         (ioctl(fd, KDGKBTYPE, &arg) == 0) &&
964         ((arg == KB_101) || (arg == KB_84)));
965 }
966
967 static int open_console(const char *path)
968 {
969     int fd;
970
971     fd = open(path, O_RDWR);
972     if (fd < 0) {
973         fd = open(path, O_WRONLY);
974     }
975     if (fd < 0) {
976         fd = open(path, O_RDONLY);
977     }
978     if (fd < 0) {
979         return -1;
980     }
981
982     return fd;
983 }
984
985 API int get_console_fd(const char *path)
986 {
987     LOGS("");
988     int fd;
989
990     if (path) {
991         fd = open_console(path);
992         if (fd >= 0) {
993             return fd;
994         }
995
996         return -1;
997     }
998
999     fd = open_console("/dev/tty0");
1000     if (fd >= 0) {
1001         return fd;
1002     }
1003
1004     fd = open_console("/dev/console");
1005     if (fd >= 0) {
1006         return fd;
1007     }
1008
1009     for (fd = 0; fd < 3; fd++) {
1010         if (is_console(fd)) {
1011             return fd;
1012         }
1013     }
1014
1015     return -1;
1016 }
1017
1018 API int vt_switch_terminal(int id)
1019 {
1020     LOGS("");
1021     int fd, ret = -1;
1022
1023     fd = get_console_fd(NULL);
1024     if (fd < 0) {
1025         return -1;
1026     }
1027
1028     if (ioctl(fd, VT_ACTIVATE, id) < 0) {
1029         goto out;
1030     }
1031
1032     if (ioctl(fd, VT_WAITACTIVE, id) < 0) {
1033         goto out;
1034     }
1035
1036     ret = 0;
1037  out:
1038     close(fd);
1039     return ret;
1040 }
1041
1042 API int vt_find_unused_terminal(void)
1043 {
1044     LOGS("");
1045     int fd, nr = -1;
1046
1047     fd = get_console_fd(NULL);
1048     if (fd < 0) {
1049         perror("Terminal open failed");
1050         return -1;
1051     }
1052
1053     if (ioctl(fd, VT_OPENQRY, &nr) < 0) {
1054         perror("VT_OPENQRY failed");
1055         goto out;
1056     }
1057
1058  out:
1059     close(fd);
1060
1061     return nr;
1062 }
1063
1064 API int vt_query_active_terminal(void)
1065 {
1066     LOGS("");
1067     int fd, ret = -1;
1068     struct vt_stat vtstat;
1069
1070     fd = get_console_fd(NULL);
1071     if (fd < 0) {
1072         return -1;
1073     }
1074
1075     if (ioctl(fd, VT_GETSTATE, &vtstat) < 0) {
1076         goto out;
1077     }
1078
1079     ret = vtstat.v_active;
1080  out:
1081     close(fd);
1082     return ret;
1083 }
1084
1085 // libs/parser.h
1086 struct unit_keyword_callback {
1087     const char *name;
1088     int (*func) (int nargs, char **args);
1089 };
1090
1091 struct unit_parser {
1092     struct unit_keyword_callback *kw;
1093 };
1094
1095 API int parse_stream(const char *name, struct unit_parser *parser);
1096 // libs/parser.c
1097 #define PARSER_MAXARGS    32
1098
1099 #define T_EOF           1
1100 #define T_STATEMENT     2
1101 #define T_ARGUMENT      3
1102 #define T_NEWLINE       7
1103 #define T_NEWBLOCK      8
1104
1105 struct parser_context {
1106     struct unit_keyword_callback *kw;
1107 };
1108
1109 struct parser_state {
1110     char *ptr;
1111     char *stmt;
1112     int line;
1113     int nexttoken;
1114     void *context;
1115 };
1116
1117 static void parser_init_state(struct parser_state *state, char *line)
1118 {
1119     state->line = 1;
1120     state->ptr = line;
1121     state->nexttoken = 0;
1122     state->stmt = NULL;
1123     state->context = NULL;
1124 }
1125
1126 static struct unit_keyword_callback *keyword_lookup(struct parser_context *ctx,
1127                             const char *kw)
1128 {
1129     int i;
1130
1131     for (i = 0; ctx->kw[i].name != NULL; i++) {
1132         if (!strcmp(ctx->kw[i].name, kw)) {
1133             return &ctx->kw[i];
1134         }
1135     }
1136
1137     return NULL;
1138 }
1139
1140 static int tokenize(struct parser_state *state)
1141 {
1142     char *x = state->ptr;
1143     char *s, *ss;
1144
1145     if (state->nexttoken) {
1146         int t = state->nexttoken;
1147         state->nexttoken = 0;
1148         return t;
1149     }
1150
1151  retry:
1152     state->stmt = s = x;
1153     ss = x + 1;
1154  resume:
1155     while (1) {
1156         switch (*x) {
1157         case 0:
1158             state->nexttoken = T_EOF;
1159             goto textdone;
1160         case '\\':
1161             x++;
1162             switch (*x) {
1163             case 0:
1164                 goto textdone;
1165             case 'n':
1166                 *s++ = '\n';
1167                 break;
1168             case 'r':
1169                 *s++ = '\r';
1170                 break;
1171             case 't':
1172                 *s++ = '\t';
1173                 break;
1174             case '\\':
1175                 *s++ = '\\';
1176                 break;
1177             case '\r':
1178                 /* \ <cr> <lf> -> line continuation */
1179                 if (x[1] != '\n') {
1180                     x++;
1181                     continue;
1182                 }
1183             case '\n':
1184                 /* \ <lf> -> line continuation */
1185                 state->line++;
1186                 x++;
1187                 /* eat any extra whitespace */
1188                 while ((*x == ' ') || (*x == '\t'))
1189                     x++;
1190                 continue;
1191             default:
1192                 /* unknown escape -- just copy */
1193                 *s++ = *x++;
1194             }
1195             continue;
1196         case ',':
1197             x++;
1198             goto textdone;
1199         case '=':
1200             x++;
1201             if (ss == x) {
1202                 goto retry;
1203             }
1204             goto textdone;
1205         case ' ':
1206         case '\t':
1207         case '\r':
1208             x++;
1209             if (ss == x) {
1210                 goto retry;
1211             }
1212             goto textdone;
1213         case '\n':
1214             x++;
1215             if (ss == x) {
1216                 state->ptr = x;
1217                 return T_NEWLINE;
1218             }
1219             state->nexttoken = T_NEWLINE;
1220             goto textdone;
1221         case '\'':
1222         case '"':
1223             x++;
1224             for (;;) {
1225                 switch (*x) {
1226                 case 0:
1227                     /* unterminated quoted thing */
1228                     state->ptr = x;
1229                     return T_EOF;
1230                 case '\'':
1231                 case '"':
1232                     x++;
1233                     goto resume;
1234                 default:
1235                     *s++ = *x++;
1236                 }
1237             }
1238             break;
1239         case '[':
1240             x++;
1241             goto resume;
1242         case ']':
1243             x++;
1244             goto resume;
1245         case '#':
1246             while (*x && (*x != '\n'))
1247                 x++;
1248             if (*x == '\n') {
1249                 state->ptr = x + 1;
1250                 return T_NEWLINE;
1251             } else {
1252                 state->ptr = x;
1253                 return T_EOF;
1254             }
1255             break;
1256         default:
1257             *s++ = *x++;
1258         }
1259     }
1260
1261  textdone:
1262     state->ptr = x;
1263     *s = 0;
1264     return T_STATEMENT;
1265 }
1266
1267 static int parse_statement(struct parser_context *ctx, int argc, char **argv,
1268                int (*func) (int argc, char **argv))
1269 {
1270     struct parser_state state;
1271     char *args[PARSER_MAXARGS];
1272     int i, nargs, done, rc;
1273     int ret = 0;
1274     UNUSED(ctx);
1275
1276     for (i = 0; i < argc; i++) {
1277         done = nargs = 0;
1278         parser_init_state(&state, argv[i]);
1279
1280         while (!done) {
1281             int token = tokenize(&state);
1282             switch (token) {
1283             case T_EOF:
1284                 if (nargs && func) {
1285                     rc = func(nargs, args);
1286                     if (rc < 0) {
1287                         WARN("Key word callback error");
1288                     }
1289                     nargs = 0;
1290                 }
1291                 done = 1;
1292                 break;
1293             case T_STATEMENT:
1294                 if (nargs < PARSER_MAXARGS) {
1295                     args[nargs++] = state.stmt;
1296                 }
1297                 break;
1298             }
1299         }
1300     }
1301
1302     return ret;
1303 }
1304
1305 API int parse_stream_core(struct parser_context *ctx, char *s)
1306 {
1307     LOGS("");
1308     struct unit_keyword_callback *kw;
1309     struct parser_state state;
1310     char *args[PARSER_MAXARGS];
1311     int nargs, rc;
1312
1313     nargs = 0;
1314     parser_init_state(&state, s);
1315
1316     for (;;) {
1317         int token = tokenize(&state);
1318         switch (token) {
1319         case T_EOF:
1320             return 0;
1321         case T_NEWLINE:
1322             if (nargs) {
1323                 if ((kw = keyword_lookup(ctx, args[0])) != NULL) {
1324                     rc = parse_statement(ctx, nargs - 1,
1325                                  &args[1],
1326                                  kw->func);
1327                     if (rc < 0) {
1328                         return -EINVAL;
1329                     }
1330                 }
1331
1332                 nargs = 0;
1333             }
1334             break;
1335         case T_STATEMENT:
1336             if (nargs < PARSER_MAXARGS) {
1337                 args[nargs++] = state.stmt;
1338             }
1339             break;
1340         }
1341     }
1342
1343     return 0;
1344 }
1345
1346 /* reads a file, making sure it is terminated with \n \0 */
1347 static char *open_stream(const char *name, unsigned int *_sz)
1348 {
1349     int sz, fd;
1350     char *data = NULL;
1351
1352     fd = open(name, O_RDONLY);
1353     if (fd < 0)
1354         return NULL;
1355
1356     sz = lseek(fd, 0, SEEK_END);
1357     if (sz < 0)
1358         goto oops;
1359
1360     if (lseek(fd, 0, SEEK_SET) != 0)
1361         goto oops;
1362
1363     data = (char *)malloc(sz + 2);
1364     if (data == 0)
1365         goto oops;
1366
1367     if (read(fd, data, sz) != sz)
1368         goto oops;
1369
1370     close(fd);
1371
1372     data[sz] = '\n';
1373     data[sz + 1] = 0;
1374     if (_sz)
1375         *_sz = sz;
1376
1377     return data;
1378
1379  oops:
1380     close(fd);
1381     if (data != 0)
1382         free(data);
1383
1384     return NULL;
1385 }
1386
1387 API int parse_stream(const char *name, struct unit_parser *parser)
1388 {
1389     LOGS("");
1390     char *stream;
1391     struct parser_context *ctx;
1392
1393     ctx = (struct parser_context *)malloc(sizeof(struct parser_context));
1394     if (ctx == NULL) {
1395         return -ENOMEM;
1396     }
1397
1398     ctx->kw = parser->kw;
1399
1400     /* File open & return file context */
1401     stream = open_stream(name, NULL);
1402     if (stream == NULL) {
1403         free(ctx);
1404         return -1;
1405     }
1406
1407     parse_stream_core(ctx, stream);
1408
1409     free(stream);
1410     free(ctx);
1411
1412     return 0;
1413 }
1414 API struct vsm_netdev *alloc_netdev(struct vsm_zone * /*zone*/, vsm_netdev_type_t  /*type*/, const char * /*netdev_name*/) {
1415     LOGS("");
1416     return NULL;
1417 }
1418 API void enter_to_ns(pid_t  /*pid*/, char * /*name*/) {
1419     LOGS("");
1420 }
1421
1422 // dummy-ops
1423 static int dummy_create_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/,
1424                  const char * /*template*/, int  /*flags*/)
1425 {
1426     return -VSM_ERROR_NOT_SUPPORTED;
1427 }
1428
1429 static int dummy_destroy_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/, int  /*force*/)
1430 {
1431     return -VSM_ERROR_NOT_SUPPORTED;
1432 }
1433
1434 static int dummy_start_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/)
1435 {
1436     return -VSM_ERROR_NOT_SUPPORTED;
1437 }
1438
1439 static int dummy_shutdown_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/, int  /*force*/)
1440 {
1441     return -VSM_ERROR_NOT_SUPPORTED;
1442 }
1443
1444 static int dummy_lock_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/, int  /*shutdown*/)
1445 {
1446     return -VSM_ERROR_NOT_SUPPORTED;
1447 }
1448
1449 static int dummy_unlock_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/)
1450 {
1451     return -VSM_ERROR_NOT_SUPPORTED;
1452 }
1453
1454 static int dummy_set_foreground(vsm_zone_h  zone)
1455 {
1456     if (zone == NULL)
1457         return -VSM_ERROR_INVALID;
1458
1459     if (zone->parent == zone) {
1460         return VSM_ERROR_NONE;
1461     }
1462     return -VSM_ERROR_NO_OBJECT;
1463 }
1464
1465 static vsm_zone_h dummy_get_foreground(vsm_context_h  ctx)
1466 {
1467     if (ctx == NULL) {
1468         errno = EINVAL;
1469         return NULL;
1470     }
1471
1472     return ctx->root_zone;
1473 }
1474
1475 static int dummy_iterate_zone(vsm_context_h  ctx, vsm_zone_iter_cb  callback, void *user_data)
1476 {
1477     if (callback) {
1478         callback(ctx->root_zone, user_data);
1479     }
1480     return VSM_ERROR_NONE;
1481 }
1482
1483 static vsm_zone_h dummy_lookup_zone_by_name(vsm_context_h ctx, const char *name)
1484 {
1485     if (strcmp(name, "") != 0) {
1486         errno = ESRCH;
1487         return NULL;
1488     }
1489
1490     return ctx->root_zone;
1491 }
1492
1493 static vsm_zone_h dummy_lookup_zone_by_pid(vsm_context_h ctx, pid_t  /*pid*/)
1494 {
1495     if (ctx == NULL)
1496         return NULL;
1497
1498     return ctx->root_zone;
1499 }
1500
1501 static int dummy_attach_zone(vsm_context_h ctx, const char *zone_name,
1502                  vsm_attach_command_s * command,
1503                  vsm_attach_options_s * opts,
1504                  pid_t * attached_process)
1505 {
1506     pid_t pid;
1507     struct vsm_attach_options_s options;
1508
1509     if (command == NULL || command->exec == NULL || zone_name == NULL) {
1510         ERROR("Invalid arguments");
1511         ctx->error = VSM_ERROR_INVALID;
1512         return -VSM_ERROR_INVALID;
1513     }
1514
1515     if (strcmp("", zone_name) != 0) {
1516         ctx->error = VSM_ERROR_INVALID;
1517         return -VSM_ERROR_INVALID;
1518     }
1519
1520     if (opts == NULL) {
1521         opts = &options;
1522         opts->uid = getuid();
1523         opts->gid = getgid();
1524         opts->env_num = 0;
1525         opts->extra_env = NULL;
1526     }
1527
1528     pid = fork();
1529     if (pid == 0) {
1530         if (opts->extra_env != NULL) {
1531             while (*opts->extra_env)
1532                 putenv(*opts->extra_env++);
1533         }
1534
1535         if (getuid() == 0 && opts->uid != 0) {
1536             if (setuid(opts->uid) != 0) {
1537                 ERROR("Failed to set uid : %d", opts->uid);
1538             }
1539         } else {
1540             WARN("setuid() is not permitted");
1541         }
1542
1543         if (getgid() == 0 && opts->gid != 0) {
1544             if (setgid(opts->gid) != 0) {
1545                 ERROR("Failed to set gid : %d", opts->gid);
1546             }
1547         } else {
1548             WARN("setgid() is not permitted");
1549         }
1550
1551         if (execvp(command->exec, command->argv) < 0) {
1552             ERROR("exevp failed : %s, %s", command->exec,
1553                   strerror(errno));
1554             exit(EXIT_FAILURE);
1555         }
1556     } else {
1557         *attached_process = pid;
1558     }
1559
1560     return VSM_ERROR_NONE;
1561 }
1562
1563 static int dummy_attach_zone_wait(vsm_context_h  ctx, const char *zone_name,
1564                   vsm_attach_command_s * command,
1565                   vsm_attach_options_s * opts)
1566 {
1567     pid_t pid = 0;
1568     int ret, status;
1569
1570     ret = dummy_attach_zone(ctx, zone_name, command, opts, &pid);
1571     if (ret != VSM_ERROR_NONE) {
1572         ERROR("API Failed.");
1573         return ret;
1574     }
1575
1576     status = wait_for_pid_status(pid);
1577     if (status == -1) {
1578         ctx->error = VSM_ERROR_GENERIC;
1579         return -VSM_ERROR_GENERIC;
1580     }
1581
1582     INFO("attached process extied : pid - %d, exit code : %d", pid,
1583          WEXITSTATUS(status));
1584
1585     return status;
1586 }
1587
1588 static vsm_zone_h dummy_join_zone(vsm_zone_h zone)
1589 {
1590     if (zone == NULL) {
1591         errno = EINVAL;
1592         return NULL;
1593     }
1594     if (zone != zone->parent) {
1595         errno = EINVAL;
1596         return NULL;
1597     }
1598
1599     return zone;
1600 }
1601
1602 static int dummy_is_equivalent_zone(vsm_context_h  /*ctx*/, pid_t  /*pid*/)
1603 {
1604     return 1;
1605 }
1606
1607 static int dummy_get_host_pid(vsm_zone_h zone, pid_t pid)
1608 {
1609     if (zone == zone->parent)
1610         return pid;
1611
1612     return -VSM_ERROR_NO_OBJECT;
1613 }
1614
1615 static int dummy_grant_device(vsm_zone_h  /*zone*/, const char * /*path*/, uint32_t  /*flags*/)
1616 {
1617     return -VSM_ERROR_NOT_SUPPORTED;
1618 }
1619
1620 static int dummy_revoke_device(vsm_zone_h  /*zone*/, const char * /*path*/)
1621 {
1622     return -VSM_ERROR_NOT_SUPPORTED;
1623 }
1624
1625 static int dummy_declare_file(vsm_context_h  /*ctx*/, vsm_fso_type_t  /*ftype*/,
1626                   const char * /*path*/, int  /*flags*/, vsm_mode_t  /*mode*/)
1627 {
1628     return VSM_ERROR_NONE;
1629 }
1630
1631 static int dummy_declare_link(vsm_context_h  /*ctx*/, const char *source,
1632                   const char * /*target*/)
1633 {
1634     int ret;
1635
1636     ret = access(source, F_OK);
1637     if (ret != 0)
1638         return -VSM_ERROR_NO_OBJECT;
1639
1640     return VSM_ERROR_NONE;
1641 }
1642
1643 struct vasum_ops dummy_ops;
1644 static int dummy_ops_init() {
1645     dummy_ops.create_zone = dummy_create_zone;
1646     dummy_ops.destroy_zone = dummy_destroy_zone;
1647     dummy_ops.start_zone = dummy_start_zone;
1648     dummy_ops.shutdown_zone = dummy_shutdown_zone;
1649     dummy_ops.lock_zone = dummy_lock_zone;
1650     dummy_ops.unlock_zone = dummy_unlock_zone;
1651     dummy_ops.set_foreground = dummy_set_foreground;
1652     dummy_ops.get_foreground = dummy_get_foreground;
1653     dummy_ops.iterate_zone = dummy_iterate_zone;
1654     dummy_ops.lookup_zone_by_name = dummy_lookup_zone_by_name;
1655     dummy_ops.lookup_zone_by_pid = dummy_lookup_zone_by_pid;
1656     dummy_ops.attach_zone = dummy_attach_zone;
1657     dummy_ops.attach_zone_wait = dummy_attach_zone_wait;
1658     dummy_ops.join_zone = dummy_join_zone;
1659     dummy_ops.is_equivalent_zone = dummy_is_equivalent_zone;
1660     dummy_ops.get_host_pid = dummy_get_host_pid;
1661     dummy_ops.grant_device = dummy_grant_device;
1662     dummy_ops.revoke_device = dummy_revoke_device;
1663     dummy_ops.declare_file = dummy_declare_file;
1664     dummy_ops.declare_link = dummy_declare_link;
1665     return 0;
1666 }
1667 int dummy_ops_init_i = dummy_ops_init();
1668
1669
1670 } //extern "C"