commit 08ff7dacd98f90282d17676773d07167056a8292
Author: sin <sin@2f30.org>
Date: Fri, 15 Nov 2013 12:11:26 +0000
Initial commit
Diffstat:
A | LICENSE | | | 21 | +++++++++++++++++++++ |
A | Makefile | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | arg.h | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | config.mk | | | 11 | +++++++++++ |
A | rs.c | | | 187 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | util.h | | | 16 | ++++++++++++++++ |
A | util/agetcwd.c | | | 18 | ++++++++++++++++++ |
A | util/apathmax.c | | | 25 | +++++++++++++++++++++++++ |
A | util/dev.c | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | util/eprintf.c | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | util/estrtol.c | | | 27 | +++++++++++++++++++++++++++ |
A | util/mkpath.c | | | 29 | +++++++++++++++++++++++++++++ |
A | util/recurse.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | util/strlcpy.c | | | 15 | +++++++++++++++ |
14 files changed, 605 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,21 @@
+MIT/X Consortium License
+
+© 2013 sin <sin@2f30.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,61 @@
+include config.mk
+
+.POSIX:
+.SUFFIXES: .c .o
+
+LIB = \
+ util/agetcwd.o \
+ util/apathmax.o \
+ util/dev.o \
+ util/eprintf.o \
+ util/estrtol.o \
+ util/mkpath.o \
+ util/recurse.o \
+ util/strlcpy.o
+
+SRC = rs.c
+
+OBJ = $(SRC:.c=.o) $(LIB)
+BIN = $(SRC:.c=)
+MAN = $(SRC:.c=.1)
+
+all: options binlib
+
+options:
+ @echo rs build options:
+ @echo "CFLAGS = $(CFLAGS)"
+ @echo "LDFLAGS = $(LDFLAGS)"
+ @echo "CC = $(CC)"
+
+binlib: util.a
+ $(MAKE) bin
+
+bin: $(BIN)
+
+$(OBJ): util.h config.mk
+
+.o:
+ @echo LD $@
+ @$(LD) -o $@ $< util.a $(LDFLAGS)
+
+.c.o:
+ @echo CC $<
+ @$(CC) -c -o $@ $< $(CFLAGS)
+
+util.a: $(LIB)
+ @echo AR $@
+ @$(AR) -r -c $@ $(LIB)
+ @ranlib $@
+
+install: all
+ @echo installing executable to $(DESTDIR)$(PREFIX)/bin
+ @cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
+ @cd $(DESTDIR)$(PREFIX)/bin && chmod 755 $(BIN)
+
+uninstall:
+ @echo removing executable from $(DESTDIR)$(PREFIX)/bin
+ @cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN)
+
+clean:
+ @echo cleaning
+ @rm -f $(BIN) $(OBJ) $(LIB) util.a
diff --git a/arg.h b/arg.h
@@ -0,0 +1,63 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef __ARG_H__
+#define __ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][1]\
+ && argv[0][0] == '-';\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM case '0':\
+ case '1':\
+ case '2':\
+ case '3':\
+ case '4':\
+ case '5':\
+ case '6':\
+ case '7':\
+ case '8':\
+ case '9'
+
+#define ARGEND }\
+ }
+
+#define ARGC() argc_
+
+#define ARGNUMF(base) (brk_ = 1, estrtol(argv[0], (base)))
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#endif
diff --git a/config.mk b/config.mk
@@ -0,0 +1,11 @@
+# rs version
+VERSION = 0.1
+
+# paths
+PREFIX = /usr/local
+
+CC = cc
+LD = $(CC)
+CPPFLAGS = -D_BSD_SOURCE -D_GNU_SOURCE
+CFLAGS = -g -std=c99 -Wall $(CPPFLAGS)
+LDFLAGS = -g -lftdi
diff --git a/rs.c b/rs.c
@@ -0,0 +1,187 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ftdi.h>
+#include <libusb-1.0/libusb.h>
+#include "util.h"
+
+static struct ftdi_context ftdictx;
+static struct ftdi_device_list *devlist;
+static struct termios tio, saved_tio;
+
+static int bflag = 0;
+static int lflag = 0;
+static int dflag = 0;
+static int vflag = 0;
+static int pflag = 0;
+
+static sig_atomic_t done = 0;
+
+static void
+interrupt(int sig)
+{
+ done = 1;
+}
+
+static int
+ttyinit(void)
+{
+ tcgetattr(STDIN_FILENO, &tio);
+ memcpy(&saved_tio, &tio, sizeof(struct termios));
+ cfmakeraw(&tio);
+ tio.c_cc[VMIN] = 0;
+ tio.c_cc[VTIME] = 0;
+ tio.c_lflag |= ISIG;
+ tio.c_cc[VQUIT] = CTRL('\\');
+ tio.c_cc[VINTR] = 0;
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
+ return 0;
+}
+
+static void
+ttyrestore(void)
+{
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tio);
+ putchar('\n');
+}
+
+static int
+loop(void)
+{
+ unsigned char buf[BUFSIZ];
+ ssize_t n = 0;
+
+ while (!done) {
+ n = read(STDIN_FILENO, buf, sizeof(buf));
+ if (n > 0)
+ ftdi_write_data(&ftdictx, buf, n);
+ n = ftdi_read_data(&ftdictx, buf, sizeof(buf));
+ if (n < 0) {
+ fprintf(stderr, "read error %d (%s)\n",
+ (int)n, ftdi_get_error_string(&ftdictx));
+ break;
+ }
+ write(STDOUT_FILENO, buf, n);
+ }
+ return n;
+}
+
+static void
+listdevs(void)
+{
+ char manufacturer[256];
+ char description[256];
+ struct ftdi_device_list *iter;
+ int i;
+ int ret;
+
+ for (i = 0, iter = devlist; iter; iter = iter->next, i++) {
+ ret = ftdi_usb_get_strings(&ftdictx, iter->dev,
+ manufacturer, sizeof(manufacturer),
+ description, sizeof(description), NULL, 0);
+ if (ret < 0) {
+ fprintf(stderr, "ftdi_usb_get_strings: %s\n",
+ ftdi_get_error_string(&ftdictx));
+ exit(EXIT_FAILURE);
+ }
+ printf("device %d: manufacturer: %s, description: %s, vendor = %04x, product = %04x\n",
+ i, manufacturer, description, iter->dev->descriptor.idVendor,
+ iter->dev->descriptor.idProduct);
+ }
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-l] [-b baudrate] [-v vendor] [-p product] [-d device]\n", argv0);
+ fprintf(stderr, "\t-l\tList devices\n");
+ fprintf(stderr, "\t-b\tSet baudrate\n");
+ fprintf(stderr, "\t-v\tSpecify vendor, defaults to 0x0403\n");
+ fprintf(stderr, "\t-p\tSpecify product, defaults to 0x6001\n");
+ fprintf(stderr, "\n\tNOTE: The break key is set to ^\\\n");
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int baudrate = 115200;
+ int dev = 0;
+ int ret;
+ struct ftdi_device_list *iter;
+ int vendor = 0x0403;
+ int product = 0x6001;
+
+ ARGBEGIN {
+ case 'l':
+ lflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ baudrate = estrtol(EARGF(usage()), 10);
+ break;
+ case 'd':
+ dflag = 1;
+ dev = estrtol(EARGF(usage()), 10);
+ break;
+ case 'v':
+ vflag = 1;
+ vendor = estrtol(EARGF(usage()), 0);
+ break;
+ case 'p':
+ pflag = 1;
+ product = estrtol(EARGF(usage()), 0);
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ ftdi_init(&ftdictx);
+ ftdi_set_interface(&ftdictx, INTERFACE_ANY);
+
+ ret = ftdi_usb_find_all(&ftdictx, &devlist, vendor, product);
+ if (ret < 0) {
+ fprintf(stderr, "ftdi_usb_find_all: %s\n",
+ ftdi_get_error_string(&ftdictx));
+ exit(EXIT_FAILURE);
+ }
+
+ if (lflag) {
+ listdevs();
+ exit(EXIT_SUCCESS);
+ }
+
+ if (dflag) {
+ for (i = 0, iter = devlist; iter; iter = iter->next, i++) {
+ if (i == dev) {
+ vendor = iter->dev->descriptor.idVendor;
+ product = iter->dev->descriptor.idProduct;
+ break;
+ }
+ }
+ if (!iter) {
+ fprintf(stderr, "Can't find device %d\n", dev);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (ftdi_usb_open(&ftdictx, vendor, product) < 0) {
+ fprintf(stderr, "ftdi_usb_open: %s\n",
+ ftdi_get_error_string(&ftdictx));
+ exit(EXIT_FAILURE);
+ }
+ ftdi_set_baudrate(&ftdictx, baudrate);
+
+ ttyinit();
+ signal(SIGINT, interrupt);
+ signal(SIGQUIT, interrupt);
+ loop();
+ ttyrestore();
+ exit(EXIT_SUCCESS);
+}
diff --git a/util.h b/util.h
@@ -0,0 +1,16 @@
+/* See LICENSE file for copyright and license details. */
+#include "arg.h"
+
+#define LEN(x) (sizeof (x) / sizeof *(x))
+
+extern char *argv0;
+
+char *agetcwd(void);
+void apathmax(char **, long *);
+int devtomajmin(const char *path, int *maj, int *min);
+int devtype(const char *majmin);
+void enprintf(int, const char *, ...);
+void eprintf(const char *, ...);
+long estrtol(const char *, int);
+void recurse(const char *, void (*)(const char *));
+size_t strlcpy(char *dest, const char *src, size_t size);
diff --git a/util/agetcwd.c b/util/agetcwd.c
@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include <unistd.h>
+
+#include "../util.h"
+
+char *
+agetcwd(void)
+{
+ char *buf;
+ long size;
+
+ apathmax(&buf, &size);
+ if(!getcwd(buf, size))
+ eprintf("getcwd:");
+
+ return buf;
+}
+
diff --git a/util/apathmax.c b/util/apathmax.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "../util.h"
+
+void
+apathmax(char **p, long *size)
+{
+ errno = 0;
+
+ if((*size = pathconf("/", _PC_PATH_MAX)) == -1) {
+ if(errno == 0) {
+ *size = BUFSIZ;
+ } else {
+ eprintf("pathconf:");
+ }
+ }
+
+ if(!(*p = malloc(*size)))
+ eprintf("malloc:");
+}
+
diff --git a/util/dev.c b/util/dev.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+#include "../util.h"
+
+/* Example `path' is /sys/devices/virtual/tty/tty0/dev */
+int
+devtomajmin(const char *path, int *maj, int *min)
+{
+ char buf[BUFSIZ];
+ int fd;
+ ssize_t n;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ eprintf("open %s:", path);
+ n = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (n < 0)
+ eprintf("%s: read error:", path);
+ if (!n)
+ return -1;
+ if (buf[n - 1] == '\n')
+ buf[n - 1] = '\0';
+ buf[n] = '\0';
+ sscanf(buf, "%d:%d", maj, min);
+ return 0;
+}
+
+/* `majmin' format is maj:min */
+int
+devtype(const char *majmin)
+{
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "/sys/dev/block/%s", majmin);
+ if (!access(path, F_OK))
+ return S_IFBLK;
+ snprintf(path, sizeof(path), "/sys/dev/char/%s", majmin);
+ if (!access(path, F_OK))
+ return S_IFCHR;
+ return -1;
+}
diff --git a/util/eprintf.c b/util/eprintf.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../util.h"
+
+char *argv0;
+
+static void venprintf(int, const char *, va_list);
+
+void
+eprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ venprintf(EXIT_FAILURE, fmt, ap);
+ va_end(ap);
+}
+
+void
+enprintf(int status, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ venprintf(status, fmt, ap);
+ va_end(ap);
+}
+
+void
+venprintf(int status, const char *fmt, va_list ap)
+{
+ /*fprintf(stderr, "%s: ", argv0);*/
+
+ vfprintf(stderr, fmt, ap);
+
+ if(fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ }
+
+ exit(status);
+}
diff --git a/util/estrtol.c b/util/estrtol.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../util.h"
+
+long
+estrtol(const char *s, int base)
+{
+ char *end;
+ long n;
+
+ errno = 0;
+ n = strtol(s, &end, base);
+ if(*end != '\0') {
+ if(base == 0)
+ eprintf("%s: not an integer\n", s);
+ else
+ eprintf("%s: not a base %d integer\n", s, base);
+ }
+ if(errno != 0)
+ eprintf("%s:", s);
+
+ return n;
+}
+
diff --git a/util/mkpath.c b/util/mkpath.c
@@ -0,0 +1,29 @@
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+int
+mkpath(const char *path, mode_t mode)
+{
+ char tmp[PATH_MAX];
+ char *p = NULL;
+ size_t len;
+
+ snprintf(tmp, sizeof(tmp),"%s",path);
+ len = strlen(tmp);
+ if(tmp[len - 1] == '/')
+ tmp[len - 1] = 0;
+ for(p = tmp + 1; *p; p++)
+ if(*p == '/') {
+ *p = 0;
+ if (mkdir(tmp, mode) < 0 && errno != EEXIST)
+ return -1;
+ *p = '/';
+ }
+ if (mkdir(tmp, mode) < 0 && errno != EEXIST)
+ return -1;
+ return 0;
+}
+
diff --git a/util/recurse.c b/util/recurse.c
@@ -0,0 +1,40 @@
+/* See LICENSE file for copyright and license details. */
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "../util.h"
+
+void
+recurse(const char *path, void (*fn)(const char *))
+{
+ char *cwd;
+ struct dirent *d;
+ struct stat st;
+ DIR *dp;
+
+ if(lstat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
+ return;
+ } else if(!(dp = opendir(path))) {
+ eprintf("opendir %s:", path);
+ }
+
+ cwd = agetcwd();
+ if(chdir(path) == -1)
+ eprintf("chdir %s:", path);
+
+ while((d = readdir(dp))) {
+ if(strcmp(d->d_name, ".") && strcmp(d->d_name, ".."))
+ fn(d->d_name);
+ }
+
+ closedir(dp);
+ if(chdir(cwd) == -1)
+ eprintf("chdir %s:", cwd);
+
+ free(cwd);
+}
+
diff --git a/util/strlcpy.c b/util/strlcpy.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <string.h>
+
+size_t
+strlcpy(char *dest, const char *src, size_t size)
+{
+ size_t ret = strlen(src);
+
+ if (size) {
+ size_t len = (ret >= size) ? size - 1 : ret;
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ }
+ return ret;
+}