Blob


1 /*
2 * Copyright (c) 2022 Omar Polo <op@openbsd.org>
3 * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/queue.h>
21 #include <sys/uio.h>
22 #include <sys/un.h>
24 #include <errno.h>
25 #include <event.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <unistd.h>
34 #include <imsg.h>
36 #include "amused.h"
37 #include "log.h"
38 #include "playlist.h"
39 #include "xmalloc.h"
41 static struct imsgbuf *ibuf;
42 char cwd[PATH_MAX];
44 static int ctl_noarg(struct parse_result *, int, char **);
45 static int ctl_add(struct parse_result *, int, char **);
46 static int ctl_show(struct parse_result *, int, char **);
47 static int ctl_load(struct parse_result *, int, char **);
48 static int ctl_jump(struct parse_result *, int, char **);
49 static int ctl_repeat(struct parse_result *, int, char **);
50 static int ctl_monitor(struct parse_result *, int, char **);
52 struct ctl_command ctl_commands[] = {
53 { "add", ADD, ctl_add, "files...", 0 },
54 { "flush", FLUSH, ctl_noarg, "", 0 },
55 { "jump", JUMP, ctl_jump, "pattern", 0 },
56 { "load", LOAD, ctl_load, "[file]", 1 },
57 { "monitor", MONITOR, ctl_monitor, "[events]", 0 },
58 { "next", NEXT, ctl_noarg, "", 0 },
59 { "pause", PAUSE, ctl_noarg, "", 0 },
60 { "play", PLAY, ctl_noarg, "", 0 },
61 { "prev", PREV, ctl_noarg, "", 0 },
62 { "repeat", REPEAT, ctl_repeat, "one|all on|off", 0 },
63 { "restart", RESTART, ctl_noarg, "", 0 },
64 { "show", SHOW, ctl_show, "[-p]", 0 },
65 { "status", STATUS, ctl_noarg, "", 0 },
66 { "stop", STOP, ctl_noarg, "", 0 },
67 { "toggle", TOGGLE, ctl_noarg, "", 0 },
68 { NULL, 0, NULL, NULL, 0 },
69 };
71 __dead void
72 usage(void)
73 {
74 fprintf(stderr, "usage: %s [-dv] [-s socket]\n", getprogname());
75 exit(1);
76 }
78 static __dead void
79 ctl_usage(struct ctl_command *ctl)
80 {
81 fprintf(stderr, "usage: %s [-v] [-s socket] %s %s\n", getprogname(),
82 ctl->name, ctl->usage);
83 exit(1);
84 }
86 /* based on canonpath from kern_pledge.c */
87 static int
88 canonpath(const char *input, char *buf, size_t bufsize)
89 {
90 const char *p;
91 char *q, path[PATH_MAX];
93 if (input[0] != '/') {
94 if (snprintf(path, sizeof(path), "%s/%s", cwd, input)
95 >= sizeof(path)) {
96 errno = ENAMETOOLONG;
97 return -1;
98 }
99 input = path;
102 p = input;
103 q = buf;
104 while (*p && (q - buf < bufsize)) {
105 if (p[0] == '/' && (p[1] == '/' || p[1] == '\0')) {
106 p += 1;
108 } else if (p[0] == '/' && p[1] == '.' &&
109 (p[2] == '/' || p[2] == '\0')) {
110 p += 2;
112 } else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
113 (p[3] == '/' || p[3] == '\0')) {
114 p += 3;
115 if (q != buf) /* "/../" at start of buf */
116 while (*--q != '/')
117 continue;
119 } else {
120 *q++ = *p++;
123 if ((*p == '\0') && (q - buf < bufsize)) {
124 *q = 0;
125 return 0;
126 } else {
127 errno = ENAMETOOLONG;
128 return -1;
132 static int
133 parse(int argc, char **argv)
135 struct ctl_command *ctl = NULL;
136 struct parse_result res;
137 const char *argv0;
138 int i, status;
140 memset(&res, 0, sizeof(res));
142 if ((argv0 = argv[0]) == NULL)
143 argv0 = "status";
145 for (i = 0; ctl_commands[i].name != NULL; ++i) {
146 if (strncmp(ctl_commands[i].name, argv0, strlen(argv0))
147 == 0) {
148 if (ctl != NULL) {
149 fprintf(stderr,
150 "ambiguous argument: %s\n", argv0);
151 usage();
153 ctl = &ctl_commands[i];
157 if (ctl == NULL) {
158 fprintf(stderr, "unknown argument: %s\n", argv[0]);
159 usage();
162 res.action = ctl->action;
163 res.ctl = ctl;
165 if (!ctl->has_pledge) {
166 /* pledge(2) default if command doesn't have its own */
167 if (pledge("stdio", NULL) == -1)
168 fatal("pledge");
171 status = ctl->main(&res, argc, argv);
172 close(ibuf->fd);
173 free(ibuf);
174 return status;
177 static int
178 load_files(struct parse_result *res, int *ret)
180 FILE *f;
181 const char *file;
182 char *line = NULL;
183 char path[PATH_MAX];
184 size_t linesize = 0, i = 0;
185 ssize_t linelen, curr = -1;
187 if (res->file == NULL)
188 f = stdin;
189 else if ((f = fopen(res->file, "r")) == NULL) {
190 log_warn("can't open %s", res->file);
191 *ret = 1;
192 return 1;
195 while ((linelen = getline(&line, &linesize, f)) != -1) {
196 if (linelen == 0)
197 continue;
198 line[linelen-1] = '\0';
199 file = line;
200 if (!strncmp(file, "> ", 2)) {
201 file += 2;
202 curr = i;
203 } else if (!strncmp(file, " ", 2))
204 file += 2;
206 memset(path, 0, sizeof(path));
207 if (canonpath(file, path, sizeof(path)) == -1) {
208 log_warn("canonpath %s", file);
209 continue;
212 i++;
213 imsg_compose(ibuf, IMSG_CTL_ADD, 0, 0, -1,
214 path, sizeof(path));
217 free(line);
218 if (ferror(f))
219 fatal("getline");
220 fclose(f);
222 if (i == 0) {
223 *ret = 1;
224 return 1;
227 imsg_compose(ibuf, IMSG_CTL_COMMIT, 0, 0, -1,
228 &curr, sizeof(curr));
229 imsg_flush(ibuf);
230 return 0;
233 static const char *
234 imsg_strerror(struct imsg *imsg)
236 size_t datalen;
237 const char *msg;
239 datalen = IMSG_DATA_SIZE(*imsg);
240 msg = imsg->data;
241 if (datalen == 0 || msg[datalen-1] != '\0')
242 fatalx("malformed error message");
244 return msg;
247 static const char *
248 imsg_name(int type)
250 switch (type) {
251 case IMSG_CTL_PLAY:
252 return "play";
253 case IMSG_CTL_TOGGLE_PLAY:
254 return "toggle";
255 case IMSG_CTL_PAUSE:
256 return "pause";
257 case IMSG_CTL_STOP:
258 return "stop";
259 case IMSG_CTL_RESTART:
260 return "restart";
261 case IMSG_CTL_FLUSH:
262 return "flush";
263 case IMSG_CTL_NEXT:
264 return "next";
265 case IMSG_CTL_PREV:
266 return "prev";
267 case IMSG_CTL_JUMP:
268 return "jump";
269 case IMSG_CTL_REPEAT:
270 return "repeat";
271 case IMSG_CTL_ADD:
272 return "add";
273 case IMSG_CTL_COMMIT:
274 return "load";
275 default:
276 return "unknown";
280 static void
281 print_time(const char *label, int64_t seconds)
283 int hours, minutes;
285 if (seconds < 0)
286 seconds = 0;
288 hours = seconds / 3600;
289 seconds -= hours * 3600;
291 minutes = seconds / 60;
292 seconds -= minutes * 60;
294 printf("%s ", label);
295 if (hours != 0)
296 printf("%02d:", hours);
297 printf("%02d:%02lld\n", minutes, (long long)seconds);
300 static int
301 ctlaction(struct parse_result *res)
303 char path[PATH_MAX];
304 struct imsg imsg;
305 struct player_status ps;
306 size_t datalen;
307 ssize_t n;
308 int i, type, ret = 0, done = 1;
310 switch (res->action) {
311 case PLAY:
312 imsg_compose(ibuf, IMSG_CTL_PLAY, 0, 0, -1, NULL, 0);
313 if (verbose) {
314 imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1,
315 NULL, 0);
316 done = 0;
318 break;
319 case PAUSE:
320 imsg_compose(ibuf, IMSG_CTL_PAUSE, 0, 0, -1, NULL, 0);
321 break;
322 case TOGGLE:
323 imsg_compose(ibuf, IMSG_CTL_TOGGLE_PLAY, 0, 0, -1, NULL, 0);
324 if (verbose) {
325 imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1,
326 NULL, 0);
327 done = 0;
329 break;
330 case STOP:
331 imsg_compose(ibuf, IMSG_CTL_STOP, 0, 0, -1, NULL, 0);
332 break;
333 case RESTART:
334 imsg_compose(ibuf, IMSG_CTL_RESTART, 0, 0, -1, NULL, 0);
335 if (verbose) {
336 imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1,
337 NULL, 0);
338 done = 0;
340 break;
341 case ADD:
342 done = 0;
343 for (i = 0; res->files[i] != NULL; ++i) {
344 memset(path, 0, sizeof(path));
345 if (canonpath(res->files[i], path, sizeof(path))
346 == -1) {
347 log_warn("canonpath %s", res->files[i]);
348 continue;
351 imsg_compose(ibuf, IMSG_CTL_ADD, 0, 0, -1,
352 path, sizeof(path));
354 ret = i == 0;
355 break;
356 case FLUSH:
357 imsg_compose(ibuf, IMSG_CTL_FLUSH, 0, 0, -1, NULL, 0);
358 break;
359 case SHOW:
360 done = 0;
361 imsg_compose(ibuf, IMSG_CTL_SHOW, 0, 0, -1, NULL, 0);
362 break;
363 case STATUS:
364 done = 0;
365 imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, NULL, 0);
366 break;
367 case NEXT:
368 imsg_compose(ibuf, IMSG_CTL_NEXT, 0, 0, -1, NULL, 0);
369 if (verbose) {
370 imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1,
371 NULL, 0);
372 done = 0;
374 break;
375 case PREV:
376 imsg_compose(ibuf, IMSG_CTL_PREV, 0, 0, -1, NULL, 0);
377 if (verbose) {
378 imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1,
379 NULL, 0);
380 done = 0;
382 break;
383 case LOAD:
384 done = 0;
385 imsg_compose(ibuf, IMSG_CTL_BEGIN, 0, 0, -1, NULL, 0);
386 break;
387 case JUMP:
388 done = 0;
389 memset(path, 0, sizeof(path));
390 strlcpy(path, res->file, sizeof(path));
391 imsg_compose(ibuf, IMSG_CTL_JUMP, 0, 0, -1,
392 path, sizeof(path));
393 break;
394 case REPEAT:
395 imsg_compose(ibuf, IMSG_CTL_REPEAT, 0, 0, -1,
396 &res->rep, sizeof(res->rep));
397 break;
398 case MONITOR:
399 done = 0;
400 imsg_compose(ibuf, IMSG_CTL_MONITOR, 0, 0, -1,
401 NULL, 0);
402 break;
403 case NONE:
404 /* action not expected */
405 fatalx("invalid action %u", res->action);
406 break;
409 if (ret != 0)
410 goto end;
412 imsg_flush(ibuf);
414 i = 0;
415 while (!done) {
416 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
417 fatalx("imsg_read error");
418 if (n == 0)
419 fatalx("pipe closed");
421 while (!done) {
422 if ((n = imsg_get(ibuf, &imsg)) == -1)
423 fatalx("imsg_get error");
424 if (n == 0)
425 break;
427 if (imsg.hdr.type == IMSG_CTL_ERR) {
428 log_warnx("%s: %s", res->ctl->name,
429 imsg_strerror(&imsg));
430 ret = 1;
431 done = 1;
432 break;
435 datalen = IMSG_DATA_SIZE(imsg);
437 switch (res->action) {
438 case ADD:
439 if (res->files[i] == NULL)
440 fatalx("received more replies than "
441 "files enqueued.");
443 if (imsg.hdr.type == IMSG_CTL_ADD)
444 log_debug("enqueued %s", res->files[i]);
445 else
446 fatalx("invalid message %d",
447 imsg.hdr.type);
448 i++;
449 done = res->files[i] == NULL;
450 break;
451 case SHOW:
452 if (datalen == 0) {
453 done = 1;
454 break;
456 if (datalen != sizeof(ps))
457 fatalx("data size mismatch");
458 memcpy(&ps, imsg.data, sizeof(ps));
459 if (ps.path[sizeof(ps.path) - 1] != '\0')
460 fatalx("received corrupted data");
461 if (res->pretty) {
462 char c = ' ';
463 if (ps.status == STATE_PLAYING)
464 c = '>';
465 printf("%c ", c);
467 puts(ps.path);
468 break;
469 case PLAY:
470 case TOGGLE:
471 case RESTART:
472 case STATUS:
473 case NEXT:
474 case PREV:
475 case JUMP:
476 if (imsg.hdr.type != IMSG_CTL_STATUS)
477 fatalx("invalid message %d",
478 imsg.hdr.type);
480 if (datalen != sizeof(ps))
481 fatalx("data size mismatch");
482 memcpy(&ps, imsg.data, sizeof(ps));
483 if (ps.path[sizeof(ps.path) - 1] != '\0')
484 fatalx("received corrupted data");
486 if (ps.status == STATE_STOPPED)
487 printf("stopped ");
488 else if (ps.status == STATE_PLAYING)
489 printf("playing ");
490 else if (ps.status == STATE_PAUSED)
491 printf("paused ");
492 else
493 printf("unknown ");
495 puts(ps.path);
497 print_time("position", ps.position);
498 print_time("duration", ps.duration);
500 printf("repeat one %s\nrepeat all %s\n",
501 ps.rp.repeat_one ? "on" : "off",
502 ps.rp.repeat_all ? "on" : "off");
504 done = 1;
505 break;
506 case LOAD:
507 if (imsg.hdr.type == IMSG_CTL_ADD)
508 break;
509 if (imsg.hdr.type == IMSG_CTL_COMMIT) {
510 done = 1;
511 break;
514 if (imsg.hdr.type != IMSG_CTL_BEGIN)
515 fatalx("invalid message %d",
516 imsg.hdr.type);
518 load_files(res, &ret);
519 break;
520 case MONITOR:
521 if (imsg.hdr.type != IMSG_CTL_MONITOR)
522 fatalx("invalid message %d",
523 imsg.hdr.type);
525 if (datalen != sizeof(type))
526 fatalx("data size mismatch");
528 memcpy(&type, imsg.data, sizeof(type));
529 if (type < 0 || type > IMSG__LAST)
530 fatalx("received corrupted data");
532 if (!res->monitor[type])
533 break;
535 puts(imsg_name(type));
536 fflush(stdout);
537 break;
538 default:
539 done = 1;
540 break;
543 imsg_free(&imsg);
547 end:
548 return ret;
551 static int
552 ctl_noarg(struct parse_result *res, int argc, char **argv)
554 int ch;
556 while ((ch = getopt(argc, argv, "")) != -1)
557 ctl_usage(res->ctl);
558 argc -= optind;
559 argv += optind;
561 if (argc > 0)
562 ctl_usage(res->ctl);
564 return ctlaction(res);
567 static int
568 ctl_add(struct parse_result *res, int argc, char **argv)
570 int ch;
572 while ((ch = getopt(argc, argv, "")) != -1)
573 ctl_usage(res->ctl);
574 argc -= optind;
575 argv += optind;
577 if (argc == 0)
578 ctl_usage(res->ctl);
579 res->files = argv;
581 return ctlaction(res);
584 static int
585 ctl_show(struct parse_result *res, int argc, char **argv)
587 int ch;
589 while ((ch = getopt(argc, argv, "p")) != -1) {
590 switch (ch) {
591 case 'p':
592 res->pretty = 1;
593 break;
594 default:
595 ctl_usage(res->ctl);
599 return ctlaction(res);
602 static int
603 ctl_load(struct parse_result *res, int argc, char **argv)
605 int ch;
607 while ((ch = getopt(argc, argv, "")) != -1)
608 ctl_usage(res->ctl);
609 argc -= optind;
610 argv += optind;
612 if (argc == 0)
613 res->file = NULL;
614 else if (argc == 1)
615 res->file = argv[0];
616 else
617 ctl_usage(res->ctl);
619 if (pledge("stdio rpath", NULL) == -1)
620 fatal("pledge");
622 return ctlaction(res);
625 static int
626 ctl_jump(struct parse_result *res, int argc, char **argv)
628 int ch;
630 while ((ch = getopt(argc, argv, "")) != -1)
631 ctl_usage(res->ctl);
632 argc -= optind;
633 argv += optind;
635 if (argc != 1)
636 ctl_usage(res->ctl);
638 res->file = argv[0];
639 return ctlaction(res);
642 static int
643 ctl_repeat(struct parse_result *res, int argc, char **argv)
645 int ch, b;
647 while ((ch = getopt(argc, argv, "")) != -1)
648 ctl_usage(res->ctl);
649 argc -= optind;
650 argv += optind;
652 if (argc != 2)
653 ctl_usage(res->ctl);
655 if (!strcmp(argv[1], "on"))
656 b = 1;
657 else if (!strcmp(argv[1], "off"))
658 b = 0;
659 else
660 ctl_usage(res->ctl);
662 res->rep.repeat_one = -1;
663 res->rep.repeat_all = -1;
664 if (!strcmp(argv[0], "one"))
665 res->rep.repeat_one = b;
666 else if (!strcmp(argv[0], "all"))
667 res->rep.repeat_all = b;
668 else
669 ctl_usage(res->ctl);
671 return ctlaction(res);
674 static int
675 ctl_monitor(struct parse_result *res, int argc, char **argv)
677 int ch;
678 const char *events;
679 char *dup, *tmp, *tok;
681 while ((ch = getopt(argc, argv, "")) != -1)
682 ctl_usage(res->ctl);
683 argc -= optind;
684 argv += optind;
686 if (argc > 1)
687 ctl_usage(res->ctl);
689 if (argc == 1)
690 events = *argv;
691 else
692 events = "play,toggle,pause,stop,restart,flush,next,prev,"
693 "jump,repeat,add,load";
695 tmp = dup = xstrdup(events);
696 while ((tok = strsep(&tmp, ",")) != NULL) {
697 if (*tok == '\0')
698 continue;
700 if (!strcmp(tok, "play"))
701 res->monitor[IMSG_CTL_PLAY] = 1;
702 else if (!strcmp(tok, "toggle"))
703 res->monitor[IMSG_CTL_TOGGLE_PLAY] = 1;
704 else if (!strcmp(tok, "pause"))
705 res->monitor[IMSG_CTL_PAUSE] = 1;
706 else if (!strcmp(tok, "stop"))
707 res->monitor[IMSG_CTL_STOP] = 1;
708 else if (!strcmp(tok, "restart"))
709 res->monitor[IMSG_CTL_RESTART] = 1;
710 else if (!strcmp(tok, "flush"))
711 res->monitor[IMSG_CTL_FLUSH] = 1;
712 else if (!strcmp(tok, "next"))
713 res->monitor[IMSG_CTL_NEXT] = 1;
714 else if (!strcmp(tok, "prev"))
715 res->monitor[IMSG_CTL_PREV] = 1;
716 else if (!strcmp(tok, "jump"))
717 res->monitor[IMSG_CTL_JUMP] = 1;
718 else if (!strcmp(tok, "repeat"))
719 res->monitor[IMSG_CTL_REPEAT] = 1;
720 else if (!strcmp(tok, "add"))
721 res->monitor[IMSG_CTL_ADD] = 1;
722 else if (!strcmp(tok, "load"))
723 res->monitor[IMSG_CTL_COMMIT] = 1;
724 else
725 fatalx("unknown event \"%s\"", tok);
728 free(dup);
729 return ctlaction(res);
732 static int
733 ctl_get_lock(const char *lockfile)
735 int lockfd;
737 if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
738 log_debug("open failed: %s", strerror(errno));
739 return -1;
742 if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
743 log_debug("flock failed: %s", strerror(errno));
744 if (errno != EAGAIN)
745 return -1;
746 while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
747 /* nop */;
748 close(lockfd);
749 return -2;
751 log_debug("flock succeeded");
753 return lockfd;
756 static int
757 ctl_connect(void)
759 struct timespec ts = { 0, 50000000 }; /* 0.05 seconds */
760 struct sockaddr_un sa;
761 size_t size;
762 int fd, lockfd = -1, locked = 0, spawned = 0;
763 int attempt = 0;
764 char *lockfile = NULL;
766 memset(&sa, 0, sizeof(sa));
767 sa.sun_family = AF_UNIX;
768 size = strlcpy(sa.sun_path, csock, sizeof(sa.sun_path));
769 if (size >= sizeof(sa.sun_path)) {
770 errno = ENAMETOOLONG;
771 return -1;
774 retry:
775 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
776 return -1;
778 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
779 log_debug("connection failed: %s", strerror(errno));
780 if (errno != ECONNREFUSED && errno != ENOENT)
781 goto failed;
782 if (attempt++ == 100)
783 goto failed;
784 close(fd);
786 if (!locked) {
787 xasprintf(&lockfile, "%s.lock", csock);
788 if ((lockfd = ctl_get_lock(lockfile)) < 0) {
789 log_debug("didn't get the lock (%d)", lockfd);
791 free(lockfile);
792 lockfile = NULL;
794 if (lockfd == -1)
795 goto retry;
798 /*
799 * Always retry at least once, even if we got
800 * the lock, because another client could have
801 * taken the lock, started the server and released
802 * the lock between our connect() and flock()
803 */
804 locked = 1;
805 goto retry;
808 if (!spawned) {
809 log_debug("spawning the daemon");
810 spawn_daemon();
811 spawned = 1;
814 nanosleep(&ts, NULL);
815 goto retry;
818 if (locked && lockfd >= 0) {
819 unlink(lockfile);
820 free(lockfile);
821 close(lockfd);
823 return fd;
825 failed:
826 if (locked) {
827 free(lockfile);
828 close(lockfd);
830 close(fd);
831 return -1;
834 __dead void
835 ctl(int argc, char **argv)
837 int ctl_sock;
839 log_init(1, LOG_DAEMON);
840 log_setverbose(verbose);
842 if (getcwd(cwd, sizeof(cwd)) == NULL)
843 fatal("getcwd");
845 if ((ctl_sock = ctl_connect()) == -1)
846 fatal("can't connect");
848 if (ctl_sock == -1)
849 fatalx("failed to connect to the daemon");
851 ibuf = xmalloc(sizeof(*ibuf));
852 imsg_init(ibuf, ctl_sock);
854 optreset = 1;
855 optind = 1;
857 exit(parse(argc, argv));