From 2187fc7c62ffad7cb514d061899d57cfd95438dc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Jan 2004 21:51:32 +0000 Subject: Add UUCP locking Add documentation git-svn-id: file:///home/lennart/svn/public/bidilink/trunk@7 9cde1c1d-e4d0-0310-8a68-bf217395ea82 --- Makefile.am | 4 +- configure.ac | 2 +- doc/Makefile.am | 36 +++++++++++++ doc/README.html.in | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/style.css | 32 ++++++++++++ src/client-tty.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 doc/Makefile.am create mode 100644 doc/README.html.in create mode 100644 doc/style.css diff --git a/Makefile.am b/Makefile.am index 87d73dc..dd5befa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,14 +17,14 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. EXTRA_DIST=bootstrap.sh README LICENSE -SUBDIRS=src # doc man +SUBDIRS=src doc # man MAINTAINERCLEANFILES = README noinst_DATA = README README: rm -f README -#$(MAKE) -C doc README + $(MAKE) -C doc README cd $(srcdir) && ln -s doc/README README homepage: diff --git a/configure.ac b/configure.ac index b676d4f..ad456aa 100644 --- a/configure.ac +++ b/configure.ac @@ -98,5 +98,5 @@ fi AM_CONDITIONAL([USE_XMLTOMAN], [test "x$xmltoman" = xyes]) -AC_CONFIG_FILES([src/Makefile Makefile]) # doc/Makefile man/Makefile doc/README.html]) +AC_CONFIG_FILES([src/Makefile Makefile doc/Makefile doc/README.html]) # man/Makefile ]) AC_OUTPUT diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..33b29a7 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,36 @@ +# $Id$ + +# This file is part of bidilink. +# +# bidilink is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# bidilink is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with bidilink; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +noinst_DATA = README.html README +EXTRA_DIST = $(noinst_DATA) style.css README.html.in + +MAINTAINERCLEANFILES = README README.html +CLEANFILES = + +if USE_LYNX +README: README.html + lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@ + +CLEANFILES += README +endif + +tidy: README.html + tidy -e < README.html + +.PHONY: tidy + diff --git a/doc/README.html.in b/doc/README.html.in new file mode 100644 index 0000000..f9f2cc2 --- /dev/null +++ b/doc/README.html.in @@ -0,0 +1,139 @@ + + + + + +bidilink @PACKAGE_VERSION@ + + + + +

bidilink @PACKAGE_VERSION@

+ +

Copyright 2003 Lennart Poettering <@PACKAGE_BUGREPORT@>

+ + + +

License

+ +

This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version.

+ +

This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details.

+ +

You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

+ +

News

+ +
Wed Jan 14 2004:
+ +

Version 0.1 released, initial release.

+ +

Overview

+ +

bidilink is a general purpose Unix tool for linking two +bidirectional data streams together. It extends the standard Unix +"filter" paradigma to bidrectional streams.

+ +

Status

+ +

Version @PACKAGE_VERSION@ is more or less stable. Its has the following stream drivers:

+ + + +

More drivers are planned, including:

+ + + +

Documentation

+ +

Have a look on the man page bidilink(1). (An XSLT capable browser is required)

+ +

Usage examples

+ +

Forward a serial port of another machine to a local pseudo TTY, which is compatible with pppd and minicom:

+ +
bidilink "exec:ssh OTHERMACHINE bidilink tty:/dev/ttyS0" pty:/dev/rmodem
+ +

This will create a symbolic link /dev/rmodem to the +allocated pseudo TTY device. Point your application to the device to +use the forwarded port. This requires that bidilink is +installed on both the local machine and the remote machine.

+ +

Bind a local serial port to a local TCP port:

+ +
bidilink tty:/dev/ttyS0 tcp-server:4711
+ +

Use telnet localhost 4711 to connect to the device

+ +

Bind a remote serial port to a local pseudo TTY:

+ +
bidilink pty:/dev/rmodem tcp-client:OTHERMACHINE:4711
+ +

This may be used as client to the server trick descibed above.

+ +

Open a local Unix socket (SOCK_STREAM) to the Internet:

+ +
bidilink tcp-server:4711 unix-client:/tmp/.esd/socket
+ +

Requirements

+ +

A recent Linux distribution. Probably, it is simple to port bidilink to other platforms, but this has not been done yet.

+ +

Installation

+ +

As this package is made with the GNU autotools you should run +./configure inside the distribution directory for configuring +the source tree. After that you should run make for +compilation and make install (as root) for installation of +bidilink.

+ +

Acknowledgements

+ +

None so far

+ +

Download

+ +

The newest release is always available from @PACKAGE_URL@

+ +

The current release is @PACKAGE_VERSION@

+ +

Get bidilink's development sources from the Subversion repository.

