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
28 #include "file_sync_service.h"
32 # include <netinet/in.h>
34 # include <sys/ioctl.h>
37 # include <sys/inotify.h>
38 # include "sdktools.h"
42 #include <system_info.h>
43 #include <tzplatform_config.h>
45 #define SYSTEM_INFO_KEY_MODEL "http://tizen.org/system/model_name"
46 #define SYSTEM_INFO_KEY_PLATFORM_NAME "http://tizen.org/system/platform.name"
48 typedef struct stinfo stinfo;
51 void (*func)(int fd, void *cookie);
57 void *service_bootstrap_func(void *x)
60 sti->func(sti->fd, sti->cookie);
66 SDB_MUTEX_DEFINE( dns_lock );
68 static void dns_service(int fd, void *cookie)
70 char *hostname = cookie;
74 sdb_mutex_lock(&dns_lock);
75 hp = gethostbyname(hostname);
80 writex(fd, hp->h_addr, 4);
82 sdb_mutex_unlock(&dns_lock);
88 extern int recovery_mode;
90 static void recover_service(int s, void *cookie)
92 unsigned char buf[4096];
93 unsigned count = (unsigned) cookie;
96 fd = sdb_creat("/tmp/update", 0644);
103 unsigned xfer = (count > 4096) ? 4096 : count;
104 if(readx(s, buf, xfer)) break;
105 if(writex(fd, buf, xfer)) break;
110 writex(s, "OKAY", 4);
112 writex(s, "FAIL", 4);
117 fd = sdb_creat("/tmp/update.begin", 0644);
121 void restart_root_service(int fd, void *cookie)
124 char value[PROPERTY_VALUE_MAX];
127 snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
128 writex(fd, buf, strlen(buf));
131 property_get("ro.debuggable", value, "");
132 if (strcmp(value, "1") != 0) {
133 snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
134 writex(fd, buf, strlen(buf));
139 property_set("service.sdb.root", "1");
140 snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
141 writex(fd, buf, strlen(buf));
147 void restart_tcp_service(int fd, void *cookie)
150 char value[PROPERTY_VALUE_MAX];
151 int port = (int)cookie;
154 snprintf(buf, sizeof(buf), "invalid port\n");
155 writex(fd, buf, strlen(buf));
160 snprintf(value, sizeof(value), "%d", port);
161 property_set("service.sdb.tcp.port", value);
162 snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
163 writex(fd, buf, strlen(buf));
167 void rootshell_service(int fd, void *cookie)
170 char *mode = (char*) cookie;
172 if (!strcmp(mode, "on")) {
173 if (rootshell_mode == 1) {
174 //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
175 // do not show message
177 if (access("/bin/su", F_OK) == 0) {
179 //allows a permitted user to execute a command as the superuser
180 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
182 snprintf(buf, sizeof(buf), "Permission denied\n");
184 writex(fd, buf, strlen(buf));
186 } else if (!strcmp(mode, "off")) {
187 if (rootshell_mode == 1) {
189 snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
190 writex(fd, buf, strlen(buf));
193 snprintf(buf, sizeof(buf), "Unknown command option\n");
194 writex(fd, buf, strlen(buf));
196 D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
200 void restart_usb_service(int fd, void *cookie)
204 property_set("service.sdb.tcp.port", "0");
205 snprintf(buf, sizeof(buf), "restarting in USB mode\n");
206 writex(fd, buf, strlen(buf));
210 void reboot_service(int fd, void *arg)
218 /* Attempt to unmount the SD card first.
219 * No need to bother checking for errors.
223 /* ask vdc to unmount it */
224 // prevent: Use of untrusted string value (TAINTED_STRING)
225 execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
226 getenv("EXTERNAL_STORAGE"), "force", NULL);
227 } else if (pid > 0) {
228 /* wait until vdc succeeds or fails */
229 waitpid(pid, &ret, 0);
232 ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
234 snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
235 writex(fd, buf, strlen(buf));
243 #define EVENT_SIZE ( sizeof (struct inotify_event) )
244 #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
245 #define CS_PATH tzplatform_mkpath(TZ_USER_SHARE,"crash/report")
247 void inoti_service(int fd, void *arg)
251 char buffer[BUF_LEN];
253 D( "inoti_service start\n");
254 ifd = inotify_init();
257 D( "inotify_init failed\n");
261 wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
265 length = sdb_read( ifd, buffer, BUF_LEN );
268 D( "inoti read failed\n");
272 while ( i < length ) {
273 struct inotify_event *event = ( struct inotify_event * )&buffer[i];
275 if ( event->mask & IN_CREATE) {
276 if (!(event->mask & IN_ISDIR)) {
278 int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
279 D( "The file %s was created.\n", cspath);
280 writex(fd, cspath, len);
281 if (cspath != NULL) {
287 i += EVENT_SIZE + event->len;
292 inotify_rm_watch( ifd, wd );
295 D( "inoti_service end\n");
301 static void echo_service(int fd, void *cookie)
309 r = read(fd, buf, 4096);
310 if(r == 0) goto done;
312 if(errno == EINTR) continue;
325 if((r < 0) && (errno == EINTR)) continue;
334 static int create_service_thread(void (*func)(int, void *), void *cookie)
340 if(sdb_socketpair(s)) {
341 D("cannot create service socket pair\n");
345 sti = malloc(sizeof(stinfo));
346 if(sti == 0) fatal("cannot allocate stinfo");
348 sti->cookie = cookie;
351 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
355 D("cannot create service thread\n");
359 D("service thread started, %d:%d\n",s[0], s[1]);
365 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
367 #ifdef HAVE_WIN32_PROC
368 D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
369 fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
371 #else /* !HAVE_WIN32_PROC */
375 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
377 D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
380 if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
381 D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
384 if(grantpt(ptm) || unlockpt(ptm) ||
385 ((devname = (char*) ptsname(ptm)) == 0)){
386 D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
393 D("- fork failed: %s -\n", strerror(errno));
403 pts = unix_open(devname, O_RDWR);
405 fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
416 // set OOM adjustment to zero
419 snprintf(text, sizeof text, "/proc/%d/oom_score_adj", getpid());
420 int fd = sdb_open(text, O_WRONLY);
422 sdb_write(fd, "0", 1);
425 // FIXME: not supposed to be here
426 D("sdb: unable to open %s due to %s\n", text, strerror(errno));
430 verify_commands(arg1);
432 execl(cmd, cmd, arg0, arg1, NULL);
433 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
434 cmd, strerror(errno), errno);
437 // Don't set child's OOM adjustment to zero.
438 // Let the child do it itself, as sometimes the parent starts
439 // running before the child has a /proc/pid/oom_adj.
440 // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
443 #endif /* !HAVE_WIN32_PROC */
445 #endif /* !SDB_HOST */
448 #define SHELL_COMMAND "/bin/sh"
450 #define SHELL_COMMAND "/bin/sh" /* tizen specific */
454 static void subproc_waiter_service(int fd, void *cookie)
456 pid_t pid = (pid_t)cookie;
458 D("entered. fd=%d of pid=%d\n", fd, pid);
461 pid_t p = waitpid(pid, &status, 0);
463 D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
465 if (WIFEXITED(status)) {
466 D("*** Exit code %d\n", WEXITSTATUS(status));
468 } else if (WIFSIGNALED(status)) {
469 D("*** Killed by signal %d\n", WTERMSIG(status));
472 D("*** Killed by unknown code %d\n", status);
477 D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
478 if (SHELL_EXIT_NOTIFY_FD >=0) {
480 res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
481 D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
482 SHELL_EXIT_NOTIFY_FD, pid, res, errno);
486 static int create_subproc_thread(const char *name)
494 ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
496 ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
498 D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
501 D("cannot create service thread\n");
504 sti = malloc(sizeof(stinfo));
505 if(sti == 0) fatal("cannot allocate stinfo");
506 sti->func = subproc_waiter_service;
507 sti->cookie = (void*)pid;
510 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
513 D("cannot create service thread\n");
517 D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
521 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
526 if(sdb_socketpair(s)) {
527 D("cannot create service socket pair\n");
537 } else if (pid > 0) {
539 // FIXME: do not wait child process hear
540 //waitpid(pid, &ret, 0);
543 D("- fork failed: %s -\n", strerror(errno));
546 D("cannot create sync service sub process\n");
550 sti = malloc(sizeof(stinfo));
551 if(sti == 0) fatal("cannot allocate stinfo");
552 sti->func = subproc_waiter_service;
553 sti->cookie = (void*)pid;
556 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
560 printf("cannot create service monitor thread\n");
564 D("service process started, fd=%d pid=%d\n",s[0], pid);
568 static int create_syncproc_thread()
572 ret_fd = create_sync_subprocess(file_sync_service, NULL);
573 // FIXME: file missing bug when root on mode
575 if (should_drop_privileges()) {
576 ret_fd = create_sync_subprocess(file_sync_service, NULL);
578 ret_fd = create_service_thread(file_sync_service, NULL);
587 #define UNKNOWN "unknown"
588 #define INFOBUF_MAXLEN 64
589 #define INFO_VERSION "2.2.0"
590 typedef struct platform_info {
592 char platform_info_version[INFOBUF_MAXLEN];
593 char model_name[INFOBUF_MAXLEN]; // Emulator
594 char platform_name[INFOBUF_MAXLEN]; // Tizen
595 char platform_version[INFOBUF_MAXLEN]; // 2.2.1
596 char profile_name[INFOBUF_MAXLEN]; // 2.2.1
599 static void get_platforminfo(int fd, void *cookie) {
603 s_strncpy(sysinfo.platform_info_version, INFO_VERSION, strlen(INFO_VERSION));
605 int r = system_info_get_platform_string(SYSTEM_INFO_KEY_MODEL, &value);
606 if (r != SYSTEM_INFO_ERROR_NONE) {
607 s_strncpy(sysinfo.model_name, UNKNOWN, strlen(UNKNOWN));
608 D("fail to get system model:%d\n", errno);
610 s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
611 D("returns model_name:%s\n", value);
617 r = system_info_get_platform_string(SYSTEM_INFO_KEY_PLATFORM_NAME, &value);
618 if (r != SYSTEM_INFO_ERROR_NONE) {
619 s_strncpy(sysinfo.platform_name, UNKNOWN, strlen(UNKNOWN));
620 D("fail to get platform name:%d\n", errno);
622 s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
623 D("returns platform_name:%s\n", value);
630 // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
631 r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
632 if (r != SYSTEM_INFO_ERROR_NONE) {
633 s_strncpy(sysinfo.platform_version, UNKNOWN, strlen(UNKNOWN));
634 D("fail to get platform version:%d\n", errno);
636 s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
637 D("returns platform_version:%s\n", value);
643 r = system_info_get_platform_string("tizen.org/feature/profile", &value);
644 if (r != SYSTEM_INFO_ERROR_NONE) {
645 s_strncpy(sysinfo.profile_name, UNKNOWN, strlen(UNKNOWN));
646 D("fail to get profile name:%d\n", errno);
648 s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
649 D("returns profile name:%s\n", value);
655 writex(fd, &sysinfo, sizeof(pinfo));
660 int service_to_fd(const char *name)
664 if(!strncmp(name, "tcp:", 4)) {
665 int port = atoi(name + 4);
666 name = strchr(name + 4, ':');
668 ret = socket_loopback_client(port, SOCK_STREAM);
670 disable_tcp_nagle(ret);
673 sdb_mutex_lock(&dns_lock);
674 ret = socket_network_client(name + 1, port, SOCK_STREAM);
675 sdb_mutex_unlock(&dns_lock);
680 #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
681 } else if(!strncmp(name, "local:", 6)) {
682 ret = socket_local_client(name + 6,
683 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
684 } else if(!strncmp(name, "localreserved:", 14)) {
685 ret = socket_local_client(name + 14,
686 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
687 } else if(!strncmp(name, "localabstract:", 14)) {
688 ret = socket_local_client(name + 14,
689 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
690 } else if(!strncmp(name, "localfilesystem:", 16)) {
691 ret = socket_local_client(name + 16,
692 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
695 } else if(!strncmp("dns:", name, 4)){
696 char *n = strdup(name + 4);
697 if(n == 0) return -1;
698 ret = create_service_thread(dns_service, n);
699 #else /* !SDB_HOST */
700 }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
701 ret = unix_open(name + 4, O_RDWR);
702 } else if(!strncmp(name, "framebuffer:", 12)) {
703 ret = create_service_thread(framebuffer_service, 0);
704 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
705 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
706 } else if (!strncmp(name, "jdwp:", 5)) {
707 ret = create_jdwp_connection_fd(atoi(name+5));
708 } else if (!strncmp(name, "log:", 4)) {
709 ret = create_service_thread(log_service, get_log_file_path(name + 4));
710 }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
712 ret = create_subproc_thread(name + 6);
714 ret = create_subproc_thread(0);
716 } else if(!strncmp(name, "sync:", 5)) {
717 //ret = create_service_thread(file_sync_service, NULL);
718 ret = create_syncproc_thread();
719 }/* else if(!strncmp(name, "remount:", 8)) {
720 ret = create_service_thread(remount_service, NULL);
721 } else if(!strncmp(name, "reboot:", 7)) {
722 void* arg = strdup(name + 7);
723 if(arg == 0) return -1;
724 ret = create_service_thread(reboot_service, arg);
725 } else if(!strncmp(name, "root:", 5)) {
726 ret = create_service_thread(restart_root_service, NULL);
727 } else if(!strncmp(name, "backup:", 7)) {
728 char* arg = strdup(name+7);
729 if (arg == NULL) return -1;
730 ret = backup_service(BACKUP, arg);
731 } else if(!strncmp(name, "restore:", 8)) {
732 ret = backup_service(RESTORE, NULL);
733 }*/ else if(!strncmp(name, "root:", 5)) {
734 ret = create_service_thread(rootshell_service, (void *)(name+5));
735 } else if(!strncmp(name, "tcpip:", 6)) {
737 /*if (sscanf(name + 6, "%d", &port) == 0) {
740 port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
741 ret = create_service_thread(restart_tcp_service, (void *)port);
742 } else if(!strncmp(name, "usb:", 4)) {
743 ret = create_service_thread(restart_usb_service, NULL);
744 } else if(!strncmp(name, "cs:", 5)) {
745 ret = create_service_thread(inoti_service, NULL);
747 } else if(!strncmp(name, "sysinfo:", 8)){
748 ret = create_service_thread(get_platforminfo, 0);
751 if (close_on_exec(ret) < 0) {
752 D("failed to close fd exec\n");
760 transport_type transport;
765 static void wait_for_state(int fd, void* cookie)
767 struct state_info* sinfo = cookie;
768 char* err = "unknown error";
770 D("wait_for_state %d\n", sinfo->state);
772 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
774 writex(fd, "OKAY", 4);
776 sendfailmsg(fd, err);
783 D("wait_for_state is done\n");
788 asocket* host_service_to_socket(const char* name, const char *serial)
790 if (!strcmp(name,"track-devices")) {
791 return create_device_tracker();
792 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
793 struct state_info* sinfo = malloc(sizeof(struct state_info));
796 sinfo->serial = strdup(serial);
798 sinfo->serial = NULL;
800 name += strlen("wait-for-");
802 if (!strncmp(name, "local", strlen("local"))) {
803 sinfo->transport = kTransportLocal;
804 sinfo->state = CS_DEVICE;
805 } else if (!strncmp(name, "usb", strlen("usb"))) {
806 sinfo->transport = kTransportUsb;
807 sinfo->state = CS_DEVICE;
808 } else if (!strncmp(name, "any", strlen("any"))) {
809 sinfo->transport = kTransportAny;
810 sinfo->state = CS_DEVICE;
816 int fd = create_service_thread(wait_for_state, sinfo);
817 return create_local_socket(fd);
821 #endif /* SDB_HOST */