revert it due to dlopen error
[sdk/target/sdbd.git] / src / subprocess.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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 <errno.h>
22
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/wait.h>
26 #include <signal.h>
27 #include "sysdeps.h"
28 #define LOG_TAG "SDBD_USER_SERVICE"
29 #include "log.h"
30 #include "sdb.h"
31 #define SHELL_COMMAND "/bin/sh"
32
33 int child_pid = 0;
34 void handle_sig_term(int sig) {
35     D("sdbu signal handler called\n");
36     if(child_pid > 0)
37     {
38         D("sdbu killing child with PID:%d\n",child_pid);
39         kill(child_pid,SIGKILL);
40     }
41     exit(0);
42 }
43
44 /* to send ptm fd to sdbd main */
45 static ssize_t send_fd(int fd, void *ptr, size_t nbytes, int sendfd)
46 {
47     struct msghdr msg;
48     struct iovec iov[1];
49     struct cmsghdr *pheader;
50     union {
51         struct cmsghdr cmhdr;
52         char control[CMSG_SPACE(sizeof(int))];
53     } control_un;
54
55     memset(&msg, 0, sizeof(msg));
56     msg.msg_control = control_un.control;
57     msg.msg_controllen = sizeof(control_un.control);
58
59     pheader = CMSG_FIRSTHDR(&msg);
60     pheader->cmsg_len = CMSG_LEN(sizeof(int));
61     pheader->cmsg_level = SOL_SOCKET;
62     pheader->cmsg_type = SCM_RIGHTS;
63     memcpy(CMSG_DATA(pheader), &sendfd, sizeof(int));
64
65     msg.msg_name = NULL;
66     msg.msg_namelen = 0;
67
68     iov[0].iov_base = ptr;
69     iov[0].iov_len = nbytes;
70     msg.msg_iov = iov;
71     msg.msg_iovlen = 1;
72
73     return sendmsg(fd, &msg, 0);
74 }
75
76 static void redirect_and_exec(int pts, const char *cmd, char * const argv[], char * const envp[])
77 {
78         if(argv == NULL) {
79                 fprintf(stderr, "sdbu argv is NULL\n");
80                 return;
81         }
82     dup2(pts, 0);
83     dup2(pts, 1);
84     dup2(pts, 2);
85
86     sdb_close(pts);
87
88     execve(cmd, argv, envp);
89 }
90
91 int main (int argc, char **argv, char **envp)
92 {
93     char devname[16];
94     int ptm;
95     pid_t pid;
96     int ret = -1;
97
98     ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC);
99     if(ptm < 0){
100         fprintf(stderr, "sdbu cannot open /dev/ptmx, errno: %d\n",errno);
101         E("sdbu cannot open /dev/ptmx, errno: %d\n",errno);
102         return ret;
103     }
104
105     if(grantpt(ptm) || unlockpt(ptm) ||
106         ptsname_r(ptm, devname, sizeof(devname)) != 0 ){
107         fprintf(stderr, "sdbu trouble with /dev/ptmx, errno: %d\n", errno);
108         E("sdbu trouble with /dev/ptmx, errno: %d\n", errno);
109         sdb_close(ptm);
110         return ret;
111     }
112     fprintf(stderr, "sdbu ptm opening success\n");
113     D("sdbu ptm opening success\n");
114
115     /* Handle the SIGTERM Signal generated in case the process takes a long time to start*/
116     signal(SIGTERM, handle_sig_term);
117     D("sdbu signal handler set with, errno: %d\n", errno);
118
119     pid = fork();
120     if(pid < 0) {
121         fprintf(stderr, "sdbu fork failed, errno: %d\n", errno);
122         sdb_close(ptm);
123         return ret;
124     }
125
126
127     /* sdbd-user's child.
128        This just open pts and exec sh */
129     if (pid == 0) {
130         D("sdbu in server process\n");
131         //usleep(500*10000);
132         //sD("after sllep\n");
133         child_pid=0;
134         int pts;
135         setsid();
136         pts = unix_open(devname, O_RDWR | O_CLOEXEC);
137         if(pts < 0) {
138             fprintf(stderr, "sdbu: child failed to open pseudo-term slave %s\n", devname);
139             E("sdbu: child failed to open pseudo-term slave %s\n", devname);
140             exit(-1);
141         }
142         fprintf(stderr, "sdbu: child open pts %s\n", devname);
143         E("sdbu: child open pts %s\n", devname);
144
145         sdb_close(ptm);
146
147         // set OOM adjustment to zero
148         {
149             char tmptext[64];
150             snprintf(tmptext, sizeof tmptext, "/proc/%d/oom_adj", getpid());
151             int fd = sdb_open(tmptext, O_WRONLY | O_CLOEXEC);
152             if (fd >= 0) {
153                 sdb_write(fd, "0", 1);
154                 sdb_close(fd);
155             } else {
156                fprintf(stderr, "sdbu: child unable to open %s due to errno:%d\n", tmptext, errno);
157                E("sdbu: child unable to open %s due to errno:%d\n", tmptext, errno);
158             }
159         }
160
161         argv[0] = SHELL_COMMAND;
162         redirect_and_exec(pts, SHELL_COMMAND, argv, envp);
163         /* if exec error */
164         fprintf(stderr, "sdbu: child exec %s failed, errno: %d\n", SHELL_COMMAND, errno);
165         exit(-1);
166     } else {
167
168         /* sdbd-user process.
169            This process open the ptm and unix socket to send ptm. */
170         /* socket create and open and bind, listen, accept and send fd here. */
171         char tmptext[32];
172         struct sockaddr_un addr;
173         int sock, s;
174         char c;
175         pid_t mypid = getpid();
176         child_pid=pid;
177         D("sdbu child_pipd=%d,pid=%d,mypid=%d\n",child_pid,pid,mypid);
178
179         D("sdbu in child process\n");
180         //usleep(500*10000);
181         //D("after sleep\n");
182
183         snprintf(tmptext, sizeof tmptext, "/tmp/.sdbduser_%d.sock", (int)mypid);
184
185         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
186         if (sock == -1) {
187             fprintf(stderr, "sdbu socket error, %d\n", errno);
188             E("sdbu socket error, %d\n", errno);
189             return -1;
190         }
191
192         char *sockpath = strndup(tmptext, strlen(tmptext));
193         if (sockpath == NULL) {
194             fprintf(stderr, "sdbu socket path error, %d\n", errno);
195             E("sdbu socket path error, %d\n", errno);
196             sdb_close(sock);
197             return -1;
198         }
199         memset(&addr, 0, sizeof(addr));
200         addr.sun_family = AF_LOCAL;
201         int len = sizeof(addr.sun_path) - 1;
202         strncpy(addr.sun_path, sockpath, len);
203         addr.sun_path[len] = '\0';
204         int slen = offsetof(struct sockaddr_un, sun_path) + strlen(sockpath);
205         if (bind(sock, (struct sockaddr *)&addr, slen) == -1) {
206             fprintf(stderr, "sdbu socket bind error, %d\n", errno);
207             E("sdbu socket bind error, %d\n", errno);
208             goto socket_fail;
209         }
210         if (listen(sock, 5) == -1) {
211             fprintf(stderr, "sdbu listen error, %d\n", errno);
212             E("sdbu listen error, %d\n", errno);
213             goto socket_fail;
214         }
215         D("sdbu before socket accept\n");
216         if ((s = sdb_socket_accept(sock, NULL, 0)) == -1) {
217             fprintf(stderr, "sdbu accept error, %d\n", errno);
218             E("sdbu accept error, %d\n", errno);
219             goto socket_fail;
220         } else {
221             D("sdbu after socket accept\n");
222             /* send ptm fd to sdbd */
223             if (send_fd(s, &c, 1, ptm) != 0) {
224                 fprintf(stderr, "sdbu send fd error, %d\n", errno);
225                 E("sdbu send fd error, %d\n", errno);
226             }
227             sdb_close(s);
228         }
229 socket_fail:
230         sdb_close(sock);
231         sdb_unlink(sockpath);
232         free(sockpath);
233         /* socket end */
234
235         return 0;
236     }
237 }