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

Midas DOC Version 1.9.5 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - 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 - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk