1 /* $NetBSD: utoppya.c,v 1.3 2008/04/28 20:24:15 martin Exp $ */
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
34 #include <sys/ioctl.h>
48 #include <dev/usb/utoppy.h>
51 #include "progressbar.h"
53 #define _PATH_DEV_UTOPPY "/dev/utoppy0"
56 * This looks weird for a reason. The toppy protocol allows for data to be
57 * transferred in 65535-byte chunks only. Anything more than this has to be
58 * split within the driver. The following value leaves enough space for the
59 * packet header plus some alignmnent slop.
61 #define TOPPY_IO_SIZE 0xffec
65 static void cmd_df(int, char **);
66 static void cmd_ls(int, char **);
67 static void cmd_rm(int, char **);
68 static void cmd_mkdir(int, char **);
69 static void cmd_rename(int, char **);
70 static void cmd_get(int, char **);
71 static void cmd_put(int, char **);
73 static struct toppy_command
{
75 void (*tc_handler
)(int, char **);
76 } toppy_commands
[] = {
82 {"rename", cmd_rename
},
91 fprintf(stderr
, "usage: %s [-f <path>] <cmd> ...\n",
98 main(int argc
, char *argv
[])
100 struct toppy_command
*tc
;
104 setprogname(argv
[0]);
105 devpath
= _PATH_DEV_UTOPPY
;
107 while ((ch
= getopt(argc
, argv
, "f:")) != -1) {
123 for (tc
= toppy_commands
; tc
->tc_cmd
!= NULL
; tc
++)
124 if (strcasecmp(argv
[0], tc
->tc_cmd
) == 0)
127 if (tc
->tc_cmd
== NULL
)
128 errx(EX_USAGE
, "'%s' is not a valid command", argv
[0]);
130 if ((toppy_fd
= open(devpath
, O_RDWR
)) < 0)
131 err(EX_OSERR
, "open(%s)", devpath
);
133 (*tc
->tc_handler
)(argc
, argv
);
141 find_toppy_dirent(const char *path
, struct utoppy_dirent
*udp
)
143 struct utoppy_dirent ud
;
144 char *d
, *b
, dir
[FILENAME_MAX
];
147 strncpy(dir
, path
, sizeof(dir
));
150 if (strcmp(b
, "/") == 0 || strcmp(b
, ".") == 0 || strcmp(d
, ".") == 0)
151 errx(EX_USAGE
, "'%s' is not a valid Toppy pathname", path
);
153 if (ioctl(toppy_fd
, UTOPPYIOREADDIR
, &d
) < 0)
154 err(EX_OSERR
, "ioctl(UTOPPYIOREADDIR, %s)", d
);
159 while ((l
= read(toppy_fd
, udp
, sizeof(*udp
))) == sizeof(*udp
)) {
160 if (strcmp(b
, udp
->ud_path
) == 0)
165 err(EX_OSERR
, "read(TOPPYDIR, %s)", d
);
170 while (read(toppy_fd
, &ud
, sizeof(ud
)) > 0)
177 cmd_df(int argc
, char **argv
)
179 struct utoppy_stats us
;
181 if (ioctl(toppy_fd
, UTOPPYIOSTATS
, &us
) < 0)
182 err(EX_OSERR
, "ioctl(UTOPPYIOSTATS)");
184 printf("Hard Disk Size: %" PRId64
" MB\n", us
.us_hdd_size
/ (1024 * 1024));
185 printf("Hard Disk Free: %" PRId64
" MB\n", us
.us_hdd_free
/ (1024 * 1024));
189 cmd_ls(int argc
, char **argv
)
191 struct utoppy_dirent ud
;
193 char *dir
, *ext
, dirbuf
[2], ex
, ft
, tmbuf
[32];
204 errx(EX_USAGE
, "usage: ls [toppy-pathname]");
206 if (ioctl(toppy_fd
, UTOPPYIOREADDIR
, &dir
) < 0)
207 err(EX_OSERR
, "ioctl(UTOPPYIOREADDIR, %s)", dir
);
209 while ((l
= read(toppy_fd
, &ud
, sizeof(ud
))) == sizeof(ud
)) {
210 switch (ud
.ud_type
) {
215 case UTOPPY_DIRENT_DIRECTORY
:
219 case UTOPPY_DIRENT_FILE
:
224 if ((ext
= strrchr(ud
.ud_path
, '.')) != NULL
&&
225 strcasecmp(ext
, ".tap") == 0)
230 tm
= localtime(&ud
.ud_mtime
);
231 strftime(tmbuf
, sizeof(tmbuf
), "%b %e %G %R", tm
);
233 printf("%crw%c %11lld %s %s\n", ft
, ex
, (long long)ud
.ud_size
,
238 err(EX_OSERR
, "read(utoppy_dirent)");
242 cmd_rm(int argc
, char **argv
)
247 errx(EX_USAGE
, "usage: rm <toppy-pathname>");
251 if (ioctl(toppy_fd
, UTOPPYIODELETE
, &path
) < 0)
252 err(EX_OSERR
, "ioctl(UTOPPYIODELETE, %s)", path
);
256 cmd_mkdir(int argc
, char **argv
)
261 errx(EX_USAGE
, "usage: mkdir <toppy-pathname>");
265 if (find_toppy_dirent(path
, NULL
))
266 errx(EX_DATAERR
, "'%s' already exists", path
);
268 if (ioctl(toppy_fd
, UTOPPYIOMKDIR
, &path
) < 0)
269 err(EX_OSERR
, "ioctl(UTOPPYIOMKDIR, %s)", path
);
273 cmd_rename(int argc
, char **argv
)
275 struct utoppy_dirent ud
;
276 struct utoppy_rename ur
;
277 char *oldpath
, *newpath
, *o
, *n
;
280 errx(EX_USAGE
, "usage: rename <from> <to>");
282 o
= oldpath
= argv
[1];
283 n
= newpath
= argv
[2];
285 for (o
= oldpath
; *o
!= '\0'; o
++)
288 for (n
= newpath
; *n
!= '\0'; n
++)
292 for (o
= oldpath
; *o
&& *o
== '\\'; o
++)
294 for (n
= newpath
; *n
&& *n
== '\\'; n
++)
297 if (strcmp(n
, o
) == 0)
298 errx(EX_DATAERR
, "'%s' and '%s' refer to the same file\n",
301 if (find_toppy_dirent(oldpath
, &ud
) == 0)
302 errx(EX_DATAERR
, "'%s' does not exist on the Toppy", oldpath
);
304 if (ud
.ud_type
!= UTOPPY_DIRENT_FILE
)
305 errx(EX_DATAERR
, "%s: not a regular file", oldpath
);
307 if (find_toppy_dirent(newpath
, &ud
))
308 errx(EX_DATAERR
, "'%s' already exists", newpath
);
313 if (ioctl(toppy_fd
, UTOPPYIORENAME
, &ur
) < 0)
314 err(EX_OSERR
, "ioctl(UTOPPYIORENAME, %s, %s)", oldpath
,
320 init_progress(FILE *to
, char *f
, off_t fsize
, off_t restart
)
324 if (ioctl(fileno(to
), TIOCGSIZE
, &ts
) == -1)
327 ttywidth
= ts
.ts_cols
;
333 restart_point
= restart
;
338 cmd_get(int argc
, char **argv
)
340 struct utoppy_readfile ur
;
341 struct utoppy_dirent ud
;
343 char *dst
, dstbuf
[FILENAME_MAX
];
347 int ch
, turbo_mode
= 0, reget
= 0, progbar
= 0;
353 while ((ch
= getopt(argc
, argv
, "prt")) != -1) {
366 errx(EX_USAGE
, "usage: get [-prt] <toppy-pathname> "
367 "[file | directory]");
374 dst
= basename(argv
[0]);
378 if (stat(dst
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
379 snprintf(dstbuf
, sizeof(dstbuf
), "%s/%s", dst
,
386 ur
.ur_path
= argv
[0];
389 if ((buf
= malloc(TOPPY_IO_SIZE
)) == NULL
)
390 err(EX_OSERR
, "malloc(TOPPY_IO_SIZE)");
392 if (strcmp(dst
, "-") == 0) {
396 warnx("Ignoring -r option in combination with stdout");
401 if (stat(dst
, &st
) < 0) {
403 err(EX_OSERR
, "stat(%s)", dst
);
405 if (!S_ISREG(st
.st_mode
))
406 errx(EX_DATAERR
, "-r only works with regular "
409 ur
.ur_offset
= st
.st_size
;
412 if ((ofp
= fopen(dst
, reget
? "a" : "w")) == NULL
)
413 err(EX_OSERR
, "fopen(%s)", dst
);
417 if (find_toppy_dirent(ur
.ur_path
, &ud
) == 0)
419 init_progress(to
, dst
, ud
.ud_size
, ur
.ur_offset
);
422 if (ioctl(toppy_fd
, UTOPPYIOTURBO
, &turbo_mode
) < 0)
423 err(EX_OSERR
, "ioctl(UTOPPYIOTURBO, %d)", turbo_mode
);
425 if (ioctl(toppy_fd
, UTOPPYIOREADFILE
, &ur
) < 0)
426 err(EX_OSERR
, "ioctl(UTOPPYIOREADFILE, %s)", ur
.ur_path
);
432 while ((l
= read(toppy_fd
, buf
, TOPPY_IO_SIZE
)) < 0 &&
439 rv
= fwrite(buf
, 1, l
, ofp
);
441 if (rv
!= (size_t)l
) {
445 err(EX_OSERR
, "fwrite(%s)", dst
);
457 err(EX_OSERR
, "read(TOPPY: ur.ur_path)");
463 cmd_put(int argc
, char **argv
)
465 struct utoppy_writefile uw
;
466 struct utoppy_dirent ud
;
468 char dstbuf
[FILENAME_MAX
];
473 int ch
, turbo_mode
= 0, reput
= 0, progbar
= 0;
479 while ((ch
= getopt(argc
, argv
, "prt")) != -1) {
492 errx(EX_USAGE
, "usage: put [-prt] <local-pathname> "
503 uw
.uw_path
= argv
[1];
505 if (stat(src
, &st
) < 0)
506 err(EX_OSERR
, "%s", src
);
508 if (!S_ISREG(st
.st_mode
))
509 errx(EX_DATAERR
, "'%s' is not a regular file", src
);
511 uw
.uw_size
= st
.st_size
;
512 uw
.uw_mtime
= st
.st_mtime
;
515 if (find_toppy_dirent(uw
.uw_path
, &ud
)) {
516 if (ud
.ud_type
== UTOPPY_DIRENT_DIRECTORY
) {
517 snprintf(dstbuf
, sizeof(dstbuf
), "%s/%s", uw
.uw_path
,
521 if (ud
.ud_type
!= UTOPPY_DIRENT_FILE
)
522 errx(EX_DATAERR
, "'%s' is not a regular file.",
526 if (ud
.ud_size
> uw
.uw_size
)
527 errx(EX_DATAERR
, "'%s' is already larger than "
528 "'%s'", uw
.uw_path
, src
);
530 uw
.uw_size
-= ud
.ud_size
;
531 uw
.uw_offset
= ud
.ud_size
;
535 if ((buf
= malloc(TOPPY_IO_SIZE
)) == NULL
)
536 err(EX_OSERR
, "malloc(TOPPY_IO_SIZE)");
538 if ((ifp
= fopen(src
, "r")) == NULL
)
539 err(EX_OSERR
, "fopen(%s)", src
);
541 if (ioctl(toppy_fd
, UTOPPYIOTURBO
, &turbo_mode
) < 0)
542 err(EX_OSERR
, "ioctl(UTOPPYIOTURBO, %d)", turbo_mode
);
544 if (ioctl(toppy_fd
, UTOPPYIOWRITEFILE
, &uw
) < 0)
545 err(EX_OSERR
, "ioctl(UTOPPYIOWRITEFILE, %s)", uw
.uw_path
);
548 init_progress(stdout
, src
, st
.st_size
, uw
.uw_offset
);
553 while ((l
= fread(buf
, 1, TOPPY_IO_SIZE
, ifp
)) > 0) {
554 rv
= write(toppy_fd
, buf
, l
);
555 if ((size_t)rv
!= l
) {
559 err(EX_OSERR
, "write(TOPPY: %s)", uw
.uw_path
);
568 err(EX_OSERR
, "fread(%s)", src
);