Skip to content

Commit

Permalink
First attempt at converting rzh off off pdpzm. There's a big bug in e…
Browse files Browse the repository at this point in the history
…cho to be fixed.
  • Loading branch information
Scott Bronson committed Jun 13, 2005
1 parent 41efe92 commit d891589
Show file tree
Hide file tree
Showing 54 changed files with 2,395 additions and 3,881 deletions.
7 changes: 4 additions & 3 deletions CHANGES
@@ -1,15 +1,16 @@
13 Jun 2005: 13 Jun 2005:
* pdpzm is excruciatingly slow. Now forking lrzsz to handle the transfer. * pdpzm works but it is excruciatingly slow. So, the third attempt:
fork a new rz process to handle the zmodem transfer.


13 Nov 2004: tagged version 0.2 (r27) 13 Nov 2004: tagged version 0.2 (r27)
* Made zmfr.c modular, sent in patches. * Made zmfr.c modular, sent in patches.
* Added send functionality but it appears very broken. * Added send functionality but it appears very broken.


5 Nov 2004: tagged version 0.1 (r21) 5 Nov 2004: tagged version 0.1 (r21)
* First version that works. Switched to the pdpzm library because the * First version that works. Switched to the pdpzm library because the
lrzsz code is supremely scary. lrzsz code is amazingly brittle.


13 Jan 2004: 15 Jan 2004:
* First version. Uses the code from lrzsz. * First version. Uses the code from lrzsz.




Expand Down
41 changes: 21 additions & 20 deletions Makefile
Expand Up @@ -2,37 +2,38 @@
# Scott Bronson # Scott Bronson
# This file is MIT licensed (public domain, but removes author liability). # This file is MIT licensed (public domain, but removes author liability).


VERSION=0.2 VERSION=0.5

# pdpzm files
CSRC=zmcore.c zmfrunix.c zmextm.c error.c pdcomm.c fifo.c bgio.c scan.c zio.c rzh.c


CSRC=bgio.c echo.c fifo.c io/io_select.c log.c rzh.c
# -lrt


# ------------------------ # # ------------------------ #


OBJ=$(CSRC:.c=.o) # OBJ=$(CSRC:.c=.o)


COPTS+=-isystem . COPTS+=-DVERSION=$(VERSION)
COPTS+=-Wall -Werror COPTS+=-Wall -Werror
COPTS+=-g COPTS+=-g
COPTS+=-DVERSION=$(VERSION)


all: rzh doc all: rzh doc
@(cd test; $(MAKE))


rzh: $(OBJ) rzh: $(CSRC)
$(CC) $(OBJ) -lrt -lutil -o rzh $(CC) $(COPTS) $(CSRC) -lutil -o rzh

#%.o: %.c
# $(CC) $(COPTS) -c $<


%.o: %.c %.c: %.re
$(CC) $(COPTS) -c $< re2c $(REOPTS) $< > $@
perl -pi -e 's/^\#line.*$$//' $@


# autogenerate deps # autogenerate deps
# See http://www.gnu.org/software/make/manual/html_chapter/make_4.html#SEC51 # See http://www.gnu.org/software/make/manual/html_chapter/make_4.html#SEC51
%.dep: %.c #%.dep: %.c
@set -e; rm -f $@; \ # @set -e; rm -f $@; \
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \ # $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ # sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$ # rm -f $@.$$$$


-include $(CSRC:.c=.dep) -include $(CSRC:.c=.dep)


Expand All @@ -43,9 +44,9 @@ doc: rzh.1


clean: clean:
rm -f rzh rzh.1 rm -f rzh rzh.1
rm -f $(CSRC:.c=.o) # rm -f $(CSRC:.c=.o)
rm -f $(CSRC:.c=.dep) # rm -f $(CSRC:.c=.dep)
rm -f $(CSRC:.c=.dep.*) # rm -f $(CSRC:.c=.dep.*)
@(cd test; $(MAKE) clean) @(cd test; $(MAKE) clean)


