home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / tcx / part01 < prev    next >
Encoding:
Text File  |  1993-04-03  |  53.2 KB  |  1,962 lines

  1. Newsgroups: comp.sources.misc
  2. From: slf@cs.mu.OZ.AU (Stewart Forster)
  3. Subject: v36i096:  tcx - Transparent Compressed Executables, v1.02, Part01/02
  4. Message-ID: <csm-v36i096=tcx.175155@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 24a2293c8edf10d7857ba228aaf52551
  6. Date: Sun, 4 Apr 1993 22:52:17 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: slf@cs.mu.OZ.AU (Stewart Forster)
  10. Posting-number: Volume 36, Issue 96
  11. Archive-name: tcx/part01
  12. Environment: SunOS, Ultrix, Irix
  13.  
  14. This is release 1.0.2 of TCX, being a system for transparently compressed 
  15. executables for Unix.  Current ports include SunOs, Ultrix, and Irix. This
  16. release fixes many of the common bugs reported on the first release which 
  17. was posted to alt.sources.  If you had problems with the original release,
  18. chances are, this will fix them.
  19.  
  20. TCX allows you to specify a compression algorithm to use when compressing 
  21. executables.  It allows for the transparent uncompression, execution and 
  22. recompression of executables compressed with the system.  Savings can be 
  23. in the range of 30-70% depending on executable and compression system type.  
  24. With GNU gzip v1+, savings are over 50% and often are at 70% on the operating
  25. systems listed above.
  26.  
  27. TCX is in current use at the University Of Melbourne, and so it is well
  28. supported, and continual improvements are being made as we need them, or
  29. as requests come in.  There is an effort to port TCX to Linux (not by me)
  30. and hopefully to other OS types soon.
  31.     
  32.             Stewart.
  33.  
  34. +-----------------------------------------------------------------------------+
  35. | Stewart Forster           Snr Systems Programmer - Dept of Computer Science |
  36. | Phone : +61 3 3444046        Richard Berry Bldng, The University Of Melbourne  |
  37. | Email : slf@cs.mu.OZ.AU   Parkville, 3052, Victoria, Australia.             |
  38. -----------------------------
  39. #! /bin/sh
  40. # This is a shell archive.  Remove anything before this line, then feed it
  41. # into a shell via "sh file" or similar.  To overwrite existing files,
  42. # type "sh file -c".
  43. # Contents:  README config.h tcx.c untcx.c
  44. # Wrapped by kent@sparky on Sun Apr  4 17:44:16 1993
  45. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  46. echo If this archive is complete, you will see the following message:
  47. echo '          "shar: End of archive 1 (of 2)."'
  48. if test -f 'README' -a "${1}" != "-c" ; then 
  49.   echo shar: Will not clobber existing file \"'README'\"
  50. else
  51.   echo shar: Extracting \"'README'\" \(5643 characters\)
  52.   sed "s/^X//" >'README' <<'END_OF_FILE'
  53. X    TCX - Transparently Compressed Executables (For Unix)
  54. X
  55. X                by
  56. X
  57. X       Stewart Forster, University Of Melbourne, 1993
  58. X
  59. XTCX is a system designed for the transparent decompression, execution
  60. Xand recompression of executables under Unix.  It allows configuration
  61. Xoptions such as the type of compression system used (compress(1),
  62. Xgzip(1), your own local system etc), timeouts between recompressions,
  63. Xand emergency directories in case a decompression fails from shortage
  64. Xof disk space.  The system is designed with a reasonable amount of
  65. Xrobustness in mind, such as in the event of system crashes, or races
  66. Xon trying to uncompress, compress or execute something.
  67. X
  68. X    Currently TCX is only proven to run on Irix 4.*, Ultrix 4.2
  69. Xor higher, and SunOs 4.1.1 or higher.  It may run on other releases
  70. Xof these OS's but has not been tested.  It should also be relatively
  71. Xeasy to port to other OS's as much of the code is fairly straight
  72. Xforward.
  73. X
  74. X    The system is used here at the Department of Computer Science
  75. XUniversity Of Melbourne, and in other departments on campus.  This is
  76. Xthe first official release of TCX to the world, so please feel free
  77. Xto comment or help in bug fixes and machine reports by sending email
  78. Xto slf@cs.mu.OZ.AU
  79. X
  80. X---------------------------------------------------------------------
  81. X
  82. X            INSTALLATION
  83. X
  84. XTCX is a small package with just the following files. If you don't
  85. Xhave these three file, get a complete distribution.
  86. X
  87. X        config.h
  88. X        tcx.c
  89. X        untcx.c
  90. X
  91. XFirst read the "FURTHER INFO" section below before configuring TCX
  92. Xfor your system, since it may influence some of your decisions.
  93. X
  94. XTo configure TCX, edit the config.h file.  There are enough directions
  95. Xtherein to help you configure for your system.  TCX relies on the
  96. Xcompression system you use to barf when the filesystem gets full
  97. Xand return a fail exit code.  If the compression system you use
  98. Xdoesn't do this, you run the risk of losing files. The GNU gzip
  99. Xpackage is known to do the correct safety checks and exit accordingly.
  100. XCompress may not under certain systems.
  101. X
  102. XOnce done editing the config file, edit the Makefile to set the C
  103. Xcompiler and libraries for your system, and compile.
  104. XDon't worry if your optimizer complains of no exit points in the
  105. Xprocedures called "check_tcxd_mode", "untcx_and_exec_local", and
  106. X"untcx_and_exec_nfs" when compiling untcx.c, these are normal.
  107. X
  108. XThe tcx, and untcx executables must be placed at the pathnames you
  109. Xspecified for them in config.h, if they are not there, the system
  110. Xwill NOT work. eg.
  111. X
  112. X    cp tcx /usr/local/bin/tcx
  113. X    cp untcx /usr/local/bin/untcx
  114. X
  115. XUntcx must also be installed setuid, so issue the following command.
  116. X
  117. X    chown root /usr/local/bin/untcx
  118. X    chmod 4711 /usr/local/bin/untcx     (or path you chose)
  119. X
  120. XDo not install the "tcx" executable setuid to anyone.
  121. X
  122. Xand copy the manual pages to your regular man directory and read them.
  123. X
  124. X    The installation is now complete.
  125. X
  126. X----------------------------------------------------------------------
  127. X
  128. X        TESTING YOUR INSTALLATION
  129. X
  130. XYou can now try running "tcx" on an innocuous executable to transform
  131. Xit, and then try running it.  Wait for the timeout interval you
  132. Xspecified (after disuse, which means not even reading the file) and it
  133. Xshould recompress.  If it doesn't recompress after about twice the
  134. Xinterval specified, check the following.
  135. X
  136. X1) Access times on the file. MAKE SURE it wasn't touched before suspecting
  137. X   something is wrong.
  138. X2) That the daemon mode for untcx started correctly.  The pid should be
  139. X   stored in ENFSDIR/.lock.  Assuming ENFSDIR is /tmp/exec as in the
  140. X   distributed config file, issue
  141. X
  142. X    ps `cat /tmp/exec/.lock`   and check that the daemon started.
  143. X
  144. X   If it didn't, there is a minor problem with permissions, or maybe
  145. X   you specified a read-only file system for ENFSDIR.
  146. X3) Check if you installed tcx where PATHTCX in the config file said
  147. X   where it was.
  148. X4) Check that the uncompressor is where PATHUNPACK in the the config
  149. X   file says it is.
  150. X5) If you're using the compress/uncompress system, it may be returning
  151. X   bad exit codes.  Try getting the GNU gzip compression package.
  152. X
  153. XIf all else comes to nought, look into the source code, or mail your
  154. Xsystem configuration and config file to slf@cs.mu.OZ.AU, and I'll
  155. Xtry and see what can be done.
  156. X
  157. X----------------------------------------------------------------------
  158. X
  159. X    FUTHER INFO / POTENTIAL BUGS
  160. X
  161. XThe compress(1) system had problems on Ultrix in that is was returning
  162. Xfailures when trying to decompress a tcx(1) executable. I was unable
  163. Xto pinpoint the source of the problem, and this problem may exist on
  164. Xother systems too. I STRONGLY recommend using the "gzip" package from
  165. XGNU as your compression system of choice, or at least for TCX, since
  166. Xit has much stronger error checking, and returns reliable exit codes.
  167. XGzip will compress from 10 to 40% better than compress, and is faster
  168. Xon uncompression, which is where the system becomes noticable to the
  169. Xuser in the effect of delays when an executable is run.
  170. X
  171. XUsers may experience a slight delay when a TCX executable is started up
  172. Xdue the decompression phase.  If this becomes a problem for large
  173. Xexecutables, you should probably discourage use of TCX on these huge
  174. Xbinaries.  The "gzip" system decompresses at around 500-700K/sec on the
  175. Xsystems I tested it on, which are all around the 25 SPECmark rating.
  176. X
  177. X----------------------------------------------------------------------
  178. X
  179. X        THANKS
  180. X
  181. XSpecial thanks go to Robert Elz, who provided invaluable input,
  182. Xsuggestions and clarifications on the whole idea.
  183. X
  184. XThanks also to Jeff Shultz who provided some potential "sticky" cases
  185. Xwhich gave me some more work to do (plus made tcx more robust).
  186. X
  187. X                Stewart.
  188. X
  189. END_OF_FILE
  190.   if test 5643 -ne `wc -c <'README'`; then
  191.     echo shar: \"'README'\" unpacked with wrong size!
  192.   fi
  193.   # end of 'README'
  194. fi
  195. if test -f 'config.h' -a "${1}" != "-c" ; then 
  196.   echo shar: Will not clobber existing file \"'config.h'\"
  197. else
  198.   echo shar: Extracting \"'config.h'\" \(7055 characters\)
  199.   sed "s/^X//" >'config.h' <<'END_OF_FILE'
  200. X/* config.h, Version 1.0.1, 25/3/1993 by Stewart Forster */
  201. X
  202. X/************************************************************************/
  203. X/*   Copyright (C) 1993 Stewart Forster                    */
  204. X/*  This program is free software; you can redistribute it and/or modify*/
  205. X/*  it under the terms of the GNU General Public License as published by*/
  206. X/*  the Free Software Foundation; either version 2, or (at your option) */
  207. X/*  any later version.                            */
  208. X/*                                    */
  209. X/*  This program is distributed in the hope that it will be useful,    */
  210. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  211. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  212. X/*  GNU General Public License for more details.            */
  213. X/*                                    */
  214. X/*  You should have received a copy of the GNU General Public License    */
  215. X/*  along with this program; if not, write to the Free Software        */
  216. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  217. X/************************************************************************/
  218. X
  219. X
  220. X/************************************************************************/
  221. X/*    OS TYPE DEFINITION                        */
  222. X/* Define one of the following where appropriate            */
  223. X/************************************************************************/
  224. X
  225. X/* #define    SUNOS        /* */
  226. X#define    IRIX        /* */
  227. X/* #define    ULTRIX        /* */
  228. X
  229. X/************************************************************************/
  230. X/* SUNOS requires the pstat command to be available.  This is part of     */
  231. X/* the SunOs distribution but fix this following path if it's wrong.    */
  232. X/************************************************************************/
  233. X
  234. X#ifdef SUNOS
  235. X#define    PSTATI    "/usr/etc/pstat -i"
  236. X#endif
  237. X
  238. X/************************************************************************/
  239. X/* PATHUNTCX is the pathname where the untcx executable resides.  Note    */
  240. X/* that this is the interpreter/unpacker and hence must exist with this    */
  241. X/* path, or else the whole system will fail! This path should also be on*/
  242. X/* a filesystem which the local system trusts setuid binaries from,    */
  243. X/* since PATHUNTCX must run setuid to root.                */
  244. X/************************************************************************/
  245. X
  246. X#define    PATHUNTCX    "/usr/local/bin/untcx"
  247. X
  248. X/************************************************************************/
  249. X/* PATHTCX is the pathname to the tcx executable.  This does not have to*/
  250. X/*  be installed setuid.                        */
  251. X/************************************************************************/
  252. X
  253. X#define    PATHTCX        "/usr/local/bin/tcx"
  254. X
  255. X/************************************************************************/
  256. X/* PATHPACKER is the pathname to the compression program you wish to use*/
  257. X/* with the system. PACKEROPTS is an optional definition of options you    */
  258. X/* wish to pass to the packer program. NB. The compression program must    */
  259. X/* be a `filter', that is, it is capable of reading from stdion and    */
  260. X/* compressing to stdout.                        */
  261. X/************************************************************************/
  262. X
  263. X#define    PATHPACKER    "/usr/local/bin/gzip"
  264. X/*#define    PACKEROPTS    "-7"            /* Optional */
  265. X
  266. X/************************************************************************/
  267. X/* PATHUNPACK and the optional UNPACKOPTS serve a similar purpose to    */
  268. X/* PATHPACKER and PACKEROPTS above. */
  269. X/************************************************************************/
  270. X
  271. X#define    PATHUNPACK    "/usr/local/bin/gzip"
  272. X#define    UNPACKOPTS    "-d"            /* Optional */
  273. X
  274. X/************************************************************************/
  275. X/* ENFSDIR is the pathname to the directory where emergency (out of disk*/
  276. X/* space locally) or NFS mounted executables get unpacked to.        */
  277. X/* On SUNOS, if you are using the "tmpfs", you will have to set ENFSDIR    */
  278. X/* to a "real disk". (A "real disk" may also be an NFS mounted partition*/
  279. X/* to which the machine has root access to).  There seems to be some    */
  280. X/* problem with fcntl locks on SUNOS tmpfs.                */
  281. X/************************************************************************/
  282. X
  283. X#define    ENFSDIR        "/tmp/exec"
  284. X
  285. X/************************************************************************/
  286. X/* SCANRATE is the interval in seconds which the tcx daemon waits before*/
  287. X/* rescanning all files it is currently managing, for recompression in    */
  288. X/* the case of local files, or deletion from ENFSDIR in the case of     */
  289. X/* emergency or NFS mounted executables.  Note that SCANRATE should    */
  290. X/* probably not be larger than ENFSTIMEOUT or LOCALTIMEOUT defined    */
  291. X/* below, otherwise you will undermine the purpose of those variables.    */
  292. X/************************************************************************/
  293. X
  294. X#define    SCANRATE    60        /* 60 seconds between scans */
  295. X
  296. X/************************************************************************/
  297. X/* ENFSTIMEOUT is the least number of seconds of disuse of an executable*/
  298. X/* residing in ENFSDIR the tcx daemon will wait for, before it attempts    */
  299. X/* to delete the executable. This should be set quite low if there isn't*/
  300. X/* much disk space available in ENFSDIR.                */
  301. X/* On SUNOS, this value only sets in after the inode is timed out of the*/
  302. X/* inode cache.  This problem will be addressed in a future release.    */
  303. X/************************************************************************/
  304. X
  305. X#define    ENFSTIMEOUT    60        /* 60 seconds of inactivity */
  306. X
  307. X/************************************************************************/
  308. X/* LOCALTIMEOUT is the least number of seconds of disuse of an        */
  309. X/* executable residing locally on the system that the tcx will wait    */
  310. X/* before attempting to repack the executable.                */
  311. X/* On SUNOS, this value only sets in after the inode is timed out of the*/
  312. X/* inode cache.  This problem will be addressed in a future release.    */
  313. X/************************************************************************/
  314. X
  315. X#define    LOCALTIMEOUT    1800        /* 30 minutes */
  316. X
  317. X
  318. X
  319. X
  320. X/************************************************************************/
  321. X/************************************************************************/
  322. X/* You should not need to edit anything after this point        */
  323. X/************************************************************************/
  324. X/************************************************************************/
  325. X
  326. X#define    MAXHEADERSIZE    256
  327. X
  328. X/* Define PUSLEEP (portable usleep definition)    */
  329. X
  330. X#ifdef    IRIX
  331. X#define _BSD_SIGNALS
  332. X#define    PUSLEEP(x)    (sginap((long)((x)/10000)))
  333. X#endif
  334. X
  335. X#ifdef    ULTRIX
  336. X#define    PUSLEEP(x)    (usleep(x))    /* usleep code in untcx.c */
  337. X#endif
  338. X
  339. X#ifdef    SUNOS
  340. X#define    PUSLEEP(x)    (usleep(x))
  341. X#endif
  342. X
  343. X#include    <stdlib.h>
  344. X#include        <unistd.h>
  345. X#include        <sys/time.h>
  346. X#include        <sys/wait.h>
  347. X#include        <sys/types.h>
  348. X
  349. X#ifdef ULTRIX
  350. X#include    <sys/param.h>
  351. X#include    <sys/mount.h>
  352. X#endif
  353. X
  354. X#ifdef IRIX
  355. X#include        <sys/statfs.h>
  356. X#endif
  357. X
  358. X#ifdef SUNOS
  359. X#include        <sys/vfs.h>
  360. X#endif
  361. X
  362. X#include        <sys/stat.h>
  363. X
  364. X#include    <fcntl.h>
  365. X#include        <string.h>
  366. X#include        <errno.h>
  367. X#include        <signal.h>
  368. X#include        <stdio.h>
  369. X
  370. X#if defined(SUNOS) || defined(ULTRIX)
  371. X#include    <utime.h>
  372. X#endif
  373. X
  374. X#ifndef    MAXPATHLEN
  375. X#define    MAXPATHLEN    1024
  376. X#endif
  377. END_OF_FILE
  378.   if test 7055 -ne `wc -c <'config.h'`; then
  379.     echo shar: \"'config.h'\" unpacked with wrong size!
  380.   fi
  381.   # end of 'config.h'
  382. fi
  383. if test -f 'tcx.c' -a "${1}" != "-c" ; then 
  384.   echo shar: Will not clobber existing file \"'tcx.c'\"
  385. else
  386.   echo shar: Extracting \"'tcx.c'\" \(8138 characters\)
  387.   sed "s/^X//" >'tcx.c' <<'END_OF_FILE'
  388. X/* tcx.c, Version 1.0.2, 25/3/1993 by Stewart Forster */
  389. X
  390. X/************************************************************************/
  391. X/*   Copyright (C) 1993 Stewart Forster                    */
  392. X/*  This program is free software; you can redistribute it and/or modify*/
  393. X/*  it under the terms of the GNU General Public License as published by*/
  394. X/*  the Free Software Foundation; either version 2, or (at your option) */
  395. X/*  any later version.                            */
  396. X/*                                    */
  397. X/*  This program is distributed in the hope that it will be useful,    */
  398. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  399. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  400. X/*  GNU General Public License for more details.            */
  401. X/*                                    */
  402. X/*  You should have received a copy of the GNU General Public License    */
  403. X/*  along with this program; if not, write to the Free Software        */
  404. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  405. X/************************************************************************/
  406. X
  407. X
  408. X#include    "config.h"
  409. X
  410. Xextern    int    errno;
  411. X
  412. Xint    main(int, char *[]);
  413. Xint    is_tcx(int);
  414. Xint    doencode(int, int);
  415. X
  416. X#ifdef ULTRIX
  417. Xint    is_file_local(char *);
  418. X#endif
  419. X
  420. Xint
  421. Xmain(int argc, char *argv[])
  422. X{
  423. Xstruct    stat    dostat;
  424. Xchar    *s;
  425. Xint    perms;
  426. Xint    infd, outfd;
  427. Xchar    tofile[MAXPATHLEN];
  428. Xchar    header[MAXHEADERSIZE];
  429. Xstruct    flock    lck;
  430. Xunsigned char c;
  431. X#ifdef ULTRIX
  432. Xint    islocal;
  433. X#endif
  434. X
  435. X    /* Check to make sure we have an argument */
  436. X
  437. X    if(argc < 2)
  438. X    {
  439. X        (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  440. X        exit(-1);
  441. X    }
  442. X
  443. X    /* Try to lstat first argument. If cannot, quit */
  444. X
  445. X    if(lstat(argv[1], &dostat) < 0)
  446. X    {
  447. X        perror(argv[1]);
  448. X        exit(-1);
  449. X    }
  450. X
  451. X    /* Make sure it's a regular file. If not, quit! */
  452. X
  453. X    if(!(dostat.st_mode & S_IFREG)||((dostat.st_mode & S_IFMT) == S_IFLNK))
  454. X    {
  455. X        (void)fprintf(stderr, "Error: %s is not a regular file\n", argv[1]);
  456. X        exit(-1);
  457. X    }
  458. X
  459. X    /* Check permissions on file, must not be setuid or setgid */
  460. X    /* Then check to see if it's an executable */
  461. X
  462. X    if(dostat.st_mode & (S_ISUID | S_ISGID))
  463. X    {
  464. X        (void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
  465. X        exit(-1);
  466. X    }
  467. X
  468. X    if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
  469. X    {
  470. X        (void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
  471. X        exit(-1);
  472. X    }
  473. X
  474. X#ifdef ULTRIX
  475. X    /* Test to see if file we are compressing is local or not */
  476. X
  477. X    if((islocal = is_file_local(argv[1])) < 0)
  478. X    {
  479. X        perror("statfs");
  480. X        exit(-1);
  481. X    }
  482. X#endif
  483. X
  484. X    /* Now open file we are compressing for reading. Quit if can't. */
  485. X
  486. X    if((infd = open(argv[1], O_RDONLY)) < 0)
  487. X    {
  488. X        perror(argv[1]);
  489. X        exit(-1);
  490. X    }
  491. X
  492. X    /* Check to make sure file is not already tcx'ed */
  493. X
  494. X    if(is_tcx(infd))
  495. X    {
  496. X        (void)fprintf(stderr, "%s is already in tcx format!\n", argv[1]);
  497. X        exit(0);
  498. X    }
  499. X
  500. X    if(lseek(infd, 0, SEEK_SET) < 0)
  501. X    {
  502. X        perror("lseek");
  503. X        exit(-1);
  504. X    }
  505. X
  506. X    /* Open generation file, and try to mimic permissions */
  507. X    /* If cannot, warn user and quit */
  508. X
  509. X    if(strrchr(argv[1], '/') == NULL)
  510. X        (void)sprintf(tofile, ".tcx.%s", argv[1]);
  511. X    else
  512. X    {
  513. X        (void)strcpy(tofile, argv[1]);
  514. X        s = strrchr(tofile, '/');
  515. X        *s = '\0';
  516. X        (void)strcat(tofile, "/.tcx.");
  517. X        s = strrchr(argv[1], '/');
  518. X        s++;
  519. X        (void)strcat(tofile, s);
  520. X    }
  521. X
  522. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  523. X
  524. X    perms = (dostat.st_mode & 0777);
  525. X    if(perms & S_IXUSR) perms |= S_IRUSR;
  526. X    if(perms & S_IXGRP) perms |= S_IRGRP;
  527. X    if(perms & S_IXOTH) perms |= S_IROTH;
  528. X    perms |= S_IWUSR;
  529. X
  530. X    /* Attempt to create scratch file */
  531. X    /* Ultrix barfs on F_SETLK if file is on an NFS mount. */
  532. X
  533. X    if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  534. X    {
  535. X#ifdef ULTRIX
  536. X        if(islocal == 0 || errno != EEXIST)
  537. X#else
  538. X        if(errno != EEXIST)
  539. X#endif
  540. X        {
  541. X            perror(tofile);
  542. X            exit(-1);
  543. X        }
  544. X
  545. X        /* Attempt to open and lock file that's there.  If we can't */
  546. X        /* lock the file, someone else must be packing it, so quit. */
  547. X        /* If we can, it must be bogus and left lying around after a*/
  548. X        /* crash, interrupt or something. Delete file and try again.*/
  549. X
  550. X        if((outfd = open(tofile, O_WRONLY)) < 0)
  551. X        {
  552. X            perror(tofile);
  553. X            exit(-1);
  554. X        }
  555. X
  556. X        if(fcntl(outfd, F_SETLK, &lck) < 0)
  557. X            exit(-1);
  558. X
  559. X        (void)unlink(tofile);    /* Unlink. Don't care if fails yet */
  560. X        (void)close(outfd);
  561. X        if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  562. X        {
  563. X            perror(tofile);
  564. X            exit(-1);
  565. X        }
  566. X    }
  567. X
  568. X    /* Attempt to lock tofile.  If can't then assume someone else */
  569. X    /* is in the process of packing this file, so quit. */
  570. X    /* Only try to lock on ULTRIX if file is local.  If not, risk */
  571. X    /* the race condition, we have no choice!. */
  572. X
  573. X#ifdef ULTRIX
  574. X    if(islocal == 1)
  575. X#endif
  576. X        if(fcntl(outfd, F_SETLK, &lck) < 0)
  577. X            exit(-1);
  578. X
  579. X    /* Do a chmod (Just to be sure - in case of user umask affecting open) */
  580. X
  581. X    if(chmod(tofile, perms) < 0)
  582. X    {
  583. X        (void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
  584. X        (void)close(infd);
  585. X        (void)close(outfd);
  586. X        if(unlink(tofile) < 0)
  587. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  588. X        exit(-1);
  589. X    }
  590. X
  591. X    if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
  592. X    {
  593. X        (void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
  594. X        (void)close(infd);
  595. X        (void)close(outfd);
  596. X        if(unlink(tofile) < 0)
  597. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  598. X        exit(-1);
  599. X    }
  600. X
  601. X    /* Spit out header and start encoding executable */
  602. X
  603. X    (void)sprintf(header, "#!%s\n", PATHUNTCX);
  604. X    if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
  605. X
  606. X    c = 0;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  607. X    c = 76;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  608. X    c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  609. X    c = 13;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  610. X    c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  611. X
  612. X    if(doencode(infd, outfd) != 0)
  613. X    {
  614. X        (void)fprintf(stderr, "Compression failed\n");
  615. X        if(unlink(tofile) < 0)
  616. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  617. X        exit(-1);
  618. X    }
  619. X
  620. X    (void)close(infd);
  621. X
  622. X    if((infd = open(argv[1], O_WRONLY)) <= 0)
  623. X    {
  624. X        perror(argv[1]);
  625. X        if(unlink(tofile) < 0)
  626. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  627. X        exit(-1);
  628. X    }
  629. X
  630. X#ifdef ULTRIX
  631. X    if(islocal == 1)
  632. X#endif
  633. X        if(fcntl(infd, F_SETLK, &lck) < 0)
  634. X        {
  635. X            if(unlink(tofile) < 0)
  636. X                (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  637. X            exit(-1);
  638. X        }
  639. X
  640. X    /* Rename() compressed version to original */
  641. X
  642. X    if(rename(tofile, argv[1]) < 0)
  643. X    {
  644. X        perror(argv[1]);
  645. X        if(unlink(tofile) < 0)
  646. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  647. X        exit(-1);
  648. X    }
  649. X
  650. X    /* Close files and hence locks */
  651. X
  652. X    (void)close(infd);
  653. X    (void)close(outfd);
  654. X
  655. X    /* All done! Bye, bye. */
  656. X
  657. X    return(0);
  658. X}
  659. X
  660. X
  661. Xint
  662. Xis_tcx(int fd)
  663. X{
  664. Xint     i;
  665. Xunsigned char   c;
  666. X
  667. X        for(i = 0; i < MAXHEADERSIZE; i++)
  668. X                if(read(fd, &c, 1) < 1 || c == 0)
  669. X                        break;
  670. X        if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  671. X            || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  672. X                return 0;
  673. X        return 1;
  674. X} /* is_tcx */
  675. X
  676. X
  677. Xint
  678. Xdoencode(int infd, int outfd)
  679. X{
  680. Xint    pid;
  681. Xunion    wait    status;
  682. X
  683. X    pid = fork();
  684. X    if(pid < 0) return -1;
  685. X    if(pid == 0)
  686. X    {
  687. X        if(dup2(infd, 0) < 0)    exit(-1);    /* Attach infd to stdin */
  688. X        (void)close(infd);
  689. X        if(dup2(outfd, 1) < 0)    exit(-1);    /* Attach outfd to stdout */
  690. X        (void)close(outfd);
  691. X#ifdef PACKEROPTS
  692. X        (void)execl(PATHPACKER, "packer", PACKEROPTS, (char *)0);
  693. X#else
  694. X        (void)execl(PATHPACKER, "packer", (char *)0);
  695. X#endif
  696. X        exit(-1);
  697. X    }
  698. X    else
  699. X        pid = wait(&status);
  700. X    return WEXITSTATUS(status);
  701. X} /* doencode */
  702. X
  703. X
  704. X#ifdef ULTRIX
  705. Xint
  706. Xis_file_local(char *path)
  707. X{
  708. Xstruct  fs_data fsbuf;
  709. X
  710. X        if(statfs(path, &fsbuf) < 1)     /* Returns 0 on "NOT MOUNTED" */
  711. X                return -1;
  712. X
  713. X        /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
  714. X        /* to a client, so return false on this condition. */
  715. X
  716. X        if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  717. X                return 0;
  718. X    return 1;
  719. X} /* is_file_local */
  720. X#endif
  721. END_OF_FILE
  722.   if test 8138 -ne `wc -c <'tcx.c'`; then
  723.     echo shar: \"'tcx.c'\" unpacked with wrong size!
  724.   fi
  725.   # end of 'tcx.c'
  726. fi
  727. if test -f 'untcx.c' -a "${1}" != "-c" ; then 
  728.   echo shar: Will not clobber existing file \"'untcx.c'\"
  729. else
  730.   echo shar: Extracting \"'untcx.c'\" \(27702 characters\)
  731.   sed "s/^X//" >'untcx.c' <<'END_OF_FILE'
  732. X/* untcx.c, Version 1.0.2, 27/3/1993 by Stewart Forster */
  733. X
  734. X/************************************************************************/
  735. X/*   Copyright (C) 1993 Stewart Forster                    */
  736. X/*  This program is free software; you can redistribute it and/or modify*/
  737. X/*  it under the terms of the GNU General Public License as published by*/
  738. X/*  the Free Software Foundation; either version 2, or (at your option) */
  739. X/*  any later version.                            */
  740. X/*                                    */
  741. X/*  This program is distributed in the hope that it will be useful,    */
  742. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  743. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  744. X/*  GNU General Public License for more details.            */
  745. X/*                                    */
  746. X/*  You should have received a copy of the GNU General Public License    */
  747. X/*  along with this program; if not, write to the Free Software        */
  748. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  749. X/************************************************************************/
  750. X
  751. X#include    "config.h"
  752. X
  753. Xtypedef struct path
  754. X{
  755. X    char    path[MAXPATHLEN]; /* Pathname to file */
  756. X    int    pid;        /* Process id compressing file */
  757. X    int    local;        /* Is file local? */
  758. X    int    ctime;        /* Inode modification time */
  759. X    struct    path    *next;    /* Next structure */
  760. X} path;
  761. X
  762. X#if defined(SUNOS)
  763. X#define    MAXOPENFILES    4096
  764. X#define    PIHASH(a, b)    (((a) + (b)) % MAXOPENFILES)
  765. X
  766. Xtypedef struct pstat
  767. X{
  768. X    int    dev;
  769. X    int    ino;
  770. X    int    cnt;
  771. X    struct    pstat    *next;
  772. X} pstat;
  773. X
  774. Xpstat    parr[MAXOPENFILES];
  775. Xpstat    *pihash[MAXOPENFILES];
  776. Xvoid    update_pstat_info();
  777. X#endif
  778. X
  779. Xextern    int    errno;
  780. Xpath    *worklist = NULL, *freelist = NULL;
  781. X
  782. X
  783. Xchar    logpath[MAXPATHLEN], logtmppath[MAXPATHLEN], lockpath[MAXPATHLEN];
  784. X
  785. Xvoid    untcx_and_exec_local(char *, char *, char *[]);
  786. Xvoid    untcx_and_exec_nfs(char *, char *, char *, char *[]);
  787. Xint    try_to_exec(char *, char *[]);
  788. Xvoid    check_tcxd_mode();
  789. Xint    tcxd_reaper();
  790. Xvoid    just_untcx(char *, char *);
  791. Xint    scan_logtail(int);
  792. Xint    is_dir_local(char *);
  793. Xint    is_tcx(int);
  794. Xint    dodecode(int, int);
  795. Xchar    *newargs[1024];
  796. X#ifdef ULTRIX
  797. Xint    usleep(int);
  798. Xint    usleep_sig();
  799. X#endif
  800. X
  801. Xint
  802. Xmain(int argc, char *argv[])
  803. X{
  804. Xchar    cwd[MAXPATHLEN];    /* Save of current working directory */
  805. Xchar    realdir[MAXPATHLEN];    /* Real directory packed executable lives in */
  806. Xchar    execname[MAXPATHLEN];    /* Name of packed/target executable */
  807. Xchar    execpath[MAXPATHLEN];    /* Full path name of packed executable */
  808. Xchar    untcxtmp[MAXPATHLEN];    /* Temporary unpack pathname */
  809. Xchar    tcxtarg[MAXPATHLEN];    /* Target path name of unpacked executable */
  810. Xchar    *c;            /* String manipulation pointers */
  811. Xstruct    stat    dostat;    /* Stat buffer */
  812. Xint    i, local, isinterp;
  813. X
  814. X    if(argc < 2)
  815. X    {
  816. X        (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  817. X        exit(-1);
  818. X    }
  819. X
  820. X    /* Re-exec if not root and pass -x along on the command line. */
  821. X    /* If it's there when we restart and we're still not root, then */
  822. X    /* avoid an exec loop by quitting with a warning. */
  823. X
  824. X    if(geteuid() != 0)
  825. X    {
  826. X        if(strcmp(argv[1], "-x") == 0)
  827. X        {
  828. X            (void)fprintf(stderr, "Error: untcx is not installed setuid!\n");
  829. X            (void)fprintf(stderr, "Contact your systems administrator\n");
  830. X            exit(-1);
  831. X        }
  832. X
  833. X        /* Push -x into argv[1] and shift rest of args along */
  834. X
  835. X        newargs[0] = argv[0];
  836. X        newargs[1] = "-x";
  837. X        for(i = 1; i < argc; i++) newargs[i+1] = argv[i];
  838. X        newargs[i + 1] = (char *)NULL;
  839. X        if(execv(PATHUNTCX, newargs) < 0)
  840. X            perror("exec");
  841. X
  842. X        /* exec failed! Warn user and quit */
  843. X
  844. X        (void)fprintf(stderr, "Unable to invoke interpreter as root\n");
  845. X        exit(-1);
  846. X    }
  847. X
  848. X    if(strcmp(argv[1], "-x") == 0)
  849. X    {
  850. X        for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  851. X        argv[i] = (char *)NULL;
  852. X        --argc;
  853. X        isinterp = 1;
  854. X    }
  855. X    else
  856. X    if(strcmp(argv[1], "-u") == 0)
  857. X    {
  858. X        for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  859. X        argv[i] = (char *)NULL;
  860. X        --argc;
  861. X        isinterp = 0;
  862. X    }
  863. X    else
  864. X    if(getuid() == 0)
  865. X        isinterp = 1;
  866. X    else
  867. X        isinterp = 0;
  868. X
  869. X    /* Copy argv[1] to argv[0] for obsolete stuff (and IRIX) */
  870. X
  871. X    argv[0] = argv[1];
  872. X
  873. X    /* Setup to catch all undesirable signals */
  874. X
  875. X    (void)signal(SIGINT, SIG_IGN);
  876. X    (void)signal(SIGHUP, SIG_IGN);
  877. X    (void)signal(SIGTSTP, SIG_IGN);
  878. X    (void)signal(SIGALRM, SIG_IGN);
  879. X    (void)signal(SIGQUIT, SIG_IGN);
  880. X    (void)signal(SIGTERM, SIG_IGN);
  881. X
  882. X    /* Set global paths */
  883. X
  884. X    (void)sprintf(logpath, "%s/log", ENFSDIR);
  885. X    (void)sprintf(logtmppath, "%s/logtmp", ENFSDIR);
  886. X    (void)sprintf(lockpath, "%s/.lock", ENFSDIR);
  887. X
  888. X    /* Check and start tcxd as required */
  889. X
  890. X    check_tcxd_mode();
  891. X
  892. X    /* Go to the uid of invoking user.  Resolve through symbolic links */
  893. X    /* as to what the real pathname of the executable is. */
  894. X
  895. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  896. X
  897. X    /* Grab argv[0] and resolve to full path name via getwd() */
  898. X
  899. X    if(getwd(cwd) == NULL)
  900. X    {
  901. X        (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  902. X        exit(-1);
  903. X    }
  904. X
  905. X    if(*argv[0] == '/')
  906. X        (void)strcpy(realdir, argv[0]);
  907. X    else
  908. X        (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
  909. X    for(;;)
  910. X    {
  911. X        if((c = strrchr(realdir, '/')) == NULL)
  912. X        {    /* Should never happen, BUT... */
  913. X            (void)fprintf(stderr, "Help! Internal corruption of variables!\n");
  914. X            exit(-1);
  915. X        }
  916. X        c++;
  917. X        (void)strcpy(execname, c);
  918. X        *c = '\0';
  919. X
  920. X        if(chdir(realdir) < 0)    /* Oops. Failed. Report and quit. */
  921. X        {
  922. X            perror(realdir);
  923. X            exit(-1);
  924. X        }
  925. X
  926. X        if(getwd(realdir) == NULL)
  927. X        {
  928. X            (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  929. X            exit(-1);
  930. X        }
  931. X
  932. X        /* Do lstat executable from here. If not a link, go on, else */
  933. X        /* read the value of the link, and append it to realdir if */
  934. X        /* it doesn't begin with a /, other just copy it to realdir */
  935. X        /* and cycle through the loop again. */
  936. X
  937. X        if(lstat(execname, &dostat) < 0)
  938. X        {
  939. X            perror(execname);
  940. X            exit(-1);
  941. X        }
  942. X
  943. X        if((dostat.st_mode & S_IFMT) == S_IFLNK)
  944. X        {
  945. X            if(readlink(execname, execpath, MAXPATHLEN) < 0)
  946. X            {
  947. X                perror(execname);
  948. X                exit(-1);
  949. X            }
  950. X            if(execpath[0] == '/')
  951. X                (void)strcpy(realdir, execpath);
  952. X            else
  953. X            {
  954. X                (void)strcat(realdir, "/");
  955. X                (void)strcat(realdir, execpath);
  956. X            }
  957. X            continue;
  958. X        }
  959. X
  960. X        if(!(dostat.st_mode & S_IFREG))
  961. X        {
  962. X            (void)fprintf(stderr, "Error: Not an executable file - %s/%s\n", realdir, execname);
  963. X            exit(-1);
  964. X        }
  965. X
  966. X        /* Now do a statfs on realdir.  If it's on an NFS mounted filesystem we */
  967. X        /* will need to unpack to ENFSDIR, otherwise we can unpack it in place, */
  968. X        /* fsbuf.f_fstyp tells what filesystem type we're on.  For IRIX this */
  969. X        /* appears to be 1 for NFS, and 3 for local based filesystems.  I could */
  970. X        /* not find any documentation on this issue, so until a more portable */
  971. X        /* method is found, I'll be using these two numbers. */
  972. X
  973. X        if((local = is_dir_local(realdir)) < 0)
  974. X            exit(-1);
  975. X
  976. X        break;
  977. X    }
  978. X
  979. X    /* Return to the original invocation directory */
  980. X
  981. X    if(chdir(cwd) < 0)    /* Oops. Failed again! Try as user again! */
  982. X    {
  983. X        perror(cwd);
  984. X        exit(-1);
  985. X    }
  986. X
  987. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  988. X
  989. X    /* Now check if last components of argv[0] and argv[1] are equal */
  990. X    /* If not, we are invoked just to decompress something, not to */
  991. X    /* execute it.  Just attempt an uncompress as the user */
  992. X
  993. X    if(isinterp == 0)
  994. X    {
  995. X#if defined(IRIX)
  996. X        if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  997. X#else
  998. X        if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  999. X#endif
  1000. X        (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  1001. X        (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  1002. X        just_untcx(tcxtarg, untcxtmp);
  1003. X        exit(0);
  1004. X    }
  1005. X
  1006. X    /* Try to do a local execute. If it returns, it means failure. */
  1007. X
  1008. X    if(local)
  1009. X    {
  1010. X        (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  1011. X        (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  1012. X        untcx_and_exec_local(tcxtarg, untcxtmp, &(argv[1]));
  1013. X    }
  1014. X
  1015. X    /* We get this far if file is not local, or the local execution */
  1016. X    /* failed for some reason like shortage of disk space. Attempt */
  1017. X    /* to unpack program to /tmp and go from there. */
  1018. X
  1019. X    for(c = realdir; *c ; c++)
  1020. X        if(*c == '/')
  1021. X            *c = '=';
  1022. X    (void)sprintf(tcxtarg, "%s/%s", ENFSDIR, realdir);
  1023. X    if(mkdir(tcxtarg, 0777) < 0)
  1024. X        if(errno != EEXIST)
  1025. X        {
  1026. X            perror(tcxtarg);
  1027. X            exit(-1);
  1028. X        }
  1029. X    (void)chmod(tcxtarg, 0777);
  1030. X    (void)strcat(tcxtarg,"/");
  1031. X    (void)strcat(tcxtarg, execname);
  1032. X    (void)sprintf(untcxtmp, "%s/%s/.untcx.%s", ENFSDIR, realdir, execname);
  1033. X
  1034. X    untcx_and_exec_nfs(argv[0], untcxtmp, tcxtarg, &(argv[1]));
  1035. X
  1036. X    /* :-(  We only get this far if everything has failed. Exit with failure */
  1037. X
  1038. X    return(-1);
  1039. X} /* main */
  1040. X
  1041. X
  1042. Xvoid
  1043. Xcheck_tcxd_mode()
  1044. X{
  1045. Xchar    *s, spid[32];
  1046. Xint    infd, logfd, lkfd, lasttime = 0, timer;
  1047. XFILE    *logfp;
  1048. Xpath    *curr, *prev;
  1049. Xstruct    stat    sb;    /* Stat buffer */
  1050. Xstruct    flock    lck;    /* File lock structure */
  1051. Xstruct    utimbuf    times;
  1052. Xint    lastoff;
  1053. X#if defined(SUNOS)
  1054. Xpstat    *pc;        /* Hash/search pointer for SUNOS */
  1055. Xint    found;
  1056. X#endif
  1057. X
  1058. X    /* Check if we're root. If not, go home */
  1059. X
  1060. X    if(geteuid() != 0)
  1061. X        return;
  1062. X
  1063. X    /* Try to create emergency/NFS execute directory and set it's permissions */
  1064. X    /* It's not important yet if we can't at this stage. */
  1065. X
  1066. X    (void)mkdir(ENFSDIR, 01777);
  1067. X    (void)chmod(ENFSDIR, 01777);
  1068. X
  1069. X    /* Attempt to create ENFSDIR/.lock  If can't, just return. */
  1070. X
  1071. X    if((lkfd = open(lockpath, O_CREAT | O_RDONLY, 0600)) < 0)
  1072. X        return;
  1073. X
  1074. X    /* Attempt to read lock ENFSDIR/.lock If can't, we assume the tcxd */
  1075. X    /* is already running. Return. */
  1076. X
  1077. X    lck.l_type = F_RDLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1078. X    if(fcntl(lkfd, F_SETLK, &lck) < 0)
  1079. X    {
  1080. X        (void)close(lkfd);
  1081. X        return;
  1082. X    }
  1083. X
  1084. X    /* Close lkfd and hence the lock on it, fork() and return */
  1085. X
  1086. X    (void)close(lkfd);
  1087. X    if(fork() != 0)    /* On parent or fork error, just return */
  1088. X        return;
  1089. X
  1090. X    /* No errors to user at this point */
  1091. X
  1092. X    (void)fclose(stderr);
  1093. X    (void)close(2);
  1094. X    (void)open("/dev/null", O_WRONLY);    /* Don't really care */
  1095. X
  1096. X    /* Make ourselves nice and rooted */
  1097. X
  1098. X#if defined(IRIX)
  1099. X    if(setuid(geteuid()) < 0) exit(-1);
  1100. X#else
  1101. X    if(setreuid(geteuid(), geteuid()) < 0) exit(-1);
  1102. X#endif
  1103. X
  1104. X    /* Check if we're root again. If not, exit */
  1105. X
  1106. X    if(geteuid() != 0)
  1107. X        exit(-1);
  1108. X
  1109. X    /* Change directory to ENFSDIR to prevent hanging on NFS server crashes */
  1110. X
  1111. X    if(chdir(ENFSDIR) < 0)
  1112. X        exit(-1);
  1113. X
  1114. X    /* Lock the server lock file to prevent more than 1 starting up */
  1115. X
  1116. X    if((lkfd = open(lockpath, O_WRONLY | O_TRUNC)) < 0)
  1117. X        exit(-1);
  1118. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1119. X    if(fcntl(lkfd, F_SETLK, &lck) < 0)
  1120. X        exit(-1);
  1121. X
  1122. X    /* Write our process id to the lock file. Don't really care if fails. */
  1123. X
  1124. X    (void)sprintf(spid, "%d\n", getpid());
  1125. X    (void)write(lkfd, spid, strlen(spid));
  1126. X
  1127. X    /* setup our child process reaper */
  1128. X
  1129. X    (void)signal(SIGCHLD, tcxd_reaper);
  1130. X
  1131. X    /* Read in log file if it's there in case of crashes */
  1132. X
  1133. X    if((lastoff = scan_logtail(0)) < 0)
  1134. X        (void)creat(logpath, 0600);
  1135. X
  1136. X    /* Loop doing tasks at hand */
  1137. X
  1138. X    for(;;)
  1139. X    {
  1140. X        /* Before starting loop, logfp should be open for reading */
  1141. X        /* at end of log file. */
  1142. X
  1143. X        lastoff = 0;
  1144. X        for(timer = 0; timer < SCANRATE; timer++, (void)sleep(1))
  1145. X        {
  1146. X            if(stat(logpath, &sb) < 0)
  1147. X                continue;
  1148. X
  1149. X            /* Don't check if not updated, but do on last time */
  1150. X
  1151. X            if(sb.st_mtime <= lasttime)
  1152. X                continue;
  1153. X            lasttime = sb.st_mtime;
  1154. X
  1155. X            lastoff = scan_logtail(lastoff);
  1156. X        }
  1157. X
  1158. X#if defined(SUNOS)
  1159. X        update_pstat_info();
  1160. X#endif
  1161. X
  1162. X        for(prev = NULL, curr = worklist; curr != NULL; prev = curr, curr = curr->next)
  1163. X        {
  1164. X            /* Stat file. If not accessed within last 30 minutes */
  1165. X            /* we consider it a candidate for compression */
  1166. X
  1167. X            if(stat(curr->path, &sb) < 0)
  1168. X            {
  1169. X                (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1170. X                curr->next = freelist; freelist = curr;
  1171. X                (prev == NULL) ? (curr = worklist) : (curr = prev);
  1172. X                if(curr == NULL) break;
  1173. X                continue;
  1174. X            }
  1175. X
  1176. X            if(curr->local==1 && (time(NULL) - sb.st_atime) < LOCALTIMEOUT)
  1177. X                    continue;
  1178. X            if(curr->local == 0 && (time(NULL) - sb.st_atime) < ENFSTIMEOUT)
  1179. X                    continue;
  1180. X
  1181. X            /* Open file for reading and test if readlock exists */
  1182. X            /* If not, then if file is local, recompress it */
  1183. X            /* otherwise, unlink it from the ENFSDIR home */
  1184. X
  1185. X#if defined(IRIX) || defined(DEC)
  1186. X            if((infd = open(curr->path, O_WRONLY)) < 0)
  1187. X            {
  1188. X                if(errno != ETXTBSY)
  1189. X                {
  1190. X                    (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1191. X                    curr->next = freelist; freelist = curr;
  1192. X                    (prev == NULL) ? (curr = worklist) : (curr = prev);
  1193. X                    if(curr == NULL) break;
  1194. X                    continue;
  1195. X                }
  1196. X                times.actime = time(NULL);
  1197. X                times.modtime = sb.st_mtime;
  1198. X                (void)utime(curr->path, ×);
  1199. X                continue;
  1200. X            }
  1201. X            (void)close(infd);
  1202. X#endif
  1203. X
  1204. X#if defined(SUNOS)
  1205. X            found = 0;
  1206. X            for(pc = pihash[PIHASH(sb.st_dev, sb.st_ino)]; pc != NULL; pc = pc->next)
  1207. X                if(pc->dev == sb.st_dev && pc->ino == sb.st_ino)
  1208. X                {
  1209. X                    if(pc->cnt < 2) break;
  1210. X                    times.actime = time(NULL);
  1211. X                    times.modtime = sb.st_mtime;
  1212. X                    (void)utime(curr->path, ×);
  1213. X                    found = 1;
  1214. X                    break;
  1215. X                }
  1216. X            if(found) continue;
  1217. X#endif
  1218. X
  1219. X            if(curr->local == -1)    /* Compression completed */
  1220. X            {
  1221. X                (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1222. X                curr->next = freelist; freelist = curr;
  1223. X                (prev == NULL) ? (curr = worklist) : (curr = prev);
  1224. X                if(curr == NULL) break;
  1225. X                continue;
  1226. X            }
  1227. X
  1228. X            if(curr->pid > 0) continue;
  1229. X
  1230. X            if(curr->local == 1)
  1231. X            {
  1232. X                /* Check inode modification times. If target is */
  1233. X                /* newer than what we know, forget it. */
  1234. X
  1235. X                if(sb.st_ctime > curr->ctime)
  1236. X                {
  1237. X                    (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1238. X                    curr->next = freelist; freelist = curr;
  1239. X                    (prev == NULL) ? (curr = worklist) : (curr = prev);
  1240. X                    if(curr == NULL) break;
  1241. X                    continue;
  1242. X                }
  1243. X
  1244. X                /* Fork and compress program */
  1245. X
  1246. X                curr->pid = fork();
  1247. X                if(curr->pid != 0) continue;
  1248. X
  1249. X                /* Here we must be the child */
  1250. X                /* Close stdio stuff and reopen to /dev/null */
  1251. X
  1252. X                (void)close(2);
  1253. X                (void)close(1);
  1254. X                (void)close(0);
  1255. X                (void)open("/dev/null", O_RDONLY);
  1256. X                (void)open("/dev/null", O_WRONLY);
  1257. X                (void)open("/dev/null", O_WRONLY);
  1258. X                (void)execl(PATHTCX, "tcx", curr->path, (char *)0);
  1259. X                exit(-1);
  1260. X            }
  1261. X
  1262. X            /* At this point, file is in ENFSDIR. Delete it */
  1263. X
  1264. X            (void)unlink(curr->path);
  1265. X            s = strrchr(curr->path, '/');
  1266. X            *s = '\0';
  1267. X            (void)rmdir(curr->path);
  1268. X
  1269. X            (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1270. X            curr->next = freelist; freelist = curr;
  1271. X            (prev == NULL) ? (curr = worklist) : (curr = prev);
  1272. X            if(curr == NULL) break;
  1273. X        } /* for */
  1274. X
  1275. X        /* Update log file in case of crashes */
  1276. X
  1277. X        lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1278. X
  1279. X        /* Do one final read in case someone has modified during */
  1280. X        /* the scan sequence. */
  1281. X
  1282. X        (void)scan_logtail(lastoff);
  1283. X
  1284. X        if((logfp = fopen(logtmppath, "w")) == NULL)
  1285. X            continue;
  1286. X        for(curr = worklist; curr != NULL; curr = curr->next)
  1287. X            (void)fprintf(logfp, "%s\n", curr->path);
  1288. X        (void)fclose(logfp);
  1289. X
  1290. X        /* Try for 20 times to lock file, sleep 5/100ths secs b/w tries */
  1291. X
  1292. X        for(timer = 0; timer < 20; timer++, PUSLEEP(50000))
  1293. X        {
  1294. X            if((logfd = open(logpath, O_WRONLY)) < 0)
  1295. X                continue;
  1296. X            if(fcntl(logfd, F_SETLK, &lck) < 0)
  1297. X            {    (void)close(logfd); continue;    }
  1298. X
  1299. X            (void)rename(logtmppath, logpath);
  1300. X            (void)close(logfd);
  1301. X            break;
  1302. X        }
  1303. X    } /* for */
  1304. X} /* check_tcxd_mode */
  1305. X
  1306. X
  1307. Xint
  1308. Xtcxd_reaper()
  1309. X{
  1310. Xunion    wait    state;
  1311. Xint    pid;
  1312. Xpath    *curr;
  1313. X
  1314. X    while((pid = wait3(&state, WNOHANG, 0)) > 0)
  1315. X        for(curr = worklist; curr != NULL; curr = curr->next)
  1316. X            if(curr->pid == pid)
  1317. X            {
  1318. X                curr->pid = -1;
  1319. X                if(WIFEXITED(state) && WEXITSTATUS(state) == 0)
  1320. X                    curr->local = -1;
  1321. X                break;
  1322. X            }
  1323. X} /* tcxd_reaper */
  1324. X
  1325. X
  1326. Xvoid
  1327. Xuntcx_and_exec_local(char *execpath, char *untcxtmp, char *argv[])
  1328. X{
  1329. Xstruct    stat    tostat;    /* Stat buffer to check on lengths */
  1330. Xint    owner, group;
  1331. Xint    perms;        /* Saved permissions to restore on target exec */
  1332. Xint    infd, outfd;    /* In and out file descriptors */
  1333. Xstruct    flock    lck;    /* File lock structure */
  1334. X
  1335. X    /* Stat executable and grab permissions */
  1336. X
  1337. X    if(stat(execpath, &tostat) < 0)
  1338. X    {
  1339. X        perror(argv[0]);
  1340. X        exit(-1);
  1341. X    }
  1342. X    perms = (tostat.st_mode & 0777);
  1343. X    owner = tostat.st_uid;
  1344. X    group = tostat.st_gid;
  1345. X
  1346. X    for(;;PUSLEEP(10000))
  1347. X    {
  1348. X        if((infd = open(execpath, O_RDWR)) < 0)
  1349. X        {
  1350. X            if(errno != ETXTBSY)
  1351. X            {
  1352. X                (void)fprintf(stderr, "Cannot write to %s\n", execpath);
  1353. X                exit(-1);
  1354. X            }
  1355. X            if((infd = open(execpath, O_RDONLY)) < 0)
  1356. X                continue;
  1357. X            (void)close(infd);
  1358. X            if(try_to_exec(execpath, argv) < 0)
  1359. X                exit(-1);
  1360. X            continue;
  1361. X        }
  1362. X
  1363. X        lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1364. X        if(fcntl(infd, F_SETLK, &lck) < 0)
  1365. X        {
  1366. X            if(fcntl(infd, F_GETLK, &lck) < 0 || lck.l_type != F_RDLCK)
  1367. X            { (void)close(infd); continue; }
  1368. X            (void)close(infd);
  1369. X            if(try_to_exec(execpath, argv) < 0)
  1370. X                exit(-1);
  1371. X            continue;
  1372. X        }
  1373. X
  1374. X        if(! is_tcx(infd))
  1375. X        {
  1376. X            (void)close(infd);
  1377. X            continue;
  1378. X        }
  1379. X
  1380. X        /* File is in packed format. Unpack it */
  1381. X
  1382. X        if((outfd = open(untcxtmp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  1383. X        {
  1384. X            if(errno != EEXIST)
  1385. X            {
  1386. X                perror(untcxtmp);
  1387. X                exit(-1);
  1388. X            }
  1389. X            if((outfd = open(untcxtmp, O_WRONLY | O_TRUNC)) < 0)
  1390. X            {
  1391. X                perror(untcxtmp);
  1392. X                exit(-1);
  1393. X            }
  1394. X        }
  1395. X
  1396. X        /* Start decompressing executable */
  1397. X
  1398. X        if(dodecode(infd, outfd) != 0)
  1399. X        {
  1400. X            if(unlink(untcxtmp) < 0)
  1401. X                perror("untcxtmp");
  1402. X            exit(-1);
  1403. X        }
  1404. X
  1405. X        (void)close(outfd);
  1406. X
  1407. X        /* Now set execute permissions on the beastie */
  1408. X
  1409. X        if(chmod(untcxtmp, perms) < 0)
  1410. X        {
  1411. X            perror(untcxtmp);
  1412. X            if(unlink(untcxtmp) < 0)
  1413. X                perror("untcxtmp");
  1414. X            exit(-1);
  1415. X        }
  1416. X
  1417. X        if(chown(untcxtmp, owner, group) < 0)
  1418. X        {
  1419. X            perror(untcxtmp);
  1420. X            if(unlink(untcxtmp) < 0)
  1421. X                perror("untcxtmp");
  1422. X            exit(-1);
  1423. X        }
  1424. X
  1425. X        /* Rename temporary file to target executable and close target */
  1426. X
  1427. X        if(rename(untcxtmp, execpath) < 0)
  1428. X        {
  1429. X            perror(untcxtmp);
  1430. X            if(unlink(untcxtmp) < 0)
  1431. X                perror("untcxtmp");
  1432. X            exit(-1);
  1433. X        }
  1434. X
  1435. X        (void)close(infd);
  1436. X
  1437. X        /* Everything OK!  Now go exec the executable. */
  1438. X
  1439. X        if(try_to_exec(execpath, argv) < 0)
  1440. X            exit(-1);
  1441. X    } /* for */
  1442. X} /* untcx_and_exec_local */
  1443. X
  1444. X
  1445. Xvoid
  1446. Xuntcx_and_exec_nfs(char *execpath, char *untcxtmp, char *tcxtarg, char *argv[])
  1447. X{
  1448. Xstruct    stat    tostat;    /* Stat buffer to check on lengths */
  1449. Xint    mtime;
  1450. Xint    owner, group;
  1451. Xint    perms;        /* Saved permissions to restore on target exec */
  1452. Xint    infd, outfd;    /* In and out file descriptors */
  1453. Xstruct    flock    lck;    /* File lock structure */
  1454. X
  1455. X    /* Stat executable and grab permissions */
  1456. X
  1457. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1458. X    if(stat(execpath, &tostat) < 0)
  1459. X    {
  1460. X        perror(argv[0]);
  1461. X        exit(-1);
  1462. X    }
  1463. X    perms = (tostat.st_mode & 0777);
  1464. X    mtime = tostat.st_mtime;
  1465. X    owner = tostat.st_uid;
  1466. X    group = tostat.st_gid;
  1467. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1468. X
  1469. X    for(;;PUSLEEP(10000))
  1470. X    {
  1471. X        if(stat(tcxtarg, &tostat) >= 0)
  1472. X            if(mtime > tostat.st_mtime)
  1473. X                (void)unlink(tcxtarg);
  1474. X            else
  1475. X            {
  1476. X                if(try_to_exec(tcxtarg, argv) < 0)
  1477. X                    exit(-1);
  1478. X                continue;
  1479. X            }
  1480. X
  1481. X        if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1482. X        if((infd = open(execpath, O_RDONLY)) < 0)
  1483. X        {
  1484. X            perror(execpath);
  1485. X            exit(-1);
  1486. X        }
  1487. X        if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1488. X
  1489. X        if(! is_tcx(infd))
  1490. X        {
  1491. X            (void)close(infd);
  1492. X            if(try_to_exec(tcxtarg, argv) < 0)
  1493. X                exit(-1);
  1494. X            continue;
  1495. X        }
  1496. X
  1497. X        /* File is in packed format. Unpack it */
  1498. X
  1499. X        if((outfd = open(untcxtmp, O_EXCL | O_CREAT | O_WRONLY)) < 0)
  1500. X        {
  1501. X            if(errno != EEXIST)
  1502. X            {
  1503. X                perror(untcxtmp);
  1504. X                exit(-1);
  1505. X            }
  1506. X            if((outfd = open(untcxtmp, O_WRONLY | O_TRUNC)) < 0)
  1507. X            {
  1508. X                perror(untcxtmp);
  1509. X                exit(-1);
  1510. X            }
  1511. X        }
  1512. X
  1513. X        lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1514. X        if(fcntl(outfd, F_SETLK, &lck) < 0)
  1515. X        {
  1516. X            (void)close(infd);
  1517. X            (void)close(outfd);
  1518. X            continue;
  1519. X        }
  1520. X
  1521. X        /* Start decompressing executable */
  1522. X
  1523. X        if(dodecode(infd, outfd) != 0)
  1524. X        {
  1525. X            if(unlink(untcxtmp) < 0)
  1526. X                perror(untcxtmp);
  1527. X            exit(-1);
  1528. X        }
  1529. X
  1530. X        (void)close(infd);
  1531. X
  1532. X        /* Now set execute permissions on the beastie */
  1533. X
  1534. X        if(chmod(untcxtmp, perms) < 0)
  1535. X        {
  1536. X            perror(untcxtmp);
  1537. X            if(unlink(untcxtmp) < 0)
  1538. X                perror(untcxtmp);
  1539. X            exit(-1);
  1540. X        }
  1541. X
  1542. X        if(chown(untcxtmp, owner, group) < 0)
  1543. X        {
  1544. X            perror(untcxtmp);
  1545. X            if(unlink(untcxtmp) < 0)
  1546. X                perror(untcxtmp);
  1547. X            exit(-1);
  1548. X        }
  1549. X
  1550. X        /* Rename temporary file to target executable and close target */
  1551. X
  1552. X        if(rename(untcxtmp, tcxtarg) < 0)
  1553. X        {
  1554. X            perror(untcxtmp);
  1555. X            if(unlink(untcxtmp) < 0)
  1556. X                perror(untcxtmp);
  1557. X            exit(-1);
  1558. X        }
  1559. X
  1560. X        (void)close(outfd);
  1561. X
  1562. X        /* Everything OK!  Now go exec the executable. */
  1563. X
  1564. X        if(try_to_exec(tcxtarg, argv) < 0)
  1565. X            exit(-1);
  1566. X    } /* for */
  1567. X} /* untcx_and_exec_nfs */
  1568. X
  1569. X
  1570. Xvoid
  1571. Xjust_untcx(char *execpath, char *untcxtmp)
  1572. X{
  1573. Xstruct    stat    tostat;    /* Stat buffer to check on lengths */
  1574. Xint    owner, group;
  1575. Xint    perms;        /* Saved permissions to restore on target exec */
  1576. Xint    infd, outfd;    /* In and out file descriptors */
  1577. Xstruct    flock    lck;    /* File lock structure */
  1578. X
  1579. X    /* Stat executable and grab permissions */
  1580. X
  1581. X    if(stat(execpath, &tostat) < 0)
  1582. X    {
  1583. X        perror(execpath);
  1584. X        exit(-1);
  1585. X    }
  1586. X    perms = (tostat.st_mode & 0777);
  1587. X    owner = tostat.st_uid;
  1588. X    group = tostat.st_gid;
  1589. X
  1590. X    if((infd = open(execpath, O_RDWR)) < 0)
  1591. X    {
  1592. X        perror(execpath);
  1593. X        exit(-1);
  1594. X    }
  1595. X
  1596. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1597. X    if(fcntl(infd, F_SETLK, &lck) < 0)
  1598. X    {
  1599. X        perror(execpath);
  1600. X        exit(-1);
  1601. X    }
  1602. X
  1603. X    if(! is_tcx(infd))
  1604. X    {
  1605. X        (void)fprintf(stderr, "File does not appear to be in tcx format. Aborting\n");
  1606. X        exit(-1);
  1607. X    }
  1608. X
  1609. X    /* File is in packed format. Unpack it */
  1610. X
  1611. X    if((outfd = open(untcxtmp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  1612. X    {
  1613. X        if(errno != EEXIST)
  1614. X        {
  1615. X            perror(untcxtmp);
  1616. X            exit(-1);
  1617. X        }
  1618. X        if((outfd = open(untcxtmp, O_WRONLY | O_TRUNC)) < 0)
  1619. X        {
  1620. X            perror(untcxtmp);
  1621. X            exit(-1);
  1622. X        }
  1623. X    }
  1624. X
  1625. X    /* Start decompressing executable */
  1626. X
  1627. X    if(dodecode(infd, outfd) != 0)
  1628. X    {
  1629. X        if(unlink(untcxtmp) < 0)
  1630. X            perror(untcxtmp);
  1631. X        exit(-1);
  1632. X    }
  1633. X
  1634. X    (void)close(outfd);
  1635. X
  1636. X    /* Now set execute permissions on the beastie */
  1637. X
  1638. X    if(chmod(untcxtmp, perms) < 0)
  1639. X    {
  1640. X        perror(untcxtmp);
  1641. X        if(unlink(untcxtmp) < 0)
  1642. X            perror(untcxtmp);
  1643. X        exit(-1);
  1644. X    }
  1645. X
  1646. X    if(chown(untcxtmp, owner, group) < 0)
  1647. X    {
  1648. X        perror(untcxtmp);
  1649. X        if(unlink(untcxtmp) < 0)
  1650. X            perror(untcxtmp);
  1651. X        exit(-1);
  1652. X    }
  1653. X
  1654. X    /* Rename temporary file to target executable and close target */
  1655. X
  1656. X    if(rename(untcxtmp, execpath) < 0)
  1657. X    {
  1658. X        perror(untcxtmp);
  1659. X        if(unlink(untcxtmp) < 0)
  1660. X            perror(untcxtmp);
  1661. X        exit(-1);
  1662. X    }
  1663. X
  1664. X    (void)close(infd);
  1665. X    return;
  1666. X} /* untcx_and_exec_local */
  1667. X
  1668. X
  1669. Xint
  1670. Xtry_to_exec(char *execpath, char *argv[])
  1671. X{
  1672. Xint    infd, try;
  1673. Xint    logfd;
  1674. XFILE    *logfp;
  1675. Xstruct    flock    lck;
  1676. X
  1677. X    if((infd = open(execpath, O_RDONLY)) < 0)
  1678. X    {
  1679. X        if(errno == ENOENT)
  1680. X        {
  1681. X            perror(execpath);
  1682. X            return -1;
  1683. X        }
  1684. X        return 0;
  1685. X    }
  1686. X
  1687. X    if(is_tcx(infd))
  1688. X    {
  1689. X        (void)close(infd);
  1690. X        return 0;
  1691. X    }
  1692. X
  1693. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1694. X    for(try = 0; try < 10; try++, PUSLEEP(50000))
  1695. X    {
  1696. X        if((logfd = open(logpath, O_WRONLY)) < 0)
  1697. X            continue;
  1698. X        if(fcntl(logfd, F_SETLK, &lck) < 0)
  1699. X        {
  1700. X            (void)close(logfd);
  1701. X            continue;
  1702. X        }
  1703. X
  1704. X        if((logfp = fopen(logpath, "a+")) == NULL)
  1705. X        {
  1706. X            (void)close(logfd);
  1707. X            continue;
  1708. X        }
  1709. X
  1710. X        (void)fprintf(logfp, "%s\n", execpath);
  1711. X        (void)fclose(logfp);
  1712. X        (void)close(logfd);
  1713. X        break;
  1714. X    }
  1715. X
  1716. X#if defined(IRIX)
  1717. X    if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  1718. X#else
  1719. X    if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1720. X#endif
  1721. X
  1722. X    /* Reset signals back to normal to prevent carriage through execv */
  1723. X
  1724. X    (void)signal(SIGINT, SIG_DFL);
  1725. X    (void)signal(SIGHUP, SIG_DFL);
  1726. X    (void)signal(SIGTSTP, SIG_DFL);
  1727. X    (void)signal(SIGALRM, SIG_DFL);
  1728. X    (void)signal(SIGQUIT, SIG_DFL);
  1729. X    (void)signal(SIGTERM, SIG_DFL);
  1730. X
  1731. X    (void)close(infd);
  1732. X    if(execv(execpath, argv) < 0)
  1733. X        perror(execpath);
  1734. X    return -1;
  1735. X} /* try_to_exec */
  1736. X
  1737. X
  1738. X#if defined(SUNOS)
  1739. Xvoid
  1740. Xupdate_pstat_info()
  1741. X{
  1742. XFILE    *fp;
  1743. Xchar    line[256], tmp[10];
  1744. Xpstat    *curr;
  1745. Xint    i, pos;
  1746. Xint    maj, min, dev, ino, cnt;
  1747. X
  1748. X    for(pos = 0 ; pos < MAXOPENFILES; pos++)
  1749. X        pihash[pos] = (pstat *)NULL;
  1750. X
  1751. X    if((fp = popen(PSTATI, "r")) == NULL)
  1752. X        return;
  1753. X    if(fgets(line, 256, fp) == NULL)
  1754. X        return;
  1755. X    for(i = 0; fgets(line, 256, fp) != NULL && i < MAXOPENFILES; i++)
  1756. X    {
  1757. X        curr = parr + i;
  1758. X        strncpy(tmp, line+16, 3);    tmp[3] = '\0';    maj = atoi(tmp);
  1759. X        strncpy(tmp, line+20, 3);    tmp[3] = '\0';    min = atoi(tmp);
  1760. X        strncpy(tmp, line+23, 6);    tmp[6] = '\0';    ino = atoi(tmp);
  1761. X        strncpy(tmp, line+61, 4);    tmp[4] = '\0';    cnt = atoi(tmp);
  1762. X        dev = maj * 256 + min;
  1763. X        pos = PIHASH(dev, ino);
  1764. X        curr->dev = dev;
  1765. X        curr->ino = ino;
  1766. X        curr->cnt = cnt;
  1767. X        curr->next = pihash[pos];
  1768. X        pihash[pos] = curr;
  1769. X    } /* while */
  1770. X    pclose(fp);
  1771. X} /* update_pstat_info */
  1772. X#endif
  1773. X
  1774. X
  1775. Xint
  1776. Xscan_logtail(int lastoff)
  1777. X{
  1778. Xchar    newpath[MAXPATHLEN], *s;
  1779. XFILE    *logfp;
  1780. Xpath    *curr;
  1781. Xstruct    stat    sb;
  1782. X
  1783. X    if(lastoff < 0)
  1784. X        lastoff = 0;
  1785. X    if((logfp = fopen(logpath, "r")) == NULL)
  1786. X        return -1;
  1787. X    (void)fseek(logfp, lastoff, SEEK_SET);
  1788. X    while(fgets(newpath, MAXPATHLEN, logfp) != NULL)
  1789. X    {
  1790. X        for(s = newpath; *s; s++) if(*s == '\n') *s = '\0';
  1791. X
  1792. X        for(curr = worklist; curr != NULL; curr = curr->next)
  1793. X            if(strcmp(curr->path, newpath) == 0) break;
  1794. X        if(curr != NULL)
  1795. X            continue;
  1796. X
  1797. X        if(stat(newpath, &sb) < 0)
  1798. X            continue;
  1799. X
  1800. X        if(freelist != NULL)
  1801. X        {
  1802. X            curr = freelist;
  1803. X            freelist = freelist->next;
  1804. X        }
  1805. X        else
  1806. X            if((curr = (path *)malloc(sizeof(path))) == NULL)
  1807. X                continue;
  1808. X
  1809. X        (void)strcpy(curr->path, newpath);
  1810. X        curr->pid = -1;
  1811. X        (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
  1812. X        curr->ctime = sb.st_ctime;
  1813. X        curr->next = worklist;
  1814. X        worklist = curr;
  1815. X    } /* while */
  1816. X    lastoff = ftell(logfp);
  1817. X    (void)fclose(logfp);
  1818. X    return lastoff;
  1819. X} /* scan_logtail */
  1820. X
  1821. X
  1822. X#ifdef ULTRIX
  1823. Xint
  1824. Xis_dir_local(char *dir)
  1825. X{
  1826. Xstruct  fs_data fsbuf;
  1827. X
  1828. X    if(statfs(dir, &fsbuf) < 1)     /* Returns 0 on "NOT MOUNTED" */
  1829. X        return -1;
  1830. X
  1831. X    /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
  1832. X    /* to a client, so return false on this condition. */
  1833. X
  1834. X    if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  1835. X        return 0;
  1836. X    return 1;
  1837. X} /* is_dir_local */
  1838. X#else
  1839. Xint
  1840. Xis_dir_local(char *dir)
  1841. X{
  1842. Xstruct    statfs    fsbuf;    /* Statfs buffer to check local versus NFS executable */
  1843. X
  1844. X    if(statfs(dir, &fsbuf, (int)(sizeof(struct statfs)), 0) < 0)
  1845. X        return -1;
  1846. X
  1847. X    /* NFS Version 2 returns -1 or 0 for both f_files, and f_ffree */
  1848. X    /* to a client, so return false on this condition. */
  1849. X
  1850. X    if((fsbuf.f_files <= 0) && (fsbuf.f_ffree <= 0))
  1851. X        return 0;
  1852. X    return 1;
  1853. X} /* is_dir_local */
  1854. X#endif
  1855. X
  1856. X
  1857. Xint
  1858. Xis_tcx(int fd)
  1859. X{
  1860. Xint    i;
  1861. Xunsigned char    c;
  1862. X
  1863. X    for(i = 0; i < 256; i++)
  1864. X        if(read(fd, &c, 1) < 1 || c == 0)
  1865. X            break;
  1866. X    if((i >= 256) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  1867. X        || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  1868. X        return 0;
  1869. X    return 1;
  1870. X} /* is_tcx */
  1871. X
  1872. X
  1873. Xint
  1874. Xdodecode(int infd, int outfd)
  1875. X{
  1876. Xint    pid;
  1877. Xunion    wait    status;
  1878. X
  1879. X    pid = fork();
  1880. X    if(pid < 0) return -1;
  1881. X    if(pid == 0)
  1882. X    {
  1883. X        if(dup2(infd, 0) < 0) exit(-1);     /* Attach infd to stdin */
  1884. X        (void)close(infd);
  1885. X        if(dup2(outfd, 1) < 0) exit(-1); /* Attach outfd to stdout */
  1886. X        (void)close(outfd);
  1887. X#ifdef    UNPACKOPTS
  1888. X        (void)execl(PATHUNPACK, "unpacker", UNPACKOPTS, (char *)0);
  1889. X#else
  1890. X        (void)execl(PATHUNPACK, "unpacker", (char *)0);
  1891. X#endif
  1892. X        exit(-1);
  1893. X    }
  1894. X    else
  1895. X        pid = wait(&status);
  1896. X    return WEXITSTATUS(status);
  1897. X} /* dodecode */
  1898. X
  1899. X
  1900. X#ifdef ULTRIX
  1901. Xint
  1902. Xusleep(int usec)
  1903. X{
  1904. Xstruct    itimerval    value, dumb;
  1905. X
  1906. X    (void)signal(SIGALRM, usleep_sig);
  1907. X
  1908. X    if(getitimer(ITIMER_REAL, &value) != 0)
  1909. X    {
  1910. X        perror("Error: couldn't get timer");
  1911. X        return(-1);
  1912. X    }
  1913. X    value.it_value.tv_sec = value.it_interval.tv_sec = (long) usec / 1000000;
  1914. X    value.it_value.tv_usec = value.it_interval.tv_usec = (long) usec % 1000000;
  1915. X        
  1916. X    if(setitimer(ITIMER_REAL, &value, &dumb) != 0) /* ignore parameter 3 */
  1917. X    {
  1918. X        perror("Error: couldn't set timer");
  1919. X        return(-1);
  1920. X    }
  1921. X
  1922. X    (void)sigpause(SIGALRM);
  1923. X
  1924. X    if(getitimer(ITIMER_REAL, &value) != 0)
  1925. X    {
  1926. X        perror("Error: couldn't get timer");
  1927. X        return(-1);
  1928. X    }
  1929. X    usec = (value.it_value.tv_sec - value.it_interval.tv_sec) * 1000000;
  1930. X    usec += (value.it_value.tv_usec - value.it_interval.tv_usec);
  1931. X    return usec;
  1932. X}
  1933. X
  1934. Xint
  1935. Xusleep_sig()
  1936. X{
  1937. X} /* usleep_sig */
  1938. X#endif
  1939. END_OF_FILE
  1940.   if test 27702 -ne `wc -c <'untcx.c'`; then
  1941.     echo shar: \"'untcx.c'\" unpacked with wrong size!
  1942.   fi
  1943.   # end of 'untcx.c'
  1944. fi
  1945. echo shar: End of archive 1 \(of 2\).
  1946. cp /dev/null ark1isdone
  1947. MISSING=""
  1948. for I in 1 2 ; do
  1949.     if test ! -f ark${I}isdone ; then
  1950.     MISSING="${MISSING} ${I}"
  1951.     fi
  1952. done
  1953. if test "${MISSING}" = "" ; then
  1954.     echo You have unpacked both archives.
  1955.     rm -f ark[1-9]isdone
  1956. else
  1957.     echo You still must unpack the following archives:
  1958.     echo "        " ${MISSING}
  1959. fi
  1960. exit 0
  1961. exit 0 # Just in case...
  1962.