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

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