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

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 - Konstantin Olchanski - Renee Poutissou - Andreas Suter - Piotr Adam Zolnierczuk