2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 //#define TRACE_TAG TRACE_SERVICES
27 #define LOG_TAG "SDBD_TRACE_SERVICES"
31 #include "file_sync_service.h"
33 #include <sys/inotify.h>
35 #include <sys/socket.h>
40 #include <system_info.h>
41 #include <tzplatform_config.h>
42 #include <sys/smack.h>
48 #include <sys/ioctl.h>
50 #include "sdbd_plugin.h"
53 #define ENV_BUF_MAX 4096
55 typedef struct stinfo stinfo;
58 void (*func)(int fd, void *cookie);
63 extern int create_async_extcmd_proc_thread( int cmd, parameters* in );
65 void *service_bootstrap_func(void *x)
68 sti->func(sti->fd, sti->cookie);
73 static int is_support_interactive_shell()
75 return (!strncmp(g_capabilities.intershell_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
79 extern int recovery_mode;
81 static void recover_service(int s, void *cookie)
83 unsigned char buf[4096];
84 unsigned count = (unsigned) cookie;
87 fd = sdb_creat("/tmp/update", 0644);
94 unsigned xfer = (count > 4096) ? 4096 : count;
95 if(readx(s, buf, xfer)) break;
96 if(writex(fd, buf, xfer)) break;
101 writex(s, "OKAY", 4);
103 writex(s, "FAIL", 4);
108 fd = sdb_creat("/tmp/update.begin", 0644);
114 static int is_support_rootonoff()
116 return (!strncmp(g_capabilities.rootonoff_support, PLUGIN_RET_ENABLED, strlen(PLUGIN_RET_ENABLED)));
119 void rootshell_service(int fd, void *cookie)
122 char *mode = (char*) cookie;
124 if (!strcmp(mode, "on")) {
125 if (rootshell_mode == 1) {
126 //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n");
127 // do not show message
129 if (is_support_rootonoff()) {
131 //allows a permitted user to execute a command as the superuser
132 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
134 snprintf(buf, sizeof(buf), "Permission denied\n");
136 writex(fd, buf, strlen(buf));
138 } else if (!strcmp(mode, "off")) {
139 if (rootshell_mode == 1) {
141 snprintf(buf, sizeof(buf), "Switched to 'sdk user' account mode\n");
142 writex(fd, buf, strlen(buf));
145 snprintf(buf, sizeof(buf), "Unknown command option : %s\n", mode);
146 writex(fd, buf, strlen(buf));
148 D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : SDK_USER_NAME);
153 enum tzplatform_get_env_error_status {
154 NO_ERROR_TZPLATFORM_ENV = 0,
155 ERROR_TZPLATFORM_ENV_GENERAL = 1,
156 ERROR_TZPLATFORM_ENV_INVALID_VARIABLES = 2,
159 void get_tzplatform_env(int fd, void *cookie) {
160 char buf[PATH_MAX] = { 0, };
161 char *env_name = (char*) cookie;
162 D("environment variable name: %s\n", env_name);
163 enum tzplatform_variable env_id = tzplatform_getid(env_name);
164 if (env_id != _TZPLATFORM_VARIABLES_INVALID_) {
165 const char *env_value = tzplatform_getenv(env_id);
167 D("environment value : %s\n", env_value);
168 snprintf(buf, sizeof(buf), "%d%s", NO_ERROR_TZPLATFORM_ENV, env_value);
170 E("failed to get environment value using tzplatform_getenv");
171 snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_GENERAL);
174 E("environment name (%s) is invalid\n", env_name);
175 snprintf(buf, sizeof(buf), "%d", ERROR_TZPLATFORM_ENV_INVALID_VARIABLES);
177 writex(fd, buf, strlen(buf));
182 void reboot_service(int fd, void *arg)
190 /* Attempt to unmount the SD card first.
191 * No need to bother checking for errors.
195 /* ask vdc to unmount it */
196 // prevent: Use of untrusted string value (TAINTED_STRING)
197 execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
198 getenv("EXTERNAL_STORAGE"), "force", NULL);
199 } else if (pid > 0) {
200 /* wait until vdc succeeds or fails */
201 waitpid(pid, &ret, 0);
204 ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
206 snprintf(buf, sizeof(buf), "reboot failed: %s errno:%d\n", errno);
207 writex(fd, buf, strlen(buf));
214 #define EVENT_SIZE ( sizeof (struct inotify_event) )
215 #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
216 #define CS_PATH tzplatform_getenv(TZ_SYS_CRASH)
218 void inoti_service(int fd, void *arg)
222 char buffer[BUF_LEN];
224 I( "inoti_service start\n");
225 ifd = inotify_init();
228 E( "inotify_init failed\n");
233 wd = inotify_add_watch(ifd, CS_PATH, IN_CREATE | IN_MOVE);
235 E("inotify_add_watch failed (errno :%d)\n", errno);
243 length = sdb_read( ifd, buffer, BUF_LEN );
246 E( "inoti read failed\n");
249 int payload = length >= EVENT_SIZE ? length - EVENT_SIZE : 0;
250 while (i >= 0 && i <= payload) {
251 struct inotify_event *event = (struct inotify_event *) &buffer[i];
253 if (event->mask & IN_CREATE) {
254 if (!(event->mask & IN_ISDIR)) {
256 int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
258 D( "The file %s was created.\n", cspath);
259 writex(fd, cspath, len);
262 E( "asprintf was failed\n" );
265 } else if (event->mask & IN_MOVE) {
266 if (!(event->mask & IN_ISDIR)) {
268 int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
270 D("The file %s was moved.\n", cspath);
271 writex(fd, cspath, len);
274 E("asprintf was failed\n");
279 if (i + EVENT_SIZE + event->len < event->len) { // in case of integer overflow
282 i += EVENT_SIZE + event->len;
287 inotify_rm_watch( ifd, wd );
290 I( "inoti_service end\n");
294 static void echo_service(int fd, void *cookie)
302 r = read(fd, buf, 4096);
303 if(r == 0) goto done;
305 if(errno == EINTR) continue;
318 if((r < 0) && (errno == EINTR)) continue;
327 static int create_service_thread(void (*func)(int, void *), void *cookie)
333 if(sdb_socketpair(s)) {
334 E("cannot create service socket pair\n");
338 sti = malloc(sizeof(stinfo));
339 if(sti == 0) fatal("cannot allocate stinfo");
341 sti->cookie = cookie;
344 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
348 E("cannot create service thread\n");
352 D("service thread started, %d:%d\n",s[0], s[1]);
356 static void redirect_and_exec(int pts, const char *cmd, char * const argv[], char * const envp[])
364 execve(cmd, argv, envp);
367 int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
372 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
374 E("[ cannot open /dev/ptmx - errno:%d ]\n",errno);
377 if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
378 E("[ cannot set cloexec to /dev/ptmx - errno:%d ]\n",errno);
381 if(grantpt(ptm) || unlockpt(ptm) ||
382 ptsname_r(ptm, devname, sizeof(devname)) != 0 ){
383 E("[ trouble with /dev/ptmx - errno:%d ]\n", errno);
390 E("- fork failed: errno:%d -\n", errno);
400 pts = unix_open(devname, O_RDWR);
402 fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
408 // set OOM adjustment to zero
411 //snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
412 snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
413 int fd = sdb_open(text, O_WRONLY);
415 sdb_write(fd, "0", 1);
418 // FIXME: not supposed to be here
419 E("sdb: unable to open %s due to errno:%d\n", text, errno);
423 if (should_drop_privileges()) {
424 if (argv[2] != NULL && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
426 D("sdb: executes root commands!!:%s\n", argv[2]);
428 if (getuid() != g_sdk_user_id && set_sdk_user_privileges(RESERVE_CAPABILITIES_AFTER_FORK) < 0) {
429 fprintf(stderr, "failed to set SDK user privileges\n");
434 set_root_privileges();
436 redirect_and_exec(pts, cmd, argv, envp);
437 fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n",
441 // Don't set child's OOM adjustment to zero.
442 // Let the child do it itself, as sometimes the parent starts
443 // running before the child has a /proc/pid/oom_adj.
444 // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
449 /* receive the ptm from child, sdbd-user */
450 static ssize_t recv_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
454 struct cmsghdr *pheader;
456 struct cmsghdr cmhdr;
457 char control[CMSG_SPACE(sizeof(int))];
461 memset(&msg, 0, sizeof(msg));
462 msg.msg_control = control_un.control;
463 msg.msg_controllen = sizeof(control_un.control);
468 iov[0].iov_base = ptr;
469 iov[0].iov_len = nbytes;
473 if ((ret = recvmsg(fd, &msg, 0)) <= 0) {
477 if ((pheader = CMSG_FIRSTHDR(&msg)) != NULL &&
478 pheader->cmsg_len == CMSG_LEN(sizeof(int))) {
479 if (pheader->cmsg_level != SOL_SOCKET) {
480 I("sdb: control level != SOL_SOCKET");
483 if (pheader->cmsg_type != SCM_RIGHTS) {
484 I("sdb: control type != SCM_RIGHTS");
487 memcpy(recvfd, CMSG_DATA(pheader), sizeof(int));
495 int create_userprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[])
499 E("- fork failed: errno:%d -\n", errno);
504 if (should_drop_privileges()) {
505 if (argv[2] != NULL && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) {
506 set_root_privileges();
507 D("sdb: executes root commands!!:%s\n", argv[2]);
509 if (getuid() != g_sdk_user_id && set_sdk_user_privileges(RESERVE_CAPABILITIES_AFTER_FORK) < 0) {
510 E("failed to set SDK user privileges\n");
515 set_root_privileges();
518 execve(cmd, argv, envp);
519 E("- exec '%s' failed: (errno:%d) -\n", cmd, errno);
522 // Don't set child's OOM adjustment to zero.
523 // Let the child do it itself, as sometimes the parent starts
524 // running before the child has a /proc/pid/oom_adj.
525 // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
528 struct sockaddr_un addr;
532 /* The child process will open .sdbduser_pid.sock socket.
533 This socket transfers the ptm fd that was opened by child process.
534 You can see related code on subprocess.c file. */
535 snprintf(tmptext, sizeof tmptext, "/tmp/.sdbduser_%d.sock", (int)(*pid));
536 char *sockpath = strdup(tmptext);
537 if (sockpath == NULL) {
538 E("failed to get socket path, %d\n", errno);
541 D("read fd socket is %s\n", sockpath);
543 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
545 E("socket error, %d\n", errno);
549 memset(&addr, 0, sizeof(addr));
550 addr.sun_family = AF_LOCAL;
551 s_strncpy(addr.sun_path, sockpath, strlen(sockpath));
552 int slen = offsetof(struct sockaddr_un, sun_path) + strlen(sockpath);
553 while (connect(sock, (struct sockaddr *)&addr, slen) == -1
555 D("try to connect socket %s, %d times.\n", sockpath, trycnt++);
556 /* sleep maximum 100 times */
560 E("failed to connect, errno: %d\n", errno);
561 if (sdb_close(sock) == -1) {
562 E("close sock error, %d\n", errno);
569 if (recv_fd(sock, &c, 1, &ptm) == -1) {
570 E("recv_fd error, %d\n", errno);
571 if (sdb_close(sock) == -1) {
572 E("close sock error, %d\n", errno);
577 D("got ptm fd from child, fd: %d\n", ptm);
580 if (sdb_close(sock) == -1) {
581 E("close sock error, %d\n", errno);
585 I("getting child's ptm successed.\n");
590 #define USER_DAEMON_COMMAND "/usr/sbin/sdbd-user"
591 #define LOGIN_COMMAND "/bin/login"
592 #define SUPER_USER "root"
593 #define LOGIN_CONFIG "/etc/login.defs"
595 static void subproc_waiter_service(int fd, void *cookie)
597 pid_t pid = (pid_t)((intptr_t)cookie);
599 D("entered. fd=%d of pid=%d\n", fd, pid);
602 pid_t p = waitpid(pid, &status, 0);
603 D("entered fd=%d, post waitpid(pid=%d)\n", fd, p);
605 D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
606 if (WIFEXITED(status)) {
607 D("*** Exit code %d\n", WEXITSTATUS(status));
609 } else if (WIFSIGNALED(status)) {
610 D("*** Killed by signal %d\n", WTERMSIG(status));
613 D("*** Killed by unknown code %d\n", status);
618 D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
619 if (SHELL_EXIT_NOTIFY_FD >=0) {
621 res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
622 D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
623 SHELL_EXIT_NOTIFY_FD, pid, res, errno);
627 void get_env(char *key, char **env)
633 fp = fopen (LOGIN_CONFIG, "r");
638 while (fgets(buf, (int) sizeof (buf), fp) != NULL) {
640 e = buf + (strlen(buf) - 1);
643 while( (e > s) && (*e == ' ' || *e == '\n' || *e == '\t')) {
648 while(*s != '\0' && (*s == ' ' || *s == '\t' || *s == '\n')) {
652 // skip comment or null string
653 if (*s == '#' || *s == '\0') {
656 value = s + strcspn(s, " \t");
659 if(!strcmp(buf, key)) {
660 *env = strdup(value);
668 static int create_subproc_thread(const char *name, int lines, int columns)
675 char *trim_value = NULL;
677 char *envp[MAX_TOKENS];
680 memset(path, 0, sizeof(path));
681 memset(envp, 0, sizeof(envp));
683 envp[envp_cnt++] = strdup("TERM=linux");
684 envp[envp_cnt++] = strdup("DISPLAY=:0");
686 if (should_drop_privileges()) {
687 if (g_sdk_home_dir_env) {
688 envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
690 envp[envp_cnt++] = strdup("HOME=/home/owner");
692 get_env("ENV_PATH", &value);
694 get_env("ENV_SUPATH", &value);
696 get_env("ENV_ROOTPATH", &value);
698 envp[envp_cnt++] = strdup("HOME=/root");
701 trim_value = str_trim(value);
702 if (trim_value != NULL) {
703 // if string is not including 'PATH=', append it.
704 if (strncmp(trim_value, "PATH", 4)) {
705 snprintf(path, sizeof(path), "PATH=%s", trim_value);
707 snprintf(path, sizeof(path), "%s", trim_value);
709 envp[envp_cnt++] = strdup(path);
711 snprintf(path, sizeof(path), "%s", value);
712 envp[envp_cnt++] = strdup(path);
717 /* get environment variables from plugin */
718 char *envp_plugin = NULL;
719 envp_plugin = malloc(ENV_BUF_MAX);
720 if (envp_plugin == NULL) {
721 E("Cannot allocate the shell commnad buffer.");
724 memset(envp_plugin, 0, ENV_BUF_MAX);
725 if (!request_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
726 envp_plugin, ENV_BUF_MAX)) {
727 E("Failed to convert the shell command. (%s)\n", name);
731 if(envp_plugin[0] != '\0') {
732 envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
737 /* Last element of envp must be the NULL-terminator to prevent execvp fail */
738 envp[envp_cnt] = NULL;
740 if(name) { // in case of shell execution directly
741 // Check the shell command validation.
742 if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
743 E("This shell command is invalid. (%s)\n", name);
747 // Convert the shell command.
748 char *new_cmd = NULL;
749 new_cmd = malloc(SDBD_SHELL_CMD_MAX);
750 if(new_cmd == NULL) {
751 E("Cannot allocate the shell commnad buffer.");
755 memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
756 if(!request_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
757 E("Failed to convert the shell command. (%s)\n", name);
762 D("converted cmd : %s\n", new_cmd);
772 ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
774 } else { // in case of shell interactively
775 // Check the capability for interactive shell support.
776 if (!is_support_interactive_shell()) {
777 E("This platform dose NOT support the interactive shell\n");
781 char * const args[] = {
786 ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
787 #if 0 // FIXME: should call login command instead of /bin/sh
788 if (should_drop_privileges()) {
794 ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, args, envp);
802 ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
807 /* free environment variables */
810 for(i = 0; i < envp_cnt; i++) {
812 D("envp[%d] = %s\n", i, envp[i]);
818 D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
821 E("cannot create service thread\n");
825 if (lines > 0 && columns > 0) {
826 D("shell size lines=%d, columns=%d\n", lines, columns);
827 struct winsize win_sz;
828 win_sz.ws_row = lines;
829 win_sz.ws_col = columns;
831 if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
832 E("failed to sync window size.\n");
836 sti = malloc(sizeof(stinfo));
837 if(sti == 0) fatal("cannot allocate stinfo");
838 sti->func = subproc_waiter_service;
839 sti->cookie = (void*)((intptr_t)pid);
842 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
845 E("cannot create service thread\n");
849 D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
853 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
858 #ifdef EXEC_AFTER_FORK
859 if(sdb_socketpair_without_execclose(s)) {
860 E("cannot create service socket pair\n");
864 if(sdb_socketpair(s)) {
865 E("cannot create service socket pair\n");
870 D("SERVICE create_sync_subprocess cookie=%s\n",(char*)cookie);
875 #ifdef EXEC_AFTER_FORK
876 // exec the new process to do file sync
877 char *fname="/usr/sbin/sdbd-service";
881 sprintf(targ,"%d",s[1]);
882 sprintf(smarg, "%d",rootshell_mode);
883 D("SERVICE fd to be used by child process %d",s[1]);
884 D("SERVICE rootmode to be used by child process %s",smarg);
887 arg[2]= strdup((char*)cookie);
888 D("SERVICE cookie to be used by child process %s",arg[2]);
896 } else if (pid > 0) {
897 D("SERVICE fd passed by parent process %d",s[1]);
899 // FIXME: do not wait child process hear
900 //waitpid(pid, &ret, 0);
902 E("- fork failed: errno:%d -\n", errno);
905 E("cannot create sync service sub process\n");
909 sti = malloc(sizeof(stinfo));
910 if(sti == 0) fatal("cannot allocate stinfo");
911 sti->func = subproc_waiter_service;
912 sti->cookie = (void*)((intptr_t)pid);
915 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
918 printf("cannot create service monitor thread\n");
922 D("service process started, fd=%d pid=%d\n",s[0], pid);
926 static int create_syncproc_thread(const char *cmd)
930 ret_fd = create_sync_subprocess(file_sync_service, (void*)cmd);
931 // FIXME: file missing bug when root on mode
933 if (should_drop_privileges()) {
934 ret_fd = create_sync_subprocess(file_sync_service, NULL);
936 ret_fd = create_service_thread(file_sync_service, NULL);
943 static int create_extcmd_subproc_thread(const char *name, int lines, int columns)
950 char *trim_value = NULL;
952 char *envp[MAX_TOKENS];
955 memset(path, 0, sizeof(path));
956 memset(envp, 0, sizeof(envp));
958 envp[envp_cnt++] = strdup("TERM=linux");
959 envp[envp_cnt++] = strdup("DISPLAY=:0");
961 if (should_drop_privileges()) {
962 if (g_sdk_home_dir_env) {
963 envp[envp_cnt++] = strdup(g_sdk_home_dir_env);
965 envp[envp_cnt++] = strdup("HOME=/home/owner");
967 get_env("ENV_PATH", &value);
969 get_env("ENV_SUPATH", &value);
971 get_env("ENV_ROOTPATH", &value);
973 envp[envp_cnt++] = strdup("HOME=/root");
976 trim_value = str_trim(value);
977 if (trim_value != NULL) {
978 // if string is not including 'PATH=', append it.
979 if (strncmp(trim_value, "PATH", 4)) {
980 snprintf(path, sizeof(path), "PATH=%s", trim_value);
982 snprintf(path, sizeof(path), "%s", trim_value);
984 envp[envp_cnt++] = strdup(path);
986 snprintf(path, sizeof(path), "%s", value);
987 envp[envp_cnt++] = strdup(path);
992 /* get environment variables from plugin */
993 char *envp_plugin = NULL;
994 envp_plugin = malloc(ENV_BUF_MAX);
995 if (envp_plugin == NULL) {
996 E("Cannot allocate the shell commnad buffer.");
999 memset(envp_plugin, 0, ENV_BUF_MAX);
1000 if (!request_extcmd_conversion_to_plugin(PLUGIN_SYNC_CMD_GET_SHELL_ENV, NULL,
1001 envp_plugin, ENV_BUF_MAX)) {
1002 E("Failed to convert the shell command. (%s)\n", name);
1006 if(envp_plugin[0] != '\0') {
1007 envp_cnt = tokenize_append(envp_plugin, "\n", envp, MAX_TOKENS, envp_cnt);
1012 /* Last element of envp must be the NULL-terminator to prevent execvp fail */
1013 envp[envp_cnt] = NULL;
1015 if(name) { // in case of shell execution directly
1016 // Check the shell command validation.
1017 if (!request_extcmd_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_SHELLCMD, name)) {
1018 E("This extcmd command is invalid. (%s)\n", name);
1022 // Convert the shell command.
1023 char *new_cmd = NULL;
1024 new_cmd = malloc(SDBD_SHELL_CMD_MAX);
1025 if(new_cmd == NULL) {
1026 E("Cannot allocate the shell commnad buffer.");
1030 memset(new_cmd, 0, SDBD_SHELL_CMD_MAX);
1031 if(!request_extcmd_conversion_to_plugin(PLUGIN_SYNC_CMD_CONVERT_SHELLCMD, name, new_cmd, SDBD_SHELL_CMD_MAX)) {
1032 E("Failed to convert the shell command. (%s)\n", name);
1037 D("converted cmd : %s\n", new_cmd);
1040 USER_DAEMON_COMMAND,
1047 ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
1049 } else { // in case of shell interactively
1050 // Check the capability for interactive shell support.
1051 if (!is_support_interactive_shell()) {
1052 E("This platform dose NOT support the interactive shell\n");
1056 char * const args[] = {
1057 USER_DAEMON_COMMAND,
1061 ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, (char * const*)args, (char * const*)envp);
1062 #if 0 // FIXME: should call login command instead of /bin/sh
1063 if (should_drop_privileges()) {
1065 USER_DAEMON_COMMAND,
1069 ret_fd = create_userprocess(USER_DAEMON_COMMAND, &pid, args, envp);
1077 ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
1082 /* free environment variables */
1085 for(i = 0; i < envp_cnt; i++) {
1087 D("envp[%d] = %s\n", i, envp[i]);
1093 D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
1096 E("cannot create service thread\n");
1100 if (lines > 0 && columns > 0) {
1101 D("shell size lines=%d, columns=%d\n", lines, columns);
1102 struct winsize win_sz;
1103 win_sz.ws_row = lines;
1104 win_sz.ws_col = columns;
1106 if (ioctl(ret_fd, TIOCSWINSZ, &win_sz) < 0) {
1107 E("failed to sync window size.\n");
1111 sti = malloc(sizeof(stinfo));
1112 if(sti == 0) fatal("cannot allocate stinfo");
1113 sti->func = subproc_waiter_service;
1114 sti->cookie = (void*)((intptr_t)pid);
1117 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
1120 E("cannot create service thread\n");
1124 D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
1128 static void get_platforminfo(int fd, void *cookie) {
1132 s_strncpy(sysinfo.platform_info_version, INFO_VERSION, sizeof(sysinfo.platform_info_version));
1134 int r = system_info_get_platform_string("http://tizen.org/system/model_name", &value);
1135 if (r != SYSTEM_INFO_ERROR_NONE) {
1136 s_strncpy(sysinfo.model_name, UNKNOWN, sizeof(sysinfo.model_name));
1137 E("fail to get system model:%d\n", errno);
1139 s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
1140 D("returns model_name:%s\n", value);
1141 if (value != NULL) {
1146 r = system_info_get_platform_string("http://tizen.org/system/platform.name", &value);
1147 if (r != SYSTEM_INFO_ERROR_NONE) {
1148 s_strncpy(sysinfo.platform_name, UNKNOWN, sizeof(sysinfo.platform_name));
1149 E("fail to get platform name:%d\n", errno);
1151 s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
1152 D("returns platform_name:%s\n", value);
1153 if (value != NULL) {
1159 // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
1160 r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
1161 if (r != SYSTEM_INFO_ERROR_NONE) {
1162 s_strncpy(sysinfo.platform_version, UNKNOWN, sizeof(sysinfo.platform_version));
1163 E("fail to get platform version:%d\n", errno);
1165 s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
1166 D("returns platform_version:%s\n", value);
1167 if (value != NULL) {
1172 r = system_info_get_platform_string("tizen.org/feature/profile", &value);
1173 if (r != SYSTEM_INFO_ERROR_NONE) {
1174 s_strncpy(sysinfo.profile_name, UNKNOWN, sizeof(sysinfo.profile_name));
1175 E("fail to get profile name:%d\n", errno);
1177 s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
1178 D("returns profile name:%s\n", value);
1179 if (value != NULL) {
1184 writex(fd, &sysinfo, sizeof(pinfo));
1189 static int put_key_value_string(char* buf, int offset, int buf_size, char* key, char* value) {
1191 if ((len = snprintf(buf+offset, buf_size-offset, "%s:%s\n", key, value)) > 0) {
1197 static void get_capability(int fd, void *cookie) {
1198 char cap_buffer[CAPBUF_SIZE] = {0,};
1199 uint16_t offset = 0;
1201 // Secure protocol support
1202 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1203 "secure_protocol", g_capabilities.secure_protocol);
1205 // Interactive shell support
1206 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1207 "intershell_support", g_capabilities.intershell_support);
1209 // File push/pull support
1210 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1211 "filesync_support", g_capabilities.filesync_support);
1213 // USB protocol support
1214 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1215 "usbproto_support", g_capabilities.usbproto_support);
1217 // Socket protocol support
1218 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1219 "sockproto_support", g_capabilities.sockproto_support);
1221 // Window size synchronization support
1222 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1223 "syncwinsz_support", g_capabilities.syncwinsz_support);
1225 // sdbd root permission
1226 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1227 "sdbd_rootperm", g_capabilities.root_permission);
1229 // Root command support
1230 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1231 "rootonoff_support", g_capabilities.rootonoff_support);
1233 // Encryption support
1234 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1235 "encryption_support", g_capabilities.encryption_support);
1238 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1239 "zone_support", g_capabilities.zone_support);
1241 // Multi-User support
1242 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1243 "multiuser_support", g_capabilities.multiuser_support);
1245 // CPU Architecture of model
1246 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1247 "cpu_arch", g_capabilities.cpu_arch);
1250 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1251 "sdk_toolpath", g_capabilities.sdk_toolpath);
1254 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1255 "profile_name", g_capabilities.profile_name);
1258 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1259 "vendor_name", g_capabilities.vendor_name);
1261 // Target name of the launch possible
1262 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1263 "can_launch", g_capabilities.can_launch);
1267 value = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
1269 snprintf(g_capabilities.device_name, sizeof(g_capabilities.device_name),
1271 if (value != NULL) {
1275 snprintf(g_capabilities.device_name, sizeof(g_capabilities.device_name),
1277 D("fail to get the Device name:%d\n", errno);
1279 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1280 "device_name", g_capabilities.device_name);
1283 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1284 "platform_version", g_capabilities.platform_version);
1287 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1288 "product_version", g_capabilities.product_version);
1291 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1292 "sdbd_version", g_capabilities.sdbd_version);
1294 // Sdbd plugin version
1295 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1296 "sdbd_plugin_version", g_capabilities.sdbd_plugin_version);
1298 // Capability version
1299 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1300 "sdbd_cap_version", g_capabilities.sdbd_cap_version);
1303 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1304 "log_enable", g_capabilities.log_enable);
1307 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1308 "log_path", g_capabilities.log_path);
1310 // Application command support
1311 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1312 "appcmd_support", g_capabilities.appcmd_support);
1314 // appid2pid support
1315 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1316 "appid2pid_support", g_capabilities.appid2pid_support);
1318 // pkgcmd debug mode support
1319 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1320 "pkgcmd_debugmode", g_capabilities.pkgcmd_debugmode);
1322 // pkgcmd debug mode support
1323 offset += put_key_value_string(cap_buffer, offset, CAPBUF_SIZE,
1324 "netcoredbg_support", g_capabilities.netcoredbg_support);
1326 offset++; // for '\0' character
1328 writex(fd, &offset, sizeof(uint16_t));
1329 writex(fd, cap_buffer, offset);
1334 static void sync_windowsize(int fd, void *cookie) {
1335 int id, lines, columns;
1336 char *size_info = (char*)cookie;
1339 if (sscanf(size_info, "%d:%d:%d", &id, &lines, &columns) == 3) {
1340 D("window size information: id=%d, lines=%d, columns=%d\n", id, lines, columns);
1342 if((s = find_local_socket(id))) {
1343 struct winsize win_sz;
1344 win_sz.ws_row = lines;
1345 win_sz.ws_col = columns;
1347 if (ioctl(s->fd, TIOCSWINSZ, &win_sz) < 0) {
1348 E("failed to sync window size.\n");
1351 I("success to sync window size.\n");
1357 const unsigned COMMAND_TIMEOUT = 10000;
1358 void get_boot(int fd, void *cookie) {
1359 char buf[2] = { 0, };
1361 int interval = 1000;
1362 while (time < COMMAND_TIMEOUT) {
1363 if (booting_done == 1) {
1364 I("get_boot:platform booting is done\n");
1365 snprintf(buf, sizeof(buf), "%s", "1");
1368 I("get_boot:platform booting is in progress\n");
1369 sdb_sleep_ms(interval);
1372 writex(fd, buf, strlen(buf));
1376 #define GRANT_FILE "/opt/share/askuser_disable"
1377 int grantfile_exist = 0;
1378 // TODO remove debug codes (snprintf buf)
1379 void handle_grantfile(int fd, void *cookie) {
1380 char buf[2] = { 0, };
1381 int opcode = atoi((char*)cookie);
1382 char* tmppath = NULL;
1384 if (opcode == 1) { // create
1385 tmppath = realpath(GRANT_FILE, NULL);
1386 if (tmppath == NULL && errno == ENOENT) {
1387 grantfile_exist = 0;
1388 FILE *f = fopen(GRANT_FILE, "w");
1392 snprintf(buf, sizeof(buf), "%s", " ");
1394 D("sdbd: cannot create %s file, errno %d.\n", GRANT_FILE, errno);
1395 snprintf(buf, sizeof(buf), "%s", "5");
1398 grantfile_exist = 1;
1399 D("sdbd: %s file is already existed.\n", GRANT_FILE);
1400 snprintf(buf, sizeof(buf), "%s", "3");
1403 } else if (opcode == 2) { // remove
1404 if (grantfile_exist != 0) {
1405 D("sdbd: %s file is already existed.\n", GRANT_FILE);
1406 snprintf(buf, sizeof(buf), "%s", "4");
1408 tmppath = realpath(GRANT_FILE, NULL);
1409 if (tmppath == NULL && errno == ENOENT) {
1410 D("sdbd: cannot find %s file.\n", GRANT_FILE);
1411 snprintf(buf, sizeof(buf), "%s", "6");
1412 } else if (tmppath != NULL && !strncmp(GRANT_FILE, tmppath, strlen(GRANT_FILE)+1)) {
1413 sdb_unlink(GRANT_FILE);
1414 snprintf(buf, sizeof(buf), "%s", " ");
1417 D("sdbd: unknown error has occured.\n");
1418 snprintf(buf, sizeof(buf), "%s", "8");
1419 if (tmppath != NULL) {
1425 // abnormal operation
1426 D("sdbd: abnormal operation.\n");
1427 snprintf(buf, sizeof(buf), "%s", "9");
1429 writex(fd, buf, strlen(buf));
1433 int request_extcmd_to_plugin(const char* in_buf) {
1434 char full_cmd[ENV_BUF_MAX] = {0,};
1435 char *tokens[MAX_TOKENS];
1436 int args_cnt = tokenize(in_buf, ":", tokens, MAX_TOKENS);
1438 E("failed to parse extcmd.\n");
1442 char* cmd_name = tokens[0];
1443 char* cmd_no = tokens[args_cnt - 2];
1444 int cmd = atoi(cmd_no);
1445 char* exec_type = tokens[args_cnt - 1];
1447 if (strlen(full_cmd) + strlen(cmd_name) + 1 >= ENV_BUF_MAX) {
1448 strncat(full_cmd, cmd_name, ENV_BUF_MAX - 1);
1449 full_cmd[ENV_BUF_MAX - 1] = '\0';
1452 strncat(full_cmd, cmd_name, ENV_BUF_MAX - 1);
1456 for(;i < args_cnt - 2;i++) {
1457 if (tokens[i] == NULL){
1460 if (strlen(full_cmd) + strlen(tokens[i]) + 2 >= ENV_BUF_MAX) {
1463 strncat(full_cmd, " ",1);
1464 strncat(full_cmd, tokens[i], ENV_BUF_MAX - 1);
1466 D("full extcmd: %s\n", full_cmd);
1467 if (!strcmp(exec_type, "sync")) {
1468 return create_extcmd_subproc_thread(full_cmd, 0, 0);
1471 else if (!strcmp(exec_type, "async")) {
1475 in = (parameters*) malloc(sizeof(parameters));
1477 E("failed to allocate memory for the parameters\n");
1481 if (strlen(full_cmd) > 0) {
1482 in->number_of_parameter = 1;
1483 in->array_of_parameter = (parameter*) malloc(sizeof(parameter));
1484 if (in->array_of_parameter == NULL) {
1486 E("failed to allocate memory for the parameter\n");
1489 in->array_of_parameter[0].type = type_string;
1490 in->array_of_parameter[0].v_string.length = strlen(full_cmd);
1491 in->array_of_parameter[0].v_string.data = strdup(full_cmd);
1493 in->number_of_parameter = 0;
1494 in->array_of_parameter = NULL;
1497 fd = create_async_extcmd_proc_thread(cmd, in);
1505 int service_to_fd(const char *name)
1509 if(!strncmp(name, "tcp:", 4)) {
1510 int port = atoi(name + 4);
1511 name = strchr(name + 4, ':');
1514 ret = socket_ifr_client(port , SOCK_STREAM, "eth0");
1516 ret = socket_ifr_client(port , SOCK_STREAM, "usb0");
1518 if (ifconfig(SDB_FORWARD_IFNAME, SDB_FORWARD_INTERNAL_IP, SDB_FORWARD_INTERNAL_MASK, 1) == 0) {
1519 ret = socket_ifr_client(port , SOCK_STREAM, SDB_FORWARD_IFNAME);
1524 ret = socket_loopback_client(port, SOCK_STREAM);
1527 disable_tcp_nagle(ret);
1532 #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
1533 } else if(!strncmp(name, "local:", 6)) {
1534 ret = socket_local_client(name + 6,
1535 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
1536 } else if(!strncmp(name, "localreserved:", 14)) {
1537 ret = socket_local_client(name + 14,
1538 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
1539 } else if(!strncmp(name, "localabstract:", 14)) {
1540 ret = socket_local_client(name + 14,
1541 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
1542 } else if(!strncmp(name, "localfilesystem:", 16)) {
1543 ret = socket_local_client(name + 16,
1544 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
1546 }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
1547 ret = unix_open(name + 4, O_RDWR);
1548 } else if(!strncmp(name, "framebuffer:", 12)) {
1549 ret = create_service_thread(framebuffer_service, 0);
1550 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
1551 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
1552 } else if (!strncmp(name, "jdwp:", 5)) {
1553 ret = create_jdwp_connection_fd(atoi(name+5));
1554 } else if (!strncmp(name, "log:", 4)) {
1555 ret = create_service_thread(log_service, get_log_file_path(name + 4));
1556 }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
1558 if (request_handlecmd_to_plugin(PLUGIN_SYNC_CMD_HANDLE_BY_PLUGIN, name+6)) {
1559 D("This shell command is handled by plugin. (%s)\n", name+6);
1560 ret = request_shellcmd_to_plugin(name+6);
1563 ret = create_subproc_thread(name + 6, 0, 0);
1566 ret = create_subproc_thread(NULL, 0, 0);
1568 } else if(!strncmp(name, "eshell:", 7)) {
1570 if (sscanf(name+7, "%d:%d", &lines, &columns) == 2) {
1571 ret = create_subproc_thread(NULL, lines, columns);
1573 } else if(!strncmp(name, "sync:", 5)) {
1574 //ret = create_service_thread(file_sync_service, NULL);
1575 ret = create_syncproc_thread(name + 5);
1576 }/* else if(!strncmp(name, "remount:", 8)) {
1577 ret = create_service_thread(remount_service, NULL);
1578 } else if(!strncmp(name, "reboot:", 7)) {
1579 void* arg = strdup(name + 7);
1580 if(arg == 0) return -1;
1581 ret = create_service_thread(reboot_service, arg);
1582 } else if(!strncmp(name, "root:", 5)) {
1583 ret = create_service_thread(restart_root_service, NULL);
1584 } else if(!strncmp(name, "backup:", 7)) {
1585 char* arg = strdup(name+7);
1586 if (arg == NULL) return -1;
1587 ret = backup_service(BACKUP, arg);
1588 } else if(!strncmp(name, "restore:", 8)) {
1589 ret = backup_service(RESTORE, NULL);
1590 }*/ else if(!strncmp(name, "root:", 5)) {
1591 char* service_name = NULL;
1593 service_name = strdup(name+5);
1594 ret = create_service_thread(rootshell_service, (void *)(service_name));
1595 } else if(!strncmp(name, "cs:", 3)) {
1596 ret = create_service_thread(inoti_service, NULL);
1597 } else if(!strncmp(name, "sysinfo:", 8)){
1598 ret = create_service_thread(get_platforminfo, 0);
1599 } else if(!strncmp(name, "capability:", 11)){
1600 ret = create_service_thread(get_capability, 0);
1601 } else if(!strncmp(name, "boot:", 5)){
1602 if (is_emulator()) {
1603 ret = create_service_thread(get_boot, 0);
1605 } else if(!strncmp(name, "shellconf:", 10)){
1606 if(!strncmp(name+10, "syncwinsz:", 10)){
1607 char* size_info = NULL;
1608 size_info = strdup(name+20);
1609 ret = create_service_thread(sync_windowsize, (void *)size_info);
1611 } else if(!strncmp(name, "tzplatformenv:", 14)) {
1612 char* env_variable = NULL;
1613 env_variable = strdup(name+14);
1614 ret = create_service_thread(get_tzplatform_env, (void *)(env_variable));
1615 } else if(!strncmp(name, "grantfile:", 10)){
1616 ret = create_service_thread(handle_grantfile, (void*)name+10);
1617 } else if(!strncmp(name, "appcmd:", 7)){
1618 ret = request_appcmd_to_plugin(name+7);
1619 } else if(!strncmp(name, "extcmd:", 7)) {
1620 ret = request_extcmd_to_plugin(name+7);
1624 if (close_on_exec(ret) < 0) {
1625 E("failed to close fd exec\n");