diff options
-rw-r--r-- | acconfig.h | 30 | ||||
-rw-r--r-- | configure.in | 84 | ||||
-rw-r--r-- | doc/ncpd.man.in | 6 | ||||
-rw-r--r-- | kde2/kpsion/kpsion.cpp | 71 | ||||
-rw-r--r-- | lib/rfsv.cc | 16 | ||||
-rw-r--r-- | lib/rfsv.h | 7 | ||||
-rw-r--r-- | lib/rfsv16.cc | 19 | ||||
-rw-r--r-- | lib/rpcs.h | 4 | ||||
-rw-r--r-- | lib/rpcs32.cc | 28 | ||||
-rw-r--r-- | lib/rpcs32.h | 4 | ||||
-rw-r--r-- | ncpd/channel.cc | 24 | ||||
-rw-r--r-- | ncpd/channel.h | 7 | ||||
-rw-r--r-- | ncpd/link.cc | 183 | ||||
-rw-r--r-- | ncpd/link.h | 29 | ||||
-rw-r--r-- | ncpd/main.cc | 5 | ||||
-rw-r--r-- | ncpd/mp_serial.c | 5 | ||||
-rw-r--r-- | ncpd/ncp.cc | 126 | ||||
-rw-r--r-- | ncpd/ncp.h | 25 | ||||
-rw-r--r-- | ncpd/packet.cc | 87 | ||||
-rw-r--r-- | ncpd/packet.h | 6 | ||||
-rw-r--r-- | ncpd/socketchan.cc | 44 | ||||
-rw-r--r-- | plpbackup/plpbackup.cc | 521 | ||||
-rw-r--r-- | plpftp/ftp.cc | 12 |
23 files changed, 1135 insertions, 208 deletions
@@ -12,9 +12,6 @@ /* Define this, if you have libreadline */ #undef HAVE_LIBREADLINE -/* Define this, if you have libhistory */ -#undef HAVE_LIBHISTORY - /* Define if the C++ compiler supports BOOL */ #undef HAVE_BOOL @@ -39,33 +36,6 @@ /* The package name */ #undef PACKAGE -/* Define this to your mtab's path */ -#undef MTAB_PATH - -/* Define this to your temporary mtab's path */ -#undef MTAB_TMP - -/* Define this this if you want to prevent plpnfsd from updating mtab */ -#undef DONT_UPDATE_MTAB - -/* Define this to your serial device node */ -#undef DDEV - -/* Define this to your serial device speed */ -#undef DSPEED - -/* Define this to the TCP port ncpd should listen on */ -#undef DPORT - -/* Define this to your default drive on your Psion */ -#undef DDRIVE - -/* Define this to your default directory on your Psion */ -#undef DBASEDIR - -/* Define this to your default mountpoint for plpnfsd */ -#undef DMOUNTPOINT - /* Define this to enable debugging code */ #undef DEBUG diff --git a/configure.in b/configure.in index e2cd512..f4e23ad 100644 --- a/configure.in +++ b/configure.in @@ -86,7 +86,8 @@ AC_ARG_ENABLE(history, if test "x$ac_enable_history" = "xyes" ; then AC_CHECK_LIB(history, add_history, [ - AC_DEFINE_UNQUOTED(HAVE_LIBHISTORY) + AC_DEFINE_UNQUOTED(HAVE_LIBHISTORY,1, + [Define this, if you have libhistory]) ac_cv_libhistory=-lhistory ]) fi @@ -102,28 +103,33 @@ AC_CHECK_LIB(rpcsoc, svcudp_create,,LDFLAGS=$ac_save_LDFLAGS) dnl checks for mount table - if desired ac_enable_mnttab=yes AC_ARG_ENABLE(mnttab, - [ --disable-mnttab disable mnttab writing [no]], - if test "$enableval" = "no" ; then - AC_MSG_RESULT([support for mnttab disabled]) - ac_enable_mnttab=no - fi + [ --disable-mnttab disable mnttab writing [no]], + if test "$enableval" = "no" ; then + AC_MSG_RESULT([support for mnttab disabled]) + ac_enable_mnttab=no + fi ) if test "x$ac_enable_mnttab" = "xyes" ; then - AC_MSG_CHECKING(for mount table) - PLP_FIND_FILE(/etc/mnttab /etc/mtab, MTAB) - AC_MSG_RESULT($MTAB) - test "$MTAB" = "NO" && AC_DEFINE_UNQUOTED(DONT_UPDATE_MTAB) - AC_DEFINE_UNQUOTED(MTAB_PATH,"$MTAB") - case "$target_alias" in - *linux*) - AC_DEFINE_UNQUOTED(MTAB_TMP,"${MTAB}~") - ;; - *) - AC_DEFINE_UNQUOTED(MTAB_TMP,"${MTAB}.plpnfsd") - ;; - esac -else - AC_DEFINE_UNQUOTED(DONT_UPDATE_MTAB) + AC_MSG_CHECKING(for mount table) + PLP_FIND_FILE(/etc/mnttab /etc/mtab, MTAB) + AC_MSG_RESULT($MTAB) + if test "$MTAB" = "NO" ; then + AC_DEFINE_UNQUOTED(DONT_UPDATE_MTAB,1, + [Define this this if you want to prevent plpnfsd from updating mtab]) + else + AC_DEFINE_UNQUOTED(MTAB_PATH,"$MTAB", + [Define this to your mtab's path]) + ac_cv_mtab_tmp="${MTAB}~" + case "$target_alias" in + *linux*) + ;; + *) + ac_cv_mtab_tmp="${MTAB}.plpnfsd" + ;; + esac + AC_DEFINE_UNQUOTED(MTAB_TMP,"${ac_cv_mtab_tmp}", + [Define this to your temporary mtab's path]) + fi fi dnl Check, if bot time.h and sys/time.h may be included @@ -158,19 +164,29 @@ AC_ARG_WITH(serial, test "$DDEV" = "NO" && AC_MSG_ERROR(NO serial lines. Use --with-serial.) ] ) -AC_DEFINE_UNQUOTED(DDEV,"$DDEV") +AC_DEFINE_UNQUOTED(DDEV,"$DDEV",[Define this to your serial device node]) AC_SUBST(DDEV) AC_ARG_WITH(speed, - [ --with-speed=SPEED override default serial speed [115200]], - [ DSPEED="$withval" - AC_MSG_RESULT(Overriding serial speed: $DSPEED) ], - [ DSPEED=115200 - AC_MSG_RESULT(Using default serial speed: $DSPEED) + [ --with-speed=SPEED override default serial speed [auto]], + [ if "$withval" = "auto" ; then + DSNAME=auto + DSPEED=-1 + else + DSPEED="$withval" + DSNAME="$withval" + fi + AC_MSG_RESULT(Overriding serial speed: $DSNAME) ], + [ DSPEED=-1 + DSNAME=auto + AC_MSG_RESULT(Using default serial speed: auto) ] ) -AC_DEFINE_UNQUOTED(DSPEED,$DSPEED) +AC_DEFINE_UNQUOTED(DSPEED,$DSPEED,[Define this to your serial device speed]) +AC_DEFINE_UNQUOTED(DSNAME,$DSNAME, + [Define this to your serial device speed alias]) AC_SUBST(DSPEED) +AC_SUBST(DSNAME) AC_ARG_WITH(port, [ --with-port=PORT override default port [7501]], @@ -180,7 +196,8 @@ AC_ARG_WITH(port, AC_MSG_RESULT(Using default port: $DPORT) ] ) -AC_DEFINE_UNQUOTED(DPORT,$DPORT) +AC_DEFINE_UNQUOTED(DPORT,$DPORT, + [Define this to the TCP port ncpd should listen on]) AC_SUBST(DPORT) AC_ARG_WITH(drive, @@ -191,7 +208,8 @@ AC_ARG_WITH(drive, AC_MSG_RESULT(Using default Psion drive: $DDRIVE) ] ) -AC_DEFINE_UNQUOTED(DDRIVE,"$DDRIVE") +AC_DEFINE_UNQUOTED(DDRIVE,"$DDRIVE", + [Define this to your default drive on your Psion]) AC_ARG_WITH(basedir, [ --with-basedir=DIR override default Psion directory [\\\\]], @@ -201,7 +219,8 @@ AC_ARG_WITH(basedir, AC_MSG_RESULT(Using default Psion directory: $DBASEDIR) ] ) -AC_DEFINE_UNQUOTED(DBASEDIR,"$DBASEDIR") +AC_DEFINE_UNQUOTED(DBASEDIR,"$DBASEDIR", + [Define this to your default directory on your Psion]) AC_ARG_WITH(mountdir, [ --with-mountdir=DIR override default mount point [/mnt/psion]], @@ -211,7 +230,8 @@ AC_ARG_WITH(mountdir, AC_MSG_RESULT(Using default mount point: $DMOUNTPOINT) ] ) -AC_DEFINE_UNQUOTED(DMOUNTPOINT,"$DMOUNTPOINT") +AC_DEFINE_UNQUOTED(DMOUNTPOINT,"$DMOUNTPOINT", + [Define this to your default mountpoint for plpnfsd]) AC_SUBST(DMOUNTPOINT) test "x$prefix" = xNONE && prefix="$ac_default_prefix" eval PKGDATA="${datadir}/${PACKAGE}" diff --git a/doc/ncpd.man.in b/doc/ncpd.man.in index d14779b..03ffda9 100644 --- a/doc/ncpd.man.in +++ b/doc/ncpd.man.in @@ -91,8 +91,10 @@ Specify the serial device to use to connect to the Psion - this defaults to @DDEV@ .TP .BI "\-b, --baudrate=" baudrate -Specify the baud rate to use for the serial connection - this defaults to -@DSPEED@ baud. +Specify the baud rate to use for the serial connection. If the word +.B auto +is specified, ncpd cycles through baudrates of 115200, 57600, 38400, 19200 +and 9600 baud. Default setting is @DSNAME@. .SH SEE ALSO plpftp(1), plpnfsd(8) diff --git a/kde2/kpsion/kpsion.cpp b/kde2/kpsion/kpsion.cpp index e6a8d4d..6ba36a7 100644 --- a/kde2/kpsion/kpsion.cpp +++ b/kde2/kpsion/kpsion.cpp @@ -864,37 +864,49 @@ doBackup() { u_int32_t handle; kapp->processEvents(); - res = plpRfsv->fopen(plpRfsv->opMode(rfsv::PSI_O_RDONLY), fn, - handle); - if (res != rfsv::E_PSI_GEN_NONE) { - if (KMessageBox::warningYesNo(this, i18n("<QT>Could not open<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) { - badBackup = true; - break; - } else { - e.setName("!"); - continue; - } - } - unsigned char *buff = new unsigned char[RFSV_SENDLEN]; - u_int32_t len; + bool tryLoop = true; do { - if ((res = plpRfsv->fread(handle, buff, RFSV_SENDLEN, len)) == - rfsv::E_PSI_GEN_NONE) { - os.writeRawBytes((char *)buff, len); - updateProgress(len); + res = plpRfsv->fopen(plpRfsv->opMode(rfsv::PSI_O_RDONLY), fn, + handle); + if (res == rfsv::E_PSI_GEN_NONE) { + unsigned char *buff = new unsigned char[RFSV_SENDLEN]; + u_int32_t len; + do { + if ((res = plpRfsv->fread(handle, buff, RFSV_SENDLEN, + len)) == rfsv::E_PSI_GEN_NONE) { + os.writeRawBytes((char *)buff, len); + updateProgress(len); + } + } while ((len > 0) && (res == rfsv::E_PSI_GEN_NONE)); + delete[]buff; + plpRfsv->fclose(handle); } - } while ((len > 0) && (res == rfsv::E_PSI_GEN_NONE)); - delete[]buff; - plpRfsv->fclose(handle); - if (res != rfsv::E_PSI_GEN_NONE) { - if (KMessageBox::warningYesNo(this, i18n("<QT>Could not read<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) { - badBackup = true; - break; + if (res != rfsv::E_PSI_GEN_NONE) { + switch (KMessageBox::warningYesNoCancel( + this, i18n( + "<QT>Could not backup<BR/><B>%1</B><BR/>" + "<FONT COLOR=RED>%2</FONT><BR/></QT>" + ).arg(fn).arg((const char *)res), + QString::null, i18n("Retry"), i18n("Ignore"))) { + case KMessageBox::Cancel: + badBackup = true; + tryLoop = false; + break; + case KMessageBox::No: + e.setName("!"); + tryLoop = false; + break; + case KMessageBox::Yes: + break; + } } else { - e.setName("!"); - continue; + tryLoop = false; } - } + } while (tryLoop); + if (badBackup) + break; + if (res != rfsv::E_PSI_GEN_NONE) + continue; backupTgz->writeFile(unixname, "root", "root", ba.size(), ba.data()); } @@ -915,7 +927,7 @@ doBackup() { kapp->processEvents(); res = plpRfsv->fsetattr(fn, 0, rfsv::PSI_A_ARCHIVE); if (res != rfsv::E_PSI_GEN_NONE) { - if (KMessageBox::warningYesNo(this, i18n("<QT>Could not set attributes of<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) { + if (KMessageBox::warningYesNo(this, i18n("<QT>Could not set attributes of<BR/><B>%1</B><BR/><FONT COLOR=red>%2</FONT><BR/>Continue?</QT>").arg(fn)) == KMessageBox::No) { break; } } @@ -998,7 +1010,6 @@ removeOldBackups(QStringList &drives) { QFileInfoListIterator it(*fil); QFileInfo *fi; ArchList alist; - Barchive *a; // Build a list of full-backups sorted by date while ((fi = it.current())) { @@ -1637,7 +1648,7 @@ killSave() { "<QT>Could not stop all processes.<BR/>" "Please stop running programs manually on the Psion, " "then klick <B>Ok</B>.")); - time_t tstart = time(0) + 5; + tstart = time(0) + 5; } } return; diff --git a/lib/rfsv.cc b/lib/rfsv.cc index 25bf91c..310d7c4 100644 --- a/lib/rfsv.cc +++ b/lib/rfsv.cc @@ -167,6 +167,22 @@ attr2String(const u_int32_t attr) return tmp; } +int rfsv:: +getSpeed() +{ + bufferStore a; + a.addStringT("NCP$GSPD"); + if (!skt->sendBufferStore(a)) + return -1; + if (skt->getBufferStore(a) != 1) + return -1; + if (a.getLen() != 5) + return -1; + if (a.getByte(0) != E_PSI_GEN_NONE) + return -1; + return a.getDWord(1); +} + /* * Local variables: * c-basic-offset: 4 @@ -600,6 +600,13 @@ public: */ static string convertSlash(const string &name); + /** + * Retrieve speed of serial link. + * + * @returns The speed of the serial link in baud or -1 on error. + */ + int getSpeed(); + protected: /** * Retrieves the PLP protocol name. Mainly internal use. diff --git a/lib/rfsv16.cc b/lib/rfsv16.cc index 2474060..773a5c1 100644 --- a/lib/rfsv16.cc +++ b/lib/rfsv16.cc @@ -222,10 +222,21 @@ fgetmtime(const char * const name, PsiTime &mtime) Enum<rfsv::errs> rfsv16:: fsetmtime(const char *name, PsiTime mtime) { - cerr << "rfsv16::fsetmtime ***" << endl; - // I don't think there's a protocol frame that allows us to set the - // modification time. SFDATE allows setting of creation time... - return E_PSI_NOT_SIBO; + // According to Alexander's protocol doc, SFDATE sets the modification + // time - and as far as I can see SIBO only keeps a modification + // time. So call SFDATE here. + bufferStore a; + string realName = convertSlash(name); + a.addDWord(mtime.getTime()); + a.addStringT(realName.c_str()); + // and this needs sending in the length word. + if (!sendCommand(SFDATE, a)) + return E_PSI_FILE_DISC; + + Enum<rfsv::errs> res = getResponse(a); + if (res != E_PSI_GEN_NONE) + cerr << "fsetmtime: Error " << res << " on file " << name << endl; + return res; } Enum<rfsv::errs> rfsv16:: @@ -338,8 +338,8 @@ public: */ virtual Enum<rfsv::errs> getMachineInfo(machineInfo &) { return rfsv::E_PSI_NOT_SIBO;} virtual Enum<rfsv::errs> closeHandle(int) { return rfsv::E_PSI_NOT_SIBO;} - virtual Enum<rfsv::errs> regOpenIter(void) { return rfsv::E_PSI_NOT_SIBO;} - virtual Enum<rfsv::errs> regReadIter(void) { return rfsv::E_PSI_NOT_SIBO;} + virtual Enum<rfsv::errs> regOpenIter(u_int32_t, char *, u_int16_t &) { return rfsv::E_PSI_NOT_SIBO;} + virtual Enum<rfsv::errs> regReadIter(u_int16_t) { return rfsv::E_PSI_NOT_SIBO;} virtual Enum<rfsv::errs> regWrite(void) { return rfsv::E_PSI_NOT_SIBO;} virtual Enum<rfsv::errs> regRead(void) { return rfsv::E_PSI_NOT_SIBO;} virtual Enum<rfsv::errs> regDelete(void) { return rfsv::E_PSI_NOT_SIBO;} diff --git a/lib/rpcs32.cc b/lib/rpcs32.cc index 38d7933..ebb4f9c 100644 --- a/lib/rpcs32.cc +++ b/lib/rpcs32.cc @@ -169,18 +169,38 @@ getMachineInfo(machineInfo &mi) static unsigned long hhh; Enum<rfsv::errs> rpcs32:: -regOpenIter(void) +regOpenIter(u_int32_t uid, char *match, u_int16_t &handle) { bufferStore a; Enum<rfsv::errs> res; - a.addStringT("HKLM\\"); + cout << "Oiter" << endl; + a.addDWord(uid); + a.addDWord(strlen(match)); + a.addStringT(match); if (!sendCommand(rpcs::REG_OPEN_ITER, a)) return rfsv::E_PSI_FILE_DISC; res = getResponse(a, true); cout << "ro: r=" << res << " a=" << a << endl; - if (a.getLen() > 0) - hhh = a.getDWord(0); + if (a.getLen() == 2) + handle = a.getWord(0); + return rfsv::E_PSI_GEN_NONE; +} + +Enum<rfsv::errs> rpcs32:: +regReadIter(u_int16_t handle) +{ + bufferStore a; + Enum<rfsv::errs> res; + + cout << "Riter" << endl; + a.addWord(handle); + if (!sendCommand(rpcs::REG_READ_ITER, a)) + return rfsv::E_PSI_FILE_DISC; + res = getResponse(a, true); + cout << "ro: r=" << res << " a=" << a << endl; + if ((a.getLen() == 3) && (a.getByte(2) == 0xff)) + return rfsv::E_PSI_FILE_EOF; return rfsv::E_PSI_GEN_NONE; } diff --git a/lib/rpcs32.h b/lib/rpcs32.h index 0256b66..70644da 100644 --- a/lib/rpcs32.h +++ b/lib/rpcs32.h @@ -48,9 +48,9 @@ class rpcs32 : public rpcs { #if 0 Enum<rfsv::errs> closeHandle(int); #endif - Enum<rfsv::errs> regOpenIter(void); + Enum<rfsv::errs> regOpenIter(u_int32_t uid, char *match, u_int16_t &handle); + Enum<rfsv::errs> regReadIter(u_int16_t handle); #if 0 - Enum<rfsv::errs> regReadIter(void); Enum<rfsv::errs> regWrite(void); Enum<rfsv::errs> regRead(void); Enum<rfsv::errs> regDelete(void); diff --git a/ncpd/channel.cc b/ncpd/channel.cc index e51b903..d3189e4 100644 --- a/ncpd/channel.cc +++ b/ncpd/channel.cc @@ -87,6 +87,30 @@ ncpDisconnect() ncpController->disconnect(ncpChannel); } +PcServer *channel:: +ncpFindPcServer(const char *name) +{ + return ncpController->findPcServer(name); +} + +void channel:: +ncpRegisterPcServer(ppsocket *skt, const char *name) +{ + ncpController->registerPcServer(skt, name); +} + +void channel:: +ncpUnregisterPcServer(PcServer *server) +{ + ncpController->unregisterPcServer(server); +} + +int channel:: +ncpGetSpeed() +{ + return ncpController->getSpeed(); +} + short int channel:: ncpProtocolVersion() { diff --git a/ncpd/channel.h b/ncpd/channel.h index 585ef31..e9bf3ea 100644 --- a/ncpd/channel.h +++ b/ncpd/channel.h @@ -31,6 +31,8 @@ class ncp; class bufferStore; +class PcServer; +class ppsocket; class channel { public: @@ -61,6 +63,11 @@ public: virtual bool terminate(); // Mainloop will terminate this class if true void terminateWhenAsked(); + PcServer *ncpFindPcServer(const char *name); + void ncpRegisterPcServer(ppsocket *skt, const char *name); + void ncpUnregisterPcServer(PcServer *server); + int ncpGetSpeed(); + protected: short int verbose; const char *connectName; diff --git a/ncpd/link.cc b/ncpd/link.cc index a52e3ef..025e131 100644 --- a/ncpd/link.cc +++ b/ncpd/link.cc @@ -44,16 +44,21 @@ extern "C" { Link *l = (Link *)arg; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); while (1) { - usleep(l->retransTimeout * 500); + usleep(l->retransTimeout() * 500); l->retransmit(); } } }; +ENUM_DEFINITION(Link::link_type, Link::LINK_TYPE_UNKNOWN) { + stringRep.add(Link::LINK_TYPE_UNKNOWN, N_("Unknown")); + stringRep.add(Link::LINK_TYPE_SIBO, N_("SIBO")); + stringRep.add(Link::LINK_TYPE_EPOC, N_("EPOC")); +} + Link::Link(const char *fname, int baud, ncp *_ncp, unsigned short _verbose) + : p(0) { - p = new packet(fname, baud, this, _verbose); - retransTimeout = ((unsigned long)baud * 1000 / 13200) + 200; theNCP = _ncp; verbose = _verbose; txSequence = 1; @@ -61,18 +66,20 @@ Link::Link(const char *fname, int baud, ncp *_ncp, unsigned short _verbose) failed = false; seqMask = 7; maxOutstanding = 1; + linkType = LINK_TYPE_UNKNOWN; for (int i = 0; i < 256; i++) xoff[i] = false; - // generate magic number for sendCon() + // generate magic number for sendReqCon() srandom(time(NULL)); conMagic = random(); + p = new packet(fname, baud, this, _verbose); + pthread_mutex_init(&queueMutex, NULL); pthread_create(&checkthread, NULL, expire_check, this); // submit a link request - bufferStore blank; - transmit(blank); + sendReqReq(); } Link::~Link() @@ -83,22 +90,27 @@ Link::~Link() delete p; } +unsigned long Link:: +retransTimeout() +{ + return ((unsigned long)getSpeed() * 1000 / 13200) + 200; +} + void Link:: reset() { + p->reset(); txSequence = 1; rxSequence = -1; failed = false; - - pthread_mutex_lock(&queueMutex); - ackWaitQueue.clear(); - holdQueue.clear(); - pthread_mutex_unlock(&queueMutex); + seqMask = 7; + maxOutstanding = 1; + linkType = LINK_TYPE_UNKNOWN; + purgeAllQueues(); for (int i = 0; i < 256; i++) xoff[i] = false; // submit a link request - bufferStore blank; - transmit(blank); + sendReqReq(); } unsigned short Link:: @@ -124,6 +136,15 @@ send(const bufferStore & buff) } void Link:: +purgeAllQueues() +{ + pthread_mutex_lock(&queueMutex); + ackWaitQueue.clear(); + holdQueue.clear(); + pthread_mutex_unlock(&queueMutex); +} + +void Link:: purgeQueue(int channel) { pthread_mutex_lock(&queueMutex); @@ -161,7 +182,7 @@ sendAck(int seq) } void Link:: -sendCon() +sendReqCon() { if (hasFailed()) return; @@ -182,8 +203,44 @@ sendCon() } void Link:: +sendReqReq() +{ + if (hasFailed()) + return; + bufferStore tmp; + if (verbose & LNK_DEBUG_LOG) + cout << "Link: >> con seq=1" << endl; + tmp.addByte(0x21); + ackWaitQueueElement e; + e.seq = 0; // expected response is Ack with seq=0 or ReqCon + gettimeofday(&e.stamp, NULL); + e.data = tmp; + e.txcount = 4; + pthread_mutex_lock(&queueMutex); + ackWaitQueue.push_back(e); + pthread_mutex_unlock(&queueMutex); + p->send(tmp); +} + +void Link:: +sendReq() +{ + if (hasFailed()) + return; + bufferStore tmp; + if (verbose & LNK_DEBUG_LOG) + cout << "Link: >> con seq=1" << endl; + tmp.addByte(0x20); + // No Ack expected for this, so no new entry in ackWaitQueue + p->send(tmp); +} + +void Link:: receive(bufferStore buff) { + if (!p) + return; + vector<ackWaitQueueElement>::iterator i; bool ackFound; bool conFound; @@ -267,17 +324,58 @@ receive(bufferStore buff) } pthread_mutex_unlock(&queueMutex); if (ackFound) { + if ((linkType == LINK_TYPE_UNKNOWN) && (seq == 0)) { + // If the remote device runs SIBO protocol, this ACK + // should be 0 (the Ack on our ReqReq request, which is + // treated as a normal Req by the SIBO machine. + failed = false; + linkType = LINK_TYPE_SIBO; + seqMask = 7; + maxOutstanding = 1; + rxSequence = 0; + txSequence = 1; + purgeAllQueues(); + if (verbose & LNK_DEBUG_LOG) + cout << "Link: 1-linkType set to " << linkType << endl; + } // Older packets implicitely ack'ed multiAck(refstamp); // Transmit waiting packets transmitWaitQueue(); } else { if (verbose & LNK_DEBUG_LOG) { - cout << "Link: << UNMATCHED ack seq=" << seq ; + cout << "Link: << UNMATCHED ack seq=" << seq; if (verbose & LNK_DEBUG_DUMP) cout << " " << buff; cout << endl; } + // If packet with seq+1 is in ackWaitQueue, resend it immediately + // (Receiving an ack for a packet not on our wait queue is a + // hint by the Psion about which was the last packet it + // received successfully.) + pthread_mutex_lock(&queueMutex); + struct timeval now; + gettimeofday(&now, NULL); + for (i = ackWaitQueue.begin(); i != ackWaitQueue.end(); i++) + if (i->seq == seq+1) { + if (i->txcount-- == 0) { + // timeout, remove packet + if (verbose & LNK_DEBUG_LOG) + cout << "Link: >> TRANSMIT timeout seq=" << + i->seq << endl; + ackWaitQueue.erase(i); + i--; + } else { + // retransmit it + i->stamp = now; + if (verbose & LNK_DEBUG_LOG) + cout << "Link: >> RETRANSMIT seq=" << i->seq + << endl; + p->send(i->data); + } + break; + } + pthread_mutex_unlock(&queueMutex); } break; @@ -288,10 +386,13 @@ receive(bufferStore buff) // May be a link confirm packet (EPOC) pthread_mutex_lock(&queueMutex); for (i = ackWaitQueue.begin(); i != ackWaitQueue.end(); i++) - if ((i->seq > 0) && (i->seq < 4) && - (i->data.getByte(0) & 0xf0) == 0x20) { + if ((i->seq == 0) && (i->data.getByte(0) & 0xf0) == 0x20) { ackWaitQueue.erase(i); + linkType = LINK_TYPE_EPOC; + if (verbose & LNK_DEBUG_LOG) + cout << "Link: 2-linkType set to " << linkType << endl; conFound = true; + failed = false; // EPOC can handle extended sequence numbers seqMask = 0x7ff; // EPOC can handle up to 8 unacknowledged packets @@ -310,6 +411,7 @@ receive(bufferStore buff) if (conFound) { rxSequence = 0; txSequence = 1; + purgeAllQueues(); sendAck(rxSequence); } else { if (verbose & LNK_DEBUG_LOG) { @@ -320,14 +422,30 @@ receive(bufferStore buff) } rxSequence = txSequence = 0; if (seq > 0) { + linkType = LINK_TYPE_EPOC; + if (verbose & LNK_DEBUG_LOG) + cout << "Link: 3-linkType set to " << linkType << endl; // EPOC can handle extended sequence numbers seqMask = 0x7ff; // EPOC can handle up to 8 unacknowledged packets maxOutstanding = 8; p->setEpoc(true); - sendCon(); - } else + purgeAllQueues(); + failed = false; + sendReqCon(); + } else { + // SIBO + linkType = LINK_TYPE_SIBO; + failed = false; + seqMask = 7; + maxOutstanding = 1; + if (verbose & LNK_DEBUG_LOG) + cout << "Link: 4-linkType set to " << linkType << endl; + rxSequence = 0; + txSequence = 1; // Our ReqReq was seq 0 + purgeAllQueues(); sendAck(rxSequence); + } } break; @@ -481,10 +599,7 @@ retransmit() { if (hasFailed()) { - pthread_mutex_lock(&queueMutex); - ackWaitQueue.clear(); - holdQueue.clear(); - pthread_mutex_unlock(&queueMutex); + purgeAllQueues(); return; } @@ -493,7 +608,7 @@ retransmit() struct timeval now; gettimeofday(&now, NULL); struct timeval expired = now; - timesub(&expired, retransTimeout); + timesub(&expired, retransTimeout()); for (i = ackWaitQueue.begin(); i != ackWaitQueue.end(); i++) if (olderthan(i->stamp, expired)) { if (i->txcount-- == 0) { @@ -501,6 +616,7 @@ retransmit() if (verbose & LNK_DEBUG_LOG) cout << "Link: >> TRANSMIT timeout seq=" << i->seq << endl; ackWaitQueue.erase(i); + failed = true; i--; } else { // retransmit it @@ -528,10 +644,27 @@ stuffToSend() bool Link:: hasFailed() { - failed |= p->linkFailed(); + bool lfailed = p->linkFailed(); + if (failed || lfailed) { + if (verbose & LNK_DEBUG_LOG) + cout << "Link: hasFailed: " << failed << ", " << lfailed << endl; + } + failed |= lfailed; return failed; } +Enum<Link::link_type> Link:: +getLinkType() +{ + return linkType; +} + +int Link:: +getSpeed() +{ + return p->getSpeed(); +} + /* * Local variables: * c-basic-offset: 4 diff --git a/ncpd/link.h b/ncpd/link.h index 81732b6..25cd280 100644 --- a/ncpd/link.h +++ b/ncpd/link.h @@ -32,6 +32,7 @@ #include "bufferstore.h" #include "bufferarray.h" +#include "Enum.h" #include <vector> #define LNK_DEBUG_LOG 4 @@ -70,6 +71,12 @@ extern "C" { class Link { public: + enum link_type { + LINK_TYPE_UNKNOWN = 0, + LINK_TYPE_SIBO = 1, + LINK_TYPE_EPOC = 2, + }; + /** * Construct a new link instance. * @@ -141,6 +148,20 @@ public: */ unsigned short getVerbose(); + /** + * Get the current link type. + * + * @returns One of LINK_TYPE_... values. + */ + Enum<link_type> getLinkType(); + + /** + * Get current speed of the serial device + * + * @returns The current speed in baud. + */ + int getSpeed(); + private: friend class packet; friend void * expire_check(void *); @@ -148,11 +169,15 @@ private: void receive(bufferStore buf); void transmit(bufferStore buf); void sendAck(int seq); - void sendCon(); + void sendReqReq(); + void sendReqCon(); + void sendReq(); void multiAck(struct timeval); void retransmit(); void transmitHoldQueue(int channel); void transmitWaitQueue(); + void purgeAllQueues(); + unsigned long retransTimeout(); pthread_t checkthread; pthread_mutex_t queueMutex; @@ -163,10 +188,10 @@ private: int rxSequence; int seqMask; int maxOutstanding; - unsigned long retransTimeout; unsigned long conMagic; unsigned short verbose; bool failed; + Enum<link_type> linkType; vector<ackWaitQueueElement> ackWaitQueue; vector<bufferStore> holdQueue; diff --git a/ncpd/main.cc b/ncpd/main.cc index f1f7f14..4771744 100644 --- a/ncpd/main.cc +++ b/ncpd/main.cc @@ -288,7 +288,10 @@ main(int argc, char **argv) autoexit = true; break; case 'b': - baudRate = atoi(optarg); + if (!strcmp(optarg, "auto")) + baudRate = -1; + else + baudRate = atoi(optarg); break; case 's': serialDevice = optarg; diff --git a/ncpd/mp_serial.c b/ncpd/mp_serial.c index 7f6a792..7483a3e 100644 --- a/ncpd/mp_serial.c +++ b/ncpd/mp_serial.c @@ -131,7 +131,7 @@ init_serial(const char *dev, int speed, int debug) perror("seteuid"); exit(1); } - if ((fd = open(dev, O_RDWR /*FRITZTEST | O_NDELAY */ | O_NOCTTY, 0)) < 0) { + if ((fd = open(dev, O_RDWR | O_NOCTTY, 0)) < 0) { perror(dev); exit(1); } @@ -184,6 +184,9 @@ ser_exit(int fd) { struct termios ti; +#ifdef TIOCNXCL + ioctl(fd, TIOCNXCL, (char *) 0); +#endif if (tcgetattr(fd, &ti) < 0) perror("tcgetattr"); ti.c_cflag &= ~CRTSCTS; diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc index 76f4d63..f20ca75 100644 --- a/ncpd/ncp.cc +++ b/ncpd/ncp.cc @@ -31,9 +31,10 @@ #include "ncp.h" #include "linkchan.h" -#include <bufferstore.h> #include "link.h" +#include <bufferstore.h> #include <bufferarray.h> +#include <rfsv.h> #define MAX_CHANNELS_PSION 256 #define MAX_CHANNELS_SIBO 8 @@ -54,6 +55,7 @@ ncp::ncp(const char *fname, int baud, unsigned short _verbose) // until detected on receipt of INFO we use these. maxChannels = MAX_CHANNELS_SIBO; protocolVersion = PV_SERIES_5; + lChan = NULL; // init channels for (int i = 0; i < MAX_CHANNELS_PSION; i++) @@ -94,6 +96,8 @@ reset() { channelPtr[i] = NULL; } failed = false; + if (lChan) + delete(lChan); lChan = NULL; protocolVersion = PV_SERIES_5; // until detected on receipt of INFO l->reset(); @@ -158,6 +162,35 @@ controlChannel(int chan, enum interControllerMessageType t, bufferStore & comman l->send(open); } +PcServer *ncp:: +findPcServer(const char *name) +{ + if (name) { + vector<PcServer>::iterator i; + for (i = pcServers.begin(); i != pcServers.end(); i++) + if (i->getName() == name) + return i; + } + return NULL; +} + +void ncp:: +registerPcServer(ppsocket *skt, const char *name) { + pcServers.push_back(PcServer(skt, name)); +} + +void ncp:: +unregisterPcServer(PcServer *server) { + if (server) { + vector<PcServer>::iterator i; + for (i = pcServers.begin(); i != pcServers.end(); i++) + if (i == server) { + pcServers.erase(i); + return; + } + } +} + void ncp:: decodeControlMessage(bufferStore & buff) { @@ -169,6 +202,7 @@ decodeControlMessage(bufferStore & buff) cout << "ncp: << " << ctrlMsgName(imt) << " " << remoteChan; bufferStore b; + int localChan; switch (imt) { case NCON_MSG_CONNECT_TO_SERVER: @@ -178,33 +212,51 @@ decodeControlMessage(bufferStore & buff) cout << endl; } - int localChan; - - // Ack with connect response - localChan = getFirstUnusedChan(); - b.addByte(remoteChan); - b.addByte(0); - controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); - - // NOTE: we don't allow connections from the - // Psion to any local "processes" other than - // LINK.* - Matt might need to change this for - // his NCP<->TCP/IP bridge code... - + failed = false; if (!strcmp(buff.getString(0), "LINK.*")) { if (lChan) - failed = true; + localChan = lChan->getNcpChannel(); + else + localChan = getFirstUnusedChan(); + + // Ack with connect response + b.addByte(remoteChan); + b.addByte(0); + controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); if (verbose & NCP_DEBUG_LOG) cout << "ncp: Link UP" << endl; - channelPtr[localChan] = lChan = new linkChan(this, localChan); - lChan->setVerbose(verbose); + // Create linkchan if it does not yet exist + if (!lChan) { + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: new passive linkChan" << endl; + channelPtr[localChan] = + lChan = new linkChan(this, localChan); + lChan->setVerbose(verbose); + } lChan->ncpConnectAck(); } else { - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: REJECT connect" << endl; - bufferStore b; + PcServer *s = findPcServer(buff.getString(0)); + bool ok = false; + + if (s) { + localChan = getFirstUnusedChan(); + ok = s->clientConnect(localChan, remoteChan); + if (!ok) + // release channel ptr + channelPtr[localChan] = NULL; + } b.addByte(remoteChan); - controlChannel(0, NCON_MSG_CHANNEL_DISCONNECT, b); + if (ok) { + b.addByte(rfsv::E_PSI_GEN_NONE); + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: ACCEPT client connect" << endl; + } else { + localChan = 0; + b.addByte(rfsv::E_PSI_FILE_NXIST); + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: REJECT client connect" << endl; + } + controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); } break; @@ -212,6 +264,7 @@ decodeControlMessage(bufferStore & buff) int forChan; + failed = false; forChan = buff.getByte(0); if (verbose & NCP_DEBUG_LOG) cout << " ch=" << forChan << " stat="; @@ -237,6 +290,7 @@ decodeControlMessage(bufferStore & buff) int ver; + failed = false; ver = buff.getByte(0); // Series 3c returns '3', as does mclink. PsiWin 1.1 // returns version 2. We return whatever version we're @@ -263,11 +317,12 @@ decodeControlMessage(bufferStore & buff) // Do we send a time of 0 or a real time? // The Psion uses this to determine whether to // restart. (See protocol docs for details) - // b.addDWord(0); b.addDWord(time(NULL)); controlChannel(0, NCON_MSG_NCP_INFO, b); - } else + } else { cout << "ALERT!!!! Unexpected Protocol Version!! (No Series 5/3?)!" << endl; + failed = true; + } break; case NCON_MSG_CHANNEL_DISCONNECT: @@ -318,7 +373,7 @@ RegisterAck(int chan, const char *name) cout << "ncp: RegisterAck: chan=" << chan << endl; for (int cNum = 1; cNum < maxLinks(); cNum++) { channel *ch = channelPtr[cNum]; - if (ch && ch->getNcpChannel() == chan) { + if (isValidChannel(cNum) && ch->getNcpChannel() == chan) { ch->setNcpConnectName(name); ch->ncpRegisterAck(); return; @@ -420,9 +475,20 @@ stuffToSend() bool ncp:: hasFailed() { - if (failed) - return true; - return l->hasFailed(); + bool lfailed = l->hasFailed(); + if (failed || lfailed) { + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: hasFailed: " << failed << ", " << lfailed << endl; + } + failed |= lfailed; + if (failed) { + if (lChan) { + channelPtr[lChan->getNcpChannel()] = NULL; + delete lChan; + } + lChan = NULL; + } + return failed; } bool ncp:: @@ -431,6 +497,12 @@ gotLinkChannel() return (lChan != NULL); } +int ncp:: +getSpeed() +{ + return l->getSpeed(); +} + char *ncp:: ctrlMsgName(unsigned char msgType) { @@ -27,14 +27,33 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif + +#include <vector> + #include "bufferstore.h" #include "linkchan.h" +#include "ppsocket.h" + class Link; class channel; #define NCP_DEBUG_LOG 1 #define NCP_DEBUG_DUMP 2 +/** + * Representation of a server process on the PC + * A dummy which does not allow connects for now. + */ +class PcServer { +public: + PcServer(ppsocket *, string _name) { name = _name; } + ~PcServer() {} + bool clientConnect(int, int) { return false; } + string getName() { return name; } +private: + string name; +}; + class ncp { public: ncp(const char *fname, int baud, unsigned short _verbose = 0); @@ -51,9 +70,14 @@ public: bool hasFailed(); bool gotLinkChannel(); + PcServer *findPcServer(const char *name); + void registerPcServer(ppsocket *skt, const char *name); + void unregisterPcServer(PcServer *server); + void setVerbose(unsigned short); unsigned short getVerbose(); short int getProtocolVersion(); + int getSpeed(); private: friend class Link; @@ -87,6 +111,7 @@ private: short int protocolVersion; linkChan *lChan; int maxChannels; + vector<PcServer> pcServers; }; #endif diff --git a/ncpd/packet.cc b/ncpd/packet.cc index 84f0f66..1d3183b 100644 --- a/ncpd/packet.cc +++ b/ncpd/packet.cc @@ -138,10 +138,17 @@ static void *pump_run(void *arg) } } -//static pthread_mutex_t outMutex; -//static pthread_mutex_t inMutex; }; +static const int baud_table[] = { + 115200, + 57600, + 38400, + 19200, + // Lower rates don't make sense ?! +}; +#define BAUD_TABLE_SIZE (sizeof(baud_table) / sizeof(int)) + packet:: packet(const char *fname, int _baud, Link *_link, unsigned short _verbose) { @@ -151,6 +158,7 @@ packet(const char *fname, int _baud, Link *_link, unsigned short _verbose) baud = _baud; theLINK = _link; isEPOC = false; + justStarted = true; // Initialize CRC table crc_table[0] = 0; @@ -174,12 +182,15 @@ packet(const char *fname, int _baud, Link *_link, unsigned short _verbose) crcIn = crcOut = 0; thisThread = pthread_self(); - fd = init_serial(devname, baud, 0); + realBaud = baud; + if (baud < 0) { + baud_index = 1; + realBaud = baud_table[0]; + } + fd = init_serial(devname, realBaud, 0); if (fd == -1) lastFatal = true; else { -// pthread_mutex_init(&inMutex, NULL); -// pthread_mutex_init(&outMutex, NULL); signal(SIGUSR1, usr1handler); pthread_create(&datapump, NULL, pump_run, this); } @@ -201,30 +212,46 @@ packet:: void packet:: reset() { + if (fd != -1) + pthread_cancel(datapump); + outRead = outWrite = 0; + internalReset(); + if (fd != -1) + pthread_create(&datapump, NULL, pump_run, this); +} + +void packet:: +internalReset() +{ if (verbose & PKT_DEBUG_LOG) cout << "resetting serial connection" << endl; if (fd != -1) { - pthread_cancel(datapump); ser_exit(fd); fd = -1; } - usleep(100000); - inRead = inWrite = outRead = outWrite = 0; + usleep(1000000); + inRead = inWrite = 0; esc = false; lastFatal = false; serialStatus = -1; lastSYN = startPkt = -1; crcIn = crcOut = 0; - fd = init_serial(devname, baud, 0); - if (fd != -1) - lastFatal = false; - else { -// pthread_mutex_init(&inMutex, NULL); -// pthread_mutex_init(&outMutex, NULL); - pthread_create(&datapump, NULL, pump_run, this); + realBaud = baud; + justStarted = true; + if (baud < 0) { + realBaud = baud_table[baud_index++]; + if (baud_index >= BAUD_TABLE_SIZE) + baud_index = 0; } + + fd = init_serial(devname, realBaud, 0); if (verbose & PKT_DEBUG_LOG) - cout << "serial connection reset, fd=" << fd << endl; + cout << "serial connection set to " << dec << realBaud + << " baud, fd=" << fd << endl; + if (fd != -1) { + lastFatal = false; + realWrite(); + } } short int packet:: @@ -245,6 +272,12 @@ setEpoc(bool _epoc) isEPOC = _epoc; } +int packet:: +getSpeed() +{ + return realBaud; +} + void packet:: send(bufferStore &b) { @@ -350,6 +383,7 @@ findSync() } } if (startPkt >= 0) { + justStarted = false; while (p != inw) { unsigned char c = inBuffer[p]; switch (inCRCstate) { @@ -393,7 +427,6 @@ findSync() if (verbose & PKT_DEBUG_LOG) cout << "packet: BAD CRC" << endl; } else { - // inQueue += rcv; if (verbose & PKT_DEBUG_LOG) { cout << "packet: << "; if (verbose & PKT_DEBUG_DUMP) @@ -412,6 +445,18 @@ findSync() inc1(p); } lastSYN = p; + } else { + // If we get here, no sync was found. + // If we are just started and the amount of received data exceeds + // 15 bytes, the baudrate is obviously wrong. + // (or the connected device is not an EPOC device). Reset the + // serial connection and try next baudrate, if auto-baud is set. + if (justStarted) { + int rx_amount = (inw > inRead) ? + inw - inRead : BUFLEN - inRead + inw; + if (rx_amount > 15) + internalReset(); + } } } @@ -422,8 +467,8 @@ linkFailed() int res; bool failed = false; - if (lastFatal) - reset(); + if (fd == -1) + return false; res = ioctl(fd, TIOCMGET, &arg); if (res < 0) lastFatal = true; @@ -453,10 +498,8 @@ linkFailed() || ((arg & TIOCM_DSR) == 0) #endif ) { - // eat possible junk on line - //while (read(fd, &res, sizeof(res)) > 0) - // ; failed = true; + justStarted = true; } if ((verbose & PKT_DEBUG_LOG) && lastFatal) cout << "packet: linkFATAL\n"; diff --git a/ncpd/packet.h b/ncpd/packet.h index aa0b90c..dcf01cc 100644 --- a/ncpd/packet.h +++ b/ncpd/packet.h @@ -57,6 +57,7 @@ public: void setEpoc(bool); void setVerbose(short int); short int getVerbose(); + int getSpeed(); bool linkFailed(); void reset(); @@ -71,6 +72,7 @@ private: void opByte(unsigned char a); void opCByte(unsigned char a, unsigned short *crc); void realWrite(); + void internalReset(); Link *theLINK; pthread_t datapump; @@ -98,10 +100,14 @@ private: int foundSync; int fd; int serialStatus; + int baud_index; + int realBaud; short int verbose; bool esc; bool lastFatal; bool isEPOC; + bool justStarted; + char *devname; int baud; }; diff --git a/ncpd/socketchan.cc b/ncpd/socketchan.cc index 83d0695..fe2b683 100644 --- a/ncpd/socketchan.cc +++ b/ncpd/socketchan.cc @@ -32,6 +32,7 @@ #include "socketchan.h" #include "ncp.h" #include <ppsocket.h> +#include <rfsv.h> socketChan:: socketChan(ppsocket * _skt, ncp * _ncpController): channel(_ncpController) @@ -72,11 +73,10 @@ ncpCommand(bufferStore & a) { // str is guaranteed to begin with NCP$, and all NCP commands are // greater than or equal to 8 characters in length. - const char *str = a.getString(); - // unsigned long len = a.getLen(); + const char *str = a.getString(4); bool ok = false; - if (!strncmp(str+4, "INFO", 4)) { + if (!strncmp(str, "INFO", 4)) { // Send information discovered during the receipt of the // NCON_MSG_NCP_INFO message. a.init(); @@ -94,26 +94,50 @@ ncpCommand(bufferStore & a) } skt->sendBufferStore(a); ok = true; - } else if (!strncmp(str+4, "CONN", 4)) { + } else if (!strncmp(str, "CONN", 4)) { // Connect to a channel that was placed in 'pending' mode, by // checking the channel table against the ID... // DO ME LATER ok = true; - } else if (!strncmp(str+4, "CHAL", 4)) { + } else if (!strncmp(str, "CHAL", 4)) { // Challenge // The idea is that the channel stays in 'secure' mode until a // valid RESP is received // DO ME LATER ok = true; - } else if (!strncmp(str+4, "RESP", 4)) { + } else if (!strncmp(str, "RESP", 4)) { // Reponse - here is the plaintext as sent in the CHAL - the // channel will only open up if this matches what ncpd has for // the encrypted plaintext. // DO ME LATER ok = true; + } else if (!strncmp(str, "GSPD", 4)) { + // Get Speed of serial device + cerr << "socketChan:: GETSPEED" << endl; + a.init(); + a.addByte(rfsv::E_PSI_GEN_NONE); + a.addDWord(ncpGetSpeed()); + skt->sendBufferStore(a); + ok = true; + } else if (!strncmp(str, "REGS", 4)) { + // Register a server-process on the PC side. + a.init(); + const char *name = a.getString(8); + if (ncpFindPcServer(name)) + a.addByte(rfsv::E_PSI_FILE_EXIST); + else { + ncpRegisterPcServer(skt, name); + a.addByte(rfsv::E_PSI_GEN_NONE); + } + skt->sendBufferStore(a); + ok = true; } - if (!ok) + if (!ok) { cerr << "socketChan:: received unknown NCP command (" << a << ")" << endl; + a.init(); + a.addByte(rfsv::E_PSI_GEN_NSUP); + skt->sendBufferStore(a); + } return ok; } @@ -223,6 +247,12 @@ socketPoll() ncpDisconnect(); skt->closeSocket(); } else if (res == 1) { + if (a.getLen() > 8 && !strncmp(a.getString(), "NCP$", 4)) { + if (!ncpCommand(a)) + cerr << "ncpd: command " << a << " unrecognized." + << endl; + return; + } ncpSend(a); } } else if (time(0) > (tryStamp + 15)) diff --git a/plpbackup/plpbackup.cc b/plpbackup/plpbackup.cc index 66dd780..cbd211c 100644 --- a/plpbackup/plpbackup.cc +++ b/plpbackup/plpbackup.cc @@ -26,6 +26,7 @@ #endif #include <sys/types.h> +#include <sys/wait.h> #include <dirent.h> #include <fstream> #include <strstream> @@ -42,6 +43,7 @@ #include <errno.h> #include <pwd.h> #include <getopt.h> +#include <fcntl.h> #include <plpintl.h> #include <ppsocket.h> @@ -68,6 +70,7 @@ unsigned long totalBytes = 0; unsigned long fileSize = 0; PlpDir toBackup; +PlpDir toRestore; vector<string> driveList; vector<string> archList; vector<string> savedCommands; @@ -115,7 +118,7 @@ generateBackupName() static const char * const generateTmpDir() { - char *tmpdir; + const char *tmpdir; static char nbuf[4096]; if (!(tmpdir = getenv("TMPDIR"))) @@ -217,7 +220,7 @@ startPrograms() { if (verbose > 0) cout << _("Restarting programs ...") << endl; - for (int i = 0; i < savedCommands.size(); i++) { + for (unsigned int i = 0; i < savedCommands.size(); i++) { int firstBlank = savedCommands[i].find(' '); string cmd = string(savedCommands[i], 0, firstBlank); string arg = string(savedCommands[i], firstBlank + 1); @@ -240,7 +243,7 @@ startPrograms() { // not registered in the Psion's path properly. Now try // the ususal \System\Apps\<AppName>\<AppName>.app // on all drives. - if (cmd.find('\\') == -1) { + if (cmd.find('\\') == cmd.npos) { u_int32_t devbits; if ((res = Rfsv->devlist(devbits)) == rfsv::E_PSI_GEN_NONE) { int i; @@ -312,7 +315,7 @@ collectFiles(bool &found, const char *dir) { if ((res = Rfsv->dir(tmp.c_str(), files)) != rfsv::E_PSI_GEN_NONE) cerr << "Error: " << res << endl; else - for (int i = 0; i < files.size(); i++) { + for (unsigned int i = 0; i < files.size(); i++) { PlpDirent e = files[i]; if (checkAbort()) @@ -337,7 +340,7 @@ collectFiles(bool &found, const char *dir) { static int reportProgress(void *, u_int32_t size) { - unsigned long percent; + unsigned long percent = 0; char pstr[10]; char bstr[10]; @@ -347,13 +350,19 @@ reportProgress(void *, u_int32_t size) return 1; switch (verbose) { case 1: - percent = (totalBytes + size) * 100 / backupSize; + if (backupSize == 0) + percent = 100; + else + percent = (totalBytes + size) * 100 / backupSize; break; case 2: - percent = size * 100 / fileSize; + if (fileSize == 0) + percent = 100; + else + percent = size * 100 / fileSize; break; } - sprintf(pstr, " %3d%%", percent); + sprintf(pstr, " %3ld%%", percent); memset(bstr, 8, sizeof(bstr)); bstr[strlen(pstr)] = '\0'; printf("%s%s", pstr, bstr); @@ -443,7 +452,7 @@ startMessage(const char *arch) cout << "all drives"; else { cout << "Drive "; - for (int i = 0; i < driveList.size(); i++) { + for (unsigned int i = 0; i < driveList.size(); i++) { cout << driveList[i++]; if (i < (driveList.size() - 1)) cout << ", "; @@ -480,18 +489,501 @@ runFormat() return 0; } +static int +editfile(char *name) +{ + int shin, shout, sherr; + int mode_out, mode_err; + int status; + int rc = -1; + int rerrno = 0; + int pid, w; + +#ifdef POSIX_SIGNALS + sigset_t sigset_mask, sigset_omask; + struct sigaction act, iact, qact; + +#else +#ifdef BSD_SIGNALS + int mask; + struct sigvec vec, ivec, qvec; + +#else + RETSIGTYPE (*istat) (int), (*qstat) (int); +#endif +#endif + + /* setup default file descriptor numbers */ + shin = 0; + shout = 1; + sherr = 2; + + /* set the file modes for stdout and stderr */ + mode_out = mode_err = O_WRONLY | O_CREAT; + + /* Make sure we don't flush this twice, once in the subprocess. */ + fflush (stdout); + fflush (stderr); + + /* The output files, if any, are now created. Do the fork and dups. + + We use vfork not so much for a performance boost (the + performance boost, if any, is modest on most modern unices), + but for the sake of systems without a memory management unit, + which find it difficult or impossible to implement fork at all + (e.g. Amiga). The other solution is spawn (see + windows-NT/run.c). */ + +#ifdef HAVE_VFORK + pid = vfork (); +#else + pid = fork (); +#endif + if (pid == 0) + { + +#ifdef SETXID_SUPPORT + /* + ** This prevents a user from creating a privileged shell + ** from the text editor when the SETXID_SUPPORT option is selected. + */ + if (!strcmp (run_argv[0], Editor) && setegid (getgid ())) + { + error (0, errno, "cannot set egid to gid"); + _exit (127); + } +#endif + + /* dup'ing is done. try to run it now */ + char *editor = getenv("EDITOR"); + if (!editor) + editor = "vi"; + execlp (editor, editor, name, NULL); + perror(editor); + _exit (127); + } + else if (pid == -1) + { + rerrno = errno; + goto out; + } + + /* the parent. Ignore some signals for now */ +#ifdef POSIX_SIGNALS + act.sa_handler = SIG_IGN; + (void) sigemptyset (&act.sa_mask); + act.sa_flags = 0; + (void) sigaction (SIGINT, &act, &iact); + (void) sigaction (SIGQUIT, &act, &qact); +#else +#ifdef BSD_SIGNALS + memset ((char *) &vec, 0, sizeof (vec)); + vec.sv_handler = SIG_IGN; + (void) sigvec (SIGINT, &vec, &ivec); + (void) sigvec (SIGQUIT, &vec, &qvec); +#else + istat = signal (SIGINT, SIG_IGN); + qstat = signal (SIGQUIT, SIG_IGN); +#endif +#endif + + /* wait for our process to die and munge return status */ +#ifdef POSIX_SIGNALS + while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) + ; +#else + while ((w = wait (&status)) != pid) { + if (w == -1 && errno != EINTR) + break; + } +#endif + + if (w == -1) { + rc = -1; + rerrno = errno; + } +#ifndef VMS /* status is return status */ + else if (WIFEXITED (status)) + rc = WEXITSTATUS (status); + else if (WIFSIGNALED (status)) { + if (WTERMSIG (status) == SIGPIPE) + perror("broken pipe"); + rc = 2; + } else + rc = 1; +#else /* VMS */ + rc = WEXITSTATUS (status); +#endif /* VMS */ + + /* restore the signals */ +#ifdef POSIX_SIGNALS + (void) sigaction (SIGINT, &iact, (struct sigaction *) NULL); + (void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL); +#else +#ifdef BSD_SIGNALS + (void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL); + (void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL); +#else + (void) signal (SIGINT, istat); + (void) signal (SIGQUIT, qstat); +#endif +#endif + + out: + if (rerrno) + errno = rerrno; + return (rc); +} + static void -runRestore() +collectIndex(FILE *f, const char *archname) { + char buf[1024]; + string drives; int i; + + PlpDir indexSel; + PlpDir indexRestore; + while (fgets(buf, sizeof(buf), f)) { + unsigned long attr; + unsigned long size; + unsigned long timeLo; + unsigned long timeHi; + char drive = buf[36]; + + char *p = strrchr(buf, '\n'); + if (p) + *p = '\0'; + if (drive != '!') { + sscanf(buf, "%08lx %08lx %08lx %08lx ", + &timeHi, &timeLo, &size, &attr); + PlpDirent e(size, attr, timeHi, timeLo, &buf[36]); + indexSel.push_back(e); + if (drives.find(drive) == drives.npos) + drives += drive; + } + } + // drives now contains the drive-chars of all drives found in + // the backup. + if (!drives.empty()) { + cout << "It contains Backups of drive "; + for (i = 0; i < drives.size(); i++) { + if (i>0) { + if (i < (drives.size() - 1)) + cout << ", "; + else + if (drives.size() > 1) + cout << " and "; + } + cout << drives[i] << ":"; + } + cout << endl; + + // Check, if one of the drives is in driveList (commandline args) + bool select = false; + for (i = 0; i < driveList.size(); i++) { + if (drives.find(driveList[i][0]) != drives.npos) + select = true; + } + if (select) { + cout << "Do you want to select individual files from this archive? (y/N)" << endl; + const char *validA = _("Y"); + char answer; + cin >> answer; + if (toupper(answer) == *validA) { + strcpy(buf, "/tmp/plpbackupL_XXXXXX"); + int fd = mkstemp(buf); + if (fd == -1) { + perror("mkstemp"); + exit(-1); + } + FILE *tf = fdopen(fd, "w"); + fprintf(tf, "# Edit this file to you needs and save it\n"); + fprintf(tf, "# Change the 'N' in the first column to 'Y'\n"); + fprintf(tf, "# if you want a file to be restored.\n"); + fprintf(tf, "# DO NOT INSERT ANY LINES!\n"); + for (i = 0; i < indexSel.size(); i++) + for (int j = 0; j < driveList.size(); j++) + if (*(indexSel[i].getName()) == driveList[j][0]) + fprintf(tf, "N %s\n", indexSel[i].getName()); + fclose(tf); + if (editfile(buf) == -1) { + perror("Could not run external editor"); + unlink(buf); + exit(-1); + } + tf = fopen(buf, "r"); + if (!tf) { + perror(buf); + unlink(buf); + exit(-1); + } + unlink(buf); + while (fgets(buf, sizeof(buf), tf)) { + char *p = strrchr(buf, '\n'); + if (p) + *p = '\0'; + if (buf[0] == 'Y') { + for (i = 0; i < indexSel.size(); i++) + if (!strcmp(indexSel[i].getName(), &buf[2])) + indexRestore.push_back(indexSel[i]); + } + } + fclose(tf); + } else { + for (i = 0; i < indexSel.size(); i++) + for (int j = 0; j < driveList.size(); j++) + if (*(indexSel[i].getName()) == driveList[j][0]) + indexRestore.push_back(indexSel[i]); + } + } else + cout << "Archive skipped, because it does not contain any files on selected drives" << endl; + } + if (!indexRestore.empty()) { + PlpDirent e(0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, archname); + for (i = 0; i < indexRestore.size(); i++) + toRestore.push_back(indexRestore[i]); + } +} + +static bool +askOverwrite(const char *name) +{ + return true; +} + +static int +cps(unsigned long size, struct timeval *start, struct timeval *end) +{ + double t = tdiff(start, end); + if (t == 0.0) + return 99999; + else + return (int)(((double)size) / t); +} + +static void +runRestore() +{ + unsigned int i; + char indexbuf[40]; ostrstream tarcmd; + string dstPath; + struct timeval start_tv, end_tv, cstart_tv, cend_tv, sstart_tv, send_tv; + for (i = 0; i < archList.size(); i++) { tarcmd << "tar --to-stdout -xzf " << archList[i] << " 'KPsion*Index'" << '\0'; + char backupType = '?'; FILE *f = popen(tarcmd.str(), "r"); - + if (!f) { + perror("Could not get backup index"); + continue; + } + fgets(indexbuf, sizeof(indexbuf), f); + if (!strncmp(indexbuf, "#plpbackup index ", 17)) + backupType = indexbuf[17]; + switch (backupType) { + case 'F': + cout << "'" << archList[i] << "' is a full backup" << endl; + collectIndex(f, archList[i].c_str()); + break; + case 'I': + cout << "'" << archList[i] << "' is a incremental backup" << endl; + collectIndex(f, archList[i].c_str()); + break; + default: + cerr << "'" << archList[i] << "' is NOT a plpbackup" << endl; + break; + } pclose(f); } + if (!toBackup.empty()) { + dstPath = ""; + backupSize = backupCount = 0; + // Calculate number of files and total bytecount + for (i = 0; i < toRestore.size(); i++) { + backupSize += toBackup[i].getSize(); + backupCount++; + } + // Stop all programs on Psion + stopPrograms(); + string dest; + string pDir; + for (i = 0; i < toBackup.size(); i++) { + PlpDirent e = toBackup[i]; + Enum<rfsv::errs> res; + u_int32_t handle; + struct timeval fstart_tv, fend_tv; + const char *fn = e.getName(); + + if ((e.getSize() == 0xdeadbeef) && (e.getAttr() == 0xdeadbeef) && + (e.getPsiTime().getPsiTimeLo() == 0xdeadbeef) && + (e.getPsiTime().getPsiTimeHi() == 0xdeadbeef)) { + if (!dstPath.empty()) + rmrf(dstPath.c_str()); + dstPath = generateTmpDir(); + tarcmd.flush(); + tarcmd << "tar xCf " << dstPath << " " << fn << '\0'; + system(tarcmd.str()); + } + if (checkAbort()) { + // remove temporary dir + rmrf(dstPath.c_str()); + // restart previously killed programs + startPrograms(); + cout << _("Restore aborted by user") << endl; + return; + } + dest = dstPath; + dest += '/'; + dest += psion2unix(fn); + fileSize = e.getSize(); + if (verbose > 1) + cout << _("Restore ") << fn << flush; + + string cpDir(fn); + int bslash = cpDir.rfind('\\'); + if (bslash != cpDir.npos) + cpDir.resize(bslash); + + if (pDir != cpDir) { + pDir = cpDir; + res = Rfsv->mkdir(pDir.c_str()); + if ((res != rfsv::E_PSI_GEN_NONE) && + (res != rfsv::E_PSI_FILE_EXIST)) { + cerr << "Could not create directory " << pDir << ": " + << res << endl; + continue; + } + } + + res = Rfsv->fcreatefile( + Rfsv->opMode(rfsv::PSI_O_RDWR), fn, handle); + if (res == rfsv::E_PSI_FILE_EXIST) { + if (!askOverwrite(fn)) + continue; + res = Rfsv->freplacefile( + Rfsv->opMode(rfsv::PSI_O_RDWR), fn, handle); + } + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not create " << fn << ": " << res << endl; + continue; + } + Rfsv->fclose(handle); + gettimeofday(&fstart_tv, NULL); + res = Rfsv->copyToPsion(dest.c_str(), fn, NULL, cab); + if (res == rfsv::E_PSI_GEN_NONE) { + u_int32_t oldattr; + res = Rfsv->fgetattr(fn, oldattr); + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not get attributes of " << fn << ": " << res << endl; + continue; + } + u_int32_t mask = e.getAttr() ^ oldattr; + u_int32_t sattr = e.getAttr() & mask; + u_int32_t dattr = ~sattr & mask; + int retry = 10; + // Retry, because file somtimes takes some time + // to close; + do { + res = Rfsv->fsetattr(fn, sattr, dattr); + if (res != rfsv::E_PSI_GEN_NONE) + usleep(100000); + retry--; + } while ((res != rfsv::E_PSI_GEN_NONE) && (retry > 0)); + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not set attributes of" << fn << ": " + << res << endl; + continue; + } + retry = 10; + do { + res = Rfsv->fsetmtime(fn, e.getPsiTime()); + if (res != rfsv::E_PSI_GEN_NONE) + usleep(100000); + retry--; + } while ((res != rfsv::E_PSI_GEN_NONE) && (retry > 0)); + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not set modification time of " << fn << ": " + << res << endl; + continue; + } + } + if (checkAbort()) { + // remove temporary dir + rmrf(dstPath.c_str()); + // restart previously killed programs + startPrograms(); + cout << _("Backup aborted by user") << endl; + return; + } + gettimeofday(&fend_tv, NULL); + if (verbose > 1) + cout << " " << cps(fileSize, &fstart_tv, &fend_tv) + << " CPS " << endl; + totalBytes += fileSize; + if (res != rfsv::E_PSI_GEN_NONE) { + if (skipError) { + e.setName("!"); + if (verbose > 0) + cerr << _("Skipping ") << fn << ": " + << res << endl; + } else { + cerr << _("Error during restore of ") << fn << ": " + << res << endl; + if (isatty(0)) { + bool askLoop = true; + do { + char answer; + string vans = _("STAR"); + + cerr << _("(S)kip all, Skip (t)his, (A)bort, (R)etry: ") + << flush; + cin >> answer; + switch (vans.find(toupper(answer))) { + case 0: + skipError = true; + // fall thru + case 1: + e.setName("!"); + askLoop = false; + break; + case 2: + i = toBackup.size(); + askLoop = false; + break; + case 3: + if (verbose > 1) + cout << _("Restore ") << fn << flush; + break; + res = Rfsv->copyFromPsion(fn, dest.c_str(), NULL, cab); + if (checkAbort()) { + // remove temporary dir + rmrf(dstPath.c_str()); + // restart previously killed programs + startPrograms(); + cout << _("Restore aborted by user") + << endl; + return; + } + if (verbose > 1) + cout << endl; + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << _("Error during restore of ") + << fn << ": " << res << endl; + } else + askLoop = false; + break; + } + } while (askLoop); + } else { + break; + } + } + } + } + } } static void @@ -539,7 +1031,7 @@ runBackup() if ((devbits & 1) && Rfsv->devinfo(i + 'A', psidr) == rfsv::E_PSI_GEN_NONE) { if (psidr.getMediaType() != 7) { - sprintf(drive, "%c:\0", 'A' + i); + sprintf(drive, "%c:", 'A' + i); if (verbose > 0) cout << _("Scanning Drive ") << drive << " ..." << flush; @@ -622,8 +1114,7 @@ runBackup() gettimeofday(&fend_tv, NULL); if (verbose > 1) cout << " " - << (int)((double)fileSize / tdiff(&fstart_tv, &fend_tv)) - << " CPS" << endl; + << cps(fileSize, &fstart_tv, &fend_tv) << " CPS" << endl; totalBytes += fileSize; if (res != rfsv::E_PSI_GEN_NONE) { if (skipError) { @@ -785,7 +1276,7 @@ runBackup() cout << _("Time for transfer: ") << tdiff(&cstart_tv, &cend_tv) << endl; cout << _("Average transfer speed: ") - << (double)backupSize / tdiff(&cstart_tv, &cend_tv) << endl; + << cps(backupSize, &cstart_tv, &cend_tv) << endl; } } } diff --git a/plpftp/ftp.cc b/plpftp/ftp.cc index 2ce30af..c94afc4 100644 --- a/plpftp/ftp.cc +++ b/plpftp/ftp.cc @@ -224,7 +224,9 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) if ((res = r.getOwnerInfo(b)) == rfsv::E_PSI_GEN_NONE) { r.getMachineType(machType); if (!once) { - cout << _("Connected to a ") << machType << _(", OwnerInfo:") << endl; + int speed = a.getSpeed(); + cout << _("Connected to a ") << machType << _(" at ") + << speed << _(" baud, OwnerInfo:") << endl; while (!b.empty()) cout << " " << b.pop().getString() << endl; cout << endl; @@ -765,9 +767,15 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv) continue; } // RPCS commands +#define EXPERIMENTAL #ifdef EXPERIMENTAL if (!strcmp(argv[0], "x")) { - r.regOpenIter(); + u_int16_t hhh; + if (r.regOpenIter(-1, "%PDF-", hhh) == rfsv::E_PSI_GEN_NONE) { + Enum<rfsv::errs> res; + while ((res = r.regReadIter(hhh)) == rfsv::E_PSI_GEN_NONE) + ;; + } continue; } if (!strcmp(argv[0], "y")) { |