dist-clean: clean dist-clean: clean
Expand Down
115 changes: 72 additions & 43 deletions bgio.c
@@ -1,16 +1,19 @@
/* bgio.c /* bgio.c
* Scott Bronson * Scott Bronson
* *
* Starts up background I/O. This file was derived from ancient BSD code. * Starts up background I/O behind another process.
* It should probably fall under some sort of BSD license. *
* NOTE: can currently only handle one ongoing bgio session because of
* the single global used by the signal callbacks. Too bad C doesn't
* have closures... Some dynamic alloc/dealloc would fix this if need be.
*/ */


#include <pty.h> #include <pty.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include <string.h> #include <string.h>
#include <termios.h>
#include <unistd.h> #include <unistd.h>
#include <utmp.h> #include <utmp.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
Expand All @@ -20,57 +23,53 @@
#include <sys/wait.h> #include <sys/wait.h>


#include "bgio.h" #include "bgio.h"
#include "log.h"




char *bgio_subshell_command=NULL; bgio_state *g_state; // this sucks.
int bgio_master;
int bgio_slave;

static int child_pid;
static struct termios stdin_termios;





static void window_resize(int dummy) static void window_resize(int dummy)
{ {
struct winsize win; bgio_state *state = g_state;
struct winsize win;


ioctl(0, TIOCGWINSZ, (char*)&win); ioctl(0, TIOCGWINSZ, (char*)&win);
ioctl(bgio_slave, TIOCSWINSZ, (char*)&win); ioctl(state->slave, TIOCSWINSZ, (char*)&win);

kill(state->child_pid, SIGWINCH);
kill(child_pid, SIGWINCH);
} }




void bgio_stop(int code) void bgio_stop(bgio_state *state, int code)
{ {
tcsetattr(0, TCSAFLUSH, &stdin_termios); tcsetattr(0, TCSAFLUSH, &state->stdin_termios);
close(bgio_master); close(state->master);
fprintf(stderr, "\r\nrzh exited.\r\n"); fprintf(stderr, "\r\nrzh exited.\r\n");
exit(code); exit(code);
} }




static void sigchild(int dummy) static void sigchild(int dummy)
{ {
bgio_state *state = g_state;
int pid; int pid;


while ((pid = wait3(&dummy, 0, 0)) > 0) { while ((pid = wait3(&dummy, 0, 0)) > 0) {
if (pid == child_pid) { if (pid == state->child_pid) {
bgio_stop(0); bgio_stop(state, 0);
} }
} }
} }




static void do_child() static void do_child(bgio_state *state, const char *cmd)
{ {
char *shell; char *shell;
char *name; char *name;


shell = getenv("SHELL"); shell = getenv("SHELL");
if(!shell) { if(!shell) {
shell = _PATH_BSHELL; shell = _PATH_BSHELL; // should be defined by stdlib.
} }


name = strrchr(shell, '/'); name = strrchr(shell, '/');
Expand All @@ -80,55 +79,85 @@ static void do_child()
name = shell; name = shell;
} }


setsid(); log_dbg("Hello from the child. shell=\"%s\"", shell);
ioctl(bgio_slave, TIOCSCTTY, 0);

close(bgio_master);
dup2(bgio_slave, 0);
dup2(bgio_slave, 1);
dup2(bgio_slave, 2);
close(bgio_slave);


if(bgio_subshell_command) { setsid();
execl(shell, name, "-c", bgio_subshell_command, 0); ioctl(state->slave, TIOCSCTTY, 0);

close(state->master);
dup2(state->slave, 0);
dup2(state->slave, 1);
dup2(state->slave, 2);
close(state->slave);

if(cmd) {
execl(shell, name, "-c", cmd, 0);
fprintf(stderr, "Could not exec %s -c %s: %s\n",
shell, cmd, strerror(errno));
} else { } else {
execl(shell, name, "-i", 0); execl(shell, name, "-i", 0);
fprintf(stderr, "Could not exec %s -i: %s\n",
shell, strerror(errno));
} }

