home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Exec 5 / CD_Magazyn_EXEC_nr_5.iso / Programy / Programowanie / cvs-1.11.lha / source / amiga / amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-08  |  47.6 KB  |  2,760 lines

  1. /*
  2.  * $Id$
  3.  *
  4.  * :ts=4
  5.  *
  6.  * AmigaOS wrapper routines for GNU CVS, using the AmiTCP V3 API
  7.  * and the SAS/C V6.58 compiler.
  8.  *
  9.  * Written and adapted by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include <exec/memory.h>
  27.  
  28. #include <dos/dosextens.h>
  29. #include <dos/dostags.h>
  30.  
  31. #include <libraries/locale.h>
  32.  
  33. #include <bsdsocket/socketbasetags.h>
  34. #include <libraries/usergroup.h>
  35.  
  36. #include <clib/exec_protos.h>
  37. #include <clib/dos_protos.h>
  38. #include <clib/utility_protos.h>
  39. #include <clib/socket_protos.h>
  40. #include <clib/usergroup_protos.h>
  41. #include <clib/locale_protos.h>
  42. #include <clib/alib_protos.h>
  43.  
  44. #include <pragmas/exec_sysbase_pragmas.h>
  45. #include <pragmas/dos_pragmas.h>
  46. #include <pragmas/utility_pragmas.h>
  47. #include <pragmas/socket_pragmas.h>
  48. #include <pragmas/usergroup_pragmas.h>
  49. #include <pragmas/locale_pragmas.h>
  50.  
  51. #include <sys/types.h>
  52. #include <sys/socket.h>
  53. #include <sys/param.h>
  54. #include <sys/ioctl.h>
  55.  
  56. #include <constructor.h>
  57. #include <utime.h>
  58. #include <stdio.h>
  59. #include <errno.h>
  60. #include <dirent.h>
  61. #include <netdb.h>
  62. #include <stat.h>
  63. #include <signal.h>
  64. #include <stdlib.h>
  65. #include <time.h>
  66. #include <pwd.h>
  67. #include <grp.h>
  68. #include <dos.h>
  69.  
  70. #include <netinet/ip.h>
  71. #include <netinet/tcp.h>
  72.  
  73. #include <net/if.h>
  74. #include <unistd.h>
  75.  
  76. #include <ios1.h>
  77.  
  78. /****************************************************************************/
  79.  
  80. #include "_assert.h"
  81.  
  82. /****************************************************************************/
  83.  
  84. #define const
  85. #define NO_NAME_REPLACEMENT
  86. #include "amiga.h"
  87. #include "error.h"
  88.  
  89. /****************************************************************************/
  90.  
  91. #define UNIX_TIME_OFFSET 252460800
  92.  
  93. /****************************************************************************/
  94.  
  95. #define ZERO    ((BPTR)NULL)
  96. #define SAME    (0)
  97. #define OK        (0)
  98. #define CANNOT    !
  99. #define NOT        !
  100.  
  101. /****************************************************************************/
  102.  
  103. /* This macro lets us long-align structures on the stack */
  104. #define D_S(type,name) \
  105.     char a_##name[sizeof(type)+3]; \
  106.     type *name = (type *)((LONG)(a_##name+3) & ~3)
  107.  
  108. /****************************************************************************/
  109.  
  110. #define NUM_ENTRIES(t)        (sizeof(t) / sizeof(t[0]))
  111.  
  112. /****************************************************************************/
  113.  
  114. #define FIB_IS_FILE(fib)    ((fib)->fib_DirEntryType < 0)
  115. #define FIB_IS_DRAWER(fib)    ((fib)->fib_DirEntryType >= 0 && \
  116.                              (fib)->fib_DirEntryType != ST_SOFTLINK && \
  117.                              (fib)->fib_DirEntryType != ST_LINKDIR)
  118.  
  119. /****************************************************************************/
  120.  
  121. #define FLAG_IS_SET(v,f)    (((v) & (f)) == (f))
  122. #define SET_FLAG(v,f)        (v |= (f))
  123.  
  124. /****************************************************************************/
  125.  
  126. extern void * xmalloc(size_t size);
  127. extern char * xstrdup(const char * const str);
  128.  
  129. /****************************************************************************/
  130.  
  131. extern struct Library * SysBase;
  132. extern struct Library * DOSBase;
  133. extern struct Library * UtilityBase;
  134.  
  135. /****************************************************************************/
  136.  
  137. static struct Library * SocketBase;
  138. static struct Library * UserGroupBase;
  139.  
  140. /****************************************************************************/
  141.  
  142. static struct Library * LocaleBase;
  143.  
  144. /****************************************************************************/
  145.  
  146. long __stack = 20000;
  147.  
  148. /****************************************************************************/
  149.  
  150. static void map_ioerr_to_errno(void);
  151. static int get_minutes_west(void);
  152. static void get_next_buffer(char **buffer_ptr);
  153. static void correct_name(char **name_ptr);
  154. static void dispatch(void);
  155. static void close_libs(void);
  156. static void initialize_libraries(void);
  157. static int recursive_unlink_file_dir(char *f);
  158. static int compare(char **a, char **b);
  159. static void convert_fileinfo_to_stat(struct FileInfoBlock *fib, struct stat *st);
  160. static void restore_home_dir(void);
  161. static int amiga_rcmd(char **remote_hostname, int remote_port, char *local_user, char *remote_user, char *command);
  162.  
  163. /****************************************************************************/
  164.  
  165. static void
  166. map_ioerr_to_errno(void)
  167. {
  168.     /* This routine maps AmigaDOS error codes to
  169.      * Unix error codes, as far as this is possible.
  170.      * This table contains AmigaDOS error codes
  171.      * the emulated routines won't generate. I have
  172.      * included them for the sake of completeness.
  173.      */
  174.     struct { LONG IoErr; int errno; } map_table[] =
  175.     {
  176.         ERROR_NO_FREE_STORE,            ENOMEM,
  177.         ERROR_TASK_TABLE_FULL,            ENOMEM,
  178.         ERROR_BAD_TEMPLATE,                EINVAL,
  179.         ERROR_BAD_NUMBER,                EINVAL,
  180.         ERROR_REQUIRED_ARG_MISSING,        EINVAL,
  181.         ERROR_KEY_NEEDS_ARG,            EINVAL,
  182.         ERROR_TOO_MANY_ARGS,            EINVAL,
  183.         ERROR_UNMATCHED_QUOTES,            EINVAL,
  184.         ERROR_LINE_TOO_LONG,            ENAMETOOLONG,
  185.         ERROR_FILE_NOT_OBJECT,            ENOEXEC,
  186.         ERROR_INVALID_RESIDENT_LIBRARY,    EIO,
  187.         ERROR_NO_DEFAULT_DIR,            EIO,
  188.         ERROR_OBJECT_IN_USE,            EBUSY,
  189.         ERROR_OBJECT_EXISTS,            EEXIST,
  190.         ERROR_DIR_NOT_FOUND,            ENOENT,
  191.         ERROR_OBJECT_NOT_FOUND,            ENOENT,
  192.         ERROR_BAD_STREAM_NAME,            EINVAL,
  193.         ERROR_OBJECT_TOO_LARGE,            EFBIG,
  194.         ERROR_ACTION_NOT_KNOWN,            ENOSYS,
  195.         ERROR_INVALID_COMPONENT_NAME,    EINVAL,
  196.         ERROR_INVALID_LOCK,                EBADF,
  197.         ERROR_OBJECT_WRONG_TYPE,        EFTYPE,
  198.         ERROR_DISK_NOT_VALIDATED,        EROFS,
  199.         ERROR_DISK_WRITE_PROTECTED,        EROFS,
  200.         ERROR_RENAME_ACROSS_DEVICES,    EXDEV,
  201.         ERROR_DIRECTORY_NOT_EMPTY,        ENOTEMPTY,
  202.         ERROR_TOO_MANY_LEVELS,            ENAMETOOLONG,
  203.         ERROR_DEVICE_NOT_MOUNTED,        ENXIO,
  204.         ERROR_SEEK_ERROR,                EIO,
  205.         ERROR_COMMENT_TOO_BIG,            ENAMETOOLONG,
  206.         ERROR_DISK_FULL,                ENOSPC,
  207.         ERROR_DELETE_PROTECTED,            EACCES,
  208.         ERROR_WRITE_PROTECTED,            EACCES,
  209.         ERROR_READ_PROTECTED,            EACCES,
  210.         ERROR_NOT_A_DOS_DISK,            EFTYPE,
  211.         ERROR_NO_DISK,                    EACCES,
  212.         ERROR_NO_MORE_ENTRIES,            EIO,
  213.         ERROR_IS_SOFT_LINK,                EFTYPE,
  214.         ERROR_OBJECT_LINKED,            EIO,
  215.         ERROR_BAD_HUNK,                    ENOEXEC,
  216.         ERROR_NOT_IMPLEMENTED,            ENOSYS,
  217.         ERROR_RECORD_NOT_LOCKED,        EIO,
  218.         ERROR_LOCK_COLLISION,            EACCES,
  219.         ERROR_LOCK_TIMEOUT,                EIO,
  220.         ERROR_UNLOCK_ERROR,                EIO,
  221.         ERROR_BUFFER_OVERFLOW,            EIO,
  222.         ERROR_BREAK,                    EINTR,
  223.         ERROR_NOT_EXECUTABLE,            ENOEXEC
  224.     };
  225.  
  226.     LONG Error = IoErr();
  227.  
  228.     if(Error != OK)
  229.     {
  230.         int i;
  231.  
  232.         /* If nothing else matches, we can always
  233.          * flag it as an I/O error.
  234.          */
  235.         errno = EIO;
  236.  
  237.         for(i = 0 ; i < NUM_ENTRIES(map_table) ; i++)
  238.         {
  239.             if(map_table[i].IoErr == Error)
  240.             {
  241.                 errno = map_table[i].errno;
  242.                 break;
  243.             }
  244.         }
  245.     }
  246. }
  247.  
  248. /****************************************************************************/
  249.  
  250. static int
  251. get_minutes_west(void)
  252. {
  253.     int minutes_west;
  254.  
  255.     if(LocaleBase == NULL)
  256.         LocaleBase = OpenLibrary("locale.library",38);
  257.  
  258.     if(LocaleBase != NULL)
  259.     {
  260.         struct Locale * loc;
  261.  
  262.         loc = OpenLocale(NULL);
  263.  
  264.         minutes_west = loc->loc_GMTOffset;
  265.  
  266.         CloseLocale(loc);
  267.     }
  268.     else
  269.     {
  270.         minutes_west = 0;
  271.     }
  272.  
  273.     return(minutes_west);
  274. }
  275.  
  276. /****************************************************************************/
  277.  
  278. #define MAX_FILENAME_LEN 1024
  279.  
  280. static void
  281. get_next_buffer(char ** buffer_ptr)
  282. {
  283.     static char buffer_slots[8][MAX_FILENAME_LEN];
  284.     static int buffer_index;
  285.  
  286.     (*buffer_ptr) = buffer_slots[buffer_index];
  287.     buffer_index = (buffer_index + 1) % 8;
  288. }
  289.  
  290. /****************************************************************************/
  291.  
  292. static void
  293. correct_name(char ** name_ptr)
  294. {
  295.     char * buffer;
  296.     int len,i;
  297.     char * name;
  298.  
  299.     ENTER();
  300.  
  301.     name = (*name_ptr);
  302.     if(name[0] == '/')
  303.     {
  304.         BOOL done;
  305.  
  306.         SHOWSTRING(name);
  307.  
  308.         get_next_buffer(&buffer);
  309.  
  310.         done = FALSE;
  311.  
  312.         len = strlen(name);
  313.         for(i = 1 ; i <= len ; i++)
  314.         {
  315.             if(name[i] == '/' || name[i] == '\0')
  316.             {
  317.                 memcpy(buffer,name+1,i-1);
  318.                 buffer[i-1] = ':';
  319.                 strcpy(&buffer[i],&name[i+1]);
  320.                 done = TRUE;
  321.                 break;
  322.             }
  323.         }
  324.  
  325.         if(NOT done)
  326.             strcpy(buffer,name);
  327.  
  328.         SHOWSTRING(buffer);
  329.  
  330.         name = buffer;
  331.     }
  332.     else
  333.     {
  334.         len = strlen(name);
  335.  
  336.         SHOWSTRING(name);
  337.  
  338.         for(i = 0 ; i < len-1 ; i++)
  339.         {
  340.             if(name[i] == ':' && name[i+1] == '/')
  341.             {
  342.                 get_next_buffer(&buffer);
  343.  
  344.                 memcpy(buffer,name,i+1);
  345.                 strcpy(&buffer[i+1],&name[i+2]);
  346.  
  347.                 SHOWSTRING(buffer);
  348.  
  349.                 name = buffer;
  350.                 break;
  351.             }
  352.         }
  353.     }
  354.  
  355.     if(strncmp(name,"./",2) == SAME)
  356.     {
  357.         get_next_buffer(&buffer);
  358.  
  359.         strcpy(buffer,name+2);
  360.         name = buffer;
  361.     }
  362.     else if (strncmp(name,"../",3) == SAME)
  363.     {
  364.         get_next_buffer(&buffer);
  365.  
  366.         strcpy(buffer,name+3);
  367.         name = buffer;
  368.     }
  369.     else if (strcmp(name,".") == SAME)
  370.     {
  371.         get_next_buffer(&buffer);
  372.  
  373.         strcpy(buffer,"");
  374.         name = buffer;
  375.     }
  376.     else if (strcmp(name,"..") == SAME)
  377.     {
  378.         get_next_buffer(&buffer);
  379.  
  380.         strcpy(buffer,"/");
  381.         name = buffer;
  382.     }
  383.  
  384.     len = strlen(name);
  385.     if(len > 0 && name[len-1] == '/')
  386.         name[--len] = '\0';
  387.  
  388.     (*name_ptr) = name;
  389.  
  390.     LEAVE();
  391. }
  392.  
  393. /****************************************************************************/
  394.  
  395. void *
  396. amiga_valloc(size_t bytes)
  397. {
  398.     void * result;
  399.  
  400.     ENTER();
  401.     SHOWVALUE(bytes);
  402.  
  403.     result = malloc(bytes);
  404.  
  405.     RETURN(result);
  406.     return(result);
  407. }
  408.  
  409. /****************************************************************************/
  410.  
  411. int
  412. amiga_symlink(char *to,char *from)
  413. {
  414.     int result;
  415.  
  416.     ENTER();
  417.  
  418.     SHOWSTRING(to);
  419.     SHOWSTRING(from);
  420.  
  421.     result = -1;
  422.     errno = EINVAL;
  423.  
  424.     RETURN(result);
  425.     return(result);
  426. }
  427.  
  428. /****************************************************************************/
  429.  
  430. int
  431. amiga_readlink(char *path,char *buf,int buf_size)
  432. {
  433.     int result;
  434.  
  435.     ENTER();
  436.  
  437.     SHOWSTRING(path);
  438.  
  439.     result = -1;
  440.     errno = EINVAL;
  441.  
  442.     RETURN(result);
  443.     return(result);
  444. }
  445.  
  446. /****************************************************************************/
  447.  
  448. unsigned
  449. amiga_sleep(unsigned seconds)
  450. {
  451.     Delay(TICKS_PER_SECOND * seconds);
  452.  
  453.     return(0);
  454. }
  455.  
  456. /****************************************************************************/
  457.  
  458. unsigned long
  459. amiga_umask(unsigned long mask)
  460. {
  461.     return(0);
  462. }
  463.  
  464. /****************************************************************************/
  465.  
  466. unsigned long
  467. amiga_waitpid(unsigned long pid,int *stat_loc,int options)
  468. {
  469.     return(0);
  470. }
  471.  
  472. /****************************************************************************/
  473.  
  474. int
  475. amiga_utime(char *name,struct utimbuf *time)
  476. {
  477.     struct DateStamp ds;
  478.     int result = -1;
  479.  
  480.     ENTER();
  481.  
  482.     correct_name(&name);
  483.  
  484.     SHOWSTRING(name);
  485.  
  486.     /* Use the current time? */
  487.     if(time == NULL)
  488.     {
  489.         DateStamp(&ds);
  490.     }
  491.     else
  492.     {
  493.         int minutes_west = get_minutes_west();
  494.         ULONG seconds;
  495.  
  496.         /* Convert the time given. */
  497.         if(time->modtime < (UNIX_TIME_OFFSET + 60 * minutes_west))
  498.             seconds = 0;
  499.         else
  500.             seconds = time->modtime - (UNIX_TIME_OFFSET + 60 * minutes_west);    /* translate from UTC to local time */
  501.  
  502.         ds.ds_Days        = (seconds / (24*60*60));
  503.         ds.ds_Minute    = (seconds % (24*60*60)) / 60;
  504.         ds.ds_Tick        = (seconds               % 60) * TICKS_PER_SECOND;
  505.     }
  506.  
  507.     if(SetFileDate((STRPTR)name,&ds))
  508.         result = 0;
  509.  
  510.     RETURN(result);
  511.     return(result);
  512. }
  513.  
  514. /****************************************************************************/
  515.  
  516. int
  517. amiga_geteuid(void)
  518. {
  519.     return(0);
  520. }
  521.  
  522. /****************************************************************************/
  523.  
  524. int
  525. amiga_getuid(void)
  526. {
  527.     return(0);
  528. }
  529.  
  530. /****************************************************************************/
  531.  
  532. long
  533. amiga_getpid(void)
  534. {
  535.     static long old_pid = -1;
  536.     long result;
  537.  
  538.     ENTER();
  539.  
  540.     if(old_pid == -1)
  541.     {
  542.         struct Process * this_process;
  543.         LONG max_cli;
  544.         LONG which;
  545.         LONG i;
  546.  
  547.         this_process = (struct Process *)FindTask(NULL);
  548.  
  549.         Forbid();
  550.  
  551.         which = max_cli = MaxCli();
  552.  
  553.         for(i = 1 ; i <= max_cli ; i++)
  554.         {
  555.             if(FindCliProc(i) == this_process)
  556.             {
  557.                 which = i;
  558.                 break;
  559.             }
  560.         }
  561.  
  562.         Permit();
  563.  
  564.         old_pid = which;
  565.     }
  566.  
  567.     result = old_pid;
  568.  
  569.     RETURN(result);
  570.     return(result);
  571. }
  572.  
  573. /****************************************************************************/
  574.  
  575. char *
  576. amiga_getlogin(void)
  577. {
  578.     static char name[256];
  579.     int i;
  580.  
  581.     ENTER();
  582.  
  583.     if(GetVar("USER",name,sizeof(name),0) <= 0)
  584.     {
  585.         if(GetVar("LOGUSER",name,sizeof(name),0) <= 0)
  586.         {
  587.             if(GetVar("USERNAME",name,sizeof(name),0) <= 0)
  588.                 strcpy(name,"anonymous");
  589.         }
  590.     }
  591.  
  592.     for(i = strlen(name)-1 ; i >= 0 ; i--)
  593.     {
  594.         if(name[i] == ' ' || name[i] == '\t' || name[i] == '\r' || name[i] == '\n')
  595.             name[i] = '\0';
  596.         else
  597.             break;
  598.     }
  599.  
  600.     SHOWSTRING(name);
  601.  
  602.     RETURN(name);
  603.     return(name);
  604. }
  605.  
  606. /****************************************************************************/
  607.  
  608. struct passwd *
  609. amiga_getpwuid(int uid)
  610. {
  611.     static struct passwd pw;
  612.  
  613.     ENTER();
  614.  
  615.     SHOWVALUE(uid);
  616.  
  617.     memset(&pw,0,sizeof(pw));
  618.  
  619.     pw.pw_dir    = "CVSHOME:";        /* pseudo-home directory */
  620.     pw.pw_gid    = 1;                /* ZZZ wrong */
  621.     pw.pw_name    = amiga_getlogin();
  622.     pw.pw_uid    = uid;                /* ZZZ wrong */
  623.  
  624.     RETURN(&pw);
  625.     return(&pw);
  626. }
  627.  
  628. /****************************************************************************/
  629.  
  630. struct passwd *
  631. amiga_getpwnam(char *name)
  632. {
  633.     struct passwd * result;
  634.  
  635.     ENTER();
  636.  
  637.     SHOWSTRING(name);
  638.  
  639.     result = amiga_getpwuid(1);
  640.  
  641.     RETURN(result);
  642.     return(result);
  643. }
  644.  
  645. /****************************************************************************/
  646.  
  647. struct group *
  648. amiga_getgrnam(char *name)
  649. {
  650.     struct group * result;
  651.  
  652.     ENTER();
  653.  
  654.     result = NULL;
  655.  
  656.     RETURN(result);
  657.     return(result);
  658. }
  659.  
  660. /****************************************************************************/
  661.  
  662. char *
  663. amiga_getpass(const char *prompt)
  664. {
  665.     struct UFB * ufb;
  666.     char * result = NULL;
  667.  
  668.     ENTER();
  669.  
  670.     SHOWSTRING(prompt);
  671.  
  672.     ufb = chkufb(fileno(stdin));
  673.     if(ufb != NULL)
  674.     {
  675.         void (*old_sig_handler)(int);
  676.  
  677.         old_sig_handler = signal(SIGINT,SIG_IGN);
  678.  
  679.         if(SetMode(ufb->ufbfh,DOSTRUE))
  680.         {
  681.             static char pwd_buf[128];
  682.             int len,c;
  683.  
  684.             fputs(prompt, stderr);
  685.             fflush(stderr);
  686.  
  687.             len = 0;
  688.             while(TRUE)
  689.             {
  690.                 c = -1;
  691.  
  692.                 while(TRUE)
  693.                 {
  694.                     if(CheckSignal(SIGBREAKF_CTRL_C))
  695.                     {
  696.                         SetMode(ufb->ufbfh,DOSFALSE);
  697.                         signal(SIGINT,old_sig_handler);
  698.  
  699.                         raise(SIGINT);
  700.  
  701.                         signal(SIGINT,SIG_IGN);
  702.                         SetMode(ufb->ufbfh,DOSTRUE);
  703.                     }
  704.  
  705.                     if(WaitForChar(ufb->ufbfh,TICKS_PER_SECOND / 2))
  706.                     {
  707.                         c = fgetc(stdin);
  708.                         if(c == '\003')
  709.                         {
  710.                             SetMode(ufb->ufbfh,DOSFALSE);
  711.                             signal(SIGINT,old_sig_handler);
  712.  
  713.                             raise(SIGINT);
  714.  
  715.                             signal(SIGINT,SIG_IGN);
  716.                             SetMode(ufb->ufbfh,DOSTRUE);
  717.                         }
  718.                         else
  719.                         {
  720.                             break;
  721.                         }
  722.                     }
  723.                 }
  724.  
  725.                 if(c == '\r' || c == '\n')
  726.                     break;
  727.  
  728.                 if(((c >= ' ' && c < 127) || (c >= 160)) && len < sizeof(pwd_buf)-1)
  729.                 {
  730.                     pwd_buf[len++] = c;
  731.                     pwd_buf[len] = '\0';
  732.                 }
  733.             }
  734.  
  735.             SetMode(ufb->ufbfh,DOSFALSE);
  736.  
  737.             fputs("\n",stderr);
  738.  
  739.             SHOWSTRING(pwd_buf);
  740.  
  741.             result = pwd_buf;
  742.         }
  743.  
  744.         signal(SIGINT,old_sig_handler);
  745.     }
  746.  
  747.     RETURN(result);
  748.     return(result);
  749. }
  750.  
  751. /****************************************************************************/
  752.  
  753. int
  754. amiga_gethostname(char * name,int namelen)
  755. {
  756.     static char hostname[256];
  757.     int i,len;
  758.  
  759.     ENTER();
  760.  
  761.     if(GetVar("HOST",hostname,sizeof(hostname),0) <= 0)
  762.     {
  763.         if(GetVar("HOSTNAME",hostname,sizeof(hostname),0) <= 0)
  764.             strcpy(hostname,"anonymous");
  765.     }
  766.  
  767.     for(i = strlen(hostname)-1 ; i >= 0 ; i--)
  768.     {
  769.         if(hostname[i] == ' ' || hostname[i] == '\t' || hostname[i] == '\r' || hostname[i] == '\n')
  770.             hostname[i] = '\0';
  771.         else
  772.             break;
  773.     }
  774.  
  775.     len = strlen(hostname);
  776.     if(len > namelen)
  777.         len = namelen;
  778.  
  779.     memcpy(name,hostname,len);
  780.     name[len] = '\0';
  781.  
  782.     SHOWSTRING(name);
  783.  
  784.     RETURN(0);
  785.     return(0);
  786. }
  787.  
  788. /****************************************************************************/
  789.  
  790. int
  791. amiga_pclose(FILE * pipe)
  792. {
  793.     ENTER();
  794.  
  795.     fclose(pipe);
  796.  
  797.     RETURN(0);
  798.     return(0);
  799. }
  800.  
  801. /****************************************************************************/
  802.  
  803. FILE *
  804. amiga_popen(char * command, const char * mode)
  805. {
  806.     FILE * result = NULL;
  807.     char temp_name[40];
  808.     BPTR output;
  809.  
  810.     ENTER();
  811.  
  812.     correct_name(&command);
  813.  
  814.     SHOWSTRING(command);
  815.     SHOWSTRING(mode);
  816.  
  817.     sprintf(temp_name,"PIPE:%08x.%08x",FindTask(NULL),time(NULL));
  818.  
  819.     output = Open(temp_name,MODE_NEWFILE);
  820.     if(output != ZERO)
  821.     {
  822.         LONG res;
  823.  
  824.         res = SystemTags(command,
  825.             SYS_Input,        Input(),
  826.             SYS_Output,        output,
  827.             SYS_Asynch,        TRUE,
  828.             SYS_UserShell,    TRUE,
  829.             NP_CloseInput,    FALSE,
  830.         TAG_END);
  831.  
  832.         switch(res)
  833.         {
  834.             case 0:
  835.                 result = fopen(temp_name,mode);
  836.                 break;
  837.  
  838.             case -1:
  839.                 errno = ENOMEM;
  840.                 Close(output);
  841.                 break;
  842.  
  843.             default:
  844.                 errno = EIO;
  845.                 break;
  846.         }
  847.     }
  848.     else
  849.     {
  850.         errno = EIO;
  851.     }
  852.  
  853.     RETURN(result);
  854.     return(result);
  855. }
  856.  
  857. /****************************************************************************/
  858.  
  859. static struct MsgPort magic_port;
  860.  
  861. /****************************************************************************/
  862.  
  863. #define ACTION_LOCATE_SOCKET    2050    /* arg1=domain, arg2=type, arg3=protocol -> lock (BPTR) */
  864. #define ACTION_COPY_DIR_SOCKET    2051    /* arg1=socket -> lock (BPTR) */
  865.  
  866. /****************************************************************************/
  867.  
  868. static void
  869. dispatch(void)
  870. {
  871.     struct FileHandle * fh;
  872.     struct FileLock * fl;
  873.     long fd;
  874.     struct DosPacket * dp;
  875.     struct Message * mn;
  876.     LONG res1,res2;
  877.  
  878.     ENTER();
  879.  
  880.     /* We arrive here with interrupt processing disabled. We don't need
  881.      * that and we certainly don't want that either.
  882.      */
  883.     Enable();
  884.  
  885.     /* There's always just one message waiting. */
  886.     mn = GetMsg(&magic_port);
  887.  
  888.     dp = (struct DosPacket *)mn->mn_Node.ln_Name;
  889.  
  890.     res1 = DOSFALSE;
  891.     res2 = 0;
  892.  
  893.     switch(dp->dp_Action)
  894.     {
  895.         case ACTION_FREE_LOCK: /* lock -> bool */
  896.  
  897.             SHOWMSG("ACTION_FREE_LOCK");
  898.  
  899.             fl = BADDR(dp->dp_Arg1);
  900.  
  901.             if(SocketBase != NULL)
  902.                 CloseSocket(fl->fl_Key);
  903.  
  904.             res1 = DOSTRUE;
  905.  
  906.             break;
  907.  
  908.         case ACTION_READ: /* socket,buffer (APTR),length -> length */
  909.  
  910.             SHOWMSG("ACTION_READ");
  911.             SHOWVALUE(dp->dp_Arg3);
  912.  
  913.             if(SocketBase != NULL)
  914.                 res1 = recv(dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,0);
  915.  
  916.             break;
  917.  
  918.         case ACTION_WRITE: /* socket,buffer (APTR),length -> length */
  919.  
  920.             SHOWMSG("ACTION_WRITE");
  921.             SHOWVALUE(dp->dp_Arg3);
  922.  
  923.             if(SocketBase != NULL)
  924.                 res1 = send(dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,0);
  925.  
  926.             break;
  927.  
  928.         case ACTION_END: /* socket -> bool */
  929.  
  930.             SHOWMSG("ACTION_END");
  931.  
  932.             if(SocketBase != NULL)
  933.                 CloseSocket(dp->dp_Arg1);
  934.  
  935.             res1 = DOSTRUE;
  936.  
  937.             break;
  938.  
  939.         case ACTION_FH_FROM_LOCK: /* file handle (BPTR), lock (BPTR) -> bool */
  940.  
  941.             SHOWMSG("ACTION_FH_FROM_LOCK");
  942.  
  943.             fh = BADDR(dp->dp_Arg1);
  944.             fl = BADDR(dp->dp_Arg2);
  945.  
  946.             fh->fh_Arg1 = fl->fl_Key;
  947.  
  948.             FreeVec(fl);
  949.  
  950.             res1 = DOSTRUE;
  951.  
  952.             break;
  953.  
  954.         case ACTION_LOCATE_SOCKET: /* domain, type, protocol -> lock (BPTR) */
  955.  
  956.             SHOWMSG("ACTION_LOCATE_SOCKET");
  957.  
  958.             if(SocketBase != NULL)
  959.                 fd = socket(dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3);
  960.             else
  961.                 fd = -1;
  962.  
  963.             if(fd < 0)
  964.             {
  965.                 res2 = ERROR_NO_FREE_STORE;
  966.                 break;
  967.             }
  968.  
  969.             fl = AllocVec(sizeof(*fl),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  970.             if(fl == NULL)
  971.             {
  972.                 CloseSocket(fd);
  973.                 res2 = ERROR_NO_FREE_STORE;
  974.                 break;
  975.             }
  976.  
  977.             fl->fl_Key        = fd;
  978.             fl->fl_Access    = SHARED_LOCK;
  979.             fl->fl_Task        = &magic_port;
  980.  
  981.             res1 = MKBADDR(fl);
  982.  
  983.             break;
  984.  
  985.         case ACTION_COPY_DIR_SOCKET: /* socket -> lock (BPTR) */
  986.  
  987.             SHOWMSG("ACTION_COPY_DIR_SOCKET");
  988.  
  989.             if(SocketBase != NULL)
  990.                 fd = Dup2Socket(dp->dp_Arg1,-1);
  991.             else
  992.                 fd = -1;
  993.  
  994.             if(fd < 0)
  995.             {
  996.                 res2 = ERROR_NO_FREE_STORE;
  997.                 break;
  998.             }
  999.  
  1000.             fl = AllocVec(sizeof(*fl),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  1001.             if(fl == NULL)
  1002.             {
  1003.                 CloseSocket(fd);
  1004.                 res2 = ERROR_NO_FREE_STORE;
  1005.                 break;
  1006.             }
  1007.  
  1008.             fl->fl_Key        = fd;
  1009.             fl->fl_Access    = SHARED_LOCK;
  1010.             fl->fl_Task        = &magic_port;
  1011.  
  1012.             res1 = MKBADDR(fl);
  1013.  
  1014.             break;
  1015.  
  1016.         default:
  1017.  
  1018.             D(("ACTION_??? (type=%ld)",dp->dp_Action));
  1019.  
  1020.             res2 = ERROR_ACTION_NOT_KNOWN;
  1021.             break;
  1022.     }
  1023.  
  1024.     SHOWVALUE(res1);
  1025.     SHOWVALUE(res2);
  1026.  
  1027.     ReplyPkt(dp,res1,res2);
  1028.  
  1029.     /* Return to the entry state, that is with interrupts disabled
  1030.      * since PutMsg() will turn them back on before it returns.
  1031.      */
  1032.     Disable();
  1033.  
  1034.     LEAVE();
  1035. }
  1036.  
  1037. /****************************************************************************/
  1038.  
  1039. static void
  1040. close_libs(void)
  1041. {
  1042.     if(LocaleBase != NULL)
  1043.     {
  1044.         CloseLibrary(LocaleBase);
  1045.         LocaleBase = NULL;
  1046.     }
  1047.  
  1048.     if(SocketBase != NULL)
  1049.     {
  1050.         CloseLibrary(SocketBase);
  1051.         SocketBase = NULL;
  1052.     }
  1053.  
  1054.     if(UserGroupBase != NULL)
  1055.     {
  1056.         CloseLibrary(UserGroupBase);
  1057.         UserGroupBase = NULL;
  1058.     }
  1059. }
  1060.  
  1061. CBMLIB_DESTRUCTOR(close_libs)
  1062. {
  1063.     ENTER();
  1064.  
  1065.     close_libs();
  1066.  
  1067.     LEAVE();
  1068. }
  1069.  
  1070. /****************************************************************************/
  1071.  
  1072. CBMLIB_CONSTRUCTOR(init_magic_port)
  1073. {
  1074.     ENTER();
  1075.  
  1076.     /* Don't try this at home kids! We're all trained professionals here. */
  1077.     magic_port.mp_Flags    = 3;
  1078.     magic_port.mp_SigTask = (APTR)dispatch;
  1079.     NewList(&magic_port.mp_MsgList);
  1080.  
  1081.     RETURN(0);
  1082.     return(0);
  1083. }
  1084.  
  1085. /****************************************************************************/
  1086.  
  1087. static void
  1088. initialize_libraries(void)
  1089. {
  1090.     ENTER();
  1091.  
  1092.     if(SocketBase == NULL && UserGroupBase == NULL)
  1093.     {
  1094.         SocketBase = OpenLibrary("bsdsocket.library",3);
  1095.         if(SocketBase != NULL)
  1096.         {
  1097.             extern STRPTR _ProgramName;
  1098.  
  1099.             if(SocketBaseTags(
  1100.                 SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  1101.                 SBTM_SETVAL(SBTC_LOGTAGPTR),                _ProgramName,
  1102.             TAG_END) != 0)
  1103.             {
  1104.                 CloseLibrary(SocketBase);
  1105.                 SocketBase = NULL;
  1106.             }
  1107.         }
  1108.  
  1109.         UserGroupBase = OpenLibrary("usergroup.library",1);
  1110.         if(UserGroupBase != NULL)
  1111.         {
  1112.             if(ug_SetupContextTags(_ProgramName,
  1113.                 UGT_ERRNOPTR(sizeof(errno)),&errno,
  1114.             TAG_END) != 0)
  1115.             {
  1116.                 CloseLibrary(UserGroupBase);
  1117.                 UserGroupBase = NULL;
  1118.             }
  1119.         }
  1120.  
  1121.         if(SocketBase == NULL)
  1122.         {
  1123.             fprintf(stderr,"Could not open 'bsdsocket.library' V3; TCP/IP stack not running?\n");
  1124.             exit(RETURN_FAIL);
  1125.         }
  1126.         else if (UserGroupBase == NULL)
  1127.         {
  1128.             fprintf(stderr,"Could not open 'usergroup.library' V1; TCP/IP stack not running?\n");
  1129.             exit(RETURN_FAIL);
  1130.         }
  1131.     }
  1132.  
  1133.     LEAVE();
  1134. }
  1135.  
  1136. /****************************************************************************/
  1137.  
  1138. void __regargs
  1139. __chkabort(void)
  1140. {
  1141.     if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
  1142.         raise(SIGINT);
  1143. }
  1144.  
  1145. void __regargs
  1146. _CXBRK(void)
  1147. {
  1148.     extern STRPTR _ProgramName;
  1149.  
  1150.     /* Flush the standard output streams so that
  1151.      * any following output will be printed after
  1152.      * any buffered stdio output.
  1153.      */
  1154.     if(WBenchMsg == NULL)
  1155.     {
  1156.         /* Don't let anybody stop us. */
  1157.         signal(SIGINT,SIG_IGN);
  1158.         signal(SIGTERM,SIG_IGN);
  1159.  
  1160.         fflush(stdout);
  1161.         fflush(stderr);
  1162.     }
  1163.  
  1164.     /* This routine is called when the program is interrupted. */
  1165.     if(DOSBase->lib_Version >= 37)
  1166.     {
  1167.         PrintFault(ERROR_BREAK,_ProgramName);
  1168.     }
  1169.     else
  1170.     {
  1171.         const char *famousLastWords = ": *** Break";
  1172.         BPTR output = Output();
  1173.  
  1174.         Write(output,(APTR)famousLastWords,strlen(famousLastWords));
  1175.         Write(output,_ProgramName,strlen(_ProgramName));
  1176.         Write(output,"\n",1);
  1177.     }
  1178.  
  1179.     restore_home_dir();
  1180.     close_libs();
  1181.  
  1182.     exit(RETURN_WARN);
  1183. }
  1184.  
  1185. /****************************************************************************/
  1186.  
  1187. char *
  1188. amiga_strerror(int code)
  1189. {
  1190.     char * result;
  1191.  
  1192.     ENTER();
  1193.  
  1194.     if(SocketBase != NULL)
  1195.     {
  1196.         struct TagItem tags[2];
  1197.  
  1198.         tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  1199.         tags[0].ti_Data    = code;
  1200.         tags[1].ti_Tag    = TAG_END;
  1201.  
  1202.         SocketBaseTagList(tags);
  1203.  
  1204.         result = (char *)tags[0].ti_Data;
  1205.     }
  1206.     else
  1207.     {
  1208.         result = strerror(code);
  1209.     }
  1210.  
  1211.     SHOWSTRING(result);
  1212.  
  1213.     RETURN(result);
  1214.     return(result);
  1215. }
  1216.  
  1217. /****************************************************************************/
  1218.  
  1219. int
  1220. amiga_mkdir(char *name,int mode)
  1221. {
  1222.     int result = OK;
  1223.     BPTR lock;
  1224.  
  1225.     ENTER();
  1226.  
  1227.     correct_name(&name);
  1228.  
  1229.     SHOWSTRING(name);
  1230.  
  1231.     lock = CreateDir(name);
  1232.     if(lock != ZERO)
  1233.     {
  1234.         UnLock(lock);
  1235.  
  1236.         amiga_chmod(name,mode);
  1237.     }
  1238.     else
  1239.     {
  1240.         LONG error = IoErr();
  1241.  
  1242.         if(error != ERROR_OBJECT_IN_USE)
  1243.         {
  1244.             SetIoErr(error);
  1245.  
  1246.             map_ioerr_to_errno();
  1247.  
  1248.             result = -1;
  1249.         }
  1250.     }
  1251.  
  1252.     RETURN(result);
  1253.     return(result);
  1254. }
  1255.  
  1256. /****************************************************************************/
  1257.  
  1258. struct hostent *
  1259. amiga_gethostbyname(char *name)
  1260. {
  1261.     struct hostent *result;
  1262.  
  1263.     ENTER();
  1264.     SHOWSTRING(name);
  1265.  
  1266.     initialize_libraries();
  1267.  
  1268.     result = gethostbyname(name);
  1269.  
  1270.     RETURN(result);
  1271.     return(result);
  1272. }
  1273.  
  1274. struct servent *
  1275. amiga_getservbyname(char *name,char *proto)
  1276. {
  1277.     struct servent *result;
  1278.  
  1279.     ENTER();
  1280.  
  1281.     SHOWSTRING(name);
  1282.     SHOWSTRING(proto);
  1283.  
  1284.     initialize_libraries();
  1285.  
  1286.     result = getservbyname(name,proto);
  1287.  
  1288.     RETURN(result);
  1289.     return(result);
  1290. }
  1291.  
  1292. /****************************************************************************/
  1293.  
  1294. int
  1295. amiga_bind(int fd,struct sockaddr *name,int namelen)
  1296. {
  1297.     struct FileHandle * fh;
  1298.     struct UFB * ufb;
  1299.     int result = -1;
  1300.  
  1301.     ENTER();
  1302.  
  1303.     initialize_libraries();
  1304.  
  1305.     ufb = chkufb(fd);
  1306.     if(ufb == NULL)
  1307.     {
  1308.         errno = EIO;
  1309.         goto out;
  1310.     }
  1311.  
  1312.     fh = (struct FileHandle *)BADDR(ufb->ufbfh);
  1313.     if(fh->fh_Type != &magic_port)
  1314.     {
  1315.         errno = EBADF;
  1316.         goto out;
  1317.     }
  1318.  
  1319.     result = bind(fh->fh_Arg1,name,namelen);
  1320.  
  1321.  out:
  1322.  
  1323.     RETURN(result);
  1324.     return(result);
  1325. }
  1326.  
  1327. int
  1328. amiga_connect(int fd,struct sockaddr *name,int namelen)
  1329. {
  1330.     struct FileHandle * fh;
  1331.     struct UFB * ufb;
  1332.     int result = -1;
  1333.  
  1334.     ENTER();
  1335.  
  1336.     initialize_libraries();
  1337.  
  1338.     ufb = chkufb(fd);
  1339.     if(ufb == NULL)
  1340.     {
  1341.         errno = EIO;
  1342.         goto out;
  1343.     }
  1344.  
  1345.     fh = (struct FileHandle *)BADDR(ufb->ufbfh);
  1346.     if(fh->fh_Type != &magic_port)
  1347.     {
  1348.         errno = EBADF;
  1349.         goto out;
  1350.     }
  1351.  
  1352.     result = connect(fh->fh_Arg1,name,namelen);
  1353.  
  1354.  out:
  1355.  
  1356.     RETURN(result);
  1357.     return(result);
  1358. }
  1359.  
  1360. int
  1361. amiga_dup(int socketfd)
  1362. {
  1363.     struct FileHandle * fh;
  1364.     BPTR socket_lock = ZERO;
  1365.     BPTR socket_handle = ZERO;
  1366.     int fd = -1;
  1367.     struct UFB * ufb;
  1368.  
  1369.     ENTER();
  1370.  
  1371.     initialize_libraries();
  1372.  
  1373.     ufb = chkufb(socketfd);
  1374.     if(ufb == NULL)
  1375.     {
  1376.         errno = EIO;
  1377.         goto out;
  1378.     }
  1379.  
  1380.     fh = (struct FileHandle *)BADDR(ufb->ufbfh);
  1381.     if(fh->fh_Type != &magic_port)
  1382.     {
  1383.         errno = EBADF;
  1384.         goto out;
  1385.     }
  1386.  
  1387.     socket_lock = DoPkt(&magic_port,ACTION_COPY_DIR_SOCKET,fh->fh_Arg1,    0,0,0,0);
  1388.     if(socket_lock == ZERO)
  1389.     {
  1390.         errno = EIO;
  1391.         goto out;
  1392.     }
  1393.  
  1394.     socket_handle = OpenFromLock(socket_lock);
  1395.     if(socket_handle == ZERO)
  1396.     {
  1397.         errno = EIO;
  1398.         goto out;
  1399.     }
  1400.  
  1401.     socket_lock = ZERO;
  1402.  
  1403.     fd = open("NIL:",O_RDWR,0777);
  1404.     if(fd < 0)
  1405.         goto out;
  1406.  
  1407.     ufb = chkufb(fd);
  1408.     if(ufb == NULL)
  1409.     {
  1410.         int error;
  1411.  
  1412.         error = errno;
  1413.  
  1414.         close(fd);
  1415.         fd = -1;
  1416.  
  1417.         errno = error;
  1418.         goto out;
  1419.     }
  1420.  
  1421.     Close(ufb->ufbfh);
  1422.     ufb->ufbfh = socket_handle;
  1423.  
  1424.     socket_handle = ZERO;
  1425.  
  1426.  out:
  1427.  
  1428.     if(fd < 0)
  1429.     {
  1430.         if(socket_handle != ZERO)
  1431.             Close(socket_handle);
  1432.  
  1433.         UnLock(socket_lock);
  1434.     }
  1435.  
  1436.     RETURN(fd);
  1437.     return(fd);
  1438. }
  1439.  
  1440. int
  1441. amiga_recv(int fd,void *buff,int nbytes,int flags)
  1442. {
  1443.     struct FileHandle * fh;
  1444.     struct UFB * ufb;
  1445.     int result = -1;
  1446.  
  1447.     ENTER();
  1448.  
  1449.     initialize_libraries();
  1450.  
  1451.     ufb = chkufb(fd);
  1452.     if(ufb == NULL)
  1453.     {
  1454.         errno = EIO;
  1455.         goto out;
  1456.     }
  1457.  
  1458.     fh = (struct FileHandle *)BADDR(ufb->ufbfh);
  1459.     if(fh->fh_Type != &magic_port)
  1460.     {
  1461.         errno = EBADF;
  1462.         goto out;
  1463.     }
  1464.  
  1465.     result = recv(fh->fh_Arg1,buff,nbytes,flags);
  1466.  
  1467.  out:
  1468.  
  1469.     RETURN(result);
  1470.     return(result);
  1471. }
  1472.  
  1473. int
  1474. amiga_send(int fd,void *buff,int nbytes,int flags)
  1475. {
  1476.     struct FileHandle * fh;
  1477.     struct UFB * ufb;
  1478.     int result = -1;
  1479.  
  1480.     ENTER();
  1481.  
  1482.     initialize_libraries();
  1483.  
  1484.     ufb = chkufb(fd);
  1485.     if(ufb == NULL)
  1486.     {
  1487.         errno = EIO;
  1488.         goto out;
  1489.     }
  1490.  
  1491.     fh = (struct FileHandle *)BADDR(ufb->ufbfh);
  1492.     if(fh->fh_Type != &magic_port)
  1493.     {
  1494.         errno = EBADF;
  1495.         goto out;
  1496.     }
  1497.  
  1498.     result = send(fh->fh_Arg1,buff,nbytes,flags);
  1499.  
  1500.  out:
  1501.  
  1502.     RETURN(result);
  1503.     return(result);
  1504. }
  1505.  
  1506. int
  1507. amiga_shutdown(int fd,int how)
  1508. {
  1509.     struct FileHandle * fh;
  1510.     struct UFB * ufb;
  1511.     int result = -1;
  1512.  
  1513.     ENTER();
  1514.  
  1515.     initialize_libraries();
  1516.  
  1517.     ufb = chkufb(fd);
  1518.     if(ufb == NULL)
  1519.     {
  1520.         errno = EIO;
  1521.         goto out;
  1522.     }
  1523.  
  1524.     fh = (struct FileHandle *)BADDR(ufb->ufbfh);
  1525.     if(fh->fh_Type != &magic_port)
  1526.     {
  1527.         errno = EBADF;
  1528.         goto out;
  1529.     }
  1530.  
  1531.     result = shutdown(fh->fh_Arg1,how);
  1532.  
  1533.  out:
  1534.  
  1535.     RETURN(result);
  1536.     return(result);
  1537. }
  1538.  
  1539. int
  1540. amiga_socket(int domain,int type,int protocol)
  1541. {
  1542.     BPTR socket_lock;
  1543.     BPTR socket_handle = ZERO;
  1544.     int fd = -1;
  1545.     struct UFB * ufb;
  1546.  
  1547.     ENTER();
  1548.  
  1549.     initialize_libraries();
  1550.  
  1551.     socket_lock = DoPkt(&magic_port,ACTION_LOCATE_SOCKET,domain,type,protocol,    0,0);
  1552.     if(socket_lock == ZERO)
  1553.     {
  1554.         errno = EIO;
  1555.         goto out;
  1556.     }
  1557.  
  1558.     socket_handle = OpenFromLock(socket_lock);
  1559.     if(socket_handle == ZERO)
  1560.     {
  1561.         errno = EIO;
  1562.         goto out;
  1563.     }
  1564.  
  1565.     socket_lock = ZERO;
  1566.  
  1567.     fd = open("NIL:",O_RDWR,0777);
  1568.     if(fd < 0)
  1569.         goto out;
  1570.  
  1571.     ufb = chkufb(fd);
  1572.     if(ufb == NULL)
  1573.     {
  1574.         int error;
  1575.  
  1576.         error = errno;
  1577.  
  1578.         close(fd);
  1579.         fd = -1;
  1580.  
  1581.         errno = error;
  1582.         goto out;
  1583.     }
  1584.  
  1585.     Close(ufb->ufbfh);
  1586.     ufb->ufbfh = socket_handle;
  1587.  
  1588.     socket_handle = ZERO;
  1589.  
  1590.  out:
  1591.  
  1592.     if(fd < 0)
  1593.     {
  1594.         if(socket_handle != ZERO)
  1595.             Close(socket_handle);
  1596.  
  1597.         UnLock(socket_lock);
  1598.     }
  1599.  
  1600.     RETURN(fd);
  1601.     return(fd);
  1602. }
  1603.  
  1604. /****************************************************************************/
  1605.  
  1606. int
  1607. amiga_piped_child(char ** argv,int * to_fd_ptr,int * from_fd_ptr)
  1608. {
  1609.     int len,total_len,quotes,escape,argc,i,j;
  1610.     char * s;
  1611.     char * arg;
  1612.     char * command;
  1613.     BPTR input = ZERO;
  1614.     BPTR output = ZERO;
  1615.     char in_name[40];
  1616.     char out_name[40];
  1617.     int result = -1;
  1618.  
  1619.     ENTER();
  1620.  
  1621.     argc = 0;
  1622.     total_len = 0;
  1623.     for (i = 0 ; argv[i] != NULL ; i++)
  1624.     {
  1625.         argc++;
  1626.         arg = argv[i];
  1627.         len = strlen(arg);
  1628.         quotes = 0;
  1629.  
  1630.         for(j = 0 ; j < len ; j++)
  1631.         {
  1632.             if(arg[j] == ' ' && quotes == 0)
  1633.                 quotes = 2;
  1634.             else if (arg[j] == '\"')
  1635.                 total_len++;
  1636.         }
  1637.  
  1638.         total_len += len + quotes + 1;
  1639.     }
  1640.  
  1641.     command = malloc(total_len+1);
  1642.     if(command == NULL)
  1643.     {
  1644.         errno = ENOMEM;
  1645.         return(-1);
  1646.     }
  1647.  
  1648.     s = command;
  1649.  
  1650.     for (i = 0 ; i < argc ; i++)
  1651.     {
  1652.         arg = argv[i];
  1653.         len = strlen(arg);
  1654.         quotes = escape = 0;
  1655.  
  1656.         for(j = 0 ; j < len ; j++)
  1657.         {
  1658.             if(arg[j] == ' ')
  1659.                 quotes = 1;
  1660.             else if (arg[j] == '\"')
  1661.                 escape = 1;
  1662.  
  1663.             if(quotes && escape)
  1664.                 break;
  1665.         }
  1666.  
  1667.         if(quotes)
  1668.             (*s++) = '\"';
  1669.  
  1670.         for(j = 0 ; j < len ; j++)
  1671.         {
  1672.             if(arg[j] == '\"')
  1673.                 (*s++) = '*';
  1674.  
  1675.             (*s++) = arg[j];
  1676.         }
  1677.  
  1678.         if(quotes)
  1679.             (*s++) = '\"';
  1680.  
  1681.         if(i < argc-1)
  1682.             (*s++) = ' ';
  1683.     }
  1684.  
  1685.     (*s) = '\0';
  1686.  
  1687.     SHOWSTRING(command);
  1688.  
  1689.     sprintf(in_name,"PIPE:in_%08x.%08x",FindTask(NULL),time(NULL));
  1690.     sprintf(out_name,"PIPE:out_%08x.%08x",FindTask(NULL),time(NULL));
  1691.  
  1692.     input = Open(in_name,MODE_OLDFILE);
  1693.     output = Open(out_name,MODE_NEWFILE);
  1694.     if(input != ZERO && output != ZERO)
  1695.     {
  1696.         LONG res;
  1697.  
  1698.         res = SystemTags(command,
  1699.             SYS_Input,        input,
  1700.             SYS_Output,        output,
  1701.             SYS_Asynch,        TRUE,
  1702.             SYS_UserShell,    TRUE,
  1703.         TAG_END);
  1704.  
  1705.         switch(res)
  1706.         {
  1707.             case 0:
  1708.                 (*to_fd_ptr) = open(in_name,O_WRONLY,0777);
  1709.                 if((*to_fd_ptr) == -1)
  1710.                     break;
  1711.  
  1712.                 (*from_fd_ptr) = open(out_name,O_RDONLY,0777);
  1713.                 if((*from_fd_ptr) == -1)
  1714.                     break;
  1715.  
  1716.                 result = 0;
  1717.                 break;
  1718.  
  1719.             case -1:
  1720.                 errno = ENOMEM;
  1721.                 Close(input);
  1722.                 Close(output);
  1723.                 break;
  1724.  
  1725.             default:
  1726.                 errno = EIO;
  1727.                 break;
  1728.         }
  1729.     }
  1730.     else
  1731.     {
  1732.         if(input != ZERO)
  1733.             Close(input);
  1734.  
  1735.         if(output != ZERO)
  1736.             Close(output);
  1737.  
  1738.         errno = EIO;
  1739.     }
  1740.  
  1741.     RETURN(result);
  1742.     return(result);
  1743. }
  1744.  
  1745. /****************************************************************************/
  1746.  
  1747. int
  1748. amiga_isabsolute(char *filename)
  1749. {
  1750.     int result = 0;
  1751.     int i;
  1752.  
  1753.     ENTER();
  1754.  
  1755.     SHOWSTRING(filename);
  1756.  
  1757.     for(i = 0 ; i < strlen(filename) ; i++)
  1758.     {
  1759.         if(filename[i] == ':')
  1760.         {
  1761.             result = 1;
  1762.             break;
  1763.         }
  1764.     }
  1765.  
  1766.     RETURN(result);
  1767.     return(result);
  1768. }
  1769.  
  1770. /****************************************************************************/
  1771.  
  1772. char *
  1773. amiga_last_component(char *path)
  1774. {
  1775.     char * result;
  1776.  
  1777.     ENTER();
  1778.  
  1779.     SHOWSTRING(path);
  1780.  
  1781.     result = FilePart(path);
  1782.  
  1783.     RETURN(result);
  1784.     return(result);
  1785. }
  1786.  
  1787. /****************************************************************************/
  1788.  
  1789. static int
  1790. recursive_unlink_file_dir(char *f)
  1791. {
  1792.     D_S(struct FileInfoBlock,fib);
  1793.     BPTR lock;
  1794.     int res = 0;
  1795.  
  1796.     lock = Lock(f,SHARED_LOCK);
  1797.     if(lock != ZERO)
  1798.     {
  1799.         if(Examine(lock,fib))
  1800.         {
  1801.             if(FIB_IS_DRAWER(fib))
  1802.             {
  1803.                 char name[110];
  1804.  
  1805.                 name[0] = '\0';
  1806.  
  1807.                 while(ExNext(lock,fib))
  1808.                 {
  1809.                     if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
  1810.                     {
  1811.                         res = -1;
  1812.                         break;
  1813.                     }
  1814.  
  1815.                     if(name[0] != '\0')
  1816.                     {
  1817.                         if(DeleteFile(name))
  1818.                         {
  1819.                             res = -1;
  1820.                             break;
  1821.                         }
  1822.  
  1823.                         name[0] = '\0';
  1824.                     }
  1825.  
  1826.                     if(FIB_IS_DRAWER(fib))
  1827.                     {
  1828.                         BPTR old_dir;
  1829.  
  1830.                         old_dir = CurrentDir(lock);
  1831.                         res = recursive_unlink_file_dir(fib->fib_FileName);
  1832.                         CurrentDir(old_dir);
  1833.  
  1834.                         if(res != 0)
  1835.                             break;
  1836.                     }
  1837.  
  1838.                     strcpy(name,fib->fib_FileName);
  1839.                 }
  1840.  
  1841.                 if(res == 0 && name[0] != '\0')
  1842.                 {
  1843.                     if(CANNOT DeleteFile(name))
  1844.                         res = -1;
  1845.                 }
  1846.             }
  1847.  
  1848.             UnLock(lock);
  1849.  
  1850.             if(res == 0)
  1851.             {
  1852.                 if(CANNOT DeleteFile(f))
  1853.                     res = -1;
  1854.             }
  1855.         }
  1856.         else
  1857.         {
  1858.             UnLock(lock);
  1859.         }
  1860.     }
  1861.  
  1862.     return(res);
  1863. }
  1864.  
  1865. int
  1866. amiga_unlink_file_dir(char * f)
  1867. {
  1868.     int res;
  1869.  
  1870.     ENTER();
  1871.  
  1872.     correct_name(&f);
  1873.  
  1874.     SHOWSTRING(f);
  1875.  
  1876.     res = recursive_unlink_file_dir(f);
  1877.  
  1878.     RETURN(res);
  1879.     return(res);
  1880. }
  1881.  
  1882. /****************************************************************************/
  1883.  
  1884. int
  1885. amiga_fncmp(char *n1,char *n2)
  1886. {
  1887.     int result;
  1888.  
  1889.     ENTER();
  1890.  
  1891.     SHOWSTRING(n1);
  1892.     SHOWSTRING(n2);
  1893.  
  1894.     result = Stricmp(n1,n2);
  1895.  
  1896.     RETURN(result);
  1897.     return(result);
  1898. }
  1899.  
  1900. /****************************************************************************/
  1901.  
  1902. void
  1903. amiga_fnfold(char *name)
  1904. {
  1905.     int c;
  1906.  
  1907.     while((c = (*(unsigned char *)name)) != '\0')
  1908.         (*name++) = ToLower(c);
  1909. }
  1910.  
  1911. /****************************************************************************/
  1912.  
  1913. int
  1914. amiga_fold_fn_char(int c)
  1915. {
  1916.     int result;
  1917.  
  1918.     result = ToLower(c);
  1919.  
  1920.     return(result);
  1921. }
  1922.  
  1923. /****************************************************************************/
  1924.  
  1925. typedef struct name_node
  1926. {
  1927.     struct name_node *    nn_next;
  1928.     char *                nn_name;
  1929.     BOOL                nn_wild;
  1930. } name_node_t;
  1931.  
  1932. static int
  1933. compare(char **a,char **b)
  1934. {
  1935.     return(Stricmp(*a,*b));
  1936. }
  1937.  
  1938. void
  1939. amiga_expand_wild(int argc,char ** argv,int * _argc,char *** _argv)
  1940. {
  1941.     struct AnchorPath * anchor;
  1942.     name_node_t * root;
  1943.     name_node_t * node;
  1944.     LONG name_plus;
  1945.     LONG name_total;
  1946.     LONG i;
  1947.  
  1948.     ENTER();
  1949.  
  1950.     anchor        = (struct AnchorPath *)xmalloc(sizeof(*anchor) + 2 * MAX_FILENAME_LEN);
  1951.     root        = NULL;
  1952.     name_plus    = 0;
  1953.     name_total    = 0;
  1954.  
  1955.     memset(anchor,0,sizeof(*anchor));
  1956.  
  1957.     anchor->ap_Strlen        = MAX_FILENAME_LEN;
  1958.     anchor->ap_BreakBits    = SIGBREAKF_CTRL_C;
  1959.  
  1960.     for(i = 0 ; i < argc ; i++)
  1961.     {
  1962.         if(i > 0 && ParsePatternNoCase(argv[i],anchor->ap_Buf,2 * MAX_FILENAME_LEN) > 0)
  1963.         {
  1964.             LONG result;
  1965.  
  1966.             result = MatchFirst(argv[i],anchor);
  1967.  
  1968.             while(result == 0)
  1969.             {
  1970.                 node = (name_node_t *)malloc(sizeof(*node) + strlen(anchor->ap_Buf) + 1);
  1971.                 if(node == NULL)
  1972.                 {
  1973.                     char buf[80];
  1974.  
  1975.                     MatchEnd(anchor);
  1976.  
  1977.                     sprintf(buf,"out of memory; can not allocate %lu bytes",
  1978.                         (unsigned long)(sizeof(*node) + strlen(anchor->ap_Buf) + 1));
  1979.  
  1980.                     error(1,0,buf);
  1981.                 }
  1982.  
  1983.                 node->nn_name = (char *)(node + 1);
  1984.                 node->nn_next = root;
  1985.                 node->nn_wild = TRUE;
  1986.  
  1987.                 strcpy(node->nn_name,anchor->ap_Buf);
  1988.  
  1989.                 root = node;
  1990.  
  1991.                 name_plus++;
  1992.                 name_total++;
  1993.  
  1994.                 result = MatchNext(anchor);
  1995.             }
  1996.  
  1997.             MatchEnd(anchor);
  1998.         }
  1999.         else
  2000.         {
  2001.             node = (name_node_t *)xmalloc(sizeof(*node));
  2002.  
  2003.             node->nn_name = argv[i];
  2004.             node->nn_next = root;
  2005.             node->nn_wild = FALSE;
  2006.  
  2007.             root = node;
  2008.  
  2009.             name_total++;
  2010.         }
  2011.     }
  2012.  
  2013.     if(name_plus > 0)
  2014.     {
  2015.         char ** last_wild;
  2016.         char ** index;
  2017.  
  2018.         index = (char **)xmalloc(sizeof(char *) * (name_total + 1));
  2019.  
  2020.         (*_argc) = name_total;
  2021.         (*_argv) = index;
  2022.  
  2023.         index = &(index[name_total]);
  2024.  
  2025.         (*index--) = NULL;
  2026.  
  2027.         node        = root;
  2028.         last_wild    = NULL;
  2029.  
  2030.         while(node != NULL)
  2031.         {
  2032.             if(node->nn_wild)
  2033.             {
  2034.                 if(last_wild == NULL)
  2035.                     last_wild = index;
  2036.             }
  2037.             else
  2038.             {
  2039.                 if(last_wild)
  2040.                 {
  2041.                     if((ULONG)last_wild - (ULONG)index > sizeof(char **))
  2042.                         qsort(index + 1,((ULONG)last_wild - (ULONG)index) / sizeof(char **),sizeof(char *),compare);
  2043.  
  2044.                     last_wild = NULL;
  2045.                 }
  2046.             }
  2047.  
  2048.             (*index--) = node->nn_name;
  2049.  
  2050.             node = node->nn_next;
  2051.         }
  2052.     }
  2053.     else
  2054.     {
  2055.         name_node_t * next;
  2056.  
  2057.         node = root;
  2058.  
  2059.         while(node != NULL)
  2060.         {
  2061.             next = node->nn_next;
  2062.  
  2063.             free(node);
  2064.  
  2065.             node = next;
  2066.         }
  2067.     }
  2068.  
  2069.     free(anchor);
  2070.  
  2071.     LEAVE();
  2072. }
  2073.  
  2074. /****************************************************************************/
  2075.  
  2076. static void
  2077. convert_fileinfo_to_stat(struct FileInfoBlock * fib,struct stat * st)
  2078. {
  2079.     ULONG flags;
  2080.     int mode;
  2081.     long time;
  2082.  
  2083.     /* This routine converts the contents of a FileInfoBlock
  2084.      * into information to fill a Unix-like stat data structure
  2085.      * with.
  2086.      */
  2087.     flags = fib->fib_Protection ^ (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  2088.  
  2089.     if(FIB_IS_DRAWER(fib))
  2090.         mode = S_IFDIR;
  2091.     else
  2092.         mode = S_IFREG;
  2093.  
  2094.     if(FLAG_IS_SET(flags,FIBF_READ))
  2095.         SET_FLAG(mode,S_IRUSR);
  2096.  
  2097.     if(FLAG_IS_SET(flags,FIBF_WRITE) && FLAG_IS_SET(flags,FIBF_DELETE))
  2098.         SET_FLAG(mode,S_IWUSR);
  2099.  
  2100.     if(FLAG_IS_SET(flags,FIBF_EXECUTE))
  2101.         SET_FLAG(mode,S_IXUSR);
  2102.  
  2103.  
  2104.     if(FLAG_IS_SET(flags,FIBF_GRP_READ))
  2105.         SET_FLAG(mode,S_IRGRP);
  2106.  
  2107.     if(FLAG_IS_SET(flags,FIBF_GRP_WRITE) && FLAG_IS_SET(flags,FIBF_GRP_DELETE))
  2108.         SET_FLAG(mode,S_IWGRP);
  2109.  
  2110.     if(FLAG_IS_SET(flags,FIBF_GRP_EXECUTE))
  2111.         SET_FLAG(mode,S_IXGRP);
  2112.  
  2113.  
  2114.     if(FLAG_IS_SET(flags,FIBF_OTR_READ))
  2115.         SET_FLAG(mode,S_IROTH);
  2116.  
  2117.     if(FLAG_IS_SET(flags,FIBF_OTR_WRITE) && FLAG_IS_SET(flags,FIBF_OTR_DELETE))
  2118.         SET_FLAG(mode,S_IWOTH);
  2119.  
  2120.     if(FLAG_IS_SET(flags,FIBF_OTR_EXECUTE))
  2121.         SET_FLAG(mode,S_IXOTH);
  2122.  
  2123.     time = fib->fib_Date.ds_Days * 24*60*60 +
  2124.            fib->fib_Date.ds_Minute * 60 +
  2125.           (fib->fib_Date.ds_Tick / TICKS_PER_SECOND);
  2126.  
  2127.     memset(st,0,sizeof(*st));
  2128.  
  2129.     st->st_mode        = mode;
  2130.     st->st_mtime    = UNIX_TIME_OFFSET + time + 60 * get_minutes_west();    /* translate from local time to UTC */
  2131.     st->st_atime    = st->st_mtime;
  2132.     st->st_ctime    = st->st_mtime;
  2133.  
  2134.     if(FIB_IS_FILE(fib))
  2135.     {
  2136.         st->st_nlink = 1;
  2137.         st->st_size  = fib->fib_Size;
  2138.     }
  2139.     else
  2140.     {
  2141.         st->st_nlink = 2;
  2142.     }
  2143. }
  2144.  
  2145. /****************************************************************************/
  2146.  
  2147. int
  2148. amiga_stat(char *name, struct stat *st)
  2149. {
  2150.     int result = -1;
  2151.     BPTR fileLock;
  2152.     int len;
  2153.  
  2154.     chkabort();
  2155.  
  2156.     correct_name(&name);
  2157.  
  2158.     len = strlen(name);
  2159.  
  2160.     fileLock = Lock((STRPTR)name,SHARED_LOCK);
  2161.     if(fileLock != ZERO)
  2162.     {
  2163.         D_S(struct FileInfoBlock,fib);
  2164.  
  2165.         if(Examine(fileLock,fib))
  2166.         {
  2167.             BPTR parentDir;
  2168.  
  2169.             /* Check if this is a root directory. */
  2170.             parentDir = ParentDir(fileLock);
  2171.             if(parentDir != ZERO)
  2172.             {
  2173.                 /* This is not the root directory. */
  2174.                 UnLock(parentDir);
  2175.             }
  2176.             else
  2177.             {
  2178.                 /* So this is a root directory. Make sure
  2179.                  * that we return proper protection bits for
  2180.                  * it, i.e. that the directory is always
  2181.                  * readable, writable, etc. This may be
  2182.                  * necessary since on the Amiga, root
  2183.                  * directories cannot have any protection
  2184.                  * bits set. Note that the "deletable"
  2185.                  * bits don't make much sense, but then
  2186.                  * these bits work together with the
  2187.                  * writable bits. The lowest four bits
  2188.                  * remain zero, which enables them all.
  2189.                  */
  2190.                 fib->fib_Protection = FIBF_OTR_READ |
  2191.                                       FIBF_OTR_WRITE |
  2192.                                       FIBF_OTR_EXECUTE |
  2193.                                       FIBF_OTR_DELETE |
  2194.                                       FIBF_GRP_READ |
  2195.                                       FIBF_GRP_WRITE |
  2196.                                       FIBF_GRP_EXECUTE |
  2197.                                       FIBF_GRP_DELETE;
  2198.             }
  2199.  
  2200.             convert_fileinfo_to_stat(fib,st);
  2201.  
  2202.             result = OK;
  2203.         }
  2204.         else
  2205.         {
  2206.             map_ioerr_to_errno();
  2207.         }
  2208.  
  2209.         UnLock(fileLock);
  2210.     }
  2211.     else
  2212.     {
  2213.         map_ioerr_to_errno();
  2214.     }
  2215.  
  2216.     return(result);
  2217. }
  2218.  
  2219. /****************************************************************************/
  2220.  
  2221. int
  2222. amiga_lstat(char *name, struct stat *statstruct)
  2223. {
  2224.     int result;
  2225.  
  2226.     result = amiga_stat(name,statstruct);
  2227.  
  2228.     return(result);
  2229. }
  2230.  
  2231. /****************************************************************************/
  2232.  
  2233. int
  2234. amiga_fstat(int fd,struct stat * st)
  2235. {
  2236.     struct UFB * ufb;
  2237.     int result = -1;
  2238.  
  2239.     chkabort();
  2240.  
  2241.     ufb = chkufb(fd);
  2242.     if(ufb != NULL)
  2243.     {
  2244.         D_S(struct FileInfoBlock,fib);
  2245.  
  2246.         if(ExamineFH(ufb->ufbfh,fib))
  2247.         {
  2248.             convert_fileinfo_to_stat(fib,st);
  2249.  
  2250.             result = OK;
  2251.         }
  2252.         else
  2253.         {
  2254.             map_ioerr_to_errno();
  2255.         }
  2256.     }
  2257.  
  2258.     return(result);
  2259. }
  2260.  
  2261. /******************************************************************************/
  2262.  
  2263. int
  2264. amiga_chmod(char *name,int mode)
  2265. {
  2266.     int result = OK;
  2267.     ULONG flags = 0;
  2268.  
  2269.     chkabort();
  2270.  
  2271.     /* Convert the file access modes into
  2272.      * Amiga typical protection bits.
  2273.      */
  2274.     if(FLAG_IS_SET(mode,S_IRUSR))
  2275.         SET_FLAG(flags,FIBF_READ);
  2276.  
  2277.     if(FLAG_IS_SET(mode,S_IWUSR))
  2278.     {
  2279.         SET_FLAG(flags,FIBF_WRITE);
  2280.         SET_FLAG(flags,FIBF_DELETE);
  2281.     }
  2282.  
  2283.     if(FLAG_IS_SET(mode,S_IXUSR))
  2284.         SET_FLAG(flags,FIBF_EXECUTE);
  2285.  
  2286.  
  2287.     if(FLAG_IS_SET(mode,S_IRGRP))
  2288.         SET_FLAG(flags,FIBF_GRP_READ);
  2289.  
  2290.     if(FLAG_IS_SET(mode,S_IWGRP))
  2291.     {
  2292.         SET_FLAG(flags,FIBF_GRP_WRITE);
  2293.         SET_FLAG(flags,FIBF_GRP_DELETE);
  2294.     }
  2295.  
  2296.     if(FLAG_IS_SET(mode,S_IXGRP))
  2297.         SET_FLAG(flags,FIBF_GRP_EXECUTE);
  2298.  
  2299.  
  2300.     if(FLAG_IS_SET(mode,S_IROTH))
  2301.         SET_FLAG(flags,FIBF_OTR_READ);
  2302.  
  2303.     if(FLAG_IS_SET(mode,S_IWOTH))
  2304.     {
  2305.         SET_FLAG(flags,FIBF_OTR_WRITE);
  2306.         SET_FLAG(flags,FIBF_OTR_DELETE);
  2307.     }
  2308.  
  2309.     if(FLAG_IS_SET(mode,S_IXOTH))
  2310.         SET_FLAG(flags,FIBF_OTR_EXECUTE);
  2311.  
  2312.     flags ^= (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  2313.  
  2314.     correct_name(&name);
  2315.  
  2316.     if(CANNOT SetProtection(name,flags))
  2317.     {
  2318.         LONG error;
  2319.  
  2320.         error = IoErr();
  2321.         if(error != ERROR_OBJECT_IN_USE)
  2322.         {
  2323.             SetIoErr(error);
  2324.  
  2325.             map_ioerr_to_errno();
  2326.  
  2327.             result = -1;
  2328.         }
  2329.     }
  2330.  
  2331.     return(result);
  2332. }
  2333.  
  2334. /****************************************************************************/
  2335.  
  2336. int
  2337. amiga_access(char *name,int modes)
  2338. {
  2339.     int result;
  2340.  
  2341.     ENTER();
  2342.  
  2343.     correct_name(&name);
  2344.  
  2345.     SHOWSTRING(name);
  2346.     SHOWVALUE(modes);
  2347.  
  2348.     /* We ignore the 'x' bit since it doesn't matter
  2349.      * on the Amiga.
  2350.      */
  2351.     result = access(name,modes & ~X_OK);
  2352.  
  2353.     RETURN(result);
  2354.     return(result);
  2355. }
  2356.  
  2357. /****************************************************************************/
  2358.  
  2359. static BPTR home_dir;
  2360.  
  2361. static void
  2362. restore_home_dir(void)
  2363. {
  2364.     if(home_dir != ZERO)
  2365.     {
  2366.         UnLock(CurrentDir(home_dir));
  2367.         home_dir = ZERO;
  2368.     }
  2369. }
  2370.  
  2371. DEFAULT_DESTRUCTOR(restore_home_dir)
  2372. {
  2373.     restore_home_dir();
  2374. }
  2375.  
  2376. /****************************************************************************/
  2377.  
  2378. int
  2379. amiga_chdir(char *path)
  2380. {
  2381.     int result;
  2382.  
  2383.     ENTER();
  2384.  
  2385.     if(home_dir == ZERO)
  2386.     {
  2387.         BPTR old_dir;
  2388.  
  2389.         /* This is tricky at best. chdir() will change the
  2390.          * current directory of this process and unlock the
  2391.          * previously active current directory lock. However,
  2392.          * the current directory lock with which this program
  2393.          * was launched *must not* be unlocked; the same lock
  2394.          * the program was launched with must be the one the
  2395.          * program exits with. This is what we are trying to
  2396.          * achieve here.
  2397.          */
  2398.         old_dir = Lock("",SHARED_LOCK);
  2399.         if(old_dir == ZERO)
  2400.         {
  2401.             errno = EIO;
  2402.             result = -1;
  2403.             goto out;
  2404.         }
  2405.  
  2406.         home_dir = CurrentDir(old_dir);
  2407.     }
  2408.  
  2409.     correct_name(&path);
  2410.  
  2411.     SHOWSTRING(path);
  2412.  
  2413.     result = chdir(path);
  2414.  
  2415.  out:
  2416.  
  2417.     RETURN(result);
  2418.     return(result);
  2419. }
  2420.  
  2421. int
  2422. amiga_creat(char *name,int prot)
  2423. {
  2424.     int result;
  2425.  
  2426.     ENTER();
  2427.  
  2428.     correct_name(&name);
  2429.  
  2430.     SHOWSTRING(name);
  2431.     SHOWVALUE(prot);
  2432.  
  2433.     result = creat(name,prot);
  2434.  
  2435.     RETURN(result);
  2436.     return(result);
  2437. }
  2438.  
  2439. FILE *
  2440. amiga_fopen(char *name,const char *modes)
  2441. {
  2442.     FILE * result;
  2443.  
  2444.     ENTER();
  2445.  
  2446.     correct_name(&name);
  2447.  
  2448.     SHOWSTRING(name);
  2449.     SHOWSTRING(modes);
  2450.  
  2451.     result = fopen(name,modes);
  2452.  
  2453.     RETURN(result);
  2454.     return(result);
  2455. }
  2456.  
  2457. int
  2458. amiga_open(char *name,int mode,int prot)
  2459. {
  2460.     int result;
  2461.  
  2462.     ENTER();
  2463.  
  2464.     correct_name(&name);
  2465.  
  2466.     SHOWSTRING(name);
  2467.     SHOWVALUE(mode);
  2468.  
  2469.     result = open(name,mode);
  2470.  
  2471.     RETURN(result);
  2472.     return(result);
  2473. }
  2474.  
  2475. void *
  2476. amiga_opendir(char *dir_name)
  2477. {
  2478.     void * result;
  2479.  
  2480.     ENTER();
  2481.  
  2482.     correct_name(&dir_name);
  2483.  
  2484.     SHOWSTRING(dir_name);
  2485.  
  2486.     result = opendir(dir_name);
  2487.  
  2488.     RETURN(result);
  2489.     return(result);
  2490. }
  2491.  
  2492. int
  2493. amiga_rename(char *old,char *new)
  2494. {
  2495.     int result;
  2496.  
  2497.     ENTER();
  2498.  
  2499.     correct_name(&old);
  2500.     correct_name(&new);
  2501.  
  2502.     SHOWSTRING(old);
  2503.     SHOWSTRING(new);
  2504.  
  2505.     result = rename(old,new);
  2506.     if(result == -1 && errno == EEXIST)
  2507.     {
  2508.         unlink(new);
  2509.         result = rename(old,new);
  2510.     }
  2511.  
  2512.     RETURN(result);
  2513.     return(result);
  2514. }
  2515.  
  2516. int
  2517. amiga_rmdir(char *name)
  2518. {
  2519.     int result;
  2520.  
  2521.     ENTER();
  2522.  
  2523.     correct_name(&name);
  2524.  
  2525.     SHOWSTRING(name);
  2526.  
  2527.     result = rmdir(name);
  2528.  
  2529.     RETURN(result);
  2530.     return(result);
  2531. }
  2532.  
  2533. int
  2534. amiga_unlink(char *name)
  2535. {
  2536.     int result;
  2537.  
  2538.     ENTER();
  2539.  
  2540.     correct_name(&name);
  2541.  
  2542.     SHOWSTRING(name);
  2543.  
  2544.     result = unlink(name);
  2545.  
  2546.     RETURN(result);
  2547.     return(result);
  2548. }
  2549.  
  2550. /****************************************************************************/
  2551.  
  2552. char *
  2553. amiga_cvs_temp_name(void)
  2554. {
  2555.     extern char *Tmpdir;
  2556.     char *value;
  2557.     char *retval;
  2558.     int max_len;
  2559.     int len;
  2560.  
  2561.     ENTER();
  2562.  
  2563.     max_len = strlen (Tmpdir) + 40;
  2564.  
  2565.     value = xmalloc (max_len);
  2566.  
  2567.     strcpy(value,Tmpdir);
  2568.     len = strlen(value);
  2569.     while(len > 0 && value[len-1] == '/')
  2570.         value[--len] = '\0';
  2571.  
  2572.     AddPart(value,"cvsXXXXXX",max_len);
  2573.  
  2574.     retval = mktemp (value);
  2575.  
  2576.     if (retval == NULL)
  2577.         error (1, errno, "cannot generate temporary filename");
  2578.  
  2579.     SHOWSTRING(value);
  2580.  
  2581.     RETURN(value);
  2582.     return(value);
  2583. }
  2584.  
  2585. /****************************************************************************/
  2586.  
  2587. static int amiga_rcmd(char **remote_hostname, int remote_port,char *local_user, char *remote_user,char *command)
  2588. {
  2589.   struct hostent *remote_hp;
  2590.   struct hostent *local_hp;
  2591.   struct sockaddr_in remote_isa;
  2592.   struct sockaddr_in local_isa;
  2593.   char local_hostname[80];
  2594.   char ch;
  2595.   int s;
  2596.   int local_port;
  2597.   int rs;
  2598.  
  2599.   remote_hp = amiga_gethostbyname(*remote_hostname);
  2600.   if(!remote_hp)
  2601.     {
  2602.     perror("couldn't get remote host address");
  2603.     exit(1);
  2604.     }
  2605.  
  2606.   /* Copy remote IP address into socket address structure */
  2607.   memset(&remote_isa,0,sizeof(remote_isa));
  2608.   remote_isa.sin_family = AF_INET;
  2609.   remote_isa.sin_port = htons(remote_port);
  2610.   memcpy(&remote_isa.sin_addr, remote_hp->h_addr, sizeof(remote_isa.sin_addr));
  2611.  
  2612.   amiga_gethostname(local_hostname, 80);
  2613.   local_hp = amiga_gethostbyname(local_hostname);
  2614.   if(!local_hp)
  2615.     {
  2616.     perror("couldn't get local host address");
  2617.     exit(1);
  2618.     }
  2619.  
  2620.   /* Copy local IP address into socket address structure */
  2621.   memset(&local_isa,0,sizeof(local_isa));
  2622.   local_isa.sin_family = AF_INET;
  2623.   memcpy(&local_isa.sin_addr, local_hp->h_addr, sizeof(local_isa.sin_addr));
  2624.  
  2625.   /* Create the local socket */
  2626.   s = amiga_socket(AF_INET, SOCK_STREAM, 0);
  2627.   if(s < 0)
  2628.     {
  2629.     perror("socket failed\n");
  2630.     exit(1);
  2631.     }
  2632.  
  2633.   /* Bind local socket with a port from IPPORT_RESERVED/2 to IPPORT_RESERVED - 1
  2634.      this requires the OPER privilege under VMS -- to allow communication with
  2635.      a stock rshd under UNIX */
  2636.  
  2637.   for(local_port = IPPORT_RESERVED - 1; local_port >= IPPORT_RESERVED/2; local_port--)
  2638.     {
  2639.     local_isa.sin_port = htons(local_port);
  2640.     rs = amiga_bind(s, (struct sockaddr *)&local_isa, sizeof(local_isa));
  2641.     if(rs == 0)
  2642.       break;
  2643.     }
  2644.  
  2645.   /* Bind local socket to an unprivileged port.  A normal rshd will drop the
  2646.      connection; you must be running a patched rshd invoked through inetd for
  2647.      this connection method to work */
  2648.  
  2649.   if (rs != 0)
  2650.     for(local_port = IPPORT_USERRESERVED - 1;
  2651.         local_port > IPPORT_RESERVED;
  2652.         local_port--)
  2653.       {
  2654.       local_isa.sin_port = htons(local_port);
  2655.       rs = amiga_bind(s, (struct sockaddr *)&local_isa, sizeof(local_isa));
  2656.       if(rs == 0)
  2657.         break;
  2658.       }
  2659.  
  2660.   rs = amiga_connect(s, (struct sockaddr *) &remote_isa, sizeof(remote_isa));
  2661.   if(rs == -1)
  2662.     {
  2663.     fprintf(stderr, "connect: errno = %d\n", errno);
  2664.     close(s);
  2665.     exit(2);
  2666.     }
  2667.  
  2668.   /* Now supply authentication information */
  2669.  
  2670.   /* Auxiliary port number for error messages, we don't use it */
  2671.   write(s, "0\0", 2);
  2672.  
  2673.   /* Who are we */
  2674.   write(s, local_user, strlen(local_user) + 1);
  2675.  
  2676.   /* Who do we want to be */
  2677.   write(s, remote_user, strlen(remote_user) + 1);
  2678.  
  2679.   /* What do we want to run */
  2680.   write(s, command, strlen(command) + 1);
  2681.  
  2682.   /* NUL is sent back to us if information is acceptable */
  2683.   read(s, &ch, 1);
  2684.   if(ch != '\0')
  2685.     {
  2686.     errno = EPERM;
  2687.     return -1;
  2688.     }
  2689.  
  2690.   return s;
  2691. }
  2692.  
  2693. static char *cvs_server;
  2694. static char *command;
  2695.  
  2696. extern int trace;
  2697.  
  2698. void
  2699. amiga_start_server (int *tofd, int *fromfd,char *client_user, char *server_user,char *server_host, char *server_cvsroot)
  2700. {
  2701.   int fd, port;
  2702.   char *portenv;
  2703.   struct servent *sptr;
  2704.  
  2705.   if (! (cvs_server = getenv ("CVS_SERVER")))
  2706.       cvs_server = "cvs";
  2707.   command = xmalloc (strlen (cvs_server)
  2708.              + strlen (server_cvsroot)
  2709.              + 50);
  2710.   sprintf(command, "%s server", cvs_server);
  2711.  
  2712.   portenv = getenv("CVS_RCMD_PORT");
  2713.   if (portenv)
  2714.       port = atoi(portenv);
  2715.   else if ((sptr = amiga_getservbyname("shell", "tcp")) != NULL)
  2716.       port = sptr->s_port;
  2717.   else
  2718.       port = 514; /* shell/tcp */
  2719.  
  2720.   if(trace)
  2721.     {
  2722.     fprintf(stderr, "amiga_start_server(): connecting to %s:%d\n",
  2723.             server_host, port);
  2724.     fprintf(stderr, "local_user = %s, remote_user = %s, CVSROOT = %s\n",
  2725.             client_user, (server_user ? server_user : client_user),
  2726.             server_cvsroot);
  2727.     }
  2728.  
  2729.   fd = amiga_rcmd(&server_host, port,
  2730.             client_user,
  2731.             (server_user ? server_user : client_user),
  2732.             command);
  2733.  
  2734.   if (fd < 0)
  2735.      error (1, errno, "cannot start server via rcmd()");
  2736.  
  2737.   (*tofd) = fd;
  2738.   (*fromfd) = fd;
  2739.  
  2740.   free (command);
  2741. }
  2742.  
  2743. void
  2744. amiga_shutdown_server (int fd)
  2745. {
  2746.     /* FIXME: shutdown on files seems to have no bad effects */
  2747.     if (amiga_shutdown (fd, 2) < 0 && errno != ENOTSOCK)
  2748.         error (1, 0, "couldn't shutdown server connection");
  2749.     if (close (fd) < 0)
  2750.         error (1, 0, "couldn't close server connection");
  2751. }
  2752.  
  2753. /****************************************************************************/
  2754.  
  2755. void
  2756. amiga_system_initialize(int * _argc,char *** _argv)
  2757. {
  2758.     amiga_expand_wild((*_argc),(*_argv),_argc,_argv);
  2759. }
  2760.