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

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