logger: set thread id column width to 2
[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(__attribute__((unused)) int type,
282                    __attribute__((unused)) const char *tag,
283                    const char *fmt, ...) {
284     va_list arg_ptr;
285     char buf[255];
286     LOGS("type=" << type << " tag=" << tag);
287     va_start(arg_ptr, fmt);
288     vsnprintf(buf, sizeof(buf), fmt, arg_ptr);
289     va_end(arg_ptr);
290     buf[sizeof(buf)-1]=0;
291     LOGD("msg=" << buf);
292 }
293
294 #define MAX_ERROR_MSG    0x1000
295 #define BUF_SIZE    4096
296
297 #define SMACK_LABEL_LEN 8
298 #define ERROR(...) do{}while(0)
299 #define WARN(...) do{}while(0)
300 #define DEBUG(...) do{}while(0)
301 #define INFO(...) do{}while(0)
302
303 // lib/utils.c
304 const char *const fso_type_strtab[] = {
305     "Directory",
306     "Regular file",
307     "FIFO",
308     "Socket",
309     "Device node"
310 };
311
312 API const char *fso_type_to_string(vsm_fso_type_t fso)
313 {
314     LOGS("");
315     if (fso < 0 || fso > VSM_FSO_MAX_TYPE) {
316         return NULL;
317     }
318
319     return fso_type_strtab[fso];
320 }
321
322 API int wait_for_pid_status(pid_t pid)
323 {
324     LOGS("");
325     int status, ret;
326
327  again:
328     ret = waitpid(pid, &status, 0);
329     if (ret == -1) {
330         if (errno == EINTR) {
331             goto again;
332         } else {
333             ERROR("waitpid pid : %d error : %s", pid, strerror(errno));
334             return -1;
335         }
336     }
337     if (ret != pid)
338         goto again;
339     return status;
340 }
341
342 API vsm_fso_type_t fso_string_to_type(char *str)
343 {
344     LOGS("");
345     int i;
346     for (i = 0; i <= VSM_FSO_MAX_TYPE; i++) {
347         int len = strlen(fso_type_strtab[i]);
348         if (strncmp(str, fso_type_strtab[i], len) == 0)
349             return static_cast<vsm_fso_type_t>(i);
350     }
351
352     return static_cast<vsm_fso_type_t>(-1);
353 }
354
355 API int mkdir_p(const char *dir, mode_t mode)
356 {
357     LOGS("");
358     const char *tmp = dir;
359     const char *orig = dir;
360
361     do {
362         dir = tmp + strspn(tmp, "/");
363         tmp = dir + strcspn(dir, "/");
364         char *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     int status = 0;
423
424     if (lstat(path, &path_stat) < 0) {
425         if (errno != ENOENT) {
426             ERROR("Unable to stat : %s");
427             return -1;
428         }
429     }
430
431     if (S_ISDIR(path_stat.st_mode)) {
432         struct dirent *d;
433         DIR *dp;
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     char buffer[BUF_SIZE];
477
478     if ((sfp = fopen(source, "r")) == NULL) {
479         ERROR("Unable to open source : %s", source);
480         return -1;
481     }
482
483     if ((dfp = fopen(dest, "w+")) == NULL) {
484         ERROR("Unable to open destination : %s", dest);
485         fclose(sfp);
486         return -1;
487     }
488
489     while (1) {
490         size_t nread, nwritten, size = BUF_SIZE;
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, "%7d", &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, "%7d", &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, "%1023s", 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;
1273     int ret = 0;
1274     UNUSED(ctx);
1275
1276     for (i = 0; i < argc; i++) {
1277         int nargs, done, rc;
1278         done = nargs = 0;
1279         parser_init_state(&state, argv[i]);
1280
1281         while (!done) {
1282             int token = tokenize(&state);
1283             switch (token) {
1284             case T_EOF:
1285                 if (nargs && func) {
1286                     rc = func(nargs, args);
1287                     if (rc < 0) {
1288                         WARN("Key word callback error");
1289                     }
1290                     nargs = 0;
1291                 }
1292                 done = 1;
1293                 break;
1294             case T_STATEMENT:
1295                 if (nargs < PARSER_MAXARGS) {
1296                     args[nargs++] = state.stmt;
1297                 }
1298                 break;
1299             }
1300         }
1301     }
1302
1303     return ret;
1304 }
1305
1306 API int parse_stream_core(struct parser_context *ctx, char *s)
1307 {
1308     LOGS("");
1309     struct unit_keyword_callback *kw;
1310     struct parser_state state;
1311     char *args[PARSER_MAXARGS];
1312     int nargs, rc;
1313
1314     nargs = 0;
1315     parser_init_state(&state, s);
1316
1317     for (;;) {
1318         int token = tokenize(&state);
1319         switch (token) {
1320         case T_EOF:
1321             return 0;
1322         case T_NEWLINE:
1323             if (nargs) {
1324                 if ((kw = keyword_lookup(ctx, args[0])) != NULL) {
1325                     rc = parse_statement(ctx, nargs - 1,
1326                                  &args[1],
1327                                  kw->func);
1328                     if (rc < 0) {
1329                         return -EINVAL;
1330                     }
1331                 }
1332
1333                 nargs = 0;
1334             }
1335             break;
1336         case T_STATEMENT:
1337             if (nargs < PARSER_MAXARGS) {
1338                 args[nargs++] = state.stmt;
1339             }
1340             break;
1341         }
1342     }
1343
1344     return 0;
1345 }
1346
1347 /* reads a file, making sure it is terminated with \n \0 */
1348 static char *open_stream(const char *name, unsigned int *_sz)
1349 {
1350     int sz, fd;
1351     char *data = NULL;
1352
1353     fd = open(name, O_RDONLY);
1354     if (fd < 0)
1355         return NULL;
1356
1357     sz = lseek(fd, 0, SEEK_END);
1358     if (sz < 0)
1359         goto oops;
1360
1361     if (lseek(fd, 0, SEEK_SET) != 0)
1362         goto oops;
1363
1364     data = (char *)malloc(sz + 2);
1365     if (data == 0)
1366         goto oops;
1367
1368     if (read(fd, data, sz) != sz)
1369         goto oops;
1370
1371     close(fd);
1372
1373     data[sz] = '\n';
1374     data[sz + 1] = 0;
1375     if (_sz)
1376         *_sz = sz;
1377
1378     return data;
1379
1380  oops:
1381     close(fd);
1382     if (data != 0)
1383         free(data);
1384
1385     return NULL;
1386 }
1387
1388 API int parse_stream(const char *name, struct unit_parser *parser)
1389 {
1390     LOGS("");
1391     char *stream;
1392     struct parser_context *ctx;
1393
1394     ctx = (struct parser_context *)malloc(sizeof(struct parser_context));
1395     if (ctx == NULL) {
1396         return -ENOMEM;
1397     }
1398
1399     ctx->kw = parser->kw;
1400
1401     /* File open & return file context */
1402     stream = open_stream(name, NULL);
1403     if (stream == NULL) {
1404         free(ctx);
1405         return -1;
1406     }
1407
1408     parse_stream_core(ctx, stream);
1409
1410     free(stream);
1411     free(ctx);
1412
1413     return 0;
1414 }
1415 API struct vsm_netdev *alloc_netdev(struct vsm_zone * /*zone*/, vsm_netdev_type_t  /*type*/, const char * /*netdev_name*/) {
1416     LOGS("");
1417     return NULL;
1418 }
1419 API void enter_to_ns(pid_t  /*pid*/, char * /*name*/) {
1420     LOGS("");
1421 }
1422
1423 // dummy-ops
1424 static int dummy_create_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/,
1425                  const char * /*template*/, int  /*flags*/)
1426 {
1427     return -VSM_ERROR_NOT_SUPPORTED;
1428 }
1429
1430 static int dummy_destroy_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/, int  /*force*/)
1431 {
1432     return -VSM_ERROR_NOT_SUPPORTED;
1433 }
1434
1435 static int dummy_start_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/)
1436 {
1437     return -VSM_ERROR_NOT_SUPPORTED;
1438 }
1439
1440 static int dummy_shutdown_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/, int  /*force*/)
1441 {
1442     return -VSM_ERROR_NOT_SUPPORTED;
1443 }
1444
1445 static int dummy_lock_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/, int  /*shutdown*/)
1446 {
1447     return -VSM_ERROR_NOT_SUPPORTED;
1448 }
1449
1450 static int dummy_unlock_zone(vsm_context_h  /*ctx*/, const char * /*zone_name*/)
1451 {
1452     return -VSM_ERROR_NOT_SUPPORTED;
1453 }
1454
1455 static int dummy_set_foreground(vsm_zone_h  zone)
1456 {
1457     if (zone == NULL)
1458         return -VSM_ERROR_INVALID;
1459
1460     if (zone->parent == zone) {
1461         return VSM_ERROR_NONE;
1462     }
1463     return -VSM_ERROR_NO_OBJECT;
1464 }
1465
1466 static vsm_zone_h dummy_get_foreground(vsm_context_h  ctx)
1467 {
1468     if (ctx == NULL) {
1469         errno = EINVAL;
1470         return NULL;
1471     }
1472
1473     return ctx->root_zone;
1474 }
1475
1476 static int dummy_iterate_zone(vsm_context_h  ctx, vsm_zone_iter_cb  callback, void *user_data)
1477 {
1478     if (callback) {
1479         callback(ctx->root_zone, user_data);
1480     }
1481     return VSM_ERROR_NONE;
1482 }
1483
1484 static vsm_zone_h dummy_lookup_zone_by_name(vsm_context_h ctx, const char *name)
1485 {
1486     if (strcmp(name, "") != 0) {
1487         errno = ESRCH;
1488         return NULL;
1489     }
1490
1491     return ctx->root_zone;
1492 }
1493
1494 static vsm_zone_h dummy_lookup_zone_by_pid(vsm_context_h ctx, pid_t  /*pid*/)
1495 {
1496     if (ctx == NULL)
1497         return NULL;
1498
1499     return ctx->root_zone;
1500 }
1501
1502 static int dummy_attach_zone(vsm_context_h ctx, const char *zone_name,
1503                  vsm_attach_command_s * command,
1504                  vsm_attach_options_s * opts,
1505                  pid_t * attached_process)
1506 {
1507     pid_t pid;
1508     struct vsm_attach_options_s options;
1509
1510     if (command == NULL || command->exec == NULL || zone_name == NULL) {
1511         ERROR("Invalid arguments");
1512         ctx->error = VSM_ERROR_INVALID;
1513         return -VSM_ERROR_INVALID;
1514     }
1515
1516     if (strcmp("", zone_name) != 0) {
1517         ctx->error = VSM_ERROR_INVALID;
1518         return -VSM_ERROR_INVALID;
1519     }
1520
1521     if (opts == NULL) {
1522         opts = &options;
1523         opts->uid = getuid();
1524         opts->gid = getgid();
1525         opts->env_num = 0;
1526         opts->extra_env = NULL;
1527     }
1528
1529     pid = fork();
1530     if (pid == 0) {
1531         if (opts->extra_env != NULL) {
1532             while (*opts->extra_env)
1533                 putenv(*opts->extra_env++);
1534         }
1535
1536         if (getuid() == 0 && opts->uid != 0) {
1537             if (setuid(opts->uid) != 0) {
1538                 ERROR("Failed to set uid : %d", opts->uid);
1539             }
1540         } else {
1541             WARN("setuid() is not permitted");
1542         }
1543
1544         if (getgid() == 0 && opts->gid != 0) {
1545             if (setgid(opts->gid) != 0) {
1546                 ERROR("Failed to set gid : %d", opts->gid);
1547             }
1548         } else {
1549             WARN("setgid() is not permitted");
1550         }
1551
1552         if (execvp(command->exec, command->argv) < 0) {
1553             ERROR("exevp failed : %s, %s", command->exec,
1554                   strerror(errno));
1555             exit(EXIT_FAILURE);
1556         }
1557     } else {
1558         *attached_process = pid;
1559     }
1560
1561     return VSM_ERROR_NONE;
1562 }
1563
1564 static int dummy_attach_zone_wait(vsm_context_h  ctx, const char *zone_name,
1565                   vsm_attach_command_s * command,
1566                   vsm_attach_options_s * opts)
1567 {
1568     pid_t pid = 0;
1569     int ret, status;
1570
1571     ret = dummy_attach_zone(ctx, zone_name, command, opts, &pid);
1572     if (ret != VSM_ERROR_NONE) {
1573         ERROR("API Failed.");
1574         return ret;
1575     }
1576
1577     status = wait_for_pid_status(pid);
1578     if (status == -1) {
1579         ctx->error = VSM_ERROR_GENERIC;
1580         return -VSM_ERROR_GENERIC;
1581     }
1582
1583     INFO("attached process extied : pid - %d, exit code : %d", pid,
1584          WEXITSTATUS(status));
1585
1586     return status;
1587 }
1588
1589 static vsm_zone_h dummy_join_zone(vsm_zone_h zone)
1590 {
1591     if (zone == NULL) {
1592         errno = EINVAL;
1593         return NULL;
1594     }
1595     if (zone != zone->parent) {
1596         errno = EINVAL;
1597         return NULL;
1598     }
1599
1600     return zone;
1601 }
1602
1603 static int dummy_is_equivalent_zone(vsm_context_h  /*ctx*/, pid_t  /*pid*/)
1604 {
1605     return 1;
1606 }
1607
1608 static int dummy_get_host_pid(vsm_zone_h zone, pid_t pid)
1609 {
1610     if (zone == zone->parent)
1611         return pid;
1612
1613     return -VSM_ERROR_NO_OBJECT;
1614 }
1615
1616 static int dummy_grant_device(vsm_zone_h  /*zone*/, const char * /*path*/, uint32_t  /*flags*/)
1617 {
1618     return -VSM_ERROR_NOT_SUPPORTED;
1619 }
1620
1621 static int dummy_revoke_device(vsm_zone_h  /*zone*/, const char * /*path*/)
1622 {
1623     return -VSM_ERROR_NOT_SUPPORTED;
1624 }
1625
1626 static int dummy_declare_file(vsm_context_h  /*ctx*/, vsm_fso_type_t  /*ftype*/,
1627                   const char * /*path*/, int  /*flags*/, vsm_mode_t  /*mode*/)
1628 {
1629     return VSM_ERROR_NONE;
1630 }
1631
1632 static int dummy_declare_link(vsm_context_h  /*ctx*/, const char *source,
1633                   const char * /*target*/)
1634 {
1635     int ret;
1636
1637     ret = access(source, F_OK);
1638     if (ret != 0)
1639         return -VSM_ERROR_NO_OBJECT;
1640
1641     return VSM_ERROR_NONE;
1642 }
1643
1644 struct vasum_ops dummy_ops;
1645 static int dummy_ops_init() {
1646     dummy_ops.create_zone = dummy_create_zone;
1647     dummy_ops.destroy_zone = dummy_destroy_zone;
1648     dummy_ops.start_zone = dummy_start_zone;
1649     dummy_ops.shutdown_zone = dummy_shutdown_zone;
1650     dummy_ops.lock_zone = dummy_lock_zone;
1651     dummy_ops.unlock_zone = dummy_unlock_zone;
1652     dummy_ops.set_foreground = dummy_set_foreground;
1653     dummy_ops.get_foreground = dummy_get_foreground;
1654     dummy_ops.iterate_zone = dummy_iterate_zone;
1655     dummy_ops.lookup_zone_by_name = dummy_lookup_zone_by_name;
1656     dummy_ops.lookup_zone_by_pid = dummy_lookup_zone_by_pid;
1657     dummy_ops.attach_zone = dummy_attach_zone;
1658     dummy_ops.attach_zone_wait = dummy_attach_zone_wait;
1659     dummy_ops.join_zone = dummy_join_zone;
1660     dummy_ops.is_equivalent_zone = dummy_is_equivalent_zone;
1661     dummy_ops.get_host_pid = dummy_get_host_pid;
1662     dummy_ops.grant_device = dummy_grant_device;
1663     dummy_ops.revoke_device = dummy_revoke_device;
1664     dummy_ops.declare_file = dummy_declare_file;
1665     dummy_ops.declare_link = dummy_declare_link;
1666     return 0;
1667 }
1668 int dummy_ops_init_i = dummy_ops_init();
1669
1670
1671 } //extern "C"