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

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