log_dbg("child got fuxored.");

exit(86);
} }


/**
* http://www.dusek.ch/manual/glibc/libc_17.html:
* Data written to the master side is received by the slave side as
* if it was the result of a user typing at an ordinary terminal,
* and data written to the slave side is sent to the master side as
* if it was written on an ordinary terminal.
*
* @param state: uninitialized memory to store the state for this conn.
* @param cmd: Command to run in child. If NULL, starts the default shell.
*
* @returns: Nothing! It prints a message to stdout and exits on failure.
* This should really be changed one day.
*/


void bgio_start() void bgio_start(bgio_state *state, const char *cmd)
{ {
struct winsize win; struct winsize win;
struct termios tt; struct termios tt;


tcgetattr(0, &stdin_termios); // this is why we can only handle one session at once.
g_state = state;

tcgetattr(0, &state->stdin_termios);
ioctl(0, TIOCGWINSZ, (char *)&win); ioctl(0, TIOCGWINSZ, (char *)&win);
if (openpty(&bgio_master, &bgio_slave, NULL, &stdin_termios, &win) < 0) { if (openpty(&state->master, &state->slave, NULL,
&state->stdin_termios, &win) < 0) {
perror("calling openpty"); perror("calling openpty");
kill(0, SIGTERM); kill(0, SIGTERM);
bgio_stop(fork_error1); fprintf(stderr, "\r\nrzh exited.\r\n");
exit(fork_error1);
} }


tt = stdin_termios; log_dbg("bgio: master=%d slave=%d", state->master, state->slave);

tt = state->stdin_termios;
cfmakeraw(&tt); cfmakeraw(&tt);
tt.c_lflag &= ~ECHO; tt.c_lflag &= ~ECHO;
tcsetattr(0, TCSAFLUSH, &tt); tcsetattr(0, TCSAFLUSH, &tt);


signal(SIGCHLD, sigchild); signal(SIGCHLD, sigchild);


child_pid = fork(); state->child_pid = fork();
if(child_pid < 0) { if(state->child_pid < 0) {
perror("forking child"); perror("forking child");
kill(0, SIGTERM); kill(0, SIGTERM);
bgio_stop(fork_error2); bgio_stop(state, fork_error2);
} }


if(child_pid == 0) { if(state->child_pid == 0) {
do_child(); do_child(state, cmd);
perror("executing child"); perror("executing child");
kill(0, SIGTERM); kill(0, SIGTERM);
bgio_stop(fork_error3); bgio_stop(state, fork_error3);
} }


signal(SIGWINCH, window_resize); signal(SIGWINCH, window_resize);
Expand Down
21 changes: 12 additions & 9 deletions bgio.h
Expand Up @@ -5,23 +5,26 @@
* This file is MIT licensed. * This file is MIT licensed.
*/ */


// Command to run in child. If NULL, starts the default shell. #include <termios.h>
extern char *bgio_subshell_command;

typedef struct {
int master; // the fd of the master
int slave; // the fd of the slave
int child_pid; // the pid of the subprocess
struct termios stdin_termios; // original termios to restore when finished
} bgio_state;


// Need to call start_bgio before these are valid.
extern int bgio_master;
extern int bgio_slave;


// Opens a pty and forks the child process specified by bgio_subshell_command. // Opens a pty and forks the child process specified by bgio_subshell_command.
void bgio_start(); void bgio_start(bgio_state *state, const char *cmd);


// Shuts down everything started by bgio_start, then exits. // Shuts down everything started by bgio_start, then exits.
void bgio_stop(int code); void bgio_stop(bgio_state *state, int code);




// result codes returned by exit(). // result codes returned by exit().
// actually, htese are mostly used by main, not bgio // actually, these are mostly used by main, not bgio
// but bgio needs to access the fork_errors.


enum { enum {
argument_error=1, argument_error=1,
Expand Down

0 comments on commit d891589

Please sign in to comment.