Merge change 1950 into donut

* changes:
  new cdma event log tags
diff --git a/adb/fdevent.c b/adb/fdevent.c
index 5d6fb96..c179b20 100644
--- a/adb/fdevent.c
+++ b/adb/fdevent.c
@@ -87,7 +87,7 @@
 {
         /* XXX: what's a good size for the passed in hint? */
     epoll_fd = epoll_create(256);
-    
+
     if(epoll_fd < 0) {
         perror("epoll_create() failed");
         exit(1);
@@ -105,7 +105,7 @@
     ev.events = 0;
     ev.data.ptr = fde;
 
-#if 0    
+#if 0
     if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
         perror("epoll_ctl() failed\n");
         exit(1);
@@ -116,7 +116,7 @@
 static void fdevent_disconnect(fdevent *fde)
 {
     struct epoll_event ev;
-    
+
     memset(&ev, 0, sizeof(ev));
     ev.events = 0;
     ev.data.ptr = fde;
@@ -133,9 +133,9 @@
 {
     struct epoll_event ev;
     int active;
-    
+
     active = (fde->state & FDE_EVENTMASK) != 0;
-    
+
     memset(&ev, 0, sizeof(ev));
     ev.events = 0;
     ev.data.ptr = fde;
@@ -241,7 +241,7 @@
 static void fdevent_disconnect(fdevent *fde)
 {
     int i, n;
-    
+
     FD_CLR(fde->fd, &read_fds);
     FD_CLR(fde->fd, &write_fds);
     FD_CLR(fde->fd, &error_fds);
@@ -283,9 +283,9 @@
     memcpy(&rfd, &read_fds, sizeof(fd_set));
     memcpy(&wfd, &write_fds, sizeof(fd_set));
     memcpy(&efd, &error_fds, sizeof(fd_set));
-    
+
     n = select(select_n, &rfd, &wfd, &efd, 0);
-    
+
     if(n < 0) {
         if(errno == EINTR) return;
         perror("select");
@@ -300,12 +300,12 @@
 
         if(events) {
             n--;
-            
+
             fde = fd_table[i];
             if(fde == 0) FATAL("missing fde for fd %d\n", i);
 
             fde->events |= events;
-            
+
             if(fde->state & FDE_PENDING) continue;
             fde->state |= FDE_PENDING;
             fdevent_plist_enqueue(fde);
@@ -320,7 +320,7 @@
     if(fde->fd < 0) {
         FATAL("bogus negative fd (%d)\n", fde->fd);
     }
-    
+
     if(fde->fd >= fd_table_max) {
         int oldmax = fd_table_max;
         if(fde->fd > 32000) {
@@ -383,9 +383,9 @@
 {
     fdevent *list = &list_pending;
     fdevent *node = list->next;
-    
+
     if(node == list) return 0;
-    
+
     list->next = node->next;
     list->next->prev = list;
     node->next = 0;
@@ -449,9 +449,9 @@
 void fdevent_set(fdevent *fde, unsigned events)
 {
     events &= FDE_EVENTMASK;
-    
+
     if((fde->state & FDE_EVENTMASK) == events) return;
-    
+
     if(fde->state & FDE_ACTIVE) {
         fdevent_update(fde, events);
         dump_fde(fde, "update");
@@ -487,13 +487,13 @@
 void fdevent_loop()
 {
     fdevent *fde;
-    
+
     for(;;) {
 #if DEBUG
         fprintf(stderr,"--- ---- waiting for events\n");
 #endif
         fdevent_process();
-        
+
         while((fde = fdevent_plist_dequeue())) {
             unsigned events = fde->events;
             fde->events = 0;
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 7a442d4..6b7e7ec 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -17,10 +17,13 @@
 #ifndef __FDEVENT_H
 #define __FDEVENT_H
 
+#include <stdint.h>  /* for int64_t */
+
 /* events that may be observed */
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
 #define FDE_ERROR             0x0004
+#define FDE_TIMEOUT           0x0008
 
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
@@ -30,6 +33,8 @@
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
 /* Allocate and initialize a new fdevent object
+ * Note: use FD_TIMER as 'fd' to create a fd-less object
+ * (used to implement timers).
 */
 fdevent *fdevent_create(int fd, fd_func func, void *arg);
 
@@ -53,6 +58,8 @@
 void fdevent_add(fdevent *fde, unsigned events);
 void fdevent_del(fdevent *fde, unsigned events);
 
+void fdevent_set_timeout(fdevent *fde, int64_t  timeout_ms);
+
 /* loop forever, handling events.
 */
 void fdevent_loop();
@@ -65,7 +72,7 @@
     int fd;
     unsigned short state;
     unsigned short events;
-    
+
     fd_func func;
     void *arg;
 };
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 4e6d385..0ebfe73 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -165,7 +165,7 @@
 }
 
 static int sync_finish_readtime(int fd, unsigned int *timestamp,
-				unsigned int *mode, unsigned int *size)
+                                unsigned int *mode, unsigned int *size)
 {
     syncmsg msg;
 
@@ -908,12 +908,12 @@
             unsigned int timestamp, mode, size;
             if (sync_finish_readtime(fd, &timestamp, &mode, &size))
                 return 1;
-	    if (size == ci->size) {
+            if (size == ci->size) {
                 /* for links, we cannot update the atime/mtime */
                 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
-		   (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
                     ci->flag = 1;
-	    }
+            }
         }
     }
 #endif
diff --git a/adb/protocol.txt b/adb/protocol.txt
index d0f307c..398d042 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -23,7 +23,7 @@
 
 
 --- protocol overview and basics ---------------------------------------
- 
+
 The transport layer deals in "messages", which consist of a 24 byte
 header followed (optionally) by a payload.  The header consists of 6
 32 bit words which are sent across the wire in little endian format.
@@ -52,7 +52,7 @@
 reversed.
 
 
-
+
 --- CONNECT(version, maxdata, "system-identity-string") ----------------
 
 The CONNECT message establishes the presence of a remote system.
@@ -114,7 +114,7 @@
 not change on later READY messages sent to the same stream.
 
 
-
+
 --- WRITE(0, remote-id, "data") ----------------------------------------
 
 The WRITE message sends data to the recipient's stream identified by
@@ -172,7 +172,7 @@
 #define A_WRTE 0x45545257
 
 
-
+
 --- implementation details ---------------------------------------------
 
 The core of the bridge program will use three threads.  One thread
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3c74e0f..389fbd2 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -67,16 +67,16 @@
 
 static __inline__ int  adb_thread_create( adb_thread_t  *thread, adb_thread_func_t  func, void*  arg)
 {
-	thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
-	if (thread->tid == (unsigned)-1L) {
-		return -1;
-	}
-	return 0;
+    thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
+    if (thread->tid == (unsigned)-1L) {
+        return -1;
+    }
+    return 0;
 }
 
 static __inline__ void  close_on_exec(int  fd)
 {
-	/* nothing really */
+    /* nothing really */
 }
 
 extern void  disable_tcp_nagle(int  fd);
@@ -138,7 +138,7 @@
 
 static __inline__ int  adb_open_mode(const char* path, int options, int mode)
 {
-	return adb_open(path, options);
+    return adb_open(path, options);
 }
 
 static __inline__ int  unix_open(const char*  path, int options,...)
@@ -203,7 +203,7 @@
 
 static __inline__ void  adb_sleep_ms( int  mseconds )
 {
-	Sleep( mseconds );
+    Sleep( mseconds );
 }
 
 extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
@@ -290,7 +290,7 @@
 
 static __inline__ void  close_on_exec(int  fd)
 {
-	fcntl( fd, F_SETFD, FD_CLOEXEC );
+    fcntl( fd, F_SETFD, FD_CLOEXEC );
 }
 
 static __inline__ int  unix_open(const char*  path, int options,...)
@@ -312,7 +312,7 @@
 
 static __inline__ int  adb_open_mode( const char*  pathname, int  options, int  mode )
 {
-	return open( pathname, options, mode );
+    return open( pathname, options, mode );
 }
 
 
@@ -368,11 +368,11 @@
 {
     int  fd = creat(path, mode);
 
-	if ( fd < 0 )
-		return -1;
+    if ( fd < 0 )
+        return -1;
 
     close_on_exec(fd);
-	return fd;
+    return fd;
 }
 #undef   creat
 #define  creat  ___xxx_creat
@@ -439,12 +439,12 @@
 
 static __inline__ void  adb_sleep_ms( int  mseconds )
 {
-	usleep( mseconds*1000 );
+    usleep( mseconds*1000 );
 }
 
 static __inline__ int  adb_mkdir(const char*  path, int mode)
 {
-	return mkdir(path, mode);
+    return mkdir(path, mode);
 }
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index c2a9a98..a8e3bb9 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -739,12 +739,12 @@
 {
     FH   serverfh = _fh_from_int(serverfd);
     FH   fh;
-    
+
     if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
         D( "adb_socket_accept: invalid fd %d\n", serverfd );
         return -1;
     }
-    
+
     fh = _fh_alloc( &_fh_socket_class );
     if (!fh) {
         D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
@@ -757,7 +757,7 @@
         D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
         return -1;
     }
-    
+
     snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
     D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
     return  _fh_to_int(fh);
@@ -768,7 +768,7 @@
 {
     FH   fh = _fh_from_int(fd);
     int  on;
-    
+
     if ( !fh || fh->clazz != &_fh_socket_class )
         return;
 
@@ -1746,7 +1746,7 @@
 
 /**  FILE EVENT HOOKS
  **/
- 
+
 static void  _event_file_prepare( EventHook  hook )
 {
     if (hook->wanted & (FDE_READ|FDE_WRITE)) {
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 7ddaa0c..0951f67 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -446,7 +446,7 @@
 }
 
 void find_devices() {
-	usb_handle* handle = NULL;
+        usb_handle* handle = NULL;
   char entry_buffer[2048];
   char interf_name[2048];
   AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
diff --git a/init/builtins.c b/init/builtins.c
index 95fb223..17df0af 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -126,7 +126,7 @@
 static void service_start_if_not_disabled(struct service *svc)
 {
     if (!(svc->flags & SVC_DISABLED)) {
-        service_start(svc);
+        service_start(svc, NULL);
     }
 }
 
@@ -316,7 +316,7 @@
     struct service *svc;
     svc = service_find_by_name(args[1]);
     if (svc) {
-        service_start(svc);
+        service_start(svc, NULL);
     }
     return 0;
 }
@@ -337,7 +337,7 @@
     svc = service_find_by_name(args[1]);
     if (svc) {
         service_stop(svc);
-        service_start(svc);
+        service_start(svc, NULL);
     }
     return 0;
 }
diff --git a/init/init.c b/init/init.c
index a748ec3..b350569 100644
--- a/init/init.c
+++ b/init/init.c
@@ -156,7 +156,7 @@
     fcntl(fd, F_SETFD, 0);
 }
 
-void service_start(struct service *svc)
+void service_start(struct service *svc, const char *dynamic_args)
 {
     struct stat s;
     pid_t pid;
@@ -192,6 +192,12 @@
         return;
     }
 
+    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
+        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]);
+        svc->flags |= SVC_DISABLED;
+        return;
+    }
+
     NOTICE("starting '%s'\n", svc->name);
 
     pid = fork();
@@ -248,7 +254,50 @@
             setuid(svc->uid);
         }
 
-        execve(svc->args[0], (char**) svc->args, (char**) ENV);
+        if (!dynamic_args)
+            execve(svc->args[0], (char**) svc->args, (char**) ENV);
+        else {
+            char *arg_ptrs[SVC_MAXARGS+1];
+            int arg_idx;
+            char *tmp = strdup(dynamic_args);
+            char *p = tmp;
+
+            /* Copy the static arguments */
+            for (arg_idx = 0; arg_idx < svc->nargs; arg_idx++) {
+                arg_ptrs[arg_idx] = svc->args[arg_idx];
+            }
+
+            int done = 0;
+            while(!done) {
+
+                if (arg_idx == SVC_MAXARGS) 
+                    break;
+
+                /* Advance over any leading whitespace */
+                if (*p == ' ') {
+                    for (p; *p != ' '; p++);
+                    p++;
+                }
+                /* Locate next argument */
+                char *q = p;
+                while(1) {
+                    if (*q == ' ') {
+                        *q = '\0';
+                        break;
+                    } else if (*q == '\0') {
+                        done = 1;
+                        break;
+                    }
+                    q++;
+                }
+                arg_ptrs[arg_idx++] = p;
+
+                q++; // Advance q to the next string
+                p = q;
+            }
+            arg_ptrs[arg_idx] = '\0';
+            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
+        }
         _exit(127);
     }
 
@@ -379,7 +428,7 @@
 
     if (next_start_time <= gettime()) {
         svc->flags &= (~SVC_RESTARTING);
-        service_start(svc);
+        service_start(svc, NULL);
         return;
     }
 
@@ -405,13 +454,29 @@
 
 static void msg_start(const char *name)
 {
-    struct service *svc = service_find_by_name(name);
+    struct service *svc;
+    char *tmp = NULL;
+    char *args = NULL;
+
+    if (!strchr(name, ':'))
+        svc = service_find_by_name(name);
+    else {
+        tmp = strdup(name);
+        strcpy(tmp, name);
+        args = strchr(tmp, ':');
+        *args = '\0';
+        args++;
+
+        svc = service_find_by_name(tmp);
+    }
     
     if (svc) {
-        service_start(svc);
+        service_start(svc, args);
     } else {
         ERROR("no such service '%s'\n", name);
     }
+    if (tmp)
+        free(tmp);
 }
 
 static void msg_stop(const char *name)
@@ -737,7 +802,7 @@
     svc = service_find_by_keychord(id);
     if (svc) {
         INFO("starting service %s from keychord\n", svc->name);
-        service_start(svc);   
+        service_start(svc, NULL);   
     } else {
         ERROR("service for keychord %d not found\n", id);
     }
diff --git a/init/init.h b/init/init.h
index b93eb50..f306b7b 100644
--- a/init/init.h
+++ b/init/init.h
@@ -116,6 +116,8 @@
 
 #define NR_SVC_SUPP_GIDS 6    /* six supplementary groups */
 
+#define SVC_MAXARGS 64
+
 struct service {
         /* list of all services */
     struct listnode slist;
@@ -160,7 +162,7 @@
 void service_for_each_flags(unsigned matchflags,
                             void (*func)(struct service *svc));
 void service_stop(struct service *svc);
-void service_start(struct service *svc);
+void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
 struct action *action_remove_queue_head(void);
diff --git a/init/parser.c b/init/parser.c
index 30fa3de..33c1a68 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -60,8 +60,6 @@
 #endif       
 }
 
-#define MAXARGS 64
-
 #define T_EOF 0
 #define T_TEXT 1
 #define T_NEWLINE 2
@@ -357,7 +355,7 @@
 static void parse_config(const char *fn, char *s)
 {
     struct parse_state state;
-    char *args[MAXARGS];
+    char *args[SVC_MAXARGS];
     int nargs;
 
     nargs = 0;
@@ -384,7 +382,7 @@
             }
             break;
         case T_TEXT:
-            if (nargs < MAXARGS) {
+            if (nargs < SVC_MAXARGS) {
                 args[nargs++] = state.text;
             }
             break;