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_internal.h>
46 typedef struct stinfo stinfo;
49 void (*func)(int fd, void *cookie);
55 void *service_bootstrap_func(void *x)
58 sti->func(sti->fd, sti->cookie);
64 SDB_MUTEX_DEFINE( dns_lock );
66 static void dns_service(int fd, void *cookie)
68 char *hostname = cookie;
72 sdb_mutex_lock(&dns_lock);
73 hp = gethostbyname(hostname);
78 writex(fd, hp->h_addr, 4);
80 sdb_mutex_unlock(&dns_lock);
86 extern int recovery_mode;
88 static void recover_service(int s, void *cookie)
90 unsigned char buf[4096];
91 unsigned count = (unsigned) cookie;
94 fd = sdb_creat("/tmp/update", 0644);
101 unsigned xfer = (count > 4096) ? 4096 : count;
102 if(readx(s, buf, xfer)) break;
103 if(writex(fd, buf, xfer)) break;
108 writex(s, "OKAY", 4);
110 writex(s, "FAIL", 4);
115 fd = sdb_creat("/tmp/update.begin", 0644);
119 void restart_root_service(int fd, void *cookie)
122 char value[PROPERTY_VALUE_MAX];
125 snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
126 writex(fd, buf, strlen(buf));
129 property_get("ro.debuggable", value, "");
130 if (strcmp(value, "1") != 0) {
131 snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
132 writex(fd, buf, strlen(buf));
137 property_set("service.sdb.root", "1");
138 snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
139 writex(fd, buf, strlen(buf));
145 void rootshell_service(int fd, void *cookie)
148 char *mode = (char*) cookie;
150 if (!strcmp(mode, "on")) {
151 if (rootshell_mode == 1) {
152 //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
153 // do not show message
155 if (access("/bin/su", F_OK) == 0) {
157 //allows a permitted user to execute a command as the superuser
158 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
160 snprintf(buf, sizeof(buf), "Permission denied\n");
162 writex(fd, buf, strlen(buf));
164 } else if (!strcmp(mode, "off")) {
165 if (rootshell_mode == 1) {
167 snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
168 writex(fd, buf, strlen(buf));
171 snprintf(buf, sizeof(buf), "Unknown command option\n");
172 writex(fd, buf, strlen(buf));
174 D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
179 void reboot_service(int fd, void *arg)
187 /* Attempt to unmount the SD card first.
188 * No need to bother checking for errors.
192 /* ask vdc to unmount it */
193 // prevent: Use of untrusted string value (TAINTED_STRING)
194 execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
195 getenv("EXTERNAL_STORAGE"), "force", NULL);
196 } else if (pid > 0) {
197 /* wait until vdc succeeds or fails */
198 waitpid(pid, &ret, 0);
201 ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
203 snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
204 writex(fd, buf, strlen(buf));
212 #define EVENT_SIZE ( sizeof (struct inotify_event) )
213 #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
214 #define CS_PATH "/opt/usr/share/crash/report"
216 void inoti_service(int fd, void *arg)
220 char buffer[BUF_LEN];
222 D( "inoti_service start\n");
223 ifd = inotify_init();
226 D( "inotify_init failed\n");
230 wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
234 length = sdb_read( ifd, buffer, BUF_LEN );
237 D( "inoti read failed\n");
240 while (i >= 0 && i <= (length - EVENT_SIZE)) {
241 struct inotify_event *event = (struct inotify_event *) &buffer[i];
243 if (event->mask & IN_CREATE) {
244 if (!(event->mask & IN_ISDIR)) {
246 int len = asprintf(&cspath, "%s/%s", CS_PATH,
248 D( "The file %s was created.\n", cspath);
249 writex(fd, cspath, len);
250 if (cspath != NULL) {
256 if (i + EVENT_SIZE + event->len < event->len) { // in case of integer overflow
259 i += EVENT_SIZE + event->len;
264 inotify_rm_watch( ifd, wd );
267 D( "inoti_service end\n");
272 void rndis_config_service(int fd, void *cookie)
276 char* mode = (char*) cookie;
279 if (vconf_get_int(DEBUG_MODE_KEY, &val)) {
280 D("Failed to get debug mode\n");
285 if (!strcmp(mode, "on")) {
289 if (vconf_set_int(DEBUG_MODE_KEY, 6)) {
290 D("Failed to set rndis %s\n", mode);
291 snprintf(buf, sizeof(buf), "Failed to set rndis %s\n", mode);
292 writex(fd, buf, strlen(buf));
295 } else if (!strcmp(mode, "off")) {
299 if (vconf_set_int(DEBUG_MODE_KEY, 2)) {
300 D("Failed to set rndis %s\n", mode);
301 snprintf(buf, sizeof(buf), "Failed to set rndis %s\n", mode);
302 writex(fd, buf, strlen(buf));
306 D("Unknown command option:(rndis %s)\n", mode);
307 snprintf(buf, sizeof(buf), "Unknown command option:(rndis %s)\n", mode);
308 writex(fd, buf, strlen(buf));
315 static void echo_service(int fd, void *cookie)
323 r = read(fd, buf, 4096);
324 if(r == 0) goto done;
326 if(errno == EINTR) continue;
339 if((r < 0) && (errno == EINTR)) continue;
348 static int create_service_thread(void (*func)(int, void *), void *cookie)
354 if(sdb_socketpair(s)) {
355 D("cannot create service socket pair\n");
359 sti = malloc(sizeof(stinfo));
360 if(sti == 0) fatal("cannot allocate stinfo");
362 sti->cookie = cookie;
365 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
369 D("cannot create service thread\n");
373 D("service thread started, %d:%d\n",s[0], s[1]);
379 static void redirect_and_exec(int pts, const char *cmd, const char *argv[], const char *envp[])
387 execve(cmd, argv, envp);
390 static int create_subprocess(const char *cmd, pid_t *pid, const char *argv[], const char *envp[])
395 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
397 D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
400 if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
401 D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
404 if(grantpt(ptm) || unlockpt(ptm) ||
405 ((devname = (char*) ptsname(ptm)) == 0)){
406 D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
413 D("- fork failed: %s -\n", strerror(errno));
423 pts = unix_open(devname, O_RDWR);
425 fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
431 // set OOM adjustment to zero
434 snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
435 int fd = sdb_open(text, O_WRONLY);
437 sdb_write(fd, "0", 1);
440 // FIXME: not supposed to be here
441 D("sdb: unable to open %s due to %s\n", text, strerror(errno));
445 if (should_drop_privileges()) {
446 if (argv[2] != NULL && verify_root_commands(argv[2])) {
448 D("sdb: executes root commands!!:%s\n", argv[2]);
450 set_developer_privileges();
454 redirect_and_exec(pts, cmd, argv, envp);
455 fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n",
459 // Don't set child's OOM adjustment to zero.
460 // Let the child do it itself, as sometimes the parent starts
461 // running before the child has a /proc/pid/oom_adj.
462 // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
466 #endif /* !SDB_HOST */
468 #define SHELL_COMMAND "/bin/sh"
469 #define LOGIN_COMMAND "/bin/login"
470 #define SDK_USER "developer"
471 #define SUPER_USER "root"
472 #define LOGIN_CONFIG "/etc/login.defs"
475 static void subproc_waiter_service(int fd, void *cookie)
477 pid_t pid = (pid_t)cookie;
479 D("entered. fd=%d of pid=%d\n", fd, pid);
482 pid_t p = waitpid(pid, &status, 0);
484 D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
486 if (WIFEXITED(status)) {
487 D("*** Exit code %d\n", WEXITSTATUS(status));
489 } else if (WIFSIGNALED(status)) {
490 D("*** Killed by signal %d\n", WTERMSIG(status));
493 D("*** Killed by unknown code %d\n", status);
498 D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
499 if (SHELL_EXIT_NOTIFY_FD >=0) {
501 res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
502 D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
503 SHELL_EXIT_NOTIFY_FD, pid, res, errno);
507 static void get_env(char *key, char **env)
514 fp = fopen (LOGIN_CONFIG, "r");
519 while (fgets(buf, (int) sizeof (buf), fp) != NULL) {
521 e = buf + (strlen(buf) - 1);
523 while(*e == ' ' || *e == '\n' || *e == '\t') {
528 while(*s != '\0' && (*s == ' ' || *s == '\t' || *s == '\n')) {
532 if (*s == '#' || *s == '\0') {
535 value = s + strcspn(s, " \t");
538 if(!strcmp(buf, key)) {
547 static int create_subproc_thread(const char *name, int lines, int columns)
554 char lines_str[20] = {'\0',};
555 char columns_str[20] = {'\0',};
558 "TERM=linux", /* without this, some programs based on screen can't work, e.g. top */
559 "DISPLAY=:0", /* without this, some programs based on without launchpad can't work */
566 if (should_drop_privileges()) {
567 envp[2] = "HOME=/home/developer";
568 get_env("ENV_PATH", &value);
570 get_env("ENV_SUPATH", &value);
571 envp[2] = "HOME=/root";
577 D("path env:%s,%s,%s,%s\n", envp[0], envp[1], envp[2], envp[3]);
579 if (lines > 0 && columns > 0) {
580 snprintf(lines_str, sizeof(lines_str), "LINES=%d", lines);
581 snprintf(columns_str, sizeof(columns_str), "COLUMNS=%d", columns);
583 envp[5] = columns_str;
584 D("shell size env:%s,%s\n", envp[4], envp[5]);
587 if(name) { // in case of shell execution directly
598 ret_fd = create_subprocess(SHELL_COMMAND, &pid, args, envp);
599 } else { // in case of shell interactively
605 ret_fd = create_subprocess(SHELL_COMMAND, &pid, args, envp);
606 #if 0 // FIXME: should call login command instead of /bin/sh
607 if (should_drop_privileges()) {
613 ret_fd = create_subprocess(SHELL_COMMAND, &pid, args, envp);
621 ret_fd = create_subprocess(LOGIN_COMMAND, &pid, args, envp);
625 D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
628 D("cannot create service thread\n");
631 sti = malloc(sizeof(stinfo));
632 if(sti == 0) fatal("cannot allocate stinfo");
633 sti->func = subproc_waiter_service;
634 sti->cookie = (void*)pid;
637 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
640 D("cannot create service thread\n");
644 D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
648 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
653 if(sdb_socketpair(s)) {
654 D("cannot create service socket pair\n");
664 } else if (pid > 0) {
666 // FIXME: do not wait child process hear
667 //waitpid(pid, &ret, 0);
670 D("- fork failed: (errno:%d) -\n", errno);
673 D("cannot create sync service sub process\n");
677 sti = malloc(sizeof(stinfo));
678 if(sti == 0) fatal("cannot allocate stinfo");
679 sti->func = subproc_waiter_service;
680 sti->cookie = (void*)pid;
683 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
687 printf("cannot create service monitor thread\n");
691 D("service process started, fd=%d pid=%d\n",s[0], pid);
695 static int create_syncproc_thread()
699 ret_fd = create_sync_subprocess(file_sync_service, NULL);
700 // FIXME: file missing bug when root on mode
702 if (should_drop_privileges()) {
703 ret_fd = create_sync_subprocess(file_sync_service, NULL);
705 ret_fd = create_service_thread(file_sync_service, NULL);
714 #define UNKNOWN "unknown"
715 #define INFOBUF_MAXLEN 64
716 #define INFO_VERSION "2.2.0"
717 typedef struct platform_info {
719 char platform_info_version[INFOBUF_MAXLEN];
720 char model_name[INFOBUF_MAXLEN]; // Emulator
721 char platform_name[INFOBUF_MAXLEN]; // Tizen
722 char platform_version[INFOBUF_MAXLEN]; // 2.2.1
723 char profile_name[INFOBUF_MAXLEN]; // 2.2.1
726 static void get_platforminfo(int fd, void *cookie) {
730 s_strncpy(sysinfo.platform_info_version, INFO_VERSION, strlen(INFO_VERSION));
732 int r = system_info_get_value_string(SYSTEM_INFO_KEY_MODEL, &value);
733 if (r != SYSTEM_INFO_ERROR_NONE) {
734 s_strncpy(sysinfo.model_name, UNKNOWN, strlen(UNKNOWN));
735 D("fail to get system model:%d\n", errno);
737 s_strncpy(sysinfo.model_name, value, sizeof(sysinfo.model_name));
738 D("returns model_name:%s\n", value);
744 r = system_info_get_value_string(SYSTEM_INFO_KEY_PLATFORM_NAME, &value);
745 if (r != SYSTEM_INFO_ERROR_NONE) {
746 s_strncpy(sysinfo.platform_name, UNKNOWN, strlen(UNKNOWN));
747 D("fail to get platform name:%d\n", errno);
749 s_strncpy(sysinfo.platform_name, value, sizeof(sysinfo.platform_name));
750 D("returns platform_name:%s\n", value);
757 // FIXME: the result is different when using SYSTEM_INFO_KEY_TIZEN_VERSION_NAME
758 r = system_info_get_platform_string("tizen.org/feature/platform.version", &value);
759 if (r != SYSTEM_INFO_ERROR_NONE) {
760 s_strncpy(sysinfo.platform_version, UNKNOWN, strlen(UNKNOWN));
761 D("fail to get platform version:%d\n", errno);
763 s_strncpy(sysinfo.platform_version, value, sizeof(sysinfo.platform_version));
764 D("returns platform_version:%s\n", value);
770 r = system_info_get_platform_string("tizen.org/feature/profile", &value);
771 if (r != SYSTEM_INFO_ERROR_NONE) {
772 s_strncpy(sysinfo.profile_name, UNKNOWN, strlen(UNKNOWN));
773 D("fail to get profile name:%d\n", errno);
775 s_strncpy(sysinfo.profile_name, value, sizeof(sysinfo.profile_name));
776 D("returns profile name:%s\n", value);
782 writex(fd, &sysinfo, sizeof(pinfo));
787 int service_to_fd(const char *name)
791 if(!strncmp(name, "tcp:", 4)) {
792 int port = atoi(name + 4);
793 name = strchr(name + 4, ':');
796 ret = socket_ifr_client(port , SOCK_STREAM, "eth0");
798 ret = socket_ifr_client(port , SOCK_STREAM, "usb0");
800 if (ifconfig(SDB_FORWARD_IFNAME, SDB_FORWARD_INTERNAL_IP, SDB_FORWARD_INTERNAL_MASK, 1) == 0) {
801 ret = socket_ifr_client(port , SOCK_STREAM, SDB_FORWARD_IFNAME);
806 ret = socket_loopback_client(port, SOCK_STREAM);
809 if (disable_tcp_nagle(ret) < 0) {
810 D("failed to disable_tcp_nagle\n");
815 sdb_mutex_lock(&dns_lock);
816 ret = socket_network_client(name + 1, port, SOCK_STREAM);
817 sdb_mutex_unlock(&dns_lock);
822 #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
823 } else if(!strncmp(name, "local:", 6)) {
824 ret = socket_local_client(name + 6,
825 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
826 } else if(!strncmp(name, "localreserved:", 14)) {
827 ret = socket_local_client(name + 14,
828 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
829 } else if(!strncmp(name, "localabstract:", 14)) {
830 ret = socket_local_client(name + 14,
831 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
832 } else if(!strncmp(name, "localfilesystem:", 16)) {
833 ret = socket_local_client(name + 16,
834 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
837 } else if(!strncmp("dns:", name, 4)){
838 char *n = strdup(name + 4);
839 if(n == 0) return -1;
840 ret = create_service_thread(dns_service, n);
841 #else /* !SDB_HOST */
842 }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
843 ret = unix_open(name + 4, O_RDWR);
844 } else if(!strncmp(name, "framebuffer:", 12)) {
845 ret = create_service_thread(framebuffer_service, 0);
846 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
847 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
848 } else if (!strncmp(name, "jdwp:", 5)) {
849 ret = create_jdwp_connection_fd(atoi(name+5));
850 } else if (!strncmp(name, "log:", 4)) {
851 ret = create_service_thread(log_service, get_log_file_path(name + 4));
852 }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
854 ret = create_subproc_thread(name + 6, 0, 0);
856 ret = create_subproc_thread(NULL, 0, 0);
858 } else if(!strncmp(name, "eshell:", 7)) {
860 if (sscanf(name+7, "%d:%d", &lines, &columns) == 2) {
861 ret = create_subproc_thread(NULL, lines, columns);
863 } else if(!strncmp(name, "sync:", 5)) {
864 //ret = create_service_thread(file_sync_service, NULL);
865 ret = create_syncproc_thread();
866 }/* else if(!strncmp(name, "remount:", 8)) {
867 ret = create_service_thread(remount_service, NULL);
868 } else if(!strncmp(name, "reboot:", 7)) {
869 void* arg = strdup(name + 7);
870 if(arg == 0) return -1;
871 ret = create_service_thread(reboot_service, arg);
872 } else if(!strncmp(name, "root:", 5)) {
873 ret = create_service_thread(restart_root_service, NULL);
874 } else if(!strncmp(name, "backup:", 7)) {
875 char* arg = strdup(name+7);
876 if (arg == NULL) return -1;
877 ret = backup_service(BACKUP, arg);
878 } else if(!strncmp(name, "restore:", 8)) {
879 ret = backup_service(RESTORE, NULL);
880 }*/ else if(!strncmp(name, "root:", 5)) {
881 char* service_name = NULL;
883 service_name = strdup(name+5);
884 ret = create_service_thread(rootshell_service, (void *)(service_name));
885 } else if(!strncmp(name, "cs:", 5)) {
886 ret = create_service_thread(inoti_service, NULL);
888 } else if(!strncmp(name, "sysinfo:", 8)){
889 ret = create_service_thread(get_platforminfo, 0);
890 } else if(!strncmp(name, "rndis:", 6)){
891 char *service_name = NULL;
893 service_name = strdup(name+6);
894 ret = create_service_thread(rndis_config_service, (void *)(service_name));
897 if (close_on_exec(ret) < 0) {
898 D("failed to close fd exec\n");
906 transport_type transport;
911 static void wait_for_state(int fd, void* cookie)
913 struct state_info* sinfo = cookie;
914 char* err = "unknown error";
916 D("wait_for_state %d\n", sinfo->state);
918 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
920 writex(fd, "OKAY", 4);
922 sendfailmsg(fd, err);
929 D("wait_for_state is done\n");
934 asocket* host_service_to_socket(const char* name, const char *serial)
936 if (!strcmp(name,"track-devices")) {
937 return create_device_tracker();
938 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
939 struct state_info* sinfo = malloc(sizeof(struct state_info));
942 sinfo->serial = strdup(serial);
944 sinfo->serial = NULL;
946 name += strlen("wait-for-");
948 if (!strncmp(name, "local", strlen("local"))) {
949 sinfo->transport = kTransportLocal;
950 sinfo->state = CS_DEVICE;
951 } else if (!strncmp(name, "usb", strlen("usb"))) {
952 sinfo->transport = kTransportUsb;
953 sinfo->state = CS_DEVICE;
954 } else if (!strncmp(name, "any", strlen("any"))) {
955 sinfo->transport = kTransportAny;
956 sinfo->state = CS_DEVICE;
962 int fd = create_service_thread(wait_for_state, sinfo);
963 return create_local_socket(fd);
967 #endif /* SDB_HOST */