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

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