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

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