• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <linux/kd.h>
24 #include <errno.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <linux/if.h>
28 #include <arpa/inet.h>
29 #include <stdlib.h>
30 #include <sys/mount.h>
31 #include <sys/resource.h>
32 #include <sys/wait.h>
33 #include <linux/loop.h>
34 #include <cutils/partition_utils.h>
35 #include <cutils/android_reboot.h>
36 #include <sys/system_properties.h>
37 #include <fs_mgr.h>
38 
39 #include <selinux/selinux.h>
40 #include <selinux/label.h>
41 
42 #include "init.h"
43 #include "keywords.h"
44 #include "property_service.h"
45 #include "devices.h"
46 #include "init_parser.h"
47 #include "util.h"
48 #include "log.h"
49 
50 #include <private/android_filesystem_config.h>
51 
52 void add_environment(const char *name, const char *value);
53 
54 extern int init_module(void *, unsigned long, const char *);
55 
write_file(const char * path,const char * value)56 static int write_file(const char *path, const char *value)
57 {
58     int fd, ret, len;
59 
60     fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600);
61 
62     if (fd < 0)
63         return -errno;
64 
65     len = strlen(value);
66 
67     do {
68         ret = write(fd, value, len);
69     } while (ret < 0 && errno == EINTR);
70 
71     close(fd);
72     if (ret < 0) {
73         return -errno;
74     } else {
75         return 0;
76     }
77 }
78 
_open(const char * path)79 static int _open(const char *path)
80 {
81     int fd;
82 
83     fd = open(path, O_RDONLY | O_NOFOLLOW);
84     if (fd < 0)
85         fd = open(path, O_WRONLY | O_NOFOLLOW);
86 
87     return fd;
88 }
89 
_chown(const char * path,unsigned int uid,unsigned int gid)90 static int _chown(const char *path, unsigned int uid, unsigned int gid)
91 {
92     int fd;
93     int ret;
94 
95     fd = _open(path);
96     if (fd < 0) {
97         return -1;
98     }
99 
100     ret = fchown(fd, uid, gid);
101     if (ret < 0) {
102         int errno_copy = errno;
103         close(fd);
104         errno = errno_copy;
105         return -1;
106     }
107 
108     close(fd);
109 
110     return 0;
111 }
112 
_chmod(const char * path,mode_t mode)113 static int _chmod(const char *path, mode_t mode)
114 {
115     int fd;
116     int ret;
117 
118     fd = _open(path);
119     if (fd < 0) {
120         return -1;
121     }
122 
123     ret = fchmod(fd, mode);
124     if (ret < 0) {
125         int errno_copy = errno;
126         close(fd);
127         errno = errno_copy;
128         return -1;
129     }
130 
131     close(fd);
132 
133     return 0;
134 }
135 
insmod(const char * filename,char * options)136 static int insmod(const char *filename, char *options)
137 {
138     void *module;
139     unsigned size;
140     int ret;
141 
142     module = read_file(filename, &size);
143     if (!module)
144         return -1;
145 
146     ret = init_module(module, size, options);
147 
148     free(module);
149 
150     return ret;
151 }
152 
setkey(struct kbentry * kbe)153 static int setkey(struct kbentry *kbe)
154 {
155     int fd, ret;
156 
157     fd = open("/dev/tty0", O_RDWR | O_SYNC);
158     if (fd < 0)
159         return -1;
160 
161     ret = ioctl(fd, KDSKBENT, kbe);
162 
163     close(fd);
164     return ret;
165 }
166 
__ifupdown(const char * interface,int up)167 static int __ifupdown(const char *interface, int up)
168 {
169     struct ifreq ifr;
170     int s, ret;
171 
172     strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
173 
174     s = socket(AF_INET, SOCK_DGRAM, 0);
175     if (s < 0)
176         return -1;
177 
178     ret = ioctl(s, SIOCGIFFLAGS, &ifr);
179     if (ret < 0) {
180         goto done;
181     }
182 
183     if (up)
184         ifr.ifr_flags |= IFF_UP;
185     else
186         ifr.ifr_flags &= ~IFF_UP;
187 
188     ret = ioctl(s, SIOCSIFFLAGS, &ifr);
189 
190 done:
191     close(s);
192     return ret;
193 }
194 
service_start_if_not_disabled(struct service * svc)195 static void service_start_if_not_disabled(struct service *svc)
196 {
197     if (!(svc->flags & SVC_DISABLED)) {
198         service_start(svc, NULL);
199     }
200 }
201 
do_chdir(int nargs,char ** args)202 int do_chdir(int nargs, char **args)
203 {
204     chdir(args[1]);
205     return 0;
206 }
207 
do_chroot(int nargs,char ** args)208 int do_chroot(int nargs, char **args)
209 {
210     chroot(args[1]);
211     return 0;
212 }
213 
do_class_start(int nargs,char ** args)214 int do_class_start(int nargs, char **args)
215 {
216         /* Starting a class does not start services
217          * which are explicitly disabled.  They must
218          * be started individually.
219          */
220     service_for_each_class(args[1], service_start_if_not_disabled);
221     return 0;
222 }
223 
do_class_stop(int nargs,char ** args)224 int do_class_stop(int nargs, char **args)
225 {
226     service_for_each_class(args[1], service_stop);
227     return 0;
228 }
229 
do_class_reset(int nargs,char ** args)230 int do_class_reset(int nargs, char **args)
231 {
232     service_for_each_class(args[1], service_reset);
233     return 0;
234 }
235 
do_domainname(int nargs,char ** args)236 int do_domainname(int nargs, char **args)
237 {
238     return write_file("/proc/sys/kernel/domainname", args[1]);
239 }
240 
do_exec(int nargs,char ** args)241 int do_exec(int nargs, char **args)
242 {
243     return -1;
244 }
245 
do_export(int nargs,char ** args)246 int do_export(int nargs, char **args)
247 {
248     add_environment(args[1], args[2]);
249     return 0;
250 }
251 
do_hostname(int nargs,char ** args)252 int do_hostname(int nargs, char **args)
253 {
254     return write_file("/proc/sys/kernel/hostname", args[1]);
255 }
256 
do_ifup(int nargs,char ** args)257 int do_ifup(int nargs, char **args)
258 {
259     return __ifupdown(args[1], 1);
260 }
261 
262 
do_insmod_inner(int nargs,char ** args,int opt_len)263 static int do_insmod_inner(int nargs, char **args, int opt_len)
264 {
265     char options[opt_len + 1];
266     int i;
267 
268     options[0] = '\0';
269     if (nargs > 2) {
270         strcpy(options, args[2]);
271         for (i = 3; i < nargs; ++i) {
272             strcat(options, " ");
273             strcat(options, args[i]);
274         }
275     }
276 
277     return insmod(args[1], options);
278 }
279 
do_insmod(int nargs,char ** args)280 int do_insmod(int nargs, char **args)
281 {
282     int i;
283     int size = 0;
284 
285     if (nargs > 2) {
286         for (i = 2; i < nargs; ++i)
287             size += strlen(args[i]) + 1;
288     }
289 
290     return do_insmod_inner(nargs, args, size);
291 }
292 
do_mkdir(int nargs,char ** args)293 int do_mkdir(int nargs, char **args)
294 {
295     mode_t mode = 0755;
296     int ret;
297 
298     /* mkdir <path> [mode] [owner] [group] */
299 
300     if (nargs >= 3) {
301         mode = strtoul(args[2], 0, 8);
302     }
303 
304     ret = make_dir(args[1], mode);
305     /* chmod in case the directory already exists */
306     if (ret == -1 && errno == EEXIST) {
307         ret = _chmod(args[1], mode);
308     }
309     if (ret == -1) {
310         return -errno;
311     }
312 
313     if (nargs >= 4) {
314         uid_t uid = decode_uid(args[3]);
315         gid_t gid = -1;
316 
317         if (nargs == 5) {
318             gid = decode_uid(args[4]);
319         }
320 
321         if (_chown(args[1], uid, gid) < 0) {
322             return -errno;
323         }
324 
325         /* chown may have cleared S_ISUID and S_ISGID, chmod again */
326         if (mode & (S_ISUID | S_ISGID)) {
327             ret = _chmod(args[1], mode);
328             if (ret == -1) {
329                 return -errno;
330             }
331         }
332     }
333 
334     return 0;
335 }
336 
337 static struct {
338     const char *name;
339     unsigned flag;
340 } mount_flags[] = {
341     { "noatime",    MS_NOATIME },
342     { "noexec",     MS_NOEXEC },
343     { "nosuid",     MS_NOSUID },
344     { "nodev",      MS_NODEV },
345     { "nodiratime", MS_NODIRATIME },
346     { "ro",         MS_RDONLY },
347     { "rw",         0 },
348     { "remount",    MS_REMOUNT },
349     { "bind",       MS_BIND },
350     { "rec",        MS_REC },
351     { "unbindable", MS_UNBINDABLE },
352     { "private",    MS_PRIVATE },
353     { "slave",      MS_SLAVE },
354     { "shared",     MS_SHARED },
355     { "defaults",   0 },
356     { 0,            0 },
357 };
358 
359 #define DATA_MNT_POINT "/data"
360 
361 /* mount <type> <device> <path> <flags ...> <options> */
do_mount(int nargs,char ** args)362 int do_mount(int nargs, char **args)
363 {
364     char tmp[64];
365     char *source, *target, *system;
366     char *options = NULL;
367     unsigned flags = 0;
368     int n, i;
369     int wait = 0;
370 
371     for (n = 4; n < nargs; n++) {
372         for (i = 0; mount_flags[i].name; i++) {
373             if (!strcmp(args[n], mount_flags[i].name)) {
374                 flags |= mount_flags[i].flag;
375                 break;
376             }
377         }
378 
379         if (!mount_flags[i].name) {
380             if (!strcmp(args[n], "wait"))
381                 wait = 1;
382             /* if our last argument isn't a flag, wolf it up as an option string */
383             else if (n + 1 == nargs)
384                 options = args[n];
385         }
386     }
387 
388     system = args[1];
389     source = args[2];
390     target = args[3];
391 
392     if (!strncmp(source, "mtd@", 4)) {
393         n = mtd_name_to_number(source + 4);
394         if (n < 0) {
395             return -1;
396         }
397 
398         sprintf(tmp, "/dev/block/mtdblock%d", n);
399 
400         if (wait)
401             wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
402         if (mount(tmp, target, system, flags, options) < 0) {
403             return -1;
404         }
405 
406         goto exit_success;
407     } else if (!strncmp(source, "loop@", 5)) {
408         int mode, loop, fd;
409         struct loop_info info;
410 
411         mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
412         fd = open(source + 5, mode);
413         if (fd < 0) {
414             return -1;
415         }
416 
417         for (n = 0; ; n++) {
418             sprintf(tmp, "/dev/block/loop%d", n);
419             loop = open(tmp, mode);
420             if (loop < 0) {
421                 return -1;
422             }
423 
424             /* if it is a blank loop device */
425             if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
426                 /* if it becomes our loop device */
427                 if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
428                     close(fd);
429 
430                     if (mount(tmp, target, system, flags, options) < 0) {
431                         ioctl(loop, LOOP_CLR_FD, 0);
432                         close(loop);
433                         return -1;
434                     }
435 
436                     close(loop);
437                     goto exit_success;
438                 }
439             }
440 
441             close(loop);
442         }
443 
444         close(fd);
445         ERROR("out of loopback devices");
446         return -1;
447     } else {
448         if (wait)
449             wait_for_file(source, COMMAND_RETRY_TIMEOUT);
450         if (mount(source, target, system, flags, options) < 0) {
451             return -1;
452         }
453 
454     }
455 
456 exit_success:
457     return 0;
458 
459 }
460 
do_mount_all(int nargs,char ** args)461 int do_mount_all(int nargs, char **args)
462 {
463     pid_t pid;
464     int ret = -1;
465     int child_ret = -1;
466     int status;
467     const char *prop;
468     struct fstab *fstab;
469 
470     if (nargs != 2) {
471         return -1;
472     }
473 
474     /*
475      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
476      * do the call in the child to provide protection to the main init
477      * process if anything goes wrong (crash or memory leak), and wait for
478      * the child to finish in the parent.
479      */
480     pid = fork();
481     if (pid > 0) {
482         /* Parent.  Wait for the child to return */
483         waitpid(pid, &status, 0);
484         if (WIFEXITED(status)) {
485             ret = WEXITSTATUS(status);
486         } else {
487             ret = -1;
488         }
489     } else if (pid == 0) {
490         /* child, call fs_mgr_mount_all() */
491         klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
492         fstab = fs_mgr_read_fstab(args[1]);
493         child_ret = fs_mgr_mount_all(fstab);
494         fs_mgr_free_fstab(fstab);
495         if (child_ret == -1) {
496             ERROR("fs_mgr_mount_all returned an error\n");
497         }
498         exit(child_ret);
499     } else {
500         /* fork failed, return an error */
501         return -1;
502     }
503 
504     /* ret is 1 if the device is encrypted, 0 if not, and -1 on error */
505     if (ret == 1) {
506         property_set("ro.crypto.state", "encrypted");
507         property_set("vold.decrypt", "1");
508     } else if (ret == 0) {
509         property_set("ro.crypto.state", "unencrypted");
510         /* If fs_mgr determined this is an unencrypted device, then trigger
511          * that action.
512          */
513         action_for_each_trigger("nonencrypted", action_add_queue_tail);
514     }
515 
516     return ret;
517 }
518 
do_swapon_all(int nargs,char ** args)519 int do_swapon_all(int nargs, char **args)
520 {
521     struct fstab *fstab;
522     int ret;
523 
524     fstab = fs_mgr_read_fstab(args[1]);
525     ret = fs_mgr_swapon_all(fstab);
526     fs_mgr_free_fstab(fstab);
527 
528     return ret;
529 }
530 
do_setcon(int nargs,char ** args)531 int do_setcon(int nargs, char **args) {
532     if (is_selinux_enabled() <= 0)
533         return 0;
534     if (setcon(args[1]) < 0) {
535         return -errno;
536     }
537     return 0;
538 }
539 
do_setenforce(int nargs,char ** args)540 int do_setenforce(int nargs, char **args) {
541     if (is_selinux_enabled() <= 0)
542         return 0;
543     if (security_setenforce(atoi(args[1])) < 0) {
544         return -errno;
545     }
546     return 0;
547 }
548 
do_setkey(int nargs,char ** args)549 int do_setkey(int nargs, char **args)
550 {
551     struct kbentry kbe;
552     kbe.kb_table = strtoul(args[1], 0, 0);
553     kbe.kb_index = strtoul(args[2], 0, 0);
554     kbe.kb_value = strtoul(args[3], 0, 0);
555     return setkey(&kbe);
556 }
557 
do_setprop(int nargs,char ** args)558 int do_setprop(int nargs, char **args)
559 {
560     const char *name = args[1];
561     const char *value = args[2];
562     char prop_val[PROP_VALUE_MAX];
563     int ret;
564 
565     ret = expand_props(prop_val, value, sizeof(prop_val));
566     if (ret) {
567         ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
568         return -EINVAL;
569     }
570     property_set(name, prop_val);
571     return 0;
572 }
573 
do_setrlimit(int nargs,char ** args)574 int do_setrlimit(int nargs, char **args)
575 {
576     struct rlimit limit;
577     int resource;
578     resource = atoi(args[1]);
579     limit.rlim_cur = atoi(args[2]);
580     limit.rlim_max = atoi(args[3]);
581     return setrlimit(resource, &limit);
582 }
583 
do_start(int nargs,char ** args)584 int do_start(int nargs, char **args)
585 {
586     struct service *svc;
587     svc = service_find_by_name(args[1]);
588     if (svc) {
589         service_start(svc, NULL);
590     }
591     return 0;
592 }
593 
do_stop(int nargs,char ** args)594 int do_stop(int nargs, char **args)
595 {
596     struct service *svc;
597     svc = service_find_by_name(args[1]);
598     if (svc) {
599         service_stop(svc);
600     }
601     return 0;
602 }
603 
do_restart(int nargs,char ** args)604 int do_restart(int nargs, char **args)
605 {
606     struct service *svc;
607     svc = service_find_by_name(args[1]);
608     if (svc) {
609         service_restart(svc);
610     }
611     return 0;
612 }
613 
do_powerctl(int nargs,char ** args)614 int do_powerctl(int nargs, char **args)
615 {
616     char command[PROP_VALUE_MAX];
617     int res;
618     int len = 0;
619     int cmd = 0;
620     char *reboot_target;
621 
622     res = expand_props(command, args[1], sizeof(command));
623     if (res) {
624         ERROR("powerctl: cannot expand '%s'\n", args[1]);
625         return -EINVAL;
626     }
627 
628     if (strncmp(command, "shutdown", 8) == 0) {
629         cmd = ANDROID_RB_POWEROFF;
630         len = 8;
631     } else if (strncmp(command, "reboot", 6) == 0) {
632         cmd = ANDROID_RB_RESTART2;
633         len = 6;
634     } else {
635         ERROR("powerctl: unrecognized command '%s'\n", command);
636         return -EINVAL;
637     }
638 
639     if (command[len] == ',') {
640         reboot_target = &command[len + 1];
641     } else if (command[len] == '\0') {
642         reboot_target = "";
643     } else {
644         ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
645         return -EINVAL;
646     }
647 
648     return android_reboot(cmd, 0, reboot_target);
649 }
650 
do_trigger(int nargs,char ** args)651 int do_trigger(int nargs, char **args)
652 {
653     action_for_each_trigger(args[1], action_add_queue_tail);
654     return 0;
655 }
656 
do_symlink(int nargs,char ** args)657 int do_symlink(int nargs, char **args)
658 {
659     return symlink(args[1], args[2]);
660 }
661 
do_rm(int nargs,char ** args)662 int do_rm(int nargs, char **args)
663 {
664     return unlink(args[1]);
665 }
666 
do_rmdir(int nargs,char ** args)667 int do_rmdir(int nargs, char **args)
668 {
669     return rmdir(args[1]);
670 }
671 
do_sysclktz(int nargs,char ** args)672 int do_sysclktz(int nargs, char **args)
673 {
674     struct timezone tz;
675 
676     if (nargs != 2)
677         return -1;
678 
679     memset(&tz, 0, sizeof(tz));
680     tz.tz_minuteswest = atoi(args[1]);
681     if (settimeofday(NULL, &tz))
682         return -1;
683     return 0;
684 }
685 
do_write(int nargs,char ** args)686 int do_write(int nargs, char **args)
687 {
688     const char *path = args[1];
689     const char *value = args[2];
690     char prop_val[PROP_VALUE_MAX];
691     int ret;
692 
693     ret = expand_props(prop_val, value, sizeof(prop_val));
694     if (ret) {
695         ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
696         return -EINVAL;
697     }
698     return write_file(path, prop_val);
699 }
700 
do_copy(int nargs,char ** args)701 int do_copy(int nargs, char **args)
702 {
703     char *buffer = NULL;
704     int rc = 0;
705     int fd1 = -1, fd2 = -1;
706     struct stat info;
707     int brtw, brtr;
708     char *p;
709 
710     if (nargs != 3)
711         return -1;
712 
713     if (stat(args[1], &info) < 0)
714         return -1;
715 
716     if ((fd1 = open(args[1], O_RDONLY)) < 0)
717         goto out_err;
718 
719     if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
720         goto out_err;
721 
722     if (!(buffer = malloc(info.st_size)))
723         goto out_err;
724 
725     p = buffer;
726     brtr = info.st_size;
727     while(brtr) {
728         rc = read(fd1, p, brtr);
729         if (rc < 0)
730             goto out_err;
731         if (rc == 0)
732             break;
733         p += rc;
734         brtr -= rc;
735     }
736 
737     p = buffer;
738     brtw = info.st_size;
739     while(brtw) {
740         rc = write(fd2, p, brtw);
741         if (rc < 0)
742             goto out_err;
743         if (rc == 0)
744             break;
745         p += rc;
746         brtw -= rc;
747     }
748 
749     rc = 0;
750     goto out;
751 out_err:
752     rc = -1;
753 out:
754     if (buffer)
755         free(buffer);
756     if (fd1 >= 0)
757         close(fd1);
758     if (fd2 >= 0)
759         close(fd2);
760     return rc;
761 }
762 
do_chown(int nargs,char ** args)763 int do_chown(int nargs, char **args) {
764     /* GID is optional. */
765     if (nargs == 3) {
766         if (_chown(args[2], decode_uid(args[1]), -1) < 0)
767             return -errno;
768     } else if (nargs == 4) {
769         if (_chown(args[3], decode_uid(args[1]), decode_uid(args[2])) < 0)
770             return -errno;
771     } else {
772         return -1;
773     }
774     return 0;
775 }
776 
get_mode(const char * s)777 static mode_t get_mode(const char *s) {
778     mode_t mode = 0;
779     while (*s) {
780         if (*s >= '0' && *s <= '7') {
781             mode = (mode<<3) | (*s-'0');
782         } else {
783             return -1;
784         }
785         s++;
786     }
787     return mode;
788 }
789 
do_chmod(int nargs,char ** args)790 int do_chmod(int nargs, char **args) {
791     mode_t mode = get_mode(args[1]);
792     if (_chmod(args[2], mode) < 0) {
793         return -errno;
794     }
795     return 0;
796 }
797 
do_restorecon(int nargs,char ** args)798 int do_restorecon(int nargs, char **args) {
799     int i;
800 
801     for (i = 1; i < nargs; i++) {
802         if (restorecon(args[i]) < 0)
803             return -errno;
804     }
805     return 0;
806 }
807 
do_setsebool(int nargs,char ** args)808 int do_setsebool(int nargs, char **args) {
809     const char *name = args[1];
810     const char *value = args[2];
811     SELboolean b;
812     int ret;
813 
814     if (is_selinux_enabled() <= 0)
815         return 0;
816 
817     b.name = name;
818     if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
819         b.value = 1;
820     else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
821         b.value = 0;
822     else {
823         ERROR("setsebool: invalid value %s\n", value);
824         return -EINVAL;
825     }
826 
827     if (security_set_boolean_list(1, &b, 0) < 0) {
828         ret = -errno;
829         ERROR("setsebool: could not set %s to %s\n", name, value);
830         return ret;
831     }
832 
833     return 0;
834 }
835 
do_loglevel(int nargs,char ** args)836 int do_loglevel(int nargs, char **args) {
837     if (nargs == 2) {
838         klog_set_level(atoi(args[1]));
839         return 0;
840     }
841     return -1;
842 }
843 
do_load_persist_props(int nargs,char ** args)844 int do_load_persist_props(int nargs, char **args) {
845     if (nargs == 1) {
846         load_persist_props();
847         return 0;
848     }
849     return -1;
850 }
851 
do_wait(int nargs,char ** args)852 int do_wait(int nargs, char **args)
853 {
854     if (nargs == 2) {
855         return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
856     } else if (nargs == 3) {
857         return wait_for_file(args[1], atoi(args[2]));
858     } else
859         return -1;
860 }
861