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>
44 typedef struct stinfo stinfo;
47 void (*func)(int fd, void *cookie);
53 void *service_bootstrap_func(void *x)
56 sti->func(sti->fd, sti->cookie);
62 SDB_MUTEX_DEFINE( dns_lock );
64 static void dns_service(int fd, void *cookie)
66 char *hostname = cookie;
70 sdb_mutex_lock(&dns_lock);
71 hp = gethostbyname(hostname);
76 writex(fd, hp->h_addr, 4);
78 sdb_mutex_unlock(&dns_lock);
84 extern int recovery_mode;
86 static void recover_service(int s, void *cookie)
88 unsigned char buf[4096];
89 unsigned count = (unsigned) cookie;
92 fd = sdb_creat("/tmp/update", 0644);
99 unsigned xfer = (count > 4096) ? 4096 : count;
100 if(readx(s, buf, xfer)) break;
101 if(writex(fd, buf, xfer)) break;
106 writex(s, "OKAY", 4);
108 writex(s, "FAIL", 4);
113 fd = sdb_creat("/tmp/update.begin", 0644);
117 void restart_root_service(int fd, void *cookie)
120 char value[PROPERTY_VALUE_MAX];
123 snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
124 writex(fd, buf, strlen(buf));
127 property_get("ro.debuggable", value, "");
128 if (strcmp(value, "1") != 0) {
129 snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
130 writex(fd, buf, strlen(buf));
135 property_set("service.sdb.root", "1");
136 snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
137 writex(fd, buf, strlen(buf));
143 void restart_tcp_service(int fd, void *cookie)
146 char value[PROPERTY_VALUE_MAX];
147 int port = (int)cookie;
150 snprintf(buf, sizeof(buf), "invalid port\n");
151 writex(fd, buf, strlen(buf));
156 snprintf(value, sizeof(value), "%d", port);
157 property_set("service.sdb.tcp.port", value);
158 snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
159 writex(fd, buf, strlen(buf));
163 void rootshell_service(int fd, void *cookie)
166 char *mode = (char*) cookie;
168 if (!strcmp(mode, "on")) {
169 if (rootshell_mode == 1) {
170 //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
171 // do not show message
173 if (access("/bin/su", F_OK) == 0) {
175 //allows a permitted user to execute a command as the superuser
176 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
178 snprintf(buf, sizeof(buf), "Permission denied\n");
180 writex(fd, buf, strlen(buf));
182 } else if (!strcmp(mode, "off")) {
183 if (rootshell_mode == 1) {
185 snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
186 writex(fd, buf, strlen(buf));
189 snprintf(buf, sizeof(buf), "Unknown command option\n");
190 writex(fd, buf, strlen(buf));
192 D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
196 void restart_usb_service(int fd, void *cookie)
200 property_set("service.sdb.tcp.port", "0");
201 snprintf(buf, sizeof(buf), "restarting in USB mode\n");
202 writex(fd, buf, strlen(buf));
206 void reboot_service(int fd, void *arg)
214 /* Attempt to unmount the SD card first.
215 * No need to bother checking for errors.
219 /* ask vdc to unmount it */
220 // prevent: Use of untrusted string value (TAINTED_STRING)
221 execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
222 getenv("EXTERNAL_STORAGE"), "force", NULL);
223 } else if (pid > 0) {
224 /* wait until vdc succeeds or fails */
225 waitpid(pid, &ret, 0);
228 ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
230 snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
231 writex(fd, buf, strlen(buf));
239 #define EVENT_SIZE ( sizeof (struct inotify_event) )
240 #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
241 #define CS_PATH tzplatform_mkpath(TZ_USER_SHARE,"crash/report")
243 void inoti_service(int fd, void *arg)
247 char buffer[BUF_LEN];
249 D( "inoti_service start\n");
250 ifd = inotify_init();
253 D( "inotify_init failed\n");
257 wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
261 length = sdb_read( ifd, buffer, BUF_LEN );
264 D( "inoti read failed\n");
268 while ( i < length ) {
269 struct inotify_event *event = ( struct inotify_event * )&buffer[i];
271 if ( event->mask & IN_CREATE) {
272 if (!(event->mask & IN_ISDIR)) {
274 int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
275 D( "The file %s was created.\n", cspath);
276 writex(fd, cspath, len);
277 if (cspath != NULL) {
283 i += EVENT_SIZE + event->len;
288 inotify_rm_watch( ifd, wd );
291 D( "inoti_service end\n");
297 static void echo_service(int fd, void *cookie)
305 r = read(fd, buf, 4096);
306 if(r == 0) goto done;
308 if(errno == EINTR) continue;
321 if((r < 0) && (errno == EINTR)) continue;
330 static int create_service_thread(void (*func)(int, void *), void *cookie)
336 if(sdb_socketpair(s)) {
337 D("cannot create service socket pair\n");
341 sti = malloc(sizeof(stinfo));
342 if(sti == 0) fatal("cannot allocate stinfo");
344 sti->cookie = cookie;
347 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
351 D("cannot create service thread\n");
355 D("service thread started, %d:%d\n",s[0], s[1]);
361 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
363 #ifdef HAVE_WIN32_PROC
364 D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
365 fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
367 #else /* !HAVE_WIN32_PROC */
371 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
373 D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
376 if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
377 D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
380 if(grantpt(ptm) || unlockpt(ptm) ||
381 ((devname = (char*) ptsname(ptm)) == 0)){
382 D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
389 D("- fork failed: %s -\n", strerror(errno));
399 pts = unix_open(devname, O_RDWR);
401 fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
412 // set OOM adjustment to zero
415 snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
416 int fd = sdb_open(text, O_WRONLY);
418 sdb_write(fd, "0", 1);
421 // FIXME: not supposed to be here
422 D("sdb: unable to open %s due to %s\n", text, strerror(errno));
426 verify_commands(arg1);
428 execl(cmd, cmd, arg0, arg1, NULL);
429 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
430 cmd, strerror(errno), errno);
433 // Don't set child's OOM adjustment to zero.
434 // Let the child do it itself, as sometimes the parent starts
435 // running before the child has a /proc/pid/oom_adj.
436 // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
439 #endif /* !HAVE_WIN32_PROC */
441 #endif /* !SDB_HOST */
444 #define SHELL_COMMAND "/bin/sh"
446 #define SHELL_COMMAND "/bin/sh" /* tizen specific */
450 static void subproc_waiter_service(int fd, void *cookie)
452 pid_t pid = (pid_t)cookie;
454 D("entered. fd=%d of pid=%d\n", fd, pid);
457 pid_t p = waitpid(pid, &status, 0);
459 D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
461 if (WIFEXITED(status)) {
462 D("*** Exit code %d\n", WEXITSTATUS(status));
464 } else if (WIFSIGNALED(status)) {
465 D("*** Killed by signal %d\n", WTERMSIG(status));
468 D("*** Killed by unknown code %d\n", status);
473 D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
474 if (SHELL_EXIT_NOTIFY_FD >=0) {
476 res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
477 D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
478 SHELL_EXIT_NOTIFY_FD, pid, res, errno);
482 static int create_subproc_thread(const char *name)
490 ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
492 ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
494 D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
497 D("cannot create service thread\n");
500 sti = malloc(sizeof(stinfo));
501 if(sti == 0) fatal("cannot allocate stinfo");
502 sti->func = subproc_waiter_service;
503 sti->cookie = (void*)pid;
506 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
509 D("cannot create service thread\n");
513 D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
517 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
522 if(sdb_socketpair(s)) {
523 D("cannot create service socket pair\n");
533 } else if (pid > 0) {
535 // FIXME: do not wait child process hear
536 //waitpid(pid, &ret, 0);
539 D("- fork failed: %s -\n", strerror(errno));
542 D("cannot create sync service sub process\n");
546 sti = malloc(sizeof(stinfo));
547 if(sti == 0) fatal("cannot allocate stinfo");
548 sti->func = subproc_waiter_service;
549 sti->cookie = (void*)pid;
552 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
556 printf("cannot create service monitor thread\n");
560 D("service process started, fd=%d pid=%d\n",s[0], pid);
564 static int create_syncproc_thread()
568 ret_fd = create_sync_subprocess(file_sync_service, NULL);
569 // FIXME: file missing bug when root on mode
571 if (should_drop_privileges()) {
572 ret_fd = create_sync_subprocess(file_sync_service, NULL);
574 ret_fd = create_service_thread(file_sync_service, NULL);
583 #define UNKNOWN "unknown"
584 #define INFOBUF_MAXLEN 64
585 #define INFO_VERSION "2.2.0"
586 typedef struct platform_info {
588 char platform_info_version[INFOBUF_MAXLEN];
589 char model_name[INFOBUF_MAXLEN]; // Emulator
590 char platform_name[INFOBUF_MAXLEN]; // Tizen
591 char platform_version[INFOBUF_MAXLEN]; // 2.2.1
592 char profile_name[INFOBUF_MAXLEN]; // 2.2.1
595 static void get_platforminfo(int fd, void *cookie) {
599 s_strncpy(sysinfo.platform_info_version, INFO_VERSION, strlen(INFO_VERSION));
601 int r = system_info_get_value_string(SYSTEM_INFO_KEY_MODEL, &value);
602 if (r != SYSTEM_INFO_ERROR_NONE) {
603 s_strncpy(sysinfo.model_name, UNKNOWN, strlen(UNKNOWN));
604 D("fail to get system model:%d\n", errno);
606 s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
607 D("returns model_name:%s\n", value);
613 r = system_info_get_value_string(SYSTEM_INFO_KEY_PLATFORM_NAME, &value);
614 if (r != SYSTEM_INFO_ERROR_NONE) {
615 s_strncpy(sysinfo.platform_name, UNKNOWN, strlen(UNKNOWN));
616 D("fail to get platform name:%d\n", errno);
618 s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
619 D("returns platform_name:%s\n", value);
626 // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
627 r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
628 if (r != SYSTEM_INFO_ERROR_NONE) {
629 s_strncpy(sysinfo.platform_version, UNKNOWN, strlen(UNKNOWN));
630 D("fail to get platform version:%d\n", errno);
632 s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
633 D("returns platform_version:%s\n", value);
639 r = system_info_get_platform_string("tizen.org/feature/profile", &value);
640 if (r != SYSTEM_INFO_ERROR_NONE) {
641 s_strncpy(sysinfo.profile_name, UNKNOWN, strlen(UNKNOWN));
642 D("fail to get profile name:%d\n", errno);
644 s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
645 D("returns profile name:%s\n", value);
651 writex(fd, &sysinfo, sizeof(pinfo));
656 int service_to_fd(const char *name)
660 if(!strncmp(name, "tcp:", 4)) {
661 int port = atoi(name + 4);
662 name = strchr(name + 4, ':');
664 ret = socket_loopback_client(port, SOCK_STREAM);
666 disable_tcp_nagle(ret);
669 sdb_mutex_lock(&dns_lock);
670 ret = socket_network_client(name + 1, port, SOCK_STREAM);
671 sdb_mutex_unlock(&dns_lock);
676 #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
677 } else if(!strncmp(name, "local:", 6)) {
678 ret = socket_local_client(name + 6,
679 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
680 } else if(!strncmp(name, "localreserved:", 14)) {
681 ret = socket_local_client(name + 14,
682 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
683 } else if(!strncmp(name, "localabstract:", 14)) {
684 ret = socket_local_client(name + 14,
685 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
686 } else if(!strncmp(name, "localfilesystem:", 16)) {
687 ret = socket_local_client(name + 16,
688 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
691 } else if(!strncmp("dns:", name, 4)){
692 char *n = strdup(name + 4);
693 if(n == 0) return -1;
694 ret = create_service_thread(dns_service, n);
695 #else /* !SDB_HOST */
696 }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
697 ret = unix_open(name + 4, O_RDWR);
698 } else if(!strncmp(name, "framebuffer:", 12)) {
699 ret = create_service_thread(framebuffer_service, 0);
700 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
701 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
702 } else if (!strncmp(name, "jdwp:", 5)) {
703 ret = create_jdwp_connection_fd(atoi(name+5));
704 } else if (!strncmp(name, "log:", 4)) {
705 ret = create_service_thread(log_service, get_log_file_path(name + 4));
706 }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
708 ret = create_subproc_thread(name + 6);
710 ret = create_subproc_thread(0);
712 } else if(!strncmp(name, "sync:", 5)) {
713 //ret = create_service_thread(file_sync_service, NULL);
714 ret = create_syncproc_thread();
715 }/* else if(!strncmp(name, "remount:", 8)) {
716 ret = create_service_thread(remount_service, NULL);
717 } else if(!strncmp(name, "reboot:", 7)) {
718 void* arg = strdup(name + 7);
719 if(arg == 0) return -1;
720 ret = create_service_thread(reboot_service, arg);
721 } else if(!strncmp(name, "root:", 5)) {
722 ret = create_service_thread(restart_root_service, NULL);
723 } else if(!strncmp(name, "backup:", 7)) {
724 char* arg = strdup(name+7);
725 if (arg == NULL) return -1;
726 ret = backup_service(BACKUP, arg);
727 } else if(!strncmp(name, "restore:", 8)) {
728 ret = backup_service(RESTORE, NULL);
729 }*/ else if(!strncmp(name, "root:", 5)) {
730 ret = create_service_thread(rootshell_service, (void *)(name+5));
731 } else if(!strncmp(name, "tcpip:", 6)) {
733 /*if (sscanf(name + 6, "%d", &port) == 0) {
736 port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
737 ret = create_service_thread(restart_tcp_service, (void *)port);
738 } else if(!strncmp(name, "usb:", 4)) {
739 ret = create_service_thread(restart_usb_service, NULL);
740 } else if(!strncmp(name, "cs:", 5)) {
741 ret = create_service_thread(inoti_service, NULL);
743 } else if(!strncmp(name, "sysinfo:", 8)){
744 ret = create_service_thread(get_platforminfo, 0);
747 if (close_on_exec(ret) < 0) {
748 D("failed to close fd exec\n");
756 transport_type transport;
761 static void wait_for_state(int fd, void* cookie)
763 struct state_info* sinfo = cookie;
764 char* err = "unknown error";
766 D("wait_for_state %d\n", sinfo->state);
768 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
770 writex(fd, "OKAY", 4);
772 sendfailmsg(fd, err);
779 D("wait_for_state is done\n");
784 asocket* host_service_to_socket(const char* name, const char *serial)
786 if (!strcmp(name,"track-devices")) {
787 return create_device_tracker();
788 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
789 struct state_info* sinfo = malloc(sizeof(struct state_info));
792 sinfo->serial = strdup(serial);
794 sinfo->serial = NULL;
796 name += strlen("wait-for-");
798 if (!strncmp(name, "local", strlen("local"))) {
799 sinfo->transport = kTransportLocal;
800 sinfo->state = CS_DEVICE;
801 } else if (!strncmp(name, "usb", strlen("usb"))) {
802 sinfo->transport = kTransportUsb;
803 sinfo->state = CS_DEVICE;
804 } else if (!strncmp(name, "any", strlen("any"))) {
805 sinfo->transport = kTransportAny;
806 sinfo->state = CS_DEVICE;
812 int fd = create_service_thread(wait_for_state, sinfo);
813 return create_local_socket(fd);
817 #endif /* SDB_HOST */