+ +
+
Lennart Poettering <@PACKAGE_BUGREPORT@>, January 2004
+ +
$Id$
+ + + diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..3605d6e --- /dev/null +++ b/doc/style.css @@ -0,0 +1,32 @@ +/* $Id$ */ + +/*** + * This file is part of bidilink. + * + * bidilink is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * bidilink is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bidilink; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + ***/ + +body { color: black; background-color: white; margin: 0.5cm; } +a:link, a:visited { color: #900000; } +p { margin-left: 0.5cm; margin-right: 0.5cm; } +div.news-date { margin-left: 0.5cm; font-size: 80%; color: #4f0000; } +p.news-text { margin-left: 1cm; } +h1 { color: #00009F; } +h2 { color: #00009F; } +h3 { color: #00004F; margin-left: 0.5cm; } +ul { margin-left: .5cm; } +ol { margin-left: .5cm; } +pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;} +.grey { color: #afafaf; } diff --git a/src/client-tty.c b/src/client-tty.c index 5f31249..59ddec5 100644 --- a/src/client-tty.c +++ b/src/client-tty.c @@ -30,17 +30,165 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "client-tty.h" +#define LOCKDIR "/var/lock" + +static const char *lockfile(const char *dev) { + static char lockfile[PATH_MAX]; + char *p = strrchr(dev, '/'); + if (p) + p++; + else + p = (char*) dev; + + snprintf(lockfile, sizeof(lockfile), "%s/LCK..%s", LOCKDIR, p); + return lockfile; +} + +static const char *tempfile(const char *path) { + static char t[PATH_MAX]; + snprintf(t, sizeof(t), "%s.tmp.%lu", path, (unsigned long) getpid()); + return t; +} + +static int device_lock(const char *dev) { + struct stat st; + int fd; + const char *path, *temp; + char buf[100]; + char uidbuf[32]; + + if (stat(LOCKDIR, &st) != 0 || !S_ISDIR(st.st_mode)) { + fprintf(stderr, "Failed to lock device, directory "LOCKDIR" not existent.\n"); + return -1; + } + + path = lockfile(dev); + temp = tempfile(path); + + for (;;) { + mode_t u; + struct passwd* pw; + char *username; + + if ((fd = open(path, O_RDONLY)) < 0) { + if (errno != ENOENT) { + fprintf(stderr, "Failed to open lock file: %s\n", strerror(errno)); + return -1; + } + } + + if (fd >= 0) { + ssize_t n; + + n = read(fd, buf, sizeof(buf) - 1); + close(fd); + + if (n < 0) { + close(fd); + fprintf(stderr, "Failed to read from lock file: %s\n", strerror(errno)); + return -1; + } + + if (n > 0) { + pid_t pid; + + if (n == 4) + pid = (pid_t) *((uint32_t*) buf); + else { + unsigned long v; + buf[n] = 0; + sscanf(buf, "%lu", &v); + pid = (pid_t) v; + } + + if (pid > 0) { + if (kill(pid, 0) < 0 && errno == ESRCH) { + fprintf(stderr, "Lockfile is stale. Overriding it.\n"); + /* Yes, here is a race condition */ + unlink(path); + } else + return 1; + } + } + } + + u = umask(0033); + fd = open(temp, O_WRONLY | O_CREAT | O_EXCL, 0666); + umask(u); + + if (fd < 0) { + fprintf(stderr, "Failed to create temporary lock file: %s\n", strerror(errno)); + return -1; + } + + if ((pw = getpwuid(getuid()))) + username = pw->pw_name; + else + snprintf(username = uidbuf, sizeof(uidbuf), "%lu", (unsigned long) getuid()); + + snprintf(buf, sizeof(buf), "%10lu %s %.20s\n", (unsigned long) getpid(), "bidilink", username); + if (write(fd, buf, strlen(buf)) < 0) { + fprintf(stderr, "Failed to write to temporary lock file: %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + if (link(temp, path) < 0) { + if (errno == EEXIST) + continue; + + fprintf(stderr, "Failed to link temporary lock file: %s\n", strerror(errno)); + } + + unlink(temp); + + return 0; + } +} + +static int device_unlock(const char *dev) { + if (unlink(lockfile(dev)) < 0) { + fprintf(stderr, "Failed to remove lock file: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +static void destruct(struct stream *s) { + assert(s && s->user); + + device_unlock((char*) s->user); + free(s->user); +} + struct stream* stream_client_tty(const char *args) { struct stream *s = NULL; struct termios ts; int fd = -1; + int r; s = malloc(sizeof(struct stream)); assert(s); memset(s, 0, sizeof(struct stream)); + + if ((r = device_lock(args)) != 0) { + if (r > 0) + fprintf(stderr, "Device locked.\n"); + goto fail; + } + if ((fd = open(args, O_RDWR|O_NOCTTY)) < 0) { fprintf(stderr, "open('%s', O_RDWR|O_NOCTTY): %s\n", args, strerror(errno)); @@ -67,6 +215,8 @@ struct stream* stream_client_tty(const char *args) { goto fail; } + s->user = strdup(args); + s->destruct = destruct; s->input_fd = s->output_fd = fd; return s; -- cgit