system.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 
00003   Name:         system.c
00004   Created by:   Stefan Ritt
00005 
00006   Contents:     All operating system dependent system services. This
00007                 file containt routines which hide all system specific
00008                 behaviour to higher levels. This is done by con-
00009                 ditional compiling using the OS_xxx variable defined
00010                 in MIDAS.H.
00011 
00012                 Details about interprocess communication can be
00013                 found in "UNIX distributed programming" by Chris
00014                 Brown, Prentice Hall
00015 
00016   $Log: system.c,v $
00017   Revision 1.83  2004/10/04 07:04:01  olchansk
00018   improve error reporting while manipulating SysV shared memory
00019 
00020   Revision 1.82  2004/01/28 01:22:39  pierre
00021   simple ss_timezone fix
00022 
00023   Revision 1.81  2004/01/22 22:47:11  pierre
00024   correct ss_timezone for VxWorks
00025 
00026   Revision 1.80  2004/01/19 20:19:14  midas
00027   Fixed compiler warnings under Windows
00028 
00029   Revision 1.79  2004/01/19 17:00:24  olchansk
00030   change ss_thread_create() and ss_thread_kill() to use midas_thread_t
00031   include sys/mount.h (moved from midasinc.h to avoid namespace pollution on macosx)
00032   update docs for ss_thread_create()
00033   on darwin/macosx, abort in ss_settime()
00034   add ss_timezone()
00035 
00036   Revision 1.78  2004/01/13 00:52:05  pierre
00037   fix dox comment for vxworks
00038 
00039   Revision 1.77  2004/01/08 08:40:10  midas
00040   Implemented standard indentation
00041 
00042   Revision 1.76  2004/01/08 06:36:10  pierre
00043   Doxygen the file
00044 
00045   Revision 1.75  2003/10/16 22:53:57  midas
00046   Changed return values for ss_thread_create to return threadId.
00047   Added ss_thread_kill for killing the passed threadId. (DBM - Triumf)
00048 
00049   Revision 1.74  2003/07/24 11:09:50  midas
00050   Fixed compiler warning under Windows
00051 
00052   Revision 1.73  2003/06/25 18:22:53  pierre
00053   Added pthread support for UNIX version - DBM
00054 
00055   Revision 1.72  2003/06/12 18:40:59  pierre
00056   include ss_tape_get_blockn
00057 
00058   Revision 1.71  2003/05/02 09:03:01  midas
00059   Fixed buffer overflows by strlcpy()
00060 
00061   Revision 1.70  2003/04/30 06:47:44  midas
00062   Fixed missing variable for NT
00063 
00064   Revision 1.69  2003/04/25 14:03:57  midas
00065   Fixed compiler warnings
00066 
00067   Revision 1.68  2003/04/25 11:47:42  midas
00068   Added ss_force_single_thread()
00069 
00070   Revision 1.67  2003/04/21 03:16:50  olchansk
00071   in ss_daemon_init(), if keep_stdout, keep BOTH stdout AND stderr.
00072   It makes no sense to keep stdout and close stderr.
00073   Stefan okey'ed this change ages ago, but I never commited it, until now.
00074 
00075   Revision 1.66  2003/04/09 13:42:53  midas
00076   Made file compile under C++
00077 
00078   Revision 1.65  2003/03/26 21:08:44  midas
00079   Removed tabs
00080 
00081   Revision 1.64  2002/10/15 19:20:24  olchansk
00082   add more debugging printout to send_tcp() and recv_tcp()
00083 
00084   Revision 1.63  2002/06/25 19:48:18  pierre
00085   doc++ functions
00086 
00087   Revision 1.62  2002/06/25 19:00:57  pierre
00088   doc++ functions
00089 
00090   Revision 1.61  2002/06/03 06:21:59  midas
00091   Fixed bug with stdout
00092 
00093   Revision 1.60  2002/06/03 06:07:15  midas
00094   Added extra parameter to ss_daemon_init to keep stdout
00095 
00096   Revision 1.59  2002/05/28 11:30:21  midas
00097   Made send_tcp() send always all bytes
00098 
00099   Revision 1.58  2001/08/22 13:51:46  midas
00100   Reorganized directio functions
00101 
00102   Revision 1.57  2001/08/07 13:07:20  midas
00103   Fixed typo
00104 
00105   Revision 1.56  2001/06/27 12:16:00  midas
00106   Fixed compiler warnings for IRIX
00107 
00108   Revision 1.55  2001/04/23 08:25:41  midas
00109   Use execvp instead execve so that mserver is searched in the full PATH
00110 
00111   Revision 1.54  2000/11/17 08:25:46  midas
00112   Added disable_shm_write flag for Linux cluster applications
00113 
00114   Revision 1.53  2000/10/20 19:05:35  pierre
00115   - Added ss_exec(...) for pid return.
00116   - Added ss_existpid(...) for pid check.
00117   - ss_system uses ss_exec with dummy pid.
00118 
00119   Revision 1.52  2000/03/08 17:38:14  midas
00120   Fixed BIIIIG bug in ss_mutex_wait_for which made the system under Linux
00121   totally unstable since mutexed didn't work at all with this bug
00122 
00123   Revision 1.51  2000/02/26 00:16:05  midas
00124   Bypass ss_kbhit and ss_getchar after becoming a daemon
00125 
00126   Revision 1.50  2000/02/15 11:07:51  midas
00127   Changed GET_xxx to bit flags
00128 
00129   Revision 1.49  1999/11/09 13:19:25  midas
00130   Fixed bug
00131 
00132   Revision 1.48  1999/11/09 13:17:27  midas
00133   Added secure ODB feature
00134 
00135   Revision 1.47  1999/11/09 08:36:54  midas
00136   Don't use console IO under Windows 95
00137 
00138   Revision 1.46  1999/10/27 13:37:04  midas
00139   Added blank line
00140 
00141   Revision 1.45  1999/10/12 13:42:37  midas
00142   Use execl in ss_system
00143 
00144   Revision 1.44  1999/10/11 14:45:37  midas
00145   Fixed bug
00146 
00147   Revision 1.43  1999/10/11 14:41:10  midas
00148   Added code to close stdin, stdout and stderr in daemon mode
00149 
00150   Revision 1.42  1999/10/11 14:13:47  midas
00151   Added ss_system which executs a program in a seperate process and closes
00152   all file descriptors from the parent. This is needed my mhttpd for example
00153   to launch programs, which should no block on the port 80 socket.
00154 
00155   Revision 1.41  1999/09/17 11:48:08  midas
00156   Alarm system half finished
00157 
00158   Revision 1.40  1999/09/15 08:57:10  midas
00159   Fixed bug im send_tcp
00160 
00161   Revision 1.39  1999/09/15 08:05:51  midas
00162   Ctrl-C handle can now be turned off by using SIG_DFL
00163 
00164   Revision 1.38  1999/08/26 08:50:56  midas
00165   Added missing status check on select() funciton
00166 
00167   Revision 1.37  1999/07/22 19:08:25  pierre
00168   - move static INT ss_in_async_routine_flag above LOCAL_ROUTINE for VxWorks
00169 
00170   Revision 1.36  1999/07/15 07:42:48  midas
00171   Added SIGTERM to ss_ctrlc_handler
00172 
00173   Revision 1.35  1999/07/15 07:35:00  midas
00174   Added ss_ctrlc_handler
00175 
00176   Revision 1.34  1999/07/08 13:41:37  midas
00177   Fixed followup error in ss_tape_read
00178 
00179   Revision 1.33  1999/07/06 09:02:20  midas
00180   Evaluater EINTR in ss_release_mutex
00181 
00182   Revision 1.32  1999/06/23 13:37:26  midas
00183   Fixed compiler warnings
00184 
00185   Revision 1.31  1999/06/23 09:42:28  midas
00186   - Changed all NT comments
00187   - Added ss_settime for VxWrorks
00188 
00189   Revision 1.30  1999/06/02 07:51:08  midas
00190   Fixed compiler error under RH6.0 with semun structure
00191 
00192   Revision 1.29  1999/05/03 10:40:41  midas
00193   Fixed segmentation violation on program close under Unix, when .ODB.SHM
00194   has been created under root, and accessed under normal user
00195 
00196   Revision 1.28  1999/04/30 13:19:55  midas
00197   Changed inter-process communication (ss_resume, bm_notify_clients, etc)
00198   to strings so that server process can receive it's own watchdog produced
00199   messages (pass buffer name insteas buffer handle)
00200 
00201   Revision 1.27  1999/04/30 10:58:59  midas
00202   Added -D debug to screen for mserver
00203 
00204   Revision 1.26  1999/04/29 10:48:03  midas
00205   Implemented "/System/Client Notify" key
00206 
00207   Revision 1.25  1999/04/29 07:06:40  midas
00208   Removed superfluous "{"
00209 
00210   Revision 1.24  1999/04/16 15:11:28  midas
00211   ss_suspends forwards more MSG_BM UPD messages (needed for JMidas seeing
00212   its own messages in parallel to an ODB key update like run start)
00213 
00214   Revision 1.23  1999/02/06 00:10:35  pierre
00215   -Fix timeout unit for ss_mutex_wait_for under VxWorks
00216 
00217   Revision 1.22  1999/02/01 11:53:45  midas
00218   Changed comment
00219 
00220   Revision 1.21  1999/01/22 09:48:16  midas
00221   Added return statements for MSDOS in mutex routines
00222 
00223   Revision 1.20  1999/01/21 23:14:05  pierre
00224   - Fix comments.
00225   - Incorporate ss_mutex_... for OS_VXWORS.
00226   - Rename ss_create_mutex() to ss_thread_create()
00227   - Incorporate ss_thread_create for OS_VXWORS.
00228 
00229   Revision 1.19  1999/01/20 08:55:44  midas
00230   - Renames ss_xxx_mutex to ss_mutex_xxx
00231   - Added timout flag to ss_mutex_wait_for
00232 
00233   Revision 1.18  1999/01/18 17:48:42  pierre
00234   - Correct ss_file_find().
00235 
00236   Revision 1.17  1998/12/10 12:47:51  midas
00237   Changed unexpexted tape error printf to cm_msg
00238 
00239   Revision 1.16  1998/12/10 10:54:52  midas
00240   Forwarded ss_tape_status to 'mt' under UNIX
00241 
00242   Revision 1.15  1998/12/10 10:45:43  midas
00243   Improved tape error codes under NT (now same as UNIX)
00244 
00245   Revision 1.14  1998/12/10 10:17:34  midas
00246   Improved tape status return values under UNIX
00247 
00248   Revision 1.13  1998/11/25 23:44:24  midas
00249   Removed O_RDWR... in ss_tape_open()
00250 
00251   Revision 1.12  1998/10/29 15:56:40  midas
00252   Printout note about unimplemented tape status command
00253 
00254   Revision 1.11  1998/10/29 15:53:52  midas
00255   Added end-of-tape detection under UNIX
00256 
00257   Revision 1.10  1998/10/29 09:37:37  midas
00258   Reordered IPC and server checks in ss_suspend() to avoid timeouts when
00259   analyze is running under full load
00260 
00261   Revision 1.9  1998/10/28 12:02:52  midas
00262   Added NO_PTY to ss_shell()
00263 
00264   Revision 1.8  1998/10/28 11:07:45  midas
00265   Added ss_shell for UNIX
00266 
00267   Revision 1.7  1998/10/27 10:53:48  midas
00268   - Added run start notification
00269   - Added ss_shell() for NT
00270 
00271   Revision 1.6  1998/10/22 12:40:34  midas
00272   Added "oflag" to ss_tape_open()
00273 
00274   Revision 1.5  1998/10/13 06:52:57  midas
00275   Fixed error occuring when .ODB.SHM had zero size
00276 
00277   Revision 1.4  1998/10/12 14:00:19  midas
00278   ss_shm_open returns memory size in case of failure
00279 
00280   Revision 1.3  1998/10/12 12:19:03  midas
00281   Added Log tag in header
00282 
00283   Revision 1.2  1998/10/12 11:59:11  midas
00284   Added Log tag in header
00285 
00286   Previous Revision history
00287   ------------------------------------------------------------------
00288   date        by    modification
00289   ---------   ---   ------------------------------------------------
00290   02-NOV-93   SR    created
00291   02-OCT-94   SR    unix semaphores added
00292   29-SEP-96   SR    tape handling added
00293   11-OCT-96   SR    screen functions added
00294   06-MAY-97   SR    removed .MTX files
00295   06-MAY-97   SR    added ss_syslog routine
00296   02-JUN-97   SR    adapted ss_syslog for ULTRIX
00297   15-MAY-98   PAA   replaces ftime by gettimeofday
00298 
00299 \********************************************************************/
00300 
00301 /**dox***************************************************************/
00302 /** @file system.c
00303 The Midas System file
00304 */
00305 
00306 /** @defgroup msfunctionc  System Functions (ss_xxx)
00307  */
00308 
00309 /**dox***************************************************************/
00310 /** @addtogroup msystemincludecode
00311  *  
00312  *  @{  */
00313 
00314 /**dox***************************************************************/
00315 /** @addtogroup msfunctionc
00316  *  
00317  *  @{  */
00318 
00319 /**dox***************************************************************/
00320 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00321 
00322 
00323 #include "midas.h"
00324 #include "msystem.h"
00325 
00326 #ifdef OS_UNIX
00327 #include <sys/mount.h>
00328 #endif
00329 
00330 static INT ss_in_async_routine_flag = 0;
00331 #ifdef LOCAL_ROUTINES
00332 #include <signal.h>
00333 
00334 /*------------------------------------------------------------------*/
00335 /* globals */
00336 
00337 /* if set, don't write to *SHM file (used for Linux cluster) */
00338 BOOL disable_shm_write = FALSE;
00339 
00340 /*------------------------------------------------------------------*/
00341 INT ss_set_async_flag(INT flag)
00342 /********************************************************************\
00343 
00344   Routine: ss_set_async_flag
00345 
00346   Purpose: Sets the ss_in_async_routine_flag according to the flag
00347      value. This is necessary when semaphore operations under
00348      UNIX are called inside an asynchrounous routine (via alarm)
00349      because they then behave different.
00350 
00351   Input:
00352     INT  flag               May be 1 or 0
00353 
00354   Output:
00355     none
00356 
00357   Function value:
00358     INT                     Previous value of the flag
00359 
00360 \********************************************************************/
00361 {
00362    INT old_flag;
00363 
00364    old_flag = ss_in_async_routine_flag;
00365    ss_in_async_routine_flag = flag;
00366    return old_flag;
00367 }
00368 
00369 /*------------------------------------------------------------------*/
00370 INT ss_shm_open(char *name, INT size, void **adr, HNDLE * handle)
00371 /********************************************************************\
00372 
00373   Routine: ss_shm_open
00374 
00375   Purpose: Create a shared memory region which can be seen by several
00376      processes which know the name.
00377 
00378   Input:
00379     char *name              Name of the shared memory
00380     INT  size               Initial size of the shared memory in bytes
00381                             if .SHM file doesn't exist
00382 
00383   Output:
00384     void  *adr              Address of opened shared memory
00385     HNDLE handle            Handle or key to the shared memory
00386 
00387   Function value:
00388     SS_SUCCESS              Successful completion
00389     SS_CREATED              Shared memory was created
00390     SS_FILE_ERROR           Paging file cannot be created
00391     SS_NO_MEMORY            Not enough memory
00392 
00393 \********************************************************************/
00394 {
00395    INT status;
00396    char mem_name[256], file_name[256], path[256];
00397 
00398    /* Add a leading SM_ to the memory name */
00399    sprintf(mem_name, "SM_%s", name);
00400 
00401    /* Build the filename out of the path, and the name of the shared memory. */
00402    cm_get_path(path);
00403    if (path[0] == 0) {
00404       getcwd(path, 256);
00405 #if defined(OS_VMS)
00406 #elif defined(OS_UNIX)
00407       strcat(path, "/");
00408 #elif defined(OS_WINNT)
00409       strcat(path, "\\");
00410 #endif
00411    }
00412 
00413    strcpy(file_name, path);
00414 #if defined (OS_UNIX)
00415    strcat(file_name, ".");      /* dot file under UNIX */
00416 #endif
00417    strcat(file_name, name);
00418    strcat(file_name, ".SHM");
00419 
00420 #ifdef OS_WINNT
00421 
00422    status = SS_SUCCESS;
00423 
00424    {
00425       HANDLE hFile, hMap;
00426       char str[256], *p;
00427       DWORD file_size;
00428 
00429       /* make the memory name unique using the pathname. This is necessary
00430          because NT doesn't use ftok. So if different experiments are
00431          running in different directories, they should not see the same
00432          shared memory */
00433       strcpy(str, path);
00434 
00435       /* replace special chars by '*' */
00436       while (strpbrk(str, "\\: "))
00437          *strpbrk(str, "\\: ") = '*';
00438       strcat(str, mem_name);
00439 
00440       /* convert to uppercase */
00441       p = str;
00442       while (*p)
00443          *p++ = (char) toupper(*p);
00444 
00445       hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, str);
00446       if (hMap == 0) {
00447          hFile = CreateFile(file_name, GENERIC_READ | GENERIC_WRITE,
00448                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
00449                             OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
00450          if (!hFile) {
00451             cm_msg(MERROR, "ss_shm_open", "CreateFile() failed");
00452             return SS_FILE_ERROR;
00453          }
00454 
00455          file_size = GetFileSize(hFile, NULL);
00456          if (file_size != 0xFFFFFFFF && file_size > 0)
00457             size = file_size;
00458 
00459          hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, size, str);
00460 
00461          if (!hMap) {
00462             status = GetLastError();
00463             cm_msg(MERROR, "ss_shm_open", "CreateFileMapping() failed, error %d", status);
00464             return SS_FILE_ERROR;
00465          }
00466 
00467          CloseHandle(hFile);
00468          status = SS_CREATED;
00469       }
00470 
00471       *adr = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
00472       *handle = (HNDLE) hMap;
00473 
00474       if (adr == NULL) {
00475          cm_msg(MERROR, "ss_shm_open", "MapViewOfFile() failed");
00476          return SS_NO_MEMORY;
00477       }
00478 
00479       return status;
00480    }
00481 
00482 #endif                          /* OS_WINNT */
00483 #ifdef OS_VMS
00484 
00485    status = SS_SUCCESS;
00486 
00487    {
00488       int addr[2];
00489       $DESCRIPTOR(memname_dsc, "dummy");
00490       $DESCRIPTOR(filename_dsc, "dummy");
00491       memname_dsc.dsc$w_length = strlen(mem_name);
00492       memname_dsc.dsc$a_pointer = mem_name;
00493       filename_dsc.dsc$w_length = strlen(file_name);
00494       filename_dsc.dsc$a_pointer = file_name;
00495 
00496       addr[0] = size;
00497       addr[1] = 0;
00498 
00499       status = ppl$create_shared_memory(&memname_dsc, addr, &PPL$M_NOUNI, &filename_dsc);
00500 
00501       if (status == PPL$_CREATED)
00502          status = SS_CREATED;
00503       else if (status != PPL$_NORMAL)
00504          status = SS_FILE_ERROR;
00505 
00506       *adr = (void *) addr[1];
00507       *handle = 0;              /* not used under VMS */
00508 
00509       if (adr == NULL)
00510          return SS_NO_MEMORY;
00511 
00512       return status;
00513    }
00514 
00515 #endif                          /* OS_VMS */
00516 #ifdef OS_UNIX
00517 
00518    status = SS_SUCCESS;
00519 
00520    {
00521       int key, shmid, fh, file_size;
00522       struct shmid_ds buf;
00523 
00524       /* create a unique key from the file name */
00525       key = ftok(file_name, 'M');
00526 
00527       /* if file doesn't exist, create it */
00528       if (key == -1) {
00529          fh = open(file_name, O_CREAT | O_TRUNC | O_BINARY, 0644);
00530          close(fh);
00531          key = ftok(file_name, 'M');
00532 
00533          if (key == -1) {
00534             cm_msg(MERROR, "ss_shm_open", "ftok() failed");
00535             return SS_FILE_ERROR;
00536          }
00537 
00538          status = SS_CREATED;
00539 
00540          /* delete any previously created memory */
00541 
00542          shmid = shmget(key, 0, 0);
00543          shmctl(shmid, IPC_RMID, &buf);
00544       } else {
00545          /* if file exists, retrieve its size */
00546          file_size = (INT) ss_file_size(file_name);
00547          if (file_size > 0)
00548             size = file_size;
00549       }
00550 
00551       /* get the shared memory, create if not existing */
00552       shmid = shmget(key, size, 0);
00553       if (shmid == -1) {
00554          //cm_msg(MINFO, "ss_shm_open", "Creating shared memory segment, key: 0x%x, size: %d",key,size);
00555          shmid = shmget(key, size, IPC_CREAT|IPC_EXCL);
00556          if (shmid == -1 && errno == EEXIST)
00557            {
00558              cm_msg(MERROR, "ss_shm_open", "Shared memory segment with key 0x%x already exists, please remove it manually: ipcrm -M 0x%x",key,key);
00559              return SS_NO_MEMORY;
00560            }
00561          status = SS_CREATED;
00562       }
00563 
00564       if (shmid == -1) {
00565          cm_msg(MERROR, "ss_shm_open", "shmget(key=0x%x,size=%d) failed, errno %d (%s)", key, size, errno, strerror(errno));
00566          return SS_NO_MEMORY;
00567       }
00568 
00569       buf.shm_perm.uid = getuid();
00570       buf.shm_perm.gid = getgid();
00571       buf.shm_perm.mode = 0666;
00572       shmctl(shmid, IPC_SET, &buf);
00573 
00574       *adr = shmat(shmid, 0, 0);
00575       *handle = (HNDLE) shmid;
00576 
00577       if ((*adr) == (void *) (-1)) {
00578          cm_msg(MERROR, "ss_shm_open","shmat(shmid=%d) failed, errno %d (%s)", shmid, errno, strerror(errno));
00579          return SS_NO_MEMORY;
00580       }
00581 
00582       /* if shared memory was created, try to load it from file */
00583       if (status == SS_CREATED) {
00584          fh = open(file_name, O_RDONLY, 0644);
00585          if (fh == -1)
00586             fh = open(file_name, O_CREAT | O_RDWR, 0644);
00587          else
00588             read(fh, *adr, size);
00589          close(fh);
00590       }
00591 
00592       return status;
00593    }
00594 
00595 #endif                          /* OS_UNIX */
00596 }
00597 
00598 /*------------------------------------------------------------------*/
00599 INT ss_shm_close(char *name, void *adr, HNDLE handle, INT destroy_flag)
00600 /********************************************************************\
00601 
00602   Routine: ss_shm_close
00603 
00604   Purpose: Close a shared memory region.
00605 
00606   Input:
00607     char *name              Name of the shared memory
00608     void *adr               Base address of shared memory
00609     HNDLE handle            Handle of shared memeory
00610     BOOL destroy            Shared memory has to be destroyd and
00611           flushed to the mapping file.
00612 
00613   Output:
00614     none
00615 
00616   Function value:
00617     SS_SUCCESS              Successful completion
00618     SS_INVALID_ADDRESS      Invalid base address
00619     SS_FILE_ERROR           Cannot write shared memory file
00620     SS_INVALID_HANDLE       Invalid shared memory handle
00621 
00622 \********************************************************************/
00623 {
00624    char mem_name[256], file_name[256], path[256];
00625 
00626    /*
00627       append a leading SM_ to the memory name to resolve name conflicts
00628       with mutex or semaphore names
00629     */
00630    sprintf(mem_name, "SM_%s", name);
00631 
00632    /* append .SHM and preceed the path for the shared memory file name */
00633    cm_get_path(path);
00634    if (path[0] == 0) {
00635       getcwd(path, 256);
00636 #if defined(OS_VMS)
00637 #elif defined(OS_UNIX)
00638       strcat(path, "/");
00639 #elif defined(OS_WINNT)
00640       strcat(path, "\\");
00641 #endif
00642    }
00643 
00644    strcpy(file_name, path);
00645 #if defined (OS_UNIX)
00646    strcat(file_name, ".");      /* dot file under UNIX */
00647 #endif
00648    strcat(file_name, name);
00649    strcat(file_name, ".SHM");
00650 
00651 #ifdef OS_WINNT
00652 
00653    if (!UnmapViewOfFile(adr))
00654       return SS_INVALID_ADDRESS;
00655 
00656    CloseHandle((HANDLE) handle);
00657 
00658    return SS_SUCCESS;
00659 
00660 #endif                          /* OS_WINNT */
00661 #ifdef OS_VMS
00662 /* outcommented because ppl$delete... makes privilege violation
00663   {
00664   int addr[2], flags, status;
00665   char mem_name[100];
00666   $DESCRIPTOR(memname_dsc, mem_name);
00667 
00668   strcpy(mem_name, "SM_");
00669   strcat(mem_name, name);
00670   memname_dsc.dsc$w_length = strlen(mem_name);
00671 
00672   flags = PPL$M_FLUSH | PPL$M_NOUNI;
00673 
00674   addr[0] = 0;
00675   addr[1] = adr;
00676 
00677   status = ppl$delete_shared_memory( &memname_dsc, addr, &flags);
00678 
00679   if (status == PPL$_NORMAL)
00680     return SS_SUCCESS;
00681 
00682   return SS_INVALID_ADDRESS;
00683   }
00684 */
00685    return SS_INVALID_ADDRESS;
00686 
00687 #endif                          /* OS_VMS */
00688 #ifdef OS_UNIX
00689 
00690    {
00691       struct shmid_ds buf;
00692       FILE *fh;
00693 
00694       /* get info about shared memory */
00695       if (shmctl(handle, IPC_STAT, &buf) < 0) {
00696          cm_msg(MERROR, "ss_shm_close", "shmctl(shmid=%d,IPC_STAT) failed, errno %d (%s)",handle,errno,strerror(errno));
00697          return SS_INVALID_HANDLE;
00698       }
00699 
00700       /* copy to file and destroy if we are the last one */
00701       if (buf.shm_nattch == 1) {
00702          if (!disable_shm_write) {
00703             fh = fopen(file_name, "w");
00704 
00705             if (fh == NULL) {
00706                cm_msg(MERROR, "ss_shm_close",
00707                       "Cannot write to file %s, please check protection", file_name);
00708             } else {
00709                /* write shared memory to file */
00710                fwrite(adr, 1, buf.shm_segsz, fh);
00711                fclose(fh);
00712             }
00713          }
00714 
00715          if (shmdt(adr) < 0) {
00716             cm_msg(MERROR, "ss_shm_close", "shmdt(shmid=%d) failed, errno %d (%s)",handle,errno,strerror(errno));
00717             return SS_INVALID_ADDRESS;
00718          }
00719 
00720          if (shmctl(handle, IPC_RMID, &buf) < 0) {
00721             cm_msg(MERROR, "ss_shm_close", "shmctl(shmid=%d,IPC_RMID) failed, errno %d (%s)",handle,errno,strerror(errno));
00722             return SS_INVALID_ADDRESS;
00723          }
00724       } else
00725          /* only detach if we are not the last */
00726       if (shmdt(adr) < 0) {
00727          cm_msg(MERROR, "ss_shm_close", "shmdt(shmid=%d) failed, errno %d (%s)",handle,errno,strerror(errno));
00728          return SS_INVALID_ADDRESS;
00729       }
00730 
00731       return SS_SUCCESS;
00732    }
00733 
00734 #endif                          /* OS_UNIX */
00735 }
00736 
00737 /*------------------------------------------------------------------*/
00738 INT ss_shm_protect(HNDLE handle, void *adr)
00739 /********************************************************************\
00740 
00741   Routine: ss_shm_protect
00742 
00743   Purpose: Protect a shared memory region, disallow read and write
00744            access to it by this process
00745 
00746   Input:
00747     HNDLE handle            Handle of shared memeory
00748     void  *adr              Address of shared memory
00749 
00750   Output:
00751     none
00752 
00753   Function value:
00754     SS_SUCCESS              Successful completion
00755     SS_INVALID_ADDRESS      Invalid base address
00756 
00757 \********************************************************************/
00758 {
00759 #ifdef OS_WINNT
00760 
00761    if (!UnmapViewOfFile(adr))
00762       return SS_INVALID_ADDRESS;
00763 
00764 #endif                          /* OS_WINNT */
00765 #ifdef OS_UNIX
00766 
00767    if (shmdt(adr) < 0) {
00768       cm_msg(MERROR, "ss_shm_protect", "shmdt() failed");
00769       return SS_INVALID_ADDRESS;
00770    }
00771 #endif                          /* OS_UNIX */
00772    return SS_SUCCESS;
00773 }
00774 
00775 /*------------------------------------------------------------------*/
00776 INT ss_shm_unprotect(HNDLE handle, void **adr)
00777 /********************************************************************\
00778 
00779   Routine: ss_shm_unprotect
00780 
00781   Purpose: Unprotect a shared memory region so that it can be accessed
00782            by this process
00783 
00784   Input:
00785     HNDLE handle            Handle or key to the shared memory, must
00786                             be obtained with ss_shm_open
00787 
00788   Output:
00789     void  *adr              Address of opened shared memory
00790 
00791   Function value:
00792     SS_SUCCESS              Successful completion
00793     SS_NO_MEMORY            Memory mapping failed
00794 
00795 \********************************************************************/
00796 {
00797 #ifdef OS_WINNT
00798 
00799    *adr = MapViewOfFile((HANDLE) handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
00800 
00801    if (*adr == NULL) {
00802       cm_msg(MERROR, "ss_shm_unprotect", "MapViewOfFile() failed");
00803       return SS_NO_MEMORY;
00804    }
00805 #endif                          /* OS_WINNT */
00806 #ifdef OS_UNIX
00807 
00808    *adr = shmat(handle, 0, 0);
00809 
00810    if ((*adr) == (void *) (-1)) {
00811       cm_msg(MERROR, "ss_shm_unprotect", "shmat() failed, errno = %d", errno);
00812       return SS_NO_MEMORY;
00813    }
00814 #endif                          /* OS_UNIX */
00815 
00816    return SS_SUCCESS;
00817 }
00818 
00819 /*------------------------------------------------------------------*/
00820 INT ss_shm_flush(char *name, void *adr, INT size)
00821 /********************************************************************\
00822 
00823   Routine: ss_shm_flush
00824 
00825   Purpose: Flush a shared memory region to its disk file.
00826 
00827   Input:
00828     char *name              Name of the shared memory
00829     void *adr               Base address of shared memory
00830     INT  size               Size of shared memeory
00831 
00832   Output:
00833     none
00834 
00835   Function value:
00836     SS_SUCCESS              Successful completion
00837     SS_INVALID_ADDRESS      Invalid base address
00838 
00839 \********************************************************************/
00840 {
00841    char mem_name[256], file_name[256], path[256];
00842 
00843    /*
00844       append a leading SM_ to the memory name to resolve name conflicts
00845       with mutex or semaphore names
00846     */
00847    sprintf(mem_name, "SM_%s", name);
00848 
00849    /* append .SHM and preceed the path for the shared memory file name */
00850    cm_get_path(path);
00851    if (path[0] == 0) {
00852       getcwd(path, 256);
00853 #if defined(OS_VMS)
00854 #elif defined(OS_UNIX)
00855       strcat(path, "/");
00856 #elif defined(OS_WINNT)
00857       strcat(path, "\\");
00858 #endif
00859    }
00860 
00861    strcpy(file_name, path);
00862 #if defined (OS_UNIX)
00863    strcat(file_name, ".");      /* dot file under UNIX */
00864 #endif
00865    strcat(file_name, name);
00866    strcat(file_name, ".SHM");
00867 
00868 #ifdef OS_WINNT
00869 
00870    if (!FlushViewOfFile(adr, size))
00871       return SS_INVALID_ADDRESS;
00872 
00873    return SS_SUCCESS;
00874 
00875 #endif                          /* OS_WINNT */
00876 #ifdef OS_VMS
00877 
00878    return SS_SUCCESS;
00879 
00880 #endif                          /* OS_VMS */
00881 #ifdef OS_UNIX
00882 
00883    if (!disable_shm_write) {
00884       FILE *fh;
00885 
00886       fh = fopen(file_name, "w");
00887 
00888       if (fh == NULL) {
00889          cm_msg(MERROR, "ss_shm_flush",
00890                 "Cannot write to file %s, please check protection", file_name);
00891       } else {
00892          /* write shared memory to file */
00893          fwrite(adr, 1, size, fh);
00894          fclose(fh);
00895       }
00896    }
00897    return SS_SUCCESS;
00898 
00899 #endif                          /* OS_UNIX */
00900 }
00901 
00902 /*------------------------------------------------------------------*/
00903 INT ss_getthandle(void)
00904 /********************************************************************\
00905 
00906   Routine: ss_getthandle
00907 
00908   Purpose: Return thread handle of current thread
00909 
00910   Input:
00911     none
00912 
00913   Output:
00914     none
00915 
00916   Function value:
00917     INT thread handle
00918 
00919 \********************************************************************/
00920 {
00921 #ifdef OS_WINNT
00922    HANDLE hThread;
00923 
00924    /*
00925       Under Windows NT, it's a little bit tricky to get a thread handle
00926       which can be passed to other processes. First the calling process
00927       has to duplicate the GetCurrentThread() handle, then the process
00928       which gets this handle also has to use DuplicateHandle with the
00929       target process as its own. Then this duplicated handle can be used
00930       to the SupendThread() and ResumeThread() functions.
00931     */
00932 
00933    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
00934                    GetCurrentProcess(), &hThread, THREAD_ALL_ACCESS, TRUE, 0);
00935 
00936    return (INT)hThread;
00937 
00938 #endif                          /* OS_WINNT */
00939 #ifdef OS_VMS
00940 
00941    return 0;
00942 
00943 #endif                          /* OS_VMS */
00944 #ifdef OS_UNIX
00945 
00946    return ss_getpid();
00947 
00948 #endif                          /* OS_VMS */
00949 }
00950 
00951 #endif                          /* LOCAL_ROUTINES */
00952 
00953 /*------------------------------------------------------------------*/
00954 struct {
00955    char c;
00956    double d;
00957 } test_align;
00958 
00959 INT ss_get_struct_align()
00960 /********************************************************************\
00961 
00962   Routine: ss_get_struct_align
00963 
00964   Purpose: Returns compiler alignment of structures. In C, structures
00965      can be byte aligned, word or even quadword aligned. This
00966      can usually be set with compiler switches. This routine
00967      tests this alignment during runtime and returns 1 for
00968      byte alignment, 2 for word alignment, 4 for dword alignment
00969      and 8 for quadword alignment.
00970 
00971   Input:
00972     <none>
00973 
00974   Output:
00975     <none>
00976 
00977   Function value:
00978     INT    Structure alignment
00979 
00980 \********************************************************************/
00981 {
00982    return (PTYPE) (&test_align.d) - (PTYPE) & test_align.c;
00983 }
00984 
00985 /*------------------------------------------------------------------*/
00986 INT ss_getpid(void)
00987 /********************************************************************\
00988 
00989   Routine: ss_getpid
00990 
00991   Purpose: Return process ID of current process
00992 
00993   Input:
00994     none
00995 
00996   Output:
00997     none
00998 
00999   Function value:
01000     INT              Process ID
01001 
01002 \********************************************************************/
01003 {
01004 #ifdef OS_WINNT
01005 
01006    return (int) GetCurrentProcessId();
01007 
01008 #endif                          /* OS_WINNT */
01009 #ifdef OS_VMS
01010 
01011    return getpid();
01012 
01013 #endif                          /* OS_VMS */
01014 #ifdef OS_UNIX
01015 
01016    return getpid();
01017 
01018 #endif                          /* OS_UNIX */
01019 #ifdef OS_VXWORKS
01020 
01021    return 0;
01022 
01023 #endif                          /* OS_VXWORKS */
01024 #ifdef OS_MSDOS
01025 
01026    return 0;
01027 
01028 #endif                          /* OS_MSDOS */
01029 }
01030 
01031 /*------------------------------------------------------------------*/
01032 
01033 static BOOL _single_thread = FALSE;
01034 
01035 void ss_force_single_thread()
01036 {
01037    _single_thread = TRUE;
01038 }
01039 
01040 INT ss_gettid(void)
01041 /********************************************************************\
01042 
01043   Routine: ss_ggettid
01044 
01045   Purpose: Return thread ID of current thread
01046 
01047   Input:
01048     none
01049 
01050   Output:
01051     none
01052 
01053   Function value:
01054     INT              thread ID
01055 
01056 \********************************************************************/
01057 {
01058    /* if forced to single thread mode, simply return fake TID */
01059    if (_single_thread)
01060       return 1;
01061 
01062 #ifdef OS_MSDOS
01063 
01064    return 0;
01065 
01066 #endif                          /* OS_MSDOS */
01067 #ifdef OS_WINNT
01068 
01069    return (int) GetCurrentThreadId();
01070 
01071 #endif                          /* OS_WINNT */
01072 #ifdef OS_VMS
01073 
01074    return ss_getpid();
01075 
01076 #endif                          /* OS_VMS */
01077 #ifdef OS_UNIX
01078 
01079    return ss_getpid();
01080 
01081 #endif                          /* OS_UNIX */
01082 #ifdef OS_VXWORKS
01083 
01084    return ss_getpid();
01085 
01086 #endif                          /* OS_VXWORKS */
01087 }
01088 
01089 /*------------------------------------------------------------------*/
01090 
01091 #ifdef OS_UNIX
01092 void catch_sigchld(int signo)
01093 {
01094    int status;
01095 
01096    wait(&status);
01097    return;
01098 }
01099 #endif
01100 
01101 INT ss_spawnv(INT mode, char *cmdname, char *argv[])
01102 /********************************************************************\
01103 
01104   Routine: ss_spawnv
01105 
01106   Purpose: Spawn a subprocess or detached process
01107 
01108   Input:
01109     INT mode         One of the following modes:
01110            P_WAIT     Wait for the subprocess to compl.
01111            P_NOWAIT   Don't wait for subprocess to compl.
01112            P_DETACH   Create detached process.
01113     char cmdname     Program name to execute
01114     char *argv[]     Optional program arguments
01115 
01116   Output:
01117     none
01118 
01119   Function value:
01120     SS_SUCCESS       Successful completeion
01121     SS_INVALID_NAME  Command could not be executed;
01122 
01123 \********************************************************************/
01124 {
01125 #ifdef OS_WINNT
01126 
01127    if (spawnvp(mode, cmdname, argv) < 0)
01128       return SS_INVALID_NAME;
01129 
01130    return SS_SUCCESS;
01131 
01132 #endif                          /* OS_WINNT */
01133 
01134 #ifdef OS_MSDOS
01135 
01136    spawnvp((int) mode, cmdname, argv);
01137 
01138    return SS_SUCCESS;
01139 
01140 #endif                          /* OS_MSDOS */
01141 
01142 #ifdef OS_VMS
01143 
01144    {
01145       char cmdstring[500], *pc;
01146       INT i, flags, status;
01147       va_list argptr;
01148 
01149       $DESCRIPTOR(cmdstring_dsc, "dummy");
01150 
01151       if (mode & P_DETACH) {
01152          cmdstring_dsc.dsc$w_length = strlen(cmdstring);
01153          cmdstring_dsc.dsc$a_pointer = cmdstring;
01154 
01155          status = sys$creprc(0, &cmdstring_dsc,
01156                              0, 0, 0, 0, 0, NULL, 4, 0, 0, PRC$M_DETACH);
01157       } else {
01158          flags = (mode & P_NOWAIT) ? 1 : 0;
01159 
01160          for (pc = argv[0] + strlen(argv[0]); *pc != ']' && pc != argv[0]; pc--);
01161          if (*pc == ']')
01162             pc++;
01163 
01164          strcpy(cmdstring, pc);
01165 
01166          if (strchr(cmdstring, ';'))
01167             *strchr(cmdstring, ';') = 0;
01168 
01169          strcat(cmdstring, " ");
01170 
01171          for (i = 1; argv[i] != NULL; i++) {
01172             strcat(cmdstring, argv[i]);
01173             strcat(cmdstring, " ");
01174          }
01175 
01176          cmdstring_dsc.dsc$w_length = strlen(cmdstring);
01177          cmdstring_dsc.dsc$a_pointer = cmdstring;
01178 
01179          status = lib$spawn(&cmdstring_dsc, 0, 0, &flags, NULL, 0, 0, 0, 0, 0, 0, 0, 0);
01180       }
01181 
01182       return BM_SUCCESS;
01183    }
01184 
01185 #endif                          /* OS_VMS */
01186 #ifdef OS_UNIX
01187    pid_t child_pid;
01188 
01189 #ifdef OS_ULTRIX
01190    union wait *status;
01191 #else
01192    int status;
01193 #endif
01194 
01195    if ((child_pid = fork()) < 0)
01196       return (-1);
01197 
01198    if (child_pid == 0) {
01199       /* now we are in the child process ... */
01200       child_pid = execvp(cmdname, argv);
01201       return SS_SUCCESS;
01202    } else {
01203       /* still in parent process */
01204       if (mode == P_WAIT)
01205 #ifdef OS_ULTRIX
01206          waitpid(child_pid, status, WNOHANG);
01207 #else
01208          waitpid(child_pid, &status, WNOHANG);
01209 #endif
01210 
01211       else
01212          /* catch SIGCHLD signal to avoid <defunc> processes */
01213          signal(SIGCHLD, catch_sigchld);
01214    }
01215 
01216    return SS_SUCCESS;
01217 
01218 #endif                          /* OS_UNIX */
01219 }
01220 
01221 /*------------------------------------------------------------------*/
01222 INT ss_shell(int sock)
01223 /********************************************************************\
01224 
01225   Routine: ss_shell
01226 
01227   Purpose: Execute shell via socket (like telnetd)
01228 
01229   Input:
01230     int  sock        Socket
01231 
01232   Output:
01233     none
01234 
01235   Function value:
01236     SS_SUCCESS       Successful completeion
01237 
01238 \********************************************************************/
01239 {
01240 #ifdef OS_WINNT
01241 
01242    HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
01243        hChildStdoutRd, hChildStdoutWr,
01244        hChildStderrRd, hChildStderrWr, hSaveStdin, hSaveStdout, hSaveStderr;
01245 
01246    SECURITY_ATTRIBUTES saAttr;
01247    PROCESS_INFORMATION piProcInfo;
01248    STARTUPINFO siStartInfo;
01249    char buffer[256], cmd[256];
01250    DWORD dwRead, dwWritten, dwAvail, i, i_cmd;
01251    fd_set readfds;
01252    struct timeval timeout;
01253 
01254    /* Set the bInheritHandle flag so pipe handles are inherited. */
01255    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
01256    saAttr.bInheritHandle = TRUE;
01257    saAttr.lpSecurityDescriptor = NULL;
01258 
01259    /* Save the handle to the current STDOUT. */
01260    hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
01261 
01262    /* Create a pipe for the child's STDOUT. */
01263    if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
01264       return 0;
01265 
01266    /* Set a write handle to the pipe to be STDOUT. */
01267    if (!SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
01268       return 0;
01269 
01270 
01271    /* Save the handle to the current STDERR. */
01272    hSaveStderr = GetStdHandle(STD_ERROR_HANDLE);
01273 
01274    /* Create a pipe for the child's STDERR. */
01275    if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0))
01276       return 0;
01277 
01278    /* Set a read handle to the pipe to be STDERR. */
01279    if (!SetStdHandle(STD_ERROR_HANDLE, hChildStderrWr))
01280       return 0;
01281 
01282 
01283    /* Save the handle to the current STDIN. */
01284    hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
01285 
01286    /* Create a pipe for the child's STDIN. */
01287    if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
01288       return 0;
01289 
01290    /* Set a read handle to the pipe to be STDIN. */
01291    if (!SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
01292       return 0;
01293 
01294    /* Duplicate the write handle to the pipe so it is not inherited. */
01295    if (!DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE,   /* not inherited */
01296                         DUPLICATE_SAME_ACCESS))
01297       return 0;
01298 
01299    CloseHandle(hChildStdinWr);
01300 
01301    /* Now create the child process. */
01302    memset(&siStartInfo, 0, sizeof(siStartInfo));
01303    siStartInfo.cb = sizeof(STARTUPINFO);
01304    siStartInfo.lpReserved = NULL;
01305    siStartInfo.lpReserved2 = NULL;
01306    siStartInfo.cbReserved2 = 0;
01307    siStartInfo.lpDesktop = NULL;
01308    siStartInfo.dwFlags = 0;
01309 
01310    if (!CreateProcess(NULL, "cmd /Q",   /* command line */
01311                       NULL,     /* process security attributes */
01312                       NULL,     /* primary thread security attributes */
01313                       TRUE,     /* handles are inherited */
01314                       0,        /* creation flags */
01315                       NULL,     /* use parent's environment */
01316                       NULL,     /* use parent's current directory */
01317                       &siStartInfo,     /* STARTUPINFO pointer */
01318                       &piProcInfo))     /* receives PROCESS_INFORMATION */
01319       return 0;
01320 
01321    /* After process creation, restore the saved STDIN and STDOUT. */
01322    SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
01323    SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);
01324    SetStdHandle(STD_ERROR_HANDLE, hSaveStderr);
01325 
01326    i_cmd = 0;
01327 
01328    do {
01329       /* query stderr */
01330       do {
01331          if (!PeekNamedPipe(hChildStderrRd, buffer, 256, &dwRead, &dwAvail, NULL))
01332             break;
01333 
01334          if (dwRead > 0) {
01335             ReadFile(hChildStderrRd, buffer, 256, &dwRead, NULL);
01336             send(sock, buffer, dwRead, 0);
01337          }
01338       } while (dwAvail > 0);
01339 
01340       /* query stdout */
01341       do {
01342          if (!PeekNamedPipe(hChildStdoutRd, buffer, 256, &dwRead, &dwAvail, NULL))
01343             break;
01344          if (dwRead > 0) {
01345             ReadFile(hChildStdoutRd, buffer, 256, &dwRead, NULL);
01346             send(sock, buffer, dwRead, 0);
01347          }
01348       } while (dwAvail > 0);
01349 
01350 
01351       /* check if subprocess still alive */
01352       if (!GetExitCodeProcess(piProcInfo.hProcess, &i))
01353          break;
01354       if (i != STILL_ACTIVE)
01355          break;
01356 
01357       /* query network socket */
01358       FD_ZERO(&readfds);
01359       FD_SET(sock, &readfds);
01360       timeout.tv_sec = 0;
01361       timeout.tv_usec = 100;
01362       select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
01363 
01364       if (FD_ISSET(sock, &readfds)) {
01365          i = recv(sock, cmd + i_cmd, 1, 0);
01366          if (i <= 0)
01367             break;
01368 
01369          /* backspace */
01370          if (cmd[i_cmd] == 8) {
01371             if (i_cmd > 0) {
01372                send(sock, "\b \b", 3, 0);
01373                i_cmd -= 1;
01374             }
01375          } else if (cmd[i_cmd] >= ' ' || cmd[i_cmd] == 13 || cmd[i_cmd] == 10) {
01376             send(sock, cmd + i_cmd, 1, 0);
01377             i_cmd += i;
01378          }
01379       }
01380 
01381       /* linefeed triggers new command */
01382       if (cmd[i_cmd - 1] == 10) {
01383          WriteFile(hChildStdinWrDup, cmd, i_cmd, &dwWritten, NULL);
01384          i_cmd = 0;
01385       }
01386 
01387    } while (TRUE);
01388 
01389    CloseHandle(hChildStdinWrDup);
01390    CloseHandle(hChildStdinRd);
01391    CloseHandle(hChildStderrRd);
01392    CloseHandle(hChildStdoutRd);
01393 
01394    return SS_SUCCESS;
01395 
01396 #endif                          /* OS_WINNT */
01397 
01398 #ifdef OS_UNIX
01399 #ifndef NO_PTY
01400    pid_t pid;
01401    int i, pipe;
01402    char line[32], buffer[1024], shell[32];
01403    fd_set readfds;
01404 
01405    if ((pid = forkpty(&pipe, line, NULL, NULL)) < 0)
01406       return 0;
01407    else if (pid > 0) {
01408       /* parent process */
01409 
01410       do {
01411          FD_ZERO(&readfds);
01412          FD_SET(sock, &readfds);
01413          FD_SET(pipe, &readfds);
01414 
01415          select(FD_SETSIZE, (void *) &readfds, NULL, NULL, NULL);
01416 
01417          if (FD_ISSET(sock, &readfds)) {
01418             memset(buffer, 0, sizeof(buffer));
01419             i = recv(sock, buffer, sizeof(buffer), 0);
01420             if (i <= 0)
01421                break;
01422             if (write(pipe, buffer, i) != i)
01423                break;
01424          }
01425 
01426          if (FD_ISSET(pipe, &readfds)) {
01427             memset(buffer, 0, sizeof(buffer));
01428             i = read(pipe, buffer, sizeof(buffer));
01429             if (i <= 0)
01430                break;
01431             send(sock, buffer, i, 0);
01432          }
01433 
01434       } while (1);
01435    } else {
01436       /* child process */
01437 
01438       if (getenv("SHELL"))
01439          strlcpy(shell, getenv("SHELL"), sizeof(shell));
01440       else
01441          strcpy(shell, "/bin/sh");
01442       execl(shell, shell, 0);
01443    }
01444 #else
01445    send(sock, "not implemented\n", 17, 0);
01446 #endif                          /* NO_PTY */
01447 
01448    return SS_SUCCESS;
01449 
01450 #endif                          /* OS_UNIX */
01451 }
01452 
01453 /*------------------------------------------------------------------*/
01454 static BOOL _daemon_flag;
01455 
01456 INT ss_daemon_init(BOOL keep_stdout)
01457 /********************************************************************\
01458 
01459   Routine: ss_daemon_init
01460 
01461   Purpose: Become a daemon
01462 
01463   Input:
01464     none
01465 
01466   Output:
01467     none
01468 
01469   Function value:
01470     SS_SUCCESS       Successful completeion
01471     SS_ABORT         fork() was not successful, or other problem
01472 
01473 \********************************************************************/
01474 {
01475 #ifdef OS_UNIX
01476 
01477    /* only implemented for UNIX */
01478    int i, fd, pid;
01479 
01480    if ((pid = fork()) < 0)
01481       return SS_ABORT;
01482    else if (pid != 0)
01483       exit(0);                  /* parent finished */
01484 
01485    /* child continues here */
01486 
01487    _daemon_flag = TRUE;
01488 
01489    /* try and use up stdin, stdout and stderr, so other
01490       routines writing to stdout etc won't cause havoc. Copied from smbd */
01491    for (i = 0; i < 3; i++) {
01492       if (keep_stdout && ((i == 1) || (i == 2)))
01493          continue;
01494 
01495       close(i);
01496       fd = open("/dev/null", O_RDWR, 0);
01497       if (fd < 0)
01498          fd = open("/dev/null", O_WRONLY, 0);
01499       if (fd < 0) {
01500          cm_msg(MERROR, "ss_system", "Can't open /dev/null");
01501          return SS_ABORT;
01502       }
01503       if (fd != i) {
01504          cm_msg(MERROR, "ss_system", "Did not get file descriptor");
01505          return SS_ABORT;
01506       }
01507    }
01508 
01509    setsid();                    /* become session leader */
01510    chdir("/");                  /* change working direcotry (not on NFS!) */
01511    umask(0);                    /* clear our file mode createion mask */
01512 
01513 #endif
01514 
01515    return SS_SUCCESS;
01516 }
01517 
01518 /*------------------------------------------------------------------*/
01519 BOOL ss_existpid(INT pid)
01520 /********************************************************************\
01521 
01522   Routine: ss_existpid
01523 
01524   Purpose: Execute a Kill sig=0 which return success if pid found.
01525 
01526   Input:
01527     pid  : pid to check
01528 
01529   Output:
01530     none
01531 
01532   Function value:
01533     TRUE      PID found
01534     FALSE     PID not found
01535 
01536 \********************************************************************/
01537 {
01538 #ifdef OS_UNIX
01539    /* only implemented for UNIX */
01540    return (kill(pid, 0) == 0 ? TRUE : FALSE);
01541 #else
01542    cm_msg(MINFO, "ss_existpid", "implemented for UNIX only");
01543    return FALSE;
01544 #endif
01545 }
01546 
01547 
01548 /**dox***************************************************************/
01549 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
01550 
01551 /********************************************************************/
01552 /**
01553 Execute command in a separate process, close all open file descriptors
01554 invoke ss_exec() and ignore pid.
01555 \code
01556 { ...
01557   char cmd[256];
01558   sprintf(cmd,"%s %s %i %s/%s %1.3lf %d",lazy.commandAfter,
01559      lazy.backlabel, lazyst.nfiles, lazy.path, lazyst.backfile,
01560      lazyst.file_size/1024.0/1024.0, blockn);
01561   cm_msg(MINFO,"Lazy","Exec post file write script:%s",cmd);
01562   ss_system(cmd);
01563 }
01564 ...
01565 \encode
01566 @param command Command to execute.
01567 @return SS_SUCCESS or ss_exec() return code
01568 */
01569 INT ss_system(char *command)
01570 {
01571 #ifdef OS_UNIX
01572    INT childpid;
01573 
01574    return ss_exec(command, &childpid);
01575 
01576 #else
01577 
01578    system(command);
01579    return SS_SUCCESS;
01580 
01581 #endif
01582 }
01583 
01584 /**dox***************************************************************/
01585 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01586 
01587 /*------------------------------------------------------------------*/
01588 INT ss_exec(char *command, INT * pid)
01589 /********************************************************************\
01590 
01591   Routine: ss_exec
01592 
01593   Purpose: Execute command in a separate process, close all open
01594            file descriptors, return the pid of the child process.
01595 
01596   Input:
01597     char * command    Command to execute
01598     INT  * pid        Returned PID of the spawned process.
01599   Output:
01600     none
01601 
01602   Function value:
01603     SS_SUCCESS       Successful completion
01604     SS_ABORT         fork() was not successful, or other problem
01605 
01606 \********************************************************************/
01607 {
01608 #ifdef OS_UNIX
01609 
01610    /* only implemented for UNIX */
01611    int i, fd;
01612 
01613    if ((*pid = fork()) < 0)
01614       return SS_ABORT;
01615    else if (*pid != 0) {
01616       /* avoid <defunc> parent processes */
01617       signal(SIGCHLD, catch_sigchld);
01618       return SS_SUCCESS;        /* parent returns */
01619    }
01620 
01621    /* child continues here... */
01622 
01623    /* close all open file descriptors */
01624    for (i = 0; i < 256; i++)
01625       close(i);
01626 
01627    /* try and use up stdin, stdout and stderr, so other
01628       routines writing to stdout etc won't cause havoc */
01629    for (i = 0; i < 3; i++) {
01630       fd = open("/dev/null", O_RDWR, 0);
01631       if (fd < 0)
01632          fd = open("/dev/null", O_WRONLY, 0);
01633       if (fd < 0) {
01634          cm_msg(MERROR, "ss_exec", "Can't open /dev/null");
01635          return SS_ABORT;
01636       }
01637       if (fd != i) {
01638          cm_msg(MERROR, "ss_exec", "Did not get file descriptor");
01639          return SS_ABORT;
01640       }
01641    }
01642 
01643    setsid();                    /* become session leader */
01644    /* chdir("/"); *//* change working directory (not on NFS!) */
01645    umask(0);                    /* clear our file mode createion mask */
01646 
01647    /* execute command */
01648    execl("/bin/sh", "sh", "-c", command, NULL);
01649 
01650 #else
01651 
01652    system(command);
01653 
01654 #endif
01655 
01656    return SS_SUCCESS;
01657 }
01658 
01659 /**dox***************************************************************/
01660 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
01661 
01662 /********************************************************************/
01663 /**
01664 Creates and returns a new thread of execution. 
01665 
01666 Note the difference when calling from vxWorks versus Linux and Windows.
01667 The parameter pointer for a vxWorks call is a VX_TASK_SPAWN structure, whereas
01668 for Linux and Windows it is a void pointer.
01669 Early versions returned SS_SUCCESS or SS_NO_THREAD instead of thread ID.
01670 
01671 Example for VxWorks
01672 \code
01673 ...
01674 VX_TASK_SPAWN tsWatch = {"Watchdog", 100, 0, 2000,  (int) pDevice, 0, 0, 0, 0, 0, 0, 0, 0 ,0};
01675 midas_thread_t thread_id = ss_thread_create((void *) taskWatch, &tsWatch);
01676 if (thread_id == 0) {
01677   printf("cannot spawn taskWatch\n");
01678 }
01679 ...
01680 \endcode
01681 Example for Linux
01682 \code
01683 ...
01684 midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
01685 if (thread_id == 0) {
01686   printf("cannot spawn taskWatch\n");
01687 }
01688 ...
01689 \endcode
01690 @param (*thread_func) Thread function to create.  
01691 @param param a pointer to a VX_TASK_SPAWN structure for vxWorks and a void pointer
01692                 for Unix and Windows
01693 @return the new thread id or zero on error
01694 */
01695 midas_thread_t ss_thread_create(INT(*thread_func) (void *), void *param)
01696 {
01697 #if defined(OS_WINNT)
01698 
01699    HANDLE status;
01700    DWORD thread_id;
01701 
01702    if (thread_func == NULL) {
01703       return 0;
01704    }
01705 
01706    status = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) thread_func,
01707                          (LPVOID) param, 0, &thread_id);
01708 
01709    return status == NULL ?  0 : (midas_thread_t)thread_id;
01710 
01711 #elif defined(OS_MSDOS)
01712 
01713    return 0;
01714 
01715 #elif defined(OS_VMS)
01716 
01717    return 0;
01718 
01719 #elif defined(OS_VXWORKS)
01720 
01721 /* taskSpawn which could be considered as a thread under VxWorks
01722    requires several argument beside the thread args
01723    taskSpawn (taskname, priority, option, stacksize, entry_point
01724               , arg1, arg2, ... , arg9, arg10)
01725    all the arg will have to be retrieved from the param list.
01726    through a structure to be simpler  */
01727 
01728    INT status;
01729    VX_TASK_SPAWN *ts;
01730 
01731    ts = (VX_TASK_SPAWN *) param;
01732    status =
01733        taskSpawn(ts->name, ts->priority, ts->options, ts->stackSize,
01734                  (FUNCPTR) thread_func, ts->arg1, ts->arg2, ts->arg3,
01735                  ts->arg4, ts->arg5, ts->arg6, ts->arg7, ts->arg8, ts->arg9, ts->arg10);
01736 
01737    return status == ERROR ? 0 : status;
01738 
01739 #elif defined(OS_UNIX)
01740 
01741    INT status;
01742    pthread_t thread_id;
01743 
01744    status = pthread_create(&thread_id, NULL, (void *) thread_func, param);
01745 
01746    return status != 0 ? 0 : thread_id;
01747 
01748 #endif
01749 }
01750 
01751 /********************************************************************/
01752 /** 
01753 Destroys the thread identified by the passed thread id. 
01754 The thread id is returned by ss_thread_create() on creation.
01755 
01756 \code
01757 ...
01758 midas_thread_t thread_id = ss_thread_create((void *) taskWatch, pDevice);
01759 if (thread_id == 0) {
01760   printf("cannot spawn taskWatch\n");
01761 }
01762 ...
01763 ss_thread_kill(thread_id);
01764 ...
01765 \endcode
01766 @param thread_id the thread id of the thread to be killed.
01767 @return SS_SUCCESS if no error, else SS_NO_THREAD
01768 */
01769 INT ss_thread_kill(midas_thread_t thread_id)
01770 {
01771 #if defined(OS_WINNT)
01772 
01773    DWORD status;
01774 
01775    status = TerminateThread(thread_id, 0);
01776 
01777    return status != 0 ? SS_SUCCESS : SS_NO_THREAD;
01778 
01779 #elif defined(OS_MSDOS)
01780 
01781    return 0;
01782 
01783 #elif defined(OS_VMS)
01784 
01785    return 0;
01786 
01787 #elif defined(OS_VXWORKS)
01788 
01789    INT status;
01790    status = taskDelete(thread_id);
01791    return status == OK ? 0 : ERROR;
01792 
01793 #elif defined(OS_UNIX)
01794 
01795    INT status;
01796    status = pthread_kill(thread_id, SIGKILL);
01797    return status == 0 ? SS_SUCCESS : SS_NO_THREAD;
01798 
01799 #endif
01800 }
01801 
01802 /**dox***************************************************************/
01803 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01804 
01805 /*------------------------------------------------------------------*/
01806 static INT skip_mutex_handle = -1;
01807 
01808 INT ss_mutex_create(char *name, HNDLE * mutex_handle)
01809 /********************************************************************\
01810 
01811   Routine: ss_mutex_create
01812 
01813   Purpose: Create a mutex with a specific name
01814 
01815     Remark: Under VxWorks the specific semaphore handling is
01816             different than other OS. But VxWorks provides
01817             the POSIX-compatible semaphore interface.
01818             Under POSIX, no timeout is supported.
01819             So for the time being, we keep the pure VxWorks
01820             The semaphore type is a Binary instead of mutex
01821             as the binary is an optimized mutex.
01822 
01823   Input:
01824     char   *name            Name of the mutex to create
01825 
01826   Output:
01827     HNDLE  *mutex_handle    Handle of the created mutex
01828 
01829   Function value:
01830     SS_CREATED              Mutex was created
01831     SS_SUCCESS              Mutex existed already and was attached
01832     SS_NO_MUTEX             Cannot create mutex
01833 
01834 \********************************************************************/
01835 {
01836    char mutex_name[256], path[256], file_name[256];
01837 
01838    /* Add a leading SM_ to the mutex name */
01839    sprintf(mutex_name, "MX_%s", name);
01840 
01841 #ifdef OS_VXWORKS
01842 
01843    /* semBCreate is a Binary semaphore which is under VxWorks a optimized mutex
01844       refering to the programmer's Guide 5.3.1 */
01845    if ((*((SEM_ID *) mutex_handle) = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == NULL)
01846       return SS_NO_MUTEX;
01847    return SS_CREATED;
01848 
01849 #endif                          /* OS_VXWORKS */
01850 
01851    /* Build the filename out of the path and the name of the mutex */
01852    cm_get_path(path);
01853    if (path[0] == 0) {
01854       getcwd(path, 256);
01855 #if defined(OS_VMS)
01856 #elif defined(OS_UNIX)
01857       strcat(path, "/");
01858 #elif defined(OS_WINNT)
01859       strcat(path, "\\");
01860 #endif
01861    }
01862 
01863    strcpy(file_name, path);
01864 #if defined (OS_UNIX)
01865    strcat(file_name, ".");      /* dot file under UNIX */
01866 #endif
01867    strcat(file_name, name);
01868    strcat(file_name, ".SHM");
01869 
01870 #ifdef OS_WINNT
01871 
01872    *mutex_handle = (HNDLE) CreateMutex(NULL, FALSE, mutex_name);
01873 
01874    if (*mutex_handle == 0)
01875       return SS_NO_MUTEX;
01876 
01877    return SS_CREATED;
01878 
01879 #endif                          /* OS_WINNT */
01880 #ifdef OS_VMS
01881 
01882    /* VMS has to use lock manager... */
01883 
01884    {
01885       INT status;
01886       $DESCRIPTOR(mutexname_dsc, "dummy");
01887       mutexname_dsc.dsc$w_length = strlen(mutex_name);
01888       mutexname_dsc.dsc$a_pointer = mutex_name;
01889 
01890       *mutex_handle = (HNDLE) malloc(8);
01891 
01892       status = sys$enqw(0, LCK$K_NLMODE, *mutex_handle, 0, &mutexname_dsc,
01893                         0, 0, 0, 0, 0, 0);
01894 
01895       if (status != SS$_NORMAL) {
01896          free((void *) *mutex_handle);
01897          *mutex_handle = 0;
01898       }
01899 
01900       if (*mutex_handle == 0)
01901          return SS_NO_MUTEX;
01902 
01903       return SS_CREATED;
01904    }
01905 
01906 #endif                          /* OS_VMS */
01907 #ifdef OS_UNIX
01908 
01909    {
01910       INT key, status, fh;
01911       struct semid_ds buf;
01912 
01913 #if (defined(OS_LINUX) && !defined(_SEM_SEMUN_UNDEFINED)) || defined(OS_FREEBSD)
01914       union semun arg;
01915 #else
01916       union semun {
01917          INT val;
01918          struct semid_ds *buf;
01919          ushort *array;
01920       } arg;
01921 #endif
01922 
01923       status = SS_SUCCESS;
01924 
01925       /* create a unique key from the file name */
01926       key = ftok(file_name, 'M');
01927       if (key < 0) {
01928          fh = open(file_name, O_CREAT, 0644);
01929          close(fh);
01930          key = ftok(file_name, 'M');
01931          status = SS_CREATED;
01932       }
01933 
01934       /* create or get semaphore */
01935       *mutex_handle = (HNDLE) semget(key, 1, 0);
01936       if (*mutex_handle < 0) {
01937          *mutex_handle = (HNDLE) semget(key, 1, IPC_CREAT);
01938          status = SS_CREATED;
01939       }
01940 
01941       if (*mutex_handle < 0) {
01942          cm_msg(MERROR, "ss_mutex_mutex", "semget() failed, errno = %d", errno);
01943          return SS_NO_MUTEX;
01944       }
01945 
01946       buf.sem_perm.uid = getuid();
01947       buf.sem_perm.gid = getgid();
01948       buf.sem_perm.mode = 0666;
01949       arg.buf = &buf;
01950 
01951       semctl(*mutex_handle, 0, IPC_SET, arg);
01952 
01953       /* if semaphore was created, set value to one */
01954       if (status == SS_CREATED) {
01955          arg.val = 1;
01956          if (semctl(*mutex_handle, 0, SETVAL, arg) < 0)
01957             return SS_NO_MUTEX;
01958       }
01959 
01960       return SS_SUCCESS;
01961    }
01962 #endif                          /* OS_UNIX */
01963 
01964 #ifdef OS_MSDOS
01965    return SS_NO_MUTEX;
01966 #endif
01967 }
01968 
01969 /*------------------------------------------------------------------*/
01970 INT ss_mutex_wait_for(HNDLE mutex_handle, INT timeout)
01971 /********************************************************************\
01972 
01973   Routine: ss_mutex_wait_for
01974 
01975   Purpose: Wait for a mutex to get owned
01976 
01977   Input:
01978     HNDLE  *mutex_handle    Handle of the created mutex
01979     INT    timeout          Timeout in ms, zero for no timeout
01980 
01981   Output:
01982     none
01983 
01984   Function value:
01985     SS_SUCCESS              Successful completion
01986     SS_NO_MUTEX             Invalid mutex handle
01987     SS_TIMEOUT              Timeout
01988 
01989 \********************************************************************/
01990 {
01991    INT status;
01992 
01993 #ifdef OS_WINNT
01994 
01995    status = WaitForSingleObject((HANDLE) mutex_handle, timeout == 0 ? INFINITE : timeout);
01996    if (status == WAIT_FAILED)
01997       return SS_NO_MUTEX;
01998    if (status == WAIT_TIMEOUT)
01999       return SS_TIMEOUT;
02000 
02001    return SS_SUCCESS;
02002 #endif                          /* OS_WINNT */
02003 #ifdef OS_VMS
02004    status = sys$enqw(0, LCK$K_EXMODE, mutex_handle, LCK$M_CONVERT, 0, 0, 0, 0, 0, 0, 0);
02005    if (status != SS$_NORMAL)
02006       return SS_NO_MUTEX;
02007    return SS_SUCCESS;
02008 
02009 #endif                          /* OS_VMS */
02010 #ifdef OS_VXWORKS
02011    /* convert timeout in ticks (1/60) = 1000/60 ~ 1/16 = >>4 */
02012    status = semTake((SEM_ID) mutex_handle, timeout == 0 ? WAIT_FOREVER : timeout >> 4);
02013    if (status == ERROR)
02014       return SS_NO_MUTEX;
02015    return SS_SUCCESS;
02016 
02017 #endif                          /* OS_VXWORKS */
02018 #ifdef OS_UNIX
02019    {
02020       DWORD start_time;
02021       struct sembuf sb;
02022 
02023 #if (defined(OS_LINUX) && !defined(_SEM_SEMUN_UNDEFINED)) || defined(OS_FREEBSD)
02024       union semun arg;
02025 #else
02026       union semun {
02027          INT val;
02028          struct semid_ds *buf;
02029          ushort *array;
02030       } arg;
02031 #endif
02032 
02033       sb.sem_num = 0;
02034       sb.sem_op = -1;           /* decrement semaphore */
02035       sb.sem_flg = SEM_UNDO;
02036 
02037       memset(&arg, 0, sizeof(arg));
02038 
02039       /* don't request the mutex when in asynchronous state
02040          and mutex was locked already by foreground process */
02041       if (ss_in_async_routine_flag)
02042          if (semctl(mutex_handle, 0, GETPID, arg) == getpid())
02043             if (semctl(mutex_handle, 0, GETVAL, arg) == 0) {
02044                skip_mutex_handle = mutex_handle;
02045                return SS_SUCCESS;
02046             }
02047 
02048       skip_mutex_handle = -1;
02049 
02050       start_time = ss_millitime();
02051 
02052       do {
02053          status = semop(mutex_handle, &sb, 1);
02054 
02055          /* return on success */
02056          if (status == 0)
02057             break;
02058 
02059          /* retry if interrupted by a ss_wake signal */
02060          if (errno == EINTR) {
02061             /* return if timeout expired */
02062             if (timeout > 0 && ss_millitime() - start_time > timeout)
02063                return SS_TIMEOUT;
02064 
02065             continue;
02066          }
02067 
02068          return SS_NO_MUTEX;
02069       } while (1);
02070 
02071       return SS_SUCCESS;
02072    }
02073 #endif                          /* OS_UNIX */
02074 
02075 #ifdef OS_MSDOS
02076    return SS_NO_MUTEX;
02077 #endif
02078 }
02079 
02080 /*------------------------------------------------------------------*/
02081 INT ss_mutex_release(HNDLE mutex_handle)
02082 /********************************************************************\
02083 
02084   Routine: ss_release_mutex
02085 
02086   Purpose: Release ownership of a mutex
02087 
02088   Input:
02089     HNDLE  *mutex_handle    Handle of the created mutex
02090 
02091   Output:
02092     none
02093 
02094   Function value:
02095     SS_SUCCESS              Successful completion
02096     SS_NO_MUTEX             Invalid mutex handle
02097 
02098 \********************************************************************/
02099 {
02100    INT status;
02101 
02102 #ifdef OS_WINNT
02103 
02104    status = ReleaseMutex((HANDLE) mutex_handle);
02105 
02106    if (status == FALSE)
02107       return SS_NO_MUTEX;
02108 
02109    return SS_SUCCESS;
02110 
02111 #endif                          /* OS_WINNT */
02112 #ifdef OS_VMS
02113 
02114    status = sys$enqw(0, LCK$K_NLMODE, mutex_handle, LCK$M_CONVERT, 0, 0, 0, 0, 0, 0, 0);
02115 
02116    if (status != SS$_NORMAL)
02117       return SS_NO_MUTEX;
02118 
02119    return SS_SUCCESS;
02120 
02121 #endif                          /* OS_VMS */
02122 
02123 #ifdef OS_VXWORKS
02124 
02125    if (semGive((SEM_ID) mutex_handle) == ERROR)
02126       return SS_NO_MUTEX;
02127    return SS_SUCCESS;
02128 #endif                          /* OS_VXWORKS */
02129 
02130 #ifdef OS_UNIX
02131    {
02132       struct sembuf sb;
02133 
02134       sb.sem_num = 0;
02135       sb.sem_op = 1;            /* increment semaphore */
02136       sb.sem_flg = SEM_UNDO;
02137 
02138       if (mutex_handle == skip_mutex_handle) {
02139          skip_mutex_handle = -1;
02140          return SS_SUCCESS;
02141       }
02142 
02143       do {
02144          status = semop(mutex_handle, &sb, 1);
02145 
02146          /* return on success */
02147          if (status == 0)
02148             break;
02149 
02150          /* retry if interrupted by a ss_wake signal */
02151          if (errno == EINTR)
02152             continue;
02153 
02154          return SS_NO_MUTEX;
02155       } while (1);
02156 
02157       return SS_SUCCESS;
02158    }
02159 #endif                          /* OS_UNIX */
02160 
02161 #ifdef OS_MSDOS
02162    return SS_NO_MUTEX;
02163 #endif
02164 }
02165 
02166 /*------------------------------------------------------------------*/
02167 INT ss_mutex_delete(HNDLE mutex_handle, INT destroy_flag)
02168 /********************************************************************\
02169 
02170   Routine: ss_mutex_delete
02171 
02172   Purpose: Delete a mutex
02173 
02174   Input:
02175     HNDLE  *mutex_handle    Handle of the created mutex
02176 
02177   Output:
02178     none
02179 
02180   Function value:
02181     SS_SUCCESS              Successful completion
02182     SS_NO_MUTEX             Invalid mutex handle
02183 
02184 \********************************************************************/
02185 {
02186 #ifdef OS_WINNT
02187 
02188    if (CloseHandle((HANDLE) mutex_handle) == FALSE)
02189       return SS_NO_MUTEX;
02190 
02191    return SS_SUCCESS;
02192 
02193 #endif                          /* OS_WINNT */
02194 #ifdef OS_VMS
02195 
02196    free((void *) mutex_handle);
02197    return SS_SUCCESS;
02198 
02199 #endif                          /* OS_VMS */
02200 
02201 #ifdef OS_VXWORKS
02202    /* no code for VxWorks destroy yet */
02203    if (semDelete((SEM_ID) mutex_handle) == ERROR)
02204       return SS_NO_MUTEX;
02205    return SS_SUCCESS;
02206 #endif                          /* OS_VXWORKS */
02207 
02208 #ifdef OS_UNIX
02209 #if (defined(OS_LINUX) && !defined(_SEM_SEMUN_UNDEFINED)) || defined(OS_FREEBSD)
02210    union semun arg;
02211 #else
02212    union semun {
02213       INT val;
02214       struct semid_ds *buf;
02215       ushort *array;
02216    } arg;
02217 #endif
02218 
02219    memset(&arg, 0, sizeof(arg));
02220 
02221    if (destroy_flag)
02222       if (semctl(mutex_handle, 0, IPC_RMID, arg) < 0)
02223          return SS_NO_MUTEX;
02224 
02225    return SS_SUCCESS;
02226 
02227 #endif                          /* OS_UNIX */
02228 
02229 #ifdef OS_MSDOS
02230    return SS_NO_MUTEX;
02231 #endif
02232 }
02233 
02234 /**dox***************************************************************/
02235 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
02236 
02237 /********************************************************************/
02238 /**
02239 Returns the actual time in milliseconds with an arbitrary
02240 origin. This time may only be used to calculate relative times.
02241 
02242 Overruns in the 32 bit value don't hurt since in a subtraction calculated
02243 with 32 bit accuracy this overrun cancels (you may think about!)..
02244 \code
02245 ...
02246 DWORD start, stop:
02247 start = ss_millitime();
02248   < do operations >
02249 stop = ss_millitime();
02250 printf("Operation took %1.3lf seconds\n",(stop-start)/1000.0);
02251 ...
02252 \endcode
02253 @return millisecond time stamp.
02254 */
02255 DWORD ss_millitime()
02256 {
02257 #ifdef OS_WINNT
02258 
02259    return (int) GetTickCount();
02260 
02261 #endif                          /* OS_WINNT */
02262 #ifdef OS_MSDOS
02263 
02264    return clock() * 55;
02265 
02266 #endif                          /* OS_MSDOS */
02267 #ifdef OS_VMS
02268 
02269    {
02270       char time[8];
02271       DWORD lo, hi;
02272 
02273       sys$gettim(time);
02274 
02275       lo = *((DWORD *) time);
02276       hi = *((DWORD *) (time + 4));
02277 
02278 /*  return *lo / 10000; */
02279 
02280       return lo / 10000 + hi * 429496.7296;
02281 
02282    }
02283 
02284 #endif                          /* OS_VMS */
02285 #ifdef OS_UNIX
02286    {
02287       struct timeval tv;
02288 
02289       gettimeofday(&tv, NULL);
02290 
02291       return tv.tv_sec * 1000 + tv.tv_usec / 1000;
02292    }
02293 
02294 #endif                          /* OS_UNIX */
02295 #ifdef OS_VXWORKS
02296    {
02297       int count;
02298       static int ticks_per_msec = 0;
02299 
02300       if (ticks_per_msec == 0)
02301          ticks_per_msec = 1000 / sysClkRateGet();
02302 
02303       return tickGet() * ticks_per_msec;
02304    }
02305 #endif                          /* OS_VXWORKS */
02306 }
02307 
02308 /********************************************************************/
02309 /**
02310 Returns the actual time in seconds since 1.1.1970 UTC.
02311 \code
02312 ...
02313 DWORD start, stop:
02314 start = ss_time();
02315   ss_sleep(12000);
02316 stop = ss_time();
02317 printf("Operation took %1.3lf seconds\n",stop-start);
02318 ...
02319 \endcode
02320 @return Time in seconds
02321 */
02322 DWORD ss_time()
02323 {
02324 #if !defined(OS_VXWORKS)
02325 #if !defined(OS_VMS)
02326    tzset();
02327 #endif
02328 #endif
02329    return (DWORD) time(NULL);
02330 }
02331 
02332 /**dox***************************************************************/
02333 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02334 
02335 /*------------------------------------------------------------------*/
02336 DWORD ss_settime(DWORD seconds)
02337 /********************************************************************\
02338 
02339   Routine: ss_settime
02340 
02341   Purpose: Set local time. Used to synchronize different computers
02342 
02343    Input:
02344     INT    Time in seconds since 1.1.1970 UTC.
02345 
02346   Output:
02347     none
02348 
02349   Function value:
02350 
02351 \********************************************************************/
02352 {
02353 #if defined(OS_WINNT)
02354    SYSTEMTIME st;
02355    struct tm *ltm;
02356 
02357    tzset();
02358    ltm = localtime((time_t *) & seconds);
02359 
02360    st.wYear = ltm->tm_year + 1900;
02361    st.wMonth = ltm->tm_mon + 1;
02362    st.wDay = ltm->tm_mday;
02363    st.wHour = ltm->tm_hour;
02364    st.wMinute = ltm->tm_min;
02365    st.wSecond = ltm->tm_sec;
02366    st.wMilliseconds = 0;
02367 
02368    SetLocalTime(&st);
02369 
02370 #elif defined(OS_DARWIN)
02371 
02372    assert(!"ss_settime() is not supported");
02373    /* not reached */
02374    return SS_NO_DRIVER;
02375 
02376 #elif defined(OS_UNIX)
02377 
02378    stime((time_t *) & seconds);
02379 
02380 #elif defined(OS_VXWORKS)
02381 
02382    struct timespec ltm;
02383 
02384    ltm.tv_sec = seconds;
02385    ltm.tv_nsec = 0;
02386    clock_settime(CLOCK_REALTIME, &ltm);
02387 
02388 #endif
02389    return SS_SUCCESS;
02390 }
02391 
02392 /*------------------------------------------------------------------*/
02393 char *ss_asctime()
02394 /********************************************************************\
02395 
02396   Routine: ss_asctime
02397 
02398   Purpose: Returns the local actual time as a string
02399 
02400   Input:
02401     none
02402 
02403   Output:
02404     none
02405 
02406   Function value:
02407     char   *     Time string
02408 
02409 \********************************************************************/
02410 {
02411    static char str[32];
02412    time_t seconds;
02413 
02414    seconds = (time_t) ss_time();
02415 
02416 #if !defined(OS_VXWORKS)
02417 #if !defined(OS_VMS)
02418    tzset();
02419 #endif
02420 #endif
02421    strcpy(str, asctime(localtime(&seconds)));
02422 
02423    /* strip new line */
02424    str[24] = 0;
02425 
02426    return str;
02427 }
02428 
02429 /*------------------------------------------------------------------*/
02430 INT ss_timezone()
02431 /********************************************************************\
02432 
02433   Routine: ss_timezone
02434 
02435   Purpose: Returns difference in seconds between coordinated universal
02436            time and local time.
02437 
02438   Input:
02439     none
02440 
02441   Output:
02442     none
02443 
02444   Function value:
02445     INT    Time difference in seconds
02446 
02447 \********************************************************************/
02448 {
02449 #if defined(OS_DARWIN) || defined(OS_VXWORKS)
02450   return 0;
02451 #else
02452   return timezone; /* on Linux, comes from "#include <time.h>". */
02453 #endif
02454 }
02455 
02456 
02457 /*------------------------------------------------------------------*/
02458 
02459 #ifdef OS_UNIX
02460 /* dummy function for signal() call */
02461 void ss_cont()
02462 {
02463 }
02464 #endif
02465 
02466 /**dox***************************************************************/
02467 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
02468 
02469 /********************************************************************/
02470 /**
02471 Suspend the calling process for a certain time.
02472 
02473 The function is similar to the sleep() function,
02474 but has a resolution of one milliseconds. Under VxWorks the resolution
02475 is 1/60 of a second. It uses the socket select() function with a time-out.
02476 See examples in ss_time()
02477 @param millisec Time in milliseconds to sleep. Zero means
02478                 infinite (until another process calls ss_wake)
02479 @return SS_SUCCESS
02480 */
02481 INT ss_sleep(INT millisec)
02482 {
02483    fd_set readfds;
02484    struct timeval timeout;
02485    int status;
02486    static int sock = 0;
02487 
02488    if (millisec == 0) {
02489 #ifdef OS_WINNT
02490       SuspendThread(GetCurrentThread());
02491 #endif
02492 #ifdef OS_VMS
02493       sys$hiber();
02494 #endif
02495 #ifdef OS_UNIX
02496       signal(SIGCONT, ss_cont);
02497       pause();
02498 #endif
02499       return SS_SUCCESS;
02500    }
02501 #ifdef OS_WINNT
02502    {
02503       WSADATA WSAData;
02504 
02505       /* Start windows sockets */
02506       if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
02507          return SS_SOCKET_ERROR;
02508    }
02509 #endif
02510 
02511    timeout.tv_sec = millisec / 1000;
02512    timeout.tv_usec = (millisec % 1000) * 1000;
02513 
02514    if (!sock)
02515       sock = socket(AF_INET, SOCK_DGRAM, 0);
02516 
02517    FD_ZERO(&readfds);
02518    FD_SET(sock, &readfds);
02519    do {
02520       status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
02521 
02522       /* if an alarm signal was cought, restart select with reduced timeout */
02523       if (status == -1 && timeout.tv_sec >= WATCHDOG_INTERVAL / 1000)
02524          timeout.tv_sec -= WATCHDOG_INTERVAL / 1000;
02525 
02526    } while (status == -1);      /* dont return if an alarm signal was cought */
02527 
02528    return SS_SUCCESS;
02529 }
02530 
02531 /**dox***************************************************************/
02532 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02533 
02534 /*------------------------------------------------------------------*/
02535 BOOL ss_kbhit()
02536 /********************************************************************\
02537 
02538   Routine: ss_kbhit
02539 
02540   Purpose: Returns TRUE if a key is pressed
02541 
02542   Input:
02543     none
02544 
02545   Output:
02546     none
02547 
02548   Function value:
02549     FALSE                 No key has been pressed
02550     TRUE                  Key has been pressed
02551 
02552 \********************************************************************/
02553 {
02554 #ifdef OS_MSDOS
02555 
02556    return kbhit();
02557 
02558 #endif                          /* OS_MSDOS */
02559 #ifdef OS_WINNT
02560 
02561    return kbhit();
02562 
02563 #endif                          /* OS_WINNT */
02564 #ifdef OS_VMS
02565 
02566    return FALSE;
02567 
02568 #endif                          /* OS_VMS */
02569 #ifdef OS_UNIX
02570 
02571    int n;
02572 
02573    if (_daemon_flag)
02574       return 0;
02575 
02576    ioctl(0, FIONREAD, &n);
02577    return (n > 0);
02578 
02579 #endif                          /* OS_UNIX */
02580 #ifdef OS_VXWORKS
02581 
02582    int n;
02583    ioctl(0, FIONREAD, (long) &n);
02584    return (n > 0);
02585 
02586 #endif                          /* OS_UNIX */
02587 }
02588 
02589 
02590 /*------------------------------------------------------------------*/
02591 #ifdef LOCAL_ROUTINES
02592 
02593 INT ss_wake(INT pid, INT tid, INT thandle)
02594 /********************************************************************\
02595 
02596   Routine: ss_wake
02597 
02598   Purpose: Wake a process with a specific ID and optional with a
02599      specific thread ID (on OS with support threads).
02600 
02601   Input:
02602     INT    pid              Process ID
02603     INT    tid              Thread ID
02604     INT    thandle          Thread handle (used under Windows NT)
02605 
02606 
02607   Output:
02608     none
02609 
02610   Function value:
02611     SS_SUCCESS              Successful completion
02612     SS_NO_PROCESS           Nonexisting process
02613 
02614 \********************************************************************/
02615 {
02616 #ifdef OS_WINNT
02617    HANDLE process_handle;
02618    HANDLE dup_thread_handle;
02619 
02620    /*
02621       Under Windows NT, it's a little bit tricky to get a thread handle
02622       which can be passed to other processes. First the calling process
02623       has to duplicate the GetCurrentThread() handle, then the process
02624       which gets this handle also has to use DuplicateHandle with the
02625       target process as its own. Then this duplicated handle can be used
02626       to the SupendThread() and ResumeThread() functions.
02627     */
02628 
02629    process_handle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
02630 
02631    if (process_handle == 0)
02632       return SS_NO_PROCESS;
02633 
02634    DuplicateHandle(process_handle, (HANDLE) thandle, GetCurrentProcess(),
02635                    &dup_thread_handle, THREAD_ALL_ACCESS, TRUE, 0);
02636 
02637    /* close handles not to waste resources */
02638    CloseHandle(process_handle);
02639 
02640    if (dup_thread_handle == 0)
02641       return SS_NO_PROCESS;
02642 
02643    ResumeThread(dup_thread_handle);
02644 
02645    /* close handles not to waste resources */
02646    CloseHandle(dup_thread_handle);
02647 
02648    return SS_SUCCESS;
02649 
02650 #endif                          /* OS_WINNT */
02651 #ifdef OS_VMS
02652 
02653    if (sys$wake(&pid, 0) == SS$_NONEXPR)
02654       return SS_NO_PROCESS;
02655 
02656    return SS_SUCCESS;
02657 
02658 #endif                          /* OS_VMS */
02659 #ifdef OS_UNIX
02660 
02661    if (kill(pid, SIGCONT) < 0)
02662       return SS_NO_PROCESS;
02663 
02664    return SS_SUCCESS;
02665 
02666    /*
02667       Bryan: kill has to get the target process out of pause(). Some
02668       UNIX documentation say that pause() terminates by receiving any
02669       signal which would be ok because the buffer manager is designed
02670       in a way where an additional wake doesn't hurt. If this is not
02671       true, one has to setup a signal(SIGCONT, dummy) in the ss_sleep
02672       routine or so. Please check this.
02673     */
02674 #endif                          /* OS_UNIX */
02675 }
02676 
02677 /*------------------------------------------------------------------*/
02678 #ifdef OS_WINNT
02679 
02680 static void (*UserCallback) (int);
02681 static UINT _timer_id = 0;
02682 
02683 VOID CALLBACK _timeCallback(UINT idEvent, UINT uReserved, DWORD dwUser,
02684                             DWORD dwReserved1, DWORD dwReserved2)
02685 {
02686    _timer_id = 0;
02687    if (UserCallback != NULL)
02688       UserCallback(0);
02689 }
02690 
02691 #endif                          /* OS_WINNT */
02692 
02693 INT ss_alarm(INT millitime, void (*func) (int))
02694 /********************************************************************\
02695 
02696   Routine: ss_alarm
02697 
02698   Purpose: Schedules an alarm. Call function referenced by *func
02699      after the specified seconds.
02700 
02701   Input:
02702     INT    millitime        Time in milliseconds
02703     void   (*func)()        Function to be called after the spe-
02704           cified time.
02705 
02706   Output:
02707     none
02708 
02709   Function value:
02710     SS_SUCCESS              Successful completion
02711 
02712 \********************************************************************/
02713 {
02714 #ifdef OS_WINNT
02715 
02716    UserCallback = func;
02717    if (millitime > 0)
02718       _timer_id =
02719           timeSetEvent(millitime, 100, (LPTIMECALLBACK) _timeCallback, 0, TIME_ONESHOT);
02720    else {
02721       if (_timer_id)
02722          timeKillEvent(_timer_id);
02723       _timer_id = 0;
02724    }
02725 
02726    return SS_SUCCESS;
02727 
02728 #endif                          /* OS_WINNT */
02729 #ifdef OS_VMS
02730 
02731    signal(SIGALRM, func);
02732    alarm(millitime / 1000);
02733    return SS_SUCCESS;
02734 
02735 #endif                          /* OS_VMS */
02736 #ifdef OS_UNIX
02737 
02738    signal(SIGALRM, func);
02739    alarm(millitime / 1000);
02740    return SS_SUCCESS;
02741 
02742 #endif                          /* OS_UNIX */
02743 }
02744 
02745 /*------------------------------------------------------------------*/
02746 void (*MidasExceptionHandler) ();
02747 
02748 #ifdef OS_WINNT
02749 
02750 LONG MidasExceptionFilter(LPEXCEPTION_POINTERS pexcep)
02751 {
02752    if (MidasExceptionHandler != NULL)
02753       MidasExceptionHandler();
02754 
02755    return EXCEPTION_CONTINUE_SEARCH;
02756 }
02757 
02758 INT MidasExceptionSignal(INT sig)
02759 {
02760    if (MidasExceptionHandler != NULL)
02761       MidasExceptionHandler();
02762 
02763    raise(sig);
02764 
02765    return 0;
02766 }
02767 
02768 /*
02769 INT _matherr(struct _exception *except)
02770 {
02771   if (MidasExceptionHandler != NULL)
02772     MidasExceptionHandler();
02773 
02774   return 0;
02775 }
02776 */
02777 
02778 #endif                          /* OS_WINNT */
02779 
02780 #ifdef OS_VMS
02781 
02782 INT MidasExceptionFilter(INT * sigargs, INT * mechargs)
02783 {
02784    if (MidasExceptionHandler != NULL)
02785       MidasExceptionHandler();
02786 
02787    return (SS$_RESIGNAL);
02788 }
02789 
02790 void MidasExceptionSignal(INT sig)
02791 {
02792    if (MidasExceptionHandler != NULL)
02793       MidasExceptionHandler();
02794 
02795    kill(getpid(), sig);
02796 }
02797 
02798 #endif                          /* OS_VMS */
02799 
02800 /*------------------------------------------------------------------*/
02801 INT ss_exception_handler(void (*func) ())
02802 /********************************************************************\
02803 
02804   Routine: ss_exception_handler
02805 
02806   Purpose: Establish new exception handler which is called before
02807      the program is aborted due to a Ctrl-Break or an access
02808      violation. This handler may clean up things which may
02809      otherwise left in an undefined state.
02810 
02811   Input:
02812     void  (*func)()     Address of handler function
02813   Output:
02814     none
02815 
02816   Function value:
02817     BM_SUCCESS          Successful completion
02818 
02819 \********************************************************************/
02820 {
02821 #ifdef OS_WINNT
02822 
02823    MidasExceptionHandler = func;
02824 /*  SetUnhandledExceptionFilter(
02825     (LPTOP_LEVEL_EXCEPTION_FILTER) MidasExceptionFilter);
02826 
02827   signal(SIGINT, MidasExceptionSignal);
02828   signal(SIGILL, MidasExceptionSignal);
02829   signal(SIGFPE, MidasExceptionSignal);
02830   signal(SIGSEGV, MidasExceptionSignal);
02831   signal(SIGTERM, MidasExceptionSignal);
02832   signal(SIGBREAK, MidasExceptionSignal);
02833   signal(SIGABRT, MidasExceptionSignal); */
02834 
02835 #endif                          /* OS_WINNT */
02836 #ifdef OS_VMS
02837 
02838    MidasExceptionHandler = func;
02839    lib$establish(MidasExceptionFilter);
02840 
02841    signal(SIGINT, MidasExceptionSignal);
02842    signal(SIGILL, MidasExceptionSignal);
02843    signal(SIGQUIT, MidasExceptionSignal);
02844    signal(SIGFPE, MidasExceptionSignal);
02845    signal(SIGSEGV, MidasExceptionSignal);
02846    signal(SIGTERM, MidasExceptionSignal);
02847 
02848 #endif                          /* OS_WINNT */
02849 
02850    return SS_SUCCESS;
02851 }
02852 
02853 #endif                          /* LOCAL_ROUTINES */
02854 
02855 /*------------------------------------------------------------------*/
02856 void *ss_ctrlc_handler(void (*func) (int))
02857 /********************************************************************\
02858 
02859   Routine: ss_ctrlc_handler
02860 
02861   Purpose: Establish new exception handler which is called before
02862      the program is aborted due to a Ctrl-Break. This handler may
02863      clean up things which may otherwise left in an undefined state.
02864 
02865   Input:
02866     void  (*func)(int)     Address of handler function, if NULL
02867                            install default handler
02868 
02869   Output:
02870     none
02871 
02872   Function value:
02873     same as signal()
02874 
02875 \********************************************************************/
02876 {
02877 #ifdef OS_WINNT
02878 
02879    if (func == NULL) {
02880       signal(SIGBREAK, SIG_DFL);
02881       return signal(SIGINT, SIG_DFL);
02882    } else {
02883       signal(SIGBREAK, func);
02884       return signal(SIGINT, func);
02885    }
02886    return NULL;
02887 
02888 #endif                          /* OS_WINNT */
02889 #ifdef OS_VMS
02890 
02891    return signal(SIGINT, func);
02892 
02893 #endif                          /* OS_WINNT */
02894 
02895 #ifdef OS_UNIX
02896 
02897    if (func == NULL) {
02898       signal(SIGTERM, SIG_DFL);
02899       return (void *) signal(SIGINT, SIG_DFL);
02900    } else {
02901       signal(SIGTERM, func);
02902       return (void *) signal(SIGINT, func);
02903    }
02904 
02905 #endif                          /* OS_UNIX */
02906 }
02907 
02908 /*------------------------------------------------------------------*/
02909 /********************************************************************\
02910 *                                                                    *
02911 *                  Suspend/resume functions                          *
02912 *                                                                    *
02913 \********************************************************************/
02914 
02915 /*------------------------------------------------------------------*/
02916 /* globals */
02917 
02918 /*
02919    The suspend structure is used in a multithread environment
02920    (multi thread server) where each thread may resume another thread.
02921    Since all threads share the same global memory, the ports and
02922    sockets for suspending and resuming must be stored in a array
02923    which keeps one entry for each thread.
02924 */
02925 
02926 typedef struct {
02927    BOOL in_use;
02928    INT thread_id;
02929    INT ipc_port;
02930    INT ipc_recv_socket;
02931    INT ipc_send_socket;
02932     INT(*ipc_dispatch) (char *, INT);
02933    INT listen_socket;
02934     INT(*listen_dispatch) (INT);
02935    RPC_SERVER_CONNECTION *server_connection;
02936     INT(*client_dispatch) (INT);
02937    RPC_SERVER_ACCEPTION *server_acception;
02938     INT(*server_dispatch) (INT, int, BOOL);
02939    struct sockaddr_in bind_addr;
02940 } SUSPEND_STRUCT;
02941 
02942 SUSPEND_STRUCT *_suspend_struct = NULL;
02943 INT _suspend_entries;
02944 
02945 /*------------------------------------------------------------------*/
02946 INT ss_suspend_init_ipc(INT index)
02947 /********************************************************************\
02948 
02949   Routine: ss_suspend_init_ipc
02950 
02951   Purpose: Create sockets used in the suspend/resume mechanism.
02952 
02953   Input:
02954     INT    index            Index to the _suspend_struct array for
02955           the calling thread.
02956   Output:
02957     <indirect>              Set entry in _suspend_struct
02958 
02959   Function value:
02960     SS_SUCCESS              Successful completion
02961     SS_SOCKET_ERROR         Error in socket routines
02962     SS_NO_MEMORY            Not enough memory
02963 
02964 \********************************************************************/
02965 {
02966    INT status, sock;
02967    int i;
02968    struct sockaddr_in bind_addr;
02969    char local_host_name[HOST_NAME_LENGTH];
02970    struct hostent *phe;
02971 
02972 #ifdef OS_WINNT
02973    {
02974       WSADATA WSAData;
02975 
02976       /* Start windows sockets */
02977       if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
02978          return SS_SOCKET_ERROR;
02979    }
02980 #endif
02981 
02982   /*--------------- create UDP receive socket -------------------*/
02983    sock = socket(AF_INET, SOCK_DGRAM, 0);
02984    if (sock == -1)
02985       return SS_SOCKET_ERROR;
02986 
02987    /* let OS choose port for socket */
02988    memset(&bind_addr, 0, sizeof(bind_addr));
02989    bind_addr.sin_family = AF_INET;
02990    bind_addr.sin_addr.s_addr = 0;
02991    bind_addr.sin_port = 0;
02992 
02993    gethostname(local_host_name, sizeof(local_host_name));
02994 
02995 #ifdef OS_VXWORKS
02996    {
02997       INT host_addr;
02998 
02999       host_addr = hostGetByName(local_host_name);
03000       memcpy((char *) &(bind_addr.sin_addr), &host_addr, 4);
03001    }
03002 #else
03003    phe = gethostbyname(local_host_name);
03004    if (phe == NULL) {
03005       cm_msg(MERROR, "ss_suspend_init_ipc", "cannot get host name");
03006       return SS_SOCKET_ERROR;
03007    }
03008    memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
03009 #endif
03010 
03011    status = bind(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
03012    if (status < 0)
03013       return SS_SOCKET_ERROR;
03014 
03015    /* find out which port OS has chosen */
03016    i = sizeof(bind_addr);
03017    getsockname(sock, (struct sockaddr *) &bind_addr, (int *) &i);
03018 
03019    _suspend_struct[index].ipc_recv_socket = sock;
03020    _suspend_struct[index].ipc_port = ntohs(bind_addr.sin_port);
03021 
03022   /*--------------- create UDP send socket ----------------------*/
03023    sock = socket(AF_INET, SOCK_DGRAM, 0);
03024 
03025    if (sock == -1)
03026       return SS_SOCKET_ERROR;
03027 
03028    /* fill out bind struct pointing to local host */
03029    memset(&bind_addr, 0, sizeof(bind_addr));
03030    bind_addr.sin_family = AF_INET;
03031    bind_addr.sin_addr.s_addr = 0;
03032 
03033 #ifdef OS_VXWORKS
03034    {
03035       INT host_addr;
03036 
03037       host_addr = hostGetByName(local_host_name);
03038       memcpy((char *) &(bind_addr.sin_addr), &host_addr, 4);
03039    }
03040 #else
03041    memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
03042 #endif
03043 
03044    memcpy(&_suspend_struct[index].bind_addr, &bind_addr, sizeof(bind_addr));
03045    _suspend_struct[index].ipc_send_socket = sock;
03046 
03047    return SS_SUCCESS;
03048 }
03049 
03050 /*------------------------------------------------------------------*/
03051 INT ss_suspend_get_index(INT * pindex)
03052 /********************************************************************\
03053 
03054   Routine: ss_suspend_init
03055 
03056   Purpose: Return the index for the suspend structure for this
03057      thread.
03058 
03059   Input:
03060     none
03061 
03062   Output:
03063     INT    *pindex          Index to the _suspend_struct array for
03064           the calling thread.
03065 
03066   Function value:
03067     SS_SUCCESS              Successful completion
03068     SS_NO_MEMORY            Not enough memory
03069 
03070 \********************************************************************/
03071 {
03072    INT index;
03073 
03074    if (_suspend_struct == NULL) {
03075       /* create a new entry for this thread */
03076       _suspend_struct = (SUSPEND_STRUCT *) malloc(sizeof(SUSPEND_STRUCT));
03077       memset(_suspend_struct, 0, sizeof(SUSPEND_STRUCT));
03078       if (_suspend_struct == NULL)
03079          return SS_NO_MEMORY;
03080 
03081       _suspend_entries = 1;
03082       *pindex = 0;
03083       _suspend_struct[0].thread_id = ss_gettid();
03084       _suspend_struct[0].in_use = TRUE;
03085    } else {
03086       /* check for an existing entry for this thread */
03087       for (index = 0; index < _suspend_entries; index++)
03088          if (_suspend_struct[index].thread_id == ss_gettid()) {
03089             if (pindex != NULL)
03090                *pindex = index;
03091 
03092             return SS_SUCCESS;
03093          }
03094 
03095       /* check for a deleted entry */
03096       for (index = 0; index < _suspend_entries; index++)
03097          if (!_suspend_struct[index].in_use)
03098             break;
03099 
03100       if (index == _suspend_entries) {
03101          /* if not found, create new one */
03102          _suspend_struct = (SUSPEND_STRUCT *) realloc(_suspend_struct,
03103                                                       sizeof
03104                                                       (SUSPEND_STRUCT) *
03105                                                       (_suspend_entries + 1));
03106          memset(&_suspend_struct[_suspend_entries], 0, sizeof(SUSPEND_STRUCT));
03107 
03108          _suspend_entries++;
03109          if (_suspend_struct == NULL) {
03110             _suspend_entries--;
03111             return SS_NO_MEMORY;
03112          }
03113       }
03114       *pindex = index;
03115       _suspend_struct[index].thread_id = ss_gettid();
03116       _suspend_struct[index].in_use = TRUE;
03117    }
03118 
03119    return SS_SUCCESS;
03120 }
03121 
03122 /*------------------------------------------------------------------*/
03123 INT ss_suspend_exit()
03124 /********************************************************************\
03125 
03126   Routine: ss_suspend_exit
03127 
03128   Purpose: Closes the sockets used in the suspend/resume mechanism.
03129      Should be called before a thread exits.
03130 
03131   Input:
03132     none
03133 
03134   Output:
03135     none
03136 
03137   Function value:
03138     SS_SUCCESS              Successful completion
03139 
03140 \********************************************************************/
03141 {
03142    INT i, status;
03143 
03144    status = ss_suspend_get_index(&i);
03145 
03146    if (status != SS_SUCCESS)
03147       return status;
03148 
03149    if (_suspend_struct[i].ipc_recv_socket) {
03150       closesocket(_suspend_struct[i].ipc_recv_socket);
03151       closesocket(_suspend_struct[i].ipc_send_socket);
03152    }
03153 
03154    memset(&_suspend_struct[i], 0, sizeof(SUSPEND_STRUCT));
03155 
03156    /* calculate new _suspend_entries value */
03157    for (i = _suspend_entries - 1; i >= 0; i--)
03158       if (_suspend_struct[i].in_use)
03159          break;
03160 
03161    _suspend_entries = i + 1;
03162 
03163    if (_suspend_entries == 0) {
03164       free(_suspend_struct);
03165       _suspend_struct = NULL;
03166    }
03167 
03168    return SS_SUCCESS;
03169 }
03170 
03171 /*------------------------------------------------------------------*/
03172 INT ss_suspend_set_dispatch(INT channel, void *connection, INT(*dispatch) ())
03173 /********************************************************************\
03174 
03175   Routine: ss_suspend_set_dispatch
03176 
03177   Purpose: Set dispatch functions which get called whenever new data
03178      on various sockets arrive inside the ss_suspend function.
03179 
03180      Beside the Inter Process Communication socket several other
03181      sockets can simultanously watched: A "listen" socket for
03182      a server main thread, server sockets which receive new
03183      RPC requests from remote clients (given by the
03184      server_acception array) and client sockets which may
03185      get notification data from remote servers (such as
03186      database updates).
03187 
03188   Input:
03189     INT    channel               One of CH_IPC, CH_CLIENT,
03190          CH_SERVER, CH_MSERVER
03191 
03192     INT    (*dispatch())         Function being called
03193 
03194   Output:
03195     none
03196 
03197   Function value:
03198     SS_SUCCESS              Successful completion
03199 
03200 \********************************************************************/
03201 {
03202    INT i, status;
03203 
03204    status = ss_suspend_get_index(&i);
03205 
03206    if (status != SS_SUCCESS)
03207       return status;
03208 
03209    if (channel == CH_IPC) {
03210       _suspend_struct[i].ipc_dispatch = (INT(*)(char *, INT)) dispatch;
03211 
03212       if (!_suspend_struct[i].ipc_recv_socket)
03213          ss_suspend_init_ipc(i);
03214    }
03215 
03216    if (channel == CH_LISTEN) {
03217       _suspend_struct[i].listen_socket = *((INT *) connection);
03218       _suspend_struct[i].listen_dispatch = (INT(*)(INT)) dispatch;
03219    }
03220 
03221    if (channel == CH_CLIENT) {
03222       _suspend_struct[i].server_connection = (RPC_SERVER_CONNECTION *) connection;
03223       _suspend_struct[i].client_dispatch = (INT(*)(INT)) dispatch;
03224    }
03225 
03226    if (channel == CH_SERVER) {
03227       _suspend_struct[i].server_acception = (RPC_SERVER_ACCEPTION *) connection;
03228       _suspend_struct[i].server_dispatch = (INT(*)(INT, int, BOOL)) dispatch;
03229    }
03230 
03231    return SS_SUCCESS;
03232 }
03233 
03234 /*------------------------------------------------------------------*/
03235 INT ss_suspend_get_port(INT * port)
03236 /********************************************************************\
03237 
03238   Routine: ss_suspend_get_port
03239 
03240   Purpose: Return the UDP port number which can be used to resume
03241      the calling thread inside a ss_suspend function. The port
03242      number can then be used by another process as a para-
03243      meter to the ss_resume function to resume the thread
03244      which called ss_suspend.
03245 
03246   Input:
03247     none
03248 
03249   Output:
03250     INT    *port            UDP port number
03251 
03252   Function value:
03253     SS_SUCCESS              Successful completion
03254 
03255 \********************************************************************/
03256 {
03257    INT index, status;
03258 
03259    status = ss_suspend_get_index(&index);
03260 
03261    if (status != SS_SUCCESS)
03262       return status;
03263 
03264    if (!_suspend_struct[index].ipc_port)
03265       ss_suspend_init_ipc(index);
03266 
03267    *port = _suspend_struct[index].ipc_port;
03268 
03269    return SS_SUCCESS;
03270 }
03271 
03272 /*------------------------------------------------------------------*/
03273 INT ss_suspend(INT millisec, INT msg)
03274 /********************************************************************\
03275 
03276   Routine: ss_suspend
03277 
03278   Purpose: Suspend the calling thread for a speficic time. If
03279      timeout (in millisec.) is negative, the thead is suspended
03280      indefinitely. It can only be resumed from another thread
03281      or process which calls ss_resume or by some data which
03282      arrives on the client or server sockets.
03283 
03284      If msg equals to one of MSG_BM, MSG_ODB, the function
03285      return whenever such a message is received.
03286 
03287   Input:
03288     INT    millisec         Timeout in milliseconds
03289     INT    msg              Return from ss_suspend when msg
03290           (MSG_BM, MSG_ODB) is received.
03291 
03292   Output:
03293     none
03294 
03295   Function value:
03296     SS_SUCCESS              Requested message was received
03297     SS_TIMEOUT              Timeout expired
03298     SS_SERVER_RECV          Server channel got data
03299     SS_CLIENT_RECV          Client channel got data
03300     SS_ABORT (RPC_ABORT)    Connection lost
03301     SS_EXIT                 Connection closed
03302 
03303 \********************************************************************/
03304 {
03305    fd_set readfds;
03306    struct timeval timeout;
03307    INT sock, server_socket;
03308    INT index, status, i, return_status;
03309    int size;
03310    struct sockaddr from_addr;
03311    char str[100], buffer[80], buffer_tmp[80];
03312 
03313    /* get index to _suspend_struct for this thread */
03314    status = ss_suspend_get_index(&index);
03315 
03316    if (status != SS_SUCCESS)
03317       return status;
03318 
03319    return_status = SS_TIMEOUT;
03320 
03321    do {
03322       FD_ZERO(&readfds);
03323 
03324       /* check listen socket */
03325       if (_suspend_struct[index].listen_socket)
03326          FD_SET(_suspend_struct[index].listen_socket, &readfds);
03327 
03328       /* check server channels */
03329       if (_suspend_struct[index].server_acception)
03330          for (i = 0; i < MAX_RPC_CONNECTION; i++) {
03331             /* RPC channel */
03332             sock = _suspend_struct[index].server_acception[i].recv_sock;
03333 
03334             /* only watch the event tcp connection belonging to this thread */
03335             if (!sock || _suspend_struct[index].server_acception[i].tid != ss_gettid())
03336                continue;
03337 
03338             /* watch server socket if no data in cache */
03339             if (recv_tcp_check(sock) == 0)
03340                FD_SET(sock, &readfds);
03341             /* set timeout to zero if data in cache (-> just quick check IPC)
03342                and not called from inside bm_send_event (-> wait for IPC) */
03343             else if (msg == 0)
03344                millisec = 0;
03345 
03346             /* event channel */
03347             sock = _suspend_struct[index].server_acception[i].event_sock;
03348 
03349             if (!sock)
03350                continue;
03351 
03352             /* watch server socket if no data in cache */
03353             if (recv_event_check(sock) == 0)
03354                FD_SET(sock, &readfds);
03355             /* set timeout to zero if data in cache (-> just quick check IPC)
03356                and not called from inside bm_send_event (-> wait for IPC) */
03357             else if (msg == 0)
03358                millisec = 0;
03359          }
03360 
03361       /* watch client recv connections */
03362       if (_suspend_struct[index].server_connection) {
03363          sock = _suspend_struct[index].server_connection->recv_sock;
03364          if (sock)
03365             FD_SET(sock, &readfds);
03366       }
03367 
03368       /* check IPC socket */
03369       if (_suspend_struct[index].ipc_recv_socket)
03370          FD_SET(_suspend_struct[index].ipc_recv_socket, &readfds);
03371 
03372       timeout.tv_sec = millisec / 1000;
03373       timeout.tv_usec = (millisec % 1000) * 1000;
03374 
03375       do {
03376          if (millisec < 0)
03377             status = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);    /* blocking */
03378          else
03379             status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
03380 
03381          /* if an alarm signal was cought, restart select with reduced timeout */
03382          if (status == -1 && timeout.tv_sec >= WATCHDOG_INTERVAL / 1000)
03383             timeout.tv_sec -= WATCHDOG_INTERVAL / 1000;
03384 
03385       } while (status == -1);   /* dont return if an alarm signal was cought */
03386 
03387       /* if listen socket got data, call dispatcher with socket */
03388       if (_suspend_struct[index].listen_socket &&
03389           FD_ISSET(_suspend_struct[index].listen_socket, &readfds)) {
03390          sock = _suspend_struct[index].listen_socket;
03391 
03392          if (_suspend_struct[index].listen_dispatch) {
03393             status = _suspend_struct[index].listen_dispatch(sock);
03394             if (status == RPC_SHUTDOWN)
03395                return status;
03396          }
03397       }
03398 
03399       /* check server channels */
03400       if (_suspend_struct[index].server_acception)
03401          for (i = 0; i < MAX_RPC_CONNECTION; i++) {
03402             /* rpc channel */
03403             sock = _suspend_struct[index].server_acception[i].recv_sock;
03404 
03405             /* only watch the event tcp connection belonging to this thread */
03406             if (!sock || _suspend_struct[index].server_acception[i].tid != ss_gettid())
03407                continue;
03408 
03409             if (recv_tcp_check(sock) || FD_ISSET(sock, &readfds)) {
03410                if (_suspend_struct[index].server_dispatch) {
03411                   status = _suspend_struct[index].server_dispatch(i, sock, msg != 0);
03412                   _suspend_struct[index].server_acception[i].
03413                       last_activity = ss_millitime();
03414 
03415                   if (status == SS_ABORT || status == SS_EXIT || status == RPC_SHUTDOWN)
03416                      return status;
03417 
03418                   return_status = SS_SERVER_RECV;
03419                }
03420             }
03421 
03422             /* event channel */
03423             sock = _suspend_struct[index].server_acception[i].event_sock;
03424             if (!sock)
03425                continue;
03426 
03427             if (recv_event_check(sock) || FD_ISSET(sock, &readfds)) {
03428                if (_suspend_struct[index].server_dispatch) {
03429                   status = _suspend_struct[index].server_dispatch(i, sock, msg != 0);
03430                   _suspend_struct[index].server_acception[i].
03431                       last_activity = ss_millitime();
03432 
03433                   if (status == SS_ABORT || status == SS_EXIT || status == RPC_SHUTDOWN)
03434                      return status;
03435 
03436                   return_status = SS_SERVER_RECV;
03437                }
03438             }
03439          }
03440 
03441       /* check server message channels */
03442       if (_suspend_struct[index].server_connection) {
03443          sock = _suspend_struct[index].server_connection->recv_sock;
03444 
03445          if (sock && FD_ISSET(sock, &readfds)) {
03446             if (_suspend_struct[index].client_dispatch)
03447                status = _suspend_struct[index].client_dispatch(sock);
03448             else {
03449                status = SS_SUCCESS;
03450                size = recv_tcp(sock, buffer, sizeof(buffer), 0);
03451 
03452                if (size <= 0)
03453                   status = SS_ABORT;
03454             }
03455 
03456             if (status == SS_ABORT) {
03457                sprintf(str, "Server connection broken to %s",
03458                        _suspend_struct[index].server_connection->host_name);
03459                cm_msg(MINFO, "ss_suspend", str);
03460 
03461                /* close client connection if link broken */
03462                closesocket(_suspend_struct[index].server_connection->send_sock);
03463                closesocket(_suspend_struct[index].server_connection->recv_sock);
03464                closesocket(_suspend_struct[index].server_connection->event_sock);
03465 
03466                memset(_suspend_struct[index].server_connection,
03467                       0, sizeof(RPC_CLIENT_CONNECTION));
03468 
03469                /* exit program after broken connection to MIDAS server */
03470                return SS_ABORT;
03471             }
03472 
03473             return_status = SS_CLIENT_RECV;
03474          }
03475       }
03476 
03477       /* check IPC socket */
03478       if (_suspend_struct[index].ipc_recv_socket &&
03479           FD_ISSET(_suspend_struct[index].ipc_recv_socket, &readfds)) {
03480          /* receive IPC message */
03481          size = sizeof(struct sockaddr);
03482          size = recvfrom(_suspend_struct[index].ipc_recv_socket,
03483                          buffer, sizeof(buffer), 0, &from_addr, (int *) &size);
03484 
03485          /* find out if this thread is connected as a server */
03486          server_socket = 0;
03487          if (_suspend_struct[index].server_acception &&
03488              rpc_get_server_option(RPC_OSERVER_TYPE) != ST_REMOTE)
03489             for (i = 0; i < MAX_RPC_CONNECTION; i++) {
03490                sock = _suspend_struct[index].server_acception[i].send_sock;
03491                if (sock && _suspend_struct[index].server_acception[i].tid == ss_gettid())
03492                   server_socket = sock;
03493             }
03494 
03495          /* receive further messages to empty UDP queue */
03496          do {
03497             FD_ZERO(&readfds);
03498             FD_SET(_suspend_struct[index].ipc_recv_socket, &readfds);
03499 
03500             timeout.tv_sec = 0;
03501             timeout.tv_usec = 0;
03502 
03503             status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
03504 
03505             if (status != -1
03506                 && FD_ISSET(_suspend_struct[index].ipc_recv_socket, &readfds)) {
03507                size = sizeof(struct sockaddr);
03508                size =
03509                    recvfrom(_suspend_struct[index].ipc_recv_socket,
03510                             buffer_tmp, sizeof(buffer_tmp), 0, &from_addr, &size);
03511 
03512                /* don't forward same MSG_BM as above */
03513                if (buffer_tmp[0] != 'B' || strcmp(buffer_tmp, buffer) != 0)
03514                   if (_suspend_struct[index].ipc_dispatch)
03515                      _suspend_struct[index].ipc_dispatch(buffer_tmp, server_socket);
03516             }
03517 
03518          } while (FD_ISSET(_suspend_struct[index].ipc_recv_socket, &readfds));
03519 
03520          /* return if received requested message */
03521          if (msg == MSG_BM && buffer[0] == 'B')
03522             return SS_SUCCESS;
03523          if (msg == MSG_ODB && buffer[0] == 'O')
03524             return SS_SUCCESS;
03525 
03526          /* call dispatcher */
03527          if (_suspend_struct[index].ipc_dispatch)
03528             _suspend_struct[index].ipc_dispatch(buffer, server_socket);
03529 
03530          return_status = SS_SUCCESS;
03531       }
03532 
03533    } while (millisec < 0);
03534 
03535    return return_status;
03536 }
03537 
03538 /*------------------------------------------------------------------*/
03539 INT ss_resume(INT port, char *message)
03540 /********************************************************************\
03541 
03542   Routine: ss_resume
03543 
03544   Purpose: Resume another thread or process which called ss_suspend.
03545      The port has to be transfered (shared memory or so) from
03546      the thread or process which should be resumed. In that
03547      process it can be obtained via ss_suspend_get_port.
03548 
03549   Input:
03550     INT    port             UDP port number
03551     INT    msg              Mesage id & parameter transferred to
03552     INT    param              target process
03553 
03554   Output:
03555     none
03556 
03557   Function value:
03558     SS_SUCCESS              Successful completion
03559     SS_SOCKET_ERROR         Socket error
03560 
03561 \********************************************************************/
03562 {
03563    INT status, index;
03564 
03565    if (ss_in_async_routine_flag) {
03566       /* if called from watchdog, tid is different under NT! */
03567       index = 0;
03568    } else {
03569       status = ss_suspend_get_index(&index);
03570 
03571       if (status != SS_SUCCESS)
03572          return status;
03573    }
03574 
03575    _suspend_struct[index].bind_addr.sin_port = htons((short) port);
03576 
03577    status = sendto(_suspend_struct[index].ipc_send_socket, message,
03578                    strlen(message) + 1, 0,
03579                    (struct sockaddr *) &_suspend_struct[index].bind_addr,
03580                    sizeof(struct sockaddr_in));
03581 
03582    if (status != (INT) strlen(message) + 1)
03583       return SS_SOCKET_ERROR;
03584 
03585    return SS_SUCCESS;
03586 }
03587 
03588 /*------------------------------------------------------------------*/
03589 /********************************************************************\
03590 *                                                                    *
03591 *                     Network functions                              *
03592 *                                                                    *
03593 \********************************************************************/
03594 
03595 /*------------------------------------------------------------------*/
03596 INT send_tcp(int sock, char *buffer, DWORD buffer_size, INT flags)
03597 /********************************************************************\
03598 
03599   Routine: send_tcp
03600 
03601   Purpose: Send network data over TCP port. Break buffer in smaller
03602            parts if larger than maximum TCP buffer size (usually 64k).
03603 
03604   Input:
03605     INT   sock               Socket which was previosly opened.
03606     DWORD buffer_size        Size of the buffer in bytes.
03607     INT   flags              Flags passed to send()
03608 
03609   Output:
03610     char  *buffer            Network receive buffer.
03611 
03612   Function value:
03613     INT                     Same as send()
03614 
03615 \********************************************************************/
03616 {
03617    DWORD count;
03618    INT status;
03619 
03620    /* transfer fragments until complete buffer is transferred */
03621 
03622    for (count = 0; (INT) count < (INT) buffer_size - NET_TCP_SIZE;) {
03623       status = send(sock, buffer + count, NET_TCP_SIZE, flags);
03624       if (status != -1)
03625          count += status;
03626       else {
03627          cm_msg(MERROR, "send_tcp",
03628                 "send(socket=%d,size=%d) returned %d, errno: %d (%s)",
03629                 sock, NET_TCP_SIZE, status, errno, strerror(errno));
03630          return status;
03631       }
03632    }
03633 
03634    while (count < buffer_size) {
03635       status = send(sock, buffer + count, buffer_size - count, flags);
03636       if (status != -1)
03637          count += status;
03638       else {
03639          cm_msg(MERROR, "send_tcp",
03640                 "send(socket=%d,size=%d) returned %d, errno: %d (%s)",
03641                 sock, (int) (buffer_size - count), status, errno, strerror(errno));
03642          return status;
03643       }
03644    }
03645 
03646    return count;
03647 }
03648 
03649 /*------------------------------------------------------------------*/
03650 INT recv_string(int sock, char *buffer, DWORD buffer_size, INT millisec)
03651 /********************************************************************\
03652 
03653   Routine: recv_string
03654 
03655   Purpose: Receive network data over TCP port. Since sockets are
03656      operated in stream mode, a single transmission via send
03657      may not transfer the full data. Therefore, one has to check
03658      at the receiver side if the full data is received. If not,
03659      one has to issue several recv() commands.
03660 
03661      The length of the data is determined by a trailing zero.
03662 
03663   Input:
03664     INT   sock               Socket which was previosly opened.
03665     DWORD buffer_size        Size of the buffer in bytes.
03666     INT   millisec           Timeout in ms
03667 
03668   Output:
03669     char  *buffer            Network receive buffer.
03670 
03671   Function value:
03672     INT                      String length
03673 
03674 \********************************************************************/
03675 {
03676    INT i, status;
03677    DWORD n;
03678    fd_set readfds;
03679    struct timeval timeout;
03680 
03681    n = 0;
03682    memset(buffer, 0, buffer_size);
03683 
03684    do {
03685       if (millisec > 0) {
03686          FD_ZERO(&readfds);
03687          FD_SET(sock, &readfds);
03688 
03689          timeout.tv_sec = millisec / 1000;
03690          timeout.tv_usec = (millisec % 1000) * 1000;
03691 
03692          do {
03693             status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
03694 
03695             /* if an alarm signal was cought, restart select with reduced timeout */
03696             if (status == -1 && timeout.tv_sec >= WATCHDOG_INTERVAL / 1000)
03697                timeout.tv_sec -= WATCHDOG_INTERVAL / 1000;
03698 
03699          } while (status == -1);        /* dont return if an alarm signal was cought */
03700 
03701          if (!FD_ISSET(sock, &readfds))
03702             break;
03703       }
03704 
03705       i = recv(sock, buffer + n, 1, 0);
03706 
03707       if (i <= 0)
03708          break;
03709 
03710       n++;
03711 
03712       if (n >= buffer_size)
03713          break;
03714 
03715    } while (buffer[n - 1] && buffer[n - 1] != 10);
03716 
03717    return n - 1;
03718 }
03719 
03720 /*------------------------------------------------------------------*/
03721 INT recv_tcp(int sock, char *net_buffer, DWORD buffer_size, INT flags)
03722 /********************************************************************\
03723 
03724   Routine: recv_tcp
03725 
03726   Purpose: Receive network data over TCP port. Since sockets are
03727      operated in stream mode, a single transmission via send
03728      may not transfer the full data. Therefore, one has to check
03729      at the receiver side if the full data is received. If not,
03730      one has to issue several recv() commands.
03731 
03732      The length of the data is determined by the data header,
03733      which consists of two DWORDs. The first is the command code
03734      (or function id), the second is the size of the following
03735      parameters in bytes. From that size recv_tcp() determines
03736      how much data to receive.
03737 
03738   Input:
03739     INT   sock               Socket which was previosly opened.
03740     char  *net_buffer        Buffer to store data to
03741     DWORD buffer_size        Size of the buffer in bytes.
03742     INT   flags              Flags passed to recv()
03743 
03744   Output:
03745     char  *buffer            Network receive buffer.
03746 
03747   Function value:
03748     INT                      Same as recv()
03749 
03750 \********************************************************************/
03751 {
03752    INT param_size, n_received, n;
03753    NET_COMMAND *nc;
03754 
03755    if (buffer_size < sizeof(NET_COMMAND_HEADER)) {
03756       cm_msg(MERROR, "recv_tcp", "parameters too large for network buffer");
03757       return -1;
03758    }
03759 
03760    /* first receive header */
03761    n_received = 0;
03762    do {
03763 #ifdef OS_UNIX
03764       do {
03765          n = recv(sock, net_buffer + n_received, sizeof(NET_COMMAND_HEADER), flags);
03766 
03767          /* don't return if an alarm signal was cought */
03768       } while (n == -1 && errno == EINTR);
03769 #else
03770       n = recv(sock, net_buffer + n_received, sizeof(NET_COMMAND_HEADER), flags);
03771 #endif
03772 
03773       if (n <= 0) {
03774          cm_msg(MERROR, "recv_tcp",
03775                 "header: recv returned %d, n_received = %d, errno: %d (%s)",
03776                 n, n_received, errno, strerror(errno));
03777          return n;
03778       }
03779 
03780       n_received += n;
03781 
03782    } while (n_received < sizeof(NET_COMMAND_HEADER));
03783 
03784    /* now receive parameters */
03785 
03786    nc = (NET_COMMAND *) net_buffer;
03787    param_size = nc->header.param_size;
03788    n_received = 0;
03789 
03790    if (param_size == 0)
03791       return sizeof(NET_COMMAND_HEADER);
03792 
03793    do {
03794 #ifdef OS_UNIX
03795       do {
03796          n = recv(sock,
03797                   net_buffer + sizeof(NET_COMMAND_HEADER) + n_received,
03798                   param_size - n_received, flags);
03799 
03800          /* don't return if an alarm signal was cought */
03801       } while (n == -1 && errno == EINTR);
03802 #else
03803       n = recv(sock, net_buffer + sizeof(NET_COMMAND_HEADER) + n_received,
03804                param_size - n_received, flags);
03805 #endif
03806 
03807       if (n <= 0) {
03808          cm_msg(MERROR, "recv_tcp",
03809                 "param: recv returned %d, n_received = %d, errno: %d (%s)",
03810                 n, n_received, errno, strerror(errno));
03811          return n;
03812       }
03813 
03814       n_received += n;
03815    } while (n_received < param_size);
03816 
03817    return sizeof(NET_COMMAND_HEADER) + param_size;
03818 }
03819 
03820 /*------------------------------------------------------------------*/
03821 INT send_udp(int sock, char *buffer, DWORD buffer_size, INT flags)
03822 /********************************************************************\
03823 
03824   Routine: send_udp
03825 
03826   Purpose: Send network data over UDP port. If buffer_size is small,
03827      collect several events and send them together. If
03828      buffer_size is larger than largest datagram size
03829      NET_UDP_SIZE, split event in several udp buffers and
03830      send them separately with serial number protection.
03831 
03832   Input:
03833     INT   sock               Socket which was previosly opened.
03834     DWORD buffer_size        Size of the buffer in bytes.
03835     INT   flags              Flags passed to send()
03836 
03837   Output:
03838     char  *buffer            Network receive buffer.
03839 
03840   Function value:
03841     INT                     Same as send()
03842 
03843 \********************************************************************/
03844 {
03845    INT status;
03846    UDP_HEADER *udp_header;
03847    static char udp_buffer[NET_UDP_SIZE];
03848    static INT serial_number = 0, n_received = 0;
03849    DWORD i, data_size;
03850 
03851    udp_header = (UDP_HEADER *) udp_buffer;
03852    data_size = NET_UDP_SIZE - sizeof(UDP_HEADER);
03853 
03854    /*
03855       If buffer size is between half the UPD size and full UDP size,
03856       send immediately a single packet.
03857     */
03858    if (buffer_size >= NET_UDP_SIZE / 2 && buffer_size <= data_size) {
03859       /*
03860          If there is any data already in the buffer, send it first.
03861        */
03862       if (n_received) {
03863          udp_header->serial_number = UDP_FIRST | n_received;
03864          udp_header->sequence_number = ++serial_number;
03865 
03866          send(sock, udp_buffer, n_received + sizeof(UDP_HEADER), flags);
03867          n_received = 0;
03868       }
03869 
03870       udp_header->serial_number = UDP_FIRST | buffer_size;
03871       udp_header->sequence_number = ++serial_number;
03872 
03873       memcpy(udp_header + 1, buffer, buffer_size);
03874       status = send(sock, udp_buffer, buffer_size + sizeof(UDP_HEADER), flags);
03875       if (status == (INT) buffer_size + (int) sizeof(UDP_HEADER))
03876          status -= sizeof(UDP_HEADER);
03877 
03878       return status;
03879    }
03880 
03881    /*
03882       If buffer size is smaller than half the UDP size, collect events
03883       until UDP buffer is optimal filled.
03884     */
03885    if (buffer_size <= data_size) {
03886       /* If udp_buffer has space, just copy it there */
03887       if (buffer_size + n_received < data_size) {
03888          memcpy(udp_buffer + sizeof(UDP_HEADER) + n_received, buffer, buffer_size);
03889 
03890          n_received += buffer_size;
03891          return buffer_size;
03892       }
03893 
03894       /* If udp_buffer has not enough space, send it */
03895       udp_header->serial_number = UDP_FIRST | n_received;
03896       udp_header->sequence_number = ++serial_number;
03897 
03898       status = send(sock, udp_buffer, n_received + sizeof(UDP_HEADER), flags);
03899 
03900       n_received = 0;
03901 
03902       memcpy(udp_header + 1, buffer, buffer_size);
03903       n_received = buffer_size;
03904 
03905       return buffer_size;
03906    }
03907 
03908    /*
03909       If buffer size is larger than UDP size, split event in several
03910       buffers.
03911     */
03912 
03913    /* If there is any data already in the buffer, send it first */
03914    if (n_received) {
03915       udp_header->serial_number = UDP_FIRST | n_received;
03916       udp_header->sequence_number = ++serial_number;
03917 
03918       send(sock, udp_buffer, n_received + sizeof(UDP_HEADER), flags);
03919       n_received = 0;
03920    }
03921 
03922    for (i = 0; i < ((buffer_size - 1) / data_size); i++) {
03923       if (i == 0) {
03924          udp_header->serial_number = UDP_FIRST | buffer_size;
03925          udp_header->sequence_number = ++serial_number;
03926       } else {
03927          udp_header->serial_number = serial_number;
03928          udp_header->sequence_number = i;
03929       }
03930 
03931       memcpy(udp_header + 1, buffer + i * data_size, data_size);
03932       send(sock, udp_buffer, NET_UDP_SIZE, flags);
03933    }
03934 
03935    /* Send remaining bytes */
03936    udp_header->serial_number = serial_number;
03937    udp_header->sequence_number = i;
03938    memcpy(udp_header + 1, buffer + i * data_size, buffer_size - i * data_size);
03939    status =
03940        send(sock, udp_buffer, sizeof(UDP_HEADER) + buffer_size - i * data_size, flags);
03941    if ((DWORD) status == sizeof(UDP_HEADER) + buffer_size - i * data_size)
03942       return buffer_size;
03943 
03944    return status;
03945 }
03946 
03947 /*------------------------------------------------------------------*/
03948 INT recv_udp(int sock, char *buffer, DWORD buffer_size, INT flags)
03949 /********************************************************************\
03950 
03951   Routine: recv_udp
03952 
03953   Purpose: Receive network data over UDP port. If received event
03954      is splitted into several buffers, recombine them checking
03955      the serial number. If one buffer is missing in a splitted
03956      event, throw away the whole event.
03957 
03958   Input:
03959     INT   sock               Socket which was previosly opened.
03960     DWORD buffer_size        Size of the buffer in bytes.
03961     INT   flags              Flags passed to recv()
03962 
03963   Output:
03964     char  *buffer            Network receive buffer.
03965 
03966   Function value:
03967     INT                     Same as recv()
03968 
03969 \********************************************************************/
03970 {
03971    INT i, status;
03972    UDP_HEADER *udp_header;
03973    char udp_buffer[NET_UDP_SIZE];
03974    DWORD serial_number, sequence_number, total_buffer_size;
03975    DWORD data_size, n_received;
03976    fd_set readfds;
03977    struct timeval timeout;
03978 
03979    udp_header = (UDP_HEADER *) udp_buffer;
03980    data_size = NET_UDP_SIZE - sizeof(UDP_HEADER);
03981 
03982    /* Receive the first buffer */
03983 #ifdef OS_UNIX
03984    do {
03985       i = recv(sock, udp_buffer, NET_UDP_SIZE, flags);
03986 
03987       /* dont return if an alarm signal was cought */
03988    } while (i == -1 && errno == EINTR);
03989 #else
03990    i = recv(sock, udp_buffer, NET_UDP_SIZE, flags);
03991 #endif
03992 
03993  start:
03994 
03995    /* Receive buffers until we get a sequence start */
03996    while (!(udp_header->serial_number & UDP_FIRST)) {
03997       /* wait for data with timeout */
03998       FD_ZERO(&readfds);
03999       FD_SET(sock, &readfds);
04000 
04001       timeout.tv_sec = 0;
04002       timeout.tv_usec = 100000; /* 0.1 s */
04003 
04004       do {
04005          status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
04006       } while (status == -1);
04007 
04008       /*
04009          If we got nothing, return zero so that calling program can do
04010          other things like checking TCP port for example.
04011        */
04012       if (!FD_ISSET(sock, &readfds))
04013          return 0;
04014 
04015 #ifdef OS_UNIX
04016       do {
04017          i = recv(sock, udp_buffer, NET_UDP_SIZE, flags);
04018 
04019          /* dont return if an alarm signal was caught */
04020       } while (i == -1 && errno == EINTR);
04021 #else
04022       i = recv(sock, udp_buffer, NET_UDP_SIZE, flags);
04023 #endif
04024    }
04025 
04026    /* if no others are following, return */
04027    total_buffer_size = udp_header->serial_number & ~UDP_FIRST;
04028    serial_number = udp_header->sequence_number;
04029    sequence_number = 0;
04030 
04031    if (total_buffer_size <= data_size) {
04032       if (buffer_size < total_buffer_size) {
04033          memcpy(buffer, udp_header + 1, buffer_size);
04034          return buffer_size;
04035       } else {
04036          memcpy(buffer, udp_header + 1, total_buffer_size);
04037          return total_buffer_size;
04038       }
04039    }
04040 
04041    /* if others are following, collect them */
04042    n_received = data_size;
04043 
04044    if (buffer_size < data_size) {
04045       memcpy(buffer, udp_header + 1, buffer_size);
04046       return buffer_size;
04047    }
04048 
04049    memcpy(buffer, udp_header + 1, data_size);
04050 
04051 
04052    do {
04053       /* wait for new data with timeout */
04054       FD_ZERO(&readfds);
04055       FD_SET(sock, &readfds);
04056 
04057       timeout.tv_sec = 0;
04058       timeout.tv_usec = 100000; /* 0.1 s */
04059 
04060       do {
04061          status = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
04062       } while (status == -1);
04063 
04064       /*
04065          If we got nothing, return zero so that calling program can do
04066          other things like checking TCP port for example.
04067        */
04068       if (!FD_ISSET(sock, &readfds))
04069          return 0;
04070 
04071 #ifdef OS_UNIX
04072       do {
04073          i = recv(sock, udp_buffer, NET_UDP_SIZE, flags);
04074 
04075          /* dont return if an alarm signal was caught */
04076       } while (i == -1 && errno == EINTR);
04077 #else
04078       i = recv(sock, udp_buffer, NET_UDP_SIZE, flags);
04079 #endif
04080 
04081       sequence_number++;
04082 
04083       /* check sequence and serial numbers */
04084       if (udp_header->serial_number != serial_number ||
04085           udp_header->sequence_number != sequence_number)
04086          /* lost one, so start again */
04087          goto start;
04088 
04089       /* copy what we got */
04090       memcpy(buffer + n_received, udp_header + 1, i - sizeof(UDP_HEADER));
04091 
04092       n_received += (i - sizeof(UDP_HEADER));
04093 
04094    } while (n_received < total_buffer_size);
04095 
04096    return n_received;
04097 }
04098 
04099 /*------------------------------------------------------------------*/
04100 
04101 #ifdef OS_MSDOS
04102 #ifdef sopen
04103 /********************************************************************\
04104    under Turbo-C, sopen is defined as a macro instead a function.
04105    Since the PCTCP library uses sopen as a function call, we supply
04106    it here.
04107 \********************************************************************/
04108 
04109 #undef sopen
04110 
04111 int sopen(const char *path, int access, int shflag, int mode)
04112 {
04113    return open(path, (access) | (shflag), mode);
04114 }
04115 
04116 #endif
04117 #endif
04118 
04119 /*------------------------------------------------------------------*/
04120 /********************************************************************\
04121 *                                                                    *
04122 *                     Tape functions                                 *
04123 *                                                                    *
04124 \********************************************************************/
04125 
04126 /*------------------------------------------------------------------*/
04127 INT ss_tape_open(char *path, INT oflag, INT * channel)
04128 /********************************************************************\
04129 
04130   Routine: ss_tape_open
04131 
04132   Purpose: Open tape channel
04133 
04134   Input:
04135     char  *path             Name of tape
04136                             Under Windows NT, usually \\.\tape0
04137                             Under UNIX, usually /dev/tape
04138     INT   oflag             Open flags, same as open()
04139 
04140   Output:
04141     INT   *channel          Channel identifier
04142 
04143   Function value:
04144     SS_SUCCESS              Successful completion
04145     SS_NO_TAPE              No tape in device
04146     SS_DEV_BUSY             Device is used by someone else
04147 
04148 \********************************************************************/
04149 {
04150 #ifdef OS_UNIX
04151    struct mtop arg;
04152 
04153    cm_enable_watchdog(FALSE);
04154 
04155    *channel = open(path, oflag, 0644);
04156 
04157    cm_enable_watchdog(TRUE);
04158 
04159    if (*channel < 0)
04160       cm_msg(MERROR, "ss_tape_open", strerror(errno));
04161 
04162    if (*channel < 0) {
04163       if (errno == EIO)
04164          return SS_NO_TAPE;
04165       if (errno == EBUSY)
04166          return SS_DEV_BUSY;
04167       return errno;
04168    }
04169 #ifdef MTSETBLK
04170    /* set variable block size */
04171    arg.mt_op = MTSETBLK;
04172    arg.mt_count = 0;
04173 
04174    ioctl(*channel, MTIOCTOP, &arg);
04175 #endif                          /* MTSETBLK */
04176 
04177 #endif                          /* OS_UNIX */
04178 
04179 #ifdef OS_WINNT
04180    INT status;
04181    TAPE_GET_MEDIA_PARAMETERS m;
04182 
04183    *channel = (INT) CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0,
04184                                0, OPEN_EXISTING, 0, NULL);
04185 
04186    if (*channel == (INT) INVALID_HANDLE_VALUE) {
04187       status = GetLastError();
04188       if (status == ERROR_SHARING_VIOLATION) {
04189          cm_msg(MERROR, "ss_tape_open", "tape is used by other process");
04190          return SS_DEV_BUSY;
04191       }
04192       if (status == ERROR_FILE_NOT_FOUND) {
04193          cm_msg(MERROR, "ss_tape_open", "tape device \"%s\" doesn't exist", path);
04194          return SS_NO_TAPE;
04195       }
04196 
04197       cm_msg(MERROR, "ss_tape_open", "unknown error %d", status);
04198       return status;
04199    }
04200 
04201    status = GetTapeStatus((HANDLE) (*channel));
04202    if (status == ERROR_NO_MEDIA_IN_DRIVE || status == ERROR_BUS_RESET) {
04203       cm_msg(MERROR, "ss_tape_open", "no media in drive");
04204       return SS_NO_TAPE;
04205    }
04206 
04207    /* set block size */
04208    memset(&m, 0, sizeof(m));
04209    m.BlockSize = TAPE_BUFFER_SIZE;
04210    SetTapeParameters((HANDLE) (*channel), SET_TAPE_MEDIA_INFORMATION, &m);
04211 
04212 #endif
04213 
04214    return SS_SUCCESS;
04215 }
04216 
04217 /*------------------------------------------------------------------*/
04218 INT ss_tape_close(INT channel)
04219 /********************************************************************\
04220 
04221   Routine: ss_tape_close
04222 
04223   Purpose: Close tape channel
04224 
04225   Input:
04226     INT   channel           Channel identifier
04227 
04228   Output:
04229     <none>
04230 
04231   Function value:
04232     SS_SUCCESS              Successful completion
04233     errno                   Low level error number
04234 
04235 \********************************************************************/
04236 {
04237    INT status;
04238 
04239 #ifdef OS_UNIX
04240 
04241    status = close(channel);
04242 
04243    if (status < 0) {
04244       cm_msg(MERROR, "ss_tape_close", strerror(errno));
04245       return errno;
04246    }
04247 #endif                          /* OS_UNIX */
04248 
04249 #ifdef OS_WINNT
04250 
04251    if (!CloseHandle((HANDLE) channel)) {
04252       status = GetLastError();
04253       cm_msg(MERROR, "ss_tape_close", "unknown error %d", status);
04254       return status;
04255    }
04256 #endif                          /* OS_WINNT */
04257 
04258    return SS_SUCCESS;
04259 }
04260 
04261 /*------------------------------------------------------------------*/
04262 INT ss_tape_status(char *path)
04263 /********************************************************************\
04264 
04265   Routine: ss_tape_status
04266 
04267   Purpose: Print status information about tape
04268 
04269   Input:
04270     char  *path             Name of tape
04271 
04272   Output:
04273     <print>                 Tape information
04274 
04275   Function value:
04276     SS_SUCCESS              Successful completion
04277 
04278 \********************************************************************/
04279 {
04280 #ifdef OS_UNIX
04281    char str[256];
04282    /* let 'mt' do the job */
04283    sprintf(str, "mt -f %s status", path);
04284    system(str);
04285 #endif                          /* OS_UNIX */
04286 
04287 #ifdef OS_WINNT
04288    INT status, channel;
04289    DWORD size;
04290    TAPE_GET_MEDIA_PARAMETERS m;
04291    TAPE_GET_DRIVE_PARAMETERS d;
04292    double x;
04293 
04294    channel = (INT) CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0,
04295                               0, OPEN_EXISTING, 0, NULL);
04296 
04297    if (channel == (INT) INVALID_HANDLE_VALUE) {
04298       status = GetLastError();
04299       if (status == ERROR_SHARING_VIOLATION) {
04300          cm_msg(MINFO, "ss_tape_status", "tape is used by other process");
04301          return SS_SUCCESS;
04302       }
04303       if (status == ERROR_FILE_NOT_FOUND) {
04304          cm_msg(MINFO, "ss_tape_status", "tape device \"%s\" doesn't exist", path);
04305          return SS_SUCCESS;
04306       }
04307 
04308       cm_msg(MINFO, "ss_tape_status", "unknown error %d", status);
04309       return status;
04310    }
04311 
04312    /* poll media changed messages */
04313    GetTapeParameters((HANDLE) channel, GET_TAPE_DRIVE_INFORMATION, &size, &d);
04314    GetTapeParameters((HANDLE) channel, GET_TAPE_DRIVE_INFORMATION, &size, &d);
04315 
04316    status = GetTapeStatus((HANDLE) channel);
04317    if (status == ERROR_NO_MEDIA_IN_DRIVE || status == ERROR_BUS_RESET) {
04318       cm_msg(MINFO, "ss_tape_status", "no media in drive");
04319       CloseHandle((HANDLE) channel);
04320       return SS_SUCCESS;
04321    }
04322 
04323    GetTapeParameters((HANDLE) channel, GET_TAPE_DRIVE_INFORMATION, &size, &d);
04324    GetTapeParameters((HANDLE) channel, GET_TAPE_MEDIA_INFORMATION, &size, &m);
04325 
04326    printf("Hardware error correction is %s\n", d.ECC ? "on" : "off");
04327    printf("Hardware compression is %s\n", d.Compression ? "on" : "off");
04328    printf("Tape %s write protected\n", m.WriteProtected ? "is" : "is not");
04329 
04330    if (d.FeaturesLow & TAPE_DRIVE_TAPE_REMAINING) {
04331       x = ((double) m.Remaining.LowPart + (double) m.Remaining.HighPart * 4.294967295E9)
04332           / 1024.0 / 1000.0;
04333       printf("Tape capacity remaining is %d MB\n", (int) x);
04334    } else
04335       printf("Tape capacity is not reported by tape\n");
04336 
04337    CloseHandle((HANDLE) channel);
04338 
04339 #endif
04340 
04341    return SS_SUCCESS;
04342 }
04343 
04344 /*------------------------------------------------------------------*/
04345 INT ss_tape_write(INT channel, void *pdata, INT count)
04346 /********************************************************************\
04347 
04348   Routine: ss_tape_write
04349 
04350   Purpose: Write count bytes to tape channel
04351 
04352   Input:
04353     INT   channel           Channel identifier
04354     void  *pdata            Address of data to write
04355     INT   count             number of bytes
04356 
04357   Output:
04358     <none>
04359 
04360   Function value:
04361     SS_SUCCESS              Successful completion
04362     SS_IO_ERROR             Physical IO error
04363     SS_TAPE_ERROR           Unknown tape error
04364 
04365 \********************************************************************/
04366 {
04367 #ifdef OS_UNIX
04368    INT status;
04369 
04370    do {
04371       status = write(channel, pdata, count);
04372 /*
04373     if (status != count)
04374       printf("count: %d - %d\n", count, status);
04375 */
04376    } while (status == -1 && errno == EINTR);
04377 
04378    if (status != count) {
04379       cm_msg(MERROR, "ss_tape_write", strerror(errno));
04380 
04381       if (errno == EIO)
04382          return SS_IO_ERROR;
04383       else
04384          return SS_TAPE_ERROR;
04385    }
04386 #endif                          /* OS_UNIX */
04387 
04388 #ifdef OS_WINNT
04389    INT status;
04390    DWORD written;
04391 
04392    WriteFile((HANDLE) channel, pdata, count, &written, NULL);
04393    if (written != (DWORD) count) {
04394       status = GetLastError();
04395       cm_msg(MERROR, "ss_tape_write", "error %d", status);
04396 
04397       return SS_IO_ERROR;
04398    }
04399 #endif                          /* OS_WINNT */
04400 
04401    return SS_SUCCESS;
04402 }
04403 
04404 /*------------------------------------------------------------------*/
04405 INT ss_tape_read(INT channel, void *pdata, INT * count)
04406 /********************************************************************\
04407 
04408   Routine: ss_tape_write
04409 
04410   Purpose: Read count bytes to tape channel
04411 
04412   Input:
04413     INT   channel           Channel identifier
04414     void  *pdata            Address of data
04415     INT   *count            Number of bytes to read
04416 
04417   Output:
04418     INT   *count            Number of read
04419 
04420   Function value:
04421     SS_SUCCESS              Successful operation
04422     <errno>                 Error code
04423 
04424 \********************************************************************/
04425 {
04426 #ifdef OS_UNIX
04427    INT n, status;
04428 
04429    do {
04430       n = read(channel, pdata, *count);
04431    } while (n == -1 && errno == EINTR);
04432 
04433    if (n == -1) {
04434       if (errno == ENOSPC || errno == EIO)
04435          status = SS_END_OF_TAPE;
04436       else {
04437          if (n == 0 && errno == 0)
04438             status = SS_END_OF_FILE;
04439          else {
04440             cm_msg(MERROR, "ss_tape_read",
04441                    "unexpected tape error: n=%d, errno=%d\n", n, errno);
04442             status = errno;
04443          }
04444       }
04445    } else
04446       status = SS_SUCCESS;
04447    *count = n;
04448 
04449    return status;
04450 
04451 #elif defined(OS_WINNT)         /* OS_UNIX */
04452 
04453    INT status;
04454    DWORD read;
04455 
04456    if (!ReadFile((HANDLE) channel, pdata, *count, &read, NULL)) {
04457       status = GetLastError();
04458       if (status == ERROR_NO_DATA_DETECTED)
04459          status = SS_END_OF_TAPE;
04460       else if (status == ERROR_FILEMARK_DETECTED)
04461          status = SS_END_OF_FILE;
04462       else if (status == ERROR_MORE_DATA)
04463          status = SS_SUCCESS;
04464       else
04465          cm_msg(MERROR, "ss_tape_read",
04466                 "unexpected tape error: n=%d, errno=%d\n", read, status);
04467    } else
04468       status = SS_SUCCESS;
04469 
04470    *count = read;
04471    return status;
04472 
04473 #else                           /* OS_WINNT */
04474 
04475    return SS_SUCCESS;
04476 
04477 #endif
04478 }
04479 
04480 /*------------------------------------------------------------------*/
04481 INT ss_tape_write_eof(INT channel)
04482 /********************************************************************\
04483 
04484   Routine: ss_tape_write_eof
04485 
04486   Purpose: Write end-of-file to tape channel
04487 
04488   Input:
04489     INT   *channel          Channel identifier
04490 
04491   Output:
04492     <none>
04493 
04494   Function value:
04495     SS_SUCCESS              Successful completion
04496     errno                   Error number
04497 
04498 \********************************************************************/
04499 {
04500    INT status;
04501 
04502 #ifdef OS_UNIX
04503    struct mtop arg;
04504 
04505    arg.mt_op = MTWEOF;
04506    arg.mt_count = 1;
04507 
04508    cm_enable_watchdog(FALSE);
04509 
04510    status = ioctl(channel, MTIOCTOP, &arg);
04511 
04512    cm_enable_watchdog(TRUE);
04513 
04514    if (status < 0) {
04515       cm_msg(MERROR, "ss_tape_write_eof", strerror(errno));
04516       return errno;
04517    }
04518 #endif                          /* OS_UNIX */
04519 
04520 #ifdef OS_WINNT
04521 
04522    TAPE_GET_DRIVE_PARAMETERS d;
04523    DWORD size;
04524 
04525    size = sizeof(TAPE_GET_DRIVE_PARAMETERS);
04526    GetTapeParameters((HANDLE) channel, GET_TAPE_DRIVE_INFORMATION, &size, &d);
04527 
04528    if (d.FeaturesHigh & TAPE_DRIVE_WRITE_FILEMARKS)
04529       status = WriteTapemark((HANDLE) channel, TAPE_FILEMARKS, 1, FALSE);
04530    else if (d.FeaturesHigh & TAPE_DRIVE_WRITE_LONG_FMKS)
04531       status = WriteTapemark((HANDLE) channel, TAPE_LONG_FILEMARKS, 1, FALSE);
04532    else if (d.FeaturesHigh & TAPE_DRIVE_WRITE_SHORT_FMKS)
04533       status = WriteTapemark((HANDLE) channel, TAPE_SHORT_FILEMARKS, 1, FALSE);
04534    else
04535       cm_msg(MERROR, "ss_tape_write_eof", "tape doesn't support writing of filemarks");
04536 
04537    if (status != NO_ERROR) {
04538       cm_msg(MERROR, "ss_tape_write_eof", "unknown error %d", status);
04539       return status;
04540    }
04541 #endif                          /* OS_WINNT */
04542 
04543    return SS_SUCCESS;
04544 }
04545 
04546 /*------------------------------------------------------------------*/
04547 INT ss_tape_fskip(INT channel, INT count)
04548 /********************************************************************\
04549 
04550   Routine: ss_tape_fskip
04551 
04552   Purpose: Skip count number of files on a tape
04553 
04554   Input:
04555     INT   *channel          Channel identifier
04556     INT   count             Number of files to skip
04557 
04558   Output:
04559     <none>
04560 
04561   Function value:
04562     SS_SUCCESS              Successful completion
04563     errno                   Error number
04564 
04565 \********************************************************************/
04566 {
04567    INT status;
04568 
04569 #ifdef OS_UNIX
04570    struct mtop arg;
04571 
04572    if (count > 0)
04573       arg.mt_op = MTFSF;
04574    else
04575       arg.mt_op = MTBSF;
04576    arg.mt_count = abs(count);
04577 
04578    cm_enable_watchdog(FALSE);
04579 
04580    status = ioctl(channel, MTIOCTOP, &arg);
04581 
04582    cm_enable_watchdog(TRUE);
04583 
04584    if (status < 0) {
04585       cm_msg(MERROR, "ss_tape_fskip", strerror(errno));
04586       return errno;
04587    }
04588 #endif                          /* OS_UNIX */
04589 
04590 #ifdef OS_WINNT
04591 
04592    status = SetTapePosition((HANDLE) channel, TAPE_SPACE_FILEMARKS, 0,
04593                             (DWORD) count, 0, FALSE);
04594 
04595    if (status == ERROR_END_OF_MEDIA)
04596       return SS_END_OF_TAPE;
04597 
04598    if (status != NO_ERROR) {
04599       cm_msg(MERROR, "ss_tape_fskip", "error %d", status);
04600       return status;
04601    }
04602 #endif                          /* OS_WINNT */
04603 
04604    return SS_SUCCESS;
04605 }
04606 
04607 /*------------------------------------------------------------------*/
04608 INT ss_tape_rskip(INT channel, INT count)
04609 /********************************************************************\
04610 
04611   Routine: ss_tape_rskip
04612 
04613   Purpose: Skip count number of records on a tape
04614 
04615   Input:
04616     INT   *channel          Channel identifier
04617     INT   count             Number of records to skip
04618 
04619   Output:
04620     <none>
04621 
04622   Function value:
04623     SS_SUCCESS              Successful completion
04624     errno                   Error number
04625 
04626 \********************************************************************/
04627 {
04628    INT status;
04629 
04630 #ifdef OS_UNIX
04631    struct mtop arg;
04632 
04633    if (count > 0)
04634       arg.mt_op = MTFSR;
04635    else
04636       arg.mt_op = MTBSR;
04637    arg.mt_count = abs(count);
04638 
04639    cm_enable_watchdog(FALSE);
04640 
04641    status = ioctl(channel, MTIOCTOP, &arg);
04642 
04643    cm_enable_watchdog(TRUE);
04644 
04645    if (status < 0) {
04646       cm_msg(MERROR, "ss_tape_rskip", strerror(errno));
04647       return errno;
04648    }
04649 #endif                          /* OS_UNIX */
04650 
04651 #ifdef OS_WINNT
04652 
04653    status =
04654        SetTapePosition((HANDLE) channel, TAPE_SPACE_RELATIVE_BLOCKS, 0,
04655                        (DWORD) count, 0, FALSE);
04656    if (status != NO_ERROR) {
04657       cm_msg(MERROR, "ss_tape_rskip", "error %d", status);
04658       return status;
04659    }
04660 #endif                          /* OS_WINNT */
04661 
04662    return CM_SUCCESS;
04663 }
04664 
04665 /*------------------------------------------------------------------*/
04666 INT ss_tape_rewind(INT channel)
04667 /********************************************************************\
04668 
04669   Routine: ss_tape_rewind
04670 
04671   Purpose: Rewind tape
04672 
04673   Input:
04674     INT   channel           Channel identifier
04675 
04676   Output:
04677     <none>
04678 
04679   Function value:
04680     SS_SUCCESS              Successful completion
04681     errno                   Error number
04682 
04683 \********************************************************************/
04684 {
04685    INT status;
04686 
04687 #ifdef OS_UNIX
04688    struct mtop arg;
04689 
04690    arg.mt_op = MTREW;
04691    arg.mt_count = 0;
04692 
04693    cm_enable_watchdog(FALSE);
04694 
04695    status = ioctl(channel, MTIOCTOP, &arg);
04696 
04697    cm_enable_watchdog(TRUE);
04698 
04699    if (status < 0) {
04700       cm_msg(MERROR, "ss_tape_rewind", strerror(errno));
04701       return errno;
04702    }
04703 #endif                          /* OS_UNIX */
04704 
04705 #ifdef OS_WINNT
04706 
04707    status = SetTapePosition((HANDLE) channel, TAPE_REWIND, 0, 0, 0, FALSE);
04708    if (status != NO_ERROR) {
04709       cm_msg(MERROR, "ss_tape_rewind", "error %d", status);
04710       return status;
04711    }
04712 #endif                          /* OS_WINNT */
04713 
04714    return CM_SUCCESS;
04715 }
04716 
04717 /*------------------------------------------------------------------*/
04718 INT ss_tape_spool(INT channel)
04719 /********************************************************************\
04720 
04721   Routine: ss_tape_spool
04722 
04723   Purpose: Spool tape forward to end of recorded data
04724 
04725   Input:
04726     INT   channel           Channel identifier
04727 
04728   Output:
04729     <none>
04730 
04731   Function value:
04732     SS_SUCCESS              Successful completion
04733     errno                   Error number
04734 
04735 \********************************************************************/
04736 {
04737    INT status;
04738 
04739 #ifdef OS_UNIX
04740    struct mtop arg;
04741 
04742 #ifdef MTEOM
04743    arg.mt_op = MTEOM;
04744 #else
04745    arg.mt_op = MTSEOD;
04746 #endif
04747    arg.mt_count = 0;
04748 
04749    cm_enable_watchdog(FALSE);
04750 
04751    status = ioctl(channel, MTIOCTOP, &arg);
04752 
04753    cm_enable_watchdog(TRUE);
04754 
04755    if (status < 0) {
04756       cm_msg(MERROR, "ss_tape_rewind", strerror(errno));
04757       return errno;
04758    }
04759 #endif                          /* OS_UNIX */
04760 
04761 #ifdef OS_WINNT
04762 
04763    status = SetTapePosition((HANDLE) channel, TAPE_SPACE_END_OF_DATA, 0, 0, 0, FALSE);
04764    if (status != NO_ERROR) {
04765       cm_msg(MERROR, "ss_tape_spool", "error %d", status);
04766       return status;
04767    }
04768 #endif                          /* OS_WINNT */
04769 
04770    return CM_SUCCESS;
04771 }
04772 
04773 /*------------------------------------------------------------------*/
04774 INT ss_tape_mount(INT channel)
04775 /********************************************************************\
04776 
04777   Routine: ss_tape_mount
04778 
04779   Purpose: Mount tape
04780 
04781   Input:
04782     INT   channel           Channel identifier
04783 
04784   Output:
04785     <none>
04786 
04787   Function value:
04788     SS_SUCCESS              Successful completion
04789     errno                   Error number
04790 
04791 \********************************************************************/
04792 {
04793    INT status;
04794 
04795 #ifdef OS_UNIX
04796    struct mtop arg;
04797 
04798 #ifdef MTLOAD
04799    arg.mt_op = MTLOAD;
04800 #else
04801    arg.mt_op = MTNOP;
04802 #endif
04803    arg.mt_count = 0;
04804 
04805    cm_enable_watchdog(FALSE);
04806 
04807    status = ioctl(channel, MTIOCTOP, &arg);
04808 
04809    cm_enable_watchdog(TRUE);
04810 
04811    if (status < 0) {
04812       cm_msg(MERROR, "ss_tape_mount", strerror(errno));
04813       return errno;
04814    }
04815 #endif                          /* OS_UNIX */
04816 
04817 #ifdef OS_WINNT
04818 
04819    status = PrepareTape((HANDLE) channel, TAPE_LOAD, FALSE);
04820    if (status != NO_ERROR) {
04821       cm_msg(MERROR, "ss_tape_mount", "error %d", status);
04822       return status;
04823    }
04824 #endif                          /* OS_WINNT */
04825 
04826    return CM_SUCCESS;
04827 }
04828 
04829 /*------------------------------------------------------------------*/
04830 INT ss_tape_unmount(INT channel)
04831 /********************************************************************\
04832 
04833   Routine: ss_tape_unmount
04834 
04835   Purpose: Unmount tape
04836 
04837   Input:
04838     INT   channel           Channel identifier
04839 
04840   Output:
04841     <none>
04842 
04843   Function value:
04844     SS_SUCCESS              Successful completion
04845     errno                   Error number
04846 
04847 \********************************************************************/
04848 {
04849    INT status;
04850 
04851 #ifdef OS_UNIX
04852    struct mtop arg;
04853 
04854 #ifdef MTOFFL
04855    arg.mt_op = MTOFFL;
04856 #else
04857    arg.mt_op = MTUNLOAD;
04858 #endif
04859    arg.mt_count = 0;
04860 
04861    cm_enable_watchdog(FALSE);
04862 
04863    status = ioctl(channel, MTIOCTOP, &arg);
04864 
04865    cm_enable_watchdog(TRUE);
04866 
04867    if (status < 0) {
04868       cm_msg(MERROR, "ss_tape_unmount", strerror(errno));
04869       return errno;
04870    }
04871 #endif                          /* OS_UNIX */
04872 
04873 #ifdef OS_WINNT
04874 
04875    status = PrepareTape((HANDLE) channel, TAPE_UNLOAD, FALSE);
04876    if (status != NO_ERROR) {
04877       cm_msg(MERROR, "ss_tape_unmount", "error %d", status);
04878       return status;
04879    }
04880 #endif                          /* OS_WINNT */
04881 
04882    return CM_SUCCESS;
04883 }
04884 
04885 /*------------------------------------------------------------------*/
04886 INT ss_tape_get_blockn(INT channel)
04887 /********************************************************************\
04888 Routine: ss_tape_get_blockn
04889 Purpose: Ask the tape channel for the present block number
04890 Input:
04891 INT   *channel          Channel identifier
04892 Function value:
04893 blockn:  >0 = block number, =0 option not available, <0 errno
04894 \********************************************************************/
04895 {
04896 #if defined(OS_DARWIN)
04897 
04898    return 0;
04899 
04900 #elif defined(OS_UNIX)
04901 
04902    INT status;
04903    struct mtpos arg;
04904 
04905    cm_enable_watchdog(FALSE);
04906    status = ioctl(channel, MTIOCPOS, &arg);
04907    cm_enable_watchdog(TRUE);
04908    if (status < 0) {
04909       if (errno == EIO)
04910          return 0;
04911       else {
04912          cm_msg(MERROR, "ss_tape_get_blockn", strerror(errno));
04913          return -errno;
04914       }
04915    }
04916    return (arg.mt_blkno);
04917 
04918 #elif defined(OS_WINNT)
04919 
04920    INT status;
04921    TAPE_GET_MEDIA_PARAMETERS media;
04922    unsigned long size;
04923    /* I'm not sure the partition count corresponds to the block count */
04924    status =
04925        GetTapeParameters((HANDLE) channel, GET_TAPE_MEDIA_INFORMATION, &size, &media);
04926    return (media.PartitionCount);
04927 
04928 #endif
04929 }
04930 
04931 
04932 /*------------------------------------------------------------------*/
04933 /********************************************************************\
04934 *                                                                    *
04935 *                     Disk functions                                 *
04936 *                                                                    *
04937 \********************************************************************/
04938 
04939 /*------------------------------------------------------------------*/
04940 double ss_disk_free(char *path)
04941 /********************************************************************\
04942 
04943   Routine: ss_disk_free
04944 
04945   Purpose: Return free disk space
04946 
04947   Input:
04948     char  *path             Name of a file in file system to check
04949 
04950   Output:
04951 
04952   Function value:
04953     doube                   Number of bytes free on disk
04954 
04955 \********************************************************************/
04956 {
04957 #ifdef OS_UNIX
04958 #if defined(OS_OSF1)
04959    struct statfs st;
04960    statfs(path, &st, sizeof(st));
04961    return (double) st.f_bavail * st.f_bsize;
04962 #elif defined(OS_LINUX)
04963    struct statfs st;
04964    statfs(path, &st);
04965    return (double) st.f_bavail * st.f_bsize;
04966 #elif defined(OS_SOLARIS)
04967    struct statvfs st;
04968    statvfs(path, &st);
04969    return (double) st.f_bavail * st.f_bsize;
04970 #elif defined(OS_IRIX)
04971    struct statfs st;
04972    statfs(path, &st, sizeof(struct statfs), 0);
04973    return (double) st.f_bfree * st.f_bsize;
04974 #else
04975    struct fs_data st;
04976    statfs(path, &st);
04977    return (double) st.fd_otsize * st.fd_bfree;
04978 #endif
04979 
04980 #elif defined(OS_WINNT)         /* OS_UNIX */
04981    DWORD SectorsPerCluster;
04982    DWORD BytesPerSector;
04983    DWORD NumberOfFreeClusters;
04984    DWORD TotalNumberOfClusters;
04985    char str[80];
04986 
04987    strcpy(str, path);
04988    if (strchr(str, ':') != NULL) {
04989       *(strchr(str, ':') + 1) = 0;
04990       strcat(str, DIR_SEPARATOR_STR);
04991       GetDiskFreeSpace(str, &SectorsPerCluster, &BytesPerSector,
04992                        &NumberOfFreeClusters, &TotalNumberOfClusters);
04993    } else
04994       GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector,
04995                        &NumberOfFreeClusters, &TotalNumberOfClusters);
04996 
04997    return (double) NumberOfFreeClusters *SectorsPerCluster * BytesPerSector;
04998 #else                           /* OS_WINNT */
04999 
05000    return 1e9;
05001 
05002 #endif
05003 }
05004 
05005 #if defined(OS_ULTRIX) || defined(OS_WINNT)
05006 int fnmatch(const char *pat, const char *str, const int flag)
05007 {
05008    while (*str != '\0') {
05009       if (*pat == '*') {
05010          pat++;
05011          if ((str = strchr(str, *pat)) == NULL)
05012             return -1;
05013       }
05014       if (*pat == *str) {
05015          pat++;
05016          str++;
05017       } else
05018          return -1;
05019    }
05020    if (*pat == '\0')
05021       return 0;
05022    else
05023       return -1;
05024 }
05025 #endif
05026 
05027 #ifdef OS_WINNT
05028 HANDLE pffile;
05029 LPWIN32_FIND_DATA lpfdata;
05030 #endif
05031 INT ss_file_find(char *path, char *pattern, char **plist)
05032 /********************************************************************\
05033 
05034   Routine: ss_file_find
05035 
05036   Purpose: Return list of files matching 'pattern' from the 'path' location
05037 
05038   Input:
05039     char  *path             Name of a file in file system to check
05040     char  *pattern          pattern string (wildcard allowed)
05041 
05042   Output:
05043     char  **plist           pointer to the lfile list
05044 
05045   Function value:
05046     int                     Number of files matching request
05047 
05048 \********************************************************************/
05049 {
05050    int i;
05051 #ifdef OS_UNIX
05052    DIR *dir_pointer;
05053    struct dirent *dp;
05054 
05055    if ((dir_pointer = opendir(path)) == NULL)
05056       return 0;
05057    *plist = (char *) malloc(MAX_STRING_LENGTH);
05058    i = 0;
05059    for (dp = readdir(dir_pointer); dp != NULL; dp = readdir(dir_pointer)) {
05060       if (fnmatch(pattern, dp->d_name, 0) == 0) {
05061          *plist = (char *) realloc(*plist, (i + 1) * MAX_STRING_LENGTH);
05062          strncpy(*plist + (i * MAX_STRING_LENGTH), dp->d_name, strlen(dp->d_name));
05063          *(*plist + (i * MAX_STRING_LENGTH) + strlen(dp->d_name)) = '\0';
05064          i++;
05065          seekdir(dir_pointer, telldir(dir_pointer));
05066       }
05067    }
05068    closedir(dir_pointer);
05069 #endif
05070 #ifdef OS_WINNT
05071    char str[255];
05072    int first;
05073 
05074    strcpy(str, path);
05075    strcat(str, "\\");
05076    strcat(str, pattern);
05077    first = 1;
05078    i = 0;
05079    lpfdata = (WIN32_FIND_DATA *) malloc(sizeof(WIN32_FIND_DATA));
05080    *plist = (char *) malloc(MAX_STRING_LENGTH);
05081    pffile = FindFirstFile(str, lpfdata);
05082    if (pffile == INVALID_HANDLE_VALUE)
05083       return 0;
05084    first = 0;
05085    *plist = (char *) realloc(*plist, (i + 1) * MAX_STRING_LENGTH);
05086    strncpy(*plist + (i * MAX_STRING_LENGTH), lpfdata->cFileName,
05087            strlen(lpfdata->cFileName));
05088    *(*plist + (i * MAX_STRING_LENGTH) + strlen(lpfdata->cFileName)) = '\0';
05089    i++;
05090    while (FindNextFile(pffile, lpfdata)) {
05091       *plist = (char *) realloc(*plist, (i + 1) * MAX_STRING_LENGTH);
05092       strncpy(*plist + (i * MAX_STRING_LENGTH), lpfdata->cFileName,
05093               strlen(lpfdata->cFileName));
05094       *(*plist + (i * MAX_STRING_LENGTH) + strlen(lpfdata->cFileName)) = '\0';
05095       i++;
05096    }
05097    free(lpfdata);
05098 #endif
05099    return i;
05100 }
05101 
05102 INT ss_file_remove(char *path)
05103 /********************************************************************\
05104 
05105   Routine: ss_file_remove
05106 
05107   Purpose: remove (delete) file given through the path
05108 
05109   Input:
05110     char  *path             Name of a file in file system to check
05111 
05112   Output:
05113 
05114   Function value:
05115     int                     function error 0= ok, -1 check errno
05116 
05117 \********************************************************************/
05118 {
05119    return remove(path);
05120 }
05121 
05122 double ss_file_size(char *path)
05123 /********************************************************************\
05124 
05125   Routine: ss_file_size
05126 
05127   Purpose: Return file size in bytes for the given path
05128 
05129   Input:
05130     char  *path             Name of a file in file system to check
05131 
05132   Output:
05133 
05134   Function value:
05135     double                     File size
05136 
05137 \********************************************************************/
05138 {
05139    struct stat stat_buf;
05140 
05141    /* allocate buffer with file size */
05142    stat(path, &stat_buf);
05143    return (double) stat_buf.st_size;
05144 }
05145 
05146 double ss_disk_size(char *path)
05147 /********************************************************************\
05148 
05149   Routine: ss_disk_size
05150 
05151   Purpose: Return full disk space
05152 
05153   Input:
05154     char  *path             Name of a file in file system to check
05155 
05156   Output:
05157 
05158   Function value:
05159     doube                   Number of bytes free on disk
05160 
05161 \********************************************************************/
05162 {
05163 #ifdef OS_UNIX
05164 #if defined(OS_OSF1)
05165    struct statfs st;
05166    statfs(path, &st, sizeof(st));
05167    return (double) st.f_blocks * st.f_fsize;
05168 #elif defined(OS_LINUX)
05169    struct statfs st;
05170    statfs(path, &st);
05171    return (double) st.f_blocks * st.f_bsize;
05172 #elif defined(OS_SOLARIS)
05173    struct statvfs st;
05174    statvfs(path, &st);
05175    if (st.f_frsize > 0)
05176       return (double) st.f_blocks * st.f_frsize;
05177    else
05178       return (double) st.f_blocks * st.f_bsize;
05179 #elif defined(OS_ULTRIX)
05180    struct fs_data st;
05181    statfs(path, &st);
05182    return (double) st.fd_btot * 1024;
05183 #elif defined(OS_IRIX)
05184    struct statfs st;
05185    statfs(path, &st, sizeof(struct statfs), 0);
05186    return (double) st.f_blocks * st.f_bsize;
05187 #else
05188 #error ss_disk_size not defined for this OS
05189 #endif
05190 #endif                          /* OS_UNIX */
05191 
05192 #ifdef OS_WINNT
05193    DWORD SectorsPerCluster;
05194    DWORD BytesPerSector;
05195    DWORD NumberOfFreeClusters;
05196    DWORD TotalNumberOfClusters;
05197    char str[80];
05198 
05199    strcpy(str, path);
05200    if (strchr(str, ':') != NULL) {
05201       *(strchr(str, ':') + 1) = 0;
05202       strcat(str, DIR_SEPARATOR_STR);
05203       GetDiskFreeSpace(str, &SectorsPerCluster, &BytesPerSector,
05204                        &NumberOfFreeClusters, &TotalNumberOfClusters);
05205    } else
05206       GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector,
05207                        &NumberOfFreeClusters, &TotalNumberOfClusters);
05208 
05209    return (double) TotalNumberOfClusters *SectorsPerCluster * BytesPerSector;
05210 #endif                          /* OS_WINNT */
05211 
05212    return 1e9;
05213 }
05214 
05215 /*------------------------------------------------------------------*/
05216 /********************************************************************\
05217 *                                                                    *
05218 *                  Screen  functions                                 *
05219 *                                                                    *
05220 \********************************************************************/
05221 
05222 /*------------------------------------------------------------------*/
05223 void ss_clear_screen()
05224 /********************************************************************\
05225 
05226   Routine: ss_clear_screen
05227 
05228   Purpose: Clear the screen
05229 
05230   Input:
05231     <none>
05232 
05233   Output:
05234     <none>
05235 
05236   Function value:
05237     <none>
05238 
05239 \********************************************************************/
05240 {
05241 #ifdef OS_WINNT
05242 
05243    HANDLE hConsole;
05244    COORD coordScreen = { 0, 0 };        /* here's where we'll home the cursor */
05245    BOOL bSuccess;
05246    DWORD cCharsWritten;
05247    CONSOLE_SCREEN_BUFFER_INFO csbi;     /* to get buffer info */
05248    DWORD dwConSize;             /* number of character cells in the current buffer */
05249 
05250    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
05251 
05252    /* get the number of character cells in the current buffer */
05253    bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
05254    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
05255 
05256    /* fill the entire screen with blanks */
05257    bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR) ' ',
05258                                          dwConSize, coordScreen, &cCharsWritten);
05259 
05260    /* put the cursor at (0, 0) */
05261    bSuccess = SetConsoleCursorPosition(hConsole, coordScreen);
05262    return;
05263 
05264 #endif                          /* OS_WINNT */
05265 #if defined(OS_UNIX) || defined(OS_VXWORKS) || defined(OS_VMS)
05266    printf("\033[2J");
05267 #endif
05268 #ifdef OS_MSDOS
05269    clrscr();
05270 #endif
05271 }
05272 
05273 /*------------------------------------------------------------------*/
05274 void ss_set_screen_size(int x, int y)
05275 /********************************************************************\
05276 
05277   Routine: ss_set_screen_size
05278 
05279   Purpose: Set the screen size in character cells
05280 
05281   Input:
05282     <none>
05283 
05284   Output:
05285     <none>
05286 
05287   Function value:
05288     <none>
05289 
05290 \********************************************************************/
05291 {
05292 #ifdef OS_WINNT
05293 
05294    HANDLE hConsole;
05295    COORD coordSize;
05296 
05297    coordSize.X = (short) x;
05298    coordSize.Y = (short) y;
05299    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
05300    SetConsoleScreenBufferSize(hConsole, coordSize);
05301 
05302 #endif                          /* OS_WINNT */
05303 }
05304 
05305 /*------------------------------------------------------------------*/
05306 void ss_printf(INT x, INT y, const char *format, ...)
05307 /********************************************************************\
05308 
05309   Routine: ss_printf
05310 
05311   Purpose: Print string at given cursor position
05312 
05313   Input:
05314     INT   x,y               Cursor position, starting from zero,
05315           x=0 and y=0 left upper corner
05316 
05317     char  *format           Format string for printf
05318     ...                     Arguments for printf
05319 
05320   Output:
05321     <none>
05322 
05323   Function value:
05324     <none>
05325 
05326 \********************************************************************/
05327 {
05328    char str[256];
05329    va_list argptr;
05330 
05331    va_start(argptr, format);
05332    vsprintf(str, (char *) format, argptr);
05333    va_end(argptr);
05334 
05335 #ifdef OS_WINNT
05336    {
05337       HANDLE hConsole;
05338       COORD dwWriteCoord;
05339       DWORD cCharsWritten;
05340 
05341       hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
05342 
05343       dwWriteCoord.X = (short) x;
05344       dwWriteCoord.Y = (short) y;
05345 
05346       WriteConsoleOutputCharacter(hConsole, str, strlen(str),
05347                                   dwWriteCoord, &cCharsWritten);
05348    }
05349 
05350 #endif                          /* OS_WINNT */
05351 
05352 #if defined(OS_UNIX) || defined(OS_VXWORKS) || defined(OS_VMS)
05353    printf("\033[%1d;%1d;H", y + 1, x + 1);
05354    printf(str);
05355    fflush(stdout);
05356 #endif
05357 
05358 #ifdef OS_MSDOS
05359    gotoxy(x + 1, y + 1);
05360    cputs(str);
05361 #endif
05362 }
05363 
05364 /*------------------------------------------------------------------*/
05365 char *ss_getpass(char *prompt)
05366 /********************************************************************\
05367 
05368   Routine: ss_getpass
05369 
05370   Purpose: Read password without echoing it at the screen
05371 
05372   Input:
05373     char   *prompt    Prompt string
05374 
05375   Output:
05376     <none>
05377 
05378   Function value:
05379     char*             Pointer to password
05380 
05381 \********************************************************************/
05382 {
05383    static char password[32];
05384 
05385    printf(prompt);
05386    memset(password, 0, sizeof(password));
05387 
05388 #ifdef OS_UNIX
05389    return (char *) getpass("");
05390 #elif defined(OS_WINNT)
05391    {
05392       HANDLE hConsole;
05393       DWORD nCharsRead;
05394 
05395       hConsole = GetStdHandle(STD_INPUT_HANDLE);
05396       SetConsoleMode(hConsole, ENABLE_LINE_INPUT);
05397       ReadConsole(hConsole, password, sizeof(password), &nCharsRead, NULL);
05398       SetConsoleMode(hConsole, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT |
05399                      ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
05400       printf("\n");
05401 
05402       if (password[strlen(password) - 1] == '\r')
05403          password[strlen(password) - 1] = 0;
05404 
05405       return password;
05406    }
05407 #elif defined(OS_MSDOS)
05408    {
05409       char c, *ptr;
05410 
05411       ptr = password;
05412       while ((c = getchar()) != EOF && c != '\n')
05413          *ptr++ = c;
05414       *ptr = 0;
05415 
05416       printf("\n");
05417       return password;
05418    }
05419 #else
05420    {
05421       ss_gets(password, 32);
05422       return password;
05423    }
05424 #endif
05425 }
05426 
05427 /*------------------------------------------------------------------*/
05428 INT ss_getchar(BOOL reset)
05429 /********************************************************************\
05430 
05431   Routine: ss_getchar
05432 
05433   Purpose: Read a single character
05434 
05435   Input:
05436     BOOL   reset            Reset terminal to standard mode
05437 
05438   Output:
05439     <none>
05440 
05441   Function value:
05442     int             0       for no character available
05443                     CH_xxs  for special character
05444                     n       ASCII code for normal character
05445                     -1      function not available on this OS
05446 
05447 \********************************************************************/
05448 {
05449 #ifdef OS_UNIX
05450 
05451    static BOOL init = FALSE;
05452    static struct termios save_termios;
05453    struct termios buf;
05454    int i, fd;
05455    char c[3];
05456 
05457    if (_daemon_flag)
05458       return 0;
05459 
05460    fd = fileno(stdin);
05461 
05462    if (reset) {
05463       if (init)
05464          tcsetattr(fd, TCSAFLUSH, &save_termios);
05465       init = FALSE;
05466       return 0;
05467    }
05468 
05469    if (!init) {
05470       tcgetattr(fd, &save_termios);
05471       memcpy(&buf, &save_termios, sizeof(buf));
05472 
05473       buf.c_lflag &= ~(ECHO | ICANON | IEXTEN);
05474 
05475       buf.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON);
05476 
05477       buf.c_cflag &= ~(CSIZE | PARENB);
05478       buf.c_cflag |= CS8;
05479       /* buf.c_oflag &= ~(OPOST); */
05480       buf.c_cc[VMIN] = 0;
05481       buf.c_cc[VTIME] = 0;
05482 
05483       tcsetattr(fd, TCSAFLUSH, &buf);
05484       init = TRUE;
05485    }
05486 
05487    memset(c, 0, 3);
05488    i = read(fd, c, 1);
05489 
05490    if (i == 0)
05491       return 0;
05492 
05493    /* check if ESC */
05494    if (c[0] == 27) {
05495       i = read(fd, c, 2);
05496       if (i == 0)               /* return if only ESC */
05497          return 27;
05498 
05499       /* cursor keys return 2 chars, others 3 chars */
05500       if (c[1] < 65)
05501          read(fd, c, 1);
05502 
05503       /* convert ESC sequence to CH_xxx */
05504       switch (c[1]) {
05505       case 49:
05506          return CH_HOME;
05507       case 50:
05508          return CH_INSERT;
05509       case 51:
05510          return CH_DELETE;
05511       case 52:
05512          return CH_END;
05513       case 53:
05514          return CH_PUP;
05515       case 54:
05516          return CH_PDOWN;
05517       case 65:
05518          return CH_UP;
05519       case 66:
05520          return CH_DOWN;
05521       case 67:
05522          return CH_RIGHT;
05523       case 68:
05524          return CH_LEFT;
05525       }
05526    }
05527 
05528    /* BS/DEL -> BS */
05529    if (c[0] == 127)
05530       return CH_BS;
05531 
05532    return c[0];
05533 
05534 #elif defined(OS_WINNT)
05535 
05536    static BOOL init = FALSE;
05537    static INT repeat_count = 0;
05538    static INT repeat_char;
05539    HANDLE hConsole;
05540    DWORD nCharsRead;
05541    INPUT_RECORD ir;
05542    OSVERSIONINFO vi;
05543 
05544    /* find out if we are under W95 */
05545    vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
05546    GetVersionEx(&vi);
05547 
05548    if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
05549       /* under W95, console doesn't work properly */
05550       int c;
05551 
05552       if (!kbhit())
05553          return 0;
05554 
05555       c = getch();
05556       if (c == 224) {
05557          c = getch();
05558          switch (c) {
05559          case 71:
05560             return CH_HOME;
05561          case 72:
05562             return CH_UP;
05563          case 73:
05564             return CH_PUP;
05565          case 75:
05566             return CH_LEFT;
05567          case 77:
05568             return CH_RIGHT;
05569          case 79:
05570             return CH_END;
05571          case 80:
05572             return CH_DOWN;
05573          case 81:
05574             return CH_PDOWN;
05575          case 82:
05576             return CH_INSERT;
05577          case 83:
05578             return CH_DELETE;
05579          }
05580       }
05581       return c;
05582    }
05583 
05584    hConsole = GetStdHandle(STD_INPUT_HANDLE);
05585 
05586    if (reset) {
05587       SetConsoleMode(hConsole, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT |
05588                      ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
05589       init = FALSE;
05590       return 0;
05591    }
05592 
05593    if (!init) {
05594       SetConsoleMode(hConsole, ENABLE_PROCESSED_INPUT);
05595       init = TRUE;
05596    }
05597 
05598    if (repeat_count) {
05599       repeat_count--;
05600       return repeat_char;
05601    }
05602 
05603    PeekConsoleInput(hConsole, &ir, 1, &nCharsRead);
05604 
05605    if (nCharsRead == 0)
05606       return 0;
05607 
05608    ReadConsoleInput(hConsole, &ir, 1, &nCharsRead);
05609 
05610    if (ir.EventType != KEY_EVENT)
05611       return ss_getchar(0);
05612 
05613    if (!ir.Event.KeyEvent.bKeyDown)
05614       return ss_getchar(0);
05615 
05616    if (ir.Event.KeyEvent.wRepeatCount > 1) {
05617       repeat_count = ir.Event.KeyEvent.wRepeatCount - 1;
05618       repeat_char = ir.Event.KeyEvent.uChar.AsciiChar;
05619       return repeat_char;
05620    }
05621 
05622    if (ir.Event.KeyEvent.uChar.AsciiChar)
05623       return ir.Event.KeyEvent.uChar.AsciiChar;
05624 
05625    if (ir.Event.KeyEvent.dwControlKeyState & (ENHANCED_KEY)) {
05626       switch (ir.Event.KeyEvent.wVirtualKeyCode) {
05627       case 33:
05628          return CH_PUP;
05629       case 34:
05630          return CH_PDOWN;
05631       case 35:
05632          return CH_END;
05633       case 36:
05634          return CH_HOME;
05635       case 37:
05636          return CH_LEFT;
05637       case 38:
05638          return CH_UP;
05639       case 39:
05640          return CH_RIGHT;
05641       case 40:
05642          return CH_DOWN;
05643       case 45:
05644          return CH_INSERT;
05645       case 46:
05646          return CH_DELETE;
05647       }
05648 
05649       return ir.Event.KeyEvent.wVirtualKeyCode;
05650    }
05651 
05652    return ss_getchar(0);
05653 
05654 #elif defined(OS_MSDOS)
05655 
05656    int c;
05657 
05658    if (!kbhit())
05659       return 0;
05660 
05661    c = getch();
05662    if (!c) {
05663       c = getch();
05664       switch (c) {
05665       case 71:
05666          return CH_HOME;
05667       case 72:
05668          return CH_UP;
05669       case 73:
05670          return CH_PUP;
05671       case 75:
05672          return CH_LEFT;
05673       case 77:
05674          return CH_RIGHT;
05675       case 79:
05676          return CH_END;
05677       case 80:
05678          return CH_DOWN;
05679       case 81:
05680          return CH_PDOWN;
05681       case 82:
05682          return CH_INSERT;
05683       case 83:
05684          return CH_DELETE;
05685       }
05686    }
05687    return c;
05688 
05689 #else
05690    return -1;
05691 #endif
05692 }
05693 
05694 /*------------------------------------------------------------------*/
05695 char *ss_gets(char *string, int size)
05696 /********************************************************************\
05697 
05698   Routine: ss_gets
05699 
05700   Purpose: Read a line from standard input. Strip trailing new line
05701            character. Return in a loop so that it cannot be interrupted
05702            by an alarm() signal (like under Sun Solaris)
05703 
05704   Input:
05705     INT    size             Size of string
05706 
05707   Output:
05708     BOOL   string           Return string
05709 
05710   Function value:
05711     char                    Return string
05712 
05713 \********************************************************************/
05714 {
05715    char *p;
05716 
05717    do {
05718       p = fgets(string, size, stdin);
05719    } while (p == NULL);
05720 
05721 
05722    if (strlen(p) > 0 && p[strlen(p) - 1] == '\n')
05723       p[strlen(p) - 1] = 0;
05724 
05725    return p;
05726 }
05727 
05728 /*------------------------------------------------------------------*/
05729 /********************************************************************\
05730 *                                                                    *
05731 *                  Direct IO functions                               *
05732 *                                                                    *
05733 \********************************************************************/
05734 
05735 /*------------------------------------------------------------------*/
05736 INT ss_directio_give_port(INT start, INT end)
05737 {
05738 #ifdef OS_WINNT
05739 
05740    /* under Windows NT, use DirectIO driver to open ports */
05741 
05742    OSVERSIONINFO vi;
05743    HANDLE hdio = 0;
05744    DWORD buffer[] = { 6, 0, 0, 0 };
05745    DWORD size;
05746 
05747    vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
05748    GetVersionEx(&vi);
05749 
05750    /* use DirectIO driver under NT to gain port access */
05751    if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
05752       hdio =
05753           CreateFile("\\\\.\\directio", GENERIC_READ, FILE_SHARE_READ,
05754                      NULL, OPEN_EXISTING, 0, NULL);
05755       if (hdio == INVALID_HANDLE_VALUE) {
05756          printf("hyt1331.c: Cannot access IO ports (No DirectIO driver installed)\n");
05757          return -1;
05758       }
05759 
05760       /* open ports */
05761       buffer[1] = start;
05762       buffer[2] = end;
05763       if (!DeviceIoControl
05764           (hdio, (DWORD) 0x9c406000, &buffer, sizeof(buffer), NULL, 0, &size, NULL))
05765          return -1;
05766    }
05767 
05768    return SS_SUCCESS;
05769 #else
05770    return SS_SUCCESS;
05771 #endif
05772 }
05773 
05774 /*------------------------------------------------------------------*/
05775 INT ss_directio_lock_port(INT start, INT end)
05776 {
05777 #ifdef OS_WINNT
05778 
05779    /* under Windows NT, use DirectIO driver to lock ports */
05780 
05781    OSVERSIONINFO vi;
05782    HANDLE hdio;
05783    DWORD buffer[] = { 7, 0, 0, 0 };
05784    DWORD size;
05785 
05786    vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
05787    GetVersionEx(&vi);
05788 
05789    /* use DirectIO driver under NT to gain port access */
05790    if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
05791       hdio =
05792           CreateFile("\\\\.\\directio", GENERIC_READ, FILE_SHARE_READ,
05793                      NULL, OPEN_EXISTING, 0, NULL);
05794       if (hdio == INVALID_HANDLE_VALUE) {
05795          printf("hyt1331.c: Cannot access IO ports (No DirectIO driver installed)\n");
05796          return -1;
05797       }
05798 
05799       /* lock ports */
05800       buffer[1] = start;
05801       buffer[2] = end;
05802       if (!DeviceIoControl
05803           (hdio, (DWORD) 0x9c406000, &buffer, sizeof(buffer), NULL, 0, &size, NULL))
05804          return -1;
05805    }
05806 
05807    return SS_SUCCESS;
05808 #else
05809    return SS_SUCCESS;
05810 #endif
05811 }
05812 
05813 /*------------------------------------------------------------------*/
05814 /********************************************************************\
05815 *                                                                    *
05816 *                  System logging                                    *
05817 *                                                                    *
05818 \********************************************************************/
05819 
05820 /*------------------------------------------------------------------*/
05821 INT ss_syslog(const char *message)
05822 /********************************************************************\
05823 
05824   Routine: ss_syslog
05825 
05826   Purpose: Write a message to the system logging facility
05827 
05828   Input:
05829     char   format  Same as for printf
05830 
05831   Output:
05832     <none>
05833 
05834   Function value:
05835     SS_SUCCESS     Successful completion
05836 
05837 \********************************************************************/
05838 {
05839 #ifdef OS_UNIX
05840    static BOOL init = FALSE;
05841 
05842    if (!init) {
05843 #ifdef OS_ULTRIX
05844       openlog("MIDAS", LOG_PID);
05845 #else
05846       openlog("MIDAS", LOG_PID, LOG_USER);
05847 #endif
05848       init = TRUE;
05849    }
05850 
05851    syslog(LOG_DEBUG, message);
05852    return SS_SUCCESS;
05853 #elif defined(OS_WINNT)         /* OS_UNIX */
05854 /*
05855 HANDLE hlog = 0;
05856 const char *pstr[2];
05857 
05858   if (!hlog)
05859     {
05860     HKEY  hk;
05861     DWORD d;
05862     char  str[80];
05863 
05864     RegCreateKey(HKEY_LOCAL_MACHINE,
05865       "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Midas", &hk);
05866 
05867     strcpy(str, (char *) rpc_get_server_option(RPC_OSERVER_NAME));
05868     RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) str, strlen(str) + 1);
05869 
05870     d = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
05871         EVENTLOG_INFORMATION_TYPE;
05872     RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) &d, sizeof(DWORD));
05873     RegCloseKey(hk);
05874 
05875     hlog = RegisterEventSource(NULL, "Midas");
05876     }
05877 
05878   pstr[0] = message;
05879   pstr[1] = NULL;
05880 
05881   if (hlog)
05882     ReportEvent(hlog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, pstr, NULL);
05883 */
05884    return SS_SUCCESS;
05885 
05886 #else                           /* OS_WINNT */
05887 
05888    return SS_SUCCESS;
05889 
05890 #endif
05891 }
05892 
05893 /*------------------------------------------------------------------*/
05894 /********************************************************************\
05895 *                                                                    *
05896 *                  Encryption                                        *
05897 *                                                                    *
05898 \********************************************************************/
05899 
05900 #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
05901 
05902 char *ss_crypt(char *buf, char *salt)
05903 /********************************************************************\
05904 
05905   Routine: ss_crypt
05906 
05907   Purpose: Simple fake of UNIX crypt(3) function, until we get
05908            a better one
05909 
05910   Input:
05911     char   *buf             Plain password
05912     char   *slalt           Two random characters
05913                             events. Can be used to skip events
05914 
05915   Output:
05916     <none>
05917 
05918   Function value:
05919     char*                   Encrypted password
05920 
05921 \********************************************************************/
05922 {
05923    int i, seed;
05924    static char enc_pw[13];
05925 
05926    memset(enc_pw, 0, sizeof(enc_pw));
05927    enc_pw[0] = salt[0];
05928    enc_pw[1] = salt[1];
05929 
05930    for (i = 0; i < 8 && buf[i]; i++)
05931       enc_pw[i + 2] = buf[i];
05932    for (; i < 8; i++)
05933       enc_pw[i + 2] = 0;
05934 
05935    seed = 123;
05936    for (i = 2; i < 13; i++) {
05937       seed = 5 * seed + 27 + enc_pw[i];
05938       enc_pw[i] = (char) bin_to_ascii(seed & 0x3F);
05939    }
05940 
05941    return enc_pw;
05942 }
05943 
05944 /**dox***************************************************************/
05945 #endif                          /* DOXYGEN_SHOULD_SKIP_THIS */
05946 
05947 /** @} */ /* end of msfunctionc */
05948 /** @} */ /* end of msystemincludecode */
05949 

Midas DOC Version 1.9.3 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Suzannah Daviel - Doxygen - Peter Green - Greg Hackman - Gertjan Hofman - Paul Knowles - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk