home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / RESCUE / TCX-LINU.TAR / tcx / untcx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-09  |  30.9 KB  |  1,382 lines

  1. /* untcx.c, Version 1.0.5, 5/4/1993 by Stewart Forster */
  2.  
  3. /************************************************************************/
  4. /*   Copyright (C) 1993 Stewart Forster                    */
  5. /*  This program is free software; you can redistribute it and/or modify*/
  6. /*  it under the terms of the GNU General Public License as published by*/
  7. /*  the Free Software Foundation; either version 2, or (at your option) */
  8. /*  any later version.                            */
  9. /*                                    */
  10. /*  This program is distributed in the hope that it will be useful,    */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  13. /*  GNU General Public License for more details.            */
  14. /*                                    */
  15. /*  You should have received a copy of the GNU General Public License    */
  16. /*  along with this program; if not, write to the Free Software        */
  17. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  18. /************************************************************************/
  19.  
  20. #include    "config.h"
  21.  
  22. typedef struct path
  23. {
  24.     char    path[MAXPATHLEN]; /* Pathname to file */
  25. #ifdef UNPACK_IN_PLACE
  26.     int    pid;        /* Process id compressing file */
  27.     int    local;        /* Is file local? */
  28. #endif
  29.     int    atime;        /* Time last known to be busy */
  30.     int    ctime;        /* Inode modification time */
  31.     struct    path    *next;    /* Next structure */
  32. } path;
  33.  
  34. #if defined(SUNOS)
  35. #define    MAXOPENFILES    4096
  36. #define    PIHASH(a, b)    (((a) + (b)) % MAXOPENFILES)
  37.  
  38. typedef struct pstat
  39. {
  40.     int    dev;
  41.     int    ino;
  42.     int    cnt;
  43.     struct    pstat    *next;
  44. } pstat;
  45.  
  46. pstat    parr[MAXOPENFILES];
  47. pstat    *pihash[MAXOPENFILES];
  48. void    update_pstat_info();
  49. #endif
  50.  
  51. extern    int    errno;
  52. path    *worklist = NULL, *freelist = NULL;
  53.  
  54.  
  55. char    logpath[MAXPATHLEN], logtmppath[MAXPATHLEN], lockpath[MAXPATHLEN];
  56.  
  57. char    cwd[MAXPATHLEN];    /* Save of current working directory */
  58. char    realdir[MAXPATHLEN];    /* Real directory packed executable lives in */
  59. char    execname[MAXPATHLEN];    /* Name of packed/target executable */
  60. char    execpath[MAXPATHLEN];    /* Full path name of packed executable */
  61. char    untcxtmp[MAXPATHLEN];    /* Temporary unpack pathname */
  62. char    tcxtarg[MAXPATHLEN];    /* Target path name of unpacked executable */
  63. char    linkpath[MAXPATHLEN];    /* Pathname of symlink to executable */
  64.  
  65. void    untcx_and_exec_local(char *, char *, char *[]);
  66. void    untcx_and_exec_nfs(char *, char *, char *, char *[]);
  67. int    try_to_exec(char *, char *, char *[]);
  68. void    check_tcxd_mode();
  69. #ifdef UNPACK_IN_PLACE
  70. SIGTYPE    tcxd_reaper();
  71. #endif
  72. void    just_untcx(char *, char *);
  73. int    scan_logtail(int);
  74. int    is_dir_local(char *);
  75. int    is_tcx(int);
  76. int    dodecode(int, int);
  77. char    *newargs[1024];
  78. #if defined(ULTRIX)
  79. int    usleep(int);
  80. int    usleep_sig();
  81. #endif
  82.  
  83. int
  84. main(int argc, char *argv[])
  85. {
  86. char    *c;            /* String manipulation pointers */
  87. struct    stat    dostat;    /* Stat buffer */
  88. int    i, isinterp, len;
  89. #ifdef UNPACK_IN_PLACE
  90. int    local;
  91. #endif
  92.  
  93.     if(argc < 2)
  94.     {
  95.         (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  96.         exit(-1);
  97.     }
  98.  
  99.     /* Re-exec if not root and pass -x along on the command line. */
  100.     /* If it's there when we restart and we're still not root, then */
  101.     /* avoid an exec loop by quitting with a warning. */
  102.  
  103.     if(geteuid() != 0)
  104.     {
  105. #ifndef LINUX
  106.         if(strcmp(argv[1], "-x") == 0)
  107. #endif
  108.         {
  109.             (void)fprintf(stderr, "Error: untcx is not installed setuid to root!\n");
  110.             (void)fprintf(stderr, "Contact your systems administrator\n");
  111.             exit(-1);
  112.         }
  113.  
  114.         /* Push -x into argv[1] and shift rest of args along */
  115.  
  116.         newargs[0] = argv[0];
  117.         newargs[1] = "-x";
  118.         for(i = 1; i < argc; i++) newargs[i+1] = argv[i];
  119.         newargs[i + 1] = (char *)NULL;
  120.         if(execv(PATHUNTCX, newargs) < 0)
  121.             perror("exec");
  122.  
  123.         /* exec failed! Warn user and quit */
  124.  
  125.         (void)fprintf(stderr, "Unable to invoke interpreter as root\n");
  126.         exit(-1);
  127.     }
  128.  
  129.     if(strcmp(argv[1], "-x") == 0)
  130.     {
  131.         for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  132.         argv[i] = (char *)NULL;
  133.         --argc;
  134.         isinterp = 1;
  135.     }
  136.     else
  137.     if(strcmp(argv[1], "-u") == 0)
  138.     {
  139.         for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  140.         argv[i] = (char *)NULL;
  141.         --argc;
  142.         isinterp = 0;
  143.     }
  144.     else
  145. #if defined(LINUX)
  146.         isinterp = 1;
  147. #else
  148.     if(getuid() == 0)
  149.         isinterp = 1;
  150.     else
  151.         isinterp = 0;
  152. #endif
  153.  
  154.     /* Copy argv[1] to argv[0] for obsolete stuff (and IRIX) */
  155.  
  156.     argv[0] = argv[1];
  157.  
  158.     /* Setup to catch all undesirable signals */
  159.  
  160.     (void)signal(SIGINT, SIG_IGN);
  161.     (void)signal(SIGHUP, SIG_IGN);
  162.     (void)signal(SIGTSTP, SIG_IGN);
  163.     (void)signal(SIGALRM, SIG_IGN);
  164.     (void)signal(SIGQUIT, SIG_IGN);
  165.     (void)signal(SIGTERM, SIG_IGN);
  166.  
  167.     /* Set global paths */
  168.  
  169.     (void)sprintf(logpath, "%s/log", ENFSDIR);
  170.     (void)sprintf(logtmppath, "%s/logtmp", ENFSDIR);
  171.     (void)sprintf(lockpath, "%s/.lock", ENFSDIR);
  172.  
  173.     /* Check and start tcxd as required */
  174.  
  175.     check_tcxd_mode();
  176.  
  177.     /* Go to the uid of invoking user.  Resolve through symbolic links */
  178.     /* as to what the real pathname of the executable is. */
  179.  
  180. #ifdef AIX
  181.     if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
  182. #else
  183.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  184. #endif
  185.  
  186.     /* Grab argv[0] and resolve to full path name via getwd() */
  187.  
  188.     if(getwd(cwd) == NULL)
  189.     {
  190.         (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  191.         exit(-1);
  192.     }
  193.  
  194.     if(*argv[0] == '/')
  195.         (void)strcpy(realdir, argv[0]);
  196.     else
  197.         (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
  198.     for(;;)
  199.     {
  200.         if((c = strrchr(realdir, '/')) == NULL)
  201.         {    /* Should never happen, BUT... */
  202.             (void)fprintf(stderr, "Help! Internal corruption of variables!\n");
  203.             exit(-1);
  204.         }
  205.         c++;
  206.         (void)strcpy(execname, c);
  207.         *c = '\0';
  208.  
  209.         if(chdir(realdir) < 0)    /* Oops. Failed. Report and quit. */
  210.         {
  211.             perror(realdir);
  212.             exit(-1);
  213.         }
  214.  
  215.         if(getwd(realdir) == NULL)
  216.         {
  217.             (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  218.             exit(-1);
  219.         }
  220.  
  221.         /* Do lstat executable from here. If not a link, go on, else */
  222.         /* read the value of the link, and append it to realdir if */
  223.         /* it doesn't begin with a /, other just copy it to realdir */
  224.         /* and cycle through the loop again. */
  225.  
  226.         if(lstat(execname, &dostat) < 0)
  227.         {
  228.             perror(execname);
  229.             exit(-1);
  230.         }
  231.  
  232.         if((dostat.st_mode & S_IFMT) == S_IFLNK)
  233.         {
  234.             if((len = readlink(execname, execpath, MAXPATHLEN)) < 0)
  235.             {
  236.                 perror(execname);
  237.                 exit(-1);
  238.             }
  239.             execpath[len] = '\0';
  240.             if(execpath[0] == '/')
  241.                 (void)strcpy(realdir, execpath);
  242.             else
  243.             {
  244.                 (void)strcat(realdir, "/");
  245.                 (void)strcat(realdir, execpath);
  246.             }
  247.             continue;
  248.         }
  249.  
  250.         if(!(dostat.st_mode & S_IFREG))
  251.         {
  252.             (void)fprintf(stderr, "Error: Not an executable file - %s/%s\n", realdir, execname);
  253.             exit(-1);
  254.         }
  255.  
  256.         /* Now do a statfs on realdir.  If it's on an NFS mounted filesystem we */
  257.         /* will need to unpack to ENFSDIR, otherwise we can unpack it in place, */
  258.  
  259. #ifdef UNPACK_IN_PLACE
  260.         if((local = is_dir_local(realdir)) < 0)
  261.             exit(-1);
  262.         if(dostat.st_nlink > 1)    /* Unpack to ENFSDIR if file is linked */
  263.             local = 0;
  264. #endif
  265.  
  266.         break;
  267.     }
  268.  
  269.     /* Return to the original invocation directory */
  270.  
  271.     if(chdir(cwd) < 0)
  272.     {
  273.         perror(cwd);
  274.         exit(-1);
  275.     }
  276.  
  277. #ifdef AIX
  278.     if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
  279. #else
  280.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  281. #endif
  282.  
  283.     /* Now check if last components of argv[0] and argv[1] are equal */
  284.     /* If not, we are invoked just to decompress something, not to */
  285.     /* execute it.  Just attempt an uncompress as the user */
  286.  
  287.     if(isinterp == 0)
  288.     {
  289. #if defined(IRIX) || defined(AIX)
  290.         if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  291. #else
  292.         if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  293. #endif
  294.         (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  295.         (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  296.         just_untcx(tcxtarg, untcxtmp);
  297.         exit(0);
  298.     }
  299.  
  300. #ifdef UNPACK_IN_PLACE
  301.     /* Try to do a local execute. If it returns, it means failure. */
  302.  
  303.     if(local)
  304.     {
  305.         (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  306.         (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  307.         untcx_and_exec_local(tcxtarg, untcxtmp, &(argv[1]));
  308.     }
  309. #endif
  310.  
  311.     /* We get this far if file is not local, or the local execution */
  312.     /* failed for some reason like shortage of disk space. Attempt */
  313.     /* to unpack program to /tmp and go from there. */
  314.  
  315.     for(c = realdir; *c ; c++)
  316.         if(*c == '/')
  317.             *c = '=';
  318.     (void)sprintf(tcxtarg, "%s/%s", ENFSDIR, realdir);
  319.     if(mkdir(tcxtarg, 0777) < 0)
  320.         if(errno != EEXIST)
  321.         {
  322.             perror(tcxtarg);
  323.             exit(-1);
  324.         }
  325.     (void)chmod(tcxtarg, 0777);
  326.     (void)strcat(tcxtarg,"/");
  327.     (void)strcat(tcxtarg, execname);
  328.     (void)sprintf(untcxtmp, "%s/%s/.untcx.%s", ENFSDIR, realdir, execname);
  329.  
  330.     untcx_and_exec_nfs(argv[0], untcxtmp, tcxtarg, &(argv[1]));
  331.  
  332.     /* :-(  We only get this far if everything has failed. Exit with failure */
  333.  
  334.     return(-1);
  335. } /* main */
  336.  
  337.  
  338. void
  339. check_tcxd_mode()
  340. {
  341. char    *s, spid[32];
  342. int    infd, logfd, lkfd, lasttime = 0, timer;
  343. FILE    *logfp;
  344. path    *curr, *prev;
  345. struct    stat    sb;    /* Stat buffer */
  346. struct    flock    lck;    /* File lock structure */
  347. int    lastoff;
  348.  
  349.     /* Check if we're root. If not, go home */
  350.  
  351.     if(geteuid() != 0)
  352.         return;
  353.  
  354.     /* Try to create emergency/NFS execute directory and set it's permissions */
  355.     /* It's not important yet if we can't at this stage. */
  356.  
  357.     (void)mkdir(ENFSDIR, 01777);
  358.     (void)chmod(ENFSDIR, 01777);
  359.  
  360.     /* Attempt to create ENFSDIR/.lock  If can't, just return. */
  361.  
  362.     if((lkfd = open(lockpath, O_CREAT | O_RDONLY, 0600)) < 0)
  363.         return;
  364.  
  365.     /* Attempt to read lock ENFSDIR/.lock If can't, we assume the tcxd */
  366.     /* is already running. Return. */
  367.  
  368.     lck.l_type = F_RDLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  369.     if(fcntl(lkfd, F_SETLK, &lck) < 0)
  370.     {
  371.         (void)close(lkfd);
  372.         return;
  373.     }
  374.  
  375.     /* Close lkfd and hence the lock on it, fork() and return */
  376.  
  377.     (void)close(lkfd);
  378.     if(fork() != 0)    /* On parent or fork error, just return */
  379.         return;
  380.  
  381.     /* No errors to user at this point */
  382.  
  383.     (void)fclose(stderr); (void)close(2);
  384.     (void)fclose(stdout); (void)close(1);
  385.     (void)open("/dev/null", O_WRONLY);
  386.     (void)open("/dev/null", O_WRONLY);    /* Don't really care */
  387.  
  388.     /* Make ourselves nice and rooted */
  389.  
  390. #ifndef AIX
  391. #if defined(IRIX)
  392.     if(setuid(geteuid()) < 0) exit(-1);
  393. #else
  394.     if(setreuid(geteuid(), geteuid()) < 0) exit(-1);
  395. #endif
  396. #endif
  397.  
  398.     /* Check if we're root again. If not, exit */
  399.  
  400.     if(geteuid() != 0)
  401.         exit(-1);
  402.  
  403.     /* Change directory to ENFSDIR to prevent hanging on NFS server crashes */
  404.  
  405.     if(chdir(ENFSDIR) < 0)
  406.         exit(-1);
  407.  
  408.     /* Lock the server lock file to prevent more than 1 starting up */
  409.  
  410.     if((lkfd = open(lockpath, O_WRONLY | O_TRUNC)) < 0)
  411.         exit(-1);
  412.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  413.     if(fcntl(lkfd, F_SETLK, &lck) < 0)
  414.         exit(-1);
  415.  
  416.     /* Write our process id to the lock file. Don't really care if fails. */
  417.  
  418.     (void)sprintf(spid, "%d\n", getpid());
  419.     (void)write(lkfd, spid, strlen(spid));
  420.  
  421. #ifdef UNPACK_IN_PLACE
  422.     /* setup our child process reaper */
  423.  
  424.     (void)signal(SIGCHLD, tcxd_reaper);
  425. #endif
  426.  
  427.     /* Read in log file if it's there in case of crashes */
  428.  
  429.     if((lastoff = scan_logtail(0)) < 0)
  430.         (void)creat(logpath, 0600);
  431.  
  432.     /* Loop doing tasks at hand */
  433.  
  434.     for(lastoff = 0;;)
  435.     {
  436.         for(timer = 0; timer < SCANRATE; timer++, (void)sleep(1))
  437.         {
  438.             if(stat(logpath, &sb) < 0)
  439.                 continue;
  440.  
  441.             /* Don't check if not updated, but do on last time */
  442.  
  443.             if(sb.st_mtime <= lasttime)
  444.                 continue;
  445.             lasttime = sb.st_mtime;
  446.  
  447.             lastoff = scan_logtail(lastoff);
  448.         }
  449.  
  450. #if defined(SUNOS)
  451.         update_pstat_info();
  452. #endif
  453.  
  454.         for(prev = NULL, curr = worklist; curr != NULL; prev = curr, curr = curr->next)
  455.         {
  456.             /* Stat file. If not accessed within LOCALTIMOUT secs */
  457.             /* for a local file, or ENFSTIMEOUT secs for an NFS file */
  458.             /* we consider it a candidate for compression. */
  459.  
  460.             if(stat(curr->path, &sb) < 0)
  461.             {
  462.                 if(lstat(curr->path, &sb) >= 0)
  463.                 {
  464.                     (void)unlink(curr->path);    /* Was symlink. Unlink it! */
  465.                     s = strrchr(curr->path, '/');
  466.                     *s = '\0';
  467.                     (void)rmdir(curr->path);
  468.                 }
  469.                 (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  470.                 curr->next = freelist; freelist = curr;
  471.                 (prev == NULL) ? (curr = worklist) : (curr = prev);
  472.                 if(curr == NULL) break;
  473.                 continue;
  474.             }
  475.  
  476.             if(sb.st_atime > curr->atime)
  477.                 curr->atime = sb.st_atime;
  478.  
  479. #ifdef UNPACK_IN_PLACE
  480.             if(curr->local == 1 && (time(NULL) - curr->atime) < LOCALTIMEOUT)
  481.                 continue;
  482.             if(curr->local == 0 && (time(NULL) - curr->atime) < ENFSTIMEOUT)
  483.                 continue;
  484. #else
  485.             if((time(NULL) - curr->atime) < ENFSTIMEOUT)
  486.                 continue;
  487. #endif
  488.  
  489. #if defined(IRIX) || defined(DEC) || defined(AIX) || defined(LINUX)
  490.             /* Attempt to open file for writing, if it fails with ETXTBSY */
  491.             /* then update access times and continue, otherwise it is a */
  492.             /* candidate for recompression. */
  493.  
  494.             if((infd = open(curr->path, O_WRONLY)) < 0)
  495.             {
  496.                 if(errno != ETXTBSY)
  497.                 {
  498.                     if(lstat(curr->path, &sb) >= 0)
  499.                     {
  500.                         (void)unlink(curr->path);    /* Was symlink. Unlink it! */
  501.                         s = strrchr(curr->path, '/');
  502.                         *s = '\0';
  503.                         (void)rmdir(curr->path);
  504.                     }
  505.                     (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  506.                     curr->next = freelist; freelist = curr;
  507.                     (prev == NULL) ? (curr = worklist) : (curr = prev);
  508.                     if(curr == NULL) break;
  509.                     continue;
  510.                 }
  511.                 curr->atime = time(NULL);
  512.                 continue;
  513.             }
  514.             (void)close(infd);
  515. #endif
  516.  
  517. #if defined(SUNOS)
  518.         {
  519.         pstat    *pc;
  520.         int    found = 0;
  521.  
  522.             for(pc = pihash[PIHASH(sb.st_dev, sb.st_ino)]; pc != NULL; pc = pc->next)
  523.                 if(pc->dev == sb.st_dev && pc->ino == sb.st_ino)
  524.                 {
  525.                     if(pc->cnt < 2) break;
  526.                     curr->atime = time(NULL);
  527.                     found = 1;
  528.                     break;
  529.                 }
  530.             if(found) continue;
  531.         }
  532. #endif
  533.  
  534. #ifdef UNPACK_IN_PLACE
  535.             if(curr->local == -1)    /* Compression completed */
  536.             {
  537.                 (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  538.                 curr->next = freelist; freelist = curr;
  539.                 (prev == NULL) ? (curr = worklist) : (curr = prev);
  540.                 if(curr == NULL) break;
  541.                 continue;
  542.             }
  543.  
  544.             if(curr->pid > 0)
  545.                 continue;
  546.  
  547.             if(curr->local == 1)
  548.             {
  549.                 /* Check inode modification times. If target is */
  550.                 /* newer than what we know, forget it. */
  551.  
  552.                 if(sb.st_ctime > curr->ctime)
  553.                 {
  554.                     (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  555.                     curr->next = freelist; freelist = curr;
  556.                     (prev == NULL) ? (curr = worklist) : (curr = prev);
  557.                     if(curr == NULL) break;
  558.                     continue;
  559.                 }
  560.  
  561.                 /* Fork and compress program */
  562.  
  563.                 curr->pid = fork();
  564.                 if(curr->pid != 0) continue;
  565.  
  566.                 /* Here we must be the child */
  567.                 /* Close stdio stuff and reopen to /dev/null */
  568.  
  569.                 (void)close(2);
  570.                 (void)close(1);
  571.                 (void)close(0);
  572.                 (void)open("/dev/null", O_RDONLY);
  573.                 (void)open("/dev/null", O_WRONLY);
  574.                 (void)open("/dev/null", O_WRONLY);
  575.                 (void)execl(PATHTCX, "tcx", curr->path, (char *)0);
  576.                 exit(-1);
  577.             }
  578. #endif
  579.  
  580.             /* At this point, file is in ENFSDIR. Delete it */
  581.  
  582.             (void)unlink(curr->path);
  583.             s = strrchr(curr->path, '/');
  584.             *s = '\0';
  585.             (void)rmdir(curr->path);
  586.  
  587.             (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  588.             curr->next = freelist; freelist = curr;
  589.             (prev == NULL) ? (curr = worklist) : (curr = prev);
  590.             if(curr == NULL) break;
  591.         } /* for */
  592.  
  593.         /* Update log file in case of crashes */
  594.  
  595.         lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  596.  
  597.         /* Do one final read in case someone has modified during */
  598.         /* the scan sequence. */
  599.  
  600.         (void)scan_logtail(lastoff);
  601.  
  602.         if((logfp = fopen(logtmppath, "w")) == NULL)
  603.             continue;
  604.         for(curr = worklist; curr != NULL; curr = curr->next)
  605.             (void)fprintf(logfp, "%s\n", curr->path);
  606.         (void)fclose(logfp);
  607.  
  608.         /* Try for 20 times to lock file, sleep 5/100ths secs b/w tries */
  609.  
  610.         for(timer = 0; timer < 20; timer++, PUSLEEP(50000))
  611.         {
  612.             if((logfd = open(logpath, O_WRONLY)) < 0)
  613.                 continue;
  614.             if(fcntl(logfd, F_SETLK, &lck) < 0)
  615.             {    (void)close(logfd); continue;    }
  616.  
  617.             (void)rename(logtmppath, logpath);
  618.             if(stat(logpath, &sb) < 0)
  619.                 lastoff = 0;
  620.             else
  621.                 lastoff = sb.st_size;
  622.             (void)close(logfd);
  623.             break;
  624.         }
  625.     } /* for */
  626. } /* check_tcxd_mode */
  627.  
  628.  
  629. #ifdef UNPACK_IN_PLACE
  630. SIGTYPE
  631. tcxd_reaper()
  632. {
  633. #if defined(AIX)
  634. int    state;
  635. #else
  636. union wait state;
  637. #endif
  638. int    pid;
  639. path    *curr;
  640.  
  641.     while((pid = wait3(&state, WNOHANG, 0)) > 0)
  642.         for(curr = worklist; curr != NULL; curr = curr->next)
  643.             if(curr->pid == pid)
  644.             {
  645.                 curr->pid = -1;
  646.                 if(WIFEXITED(state) && WEXITSTATUS(state) == 0)
  647.                     curr->local = -1;
  648.                 break;
  649.             }
  650. #if defined(IRIX) || defined(AIX)
  651.     (void)signal(SIGCHLD, tcxd_reaper);
  652. #endif
  653. } /* tcxd_reaper */
  654. #endif
  655.  
  656.  
  657. #ifdef UNPACK_IN_PLACE
  658. void
  659. untcx_and_exec_local(char *expath, char *untemp, char *argv[])
  660. {
  661. struct    stat    tostat;    /* Stat buffer to check on lengths */
  662. int    owner, group;
  663. int    perms;        /* Saved permissions to restore on target exec */
  664. int    infd, outfd;    /* In and out file descriptors */
  665. struct    flock    lck;    /* File lock structure */
  666.  
  667.     /* In this function argv[0] and expath would normally be the same */
  668.     /* BUT, if argv[0] is a symlink to expath, we want to invoke it */
  669.     /* like that, and not via expath. */
  670.  
  671.     /* Stat executable and grab permissions */
  672.  
  673.     if(stat(expath, &tostat) < 0)
  674.     {
  675.         perror(argv[0]);
  676.         exit(-1);
  677.     }
  678.     perms = (tostat.st_mode & 0777);
  679.     owner = tostat.st_uid;
  680.     group = tostat.st_gid;
  681.  
  682.     for(;;PUSLEEP(10000))
  683.     {
  684.         if((infd = open(expath, O_RDWR)) < 0)
  685.         {
  686.             if(errno != ETXTBSY)
  687.             {
  688.                 (void)fprintf(stderr, "Cannot write to %s\n", expath);
  689.                 exit(-1);
  690.             }
  691.             if((infd = open(expath, O_RDONLY)) < 0)
  692.                 continue;
  693.             (void)close(infd);
  694.             if(try_to_exec(expath, argv[0], argv) < 0)
  695.                 exit(-1);
  696.             continue;
  697.         }
  698.  
  699.         lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  700.         if(fcntl(infd, F_SETLK, &lck) < 0)
  701.         {
  702.             if(fcntl(infd, F_GETLK, &lck) < 0 || lck.l_type != F_RDLCK)
  703.             { (void)close(infd); continue; }
  704.             (void)close(infd);
  705.             if(try_to_exec(expath, argv[0], argv) < 0)
  706.                 exit(-1);
  707.             continue;
  708.         }
  709.  
  710.         if(! is_tcx(infd))
  711.         {
  712.             (void)close(infd);
  713.             if(try_to_exec(expath, argv[0], argv) < 0)
  714.                 exit(-1);
  715.             continue;
  716.         }
  717.  
  718.         /* File is in packed format. Unpack it */
  719.  
  720.         if((outfd = open(untemp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  721.         {
  722.             if(errno != EEXIST)
  723.             {
  724.                 perror(untemp);
  725.                 exit(-1);
  726.             }
  727.             if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
  728.             {
  729.                 perror(untemp);
  730.                 exit(-1);
  731.             }
  732.         }
  733.  
  734.         /* Start decompressing executable */
  735.  
  736.         if(dodecode(infd, outfd) != 0)
  737.         {
  738.             if(unlink(untemp) < 0)
  739.                 perror(untemp);
  740.             exit(-1);
  741.         }
  742.  
  743.         (void)close(outfd);
  744.  
  745.         /* Now set execute permissions on the beastie */
  746.  
  747.         if(chmod(untemp, perms) < 0)
  748.         {
  749.             perror(untemp);
  750.             if(unlink(untemp) < 0)
  751.                 perror(untemp);
  752.             exit(-1);
  753.         }
  754.  
  755.         if(chown(untemp, owner, group) < 0)
  756.         {
  757.             perror(untemp);
  758.             if(unlink(untemp) < 0)
  759.                 perror(untemp);
  760.             exit(-1);
  761.         }
  762.  
  763.         /* Rename untemporary file to target executable and close target */
  764.  
  765.         if(rename(untemp, expath) < 0)
  766.         {
  767.             perror(untemp);
  768.             if(unlink(untemp) < 0)
  769.                 perror(untemp);
  770.             exit(-1);
  771.         }
  772.  
  773.         (void)close(infd);
  774.  
  775.         /* Everything OK!  Now go exec the executable. */
  776.  
  777.         if(try_to_exec(expath, argv[0], argv) < 0)
  778.             exit(-1);
  779.     } /* for */
  780. } /* untcx_and_exec_local */
  781. #endif
  782.  
  783.  
  784. void
  785. untcx_and_exec_nfs(char *expath, char *untemp, char *targ, char *argv[])
  786. {
  787. struct    stat    tostat;    /* Stat buffer to check on lengths */
  788. int    mtime;
  789. int    owner, group;
  790. int    perms;        /* Saved permissions to restore on target exec */
  791. int    infd, outfd;    /* In and out file descriptors */
  792. struct    flock    lck;    /* File lock structure */
  793. char    *c;
  794. int    len;
  795.  
  796.     /* Stat executable and grab permissions */
  797.  
  798. #ifdef AIX
  799.     if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
  800. #else
  801.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  802. #endif
  803.  
  804.     if(stat(expath, &tostat) < 0) { perror(argv[0]); exit(-1); }
  805.  
  806.     perms = (tostat.st_mode & 0777);
  807.     mtime = tostat.st_mtime;
  808.     owner = tostat.st_uid;
  809.     group = tostat.st_gid;
  810.  
  811.     /* resolve first stage of argv[0] */
  812.  
  813.     if(getwd(cwd) == NULL) { (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd); exit(-1); }
  814.  
  815.     if(*argv[0] == '/') (void)strcpy(realdir, argv[0]); else (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
  816.  
  817.     if((c = strrchr(realdir, '/')) == NULL) { (void)fprintf(stderr, "Help! Internal corruption of variables!\n"); exit(-1); }
  818.  
  819.     c++; (void)strcpy(execname, c); *c = '\0';
  820.  
  821.     if(chdir(realdir) < 0) { perror(realdir); exit(-1); }
  822.  
  823.     if(getwd(realdir) == NULL) { (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd); exit(-1); }
  824.  
  825.     for(c = realdir; *c; c++)
  826.         if(*c == '/')
  827.             *c = '=';
  828.     (void)sprintf(linkpath, "%s/%s", ENFSDIR, realdir);
  829.     if(mkdir(linkpath, 0777) < 0)
  830.     {
  831.         if(errno != EEXIST) { perror(linkpath); exit(-1); }
  832.     }
  833.     else
  834.         (void)chmod(linkpath, 0777);
  835.     (void)strcat(linkpath,"/");
  836.     (void)strcat(linkpath, execname);
  837.  
  838.     if(chdir(cwd) < 0) { perror(cwd); exit(-1); }
  839.     
  840. #ifdef AIX
  841.     if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
  842. #else
  843.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  844. #endif
  845.  
  846.     /* Statistics done! Now try to unpack and run it! */
  847.  
  848.     for(;;PUSLEEP(10000))
  849.     {
  850.         if(stat(targ, &tostat) >= 0)
  851.         {
  852.             if(mtime > tostat.st_mtime)
  853.             {
  854.                 if(strcmp(linkpath, targ) == 0)
  855.                     (void)unlink(linkpath);
  856.                 (void)unlink(targ);
  857.             }
  858.             else
  859.             {
  860.                 if(strcmp(linkpath, targ) == 0)
  861.                 {
  862.                     if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
  863.                 }
  864.                 else
  865.                 if((len = readlink(linkpath, realdir, MAXPATHLEN)) >= 0 && strncmp(realdir, targ, len) == 0)
  866.                 {
  867.                     if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
  868.                 }
  869.                 else
  870.                 {
  871.                     (void)unlink(linkpath);
  872.  
  873.                     if(symlink(targ, linkpath) < 0) { perror(linkpath); exit(-1); }
  874.  
  875.                     if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
  876.                 }
  877.             }
  878.         }
  879.         else
  880.         {
  881.             /* If symlink to file is there, then get rid of it! */
  882.  
  883.             if((len = readlink(linkpath, realdir, MAXPATHLEN)) >= 0 && strncmp(realdir, targ, len) == 0)
  884.                 (void)unlink(linkpath);
  885.         }
  886.  
  887. #ifdef AIX
  888.         if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
  889. #else
  890.         if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  891. #endif
  892.         if((infd = open(expath, O_RDONLY)) < 0)
  893.         {
  894.             perror(expath);
  895.             exit(-1);
  896.         }
  897. #ifdef AIX
  898.         if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
  899. #else
  900.         if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  901. #endif
  902.  
  903.         if(! is_tcx(infd))
  904.         {
  905.             (void)close(infd);
  906.             if(try_to_exec(expath, argv[0], argv) < 0)
  907.                 exit(-1);
  908.             continue;
  909.         }
  910.  
  911.         /* File is in packed format. Unpack it */
  912.  
  913.         if((outfd = open(untemp, O_EXCL | O_CREAT | O_WRONLY)) < 0)
  914.         {
  915.             if(errno != EEXIST)
  916.             {
  917.                 perror(untemp);
  918.                 exit(-1);
  919.             }
  920.             if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
  921.             {
  922.                 perror(untemp);
  923.                 exit(-1);
  924.             }
  925.         }
  926.  
  927.         lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  928.         if(fcntl(outfd, F_SETLK, &lck) < 0)
  929.         {
  930.             (void)close(infd);
  931.             (void)close(outfd);
  932.             continue;
  933.         }
  934.  
  935.         /* Start decompressing executable */
  936.  
  937.         if(dodecode(infd, outfd) != 0)
  938.         {
  939.             if(unlink(untemp) < 0)
  940.                 perror(untemp);
  941.             exit(-1);
  942.         }
  943.  
  944.         (void)close(infd);
  945.  
  946.         /* Now set execute permissions on the beastie */
  947.  
  948.         if(chmod(untemp, perms) < 0)
  949.         {
  950.             perror(untemp);
  951.             if(unlink(untemp) < 0)
  952.                 perror(untemp);
  953.             exit(-1);
  954.         }
  955.  
  956.         if(chown(untemp, owner, group) < 0)
  957.         {
  958.             perror(untemp);
  959.             if(unlink(untemp) < 0)
  960.                 perror(untemp);
  961.             exit(-1);
  962.         }
  963.  
  964.         /* Rename untemporary file to target executable and close target */
  965.  
  966.         if(rename(untemp, targ) < 0)
  967.         {
  968.             perror(untemp);
  969.             if(unlink(untemp) < 0)
  970.                 perror(untemp);
  971.             exit(-1);
  972.         }
  973.  
  974.         (void)close(outfd);
  975.  
  976.         /* Now create symlink from linkpath to targ if they are not equal */
  977.  
  978.         if(strcmp(linkpath, targ) != 0 && symlink(targ, linkpath) < 0)
  979.         {
  980.             perror(linkpath);
  981.             exit(-1);
  982.         }
  983.  
  984.         /* Everything OK!  Now go exec the executable. */
  985.  
  986.         if(try_to_exec(targ, linkpath, argv) < 0)
  987.             exit(-1);
  988.     } /* for */
  989. } /* untcx_and_exec_nfs */
  990.  
  991.  
  992. void
  993. just_untcx(char *expath, char *untemp)
  994. {
  995. struct    stat    tostat;    /* Stat buffer to check on lengths */
  996. int    owner, group;
  997. int    perms;        /* Saved permissions to restore on target exec */
  998. int    infd, outfd;    /* In and out file descriptors */
  999. struct    flock    lck;    /* File lock structure */
  1000.  
  1001.     /* Stat executable and grab permissions */
  1002.  
  1003.     if(stat(expath, &tostat) < 0)
  1004.     {
  1005.         perror(expath);
  1006.         exit(-1);
  1007.     }
  1008.     perms = (tostat.st_mode & 0777);
  1009.     owner = tostat.st_uid;
  1010.     group = tostat.st_gid;
  1011.  
  1012.     if((infd = open(expath, O_RDWR)) < 0)
  1013.     {
  1014.         perror(expath);
  1015.         exit(-1);
  1016.     }
  1017.  
  1018.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1019.     if(fcntl(infd, F_SETLK, &lck) < 0)
  1020.     {
  1021.         perror(expath);
  1022.         exit(-1);
  1023.     }
  1024.  
  1025.     if(! is_tcx(infd))
  1026.     {
  1027.         (void)fprintf(stderr, "File does not appear to be in tcx format. Aborting\n");
  1028.         exit(-1);
  1029.     }
  1030.  
  1031.     /* File is in packed format. Unpack it */
  1032.  
  1033.     if((outfd = open(untemp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  1034.     {
  1035.         if(errno != EEXIST)
  1036.         {
  1037.             perror(untemp);
  1038.             exit(-1);
  1039.         }
  1040.         if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
  1041.         {
  1042.             perror(untemp);
  1043.             exit(-1);
  1044.         }
  1045.     }
  1046.  
  1047.     /* Start decompressing executable */
  1048.  
  1049.     if(dodecode(infd, outfd) != 0)
  1050.     {
  1051.         if(unlink(untemp) < 0)
  1052.             perror(untemp);
  1053.         exit(-1);
  1054.     }
  1055.  
  1056.     (void)close(outfd);
  1057.  
  1058.     /* Now set execute permissions on the beastie */
  1059.  
  1060.     if(chmod(untemp, perms) < 0)
  1061.     {
  1062.         perror(untemp);
  1063.         if(unlink(untemp) < 0)
  1064.             perror(untemp);
  1065.         exit(-1);
  1066.     }
  1067.  
  1068.     if(chown(untemp, owner, group) < 0)
  1069.     {
  1070.         perror(untemp);
  1071.         if(unlink(untemp) < 0)
  1072.             perror(untemp);
  1073.         exit(-1);
  1074.     }
  1075.  
  1076.     /* Rename untemporary file to target executable and close target */
  1077.  
  1078.     if(rename(untemp, expath) < 0)
  1079.     {
  1080.         perror(untemp);
  1081.         if(unlink(untemp) < 0)
  1082.             perror(untemp);
  1083.         exit(-1);
  1084.     }
  1085.  
  1086.     (void)close(infd);
  1087.     return;
  1088. } /* just_untcx */
  1089.  
  1090.  
  1091. int
  1092. try_to_exec(char *expath, char *lnpath, char *argv[])
  1093. {
  1094. int    infd, try;
  1095. int    logfd;
  1096. FILE    *logfp;
  1097. struct    flock    lck;
  1098.  
  1099.     if((infd = open(lnpath, O_RDONLY)) < 0)
  1100.     {
  1101.         if(errno == ENOENT)
  1102.         {
  1103.             perror(lnpath);
  1104.             return -1;
  1105.         }
  1106.         return 0;
  1107.     }
  1108.  
  1109.     if(is_tcx(infd))
  1110.     {
  1111.         (void)close(infd);
  1112.         return 0;
  1113.     }
  1114.  
  1115.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1116.     for(try = 0; try < 10; try++, PUSLEEP(50000))
  1117.     {
  1118.         if((logfd = open(logpath, O_WRONLY)) < 0)
  1119.             continue;
  1120.         if(fcntl(logfd, F_SETLK, &lck) < 0)
  1121.         {
  1122.             (void)close(logfd);
  1123.             continue;
  1124.         }
  1125.  
  1126.         if((logfp = fopen(logpath, "a+")) == NULL)
  1127.         {
  1128.             (void)close(logfd);
  1129.             continue;
  1130.         }
  1131.  
  1132. #ifdef UNPACK_IN_PLACE
  1133.         (void)fprintf(logfp, "%s\n", expath);
  1134. #else
  1135.         if(strstr(expath, ENFSDIR) == expath)
  1136.             (void)fprintf(logfp, "%s\n", expath);
  1137. #endif
  1138.         if((strstr(lnpath, ENFSDIR) == lnpath) && (strcmp(lnpath, expath) != 0))
  1139.             (void)fprintf(logfp, "%s\n", lnpath);
  1140.         (void)fclose(logfp);
  1141.         (void)close(logfd);
  1142.         break;
  1143.     }
  1144.  
  1145. #if defined(IRIX) || defined(AIX)
  1146.     if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  1147. #else
  1148.     if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1149. #endif
  1150.  
  1151.     /* Reset signals back to normal to prevent carriage through execv */
  1152.  
  1153.     (void)signal(SIGINT, SIG_DFL);
  1154.     (void)signal(SIGHUP, SIG_DFL);
  1155.     (void)signal(SIGTSTP, SIG_DFL);
  1156.     (void)signal(SIGALRM, SIG_DFL);
  1157.     (void)signal(SIGQUIT, SIG_DFL);
  1158.     (void)signal(SIGTERM, SIG_DFL);
  1159.  
  1160.     (void)close(infd);
  1161.     if(execv(lnpath, argv) < 0)
  1162.         perror(lnpath);
  1163.     return -1;
  1164. } /* try_to_exec */
  1165.  
  1166.  
  1167. #if defined(SUNOS)
  1168. void
  1169. update_pstat_info()
  1170. {
  1171. FILE    *fp;
  1172. char    line[256], tmp[10];
  1173. pstat    *curr;
  1174. int    i, pos;
  1175. int    maj, min, dev, ino, cnt;
  1176.  
  1177.     for(pos = 0 ; pos < MAXOPENFILES; pos++)
  1178.         pihash[pos] = (pstat *)NULL;
  1179.  
  1180.     if((fp = popen(PSTATI, "r")) == NULL)
  1181.         return;
  1182.     if(fgets(line, 256, fp) == NULL)
  1183.         return;
  1184.     for(i = 0; fgets(line, 256, fp) != NULL && i < MAXOPENFILES; i++)
  1185.     {
  1186.         curr = parr + i;
  1187.         strncpy(tmp, line+16, 3);    tmp[3] = '\0';    maj = atoi(tmp);
  1188.         strncpy(tmp, line+20, 3);    tmp[3] = '\0';    min = atoi(tmp);
  1189.         strncpy(tmp, line+23, 6);    tmp[6] = '\0';    ino = atoi(tmp);
  1190.         strncpy(tmp, line+61, 4);    tmp[4] = '\0';    cnt = atoi(tmp);
  1191.         dev = maj * 256 + min;
  1192.         pos = PIHASH(dev, ino);
  1193.         curr->dev = dev;
  1194.         curr->ino = ino;
  1195.         curr->cnt = cnt;
  1196.         curr->next = pihash[pos];
  1197.         pihash[pos] = curr;
  1198.     } /* while */
  1199.     pclose(fp);
  1200. } /* update_pstat_info */
  1201. #endif
  1202.  
  1203.  
  1204. int
  1205. scan_logtail(int lastoff)
  1206. {
  1207. char    newpath[MAXPATHLEN], *s;
  1208. int    len;
  1209. FILE    *logfp;
  1210. path    *curr;
  1211. struct    stat    sb;
  1212.  
  1213.     if(lastoff < 0)
  1214.         lastoff = 0;
  1215.     if((logfp = fopen(logpath, "r")) == NULL)
  1216.         return -1;
  1217.     (void)fseek(logfp, lastoff, SEEK_SET);
  1218.     while(fgets(newpath, MAXPATHLEN, logfp) != NULL)
  1219.     {
  1220.         for(s = newpath; *s; s++) if(*s == '\n') *s = '\0';
  1221.  
  1222.         if(lstat(newpath, &sb) < 0)
  1223.             continue;
  1224.  
  1225.         for(curr = worklist; curr != NULL; curr = curr->next)
  1226.             if(strcmp(curr->path, newpath) == 0) break;
  1227.  
  1228.         if(curr != NULL)    /* Reset indicators on known file */
  1229.         {
  1230.             curr->ctime = sb.st_ctime;
  1231. #ifdef UNPACK_IN_PLACE
  1232.             curr->pid = -1;
  1233.             (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
  1234. #endif
  1235.             continue;
  1236.         }
  1237.  
  1238.         if(freelist != NULL)
  1239.         {
  1240.             curr = freelist;
  1241.             freelist = freelist->next;
  1242.         }
  1243.         else
  1244.             if((curr = (path *)malloc(sizeof(path))) == NULL)
  1245.                 continue;
  1246.  
  1247.         (void)strcpy(curr->path, newpath);
  1248. #ifdef UNPACK_IN_PLACE
  1249.         curr->pid = -1;
  1250.         (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
  1251. #endif
  1252.         curr->atime = sb.st_atime;
  1253.         curr->ctime = sb.st_ctime;
  1254.         curr->next = worklist;
  1255.         worklist = curr;
  1256.     } /* while */
  1257.     lastoff = ftell(logfp);
  1258.     (void)fclose(logfp);
  1259.     return lastoff;
  1260. } /* scan_logtail */
  1261.  
  1262.  
  1263. #ifdef UNPACK_IN_PLACE
  1264. int
  1265. is_dir_local(char *dir)
  1266. {
  1267. #if defined(ULTRIX)
  1268. struct  fs_data fsbuf;
  1269. int    success = 1;     /* Returns 0 on "NOT MOUNTED" */
  1270. #else
  1271. struct    statfs    fsbuf;    /* Statfs buffer to check local versus NFS executable */
  1272. int    success = 0;    
  1273. #endif
  1274.  
  1275. #if defined(IRIX)
  1276.     if(statfs(dir, &fsbuf, (int)(sizeof(struct statfs)), 0) < success)
  1277. #else
  1278.     if(statfs(dir, &fsbuf) < success)
  1279. #endif
  1280.         return -1;
  1281.  
  1282.     /* NFS Version 2 returns -1 or 0 for both free inodes, and total */
  1283.     /* inodes to a client, so return false on this condition. */
  1284.  
  1285. #if defined(ULTRIX)
  1286.     if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  1287. #else
  1288.     if((fsbuf.f_files <= 0) && (fsbuf.f_ffree <= 0))
  1289. #endif
  1290.         return 0;
  1291.     return 1;
  1292. } /* is_dir_local */
  1293. #endif
  1294.  
  1295.  
  1296. int
  1297. is_tcx(int fd)
  1298. {
  1299. int    i;
  1300. unsigned char    c;
  1301.  
  1302.     for(i = 0; i < 256; i++)
  1303.         if(read(fd, &c, 1) < 1 || c == 0)
  1304.             break;
  1305.     if((i >= 256) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  1306.         || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  1307.         return 0;
  1308.     return 1;
  1309. } /* is_tcx */
  1310.  
  1311.  
  1312. int
  1313. dodecode(int infd, int outfd)
  1314. {
  1315. int    pid;
  1316. #if defined(IRIX) || defined(AIX)
  1317. int    status;
  1318. #else
  1319. union wait status;
  1320. #endif
  1321.  
  1322.     pid = fork();
  1323.     if(pid < 0) return -1;
  1324.     if(pid == 0)
  1325.     {
  1326.         if(dup2(infd, 0) < 0) exit(-1);     /* Attach infd to stdin */
  1327.         (void)close(infd);
  1328.         if(dup2(outfd, 1) < 0) exit(-1); /* Attach outfd to stdout */
  1329.         (void)close(outfd);
  1330. #ifdef    UNPACKOPTS
  1331.         (void)execl(PATHUNPACK, PATHUNPACK, UNPACKOPTS, (char *)0);
  1332. #else
  1333.         (void)execl(PATHUNPACK, PATHUNPACK, (char *)0);
  1334. #endif
  1335.         exit(-1);
  1336.     }
  1337.     else
  1338.         pid = wait(&status);
  1339.     return WEXITSTATUS(status);
  1340. } /* dodecode */
  1341.  
  1342.  
  1343. #ifdef ULTRIX
  1344. int
  1345. usleep(int usec)
  1346. {
  1347. struct    itimerval    value, dumb;
  1348.  
  1349.     (void)signal(SIGALRM, usleep_sig);
  1350.  
  1351.     if(getitimer(ITIMER_REAL, &value) != 0)
  1352.     {
  1353.         perror("Error: couldn't get timer");
  1354.         return(-1);
  1355.     }
  1356.     value.it_value.tv_sec = value.it_interval.tv_sec = (long) usec / 1000000;
  1357.     value.it_value.tv_usec = value.it_interval.tv_usec = (long) usec % 1000000;
  1358.         
  1359.     if(setitimer(ITIMER_REAL, &value, &dumb) != 0) /* ignore parameter 3 */
  1360.     {
  1361.         perror("Error: couldn't set timer");
  1362.         return(-1);
  1363.     }
  1364.  
  1365.     (void)sigpause(SIGALRM);
  1366.  
  1367.     if(getitimer(ITIMER_REAL, &value) != 0)
  1368.     {
  1369.         perror("Error: couldn't get timer");
  1370.         return(-1);
  1371.     }
  1372.     usec = (value.it_value.tv_sec - value.it_interval.tv_sec) * 1000000;
  1373.     usec += (value.it_value.tv_usec - value.it_interval.tv_usec);
  1374.     return usec;
  1375. }
  1376.  
  1377. int
  1378. usleep_sig()
  1379. {
  1380. } /* usleep_sig */
  1381. #endif
  1382.