static sg_error sg_get_user_stats_int(sg_vector **user_stats_vector_ptr) { size_t num_users = 0; sg_user_stats *user_ptr; time_t now = time(NULL); #if defined (WIN32) LPWKSTA_USER_INFO_0 buf = NULL; LPWKSTA_USER_INFO_0 tmp_buf; unsigned long entries_read = 0; unsigned long entries_tot = 0; unsigned long resumehandle = 0; NET_API_STATUS nStatus; int i; char name[256]; #undef VECTOR_UPDATE_ERROR_CLEANUP #define VECTOR_UPDATE_ERROR_CLEANUP if (buf != NULL) NetApiBufferFree(buf); do { nStatus = NetWkstaUserEnum(NULL, 0, (LPBYTE*)&buf, MAX_PREFERRED_LENGTH, &entries_read, &entries_tot, &resumehandle); if((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) { if((tmp_buf = buf) == NULL) continue; for( i = 0; i < entries_read; ++i ) { /* assert(tmp_buf != NULL); */ if( tmp_buf == NULL ) { sg_set_error(SG_ERROR_PERMISSION, "User list"); ERROR_LOG("user", "Permission denied fetching user details"); break; /* XXX break and not return? */ } /* It's in unicode. We are not. Convert */ WideCharToMultiByte(CP_ACP, 0, tmp_buf->wkui0_username, -1, name, sizeof(name), NULL, NULL); VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( SG_ERROR_NONE != sg_update_string( &user_ptr[num_users].login_name, name ) ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } user_ptr[num_users].systime = now; ++tmp_buf; ++num_users; } } else { RETURN_WITH_SET_ERROR("user", SG_ERROR_PERMISSION, "User enum"); } if (buf != NULL) { NetApiBufferFree(buf); buf=NULL; } } while (nStatus == ERROR_MORE_DATA); if (buf != NULL) NetApiBufferFree(buf); #elif defined(CAN_USE_UTMPX) || defined(CAN_USE_UTMP) #define SG_LUPDATE_IF(tgt,obj,memb) \ (((void *)(&(obj->memb))) == ((void *)(&(obj->memb[0])))) \ ? sg_lupdate_string(tgt, obj->memb, sizeof(obj->memb))\ : sg_update_string(tgt, obj->memb) #define UTMP_MUTEX_NAME "utmp" #undef VECTOR_UPDATE_ERROR_CLEANUP # if defined(CAN_USE_UTMPX) struct utmpx *utx; # endif # if defined(CAN_USE_UTMP) struct utmp *ut; # endif /* following block contains code for utmpx */ # if defined(CAN_USE_UTMPX) # ifdef ENABLE_THREADS # define VECTOR_UPDATE_ERROR_CLEANUP endutxent(); sg_unlock_mutex(UTMP_MUTEX_NAME); sg_lock_mutex(UTMP_MUTEX_NAME); # else # define VECTOR_UPDATE_ERROR_CLEANUP endutxent(); # endif setutxent(); while( NULL != (utx = getutxent()) ) { if( USER_PROCESS != utx->ut_type ) continue; VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, utx, ut_user ) ) || # if defined(HAVE_UTMPX_HOST) # if defined(HAVE_UTMPX_SYSLEN) ( SG_ERROR_NONE != sg_lupdate_string( &user_ptr[num_users].hostname, utx->ut_host, utx->ut_syslen + 1 ) ) || # else ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].hostname, utx, ut_host ) ) || # endif # endif ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].device, utx, ut_line ) ) || ( SG_ERROR_NONE != sg_update_mem( (void *)(&user_ptr[num_users].record_id), utx->ut_id, sizeof(utx->ut_id) ) ) ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } user_ptr[num_users].record_id_size = sizeof(utx->ut_id); user_ptr[num_users].pid = utx->ut_pid; user_ptr[num_users].login_time = utx->ut_tv.tv_sec; user_ptr[num_users].systime = now; ++num_users; } endutxent(); if(!num_users) { # endif /* following block contains code for utmp */ # if defined(CAN_USE_UTMP) # undef VECTOR_UPDATE_ERROR_CLEANUP # ifdef ENABLE_THREADS # define VECTOR_UPDATE_ERROR_CLEANUP endutent(); sg_unlock_mutex(UTMP_MUTEX_NAME); # else # define VECTOR_UPDATE_ERROR_CLEANUP endutent(); # endif setutent(); while( NULL != (ut = getutent()) ) { # ifdef HAVE_UTMP_TYPE if( USER_PROCESS != ut->ut_type ) continue; # elif defined(HAVE_UTMP_NAME) if (ut->ut_name[0] == '\0') continue; # elif defined(HAVE_UTMP_USER) if (ut->ut_user[0] == '\0') continue; # endif VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].device, ut, ut_line ) ) # if defined(HAVE_UTMP_USER) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, ut, ut_user ) ) # elif defined(HAVE_UTMP_NAME) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, ut, ut_name ) ) # endif # if defined(HAVE_UTMP_HOST) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].hostname, ut, ut_host ) ) # endif # if defined(HAVE_UTMP_ID) || ( SG_ERROR_NONE != sg_update_mem( (void **)(&user_ptr[num_users].record_id), ut->ut_id, sizeof(ut->ut_id) ) ) # endif ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } # if defined(HAVE_UTMP_ID) user_ptr[num_users].record_id_size = sizeof(ut->ut_id); # endif # if defined(HAVE_UTMP_PID) user_ptr[num_users].pid = ut->ut_pid; # endif #if defined(HAVE_UTMP_TIME) user_ptr[num_users].login_time = ut->ut_time; #endif user_ptr[num_users].systime = now; ++num_users; } endutent(); # endif # if defined(CAN_USE_UTMPX) } #endif # ifdef ENABLE_THREADS sg_unlock_mutex(UTMP_MUTEX_NAME); # endif #elif defined(HAVE_STRUCT_UTMP) && defined(_PATH_UTMP) struct utmp entry; FILE *f; if ((f=fopen(_PATH_UTMP, "r")) == NULL) { RETURN_WITH_SET_ERROR_WITH_ERRNO("user", SG_ERROR_OPEN, _PATH_UTMP); } #ifdef SG_LUPDATE_IF #undef SG_LUPDATE_IF #endif #define SG_LUPDATE_IF(tgt,obj,memb) \ (((void *)(&(obj.memb))) == ((void *)(&(obj.memb[0])))) \ ? sg_lupdate_string(tgt, obj.memb, sizeof(obj.memb))\ : sg_update_string(tgt, obj.memb) #undef VECTOR_UPDATE_ERROR_CLEANUP #define VECTOR_UPDATE_ERROR_CLEANUP fclose(f); while((fread(&entry, sizeof(entry),1,f)) != 0){ #ifdef HAVE_UTMP_TYPE if( USER_PROCESS != ut->ut_type ) continue; #elif defined(HAVE_UTMP_NAME) if (entry.ut_name[0] == '\0') continue; #elif defined(HAVE_UTMP_USER) if (entry.ut_user[0] == '\0') continue; #endif VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].device, entry, ut_line ) ) #if defined(HAVE_UTMP_USER) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, entry, ut_user ) ) #elif defined(HAVE_UTMP_NAME) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, entry, ut_name ) ) #endif #if defined(HAVE_UTMP_HOST) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].hostname, entry, ut_host ) ) #endif #if defined(HAVE_UTMP_ID) || ( SG_ERROR_NONE != sg_update_mem( &user_ptr[num_users].record_id, entry.ut_id, sizeof(entry.ut_id) ) ) #endif ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } #if defined(HAVE_UTMP_ID) user_ptr[num_users].record_id_size = sizeof(entry.ut_id); #endif #if defined(HAVE_UTMP_PID) user_ptr[num_users].pid = entry.ut_pid; #endif #if defined(HAVE_UTMP_TIME) user_ptr[num_users].login_time = entry.ut_time; #endif user_ptr[num_users].systime = now; ++num_users; } fclose(f); #else RETURN_WITH_SET_ERROR("user", SG_ERROR_UNSUPPORTED, OS_TYPE); #endif return SG_ERROR_NONE; }
static sg_error sg_get_host_info_int(sg_host_info *host_info_buf) { #ifdef WIN32 unsigned long nameln; char *name; long long result; OSVERSIONINFOEX osinfo; SYSTEM_INFO sysinfo; char *tmp_name; char tmp[10]; #else struct utsname os; # if defined(HPUX) struct pst_static pstat_static; struct pst_dynamic pstat_dynamic; time_t currtime; long boottime; # elif defined(SOLARIS) time_t boottime, curtime; kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *kn; char *isainfo = NULL; long isabufsz, rc; # elif defined(LINUX) || defined(CYGWIN) FILE *f; # elif defined(ALLBSD) int mib[2]; struct timeval boottime; time_t curtime; size_t size; int ncpus; # if defined(HW_MACHINE_ARCH) || defined(HW_MACHINE) char arch_name[16]; # endif # elif defined(AIX) static perfstat_cpu_total_t cpu_total; sg_error rc; # if defined(HAVE_GETUTXENT) struct utmpx *ut; # else struct utmp *ut; # endif # endif #endif host_info_buf->ncpus = 0; host_info_buf->maxcpus = 0; host_info_buf->bitwidth = 0; host_info_buf->host_state = sg_unknown_configuration; host_info_buf->uptime = 0; host_info_buf->systime = 0; #ifdef WIN32 /* these settings are static after boot, so why get them * constantly? * * Because we want to know some changes anyway - at least * when the hostname (DNS?) changes */ /* get system name */ nameln = MAX_COMPUTERNAME_LENGTH + 1; name = sg_malloc(nameln); if(name == NULL) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } /* * XXX probably GetComputerNameEx() is a better entry point ... */ if( GetComputerName(name, &nameln) == 0 ) { free(name); RETURN_WITH_SET_ERROR("os", SG_ERROR_HOST, "GetComputerName"); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->hostname, name)) { free(name); RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } free(name); /* get OS name, version and build */ ZeroMemory(&osinfo, sizeof(OSVERSIONINFOEX)); osinfo.dwOSVersionInfoSize = sizeof(osinfo); if(!GetVersionEx(&osinfo)) { RETURN_WITH_SET_ERROR("os", SG_ERROR_HOST, "GetVersionEx"); } GetSystemInfo(&sysinfo); /* Release - single number */ if(snprintf(tmp, sizeof(tmp), "%ld", osinfo.dwBuildNumber) == -1) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SPRINTF, NULL); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_release, tmp)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } /* Version */ /* usually a single digit . single digit, eg 5.0 */ if(snprintf(tmp, sizeof(tmp), "%ld.%ld", osinfo.dwMajorVersion, osinfo.dwMinorVersion) == -1) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_version, tmp)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } /* OS name */ tmp_name = get_os_name(osinfo, sysinfo); if(tmp_name == NULL) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_name, tmp_name)) { free(tmp_name); RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } free(tmp_name); /* Platform */ switch(sysinfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, "Intel")) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } break; case PROCESSOR_ARCHITECTURE_IA64: if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, "IA64")) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } break; case PROCESSOR_ARCHITECTURE_AMD64: if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, "AMD64")) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } break; default: if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, "Unknown")){ RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } break; } if(read_counter_large(SG_WIN32_UPTIME, &result)) { RETURN_WITH_SET_ERROR("os", SG_ERROR_PDHREAD, PDH_UPTIME); } host_info_buf->uptime = (time_t) result; #else if((uname(&os)) < 0) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_UNAME, NULL); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_name, os.sysname)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_release, os.release)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_version, os.version)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, os.machine)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->hostname, os.nodename)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } /* get uptime */ #ifdef HPUX if (pstat_getstatic(&pstat_static, sizeof(pstat_static), 1, 0) == -1) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_PSTAT, "pstat_static"); } if (pstat_getdynamic(&pstat_dynamic, sizeof(pstat_dynamic), 1, 0) == -1) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_PSTAT, "pstat_dynamic"); } currtime = time(NULL); boottime = pstat_static.boot_time; host_info_buf->uptime = currtime - boottime; host_info_buf->ncpus = pstat_dynamic.psd_proc_cnt; host_info_buf->maxcpus = pstat_dynamic.psd_max_proc_cnt; host_info_buf->bitwidth = sysconf(_SC_KERNEL_BITS); /* * TODO: getting virtualization state * 1) on boostrapping this component, try loading /opt/hpvm/lib/libhpvm.so (or so) * 2) get function addresses for * a) HPVM_boolean hpvm_api_server_check() * b) HPVM_boolean hpvm_api_virtmach_check() * * Seems to be hardware virtualization ... * See: http://docstore.mik.ua/manuals/hp-ux/en/T2767-90141/index.html (hpvmpubapi(3)) * http://jreypo.wordpress.com/tag/hpvm/ * http://jreypo.wordpress.com/category/hp-ux/page/3/ * http://h20338.www2.hp.com/enterprise/us/en/os/hpux11i-partitioning-integrity-vm.html */ #elif defined(SOLARIS) if ((kc = kstat_open()) == NULL) { RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_OPEN, NULL); } if((ksp=kstat_lookup(kc, "unix", -1, "system_misc"))==NULL){ kstat_close(kc); RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_LOOKUP, "unix,-1,system_misc"); } if (kstat_read(kc, ksp, 0) == -1) { kstat_close(kc); RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_READ, NULL); } if((kn=kstat_data_lookup(ksp, "boot_time")) == NULL){ kstat_close(kc); RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_DATA_LOOKUP, "boot_time"); } /* XXX verify on Solaris 10 if it's still ui32 */ boottime = (kn->value.ui32); kstat_close(kc); time(&curtime); host_info_buf->uptime = curtime - boottime; host_info_buf->ncpus = sysconf(_SC_NPROCESSORS_ONLN); host_info_buf->maxcpus = sysconf(_SC_NPROCESSORS_CONF); isainfo = sg_malloc( isabufsz = (32 * sizeof(*isainfo)) ); if( NULL == isainfo ) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } # define MKSTR(x) #x # if defined(SI_ARCHITECTURE_K) # define SYSINFO_CMD SI_ARCHITECTURE_K # elif defined(SI_ISALIST) # define SYSINFO_CMD SI_ISALIST # else # define SYSINFO_CMD SI_ARCHITECTURE # endif sysinfo_again: if( -1 == ( rc = sysinfo( SYSINFO_CMD, isainfo, isabufsz ) ) ) { free(isainfo); RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSINFO, MKSTR(SYSINFO_CMD) ); } else if( rc > isabufsz ) { char *tmp = sg_realloc(isainfo, rc); if( NULL == tmp ) { free(isainfo); RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } isabufsz = rc; isainfo = tmp; goto sysinfo_again; } host_info_buf->bitwidth = get_bitwidth_by_arch_name(isainfo); free(isainfo); host_info_buf->host_state = sg_unknown_configuration; #elif defined(LINUX) || defined(CYGWIN) if ((f=fopen("/proc/uptime", "r")) == NULL) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_OPEN, "/proc/uptime"); } #define TIME_T_SCANF_FMT (sizeof(int[(((time_t)-1)/2)%4+1]) == sizeof(int[1]) ? "%ld %*d" : "%lu %*d" ) if((fscanf(f,TIME_T_SCANF_FMT,&host_info_buf->uptime)) != 1){ fclose(f); RETURN_WITH_SET_ERROR("os", SG_ERROR_PARSE, NULL); } fclose(f); # if defined(LINUX) host_info_buf->ncpus = sysconf(_SC_NPROCESSORS_ONLN); host_info_buf->maxcpus = sysconf(_SC_NPROCESSORS_CONF); if( access( "/proc/sys/kernel/vsyscall64", F_OK ) == 0 || access( "/proc/sys/abi/vsyscall32", F_OK ) == 0 ) { host_info_buf->bitwidth = 64; } else { host_info_buf->bitwidth = sysconf(_SC_LONG_BIT); // well, maybe 64-bit disabled 128-bit system o.O } host_info_buf->host_state = sg_unknown_configuration; # endif #elif defined(ALLBSD) mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof(boottime); if (sysctl(mib, 2, &boottime, &size, NULL, 0) < 0) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_KERN.KERN_BOOTTIME"); } time(&curtime); host_info_buf->uptime= curtime - boottime.tv_sec; # if defined(HW_NCPU) mib[0] = CTL_HW; mib[1] = HW_NCPU; size = sizeof(int); if( sysctl( mib, 2, &ncpus, &size, NULL, 0 ) < 0 ) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_NCPU" ); } # endif # if defined(HW_MACHINE_ARCH) mib[0] = CTL_HW; mib[1] = HW_MACHINE_ARCH; size = sizeof(arch_name); if( sysctl( mib, 2, arch_name, &size, NULL, 0 ) == 0 ) { host_info_buf->bitwidth = get_bitwidth_by_arch_name(arch_name); } else { # endif # if defined(HW_MACHINE) mib[0] = CTL_HW; mib[1] = HW_MACHINE; size = sizeof(arch_name); if( sysctl( mib, 2, arch_name, &size, NULL, 0 ) == 0 ) { host_info_buf->bitwidth = get_bitwidth_by_arch_name(arch_name); } else { SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_MACHINE" ); } # elif defined(HW_MACHINE_ARCH) SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_MACHINE_ARCH" ); # endif # if defined(HW_MACHINE_ARCH) } # endif host_info_buf->host_state = sg_unknown_configuration; /* details must be analysed "manually", no syscall */ host_info_buf->maxcpus = (unsigned)ncpus; # if defined(HW_NCPUONLINE) /* use knowledge about number of cpu's online, when available instead of assuming all of them */ mib[0] = CTL_HW; mib[1] = HW_NCPUONLINE; size = sizeof(int); if( sysctl( mib, 2, &ncpus, &size, NULL, 0 ) < 0 ) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_NCPUONLINE" ); } # endif host_info_buf->ncpus = (unsigned)ncpus; #elif defined(AIX) if(perfstat_cpu_total(NULL, &cpu_total, sizeof(cpu_total), 1) != 1) { RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "perfstat_cpu_total"); } if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, cpu_total.description)) { RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() ); } host_info_buf->ncpus = cpu_total.ncpus; host_info_buf->maxcpus = cpu_total.ncpus_cfg; host_info_buf->bitwidth = sysconf(_SC_AIX_KERNEL_BITMODE); if( sysconf(_SC_LPAR_ENABLED) > 0 ) { host_info_buf->host_state = sg_hardware_virtualized; } else { host_info_buf->host_state = sg_physical_host; } #ifdef ENABLE_THREADS if( SG_ERROR_NONE != ( rc = sg_lock_mutex("utmp") ) ) { RETURN_FROM_PREVIOUS_ERROR( "os", rc ); } #endif # if defined(HAVE_GETUTXENT) # define UTENTFN getutxent # define UTENTTM ut->ut_tv.tv_sec setutxent(); # else # define UTENTFN getutent # define UTENTTM ut->ut_time setutent(); # endif while( NULL != ( ut = UTENTFN() ) ) { if( ut->ut_type == BOOT_TIME ) { host_info_buf->uptime = time(NULL) - UTENTTM; break; } } # if defined(HAVE_GETUTXENT) endutxent(); # else endutent(); # endif #ifdef ENABLE_THREADS if( SG_ERROR_NONE != ( rc = sg_unlock_mutex("utmp") ) ) { RETURN_FROM_PREVIOUS_ERROR( "os", rc ); } #endif #else RETURN_WITH_SET_ERROR("os", SG_ERROR_UNSUPPORTED, OS_TYPE); #endif #endif /* WIN32 */ host_info_buf->systime = time(NULL); return SG_ERROR_NONE; }