Mercurial > hg > Members > kono > nitros9-code
view 3rdparty/packages/uucpbb/src/gproto.c @ 2855:e126b9acab32 lwtools-port
rules.mak: Do not hardcode path for "echo"
It is basically the only tool with full path here and I don't see any
reason for it. We don't use special echo options that would fail
on the shell built-in echo.
Also don't hardcode path for losetup. sudo should make sure you
have the relevant location in your path, and that the path is sanitized,
otherwise your sudo setup is broken.
author | Tormod Volden <debian.tormod@gmail.com> |
---|---|
date | Sat, 13 Jul 2013 11:30:31 +0200 |
parents | c4c7facbd082 |
children |
line wrap: on
line source
/* gproto.c These are the g protocol routines for UUCPbb package. Copyright (C) 1990, 1993 Rick Adams and Bob Billson This file is part of the OS-9 UUCP package, UUCPbb. 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. The author of UUCPbb, Bob Billson, can be contacted at: bob@kc2wz.bubble.org or uunet!kc2wz!bob or by snail mail: 21 Bates Way, Westfield, NJ 07090 */ #include "uucp.h" #include "uucico.h" #define CLOSE2 9 /* Added --BGP */ #ifdef DEBUG #define debuglvl ((int)0x62726164) #endif /* used for a quick calculation of packet sizes, only in this file */ static int uucpbufsiz[9] = {0, 32, 64, 128, 256, 512, 1024, 2048, 4096}; /* This variable tells swin_flush() to accept a LDATA(HY) in response to a LDATA(HY) sent by us. Normally, only an RR or RJ are accepted -- BAS */ static QQ flag eat_HY = FALSE; /* BAS */ static char msg[200]; int gproto() { register flag state; short length, i; int qq = 0; /* sseq needs to be initialized for wtcontrol */ sseq = 0; /* Tell remote the window size we can handle */ wtcontrol (INITA | rec_window); if (rdpacket (msg, &length) != INITA) { logerror ("bad response to INITA"); return (ABORT); } /* get the size the remote can handle */ winsiz = inpacket.C & 0x07; /* Use the window size the remote sent us or our size, whichever is smaller. */ winsiz = min (rec_window, winsiz); /* Set data packet size */ if (debuglvl > 4) fprintf (log, "Sent: INITB %d\n", rec_segment); wtcontrol (INITB | rec_segment-1); if (rdpacket (msg, &length) != INITB) { logerror ("bad response to INITB"); return (ABORT); } /* Get the data segment size the remote wants to use. */ segsiz = inpacket.C & 0x07; /* Tell the remote the window we will use. */ wtcontrol (INITC | winsiz); for (i = 0; i < 4; ++i) if (rdpacket (msg, &length) != INITC) logerror ("bad response to INITC"); else break; winsiz = inpacket.C & 0x07; if (debuglvl > 0) fprintf (log, "%s %s %s DEBUG--gproto: protocol started; segsize = %d, winsize = %d\n", sender, sysname, gtime(), segsiz, winsiz); for (rseq = sseq = 0, state = role;;) switch (state) { case MASTER: state = master(); break; case SLAVE: state = slave(); break; /* The close sequence can be started from either side. This is the case when we have not been sent a CLOSE yet. -BAS That is: US THEM CLOSE -> <- CLOSE */ case CLOSE: /* close up shop */ for (i = 0; i < 3; i++) { wtcontrol (CLOSE); if (rdpacket (msg, &length) == CLOSE) return (_END); } break; /* This case should handle that case where we have been sent a CLOSE. The CLOSE itself is read by master() and slave() -BAS That is: US THEM <- CLOSE [read at master() or slave()] CLOSE -> */ case CLOSE2: wtcontrol (CLOSE); return (_END); break; } } /* This should ONLY be executed when the role is MASTER otherwise, things will get confused --BAS */ int master() { register int type; int len; /* find and perform all queued work as master */ findwork(); #ifndef DEBUG if (debuglvl > 1) fputs ("master: asking remote if it has work for us\n", log); else if (debuglvl > 1) fputs ("master: sending H to Slave to see if it has work for us\n", log); #endif /* does other system have queued work for us? */ wtmsg ("H"); #ifdef DEBUG fputs("master: Sent H to slave\n",log); #endif /* The only valid responses from H should be HY or HN. An HN means that the slave has work to do and roles should be switched. HY means it's ok to begin to shut the protocol down --BAS */ #ifdef DEBUG fputs("master: About to read an HY or HN from slave\n",log); #endif rdmsg (msg); #ifdef DEBUG fputs("master: Read an HY or HN from slave\n",log); #endif if (strncmp (msg, "HN", 2) == 0) { if (debuglvl > 1) fputs ("master: Slave wants to reverse roles\n", log); role = SLAVE; return (SLAVE); } /* We should probably check to make sure that message was an HY --BAS */ #ifndef DEBUG if (debuglvl > 1) fputs ("master: remote says no, hang up\n", log); #else if (debuglvl > 1) fputs ("master: slave must want to quit\n", log); fputs ("master: About to send final HY to slave\n", log); #endif /* We need to munch an LDATA(HY) when we run Taylor UUCP -- BAS */ eat_HY = TRUE; swin_send (LDATA,"HY",2); eat_HY = FALSE; #ifdef DEBUG fputs ("master: Sent final HY to slave\n", log); #endif if (debuglvl > 3) fputs ("master: About to read last message from slave\n", log); type = getpacket (msg, &len); #ifdef DEBUG fputs ("master: Got last message from slave\n", log); #endif switch (type) { /* This case takes care of any LDATA or SDATA packets at the end Apparently Ultrix uucico sends this -- BAS */ case LDATA: case SDATA: if (debuglvl > 3) fputs ("master: slave sent us a LDATA or SDATA, RR it and send a CLOSE.\n", log); rseq = (++rseq & 0x07); wtcontrol (RR | rseq); break; /* This is the usual case for Sun uucico [really System V, I think] and whatever UUNET Tech. uses. -- BAS */ case RR: if (debuglvl > 3) fputs ("master: slave sent us an RR, send them CLOSE.\n", log); return (CLOSE); break; /* This seems to be the usual case for Taylor UUCP. -- BAS */ case CLOSE: if (debuglvl > 3) fputs ("master: slave sent us an CLOSE, send them one.\n", log); return (CLOSE2); break; /* This may handle everything else, maybe not??? Who knows.... -- BAS */ default: if (debuglvl > 1) { fprintf (log, "master: slave sent us something--> %d\n", type); fputs (" send them a CLOSE.\n", log); } break; } return (CLOSE); } /* This should ONLY be executed when role is SLAVE, otherwise things will get confused. --BAS */ int slave() { register int type; int len; /* do all the queued work for us */ for (rdmsg (msg); strcmp (msg, "H") != 0; rdmsg (msg)) { if (debuglvl > 1) /* DEBUG */ fprintf (log, "DEBUG--slave: cline=%s:\n", msg); slavework (msg); } /* We need to check to see if we have any work to send --BAS */ if (anywork() == 1) { if (debuglvl > 3) fputs ("slave: switch roles, send HN to master\n", log); wtmsg ("HN"); #ifdef DEBUG fputs ("slave: Sent an HN to master\n", log); #endif role = MASTER; return (MASTER); } if (debuglvl > 3) fputs ("slave: slave has no work to do, send last HY to master\n", log); wtmsg ("HY"); #ifdef DEBUG fputs ("slave: Sent last HY to master\n", log); #endif if (debuglvl > 3) fputs ("slave: read last message from master\n", log); /* According to the spec. on the 'g' protocol, the only thing that should be sent from the master is a LDATA(HY), however, at least Ultrix uucico will send a CLOSE. Nice huh?... --BAS */ type = getpacket (msg, &len); #ifdef DEBUG fputs ("slave: Got last message from master\n", log); #endif switch (type) { /* This seems to be the usual case for Sun and Taylor, most uucicos, I think -- BAS */ case LDATA: case SDATA: if (debuglvl > 3) fputs ("slave: master sent us a LDATA or SDATA, RR it and send a CLOSE.\n", log); rseq = (++rseq & 0x07); wtcontrol (RR | rseq); break; /* Never seen this one actually execute. -- BAS */ case RR: if (debuglvl > 3) fputs ("slave: master sent us an RR, send them CLOSE.\n", log); return (CLOSE); break; /* Ultrix apparently sends this. -- BAS */ case CLOSE: if (debuglvl > 3) fputs ("slave: master sent us an CLOSE, send them one.\n", log); return (CLOSE2); break; /* Don't know what this could be, really.... -- BAS */ default: if (debuglvl > 1) { fprintf (log, "slave: master sent us something--> %d\n", type); fputs (" send them a CLOSE.\n", log); } break; } return (CLOSE); } /* swin_init initialize sending window */ int swin_init() { swin = sseq; } /* swin_send Send one packet, update window if reply is ready return only if window is not fully extended. */ int swin_send (type, data, length) char type, *data; int length; { /* send current packet */ sseq = (++sseq & 7); wtdata (type, data, length); swin_flush (FALSE); } /* swin_flush wait for sending window to be emptied if sw_flag == TRUE, return when swin == sseq if sw_flag != TRUE, return when window is not fully extended */ int swin_flush (sw_flag) int sw_flag; { char tseq = sseq; register int type; int length, size; flag ready = TRUE; struct pk *outp; #ifndef _OSK unsigned cksum; #else unsigned short cksum; #endif /* read response if one is ready on error, retransmit all packets up to sseq return only when it's safe to send another packet ie: if window is full, wait for response from remote. Eddie Kuns fixed a bug in the original routine where retransmitting a block required that some values be updated first. Eddie's fix is included here. */ do { /* If we have to retransmit a packet, do so */ if (tseq != sseq) { tseq = (++tseq & 7); outp = &(outpacket[tseq]); size = uucpbufsiz[outp->K]; /* get old data checksum so we can update it later */ cksum = MAGIC - ((outp->C0 & 0xff) | (outp->C1 << 8)); cksum ^= (outp->C & 0xFF); /* first update "last packet read" counter */ outp->C &= 0xf8; outp->C |= rseq & 0x7; /* now update checksums */ cksum = MAGIC - (cksum ^ (outp->C & 0xFF)); outp->C0 = cksum & 0xFF; outp->C1 = (cksum >> 8) & 0xFF; outp->X = outp->K ^ outp->C0 ^ outp->C1 ^ outp->C; write(port, outp, size + 6); if (debuglvl > 4) dumpcode("R> ", outp); if (debuglvl > 8) { fputs (" ", log); strdump (outp->data); } } /* read reply if one is waiting if we cannot exit yet, force reading a packet if retransmitting packets, do not force reading a packet. _gs_rdy() is necessary, sliding windows are disabled otherwise */ if (_gs_rdy (port) > 0 || (!ready && tseq == sseq)) { type = getpacket (msg, &length); /* This is a bit of a hack to keep master() clean. Taylor UUCP, and perhaps others, like to send strange things at the shutdown of the protocol --BAS */ if (eat_HY && type == LDATA) if (strncmp (msg, "HY", 2) == 0) { if (debuglvl > 3) fputs ("swin_flush: eating an LDATA(HY) and sending RR\n", log); /* Tell a bit of a lie to the switch statement that follows... -- BAS */ type = RR; rseq = (++rseq & 0x07); wtcontrol (RR | rseq); } switch (type) { /* All is OK! */ case RR: swin = inpacket.C & 7; /* slide window here */ break; /* Error detected */ case RJ: swin = inpacket.C & 7; /* last good packet */ tseq = swin; /* retransmit at next packet */ break; /* Huh? Unexpected packet type! Log error. --REB */ default: if (debuglvl > 0) fprintf (log, "\n%s %s %s Unexpected packet type: $%X msg = %s\n", sender, sysname, gtime(), type, msg); } } /* set value of "ready" TRICK: open window = ((sseq + 7) - swin) & 7 = (sseq - swin) & 7 even when sseq < swin! */ if (sw_flag) ready = (swin == sseq); else ready = (((sseq - swin) & 7) < winsiz); } while (tseq != sseq || !ready); } /* wtdata --packetize data + send. Don't wait for response */ int wtdata (type, data, length) char type, *data; int length; { register struct pk *outp; #ifdef _OSK short cksum; #else unsigned cksum; #endif int size, diff, i; char *p; outp = &(outpacket[sseq]); for (i = 0; i < 64; i++) outp->data[i] = 0; outp->DLE = 0x10; p = outp->data; outp->C = type; if (type == (char) SDATA) { size = 64; outp->K = K64; diff = size - length; if ((diff & 0x80) == 0) *p++ = (diff & 0xFF); else { *p++ = (diff & 0xFF) | 0x80; *p++ = diff >> 7; } } else { size = 64; /* our packet size */ outp->K = K64; } outp->C |= (sseq & 0x7) << 3; outp->C |= rseq & 0x7; /* Move data into outgoing packet */ memcpy (p, data, length < size ? length : size); cksum = MAGIC - (g_chksum (outp->data, size) ^ (outp->C & 0xFF)); outp->C0 = cksum & 0xFF; outp->C1 = (cksum >> 8) & 0xFF; outp->X = outp->K ^ outp->C0 ^ outp->C1 ^ outp->C; if (debuglvl > 7) dumpcode (">> ", outp); write (port, outp, size + 6); } /* wtmsg --write g-proto message, wait for RR */ int wtmsg (message) char *message; { register char *p; if (debuglvl >= 5) fprintf (log, ">> %s\n", message); p = message; /* initialize sliding windows */ swin_init(); /* send message; swin_send updates sseq */ do { int lenp = strlen (p); /* write data packet containing message */ swin_send (LDATA, p, lenp); p += lenp < 64 ? lenp : 64; } while (*p); /* make sure all packets are sent */ swin_flush (TRUE); } /* wtcontrol --write control packet, don't wait for response */ int wtcontrol (code) register int code; { static struct pk outp; #ifdef _OSK short cksum; #else int cksum; #endif code &= 0xFF; outp.DLE = 0x10; outp.K = KCONTROL; outp.C = code; cksum = MAGIC - code; outp.C0 = cksum & 0xFF; outp.C1 = (cksum >> 8) & 0xFF; outp.X = outp.K ^ outp.C0 ^ outp.C1 ^ code; if (debuglvl > 7) dumpcode (">> ", &outp); write (port, &outp, 6); } /* rdpacket --read a packet Return: data length of data (zero if no data) type of packet (CLOSE, LDATA, SDATA, RR, INITA, etc) */ int rdpacket (data, length) char *data; int *length; { char c, *p; #ifdef _OSK short cksum; #else unsigned cksum; #endif int diff = 0, type; *length = 0; *data = '\0'; /* scan for leading DLE */ do { if (readport (&c, PKTTIME, GET_TRY) == TIMEDOUT) longjmp (env, FATAL); } while (c != 0x10); inpacket.DLE = c; /* read packet header */ if (readport (&inpacket.K, PKTTIME, MAXTRY) == TIMEDOUT) longjmp (env, FATAL); if (readport (&inpacket.C0, PKTTIME, MAXTRY) == TIMEDOUT) longjmp (env, FATAL); if (readport (&inpacket.C1, PKTTIME, MAXTRY) == TIMEDOUT) longjmp (env, FATAL); if (readport (&inpacket.C, PKTTIME, MAXTRY) == TIMEDOUT) longjmp (env, FATAL); if (readport (&inpacket.X, PKTTIME, MAXTRY) == TIMEDOUT) longjmp (env, FATAL); /* return type of packet */ if ((inpacket.C & 0xC0) == 0) type = inpacket.C & 0x38; else type = inpacket.C & 0xC0; /* check XOR checksum of packet */ if ((inpacket.K ^ inpacket.C0 ^ inpacket.C1 ^ inpacket.C) != inpacket.X) return (FALSE); if (debuglvl > 7) dumpcode ("<< ", &inpacket); /* control packet? */ if (inpacket.K == KCONTROL) return (type); /* if not control packet, read data */ if (inpacket.K != KCONTROL) { if (inpacket.K == 0) *length = 0; else { *length = uucpbufsiz[inpacket.K]; /* If we don't get a whole packet, return error */ if (readfill (inpacket.data, *length) != *length) return (FALSE); } } cksum = MAGIC - (g_chksum (inpacket.data, *length) ^(inpacket.C & 0xFF)); /* short data packet, or long data packet? */ if ((inpacket.C & 0xC0) == SDATA) { /* short data packet */ diff = inpacket.data[0] & 0xFF; p = inpacket.data; if ((diff & 0x80) == 0) { *length -= diff; p++; } else { diff &= 0x7F; diff |= ((inpacket.data[1] & 0xFF) << 7); *length -= diff; p += 2; } } else { /* long data packet */ p = inpacket.data; } /* check checksum of data portion */ if (cksum != ((inpacket.C1 << 8) | (inpacket.C0 & 0xFF))) return (FALSE); else { if (*length) memcpy (data, p, *length); return (type); } } /* rdmsg --read g-proto message */ int rdmsg (message) char *message; { register int i; int msglen, length, type; char *p; p = message; do { for (i = 0; i < GET_TRY; i++) if ((type = getpacket (p, &length)) == LDATA || type == SDATA) { rseq = (++rseq & 0x7); wtcontrol (RR | rseq); break; } /* fatal error abort back to uucico() */ if (i == GET_TRY) { logerror ("rdmsg: didn't get message"); longjmp (env, FATAL); } msglen = strlen (inpacket.data); p += msglen; } while (type == LDATA && length == msglen); if (debuglvl > 4) fprintf (log, "<< %s\n", message); } /* getpacket --get data packet */ int getpacket (data, length) char *data; int *length; { int status; register int tries; for (tries = 0; tries < GET_TRY; tries++) { status = rdpacket (data, length); if (!status) wtcontrol (RJ | rseq); else return (status); } /* If we get too many errors, abort to highest level and exit. */ putc ('\n', log); logerror ("getpacket: too many checksum errors in received packets"); fputs (" *** TRANSFER ABORTED ***\n", log); longjmp (env, FATAL); } /*========== Calculate checksum routines for 6809, 6309 and OSK ==========*/ #ifdef _OSK /* g_chksum for OSK borrowed from Taylor UUCP */ int g_chksum (z, c) register char *z; register int c; { register unsigned int ichk1, ichk2; ichk1 = 0xffff; ichk2 = 0; do { register unsigned int b; /* rotate ichk1 left */ if ((ichk1 & 0x8000) == 0) ichk1 <<= 1; else { ichk1 <<= 1; ++ichk1; } /* add next character to ichk1 */ b = *z++ & 0xff; ichk1 += b; /* add ichk1 xor the checksum position in the buffer counting from the back to ichk2. */ ichk2 += ichk1 ^ c; /* if the character was zero, or adding it to ichk1 causes an overflow, xor ichk2 to ichk1 */ if (b == 0 || (ichk1 & 0xffff) < b) ichk1 ^= ichk2; } while (--c > 0); return (ichk1 & 0xffff); } #else # ifndef m6309 # asm assembler routine for OS9/6809 using 6809 * Remember below that C identifiers are 8 characters long vsect dp ChkSum rmb 2 X rmb 2 endsect g_chksum: ldd #0 std <X deca decb std <ChkSum pshs u,y ldu 6,s Get pointer into U. ldy 8,s Get count into Y beq Fin_CRC In case the count = 0 Upd_CRC1 ldd <ChkSum aslb ChkSum <<= 1 (and += 1 if negative) rola adcb #0 std <ChkSum pshs d t = chksum clra chksum += *(s++) ldb ,u+ addd ,s std <ChkSum pshs y X += chksum ^ n eora ,s+ eorb ,s+ addd <X std <X ldd <ChkSum if ( (unsigned) chksum <= t) cmpd ,s++ bhi Next eora <X chksum ^= x; eorb <X+1 std <ChkSum Next leay -1,y bne Upd_CRC1 Fin_CRC puls u,y,pc # endasm # else # asm assembler routine for OS9/6809 using 6309 * This routine uses the W register. It assumes OS-9's kernel is * patched so it does not destroy the contents of W during * interrupts. Burke & Burke's PowerBoost is an example of such * a patch. * Remember below that C identifiers are 8 characters long vsect dp ChkSum rmb 2 X rmb 2 endsect g_chksum: fdb $104f clrd std <X fdb $104a decd std <ChkSum pshs u,y ldu 6,s Get pointer into U. ldy 8,s Get count into Y beq Fin_CRC In case the count = 0 Upd_CRC1 ldd <ChkSum fdb $1048 asld ChkSum <<= 1 (and += 1 if negative) adcb #0 std <ChkSum fdb $1f06 tfr d,w t = chksum clra chksum += *(s++) ldb ,u+ fcb $10,$30,$60 addr w,d std <ChkSum fcb $10,$36,$20 eorr y,d X += chksum ^ n addd <X std <X ldd <ChkSum if ( (unsigned) chksum <= t) fcb $10,$37,$60 cmpr w,d bhi Next eora <X chksum ^= x; eorb <X+1 std <ChkSum Next leay -1,y bne Upd_CRC1 Fin_CRC puls u,y,pc # endasm # endif #endif