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"
41 typedef struct stinfo stinfo;
44 void (*func)(int fd, void *cookie);
50 void *service_bootstrap_func(void *x)
53 sti->func(sti->fd, sti->cookie);
59 SDB_MUTEX_DEFINE( dns_lock );
61 static void dns_service(int fd, void *cookie)
63 char *hostname = cookie;
67 sdb_mutex_lock(&dns_lock);
68 hp = gethostbyname(hostname);
73 writex(fd, hp->h_addr, 4);
75 sdb_mutex_unlock(&dns_lock);
81 extern int recovery_mode;
83 static void recover_service(int s, void *cookie)
85 unsigned char buf[4096];
86 unsigned count = (unsigned) cookie;
89 fd = sdb_creat("/tmp/update", 0644);
96 unsigned xfer = (count > 4096) ? 4096 : count;
97 if(readx(s, buf, xfer)) break;
98 if(writex(fd, buf, xfer)) break;
103 writex(s, "OKAY", 4);
105 writex(s, "FAIL", 4);
110 fd = sdb_creat("/tmp/update.begin", 0644);
114 void restart_root_service(int fd, void *cookie)
117 char value[PROPERTY_VALUE_MAX];
120 snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
121 writex(fd, buf, strlen(buf));
124 property_get("ro.debuggable", value, "");
125 if (strcmp(value, "1") != 0) {
126 snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
127 writex(fd, buf, strlen(buf));
132 property_set("service.sdb.root", "1");
133 snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
134 writex(fd, buf, strlen(buf));
140 void restart_tcp_service(int fd, void *cookie)
143 char value[PROPERTY_VALUE_MAX];
144 int port = (int)cookie;
147 snprintf(buf, sizeof(buf), "invalid port\n");
148 writex(fd, buf, strlen(buf));
153 snprintf(value, sizeof(value), "%d", port);
154 property_set("service.sdb.tcp.port", value);
155 snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
156 writex(fd, buf, strlen(buf));
160 void rootshell_service(int fd, void *cookie)
163 char *mode = (char*) cookie;
165 if (!strcmp(mode, "on")) {
166 if (rootshell_mode == 1) {
167 //snprintf(buf, sizeof(buf), "Already changed to developer mode\n");
168 // do not show message
170 if (access("/bin/su", F_OK) == 0) {
172 //allows a permitted user to execute a command as the superuser
173 snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n");
175 snprintf(buf, sizeof(buf), "Permission denied\n");
177 writex(fd, buf, strlen(buf));
179 } else if (!strcmp(mode, "off")) {
180 if (rootshell_mode == 1) {
182 snprintf(buf, sizeof(buf), "Switched to 'developer' account mode\n");
183 writex(fd, buf, strlen(buf));
186 snprintf(buf, sizeof(buf), "Unknown command option\n");
187 writex(fd, buf, strlen(buf));
189 D("set rootshell to %s\n", rootshell_mode == 1 ? "root" : "developer");
193 void restart_usb_service(int fd, void *cookie)
197 property_set("service.sdb.tcp.port", "0");
198 snprintf(buf, sizeof(buf), "restarting in USB mode\n");
199 writex(fd, buf, strlen(buf));
203 void reboot_service(int fd, void *arg)
211 /* Attempt to unmount the SD card first.
212 * No need to bother checking for errors.
216 /* ask vdc to unmount it */
217 // prevent: Use of untrusted string value (TAINTED_STRING)
218 execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
219 getenv("EXTERNAL_STORAGE"), "force", NULL);
220 } else if (pid > 0) {
221 /* wait until vdc succeeds or fails */
222 waitpid(pid, &ret, 0);
225 ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
227 snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
228 writex(fd, buf, strlen(buf));
236 #define EVENT_SIZE ( sizeof (struct inotify_event) )
237 #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
238 #define CS_PATH "/opt/usr/share/crash/report"
240 void inoti_service(int fd, void *arg)
244 char buffer[BUF_LEN];
246 D( "inoti_service start\n");
247 ifd = inotify_init();
250 D( "inotify_init failed\n");
254 wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
258 length = sdb_read( ifd, buffer, BUF_LEN );
261 D( "inoti read failed\n");
265 while ( i < length ) {
266 struct inotify_event *event = ( struct inotify_event * )&buffer[i];
268 if ( event->mask & IN_CREATE) {
269 if (!(event->mask & IN_ISDIR)) {
271 int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
272 D( "The file %s was created.\n", cspath);
273 writex(fd, cspath, len);
274 if (cspath != NULL) {
280 i += EVENT_SIZE + event->len;
285 inotify_rm_watch( ifd, wd );
288 D( "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 D("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 D("cannot create service thread\n");
352 D("service thread started, %d:%d\n",s[0], s[1]);
358 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
360 #ifdef HAVE_WIN32_PROC
361 D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
362 fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
364 #else /* !HAVE_WIN32_PROC */
368 ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
370 D("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
373 if (fcntl(ptm, F_SETFD, FD_CLOEXEC) < 0) {
374 D("[ cannot set cloexec to /dev/ptmx - %s ]\n",strerror(errno));
377 if(grantpt(ptm) || unlockpt(ptm) ||
378 ((devname = (char*) ptsname(ptm)) == 0)){
379 D("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
386 D("- fork failed: %s -\n", strerror(errno));
396 pts = unix_open(devname, O_RDWR);
398 fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
409 // set OOM adjustment to zero
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 D("sdb: unable to open %s due to %s\n", text, strerror(errno));
423 verify_commands(arg1);
425 execl(cmd, cmd, arg0, arg1, NULL);
426 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
427 cmd, strerror(errno), errno);
430 // Don't set child's OOM adjustment to zero.
431 // Let the child do it itself, as sometimes the parent starts
432 // running before the child has a /proc/pid/oom_adj.
433 // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
436 #endif /* !HAVE_WIN32_PROC */
438 #endif /* !SDB_HOST */
441 #define SHELL_COMMAND "/bin/sh"
443 #define SHELL_COMMAND "/bin/sh" /* tizen specific */
447 static void subproc_waiter_service(int fd, void *cookie)
449 pid_t pid = (pid_t)cookie;
451 D("entered. fd=%d of pid=%d\n", fd, pid);
454 pid_t p = waitpid(pid, &status, 0);
456 D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
458 if (WIFEXITED(status)) {
459 D("*** Exit code %d\n", WEXITSTATUS(status));
461 } else if (WIFSIGNALED(status)) {
462 D("*** Killed by signal %d\n", WTERMSIG(status));
465 D("*** Killed by unknown code %d\n", status);
470 D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
471 if (SHELL_EXIT_NOTIFY_FD >=0) {
473 res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
474 D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
475 SHELL_EXIT_NOTIFY_FD, pid, res, errno);
479 static int create_subproc_thread(const char *name)
487 ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
489 ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
491 D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
494 printf("cannot create service thread\n");
497 sti = malloc(sizeof(stinfo));
498 if(sti == 0) fatal("cannot allocate stinfo");
499 sti->func = subproc_waiter_service;
500 sti->cookie = (void*)pid;
503 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
506 printf("cannot create service thread\n");
510 D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
514 static int create_sync_subprocess(void (*func)(int, void *), void* cookie) {
519 if(sdb_socketpair(s)) {
520 D("cannot create service socket pair\n");
530 } else if (pid > 0) {
532 // FIXME: do not wait child process hear
533 //waitpid(pid, &ret, 0);
536 D("- fork failed: %s -\n", strerror(errno));
539 D("cannot create sync service sub process\n");
543 sti = malloc(sizeof(stinfo));
544 if(sti == 0) fatal("cannot allocate stinfo");
545 sti->func = subproc_waiter_service;
546 sti->cookie = (void*)pid;
549 if(sdb_thread_create( &t, service_bootstrap_func, sti)){
553 printf("cannot create service monitor thread\n");
557 D("service process started, fd=%d pid=%d\n",s[0], pid);
561 static int create_syncproc_thread()
565 if (should_drop_privileges()) {
566 ret_fd = create_sync_subprocess(file_sync_service, NULL);
568 ret_fd = create_service_thread(file_sync_service, NULL);
576 int service_to_fd(const char *name)
580 if(!strncmp(name, "tcp:", 4)) {
581 int port = atoi(name + 4);
582 name = strchr(name + 4, ':');
584 ret = socket_loopback_client(port, SOCK_STREAM);
586 disable_tcp_nagle(ret);
589 sdb_mutex_lock(&dns_lock);
590 ret = socket_network_client(name + 1, port, SOCK_STREAM);
591 sdb_mutex_unlock(&dns_lock);
596 #ifndef HAVE_WINSOCK /* winsock doesn't implement unix domain sockets */
597 } else if(!strncmp(name, "local:", 6)) {
598 ret = socket_local_client(name + 6,
599 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
600 } else if(!strncmp(name, "localreserved:", 14)) {
601 ret = socket_local_client(name + 14,
602 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
603 } else if(!strncmp(name, "localabstract:", 14)) {
604 ret = socket_local_client(name + 14,
605 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
606 } else if(!strncmp(name, "localfilesystem:", 16)) {
607 ret = socket_local_client(name + 16,
608 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
611 } else if(!strncmp("dns:", name, 4)){
612 char *n = strdup(name + 4);
613 if(n == 0) return -1;
614 ret = create_service_thread(dns_service, n);
615 #else /* !SDB_HOST */
616 }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
617 ret = unix_open(name + 4, O_RDWR);
618 } else if(!strncmp(name, "framebuffer:", 12)) {
619 ret = create_service_thread(framebuffer_service, 0);
620 } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
621 ret = create_service_thread(recover_service, (void*) atoi(name + 8));
622 } else if (!strncmp(name, "jdwp:", 5)) {
623 ret = create_jdwp_connection_fd(atoi(name+5));
624 } else if (!strncmp(name, "log:", 4)) {
625 ret = create_service_thread(log_service, get_log_file_path(name + 4));
626 }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
628 ret = create_subproc_thread(name + 6);
630 ret = create_subproc_thread(0);
632 } else if(!strncmp(name, "sync:", 5)) {
633 //ret = create_service_thread(file_sync_service, NULL);
634 ret = create_syncproc_thread();
635 }/* else if(!strncmp(name, "remount:", 8)) {
636 ret = create_service_thread(remount_service, NULL);
637 } else if(!strncmp(name, "reboot:", 7)) {
638 void* arg = strdup(name + 7);
639 if(arg == 0) return -1;
640 ret = create_service_thread(reboot_service, arg);
641 } else if(!strncmp(name, "root:", 5)) {
642 ret = create_service_thread(restart_root_service, NULL);
643 } else if(!strncmp(name, "backup:", 7)) {
644 char* arg = strdup(name+7);
645 if (arg == NULL) return -1;
646 ret = backup_service(BACKUP, arg);
647 } else if(!strncmp(name, "restore:", 8)) {
648 ret = backup_service(RESTORE, NULL);
649 }*/ else if(!strncmp(name, "root:", 5)) {
650 ret = create_service_thread(rootshell_service, (void *)(name+5));
651 } else if(!strncmp(name, "tcpip:", 6)) {
653 /*if (sscanf(name + 6, "%d", &port) == 0) {
656 port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
657 ret = create_service_thread(restart_tcp_service, (void *)port);
658 } else if(!strncmp(name, "usb:", 4)) {
659 ret = create_service_thread(restart_usb_service, NULL);
660 } else if(!strncmp(name, "cs:", 5)) {
661 ret = create_service_thread(inoti_service, NULL);
664 } else if(!strncmp(name, "echo:", 5)){
665 ret = create_service_thread(echo_service, 0);
669 if (close_on_exec(ret) < 0) {
670 D("failed to close fd exec\n");
678 transport_type transport;
683 static void wait_for_state(int fd, void* cookie)
685 struct state_info* sinfo = cookie;
686 char* err = "unknown error";
688 D("wait_for_state %d\n", sinfo->state);
690 atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
692 writex(fd, "OKAY", 4);
694 sendfailmsg(fd, err);
701 D("wait_for_state is done\n");
706 asocket* host_service_to_socket(const char* name, const char *serial)
708 if (!strcmp(name,"track-devices")) {
709 return create_device_tracker();
710 } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
711 struct state_info* sinfo = malloc(sizeof(struct state_info));
714 sinfo->serial = strdup(serial);
716 sinfo->serial = NULL;
718 name += strlen("wait-for-");
720 if (!strncmp(name, "local", strlen("local"))) {
721 sinfo->transport = kTransportLocal;
722 sinfo->state = CS_DEVICE;
723 } else if (!strncmp(name, "usb", strlen("usb"))) {
724 sinfo->transport = kTransportUsb;
725 sinfo->state = CS_DEVICE;
726 } else if (!strncmp(name, "any", strlen("any"))) {
727 sinfo->transport = kTransportAny;
728 sinfo->state = CS_DEVICE;
734 int fd = create_service_thread(wait_for_state, sinfo);
735 return create_local_socket(fd);
739 #endif /* SDB_HOST */