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

Midas DOC Version 2.0.2 ---- 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