uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), multiplier = ((uint64_t)1000L / ticks), cpuspeed; int numcpus = 0, i = 0; unsigned long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr; char line[512], speedPath[256], model[512]; FILE *fpStat = fopen("/proc/stat", "r"); FILE *fpModel = fopen("/proc/cpuinfo", "r"); FILE *fpSpeed; uv_cpu_info_t* cpu_info; if (fpModel) { while (fgets(line, 511, fpModel) != NULL) { if (strncmp(line, "model name", 10) == 0) { numcpus++; if (numcpus == 1) { char *p = strchr(line, ':') + 2; strcpy(model, p); model[strlen(model)-1] = 0; } } else if (strncmp(line, "cpu MHz", 7) == 0) { if (numcpus == 1) { sscanf(line, "%*s %*s : %u", &cpuspeed); } } } fclose(fpModel); } *cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t)); if (!(*cpu_infos)) { return uv__new_artificial_error(UV_ENOMEM); } *count = numcpus; cpu_info = *cpu_infos; if (fpStat) { while (fgets(line, 511, fpStat) != NULL) { if (strncmp(line, "cpu ", 4) == 0) { continue; } else if (strncmp(line, "cpu", 3) != 0) { break; } sscanf(line, "%*s %lu %lu %lu %lu %*s %lu", &ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr); snprintf(speedPath, sizeof(speedPath), "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i); fpSpeed = fopen(speedPath, "r"); if (fpSpeed) { if (fgets(line, 511, fpSpeed) != NULL) { sscanf(line, "%u", &cpuspeed); cpuspeed /= 1000; } fclose(fpSpeed); } cpu_info->cpu_times.user = ticks_user * multiplier; cpu_info->cpu_times.nice = ticks_nice * multiplier; cpu_info->cpu_times.sys = ticks_sys * multiplier; cpu_info->cpu_times.idle = ticks_idle * multiplier; cpu_info->cpu_times.irq = ticks_intr * multiplier; cpu_info->model = strdup(model); cpu_info->speed = cpuspeed; cpu_info++; } fclose(fpStat); } return uv_ok_; }
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifdef SUNOS_NO_IFADDRS return uv__new_artificial_error(UV_ENOSYS); #else struct ifaddrs *addrs, *ent; char ip[INET6_ADDRSTRLEN]; uv_interface_address_t* address; if (getifaddrs(&addrs) != 0) { return uv__new_sys_error(errno); } *count = 0; /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family == PF_PACKET)) { continue; } (*count)++; } *addresses = (uv_interface_address_t*) malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { return uv__new_artificial_error(UV_ENOMEM); } address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { memset(&ip, 0, sizeof(ip)); if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { continue; } if (ent->ifa_addr == NULL) { continue; } address->name = strdup(ent->ifa_name); if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr); } else { address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr); } address->is_internal = ent->ifa_flags & IFF_PRIVATE || ent->ifa_flags & IFF_LOOPBACK ? 1 : 0; address++; } freeifaddrs(addrs); return uv_ok_; #endif /* SUNOS_NO_IFADDRS */ }
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifndef HAVE_IFADDRS_H return uv__new_artificial_error(UV_ENOSYS); #else struct ifaddrs *addrs, *ent; char ip[INET6_ADDRSTRLEN]; uv_interface_address_t* address; if (getifaddrs(&addrs) != 0) { return uv__new_sys_error(errno); } *count = 0; /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family == PF_PACKET)) { continue; } (*count)++; } *addresses = (uv_interface_address_t*) malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { return uv__new_artificial_error(UV_ENOMEM); } address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { bzero(&ip, sizeof (ip)); if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { continue; } if (ent->ifa_addr == NULL) { continue; } /* * On Linux getifaddrs returns information related to the raw underlying * devices. We're not interested in this information. */ if (ent->ifa_addr->sa_family == PF_PACKET) { continue; } address->name = strdup(ent->ifa_name); if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr); } else { address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr); } address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0; address++; } freeifaddrs(addrs); return uv_ok_; #endif }
void uv__set_artificial_error(uv_loop_t* loop, uv_err_code code) { loop->last_err = uv__new_artificial_error(code); }
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int lookup_instance; kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *knp; uv_cpu_info_t* cpu_info; if ((kc = kstat_open()) == NULL) { return uv__new_sys_error(errno); } /* Get count of cpus */ lookup_instance = 0; while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) { lookup_instance++; } *cpu_infos = (uv_cpu_info_t*) malloc(lookup_instance * sizeof(uv_cpu_info_t)); if (!(*cpu_infos)) { return uv__new_artificial_error(UV_ENOMEM); } *count = lookup_instance; cpu_info = *cpu_infos; lookup_instance = 0; while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) { if (kstat_read(kc, ksp, NULL) == -1) { cpu_info->speed = 0; cpu_info->model = NULL; } else { knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz"); assert(knp->data_type == KSTAT_DATA_INT32 || knp->data_type == KSTAT_DATA_INT64); cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32 : knp->value.i64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand"); assert(knp->data_type == KSTAT_DATA_STRING); cpu_info->model = strdup(KSTAT_NAMED_STR_PTR(knp)); } lookup_instance++; cpu_info++; } cpu_info = *cpu_infos; lookup_instance = 0; while ((ksp = kstat_lookup(kc, (char *)"cpu", lookup_instance, (char *)"sys"))){ if (kstat_read(kc, ksp, NULL) == -1) { cpu_info->cpu_times.user = 0; cpu_info->cpu_times.nice = 0; cpu_info->cpu_times.sys = 0; cpu_info->cpu_times.idle = 0; cpu_info->cpu_times.irq = 0; } else { knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_user"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.user = knp->value.ui64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_kernel"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.sys = knp->value.ui64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_idle"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.idle = knp->value.ui64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"intr"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.irq = knp->value.ui64; cpu_info->cpu_times.nice = 0; } lookup_instance++; cpu_info++; } kstat_close(kc); return uv_ok_; }
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses_ptr, int* count_ptr) { IP_ADAPTER_ADDRESSES* win_address_buf; ULONG win_address_buf_size; IP_ADAPTER_ADDRESSES* win_address; uv_interface_address_t* uv_address_buf; char* name_buf; size_t uv_address_buf_size; uv_interface_address_t* uv_address; int count; /* Fetch the size of the adapters reported by windows, and then get the */ /* list itself. */ win_address_buf_size = 0; win_address_buf = NULL; for (;;) { ULONG r; /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ /* win_address_buf_size. */ r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, win_address_buf, &win_address_buf_size); if (r == ERROR_SUCCESS) break; free(win_address_buf); switch (r) { case ERROR_BUFFER_OVERFLOW: /* This happens when win_address_buf is NULL or too small to hold */ /* all adapters. */ win_address_buf = malloc(win_address_buf_size); if (win_address_buf == NULL) return uv__new_artificial_error(UV_ENOMEM); continue; case ERROR_NO_DATA: { /* No adapters were found. */ uv_address_buf = malloc(1); if (uv_address_buf == NULL) return uv__new_artificial_error(UV_ENOMEM); *count_ptr = 0; *addresses_ptr = uv_address_buf; return uv_ok_; } case ERROR_ADDRESS_NOT_ASSOCIATED: return uv__new_artificial_error(UV_EAGAIN); case ERROR_INVALID_PARAMETER: /* MSDN says: * "This error is returned for any of the following conditions: the * SizePointer parameter is NULL, the Address parameter is not * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for * the parameters requested is greater than ULONG_MAX." * Since the first two conditions are not met, it must be that the * adapter data is too big. */ return uv__new_artificial_error(UV_ENOBUFS); default: /* Other (unspecified) errors can happen, but we don't have any */ /* special meaning for them. */ assert(r != ERROR_SUCCESS); return uv__new_sys_error(r); } } /* Count the number of enabled interfaces and compute how much space is */ /* needed to store their info. */ count = 0; uv_address_buf_size = 0; for (win_address = win_address_buf; win_address != NULL; win_address = win_address->Next) { /* Use IP_ADAPTER_UNICAST_ADDRESS_XP to retain backwards compatibility */ /* with Windows XP */ IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; int name_size; /* Interfaces that are not 'up' should not be reported. Also skip */ /* interfaces that have no associated unicast address, as to avoid */ /* allocating space for the name for this interface. */ if (win_address->OperStatus != IfOperStatusUp || win_address->FirstUnicastAddress == NULL) continue; /* Compute the size of the interface name. */ name_size = WideCharToMultiByte(CP_UTF8, 0, win_address->FriendlyName, -1, NULL, 0, NULL, FALSE); if (name_size <= 0) { free(win_address_buf); return uv__new_sys_error(GetLastError()); } uv_address_buf_size += name_size; /* Count the number of addresses associated with this interface, and */ /* compute the size. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) win_address->FirstUnicastAddress; unicast_address != NULL; unicast_address = unicast_address->Next) { count++; uv_address_buf_size += sizeof(uv_interface_address_t); } } /* Allocate space to store interface data plus adapter names. */ uv_address_buf = malloc(uv_address_buf_size); if (uv_address_buf == NULL) { free(win_address_buf); return uv__new_artificial_error(UV_ENOMEM); } /* Compute the start of the uv_interface_address_t array, and the place in */ /* the buffer where the interface names will be stored. */ uv_address = uv_address_buf; name_buf = (char*) (uv_address_buf + count); /* Fill out the output buffer. */ for (win_address = win_address_buf; win_address != NULL; win_address = win_address->Next) { IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; int name_size; size_t max_name_size; if (win_address->OperStatus != IfOperStatusUp || win_address->FirstUnicastAddress == NULL) continue; /* Convert the interface name to UTF8. */ max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; if (max_name_size > (size_t) INT_MAX) max_name_size = INT_MAX; name_size = WideCharToMultiByte(CP_UTF8, 0, win_address->FriendlyName, -1, name_buf, (int) max_name_size, NULL, FALSE); if (name_size <= 0) { free(win_address_buf); free(uv_address_buf); return uv__new_sys_error(GetLastError()); } /* Add an uv_interface_address_t element for every unicast address. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) win_address->FirstUnicastAddress; unicast_address != NULL; unicast_address = unicast_address->Next) { struct sockaddr* sa; uv_address->name = name_buf; sa = unicast_address->Address.lpSockaddr; if (sa->sa_family == AF_INET6) uv_address->address.address6 = *((struct sockaddr_in6 *) sa); else uv_address->address.address4 = *((struct sockaddr_in *) sa); uv_address->is_internal = (win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK); uv_address++; } name_buf += name_size; } free(win_address_buf); *addresses_ptr = uv_address_buf; *count_ptr = count; return uv_ok_; }
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int lookup_instance; kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *knp; uv_cpu_info_t* cpu_info; if ((kc = kstat_open()) == NULL) { return uv__new_sys_error(errno); } /* Get count of cpus */ lookup_instance = 0; while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) { lookup_instance++; } *cpu_infos = (uv_cpu_info_t*) malloc(lookup_instance * sizeof(uv_cpu_info_t)); if (!(*cpu_infos)) { return uv__new_artificial_error(UV_ENOMEM); } *count = lookup_instance; cpu_info = *cpu_infos; lookup_instance = 0; while ((ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL))) { if (kstat_read(kc, ksp, NULL) == -1) { /* * It is deeply annoying, but some kstats can return errors * under otherwise routine conditions. (ACPI is one * offender; there are surely others.) To prevent these * fouled kstats from completely ruining our day, we assign * an "error" member to the return value that consists of * the strerror(). */ cpu_info->speed = 0; cpu_info->model = NULL; } else { knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz"); assert(knp->data_type == KSTAT_DATA_INT32); cpu_info->speed = knp->value.i32; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand"); assert(knp->data_type == KSTAT_DATA_STRING); cpu_info->model = KSTAT_NAMED_STR_PTR(knp); } lookup_instance++; cpu_info++; } cpu_info = *cpu_infos; lookup_instance = 0; while ((ksp = kstat_lookup(kc, (char *)"cpu", lookup_instance, (char *)"sys"))){ if (kstat_read(kc, ksp, NULL) == -1) { cpu_info->cpu_times.user = 0; cpu_info->cpu_times.nice = 0; cpu_info->cpu_times.sys = 0; cpu_info->cpu_times.idle = 0; cpu_info->cpu_times.irq = 0; } else { knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_user"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.user = knp->value.ui64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_kernel"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.sys = knp->value.ui64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_idle"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.idle = knp->value.ui64; knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"intr"); assert(knp->data_type == KSTAT_DATA_UINT64); cpu_info->cpu_times.irq = knp->value.ui64; cpu_info->cpu_times.nice = 0; } lookup_instance++; cpu_info++; } kstat_close(kc); return uv_ok_; }
uv_err_t uv_uptime(double* uptime) { BYTE stack_buffer[4096]; BYTE* malloced_buffer = NULL; BYTE* buffer = (BYTE*) stack_buffer; size_t buffer_size = sizeof(stack_buffer); DWORD data_size; PERF_DATA_BLOCK* data_block; PERF_OBJECT_TYPE* object_type; PERF_COUNTER_DEFINITION* counter_definition; DWORD i; for (;;) { LONG result; data_size = (DWORD) buffer_size; result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, L"2", NULL, NULL, buffer, &data_size); if (result == ERROR_SUCCESS) { break; } else if (result != ERROR_MORE_DATA) { *uptime = 0; return uv__new_sys_error(result); } free(malloced_buffer); buffer_size *= 2; /* Don't let the buffer grow infinitely. */ if (buffer_size > 1 << 20) { goto internalError; } buffer = malloced_buffer = (BYTE*) malloc(buffer_size); if (malloced_buffer == NULL) { *uptime = 0; return uv__new_artificial_error(UV_ENOMEM); } } if (data_size < sizeof(*data_block)) goto internalError; data_block = (PERF_DATA_BLOCK*) buffer; if (wmemcmp(data_block->Signature, L"PERF", 4) != 0) goto internalError; if (data_size < data_block->HeaderLength + sizeof(*object_type)) goto internalError; object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength); if (object_type->NumInstances != PERF_NO_INSTANCES) goto internalError; counter_definition = (PERF_COUNTER_DEFINITION*) (buffer + data_block->HeaderLength + object_type->HeaderLength); for (i = 0; i < object_type->NumCounters; i++) { if ((BYTE*) counter_definition + sizeof(*counter_definition) > buffer + data_size) { break; } if (counter_definition->CounterNameTitleIndex == 674 && counter_definition->CounterSize == sizeof(uint64_t)) { if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size || !(counter_definition->CounterType & PERF_OBJECT_TIMER)) { goto internalError; } else { BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + counter_definition->CounterOffset; uint64_t value = *((uint64_t*) address); *uptime = (double) (object_type->PerfTime.QuadPart - value) / (double) object_type->PerfFreq.QuadPart; free(malloced_buffer); return uv_ok_; } } counter_definition = (PERF_COUNTER_DEFINITION*) ((BYTE*) counter_definition + counter_definition->ByteLength); } /* If we get here, the uptime value was not found. */ free(malloced_buffer); *uptime = 0; return uv__new_artificial_error(UV_ENOSYS); internalError: free(malloced_buffer); *uptime = 0; return uv__new_artificial_error(UV_EIO); }
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { uv_cpu_info_t* cpu_infos; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; DWORD sppi_size; SYSTEM_INFO system_info; DWORD cpu_count, r, i; NTSTATUS status; ULONG result_size; uv_err_t err; uv_cpu_info_t* cpu_info; cpu_infos = NULL; cpu_count = 0; sppi = NULL; uv__once_init(); GetSystemInfo(&system_info); cpu_count = system_info.dwNumberOfProcessors; cpu_infos = calloc(cpu_count, sizeof *cpu_infos); if (cpu_infos == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto error; } sppi_size = cpu_count * sizeof(*sppi); sppi = malloc(sppi_size); if (sppi == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto error; } status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, sppi_size, &result_size); if (!NT_SUCCESS(status)) { err = uv__new_sys_error(pRtlNtStatusToDosError(status)); goto error; } assert(result_size == sppi_size); for (i = 0; i < cpu_count; i++) { WCHAR key_name[128]; HKEY processor_key; DWORD cpu_speed; DWORD cpu_speed_size = sizeof(cpu_speed); WCHAR cpu_brand[256]; DWORD cpu_brand_size = sizeof(cpu_brand); int len; len = _snwprintf(key_name, ARRAY_SIZE(key_name), L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i); assert(len > 0 && len < ARRAY_SIZE(key_name)); r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_QUERY_VALUE, &processor_key); if (r != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); goto error; } if (RegQueryValueExW(processor_key, L"~MHz", NULL, NULL, (BYTE*) &cpu_speed, &cpu_speed_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); RegCloseKey(processor_key); goto error; } if (RegQueryValueExW(processor_key, L"ProcessorNameString", NULL, NULL, (BYTE*) &cpu_brand, &cpu_brand_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); RegCloseKey(processor_key); goto error; } RegCloseKey(processor_key); cpu_info = &cpu_infos[i]; cpu_info->speed = cpu_speed; cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - sppi[i].IdleTime.QuadPart) / 10000; cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; len = WideCharToMultiByte(CP_UTF8, 0, cpu_brand, cpu_brand_size / sizeof(WCHAR), NULL, 0, NULL, NULL); if (len == 0) { err = uv__new_sys_error(GetLastError()); goto error; } assert(len > 0); /* Allocate 1 extra byte for the null terminator. */ cpu_info->model = malloc(len + 1); if (cpu_info->model == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto error; } if (WideCharToMultiByte(CP_UTF8, 0, cpu_brand, cpu_brand_size / sizeof(WCHAR), cpu_info->model, len, NULL, NULL) == 0) { err = uv__new_sys_error(GetLastError()); goto error; } /* Ensure that cpu_info->model is null terminated. */ cpu_info->model[len] = '\0'; } free(sppi); *cpu_count_ptr = cpu_count; *cpu_infos_ptr = cpu_infos; return uv_ok_; error: /* This is safe because the cpu_infos array is zeroed on allocation. */ for (i = 0; i < cpu_count; i++) free(cpu_infos[i].model); free(cpu_infos); free(sppi); return err; }
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs *addrs, *ent; char ip[INET6_ADDRSTRLEN]; uv_interface_address_t* address; if (getifaddrs(&addrs) != 0) { return uv__new_sys_error(errno); } *count = 0; /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) || (ent->ifa_addr == NULL) || (ent->ifa_addr->sa_family == AF_LINK)) { continue; } (*count)++; } *addresses = (uv_interface_address_t*) malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { return uv__new_artificial_error(UV_ENOMEM); } address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { bzero(&ip, sizeof (ip)); if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) { continue; } if (ent->ifa_addr == NULL) { continue; } /* * On Mac OS X getifaddrs returns information related to Mac Addresses for * various devices, such as firewire, etc. These are not relevant here. */ if (ent->ifa_addr->sa_family == AF_LINK) { continue; } address->name = strdup(ent->ifa_name); if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr); } else { address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr); } address->is_internal = ent->ifa_flags & IFF_LOOPBACK ? 1 : 0; address++; } freeifaddrs(addrs); return uv_ok_; }
uv_err_t uv_chdir(const char* dir) { WCHAR utf16_buffer[MAX_PATH]; size_t utf16_len; WCHAR drive_letter, env_var[4]; if (dir == NULL) { return uv__new_artificial_error(UV_EINVAL); } if (MultiByteToWideChar(CP_UTF8, 0, dir, -1, utf16_buffer, MAX_PATH) == 0) { DWORD error = GetLastError(); /* The maximum length of the current working directory is 260 chars, */ /* including terminating null. If it doesn't fit, the path name must be */ /* too long. */ if (error == ERROR_INSUFFICIENT_BUFFER) { return uv__new_artificial_error(UV_ENAMETOOLONG); } else { return uv__new_sys_error(error); } } if (!SetCurrentDirectoryW(utf16_buffer)) { return uv__new_sys_error(GetLastError()); } /* Windows stores the drive-local path in an "hidden" environment variable, */ /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ /* update this, so we'll have to do it. */ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); if (utf16_len == 0) { return uv__new_sys_error(GetLastError()); } else if (utf16_len > MAX_PATH) { return uv__new_artificial_error(UV_EIO); } /* The returned directory should not have a trailing slash, unless it */ /* points at a drive root, like c:\. Remove it if needed. */ if (utf16_buffer[utf16_len - 1] == L'\\' && !(utf16_len == 3 && utf16_buffer[1] == L':')) { utf16_len--; utf16_buffer[utf16_len] = L'\0'; } if (utf16_len < 2 || utf16_buffer[1] != L':') { /* Doesn't look like a drive letter could be there - probably an UNC */ /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ drive_letter = 0; } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { drive_letter = utf16_buffer[0]; } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') { /* Convert to uppercase. */ drive_letter = utf16_buffer[0] - L'a' + L'A'; } else { /* Not valid. */ drive_letter = 0; } if (drive_letter != 0) { /* Construct the environment variable name and set it. */ env_var[0] = L'='; env_var[1] = drive_letter; env_var[2] = L':'; env_var[3] = L'\0'; if (!SetEnvironmentVariableW(env_var, utf16_buffer)) { return uv__new_sys_error(GetLastError()); } } return uv_ok_; }
uv_err_t uv_set_process_title(const char* title) { /* TODO implement me */ return uv__new_artificial_error(UV_ENOSYS); }
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; DWORD sppi_size; SYSTEM_INFO system_info; DWORD cpu_count, i, r; ULONG result_size; size_t size; uv_err_t err; uv_cpu_info_t* cpu_info; *cpu_infos = NULL; *count = 0; uv__once_init(); GetSystemInfo(&system_info); cpu_count = system_info.dwNumberOfProcessors; size = cpu_count * sizeof(uv_cpu_info_t); *cpu_infos = (uv_cpu_info_t*) malloc(size); if (*cpu_infos == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto out; } memset(*cpu_infos, 0, size); sppi_size = sizeof(*sppi) * cpu_count; sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size); if (!sppi) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, sppi_size, &result_size); if (r != ERROR_SUCCESS || result_size != sppi_size) { err = uv__new_sys_error(GetLastError()); goto out; } for (i = 0; i < cpu_count; i++) { WCHAR key_name[128]; HKEY processor_key; DWORD cpu_speed; DWORD cpu_speed_size = sizeof(cpu_speed); WCHAR cpu_brand[256]; DWORD cpu_brand_size = sizeof(cpu_brand); _snwprintf(key_name, ARRAY_SIZE(key_name), L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i); r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_QUERY_VALUE, &processor_key); if (r != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); goto out; } if (RegQueryValueExW(processor_key, L"~MHz", NULL, NULL, (BYTE*) &cpu_speed, &cpu_speed_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); RegCloseKey(processor_key); goto out; } if (RegQueryValueExW(processor_key, L"ProcessorNameString", NULL, NULL, (BYTE*) &cpu_brand, &cpu_brand_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); RegCloseKey(processor_key); goto out; } RegCloseKey(processor_key); cpu_info = &(*cpu_infos)[i]; cpu_info->speed = cpu_speed; cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - sppi[i].IdleTime.QuadPart) / 10000; cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; size = uv_utf16_to_utf8(cpu_brand, cpu_brand_size / sizeof(WCHAR), NULL, 0); if (size == 0) { err = uv__new_sys_error(GetLastError()); goto out; } /* Allocate 1 extra byte for the null terminator. */ cpu_info->model = (char*) malloc(size + 1); if (cpu_info->model == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto out; } if (uv_utf16_to_utf8(cpu_brand, cpu_brand_size / sizeof(WCHAR), cpu_info->model, size) == 0) { err = uv__new_sys_error(GetLastError()); goto out; } /* Ensure that cpu_info->model is null terminated. */ cpu_info->model[size] = '\0'; (*count)++; } err = uv_ok_; out: if (sppi) { free(sppi); } if (err.code != UV_OK && *cpu_infos != NULL) { int i; for (i = 0; i < *count; i++) { /* This is safe because the cpu_infos memory area is zeroed out */ /* immediately after allocating it. */ free((*cpu_infos)[i].model); } free(*cpu_infos); *cpu_infos = NULL; *count = 0; } return err; }
int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv_process_options_t options) { int i; uv_err_t err = uv_ok_; WCHAR* path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; if (options.flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { uv__set_artificial_error(loop, UV_ENOTSUP); return -1; } if (options.file == NULL || options.args == NULL) { uv__set_artificial_error(loop, UV_EINVAL); return -1; } assert(options.file != NULL); assert(!(options.flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); uv_process_init(loop, process); process->exit_cb = options.exit_cb; err = uv_utf8_to_utf16_alloc(options.file, &application); if (err.code != UV_OK) goto done; err = make_program_args(options.args, options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err.code != UV_OK) goto done; if (options.env) { err = make_program_env(options.env, &env); if (err.code != UV_OK) goto done; } if (options.cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options.cwd, &cwd); if (err.code != UV_OK) goto done; } else { /* Inherit cwd */ DWORD cwd_len, r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { err = uv__new_sys_error(GetLastError()); goto done; } cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR)); if (cwd == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto done; } r = GetCurrentDirectoryW(cwd_len, cwd); if (r == 0 || r >= cwd_len) { err = uv__new_sys_error(GetLastError()); goto done; } } /* Get PATH environment variable. */ { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); if (path_len == 0) { err = uv__new_sys_error(GetLastError()); goto done; } path = (WCHAR*) malloc(path_len * sizeof(WCHAR)); if (path == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto done; } r = GetEnvironmentVariableW(L"PATH", path, path_len); if (r == 0 || r >= path_len) { err = uv__new_sys_error(GetLastError()); goto done; } } application_path = search_path(application, cwd, path); if (application_path == NULL) { /* Not found. */ err = uv__new_artificial_error(UV_ENOENT); goto done; } err = uv__stdio_create(loop, &options, &process->child_stdio_buffer); if (err.code != UV_OK) goto done; startup.cb = sizeof(startup); startup.lpReserved = NULL; startup.lpDesktop = NULL; startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); if (options.flags & UV_PROCESS_WINDOWS_HIDE) { /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; } else { startup.wShowWindow = SW_SHOWDEFAULT; } process_flags = CREATE_UNICODE_ENVIRONMENT; if (options.flags & UV_PROCESS_DETACHED) { process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } if (CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags, env, cwd, &startup, &info)) { /* Spawn succeeded */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options.stdio_count; i++) { const uv_stdio_container_t* fdopt = &options.stdio[i]; if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId; } } /* Setup notifications for when the child process exits. */ result = RegisterWaitForSingleObject(&process->wait_handle, process->process_handle, exit_wait_callback, (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!result) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } CloseHandle(info.hThread); } else { /* CreateProcessW failed. */ err = uv__new_sys_error(GetLastError()); } done: free(application); free(application_path); free(arguments); free(cwd); free(env); free(path); process->spawn_error = err; if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; } /* Make the handle active. It will remain active until the exit callback */ /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* If an error happened, queue the exit req. */ if (err.code != UV_OK) { process->exit_cb_pending = 1; uv_insert_pending_req(loop, (uv_req_t*) &process->exit_req); } return 0; }
/* * The way windows takes environment variables is different than what C does; * Windows wants a contiguous block of null-terminated strings, terminated * with an additional null. * * Windows has a few "essential" environment variables. winsock will fail * to initialize if SYSTEMROOT is not defined; some APIs make reference to * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that * these get defined if the input environment block does not contain any * values for them. */ uv_err_t make_program_env(char* env_block[], WCHAR** dst_ptr) { WCHAR* dst; WCHAR* ptr; char** env; size_t env_len = 1; /* room for closing null */ int len; int i; DWORD var_size; env_var_t required_vars[] = { E_V("SYSTEMROOT"), E_V("SYSTEMDRIVE"), E_V("TEMP"), }; for (env = env_block; *env; env++) { int len; check_required_vars_contains_var(required_vars, ARRAY_SIZE(required_vars), *env); len = MultiByteToWideChar(CP_UTF8, 0, *env, -1, NULL, 0); if (len <= 0) { return uv__new_sys_error(GetLastError()); } env_len += len; } for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { if (!required_vars[i].supplied) { env_len += required_vars[i].len; var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); if (var_size == 0) { return uv__new_sys_error(GetLastError()); } required_vars[i].value_len = var_size; env_len += var_size; } } dst = malloc(env_len * sizeof(WCHAR)); if (!dst) { return uv__new_artificial_error(UV_ENOMEM); } ptr = dst; for (env = env_block; *env; env++, ptr += len) { len = MultiByteToWideChar(CP_UTF8, 0, *env, -1, ptr, (int) (env_len - (ptr - dst))); if (len <= 0) { free(dst); return uv__new_sys_error(GetLastError()); } } for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { if (!required_vars[i].supplied) { wcscpy(ptr, required_vars[i].wide); ptr += required_vars[i].len - 1; *ptr++ = L'='; var_size = GetEnvironmentVariableW(required_vars[i].wide, ptr, required_vars[i].value_len); if (var_size == 0) { uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); } ptr += required_vars[i].value_len; } } /* Terminate with an extra NULL. */ *ptr = L'\0'; *dst_ptr = dst; return uv_ok_; }
uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { char** arg; WCHAR* dst = NULL; WCHAR* temp_buffer = NULL; size_t dst_len = 0; size_t temp_buffer_len = 0; WCHAR* pos; int arg_count = 0; uv_err_t err = uv_ok_; /* Count the required size. */ for (arg = args; *arg; arg++) { DWORD arg_len; arg_len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, NULL, 0); if (arg_len == 0) { return uv__new_sys_error(GetLastError()); } dst_len += arg_len; if (arg_len > temp_buffer_len) temp_buffer_len = arg_len; arg_count++; } /* Adjust for potential quotes. Also assume the worst-case scenario */ /* that every character needs escaping, so we need twice as much space. */ dst_len = dst_len * 2 + arg_count * 2; /* Allocate buffer for the final command line. */ dst = (WCHAR*) malloc(dst_len * sizeof(WCHAR)); if (dst == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto error; } /* Allocate temporary working buffer. */ temp_buffer = (WCHAR*) malloc(temp_buffer_len * sizeof(WCHAR)); if (temp_buffer == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto error; } pos = dst; for (arg = args; *arg; arg++) { DWORD arg_len; /* Convert argument to wide char. */ arg_len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, temp_buffer, (int) (dst + dst_len - pos)); if (arg_len == 0) { goto error; } if (verbatim_arguments) { /* Copy verbatim. */ wcscpy(pos, temp_buffer); pos += arg_len - 1; } else { /* Quote/escape, if needed. */ pos = quote_cmd_arg(temp_buffer, pos); } *pos++ = *(arg + 1) ? L' ' : L'\0'; } free(temp_buffer); *dst_ptr = dst; return uv_ok_; error: free(dst); free(temp_buffer); return err; }