2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/socket.h>
33 #include <readline/readline.h>
34 #include <readline/history.h>
38 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
52 struct tls_config *tlsconf;
56 struct evbuffer *dirbuf;
62 #define ASSERT_EMPTYBUF() assert(EVBUFFER_LENGTH(buf) == 0)
66 read_line(const char *prompt)
71 if ((line = readline(prompt)) == NULL)
73 /* XXX: trim spaces? */
84 read_line(const char *prompt)
86 char *ch, *line = NULL;
93 linelen = getline(&line, &linesize, stdin);
97 if ((ch = strchr(line, '\n')) != NULL)
106 fprintf(stderr, "usage: %s [-c] host[:port] [path]\n",
108 fprintf(stderr, PACKAGE_NAME " suite version " PACKAGE VERSION "\n");
117 while (EVBUFFER_LENGTH(evb) != 0) {
118 r = tls_write(ctx, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
120 case TLS_WANT_POLLIN:
121 case TLS_WANT_POLLOUT:
124 errx(1, "tls: %s", tls_error(ctx));
126 evbuffer_drain(evb, r);
132 mustread(void *d, size_t len)
137 switch (r = tls_read(ctx, d, len)) {
138 case TLS_WANT_POLLIN:
139 case TLS_WANT_POLLOUT:
142 errx(1, "tls: %s", tls_error(ctx));
157 mustread(&len, sizeof(len));
159 if (len < HEADERSIZE)
160 errx(1, "read message of invalid length %d", len);
162 len -= 4; /* skip the length just read */
165 switch (r = tls_read(ctx, tmp, sizeof(tmp))) {
166 case TLS_WANT_POLLIN:
167 case TLS_WANT_POLLOUT:
170 errx(1, "tls: %s", tls_error(ctx));
173 evbuffer_add(buf, tmp, r);
179 np_read64(struct evbuffer *buf)
183 evbuffer_remove(buf, &n, sizeof(n));
188 np_read32(struct evbuffer *buf)
192 evbuffer_remove(buf, &n, sizeof(n));
197 np_read16(struct evbuffer *buf)
201 evbuffer_remove(buf, &n, sizeof(n));
206 np_read8(struct evbuffer *buf)
210 evbuffer_remove(buf, &n, sizeof(n));
215 np_readstr(struct evbuffer *buf)
220 len = np_read16(buf);
221 assert(EVBUFFER_LENGTH(buf) >= len);
223 if ((str = calloc(1, len+1)) == NULL)
225 evbuffer_remove(buf, str, len);
230 np_read_qid(struct evbuffer *buf, struct qid *qid)
232 assert(EVBUFFER_LENGTH(buf) >= QIDSIZE);
234 qid->type = np_read8(buf);
235 qid->vers = np_read32(buf);
236 qid->path = np_read64(buf);
251 err = np_readstr(buf);
252 errx(1, "expected %s, got error %s",
253 pp_msg_type(type), err);
256 errx(1, "expected %s, got msg type %s",
257 pp_msg_type(type), pp_msg_type(t));
261 expect2(uint8_t type, uint16_t tag)
271 errx(1, "expected tag 0x%x, got 0x%x", tag, t);
279 tversion(VERSION9P, MSIZE9P);
282 expect2(Rversion, NOTAG);
284 msize = np_read32(buf);
285 version = np_readstr(buf);
288 errx(1, "got unexpected msize: %d", msize);
289 if (strcmp(version, VERSION9P))
290 errx(1, "unexpected 9p version: %s", version);
297 do_attach(const char *path)
304 if ((user = getenv("USER")) == NULL)
307 tattach(PWDFID, NOFID, user, path);
310 expect2(Rattach, iota_tag);
311 np_read_qid(buf, &qid);
317 do_open(uint32_t fid, uint8_t mode)
325 expect2(Ropen, iota_tag);
327 np_read_qid(buf, &qid);
328 iounit = np_read32(buf);
336 do_clunk(uint32_t fid)
341 expect2(Rclunk, iota_tag);
347 dup_fid(int fid, int nfid)
351 twalk(fid, nfid, NULL, 0);
354 expect2(Rwalk, iota_tag);
356 nwqid = np_read16(buf);
363 do_connect(const char *connspec, const char *path)
369 host = xstrdup(connspec);
370 if ((colon = strchr(host, ':')) != NULL) {
377 fatalx("non-tls mode is not supported");
379 if ((tlsconf = tls_config_new()) == NULL)
380 fatalx("tls_config_new");
381 tls_config_insecure_noverifycert(tlsconf);
382 tls_config_insecure_noverifyname(tlsconf);
383 if (tls_config_set_keypair_file(tlsconf, crtpath, keypath) == -1)
384 fatalx("can't load certs (%s, %s)", crtpath, keypath);
386 if ((ctx = tls_client()) == NULL)
388 if (tls_configure(ctx, tlsconf) == -1)
389 fatalx("tls_configure: %s", tls_error(ctx));
391 printf("connecting to %s:%s...", host, port);
394 if (tls_connect(ctx, host, port) == -1)
395 fatalx("can't connect to %s:%s: %s", host, port,
398 for (handshake = 0; !handshake;) {
399 switch (tls_handshake(ctx)) {
401 fatalx("tls_handshake: %s", tls_error(ctx));
417 cmd_bell(int argc, const char **argv)
422 puts("bell mode enabled");
424 puts("bell mode disabled");
431 if (!strcmp(*argv, "on")) {
433 puts("bell mode enabled");
437 if (!strcmp(*argv, "off")) {
439 puts("bell mode disabled");
444 printf("bell [on | off]\n");
448 cmd_bye(int argc, const char **argv)
455 cmd_ls(int argc, const char **argv)
461 printf("ls don't take arguments (yet)\n");
468 evbuffer_drain(dirbuf, EVBUFFER_LENGTH(dirbuf));
471 tread(1, off, BUFSIZ);
474 expect2(Rread, iota_tag);
476 len = np_read32(buf);
480 evbuffer_add_buffer(dirbuf, buf);
486 while (EVBUFFER_LENGTH(dirbuf) != 0) {
492 size = np_read16(dirbuf);
493 assert(size <= EVBUFFER_LENGTH(dirbuf));
495 np_read16(dirbuf); /* skip type */
496 np_read32(dirbuf); /* skip dev */
498 np_read_qid(dirbuf, &qid);
499 printf("%s ", pp_qid_type(qid.type));
501 np_read32(dirbuf); /* skip mode */
502 np_read32(dirbuf); /* skip atime */
503 np_read32(dirbuf); /* skip mtime */
505 len = np_read64(dirbuf);
506 printf("%llu ", (unsigned long long)len);
508 name = np_readstr(dirbuf);
509 printf("%s\n", name);
512 free(np_readstr(dirbuf)); /* skip uid */
513 free(np_readstr(dirbuf)); /* skip gid */
514 free(np_readstr(dirbuf)); /* skip muid */
521 cmd_verbose(int argc, const char **argv)
524 log_setverbose(!log_getverbose());
525 if (log_getverbose())
526 puts("verbose mode enabled");
528 puts("verbose mode disabled");
535 if (!strcmp(*argv, "on")) {
537 puts("verbose mode enabled");
541 if (!strcmp(*argv, "off")) {
543 puts("verbose mode disabled");
548 printf("verbose [on | off]\n");
552 excmd(int argc, const char **argv)
556 void (*fn)(int, const char **);
562 {"verbose", cmd_verbose},
568 for (i = 0; i < nitems(cmds); ++i) {
569 if (!strcmp(cmds[i].name, *argv)) {
570 cmds[i].fn(argc-1, argv+1);
575 log_warnx("unknown command %s", *argv);
579 main(int argc, char **argv)
583 log_init(1, LOG_DAEMON);
585 log_procinit(getprogname());
587 while ((ch = getopt(argc, argv, "C:cK:")) != -1) {
608 if ((evb = evbuffer_new()) == NULL)
609 fatal("evbuffer_new");
611 if ((buf = evbuffer_new()) == NULL)
612 fatal("evbuffer_new");
614 if ((dirbuf = evbuffer_new()) == NULL)
615 fatal("evbuferr_new");
617 do_connect(argv[0], argv[1]);
619 /* cmd_ls(0, NULL); */
623 char *line, *argv[16] = {0}, **ap;
625 if ((line = read_line("kamiftp> ")) == NULL)
628 for (argc = 0, ap = argv; ap < &argv[15] &&
629 (*ap = strsep(&line, " \t")) != NULL;) {
633 excmd(argc, (const char **)argv);