1 /*
2  * Copyright (c) 2004-2009 Hyperic, Inc.
3  * Copyright (c) 2009 SpringSource, Inc.
4  * Copyright (c) 2009-2010 VMware, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "sigar.h"
20 #include "sigar_private.h"
21 #include "sigar_pdh.h"
22 #include "sigar_os.h"
23 #include "sigar_util.h"
24 #include "sigar_format.h"
25 #include <shellapi.h>
26 #include <assert.h>
27 
28 #define USING_WIDE_S(s) (s)->using_wide
29 #define USING_WIDE()    USING_WIDE_S(sigar)
30 
31 #define PERFBUF_SIZE 8192
32 
33 #define PERF_TITLE_PROC       230
34 #define PERF_TITLE_SYS_KEY   "2"
35 #define PERF_TITLE_MEM_KEY   "4"
36 #define PERF_TITLE_PROC_KEY  "230"
37 #define PERF_TITLE_CPU_KEY   "238"
38 #define PERF_TITLE_DISK_KEY  "236"
39 
40 #define PERF_TITLE_CPU_USER    142
41 #define PERF_TITLE_CPU_IDLE    1746
42 #define PERF_TITLE_CPU_SYS     144
43 #define PERF_TITLE_CPU_IRQ     698
44 
45 typedef enum {
46     PERF_IX_CPU_USER,
47     PERF_IX_CPU_IDLE,
48     PERF_IX_CPU_SYS,
49     PERF_IX_CPU_IRQ,
50     PERF_IX_CPU_MAX
51 } perf_cpu_offsets_t;
52 
53 #define PERF_TITLE_CPUTIME    6
54 #define PERF_TITLE_PAGE_FAULTS 28
55 #define PERF_TITLE_MEM_VSIZE  174
56 #define PERF_TITLE_MEM_SIZE   180
57 #define PERF_TITLE_THREAD_CNT 680
58 #define PERF_TITLE_HANDLE_CNT 952
59 #define PERF_TITLE_PID        784
60 #define PERF_TITLE_PPID       1410
61 #define PERF_TITLE_PRIORITY   682
62 #define PERF_TITLE_START_TIME 684
63 
64 typedef enum {
65     PERF_IX_CPUTIME,
66     PERF_IX_PAGE_FAULTS,
67     PERF_IX_MEM_VSIZE,
68     PERF_IX_MEM_SIZE,
69     PERF_IX_THREAD_CNT,
70     PERF_IX_HANDLE_CNT,
71     PERF_IX_PID,
72     PERF_IX_PPID,
73     PERF_IX_PRIORITY,
74     PERF_IX_START_TIME,
75     PERF_IX_MAX
76 } perf_proc_offsets_t;
77 
78 typedef enum {
79     PERF_IX_DISK_TIME,
80     PERF_IX_DISK_READ_TIME,
81     PERF_IX_DISK_WRITE_TIME,
82     PERF_IX_DISK_READ,
83     PERF_IX_DISK_WRITE,
84     PERF_IX_DISK_READ_BYTES,
85     PERF_IX_DISK_WRITE_BYTES,
86     PERF_IX_DISK_QUEUE,
87     PERF_IX_DISK_MAX
88 } perf_disk_offsets_t;
89 
90 #define PERF_TITLE_DISK_TIME 200 /* % Disk Time */
91 #define PERF_TITLE_DISK_READ_TIME 202 /* % Disk Read Time */
92 #define PERF_TITLE_DISK_WRITE_TIME 204 /* % Disk Write Time */
93 #define PERF_TITLE_DISK_READ  214 /* Disk Reads/sec */
94 #define PERF_TITLE_DISK_WRITE 216 /* Disk Writes/sec */
95 #define PERF_TITLE_DISK_READ_BYTES  220 /* Disk Read Bytes/sec */
96 #define PERF_TITLE_DISK_WRITE_BYTES 222 /* Disk Write Bytes/sec */
97 #define PERF_TITLE_DISK_QUEUE 198 /* Current Disk Queue Length */
98 
99 /*
100  * diff is:
101  *   ExW      -> ExA
102  *   wcounter -> counter
103  */
104 #define MyRegQueryValue() \
105     (USING_WIDE() ? \
106         RegQueryValueExW(sigar->handle, \
107                          wcounter_key, NULL, &type, \
108                          sigar->perfbuf, \
109                          &bytes) : \
110         RegQueryValueExA(sigar->handle, \
111                          counter_key, NULL, &type, \
112                          sigar->perfbuf, \
113                          &bytes))
114 
115 #define PERF_VAL(ix) \
116     perf_offsets[ix] ? \
117         *((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0
118 
119 #define PERF_VAL64(ix) \
120     perf_offsets[ix] ? \
121         *((sigar_uint64_t *)((BYTE *)counter_block + perf_offsets[ix])) : 0
122 
123 /* 1/100ns units to milliseconds */
124 #define NS100_2MSEC(t) ((t) / 10000)
125 
126 #define PERF_VAL_CPU(ix) \
127     NS100_2MSEC(PERF_VAL(ix))
128 
129 #define MS_LOOPBACK_ADAPTER "Microsoft Loopback Adapter"
130 #define NETIF_LA "la"
131 
sigar_FileTimeToTime(FILETIME *ft)132 sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft)
133 {
134     sigar_uint64_t time;
135     time = ft->dwHighDateTime;
136     time = time << 32;
137     time |= ft->dwLowDateTime;
138     time /= 10;
139     time -= EPOCH_DELTA;
140     return time;
141 }
142 
perfbuf_init(sigar_t *sigar)143 static DWORD perfbuf_init(sigar_t *sigar)
144 {
145     if (!sigar->perfbuf) {
146         sigar->perfbuf = malloc(PERFBUF_SIZE);
147         sigar->perfbuf_size = PERFBUF_SIZE;
148     }
149 
150     return sigar->perfbuf_size;
151 }
152 
perfbuf_grow(sigar_t *sigar)153 static DWORD perfbuf_grow(sigar_t *sigar)
154 {
155     sigar->perfbuf_size += PERFBUF_SIZE;
156 
157     sigar->perfbuf =
158         realloc(sigar->perfbuf, sigar->perfbuf_size);
159 
160     return sigar->perfbuf_size;
161 }
162 
get_counter_name(char *key)163 static char *get_counter_name(char *key)
164 {
165     if (strEQ(key, PERF_TITLE_MEM_KEY)) {
166         return "Memory";
167     }
168     else if (strEQ(key, PERF_TITLE_PROC_KEY)) {
169         return "Process";
170     }
171     else if (strEQ(key, PERF_TITLE_CPU_KEY)) {
172         return "Processor";
173     }
174     else if (strEQ(key, PERF_TITLE_DISK_KEY)) {
175         return "LogicalDisk";
176     }
177     else {
178         return key;
179     }
180 }
181 
get_perf_object_inst(sigar_t *sigar, char *counter_key, DWORD inst, DWORD *err)182 static PERF_OBJECT_TYPE *get_perf_object_inst(sigar_t *sigar,
183                                               char *counter_key,
184                                               DWORD inst, DWORD *err)
185 {
186     DWORD retval, type, bytes;
187     WCHAR wcounter_key[MAX_PATH+1];
188     PERF_DATA_BLOCK *block;
189     PERF_OBJECT_TYPE *object;
190 
191     *err = SIGAR_OK;
192 
193     if (USING_WIDE()) {
194         SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key));
195     }
196 
197     bytes = perfbuf_init(sigar);
198 
199     while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) {
200         if (retval == ERROR_MORE_DATA) {
201             bytes = perfbuf_grow(sigar);
202         }
203         else {
204             *err = retval;
205             return NULL;
206         }
207     }
208 
209     block = (PERF_DATA_BLOCK *)sigar->perfbuf;
210     if (block->NumObjectTypes == 0) {
211         counter_key = get_counter_name(counter_key);
212         sigar_strerror_printf(sigar, "No %s counters defined (disabled?)",
213                               counter_key);
214         *err = -1;
215         return NULL;
216     }
217     object = PdhFirstObject(block);
218 
219     /*
220      * only seen on windows 2003 server when pdh.dll
221      * functions are in use by the same process.
222      * confucius say what the fuck.
223      */
224     if (inst && (object->NumInstances == PERF_NO_INSTANCES)) {
225         int i;
226 
227         for (i=0; i<block->NumObjectTypes; i++) {
228             if (object->NumInstances != PERF_NO_INSTANCES) {
229                 return object;
230             }
231             object = PdhNextObject(object);
232         }
233         return NULL;
234     }
235     else {
236         return object;
237     }
238 }
239 
240 #define get_perf_object(sigar, counter_key, err) \
241     get_perf_object_inst(sigar, counter_key, 1, err)
242 
get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem)243 static int get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem)
244 {
245     DWORD status;
246     PERF_OBJECT_TYPE *object =
247         get_perf_object_inst(sigar, PERF_TITLE_MEM_KEY, 0, &status);
248     PERF_INSTANCE_DEFINITION *inst;
249     PERF_COUNTER_DEFINITION *counter;
250     BYTE *data;
251     DWORD i;
252 
253     if (!object) {
254         return status;
255     }
256 
257     data = (BYTE *)((BYTE *)object + object->DefinitionLength);
258 
259     for (i=0, counter = PdhFirstCounter(object);
260          i<object->NumCounters;
261          i++, counter = PdhNextCounter(counter))
262     {
263         DWORD offset = counter->CounterOffset;
264 
265         switch (counter->CounterNameTitleIndex) {
266           case 48: /* "Pages Output/sec" */
267             if (swap) swap->page_out = *((DWORD *)(data + offset));
268             break;
269           case 76: /* "System Cache Resident Bytes" aka file cache */
270             if (mem) {
271                 sigar_uint64_t kern = *((DWORD *)(data + offset));
272                 mem->actual_free = mem->free + kern;
273                 mem->actual_used = mem->used - kern;
274                 return SIGAR_OK;
275             }
276           case 822: /* "Pages Input/sec" */
277             if (swap) swap->page_in = *((DWORD *)(data + offset));
278             break;
279           default:
280             continue;
281         }
282     }
283 
284     return SIGAR_OK;
285 }
286 
get_sysinfo(sigar_t *sigar)287 static void get_sysinfo(sigar_t *sigar)
288 {
289     SYSTEM_INFO sysinfo;
290 
291     GetSystemInfo(&sysinfo);
292 
293     sigar->ncpu = sysinfo.dwNumberOfProcessors;
294     sigar->pagesize = sysinfo.dwPageSize;
295 }
296 
297 /* for C# bindings */
sigar_new(void)298 SIGAR_DECLARE(sigar_t *) sigar_new(void)
299 {
300     sigar_t *sigar;
301     if (sigar_open(&sigar) != SIGAR_OK) {
302         return NULL;
303     }
304     return sigar;
305 }
306 
307 static sigar_wtsapi_t sigar_wtsapi = {
308     "wtsapi32.dll",
309     NULL,
310     { "WTSEnumerateSessionsA", NULL },
311     { "WTSFreeMemory", NULL },
312     { "WTSQuerySessionInformationA", NULL },
313     { NULL, NULL }
314 };
315 
316 static sigar_iphlpapi_t sigar_iphlpapi = {
317     "iphlpapi.dll",
318     NULL,
319     { "GetIpForwardTable", NULL },
320     { "GetIpAddrTable", NULL },
321     { "GetIfTable", NULL },
322     { "GetIfEntry", NULL },
323     { "GetNumberOfInterfaces", NULL },
324     { "GetTcpTable", NULL },
325     { "GetUdpTable", NULL },
326     { "AllocateAndGetTcpExTableFromStack", NULL },
327     { "AllocateAndGetUdpExTableFromStack", NULL },
328     { "GetTcpStatistics", NULL },
329     { "GetNetworkParams", NULL },
330     { "GetAdaptersInfo", NULL },
331     { "GetAdaptersAddresses", NULL },
332     { "GetIpNetTable", NULL },
333     { NULL, NULL }
334 };
335 
336 static sigar_advapi_t sigar_advapi = {
337     "advapi32.dll",
338     NULL,
339     { "ConvertStringSidToSidA", NULL },
340     { "QueryServiceStatusEx", NULL },
341     { NULL, NULL }
342 };
343 
344 static sigar_ntdll_t sigar_ntdll = {
345     "ntdll.dll",
346     NULL,
347     { "NtQuerySystemInformation", NULL },
348     { "NtQueryInformationProcess", NULL },
349     { NULL, NULL }
350 };
351 
352 static sigar_psapi_t sigar_psapi = {
353     "psapi.dll",
354     NULL,
355     { "EnumProcessModules", NULL },
356     { "EnumProcesses", NULL },
357     { "GetModuleFileNameExA", NULL },
358     { NULL, NULL }
359 };
360 
361 static sigar_psapi_t sigar_winsta = {
362     "winsta.dll",
363     NULL,
364     { "WinStationQueryInformationW", NULL },
365     { NULL, NULL }
366 };
367 
368 static sigar_psapi_t sigar_kernel = {
369     "kernel32.dll",
370     NULL,
371     { "GlobalMemoryStatusEx", NULL },
372     { NULL, NULL }
373 };
374 
375 static sigar_mpr_t sigar_mpr = {
376     "mpr.dll",
377     NULL,
378     { "WNetGetConnectionA", NULL },
379     { NULL, NULL }
380 };
381 
382 #define DLLMOD_COPY(name) \
383     memcpy(&(sigar->name), &sigar_##name, sizeof(sigar_##name))
384 
385 #define DLLMOD_INIT(name, all) \
386     sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->name), all)
387 
388 #define DLLMOD_FREE(name) \
389     sigar_dllmod_free((sigar_dll_module_t *)&(sigar->name))
390 
sigar_dllmod_free(sigar_dll_module_t *module)391 static void sigar_dllmod_free(sigar_dll_module_t *module)
392 {
393     if (module->handle) {
394         FreeLibrary(module->handle);
395         module->handle = NULL;
396     }
397 }
398 
sigar_dllmod_init(sigar_t *sigar, sigar_dll_module_t *module, int all)399 static int sigar_dllmod_init(sigar_t *sigar,
400                              sigar_dll_module_t *module,
401                              int all)
402 {
403     sigar_dll_func_t *funcs = &module->funcs[0];
404     int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
405     int rc, success;
406 
407     if (module->handle == INVALID_HANDLE_VALUE) {
408         return ENOENT; /* XXX better rc */
409     }
410 
411     if (module->handle) {
412         return SIGAR_OK;
413     }
414 
415     module->handle = LoadLibrary(module->name);
416     if (!(success = (module->handle ? TRUE : FALSE))) {
417         rc = GetLastError();
418         /* dont try again */
419         module->handle = INVALID_HANDLE_VALUE;
420     }
421 
422     if (is_debug) {
423         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
424                          "LoadLibrary(%s): %s",
425                          module->name,
426                          success ?
427                          "OK" :
428                          sigar_strerror(sigar, rc));
429     }
430 
431     if (!success) {
432         return rc;
433     }
434 
435     while (funcs->name) {
436         funcs->func = GetProcAddress(module->handle, funcs->name);
437 
438         if (!(success = (funcs->func ? TRUE : FALSE))) {
439             rc = GetLastError();
440         }
441 
442         if (is_debug) {
443             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
444                              "GetProcAddress(%s:%s): %s",
445                              module->name, funcs->name,
446                              success ?
447                              "OK" :
448                              sigar_strerror(sigar, rc));
449         }
450 
451         if (all && !success) {
452             return rc;
453         }
454 
455         funcs++;
456     }
457 
458     return SIGAR_OK;
459 }
460 
sigar_wsa_init(sigar_t *sigar)461 int sigar_wsa_init(sigar_t *sigar)
462 {
463     if (sigar->ws_version == 0) {
464         WSADATA data;
465 
466         if (WSAStartup(MAKEWORD(2, 0), &data)) {
467             sigar->ws_error = WSAGetLastError();
468             WSACleanup();
469             return sigar->ws_error;
470         }
471 
472         sigar->ws_version = data.wVersion;
473     }
474 
475     return SIGAR_OK;
476 }
477 
sigar_enable_privilege(char *name)478 static int sigar_enable_privilege(char *name)
479 {
480     int status;
481     HANDLE handle;
482     TOKEN_PRIVILEGES tok;
483 
484     SIGAR_ZERO(&tok);
485 
486     if (!OpenProcessToken(GetCurrentProcess(),
487                           TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
488                           &handle))
489     {
490         return GetLastError();
491     }
492 
493     if (LookupPrivilegeValue(NULL, name,
494                              &tok.Privileges[0].Luid))
495     {
496         tok.PrivilegeCount = 1;
497         tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
498 
499         if (AdjustTokenPrivileges(handle, FALSE, &tok, 0, NULL, 0)) {
500             status = SIGAR_OK;
501         }
502         else {
503             status = GetLastError();
504         }
505     }
506     else {
507         status = GetLastError();
508     }
509 
510     CloseHandle(handle);
511 
512     return status;
513 }
514 
sigar_os_open(sigar_t **sigar_ptr)515 int sigar_os_open(sigar_t **sigar_ptr)
516 {
517     LONG result;
518     HINSTANCE h;
519     OSVERSIONINFO version;
520     int i;
521     sigar_t *sigar;
522 
523     *sigar_ptr = sigar = malloc(sizeof(*sigar));
524     sigar->machine = ""; /* local machine */
525     sigar->using_wide = 0; /*XXX*/
526 
527     sigar->perfbuf = NULL;
528     sigar->perfbuf_size = 0;
529 
530     version.dwOSVersionInfoSize = sizeof(version);
531     GetVersionEx(&version);
532 
533     /*
534      * 4 == NT 4.0
535      * 5 == 2000, XP, 2003 Server
536      */
537     sigar->winnt = (version.dwMajorVersion == 4);
538 
539     if (USING_WIDE_S(sigar)) {
540         WCHAR wmachine[MAX_PATH+1];
541 
542         SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine));
543 
544         result = RegConnectRegistryW(wmachine,
545                                      HKEY_PERFORMANCE_DATA,
546                                      &sigar->handle);
547     }
548     else {
549         result = RegConnectRegistryA(sigar->machine,
550                                      HKEY_PERFORMANCE_DATA,
551                                      &sigar->handle);
552     }
553 
554     get_sysinfo(sigar);
555 
556     DLLMOD_COPY(wtsapi);
557     DLLMOD_COPY(iphlpapi);
558     DLLMOD_COPY(advapi);
559     DLLMOD_COPY(ntdll);
560     DLLMOD_COPY(psapi);
561     DLLMOD_COPY(winsta);
562     DLLMOD_COPY(kernel);
563     DLLMOD_COPY(mpr);
564 
565     sigar->log_level = -1; /* else below segfaults */
566     /* XXX init early for use by javasigar.c */
567     sigar_dllmod_init(sigar,
568                       (sigar_dll_module_t *)&sigar->advapi,
569                       FALSE);
570 
571     sigar->netif_mib_rows = NULL;
572     sigar->netif_addr_rows = NULL;
573     sigar->netif_adapters = NULL;
574     sigar->netif_names = NULL;
575     sigar->pinfo.pid = -1;
576     sigar->ws_version = 0;
577     sigar->lcpu = -1;
578 
579     /* increase process visibility */
580     sigar_enable_privilege(SE_DEBUG_NAME);
581 
582     return result;
583 }
584 
dllmod_init_ntdll(sigar_t *sigar)585 void dllmod_init_ntdll(sigar_t *sigar)
586 {
587     DLLMOD_INIT(ntdll, FALSE);
588 }
589 
sigar_os_close(sigar_t *sigar)590 int sigar_os_close(sigar_t *sigar)
591 {
592     int retval;
593 
594     DLLMOD_FREE(wtsapi);
595     DLLMOD_FREE(iphlpapi);
596     DLLMOD_FREE(advapi);
597     DLLMOD_FREE(ntdll);
598     DLLMOD_FREE(psapi);
599     DLLMOD_FREE(winsta);
600     DLLMOD_FREE(kernel);
601     DLLMOD_FREE(mpr);
602 
603     if (sigar->perfbuf) {
604         free(sigar->perfbuf);
605     }
606 
607     retval = RegCloseKey(sigar->handle);
608 
609     if (sigar->ws_version != 0) {
610         WSACleanup();
611     }
612 
613     if (sigar->netif_mib_rows) {
614         sigar_cache_destroy(sigar->netif_mib_rows);
615     }
616 
617     if (sigar->netif_addr_rows) {
618         sigar_cache_destroy(sigar->netif_addr_rows);
619     }
620 
621     if (sigar->netif_adapters) {
622         sigar_cache_destroy(sigar->netif_adapters);
623     }
624 
625     if (sigar->netif_names) {
626         sigar_cache_destroy(sigar->netif_names);
627     }
628 
629     free(sigar);
630 
631     return retval;
632 }
633 
sigar_os_error_string(sigar_t *sigar, int err)634 char *sigar_os_error_string(sigar_t *sigar, int err)
635 {
636     switch (err) {
637       case SIGAR_NO_SUCH_PROCESS:
638         return "No such process";
639         break;
640     }
641     return NULL;
642 }
643 
644 #define sigar_GlobalMemoryStatusEx \
645     sigar->kernel.memory_status.func
646 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)647 SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
648 {
649     DLLMOD_INIT(kernel, TRUE);
650 
651     if (sigar_GlobalMemoryStatusEx) {
652         MEMORYSTATUSEX memstat;
653 
654         memstat.dwLength = sizeof(memstat);
655 
656         if (!sigar_GlobalMemoryStatusEx(&memstat)) {
657             return GetLastError();
658         }
659 
660         mem->total = memstat.ullTotalPhys;
661         mem->free  = memstat.ullAvailPhys;
662     }
663     else {
664         MEMORYSTATUS memstat;
665         GlobalMemoryStatus(&memstat);
666         mem->total = memstat.dwTotalPhys;
667         mem->free  = memstat.dwAvailPhys;
668     }
669 
670     mem->used = mem->total - mem->free;
671 
672     mem->actual_free = mem->free;
673     mem->actual_used = mem->used;
674     /* set actual_{free,used} */
675     get_mem_counters(sigar, NULL, mem);
676 
677     sigar_mem_calc_ram(sigar, mem);
678 
679     return SIGAR_OK;
680 }
681 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)682 SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
683 {
684     int status;
685     DLLMOD_INIT(kernel, TRUE);
686 
687     if (sigar_GlobalMemoryStatusEx) {
688         MEMORYSTATUSEX memstat;
689 
690         memstat.dwLength = sizeof(memstat);
691 
692         if (!sigar_GlobalMemoryStatusEx(&memstat)) {
693             return GetLastError();
694         }
695 
696         swap->total = memstat.ullTotalPageFile;
697         swap->free  = memstat.ullAvailPageFile;
698     }
699     else {
700         MEMORYSTATUS memstat;
701         GlobalMemoryStatus(&memstat);
702         swap->total = memstat.dwTotalPageFile;
703         swap->free  = memstat.dwAvailPageFile;
704     }
705 
706     swap->used = swap->total - swap->free;
707 
708     if (get_mem_counters(sigar, swap, NULL) != SIGAR_OK) {
709         swap->page_in = SIGAR_FIELD_NOTIMPL;
710         swap->page_out = SIGAR_FIELD_NOTIMPL;
711     }
712 
713     return SIGAR_OK;
714 }
715 
get_cpu_instance(sigar_t *sigar, DWORD *perf_offsets, DWORD *num, DWORD *err)716 static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
717                                                   DWORD *perf_offsets,
718                                                   DWORD *num, DWORD *err)
719 {
720     PERF_OBJECT_TYPE *object = get_perf_object(sigar, PERF_TITLE_CPU_KEY, err);
721     PERF_INSTANCE_DEFINITION *inst;
722     PERF_COUNTER_DEFINITION *counter;
723     DWORD i;
724 
725     if (!object) {
726         return NULL;
727     }
728 
729     for (i=0, counter = PdhFirstCounter(object);
730          i<object->NumCounters;
731          i++, counter = PdhNextCounter(counter))
732     {
733         DWORD offset = counter->CounterOffset;
734 
735         switch (counter->CounterNameTitleIndex) {
736           case PERF_TITLE_CPU_SYS:
737             perf_offsets[PERF_IX_CPU_SYS] = offset;
738             break;
739           case PERF_TITLE_CPU_USER:
740             perf_offsets[PERF_IX_CPU_USER] = offset;
741             break;
742           case PERF_TITLE_CPU_IDLE:
743             perf_offsets[PERF_IX_CPU_IDLE] = offset;
744             break;
745           case PERF_TITLE_CPU_IRQ:
746             perf_offsets[PERF_IX_CPU_IRQ] = offset;
747             break;
748         }
749     }
750 
751     if (num) {
752         *num = object->NumInstances;
753     }
754 
755     return PdhFirstInstance(object);
756 }
757 
758 #define SPPI_MAX 128 /* XXX unhardcode; should move off this api anyhow */
759 
760 #define sigar_NtQuerySystemInformation \
761    sigar->ntdll.query_sys_info.func
762 
get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu, DWORD idx, PERF_COUNTER_BLOCK *counter_block, DWORD *perf_offsets)763 static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu,
764                         DWORD idx,
765                         PERF_COUNTER_BLOCK *counter_block,
766                         DWORD *perf_offsets)
767 {
768     cpu->idle = 0;
769 
770     if (perf_offsets[PERF_IX_CPU_IDLE]) {
771         cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE);
772     }
773     else {
774         /* windows NT and 2000 do not have an Idle counter */
775         DLLMOD_INIT(ntdll, FALSE);
776         if (sigar_NtQuerySystemInformation) {
777             DWORD retval, num;
778             SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
779             /* into the lungs of hell */
780             sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
781                                            &info, sizeof(info), &retval);
782 
783             if (!retval) {
784                 return GetLastError();
785             }
786             num = retval/sizeof(info[0]);
787 
788             if (idx == -1) {
789                 int i;
790                 for (i=0; i<num; i++) {
791                     cpu->idle += NS100_2MSEC(info[i].IdleTime.QuadPart);
792                 }
793             }
794             else if (idx < num) {
795                 cpu->idle = NS100_2MSEC(info[idx].IdleTime.QuadPart);
796             }
797             else {
798                 return ERROR_INVALID_DATA;
799             }
800         }
801         else {
802             return ERROR_INVALID_FUNCTION;
803         }
804     }
805 
806     return SIGAR_OK;
807 }
808 
sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)809 static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)
810 {
811     int status;
812     PERF_INSTANCE_DEFINITION *inst;
813     PERF_COUNTER_BLOCK *counter_block;
814     DWORD perf_offsets[PERF_IX_CPU_MAX], err;
815 
816     SIGAR_ZERO(cpu);
817     memset(&perf_offsets, 0, sizeof(perf_offsets));
818 
819     inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
820 
821     if (!inst) {
822         return err;
823     }
824 
825     /* first instance is total, rest are per-cpu */
826     counter_block = PdhGetCounterBlock(inst);
827 
828     cpu->sys  = PERF_VAL_CPU(PERF_IX_CPU_SYS);
829     cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER);
830     status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
831     cpu->irq = PERF_VAL_CPU(PERF_IX_CPU_IRQ);
832     cpu->nice = 0; /* no nice here */
833     cpu->wait = 0; /*N/A?*/
834     cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait + cpu->irq;
835 
836     if (status != SIGAR_OK) {
837         sigar_log_printf(sigar, SIGAR_LOG_WARN,
838                          "unable to determine idle cpu time: %s",
839                          sigar_strerror(sigar, status));
840     }
841 
842     return SIGAR_OK;
843 }
844 
sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)845 static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)
846 {
847     DWORD retval, num;
848     int i;
849     SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
850     /* into the lungs of hell */
851     sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
852                                    &info, sizeof(info), &retval);
853 
854     if (!retval) {
855         return GetLastError();
856     }
857     num = retval/sizeof(info[0]);
858     SIGAR_ZERO(cpu);
859 
860     for (i=0; i<num; i++) {
861         cpu->idle += NS100_2MSEC(info[i].IdleTime.QuadPart);
862         cpu->user += NS100_2MSEC(info[i].UserTime.QuadPart);
863         cpu->sys  += NS100_2MSEC(info[i].KernelTime.QuadPart -
864                                  info[i].IdleTime.QuadPart);
865         cpu->irq  += NS100_2MSEC(info[i].InterruptTime.QuadPart);
866     }
867     cpu->total = cpu->idle + cpu->user + cpu->sys;
868 
869     return SIGAR_OK;
870 }
871 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)872 SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
873 {
874     DLLMOD_INIT(ntdll, FALSE);
875     if (sigar_NtQuerySystemInformation) {
876         return sigar_cpu_ntsys_get(sigar, cpu);
877     }
878     else {
879         return sigar_cpu_perflib_get(sigar, cpu);
880     }
881 }
882 
sigar_cpu_list_perflib_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)883 static int sigar_cpu_list_perflib_get(sigar_t *sigar,
884                                       sigar_cpu_list_t *cpulist)
885 {
886     int status, i, j;
887     PERF_INSTANCE_DEFINITION *inst;
888     DWORD perf_offsets[PERF_IX_CPU_MAX], num, err;
889     int core_rollup = sigar_cpu_core_rollup(sigar);
890 
891     memset(&perf_offsets, 0, sizeof(perf_offsets));
892 
893     /* first instance is total, rest are per-cpu */
894     inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err);
895 
896     if (!inst) {
897         return err;
898     }
899 
900     if (!sigar->winnt) {
901         /* skip Processor _Total instance (NT doesnt have one) */
902         --num;
903         inst = PdhNextInstance(inst);
904     }
905 
906     sigar_cpu_list_create(cpulist);
907 
908     /* verify there's a counter for each logical cpu */
909     if (core_rollup && (sigar->ncpu != num)) {
910         core_rollup = 0;
911     }
912 
913     for (i=0; i<num; i++) {
914         PERF_COUNTER_BLOCK *counter_block;
915         sigar_cpu_t *cpu;
916 
917         if (core_rollup && (i % sigar->lcpu)) {
918             /* merge times of logical processors */
919             cpu = &cpulist->data[cpulist->number-1];
920         }
921         else {
922             SIGAR_CPU_LIST_GROW(cpulist);
923             cpu = &cpulist->data[cpulist->number++];
924             SIGAR_ZERO(cpu);
925         }
926 
927         counter_block = PdhGetCounterBlock(inst);
928 
929         cpu->sys  += PERF_VAL_CPU(PERF_IX_CPU_SYS);
930         cpu->user += PERF_VAL_CPU(PERF_IX_CPU_USER);
931         cpu->irq  += PERF_VAL_CPU(PERF_IX_CPU_IRQ);
932         get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets);
933         cpu->nice = cpu->wait = 0; /*N/A*/
934 
935         /*XXX adding up too much here if xeon, but not using this atm*/
936         cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->irq;
937 
938         inst = PdhNextInstance(inst);
939     }
940 
941     return SIGAR_OK;
942 }
943 
sigar_cpu_list_ntsys_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)944 static int sigar_cpu_list_ntsys_get(sigar_t *sigar,
945                                     sigar_cpu_list_t *cpulist)
946 {
947     DWORD retval, num;
948     int status, i, j;
949     int core_rollup = sigar_cpu_core_rollup(sigar);
950 
951     SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
952     /* into the lungs of hell */
953     sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
954                           &info, sizeof(info), &retval);
955 
956     if (!retval) {
957         return GetLastError();
958     }
959     num = retval/sizeof(info[0]);
960 
961     sigar_cpu_list_create(cpulist);
962 
963     /* verify there's a counter for each logical cpu */
964     if (core_rollup && (sigar->ncpu != num)) {
965         core_rollup = 0;
966     }
967 
968     for (i=0; i<num; i++) {
969         sigar_cpu_t *cpu;
970         sigar_uint64_t idle, user, sys;
971 
972         if (core_rollup && (i % sigar->lcpu)) {
973             /* merge times of logical processors */
974             cpu = &cpulist->data[cpulist->number-1];
975         }
976         else {
977             SIGAR_CPU_LIST_GROW(cpulist);
978             cpu = &cpulist->data[cpulist->number++];
979             SIGAR_ZERO(cpu);
980         }
981 
982         idle = NS100_2MSEC(info[i].IdleTime.QuadPart);
983         user = NS100_2MSEC(info[i].UserTime.QuadPart);
984         sys  = NS100_2MSEC(info[i].KernelTime.QuadPart -
985                            info[i].IdleTime.QuadPart);
986         cpu->idle += idle;
987         cpu->user += user;
988         cpu->sys  += sys;
989         cpu->nice = cpu->wait = 0; /*N/A*/
990         cpu->total += idle + user + sys;
991     }
992 
993     return SIGAR_OK;
994 }
995 
sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)996 SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar,
997                                       sigar_cpu_list_t *cpulist)
998 {
999     DLLMOD_INIT(ntdll, FALSE);
1000     if (sigar_NtQuerySystemInformation) {
1001         return sigar_cpu_list_ntsys_get(sigar, cpulist);
1002     }
1003     else {
1004         return sigar_cpu_list_perflib_get(sigar, cpulist);
1005     }
1006 }
1007 
1008 #define PERF_TITLE_UPTIME_KEY 674 /* System Up Time */
1009 
sigar_uptime_get(sigar_t *sigar, sigar_uptime_t *uptime)1010 SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar,
1011                                     sigar_uptime_t *uptime)
1012 {
1013     DWORD status;
1014     PERF_OBJECT_TYPE *object =
1015         get_perf_object_inst(sigar, PERF_TITLE_SYS_KEY, 0, &status);
1016     PERF_INSTANCE_DEFINITION *inst;
1017     PERF_COUNTER_DEFINITION *counter;
1018     BYTE *data;
1019     DWORD i;
1020 
1021     if (!object) {
1022         return status;
1023     }
1024 
1025     data = (BYTE *)((BYTE *)object + object->DefinitionLength);
1026 
1027     for (i=0, counter = PdhFirstCounter(object);
1028          i<object->NumCounters;
1029          i++, counter = PdhNextCounter(counter))
1030     {
1031         if (counter->CounterNameTitleIndex == PERF_TITLE_UPTIME_KEY) {
1032             DWORD offset = counter->CounterOffset;
1033             LONGLONG time = object->PerfTime.QuadPart;
1034             LONGLONG freq = object->PerfFreq.QuadPart;
1035             LONGLONG counter = *((LONGLONG *)(data + offset));
1036             uptime->uptime = (time - counter) / freq;
1037             return SIGAR_OK;
1038         }
1039     }
1040 
1041     /* http://msdn.microsoft.com/en-us/library/ms724408.aspx */
1042     return GetTickCount() / 1000;
1043 }
1044 
1045 /*
1046  * there is no api for this info.
1047  * closest i've seen is enumerating the entire process table
1048  * and calculating an average based on process times.
1049  */
sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg)1050 SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar,
1051                                      sigar_loadavg_t *loadavg)
1052 {
1053     return SIGAR_ENOTIMPL;
1054 }
1055 
1056 #define get_process_object(sigar, err) \
1057     get_perf_object(sigar, PERF_TITLE_PROC_KEY, err)
1058 
sigar_proc_list_get_perf(sigar_t *sigar, sigar_proc_list_t *proclist)1059 static int sigar_proc_list_get_perf(sigar_t *sigar,
1060                                     sigar_proc_list_t *proclist)
1061 {
1062 
1063     PERF_OBJECT_TYPE *object;
1064     PERF_INSTANCE_DEFINITION *inst;
1065     PERF_COUNTER_DEFINITION *counter;
1066     DWORD i, err;
1067     DWORD perf_offsets[PERF_IX_MAX];
1068 
1069     perf_offsets[PERF_IX_PID] = 0;
1070 
1071     object = get_process_object(sigar, &err);
1072 
1073     if (!object) {
1074         return err;
1075     }
1076 
1077     /*
1078      * note we assume here:
1079      *  block->NumObjectTypes == 1
1080      *  object->ObjectNameTitleIndex == PERF_TITLE_PROC
1081      *
1082      * which should always be the case.
1083      */
1084 
1085     for (i=0, counter = PdhFirstCounter(object);
1086          i<object->NumCounters;
1087          i++, counter = PdhNextCounter(counter))
1088     {
1089         DWORD offset = counter->CounterOffset;
1090 
1091         switch (counter->CounterNameTitleIndex) {
1092           case PERF_TITLE_PID:
1093             perf_offsets[PERF_IX_PID] = offset;
1094             break;
1095         }
1096     }
1097 
1098     for (i=0, inst = PdhFirstInstance(object);
1099          i<object->NumInstances;
1100          i++, inst = PdhNextInstance(inst))
1101     {
1102         PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
1103         DWORD pid = PERF_VAL(PERF_IX_PID);
1104 
1105         if (pid == 0) {
1106             continue; /* dont include the system Idle process */
1107         }
1108 
1109         SIGAR_PROC_LIST_GROW(proclist);
1110 
1111         proclist->data[proclist->number++] = pid;
1112     }
1113 
1114     return SIGAR_OK;
1115 }
1116 
1117 #define sigar_EnumProcesses \
1118     sigar->psapi.enum_processes.func
1119 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)1120 int sigar_os_proc_list_get(sigar_t *sigar,
1121                            sigar_proc_list_t *proclist)
1122 {
1123     DLLMOD_INIT(psapi, FALSE);
1124 
1125     if (sigar_EnumProcesses) {
1126         DWORD retval, *pids;
1127         DWORD size = 0, i;
1128 
1129         do {
1130             /* re-use the perfbuf */
1131             if (size == 0) {
1132                 size = perfbuf_init(sigar);
1133             }
1134             else {
1135                 size = perfbuf_grow(sigar);
1136             }
1137 
1138             if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf,
1139                                      sigar->perfbuf_size,
1140                                      &retval))
1141             {
1142                 return GetLastError();
1143             }
1144         } while (retval == sigar->perfbuf_size); //unlikely
1145 
1146         pids = (DWORD *)sigar->perfbuf;
1147 
1148         size = retval / sizeof(DWORD);
1149 
1150         for (i=0; i<size; i++) {
1151             DWORD pid = pids[i];
1152             if (pid == 0) {
1153                 continue; /* dont include the system Idle process */
1154             }
1155             SIGAR_PROC_LIST_GROW(proclist);
1156             proclist->data[proclist->number++] = pid;
1157         }
1158 
1159         return SIGAR_OK;
1160     }
1161     else {
1162         return sigar_proc_list_get_perf(sigar, proclist);
1163     }
1164 }
1165 
1166 #define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
1167 
open_process(sigar_pid_t pid)1168 static HANDLE open_process(sigar_pid_t pid)
1169 {
1170     return OpenProcess(PROCESS_DAC, 0, (DWORD)pid);
1171 }
1172 
1173 /*
1174  * Pretty good explanation of counters:
1175  * http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory
1176  */
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)1177 SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
1178                                       sigar_proc_mem_t *procmem)
1179 {
1180     int status = get_proc_info(sigar, pid);
1181     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1182 
1183     if (status != SIGAR_OK) {
1184         return status;
1185     }
1186 
1187     procmem->size     = pinfo->size;     /* "Virtual Bytes" */
1188     procmem->resident = pinfo->resident; /* "Working Set" */
1189     procmem->share    = SIGAR_FIELD_NOTIMPL;
1190     procmem->page_faults  = pinfo->page_faults;
1191     procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
1192     procmem->major_faults = SIGAR_FIELD_NOTIMPL;
1193 
1194     return SIGAR_OK;
1195 }
1196 
1197 #define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY)
1198 
1199 SIGAR_DECLARE(int)
sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_cred_name_t *proccredname)1200 sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid,
1201                          sigar_proc_cred_name_t *proccredname)
1202 {
1203     HANDLE proc, token;
1204     DWORD len;
1205     int success;
1206     TOKEN_USER *user = NULL;
1207     TOKEN_PRIMARY_GROUP *group = NULL;
1208     SID_NAME_USE type;
1209     char domain[SIGAR_CRED_NAME_MAX];
1210 
1211     /* XXX cache lookup */
1212 
1213     if (!(proc = open_process(pid))) {
1214         return GetLastError();
1215     }
1216 
1217     if (!OpenProcessToken(proc, TOKEN_DAC, &token)) {
1218         CloseHandle(proc);
1219         return GetLastError();
1220     }
1221 
1222     CloseHandle(proc);
1223 
1224     success =
1225         !GetTokenInformation(token, TokenUser, NULL, 0, &len) &&
1226         (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1227         (user = malloc(len)) &&
1228         GetTokenInformation(token, TokenUser, user, len, &len);
1229 
1230     if (success) {
1231         DWORD domain_len = sizeof(domain);
1232         DWORD user_len = sizeof(proccredname->user);
1233 
1234         success = LookupAccountSid(NULL, user->User.Sid,
1235                                    proccredname->user, &user_len,
1236                                    domain, &domain_len, &type);
1237     }
1238 
1239     if (user != NULL) {
1240         free(user);
1241     }
1242     if (!success) {
1243         CloseHandle(token);
1244         return GetLastError();
1245     }
1246 
1247     success =
1248         !GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &len) &&
1249         (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1250         (group = malloc(len)) &&
1251         GetTokenInformation(token, TokenPrimaryGroup, group, len, &len);
1252 
1253     if (success) {
1254         DWORD domain_len = sizeof(domain);
1255         DWORD group_len = sizeof(proccredname->group);
1256 
1257         success = LookupAccountSid(NULL, group->PrimaryGroup,
1258                                    proccredname->group, &group_len,
1259                                    domain, &domain_len, &type);
1260     }
1261 
1262     if (group != NULL) {
1263         free(group);
1264     }
1265 
1266     CloseHandle(token);
1267 
1268     if (!success) {
1269         return GetLastError();
1270     }
1271 
1272     return SIGAR_OK;
1273 }
1274 
sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_cred_t *proccred)1275 SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
1276                                        sigar_proc_cred_t *proccred)
1277 {
1278     return SIGAR_ENOTIMPL;
1279 }
1280 
1281 #define FILETIME2MSEC(ft) \
1282 	NS100_2MSEC((((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime))
1283 
sigar_time_now_millis(void)1284 sigar_int64_t sigar_time_now_millis(void)
1285 {
1286     SYSTEMTIME st;
1287     FILETIME time;
1288 
1289     GetSystemTime(&st);
1290     SystemTimeToFileTime(&st, &time);
1291 
1292     return sigar_FileTimeToTime(&time) / 1000;
1293 }
1294 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)1295 SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
1296                                        sigar_proc_time_t *proctime)
1297 {
1298     HANDLE proc = open_process(pid);
1299     FILETIME start_time, exit_time, system_time, user_time;
1300     int status = ERROR_SUCCESS;
1301 
1302     if (!proc) {
1303         return GetLastError();
1304     }
1305 
1306     if (!GetProcessTimes(proc,
1307                          &start_time, &exit_time,
1308                          &system_time, &user_time))
1309     {
1310         status = GetLastError();
1311     }
1312 
1313     CloseHandle(proc);
1314 
1315     if (status != ERROR_SUCCESS) {
1316         return status;
1317     }
1318 
1319     if (start_time.dwHighDateTime) {
1320         proctime->start_time =
1321             sigar_FileTimeToTime(&start_time) / 1000;
1322     }
1323     else {
1324         proctime->start_time = 0;
1325     }
1326 
1327     proctime->user = FILETIME2MSEC(user_time);
1328     proctime->sys  = FILETIME2MSEC(system_time);
1329     proctime->total = proctime->user + proctime->sys;
1330 
1331     return SIGAR_OK;
1332 }
1333 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)1334 SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
1335 					sigar_proc_state_t *procstate)
1336 {
1337     int status = get_proc_info(sigar, pid);
1338     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1339 
1340     if (status != SIGAR_OK) {
1341         return status;
1342     }
1343 
1344     memcpy(procstate->name, pinfo->name, sizeof(procstate->name));
1345     procstate->state = pinfo->state;
1346     procstate->ppid = pinfo->ppid;
1347     procstate->priority = pinfo->priority;
1348     procstate->nice = SIGAR_FIELD_NOTIMPL;
1349     procstate->tty =  SIGAR_FIELD_NOTIMPL;
1350     procstate->threads = pinfo->threads;
1351     procstate->processor = SIGAR_FIELD_NOTIMPL;
1352 
1353     return SIGAR_OK;
1354 }
1355 
get_proc_info(sigar_t *sigar, sigar_pid_t pid)1356 int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
1357 {
1358     PERF_OBJECT_TYPE *object;
1359     PERF_INSTANCE_DEFINITION *inst;
1360     PERF_COUNTER_DEFINITION *counter;
1361     DWORD i, err;
1362     DWORD perf_offsets[PERF_IX_MAX];
1363     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1364     time_t timenow = time(NULL);
1365 
1366     if (pinfo->pid == pid) {
1367         if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) {
1368             return SIGAR_OK;
1369         }
1370     }
1371 
1372     memset(&perf_offsets, 0, sizeof(perf_offsets));
1373 
1374     object = get_process_object(sigar, &err);
1375 
1376     if (object == NULL) {
1377         return err;
1378     }
1379 
1380     pinfo->pid = pid;
1381     pinfo->mtime = timenow;
1382 
1383     /*
1384      * note we assume here:
1385      *  block->NumObjectTypes == 1
1386      *  object->ObjectNameTitleIndex == PERF_TITLE_PROC
1387      *
1388      * which should always be the case.
1389      */
1390 
1391     for (i=0, counter = PdhFirstCounter(object);
1392          i<object->NumCounters;
1393          i++, counter = PdhNextCounter(counter))
1394     {
1395         DWORD offset = counter->CounterOffset;
1396 
1397         switch (counter->CounterNameTitleIndex) {
1398           case PERF_TITLE_CPUTIME:
1399             perf_offsets[PERF_IX_CPUTIME] = offset;
1400             break;
1401           case PERF_TITLE_PAGE_FAULTS:
1402             perf_offsets[PERF_IX_PAGE_FAULTS] = offset;
1403             break;
1404           case PERF_TITLE_MEM_VSIZE:
1405             assert(counter->CounterSize >= 8);
1406             perf_offsets[PERF_IX_MEM_VSIZE] = offset;
1407             break;
1408           case PERF_TITLE_MEM_SIZE:
1409             assert(counter->CounterSize >= 8);
1410             perf_offsets[PERF_IX_MEM_SIZE] = offset;
1411             break;
1412           case PERF_TITLE_THREAD_CNT:
1413             perf_offsets[PERF_IX_THREAD_CNT] = offset;
1414             break;
1415           case PERF_TITLE_HANDLE_CNT:
1416             perf_offsets[PERF_IX_HANDLE_CNT] = offset;
1417             break;
1418           case PERF_TITLE_PID:
1419             perf_offsets[PERF_IX_PID] = offset;
1420             break;
1421           case PERF_TITLE_PPID:
1422             perf_offsets[PERF_IX_PPID] = offset;
1423             break;
1424           case PERF_TITLE_PRIORITY:
1425             perf_offsets[PERF_IX_PRIORITY] = offset;
1426             break;
1427           case PERF_TITLE_START_TIME:
1428             perf_offsets[PERF_IX_START_TIME] = offset;
1429             break;
1430         }
1431     }
1432 
1433     for (i=0, inst = PdhFirstInstance(object);
1434          i<object->NumInstances;
1435          i++, inst = PdhNextInstance(inst))
1436     {
1437         PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
1438         sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID);
1439 
1440         if (this_pid != pid) {
1441             continue;
1442         }
1443 
1444         pinfo->state = 'R'; /* XXX? */
1445         SIGAR_W2A(PdhInstanceName(inst),
1446                   pinfo->name, sizeof(pinfo->name));
1447 
1448         pinfo->size     = PERF_VAL64(PERF_IX_MEM_VSIZE);
1449         pinfo->resident = PERF_VAL64(PERF_IX_MEM_SIZE);
1450         pinfo->ppid     = PERF_VAL(PERF_IX_PPID);
1451         pinfo->priority = PERF_VAL(PERF_IX_PRIORITY);
1452         pinfo->handles  = PERF_VAL(PERF_IX_HANDLE_CNT);
1453         pinfo->threads  = PERF_VAL(PERF_IX_THREAD_CNT);
1454         pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS);
1455 
1456         return SIGAR_OK;
1457     }
1458 
1459     return SIGAR_NO_SUCH_PROCESS;
1460 }
1461 
sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_args_t *procargs)1462 static int sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
1463                                       sigar_proc_args_t *procargs)
1464 {
1465     int status;
1466     char cmdline[SIGAR_CMDLINE_MAX], *ptr = cmdline, *arg;
1467     HANDLE proc = open_process(pid);
1468 
1469     if (proc) {
1470         status = sigar_proc_args_peb_get(sigar, proc, procargs);
1471 
1472         CloseHandle(proc);
1473 
1474         if (status == SIGAR_OK) {
1475             return status;
1476         }
1477     }
1478 
1479     /* likely we are 32-bit, pid process is 64-bit */
1480     status = sigar_proc_args_wmi_get(sigar, pid, procargs);
1481     if (status == ERROR_NOT_FOUND) {
1482         status = SIGAR_NO_SUCH_PROCESS;
1483     }
1484     return status;
1485 }
1486 
sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_args_t *procargs)1487 int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
1488                           sigar_proc_args_t *procargs)
1489 {
1490     if (pid == sigar->pid) {
1491         return sigar_parse_proc_args(sigar, NULL, procargs);
1492     }
1493     else {
1494         return sigar_remote_proc_args_get(sigar, pid, procargs);
1495     }
1496 }
1497 
sigar_proc_env_parse(UCHAR *ptr, sigar_proc_env_t *procenv, int multi)1498 static int sigar_proc_env_parse(UCHAR *ptr, sigar_proc_env_t *procenv,
1499                                 int multi)
1500 {
1501     while (*ptr) {
1502         UCHAR *val;
1503         int klen, vlen, status;
1504         char key[128]; /* XXX is there a max key size? */
1505 
1506         if (*ptr == '=') {
1507             ptr += strlen(ptr)+1;
1508             continue;
1509         }
1510 
1511         val = strchr(ptr, '=');
1512 
1513         if (val == NULL) {
1514             break; /*XXX*/
1515         }
1516 
1517         klen = val - ptr;
1518         SIGAR_SSTRCPY(key, ptr);
1519         key[klen] = '\0';
1520         ++val;
1521 
1522         vlen = strlen(val);
1523 
1524         status = procenv->env_getter(procenv->data,
1525                                      key, klen, val, vlen);
1526 
1527         if (status != SIGAR_OK) {
1528             /* not an error; just stop iterating */
1529             return status;
1530         }
1531 
1532         if (!multi) {
1533             break; /* caller only provided 1 key=val pair */
1534         }
1535 
1536         ptr += klen + 1 + vlen + 1;
1537     }
1538 
1539     return SIGAR_OK;
1540 }
1541 
sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_env_t *procenv)1542 static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
1543                                     sigar_proc_env_t *procenv)
1544 {
1545     UCHAR *env = (UCHAR*)GetEnvironmentStrings();
1546 
1547     sigar_proc_env_parse(env, procenv, TRUE);
1548 
1549     FreeEnvironmentStrings(env);
1550 
1551     return SIGAR_OK;
1552 }
1553 
sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_env_t *procenv)1554 static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
1555                                      sigar_proc_env_t *procenv)
1556 {
1557     int status;
1558     HANDLE proc = open_process(pid);
1559     WCHAR env[4096];
1560 
1561     if (!proc) {
1562         return GetLastError();
1563     }
1564 
1565     status = sigar_proc_env_peb_get(sigar, proc, env, sizeof(env));
1566 
1567     CloseHandle(proc);
1568 
1569     if (status == SIGAR_OK) {
1570         LPBYTE ptr = (LPBYTE)env;
1571         DWORD size = sizeof(env);
1572         UCHAR ent[4096];
1573 
1574         while ((size > 0) && (*ptr != L'\0')) {
1575             DWORD len = (wcslen((LPWSTR)ptr) + 1) * sizeof(WCHAR);
1576             /* multi=FALSE so no need to: memset(ent, '\0', sizeof(ent)) */
1577             SIGAR_W2A((WCHAR *)ptr, ent, sizeof(ent));
1578             if (sigar_proc_env_parse(ent, procenv, FALSE) != SIGAR_OK) {
1579                 break;
1580             }
1581             size -= len;
1582             ptr += len;
1583         }
1584     }
1585 
1586     return status;
1587 }
1588 
sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_env_t *procenv)1589 SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
1590                                       sigar_proc_env_t *procenv)
1591 {
1592     if (pid == sigar->pid) {
1593         if (procenv->type == SIGAR_PROC_ENV_KEY) {
1594             char value[32767]; /* max size from msdn docs */
1595             DWORD retval =
1596                 GetEnvironmentVariable(procenv->key, value, sizeof(value));
1597 
1598             if (retval == 0) {
1599                 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
1600                     return SIGAR_OK;
1601                 }
1602                 return GetLastError();
1603             }
1604             else if (retval > sizeof(value)) {
1605                 /* XXX shouldnt happen */
1606                 return GetLastError();
1607             }
1608 
1609             procenv->env_getter(procenv->data,
1610                                 procenv->key, procenv->klen,
1611                                 value, retval);
1612             return SIGAR_OK;
1613         }
1614         else {
1615             return sigar_local_proc_env_get(sigar, pid, procenv);
1616         }
1617     }
1618     else {
1619         return sigar_remote_proc_env_get(sigar, pid, procenv);
1620     }
1621 }
1622 
sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_fd_t *procfd)1623 SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
1624                                      sigar_proc_fd_t *procfd)
1625 {
1626     int status;
1627     sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
1628 
1629     pinfo->pid = -1; /* force update */
1630     if ((status = get_proc_info(sigar, pid)) != SIGAR_OK) {
1631         return status;
1632     }
1633 
1634     procfd->total = pinfo->handles;
1635 
1636     return SIGAR_OK;
1637 }
1638 
sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_exe_t *procexe)1639 SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
1640                                       sigar_proc_exe_t *procexe)
1641 {
1642     int status = SIGAR_OK;
1643     HANDLE proc = open_process(pid);
1644 
1645     if (!proc) {
1646         return GetLastError();
1647     }
1648 
1649     status = sigar_proc_exe_peb_get(sigar, proc, procexe);
1650     if (procexe->name[0] == '\0') {
1651         /* likely we are 32-bit, pid process is 64-bit */
1652         /* procexe->cwd[0] = XXX where else can we try? */
1653         status = sigar_proc_exe_wmi_get(sigar, pid, procexe);
1654         if (status == ERROR_NOT_FOUND) {
1655             status = SIGAR_NO_SUCH_PROCESS;
1656         }
1657     }
1658 
1659     if (procexe->cwd[0] != '\0') {
1660         /* strip trailing '\' */
1661         int len = strlen(procexe->cwd);
1662         if (procexe->cwd[len-1] == '\\') {
1663             procexe->cwd[len-1] = '\0';
1664         }
1665         /* uppercase driver letter */
1666         procexe->cwd[0] = toupper(procexe->cwd[0]);
1667         /* e.g. C:\ */
1668         strncpy(procexe->root, procexe->cwd, 3);
1669         procexe->root[3] = '\0';
1670     }
1671     else {
1672         procexe->root[0] = '\0';
1673     }
1674 
1675     if (procexe->name[0] != '\0') {
1676         /* uppercase driver letter */
1677         procexe->name[0] = toupper(procexe->name[0]);
1678     }
1679 
1680     CloseHandle(proc);
1681 
1682     return status;
1683 }
1684 
1685 #define sigar_EnumProcessModules \
1686     sigar->psapi.enum_modules.func
1687 
1688 #define sigar_GetModuleFileNameEx \
1689     sigar->psapi.get_module_name.func
1690 
sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_modules_t *procmods)1691 SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
1692                                           sigar_proc_modules_t *procmods)
1693 {
1694     HANDLE proc;
1695     HMODULE modules[1024];
1696     DWORD size = 0;
1697     unsigned int i;
1698 
1699     if (DLLMOD_INIT(psapi, TRUE) != SIGAR_OK) {
1700         return SIGAR_ENOTIMPL;
1701     }
1702 
1703     if (!(proc = open_process(pid))) {
1704         return GetLastError();
1705     }
1706 
1707     if (!sigar_EnumProcessModules(proc, modules, sizeof(modules), &size)) {
1708         CloseHandle(proc);
1709         return GetLastError();
1710     }
1711 
1712     for (i=0; i<(size/sizeof(HMODULE)); i++) {
1713         int status;
1714         char name[MAX_PATH];
1715 
1716         if (!sigar_GetModuleFileNameEx(proc, modules[i],
1717                                        name, sizeof(name)))
1718         {
1719             continue;
1720         }
1721 
1722         status = procmods->module_getter(procmods->data,
1723                                          name, strlen(name));
1724 
1725         if (status != SIGAR_OK) {
1726             /* not an error; just stop iterating */
1727             break;
1728         }
1729     }
1730 
1731     CloseHandle(proc);
1732 
1733     return SIGAR_OK;
1734 }
1735 
1736 #define FT2INT64(ft) \
1737   ((__int64)((__int64)(ft).dwHighDateTime << 32 | \
1738              (__int64)(ft).dwLowDateTime))
1739 
sigar_thread_cpu_get(sigar_t *sigar, sigar_uint64_t id, sigar_thread_cpu_t *cpu)1740 SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar,
1741                                         sigar_uint64_t id,
1742                                         sigar_thread_cpu_t *cpu)
1743 {
1744     FILETIME start, exit, sys, user;
1745     DWORD retval;
1746 
1747     if (id != 0) {
1748         return SIGAR_ENOTIMPL;
1749     }
1750 
1751     retval = GetThreadTimes(GetCurrentThread(),
1752                             &start, &exit, &sys, &user);
1753 
1754     if (retval == 0) {
1755         return GetLastError();
1756     }
1757 
1758     cpu->user  = FT2INT64(user) * 100;
1759     cpu->sys   = FT2INT64(sys)  * 100;
1760     cpu->total = (FT2INT64(user) + FT2INT64(sys)) * 100;
1761 
1762     return SIGAR_OK;
1763 }
1764 
sigar_os_fs_type_get(sigar_file_system_t *fsp)1765 int sigar_os_fs_type_get(sigar_file_system_t *fsp)
1766 {
1767     return fsp->type;
1768 }
1769 
1770 #ifndef FILE_READ_ONLY_VOLUME
1771 #define FILE_READ_ONLY_VOLUME 0x00080000
1772 #endif
1773 #ifndef FILE_NAMED_STREAMS
1774 #define FILE_NAMED_STREAMS 0x00040000
1775 #endif
1776 #ifndef FILE_SEQUENTIAL_WRITE_ONCE
1777 #define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
1778 #endif
1779 #ifndef FILE_SUPPORTS_TRANSACTIONS
1780 #define FILE_SUPPORTS_TRANSACTIONS 0x00200000
1781 #endif
1782 
get_fs_options(char *opts, int osize, long flags)1783 static void get_fs_options(char *opts, int osize, long flags)
1784 {
1785     *opts = '\0';
1786     if (flags & FILE_READ_ONLY_VOLUME)        strncat(opts, "ro", osize);
1787     else                                      strncat(opts, "rw", osize);
1788 #if 0 /*XXX*/
1789     if (flags & FILE_CASE_PRESERVED_NAMES)    strncat(opts, ",casepn", osize);
1790     if (flags & FILE_CASE_SENSITIVE_SEARCH)   strncat(opts, ",casess", osize);
1791     if (flags & FILE_FILE_COMPRESSION)        strncat(opts, ",fcomp", osize);
1792     if (flags & FILE_NAMED_STREAMS)           strncat(opts, ",streams", osize);
1793     if (flags & FILE_PERSISTENT_ACLS)         strncat(opts, ",acls", osize);
1794     if (flags & FILE_SEQUENTIAL_WRITE_ONCE)   strncat(opts, ",wronce", osize);
1795     if (flags & FILE_SUPPORTS_ENCRYPTION)     strncat(opts, ",efs", osize);
1796     if (flags & FILE_SUPPORTS_OBJECT_IDS)     strncat(opts, ",oids", osize);
1797     if (flags & FILE_SUPPORTS_REPARSE_POINTS) strncat(opts, ",reparse", osize);
1798     if (flags & FILE_SUPPORTS_SPARSE_FILES)   strncat(opts, ",sparse", osize);
1799     if (flags & FILE_SUPPORTS_TRANSACTIONS)   strncat(opts, ",trans", osize);
1800     if (flags & FILE_UNICODE_ON_DISK)         strncat(opts, ",unicode", osize);
1801     if (flags & FILE_VOLUME_IS_COMPRESSED)    strncat(opts, ",vcomp", osize);
1802     if (flags & FILE_VOLUME_QUOTAS)           strncat(opts, ",quota", osize);
1803 #endif
1804 }
1805 
1806 #define sigar_WNetGetConnection \
1807     sigar->mpr.get_net_connection.func
1808 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)1809 SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar,
1810                                               sigar_file_system_list_t *fslist)
1811 {
1812     char name[256];
1813     char *ptr = name;
1814     /* XXX: hmm, Find{First,Next}Volume not available in my sdk */
1815     DWORD len = GetLogicalDriveStringsA(sizeof(name), name);
1816 
1817     DLLMOD_INIT(mpr, TRUE);
1818 
1819     if (len == 0) {
1820         return GetLastError();
1821     }
1822 
1823     sigar_file_system_list_create(fslist);
1824 
1825     while (*ptr) {
1826         sigar_file_system_t *fsp;
1827         DWORD flags, serialnum=0;
1828         char fsname[1024];
1829         UINT drive_type = GetDriveType(ptr);
1830         int type;
1831 
1832         switch (drive_type) {
1833           case DRIVE_FIXED:
1834             type = SIGAR_FSTYPE_LOCAL_DISK;
1835             break;
1836           case DRIVE_REMOTE:
1837             type = SIGAR_FSTYPE_NETWORK;
1838             break;
1839           case DRIVE_CDROM:
1840             type = SIGAR_FSTYPE_CDROM;
1841             break;
1842           case DRIVE_RAMDISK:
1843             type = SIGAR_FSTYPE_RAM_DISK;
1844             break;
1845           case DRIVE_REMOVABLE:
1846             /* skip floppy, usb, etc. drives */
1847             ptr += strlen(ptr)+1;
1848             continue;
1849           default:
1850             type = SIGAR_FSTYPE_NONE;
1851             break;
1852         }
1853 
1854         fsname[0] = '\0';
1855 
1856         GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL,
1857                              &flags, fsname, sizeof(fsname));
1858 
1859         if (!serialnum && (drive_type == DRIVE_FIXED)) {
1860             ptr += strlen(ptr)+1;
1861             continue; /* ignore unformatted partitions */
1862         }
1863 
1864         SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
1865 
1866         fsp = &fslist->data[fslist->number++];
1867 
1868         fsp->type = type;
1869         SIGAR_SSTRCPY(fsp->dir_name, ptr);
1870         SIGAR_SSTRCPY(fsp->dev_name, ptr);
1871 
1872         if ((drive_type == DRIVE_REMOTE) && sigar_WNetGetConnection) {
1873             DWORD len = sizeof(fsp->dev_name);
1874             char drive[3] = {'\0', ':', '\0'}; /* e.g. "X:" w/o trailing "\" */
1875             drive[0] = fsp->dir_name[0];
1876             sigar_WNetGetConnection(drive, fsp->dev_name, &len);
1877             /* ignoring failure, leaving dev_name as dir_name */
1878         }
1879 
1880         /* we set fsp->type, just looking up sigar.c:fstype_names[type] */
1881         sigar_fs_type_get(fsp);
1882 
1883         if (*fsname == '\0') {
1884             SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name);
1885         }
1886         else {
1887             SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */
1888         }
1889 
1890         get_fs_options(fsp->options, sizeof(fsp->options)-1, flags);
1891 
1892         ptr += strlen(ptr)+1;
1893     }
1894 
1895     return SIGAR_OK;
1896 }
1897 
get_disk_instance(sigar_t *sigar, DWORD *perf_offsets, DWORD *num, DWORD *err)1898 static PERF_INSTANCE_DEFINITION *get_disk_instance(sigar_t *sigar,
1899                                                    DWORD *perf_offsets,
1900                                                    DWORD *num, DWORD *err)
1901 {
1902     PERF_OBJECT_TYPE *object =
1903         get_perf_object(sigar, PERF_TITLE_DISK_KEY, err);
1904     PERF_INSTANCE_DEFINITION *inst;
1905     PERF_COUNTER_DEFINITION *counter;
1906     DWORD i, found=0;
1907 
1908     if (!object) {
1909         return NULL;
1910     }
1911 
1912     for (i=0, counter = PdhFirstCounter(object);
1913          i<object->NumCounters;
1914          i++, counter = PdhNextCounter(counter))
1915     {
1916         DWORD offset = counter->CounterOffset;
1917 
1918         switch (counter->CounterNameTitleIndex) {
1919           case PERF_TITLE_DISK_TIME:
1920             perf_offsets[PERF_IX_DISK_TIME] = offset;
1921             found = 1;
1922             break;
1923           case PERF_TITLE_DISK_READ_TIME:
1924             perf_offsets[PERF_IX_DISK_READ_TIME] = offset;
1925             found = 1;
1926             break;
1927           case PERF_TITLE_DISK_WRITE_TIME:
1928             perf_offsets[PERF_IX_DISK_WRITE_TIME] = offset;
1929             found = 1;
1930             break;
1931           case PERF_TITLE_DISK_READ:
1932             perf_offsets[PERF_IX_DISK_READ] = offset;
1933             found = 1;
1934             break;
1935           case PERF_TITLE_DISK_WRITE:
1936             perf_offsets[PERF_IX_DISK_WRITE] = offset;
1937             found = 1;
1938             break;
1939           case PERF_TITLE_DISK_READ_BYTES:
1940             perf_offsets[PERF_IX_DISK_READ_BYTES] = offset;
1941             found = 1;
1942             break;
1943           case PERF_TITLE_DISK_WRITE_BYTES:
1944             perf_offsets[PERF_IX_DISK_WRITE_BYTES] = offset;
1945             found = 1;
1946             break;
1947           case PERF_TITLE_DISK_QUEUE:
1948             perf_offsets[PERF_IX_DISK_QUEUE] = offset;
1949             found = 1;
1950             break;
1951         }
1952     }
1953 
1954     if (!found) {
1955         *err = ENOENT;
1956         return NULL;
1957     }
1958 
1959     if (num) {
1960         *num = object->NumInstances;
1961     }
1962 
1963     return PdhFirstInstance(object);
1964 }
1965 
sigar_disk_usage_get(sigar_t *sigar, const char *dirname, sigar_disk_usage_t *disk)1966 SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar,
1967                                         const char *dirname,
1968                                         sigar_disk_usage_t *disk)
1969 {
1970     DWORD i, err;
1971     PERF_OBJECT_TYPE *object =
1972         get_perf_object(sigar, PERF_TITLE_DISK_KEY, &err);
1973     PERF_INSTANCE_DEFINITION *inst;
1974     PERF_COUNTER_DEFINITION *counter;
1975     DWORD perf_offsets[PERF_IX_DISK_MAX];
1976 
1977     SIGAR_DISK_STATS_INIT(disk);
1978 
1979     if (!object) {
1980         return err;
1981     }
1982 
1983     memset(&perf_offsets, 0, sizeof(perf_offsets));
1984     inst = get_disk_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
1985 
1986     if (!inst) {
1987         return err;
1988     }
1989 
1990     for (i=0, inst = PdhFirstInstance(object);
1991          i<object->NumInstances;
1992          i++, inst = PdhNextInstance(inst))
1993     {
1994         char drive[MAX_PATH];
1995         PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
1996         wchar_t *name = (wchar_t *)((BYTE *)inst + inst->NameOffset);
1997 
1998         SIGAR_W2A(name, drive, sizeof(drive));
1999 
2000         if (sigar_isdigit(*name)) {
2001             char *ptr = strchr(drive, ' '); /* 2000 Server "0 C:" */
2002 
2003             if (ptr) {
2004                 ++ptr;
2005                 SIGAR_SSTRCPY(drive, ptr);
2006             }
2007             else {
2008                 /* XXX NT is a number only "0", how to map? */
2009             }
2010         }
2011 
2012         if (strnEQ(drive, dirname, 2)) {
2013             disk->time   = PERF_VAL(PERF_IX_DISK_TIME);
2014             disk->rtime  = PERF_VAL(PERF_IX_DISK_READ_TIME);
2015             disk->wtime  = PERF_VAL(PERF_IX_DISK_WRITE_TIME);
2016             disk->reads  = PERF_VAL(PERF_IX_DISK_READ);
2017             disk->writes = PERF_VAL(PERF_IX_DISK_WRITE);
2018             disk->read_bytes  = PERF_VAL(PERF_IX_DISK_READ_BYTES);
2019             disk->write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES);
2020             disk->queue = PERF_VAL(PERF_IX_DISK_QUEUE);
2021             return SIGAR_OK;
2022         }
2023     }
2024 
2025     return ENXIO;
2026 }
2027 
2028 SIGAR_DECLARE(int)
sigar_file_system_usage_get(sigar_t *sigar, const char *dirname, sigar_file_system_usage_t *fsusage)2029 sigar_file_system_usage_get(sigar_t *sigar,
2030                             const char *dirname,
2031                             sigar_file_system_usage_t *fsusage)
2032 {
2033     BOOL retval;
2034     ULARGE_INTEGER avail, total, free;
2035     int status;
2036 
2037     /* prevent dialog box if A:\ drive is empty */
2038     UINT errmode = SetErrorMode(SEM_FAILCRITICALERRORS);
2039 
2040     retval = GetDiskFreeSpaceEx(dirname,
2041                                 &avail, &total, &free);
2042 
2043     /* restore previous error mode */
2044     SetErrorMode(errmode);
2045 
2046     if (!retval) {
2047         return GetLastError();
2048     }
2049 
2050     fsusage->total = total.QuadPart / 1024;
2051     fsusage->free  = free.QuadPart / 1024;
2052     fsusage->avail = avail.QuadPart / 1024;
2053     fsusage->used  = fsusage->total - fsusage->free;
2054     fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
2055 
2056     /* N/A */
2057     fsusage->files      = SIGAR_FIELD_NOTIMPL;
2058     fsusage->free_files = SIGAR_FIELD_NOTIMPL;
2059 
2060     status = sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
2061 
2062     return SIGAR_OK;
2063 }
2064 
sigar_cpu_info_get(sigar_t *sigar, sigar_cpu_info_t *info)2065 static int sigar_cpu_info_get(sigar_t *sigar, sigar_cpu_info_t *info)
2066 {
2067     HKEY key, cpu;
2068     int i = 0;
2069     char id[MAX_PATH + 1];
2070     DWORD size = 0, rc;
2071 
2072     RegOpenKey(HKEY_LOCAL_MACHINE,
2073                "HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &key);
2074 
2075     //just lookup the first id, then assume all cpus are the same.
2076     rc = RegEnumKey(key, 0, id, sizeof(id));
2077     if (rc != ERROR_SUCCESS) {
2078         RegCloseKey(key);
2079         return rc;
2080     }
2081 
2082     rc = RegOpenKey(key, id, &cpu);
2083     if (rc != ERROR_SUCCESS) {
2084         RegCloseKey(key);
2085         return rc;
2086     }
2087 
2088     size = sizeof(info->vendor);
2089     if (RegQueryValueEx(cpu, "VendorIdentifier", NULL, NULL,
2090                         (LPVOID)&info->vendor, &size) ||
2091         strEQ(info->vendor, "GenuineIntel"))
2092     {
2093         SIGAR_SSTRCPY(info->vendor, "Intel");
2094     }
2095     else {
2096         if (strEQ(info->vendor, "AuthenticAMD")) {
2097             SIGAR_SSTRCPY(info->vendor, "AMD");
2098         }
2099     }
2100 
2101     size = sizeof(info->model);
2102     if (RegQueryValueEx(cpu, "ProcessorNameString", NULL, NULL,
2103                         (LPVOID)&info->model, &size))
2104     {
2105         size = sizeof(info->model);
2106         if (RegQueryValueEx(cpu, "Identifier", NULL, NULL,
2107                             (LPVOID)&info->model, &size))
2108         {
2109             SIGAR_SSTRCPY(info->model, "x86");
2110         }
2111     }
2112     else {
2113         sigar_cpu_model_adjust(sigar, info);
2114     }
2115 
2116     size = sizeof(info->mhz); // == sizeof(DWORD)
2117     if (RegQueryValueEx(cpu, "~MHz", NULL, NULL,
2118                         (LPVOID)&info->mhz, &size))
2119     {
2120         info->mhz = -1;
2121     }
2122 
2123     info->cache_size = -1; //XXX
2124     RegCloseKey(key);
2125     RegCloseKey(cpu);
2126 
2127     info->total_cores = sigar->ncpu;
2128     info->cores_per_socket = sigar->lcpu;
2129     info->total_sockets = sigar_cpu_socket_count(sigar);
2130 
2131     return SIGAR_OK;
2132 }
2133 
sigar_cpu_info_list_get(sigar_t *sigar, sigar_cpu_info_list_t *cpu_infos)2134 SIGAR_DECLARE(int) sigar_cpu_info_list_get(sigar_t *sigar,
2135                                            sigar_cpu_info_list_t *cpu_infos)
2136 {
2137     int i, status;
2138     sigar_cpu_info_t info;
2139     int core_rollup = sigar_cpu_core_rollup(sigar);
2140 
2141     sigar_cpu_info_list_create(cpu_infos);
2142 
2143     status = sigar_cpu_info_get(sigar, &info);
2144 
2145     if (status != SIGAR_OK) {
2146         return status;
2147     }
2148 
2149     for (i=0; i<sigar->ncpu; i++) {
2150         SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
2151 
2152         if (core_rollup && (i % sigar->lcpu)) {
2153             continue; /* fold logical processors */
2154         }
2155 
2156         memcpy(&cpu_infos->data[cpu_infos->number++],
2157                &info, sizeof(info));
2158     }
2159 
2160     return SIGAR_OK;
2161 }
2162 
2163 #define sigar_GetNetworkParams \
2164     sigar->iphlpapi.get_net_params.func
2165 
2166 #define sigar_GetAdaptersInfo \
2167     sigar->iphlpapi.get_adapters_info.func
2168 
2169 #define sigar_GetAdaptersAddresses \
2170     sigar->iphlpapi.get_adapters_addrs.func
2171 
2172 #define sigar_GetNumberOfInterfaces \
2173     sigar->iphlpapi.get_num_if.func
2174 
sigar_netif_cache_new(sigar_t *sigar)2175 static sigar_cache_t *sigar_netif_cache_new(sigar_t *sigar)
2176 {
2177     DWORD num = 0;
2178 
2179     DLLMOD_INIT(iphlpapi, FALSE);
2180 
2181     if (sigar_GetNumberOfInterfaces) {
2182         DWORD rc = sigar_GetNumberOfInterfaces(&num);
2183 
2184         if (rc == NO_ERROR) {
2185             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2186                              "GetNumberOfInterfaces=%d",
2187                              num);
2188         }
2189         else {
2190             sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2191                              "GetNumberOfInterfaces failed: %s",
2192                              sigar_strerror(sigar, rc));
2193         }
2194     }
2195 
2196     if (num == 0) {
2197         num = 10; /* reasonable default */
2198     }
2199 
2200     return sigar_cache_new(num);
2201 }
2202 
sigar_get_adapters_info(sigar_t *sigar, PIP_ADAPTER_INFO *adapter)2203 static int sigar_get_adapters_info(sigar_t *sigar,
2204                                    PIP_ADAPTER_INFO *adapter)
2205 {
2206     ULONG size = sigar->ifconf_len;
2207     DWORD rc;
2208 
2209     DLLMOD_INIT(iphlpapi, FALSE);
2210 
2211     if (!sigar_GetAdaptersInfo) {
2212         return SIGAR_ENOTIMPL;
2213     }
2214 
2215     *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
2216     rc = sigar_GetAdaptersInfo(*adapter, &size);
2217 
2218     if (rc == ERROR_BUFFER_OVERFLOW) {
2219         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2220                          "GetAdaptersInfo "
2221                          "realloc ifconf_buf old=%d, new=%d",
2222                          sigar->ifconf_len, size);
2223         sigar->ifconf_len = size;
2224         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
2225                                     sigar->ifconf_len);
2226 
2227         *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
2228         rc = sigar_GetAdaptersInfo(*adapter, &size);
2229     }
2230 
2231     if (rc != NO_ERROR) {
2232         return rc;
2233     }
2234     else {
2235         return SIGAR_OK;
2236     }
2237 }
2238 
sigar_get_adapter_info(sigar_t *sigar, DWORD index, IP_ADAPTER_INFO **adapter)2239 static int sigar_get_adapter_info(sigar_t *sigar,
2240                                   DWORD index,
2241                                   IP_ADAPTER_INFO **adapter)
2242 {
2243     sigar_cache_entry_t *entry;
2244     *adapter = NULL;
2245 
2246     if (sigar->netif_adapters) {
2247         entry = sigar_cache_get(sigar->netif_adapters, index);
2248         if (entry->value) {
2249             *adapter = (IP_ADAPTER_INFO *)entry->value;
2250         }
2251     }
2252     else {
2253         int status;
2254         IP_ADAPTER_INFO *info;
2255 
2256         sigar->netif_adapters =
2257             sigar_netif_cache_new(sigar);
2258 
2259         status = sigar_get_adapters_info(sigar, &info);
2260         if (status != SIGAR_OK) {
2261             return status;
2262         }
2263 
2264         while (info) {
2265             entry = sigar_cache_get(sigar->netif_adapters,
2266                                     info->Index);
2267             if (!entry->value) {
2268                 entry->value = malloc(sizeof(*info));
2269             }
2270             memcpy(entry->value, info, sizeof(*info));
2271             if (info->Index == index) {
2272                 *adapter = info;
2273             }
2274 
2275             info = info->Next;
2276         }
2277     }
2278 
2279     if (*adapter) {
2280         return SIGAR_OK;
2281     }
2282     else {
2283         return ENOENT;
2284     }
2285 }
2286 
sigar_get_adapters_addresses(sigar_t *sigar, ULONG family, ULONG flags, PIP_ADAPTER_ADDRESSES *addrs)2287 static int sigar_get_adapters_addresses(sigar_t *sigar,
2288                                         ULONG family, ULONG flags,
2289                                         PIP_ADAPTER_ADDRESSES *addrs)
2290 {
2291     ULONG size = sigar->ifconf_len;
2292     ULONG rc;
2293 
2294     DLLMOD_INIT(iphlpapi, FALSE);
2295 
2296     if (!sigar_GetAdaptersAddresses) {
2297         return SIGAR_ENOTIMPL;
2298     }
2299 
2300     *addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf;
2301     rc = sigar_GetAdaptersAddresses(family,
2302                                     flags,
2303                                     NULL,
2304                                     *addrs,
2305                                     &size);
2306 
2307     if (rc == ERROR_BUFFER_OVERFLOW) {
2308         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2309                          "GetAdaptersAddresses "
2310                          "realloc ifconf_buf old=%d, new=%d",
2311                          sigar->ifconf_len, size);
2312         sigar->ifconf_len = size;
2313         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
2314                                     sigar->ifconf_len);
2315 
2316         *addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf;
2317         rc = sigar_GetAdaptersAddresses(family,
2318                                         flags,
2319                                         NULL,
2320                                         *addrs,
2321                                         &size);
2322     }
2323 
2324     if (rc != ERROR_SUCCESS) {
2325         return rc;
2326     }
2327     else {
2328         return SIGAR_OK;
2329     }
2330 }
2331 
2332 #define sigar_GetIpAddrTable \
2333     sigar->iphlpapi.get_ipaddr_table.func
2334 
sigar_get_ipaddr_table(sigar_t *sigar, PMIB_IPADDRTABLE *ipaddr)2335 static int sigar_get_ipaddr_table(sigar_t *sigar,
2336                                   PMIB_IPADDRTABLE *ipaddr)
2337 {
2338     ULONG size = sigar->ifconf_len;
2339     DWORD rc;
2340 
2341     DLLMOD_INIT(iphlpapi, FALSE);
2342 
2343     if (!sigar_GetIpAddrTable) {
2344         return SIGAR_ENOTIMPL;
2345     }
2346 
2347     *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
2348     rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
2349 
2350     if (rc == ERROR_INSUFFICIENT_BUFFER) {
2351         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2352                          "GetIpAddrTable "
2353                          "realloc ifconf_buf old=%d, new=%d",
2354                          sigar->ifconf_len, size);
2355         sigar->ifconf_len = size;
2356         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
2357                                     sigar->ifconf_len);
2358 
2359         *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
2360         rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
2361     }
2362 
2363     if (rc != NO_ERROR) {
2364         return rc;
2365     }
2366     else {
2367         return SIGAR_OK;
2368     }
2369 }
2370 
2371 #ifndef MIB_IPADDR_PRIMARY
2372 #define MIB_IPADDR_PRIMARY 0x0001
2373 #endif
2374 
sigar_get_netif_ipaddr(sigar_t *sigar, DWORD index, MIB_IPADDRROW **ipaddr)2375 static int sigar_get_netif_ipaddr(sigar_t *sigar,
2376                                   DWORD index,
2377                                   MIB_IPADDRROW **ipaddr)
2378 {
2379     sigar_cache_entry_t *entry;
2380     *ipaddr = NULL;
2381 
2382     if (sigar->netif_addr_rows) {
2383         entry = sigar_cache_get(sigar->netif_addr_rows, index);
2384         if (entry->value) {
2385             *ipaddr = (MIB_IPADDRROW *)entry->value;
2386         }
2387     }
2388     else {
2389         int status, i;
2390         MIB_IPADDRTABLE *mib;
2391 
2392         sigar->netif_addr_rows =
2393             sigar_netif_cache_new(sigar);
2394 
2395         status = sigar_get_ipaddr_table(sigar, &mib);
2396         if (status != SIGAR_OK) {
2397             return status;
2398         }
2399 
2400         for (i=0; i<mib->dwNumEntries; i++) {
2401             MIB_IPADDRROW *row = &mib->table[i];
2402             short type;
2403 
2404 #ifdef SIGAR_USING_MSC6
2405             type = row->unused2;
2406 #else
2407             type = row->wType;
2408 #endif
2409             if (!(type & MIB_IPADDR_PRIMARY)) {
2410                 continue;
2411             }
2412 
2413             entry = sigar_cache_get(sigar->netif_addr_rows,
2414                                     row->dwIndex);
2415             if (!entry->value) {
2416                 entry->value = malloc(sizeof(*row));
2417             }
2418             memcpy(entry->value, row, sizeof(*row));
2419 
2420             if (row->dwIndex == index) {
2421                 *ipaddr = row;
2422             }
2423         }
2424     }
2425 
2426     if (*ipaddr) {
2427         return SIGAR_OK;
2428     }
2429     else {
2430         return ENOENT;
2431     }
2432 }
2433 
sigar_net_info_get(sigar_t *sigar, sigar_net_info_t *netinfo)2434 SIGAR_DECLARE(int) sigar_net_info_get(sigar_t *sigar,
2435                                       sigar_net_info_t *netinfo)
2436 {
2437     PIP_ADAPTER_INFO adapter;
2438     FIXED_INFO *info;
2439     ULONG len = 0;
2440     IP_ADDR_STRING *ip;
2441     DWORD rc;
2442 
2443     DLLMOD_INIT(iphlpapi, FALSE);
2444 
2445     if (!sigar_GetNetworkParams) {
2446         return SIGAR_ENOTIMPL;
2447     }
2448 
2449     SIGAR_ZERO(netinfo);
2450 
2451     rc = sigar_GetNetworkParams(NULL, &len);
2452     if (rc != ERROR_BUFFER_OVERFLOW) {
2453         return rc;
2454     }
2455 
2456     info = malloc(len);
2457     rc = sigar_GetNetworkParams(info, &len);
2458     if (rc != NO_ERROR) {
2459         free(info);
2460         return rc;
2461     }
2462 
2463     SIGAR_SSTRCPY(netinfo->host_name, info->HostName);
2464     SIGAR_SSTRCPY(netinfo->domain_name, info->DomainName);
2465     SIGAR_SSTRCPY(netinfo->primary_dns,
2466                   info->DnsServerList.IpAddress.String);
2467 
2468     if ((ip = info->DnsServerList.Next)) {
2469         SIGAR_SSTRCPY(netinfo->secondary_dns,
2470                       ip->IpAddress.String);
2471     }
2472 
2473     free(info);
2474 
2475     if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) {
2476         return SIGAR_OK;
2477     }
2478 
2479     while (adapter) {
2480         /* should only be 1 */
2481         if (adapter->GatewayList.IpAddress.String[0]) {
2482             SIGAR_SSTRCPY(netinfo->default_gateway,
2483                           adapter->GatewayList.IpAddress.String);
2484         }
2485 #if 0
2486         if (apapters->DhcpEnabled) {
2487             SIGAR_SSTRCPY(netinfo->dhcp_server,
2488                           apdaters->DhcpServer.IpAddress.String);
2489         }
2490 #endif
2491         adapter = adapter->Next;
2492     }
2493 
2494     return SIGAR_OK;
2495 }
2496 
2497 #define sigar_GetIpForwardTable \
2498     sigar->iphlpapi.get_ipforward_table.func
2499 
sigar_net_route_list_get(sigar_t *sigar, sigar_net_route_list_t *routelist)2500 SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar,
2501                                             sigar_net_route_list_t *routelist)
2502 {
2503     PMIB_IPFORWARDTABLE buffer = NULL;
2504     ULONG bufsize = 0;
2505     DWORD rc, i;
2506     MIB_IPFORWARDTABLE *ipt;
2507     sigar_net_route_t *route;
2508 
2509     DLLMOD_INIT(iphlpapi, FALSE);
2510     if (!sigar_GetIpForwardTable) {
2511         return SIGAR_ENOTIMPL;
2512     }
2513 
2514     rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
2515     if (rc != ERROR_INSUFFICIENT_BUFFER) {
2516         return GetLastError();
2517     }
2518 
2519     buffer = malloc(bufsize);
2520     rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
2521     if (rc != NO_ERROR) {
2522         free(buffer);
2523         return GetLastError();
2524     }
2525 
2526     if (!sigar->netif_names) {
2527         sigar_net_interface_list_get(sigar, NULL);
2528     }
2529 
2530     sigar_net_route_list_create(routelist);
2531     routelist->size = routelist->number = 0;
2532 
2533     ipt = buffer;
2534 
2535     for (i=0; i<ipt->dwNumEntries; i++) {
2536         MIB_IPFORWARDROW *ipr = ipt->table + i;
2537         sigar_cache_entry_t *entry;
2538 
2539         SIGAR_NET_ROUTE_LIST_GROW(routelist);
2540 
2541         route = &routelist->data[routelist->number++];
2542         SIGAR_ZERO(route); /* XXX: other fields */
2543 
2544         sigar_net_address_set(route->destination,
2545                               ipr->dwForwardDest);
2546 
2547         sigar_net_address_set(route->mask,
2548                               ipr->dwForwardMask);
2549 
2550         sigar_net_address_set(route->gateway,
2551                               ipr->dwForwardNextHop);
2552 
2553         route->metric = ipr->dwForwardMetric1;
2554 
2555         route->flags = SIGAR_RTF_UP;
2556         if ((ipr->dwForwardDest == 0) &&
2557             (ipr->dwForwardMask == 0))
2558         {
2559             route->flags |= SIGAR_RTF_GATEWAY;
2560         }
2561 
2562         entry = sigar_cache_get(sigar->netif_names, ipr->dwForwardIfIndex);
2563         if (entry->value) {
2564             SIGAR_SSTRCPY(route->ifname, (char *)entry->value);
2565         }
2566     }
2567 
2568     free(buffer);
2569 
2570     return SIGAR_OK;
2571 }
2572 
2573 #define sigar_GetIfTable \
2574     sigar->iphlpapi.get_if_table.func
2575 
2576 #define sigar_GetIfEntry \
2577     sigar->iphlpapi.get_if_entry.func
2578 
sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)2579 static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)
2580 {
2581     ULONG size = sigar->ifconf_len;
2582     DWORD rc;
2583 
2584     DLLMOD_INIT(iphlpapi, FALSE);
2585 
2586     if (!sigar_GetIfTable) {
2587         return SIGAR_ENOTIMPL;
2588     }
2589 
2590     *iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
2591     rc = sigar_GetIfTable(*iftable, &size, FALSE);
2592 
2593     if (rc == ERROR_INSUFFICIENT_BUFFER) {
2594         sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2595                          "GetIfTable "
2596                          "realloc ifconf_buf old=%d, new=%d",
2597                          sigar->ifconf_len, size);
2598         sigar->ifconf_len = size;
2599         sigar->ifconf_buf = realloc(sigar->ifconf_buf,
2600                                     sigar->ifconf_len);
2601 
2602         *iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
2603         rc = sigar_GetIfTable(*iftable, &size, FALSE);
2604     }
2605 
2606     if (rc != NO_ERROR) {
2607         return rc;
2608     }
2609     else {
2610         return SIGAR_OK;
2611     }
2612 }
2613 
get_mib_ifrow(sigar_t *sigar, const char *name, MIB_IFROW **ifrp)2614 static int get_mib_ifrow(sigar_t *sigar,
2615                          const char *name,
2616                          MIB_IFROW **ifrp)
2617 {
2618     int status, key, cached=0;
2619     sigar_cache_entry_t *entry;
2620 
2621     if (sigar->netif_mib_rows) {
2622         cached = 1;
2623     }
2624     else {
2625         status = sigar_net_interface_list_get(sigar, NULL);
2626         if (status != SIGAR_OK) {
2627             return status;
2628         }
2629     }
2630     key = netif_hash(name);
2631     entry = sigar_cache_get(sigar->netif_mib_rows, key);
2632     if (!entry->value) {
2633         return ENOENT;
2634     }
2635 
2636     *ifrp = (MIB_IFROW *)entry->value;
2637     if (cached) {
2638         /* refresh */
2639         if ((status = sigar_GetIfEntry(*ifrp)) != NO_ERROR) {
2640             return status;
2641         }
2642     }
2643 
2644     return SIGAR_OK;
2645 }
2646 
netif_hash(char *s)2647 int netif_hash(char *s)
2648 {
2649     int hash = 0;
2650     while (*s) {
2651         hash = 31*hash + *s++;
2652     }
2653     return hash;
2654 }
2655 
2656 /* Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211 */
2657 #ifndef IF_TYPE_IEEE80211
2658 #define IF_TYPE_IEEE80211 71
2659 #endif
2660 
2661 SIGAR_DECLARE(int)
sigar_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist)2662 sigar_net_interface_list_get(sigar_t *sigar,
2663                              sigar_net_interface_list_t *iflist)
2664 {
2665     MIB_IFTABLE *ift;
2666     int i, status;
2667     int lo=0, eth=0, la=0;
2668 
2669     if (!sigar->netif_mib_rows) {
2670         sigar->netif_mib_rows =
2671             sigar_netif_cache_new(sigar);
2672     }
2673 
2674     if (!sigar->netif_names) {
2675         sigar->netif_names =
2676             sigar_netif_cache_new(sigar);
2677     }
2678 
2679     if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) {
2680         return status;
2681     }
2682 
2683     if (iflist) {
2684         iflist->number = 0;
2685         iflist->size = ift->dwNumEntries;
2686         iflist->data =
2687             malloc(sizeof(*(iflist->data)) * iflist->size);
2688     }
2689 
2690     for (i=0; i<ift->dwNumEntries; i++) {
2691         char name[16];
2692         int key;
2693         MIB_IFROW *ifr = ift->table + i;
2694         sigar_cache_entry_t *entry;
2695 
2696         if (strEQ(ifr->bDescr, MS_LOOPBACK_ADAPTER)) {
2697             /* special-case */
2698             sprintf(name, NETIF_LA "%d", la++);
2699         }
2700         else if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
2701             sprintf(name, "lo%d", lo++);
2702         }
2703         else if ((ifr->dwType == MIB_IF_TYPE_ETHERNET) ||
2704                  (ifr->dwType == IF_TYPE_IEEE80211))
2705         {
2706             sprintf(name, "eth%d", eth++);
2707         }
2708         else {
2709             continue; /*XXX*/
2710         }
2711 
2712         if (iflist) {
2713             iflist->data[iflist->number++] = sigar_strdup(name);
2714         }
2715 
2716         key = netif_hash(name);
2717         entry = sigar_cache_get(sigar->netif_mib_rows, key);
2718         if (!entry->value) {
2719             entry->value = malloc(sizeof(*ifr));
2720         }
2721         memcpy(entry->value, ifr, sizeof(*ifr));
2722 
2723         /* save dwIndex -> name mapping for use by route_list */
2724         entry = sigar_cache_get(sigar->netif_names, ifr->dwIndex);
2725         if (!entry->value) {
2726             entry->value = sigar_strdup(name);
2727         }
2728     }
2729 
2730     return SIGAR_OK;
2731 }
2732 
sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index, sigar_net_interface_config_t *ifconfig)2733 static int sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index,
2734                                                 sigar_net_interface_config_t *ifconfig)
2735 {
2736 #ifdef SIGAR_USING_MSC6
2737     return SIGAR_ENOTIMPL;
2738 #else
2739     int status;
2740     PIP_ADAPTER_ADDRESSES aa, addrs;
2741     ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
2742 
2743     status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, flags, &aa);
2744 
2745     if (status != SIGAR_OK) {
2746         return status;
2747     }
2748 
2749     for (addrs = aa; addrs; addrs = addrs->Next) {
2750         PIP_ADAPTER_UNICAST_ADDRESS addr;
2751         if (addrs->IfIndex != index) {
2752             continue;
2753         }
2754         for (addr = addrs->FirstUnicastAddress; addr; addr = addr->Next) {
2755             struct sockaddr *sa = addr->Address.lpSockaddr;
2756 
2757             if (sa->sa_family == AF_INET6) {
2758                 struct in6_addr *inet6 = SIGAR_SIN6_ADDR(sa);
2759 
2760                 sigar_net_address6_set(ifconfig->address6, inet6);
2761                 sigar_net_interface_scope6_set(ifconfig, inet6);
2762                 if (addrs->FirstPrefix) {
2763                     ifconfig->prefix6_length = addrs->FirstPrefix->PrefixLength;
2764                 }
2765                 return SIGAR_OK;
2766             }
2767         }
2768     }
2769     return SIGAR_ENOENT;
2770 #endif
2771 }
2772 
2773 SIGAR_DECLARE(int)
sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)2774 sigar_net_interface_config_get(sigar_t *sigar,
2775                                const char *name,
2776                                sigar_net_interface_config_t *ifconfig)
2777 {
2778     MIB_IFROW *ifr;
2779     MIB_IPADDRROW *ipaddr;
2780     int status;
2781 
2782     if (!name) {
2783         return sigar_net_interface_config_primary_get(sigar, ifconfig);
2784     }
2785 
2786     status = get_mib_ifrow(sigar, name, &ifr);
2787     if (status != SIGAR_OK) {
2788         return status;
2789     }
2790 
2791     SIGAR_ZERO(ifconfig);
2792 
2793     SIGAR_SSTRCPY(ifconfig->name, name);
2794 
2795     ifconfig->mtu = ifr->dwMtu;
2796 
2797     sigar_net_address_mac_set(ifconfig->hwaddr,
2798                               ifr->bPhysAddr,
2799                               SIGAR_IFHWADDRLEN);
2800 
2801     SIGAR_SSTRCPY(ifconfig->description,
2802                   ifr->bDescr);
2803 
2804     if (ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL) {
2805         ifconfig->flags |= SIGAR_IFF_UP|SIGAR_IFF_RUNNING;
2806     }
2807 
2808     status = sigar_get_netif_ipaddr(sigar,
2809                                     ifr->dwIndex,
2810                                     &ipaddr);
2811 
2812     if (status == SIGAR_OK) {
2813         sigar_net_address_set(ifconfig->address,
2814                               ipaddr->dwAddr);
2815 
2816         sigar_net_address_set(ifconfig->netmask,
2817                               ipaddr->dwMask);
2818 
2819         if (ifr->dwType != MIB_IF_TYPE_LOOPBACK) {
2820             if (ipaddr->dwBCastAddr) {
2821                 long bcast =
2822                     ipaddr->dwAddr & ipaddr->dwMask;
2823 
2824                 bcast |= ~ipaddr->dwMask;
2825                 ifconfig->flags |= SIGAR_IFF_BROADCAST;
2826 
2827                 sigar_net_address_set(ifconfig->broadcast,
2828                                       bcast);
2829             }
2830         }
2831     }
2832 
2833     /* hack for MS_LOOPBACK_ADAPTER */
2834     if (strnEQ(name, NETIF_LA, sizeof(NETIF_LA)-1)) {
2835         ifr->dwType = MIB_IF_TYPE_LOOPBACK;
2836     }
2837 
2838     if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
2839         ifconfig->flags |= SIGAR_IFF_LOOPBACK;
2840 
2841         SIGAR_SSTRCPY(ifconfig->type,
2842                       SIGAR_NIC_LOOPBACK);
2843     }
2844     else {
2845         if (ipaddr) {
2846             ifconfig->flags |= SIGAR_IFF_MULTICAST;
2847         }
2848 
2849         SIGAR_SSTRCPY(ifconfig->type,
2850                       SIGAR_NIC_ETHERNET);
2851     }
2852 
2853     sigar_net_interface_ipv6_config_init(ifconfig);
2854     sigar_net_interface_ipv6_config_find(sigar, ifr->dwIndex, ifconfig);
2855 
2856     return SIGAR_OK;
2857 }
2858 
2859 SIGAR_DECLARE(int)
sigar_net_interface_stat_get(sigar_t *sigar, const char *name, sigar_net_interface_stat_t *ifstat)2860 sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
2861                              sigar_net_interface_stat_t *ifstat)
2862 {
2863     MIB_IFROW *ifr;
2864     int status;
2865 
2866     status = get_mib_ifrow(sigar, name, &ifr);
2867     if (status != SIGAR_OK) {
2868         return status;
2869     }
2870 
2871     ifstat->rx_bytes    = ifr->dwInOctets;
2872     ifstat->rx_packets  = ifr->dwInUcastPkts + ifr->dwInNUcastPkts;
2873     ifstat->rx_errors   = ifr->dwInErrors;
2874     ifstat->rx_dropped  = ifr->dwInDiscards;
2875     ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
2876     ifstat->rx_frame    = SIGAR_FIELD_NOTIMPL;
2877 
2878     ifstat->tx_bytes      = ifr->dwOutOctets;
2879     ifstat->tx_packets    = ifr->dwOutUcastPkts + ifr->dwOutNUcastPkts;
2880     ifstat->tx_errors     = ifr->dwOutErrors;
2881     ifstat->tx_dropped    = ifr->dwOutDiscards;
2882     ifstat->tx_overruns   = SIGAR_FIELD_NOTIMPL;
2883     ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL;
2884     ifstat->tx_carrier    = SIGAR_FIELD_NOTIMPL;
2885 
2886     ifstat->speed         = ifr->dwSpeed;
2887 
2888     return SIGAR_OK;
2889 }
2890 
2891 #define IS_TCP_SERVER(state, flags) \
2892     ((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN))
2893 
2894 #define IS_TCP_CLIENT(state, flags) \
2895     ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN))
2896 
2897 #define sigar_GetTcpTable \
2898     sigar->iphlpapi.get_tcp_table.func
2899 
net_conn_get_tcp(sigar_net_connection_walker_t *walker)2900 static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
2901 {
2902     sigar_t *sigar = walker->sigar;
2903     int flags = walker->flags;
2904     int status, i;
2905     DWORD rc, size=0;
2906     PMIB_TCPTABLE tcp;
2907 
2908     DLLMOD_INIT(iphlpapi, FALSE);
2909 
2910     if (!sigar_GetTcpTable) {
2911         return SIGAR_ENOTIMPL;
2912     }
2913 
2914     rc = sigar_GetTcpTable(NULL, &size, FALSE);
2915     if (rc != ERROR_INSUFFICIENT_BUFFER) {
2916         return GetLastError();
2917     }
2918     tcp = malloc(size);
2919     rc = sigar_GetTcpTable(tcp, &size, FALSE);
2920     if (rc) {
2921         free(tcp);
2922         return GetLastError();
2923     }
2924 
2925     /* go in reverse to get LISTEN states first */
2926     for (i = (tcp->dwNumEntries-1); i >= 0; i--) {
2927         sigar_net_connection_t conn;
2928         DWORD state = tcp->table[i].dwState;
2929 
2930         if (!(IS_TCP_SERVER(state, flags) ||
2931               IS_TCP_CLIENT(state, flags)))
2932         {
2933             continue;
2934         }
2935 
2936         conn.local_port  = htons((WORD)tcp->table[i].dwLocalPort);
2937         conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort);
2938 
2939         conn.type = SIGAR_NETCONN_TCP;
2940 
2941         sigar_net_address_set(conn.local_address,
2942                               tcp->table[i].dwLocalAddr);
2943 
2944         sigar_net_address_set(conn.remote_address,
2945                               tcp->table[i].dwRemoteAddr);
2946 
2947         conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
2948 
2949         switch (state) {
2950           case MIB_TCP_STATE_CLOSED:
2951             conn.state = SIGAR_TCP_CLOSE;
2952             break;
2953           case MIB_TCP_STATE_LISTEN:
2954             conn.state = SIGAR_TCP_LISTEN;
2955             break;
2956           case MIB_TCP_STATE_SYN_SENT:
2957             conn.state = SIGAR_TCP_SYN_SENT;
2958             break;
2959           case MIB_TCP_STATE_SYN_RCVD:
2960             conn.state = SIGAR_TCP_SYN_RECV;
2961             break;
2962           case MIB_TCP_STATE_ESTAB:
2963             conn.state = SIGAR_TCP_ESTABLISHED;
2964             break;
2965           case MIB_TCP_STATE_FIN_WAIT1:
2966             conn.state = SIGAR_TCP_FIN_WAIT1;
2967             break;
2968           case MIB_TCP_STATE_FIN_WAIT2:
2969             conn.state = SIGAR_TCP_FIN_WAIT2;
2970             break;
2971           case MIB_TCP_STATE_CLOSE_WAIT:
2972             conn.state = SIGAR_TCP_CLOSE_WAIT;
2973             break;
2974           case MIB_TCP_STATE_CLOSING:
2975             conn.state = SIGAR_TCP_CLOSING;
2976             break;
2977           case MIB_TCP_STATE_LAST_ACK:
2978             conn.state = SIGAR_TCP_LAST_ACK;
2979             break;
2980           case MIB_TCP_STATE_TIME_WAIT:
2981             conn.state = SIGAR_TCP_TIME_WAIT;
2982             break;
2983           case MIB_TCP_STATE_DELETE_TCB:
2984           default:
2985             conn.state = SIGAR_TCP_UNKNOWN;
2986             break;
2987         }
2988 
2989         if (walker->add_connection(walker, &conn) != SIGAR_OK) {
2990             break;
2991         }
2992     }
2993 
2994     free(tcp);
2995     return SIGAR_OK;
2996 }
2997 
2998 #define IS_UDP_SERVER(conn, flags) \
2999     ((flags & SIGAR_NETCONN_SERVER) && !conn.remote_port)
3000 
3001 #define IS_UDP_CLIENT(state, flags) \
3002     ((flags & SIGAR_NETCONN_CLIENT) && conn.remote_port)
3003 
3004 #define sigar_GetUdpTable \
3005     sigar->iphlpapi.get_udp_table.func
3006 
net_conn_get_udp(sigar_net_connection_walker_t *walker)3007 static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
3008 {
3009     /* Disabled because it isn't properly implemented and
3010      * cause the windows runtime to abort due to use
3011      * of uninitialized variable in the for-loop below.
3012      * IS_UDP_SERVER(conn, flags) We don't use this
3013      * functionality anyway
3014      */
3015     return SIGAR_ENOTIMPL;
3016 
3017 #if 0
3018     sigar_t *sigar = walker->sigar;
3019     int flags = walker->flags;
3020     int status;
3021     DWORD rc, size=0, i;
3022     PMIB_UDPTABLE udp;
3023 
3024     DLLMOD_INIT(iphlpapi, FALSE);
3025 
3026     if (!sigar_GetUdpTable) {
3027         return SIGAR_ENOTIMPL;
3028     }
3029 
3030     rc = sigar_GetUdpTable(NULL, &size, FALSE);
3031     if (rc != ERROR_INSUFFICIENT_BUFFER) {
3032         return GetLastError();
3033     }
3034     udp = malloc(size);
3035     rc = sigar_GetUdpTable(udp, &size, FALSE);
3036     if (rc) {
3037         free(udp);
3038         return GetLastError();
3039     }
3040 
3041     for (i = 0; i < udp->dwNumEntries; i++) {
3042         sigar_net_connection_t conn;
3043 
3044         if (!(IS_UDP_SERVER(conn, flags) ||
3045               IS_UDP_CLIENT(conn, flags)))
3046         {
3047             continue;
3048         }
3049 
3050         conn.local_port  = htons((WORD)udp->table[i].dwLocalPort);
3051         conn.remote_port = 0;
3052 
3053         conn.type = SIGAR_NETCONN_UDP;
3054 
3055         sigar_net_address_set(conn.local_address,
3056                               udp->table[i].dwLocalAddr);
3057 
3058         sigar_net_address_set(conn.remote_address, 0);
3059 
3060         conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
3061 
3062         if (walker->add_connection(walker, &conn) != SIGAR_OK) {
3063             break;
3064         }
3065     }
3066 
3067     free(udp);
3068     return SIGAR_OK;
3069 #endif
3070 }
3071 
3072 SIGAR_DECLARE(int)
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)3073 sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
3074 {
3075     int status;
3076 
3077     if (walker->flags & SIGAR_NETCONN_TCP) {
3078         status = net_conn_get_tcp(walker);
3079 
3080         if (status != SIGAR_OK) {
3081             return status;
3082         }
3083     }
3084 
3085     if (walker->flags & SIGAR_NETCONN_UDP) {
3086         status = net_conn_get_udp(walker);
3087 
3088         if (status != SIGAR_OK) {
3089             return status;
3090         }
3091     }
3092 
3093     return SIGAR_OK;
3094 }
3095 
3096 #define sigar_GetTcpStatistics \
3097     sigar->iphlpapi.get_tcp_stats.func
3098 
3099 SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar, sigar_tcp_t *tcp)3100 sigar_tcp_get(sigar_t *sigar,
3101               sigar_tcp_t *tcp)
3102 {
3103     MIB_TCPSTATS mib;
3104     int status;
3105 
3106     DLLMOD_INIT(iphlpapi, FALSE);
3107 
3108     if (!sigar_GetTcpStatistics) {
3109         return SIGAR_ENOTIMPL;
3110     }
3111 
3112     status = sigar_GetTcpStatistics(&mib);
3113 
3114     if (status != NO_ERROR) {
3115         return status;
3116     }
3117 
3118     tcp->active_opens = mib.dwActiveOpens;
3119     tcp->passive_opens = mib.dwPassiveOpens;
3120     tcp->attempt_fails = mib.dwAttemptFails;
3121     tcp->estab_resets = mib.dwEstabResets;
3122     tcp->curr_estab = mib.dwCurrEstab;
3123     tcp->in_segs = mib.dwInSegs;
3124     tcp->out_segs = mib.dwOutSegs;
3125     tcp->retrans_segs = mib.dwRetransSegs;
3126     tcp->in_errs = mib.dwInErrs;
3127     tcp->out_rsts = mib.dwOutRsts;
3128 
3129     return SIGAR_OK;
3130 }
3131 
3132 SIGAR_DECLARE(int)
sigar_nfs_client_v2_get(sigar_t *sigar, sigar_nfs_client_v2_t *nfs)3133 sigar_nfs_client_v2_get(sigar_t *sigar,
3134                         sigar_nfs_client_v2_t *nfs)
3135 {
3136     return SIGAR_ENOTIMPL;
3137 }
3138 
3139 SIGAR_DECLARE(int)
sigar_nfs_server_v2_get(sigar_t *sigar, sigar_nfs_server_v2_t *nfs)3140 sigar_nfs_server_v2_get(sigar_t *sigar,
3141                         sigar_nfs_server_v2_t *nfs)
3142 {
3143     return SIGAR_ENOTIMPL;
3144 }
3145 
3146 SIGAR_DECLARE(int)
sigar_nfs_client_v3_get(sigar_t *sigar, sigar_nfs_client_v3_t *nfs)3147 sigar_nfs_client_v3_get(sigar_t *sigar,
3148                         sigar_nfs_client_v3_t *nfs)
3149 {
3150     return SIGAR_ENOTIMPL;
3151 }
3152 
3153 SIGAR_DECLARE(int)
sigar_nfs_server_v3_get(sigar_t *sigar, sigar_nfs_server_v3_t *nfs)3154 sigar_nfs_server_v3_get(sigar_t *sigar,
3155                         sigar_nfs_server_v3_t *nfs)
3156 {
3157     return SIGAR_ENOTIMPL;
3158 }
3159 
3160 #define sigar_GetTcpExTable \
3161     sigar->iphlpapi.get_tcpx_table.func
3162 
3163 #define sigar_GetUdpExTable \
3164     sigar->iphlpapi.get_udpx_table.func
3165 
sigar_proc_port_get(sigar_t *sigar, int protocol, unsigned long port, sigar_pid_t *pid)3166 SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar,
3167                                        int protocol,
3168                                        unsigned long port,
3169                                        sigar_pid_t *pid)
3170 {
3171     DWORD rc, i;
3172 
3173     DLLMOD_INIT(iphlpapi, FALSE);
3174 
3175     if (protocol == SIGAR_NETCONN_TCP) {
3176         PMIB_TCPEXTABLE tcp;
3177 
3178         if (!sigar_GetTcpExTable) {
3179             return SIGAR_ENOTIMPL;
3180         }
3181 
3182         rc = sigar_GetTcpExTable(&tcp, FALSE, GetProcessHeap(),
3183                                  2, 2);
3184 
3185         if (rc) {
3186             return GetLastError();
3187         }
3188 
3189         for (i=0; i<tcp->dwNumEntries; i++) {
3190             if (tcp->table[i].dwState != MIB_TCP_STATE_LISTEN) {
3191                 continue;
3192             }
3193 
3194             if (htons((WORD)tcp->table[i].dwLocalPort) != port) {
3195                 continue;
3196             }
3197 
3198             *pid = tcp->table[i].dwProcessId;
3199 
3200             return SIGAR_OK;
3201         }
3202     }
3203     else if (protocol == SIGAR_NETCONN_UDP) {
3204         PMIB_UDPEXTABLE udp;
3205 
3206         if (!sigar_GetUdpExTable) {
3207             return SIGAR_ENOTIMPL;
3208         }
3209 
3210         rc = sigar_GetUdpExTable(&udp, FALSE, GetProcessHeap(),
3211                                  2, 2);
3212 
3213         if (rc) {
3214             return GetLastError();
3215         }
3216 
3217         for (i=0; i<udp->dwNumEntries; i++) {
3218             if (htons((WORD)udp->table[i].dwLocalPort) != port) {
3219                 continue;
3220             }
3221 
3222             *pid = udp->table[i].dwProcessId;
3223 
3224             return SIGAR_OK;
3225         }
3226     }
3227     else {
3228         return SIGAR_ENOTIMPL;
3229     }
3230 
3231     return ENOENT;
3232 }
3233 
3234 #define sigar_GetIpNetTable \
3235     sigar->iphlpapi.get_ipnet_table.func
3236 
sigar_arp_list_get(sigar_t *sigar, sigar_arp_list_t *arplist)3237 SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar,
3238                                       sigar_arp_list_t *arplist)
3239 {
3240     int status;
3241     DWORD rc, size=0, i;
3242     PMIB_IPNETTABLE ipnet;
3243 
3244     DLLMOD_INIT(iphlpapi, FALSE);
3245 
3246     if (!sigar_GetIpNetTable) {
3247         return SIGAR_ENOTIMPL;
3248     }
3249 
3250     rc = sigar_GetIpNetTable(NULL, &size, FALSE);
3251     if (rc != ERROR_INSUFFICIENT_BUFFER) {
3252         return GetLastError();
3253     }
3254     ipnet = malloc(size);
3255     rc = sigar_GetIpNetTable(ipnet, &size, FALSE);
3256     if (rc) {
3257         free(ipnet);
3258         return GetLastError();
3259     }
3260 
3261     sigar_arp_list_create(arplist);
3262 
3263     if (!sigar->netif_names) {
3264         /* dwIndex -> name map */
3265         sigar_net_interface_list_get(sigar, NULL);
3266     }
3267 
3268     for (i = 0; i < ipnet->dwNumEntries; i++) {
3269         sigar_arp_t *arp;
3270         PMIB_IPNETROW entry;
3271         sigar_cache_entry_t *ifname;
3272 
3273         entry = &ipnet->table[i];
3274         SIGAR_ARP_LIST_GROW(arplist);
3275         arp = &arplist->data[arplist->number++];
3276 
3277         sigar_net_address_set(arp->address,
3278                               entry->dwAddr);
3279 
3280         sigar_net_address_mac_set(arp->hwaddr,
3281                                   entry->bPhysAddr,
3282                                   entry->dwPhysAddrLen);
3283 
3284         ifname = sigar_cache_get(sigar->netif_names, entry->dwIndex);
3285         if (ifname->value) {
3286             SIGAR_SSTRCPY(arp->ifname, (char *)ifname->value);
3287         }
3288 
3289         arp->flags = 0; /*XXX*/
3290         SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/
3291     }
3292 
3293     free(ipnet);
3294 
3295     return SIGAR_OK;
3296 }
3297 
3298 #include <lm.h>
3299 
sigar_who_net_sessions(sigar_t *sigar, sigar_who_list_t *wholist)3300 static int sigar_who_net_sessions(sigar_t *sigar,
3301                                   sigar_who_list_t *wholist)
3302 {
3303     NET_API_STATUS status;
3304     LPSESSION_INFO_10 buffer=NULL, ptr;
3305     DWORD entries=0, total_entries=0;
3306     DWORD resume_handle=0;
3307     DWORD i;
3308 
3309     do {
3310         status = NetSessionEnum(NULL, /* server name */
3311                                 NULL, /* client name */
3312                                 NULL, /* user name */
3313                                 10,   /* level */
3314                                 (LPBYTE*)&buffer,
3315                                 MAX_PREFERRED_LENGTH,
3316                                 &entries,
3317                                 &total_entries,
3318                                 &resume_handle);
3319 
3320         if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) {
3321             if ((ptr = buffer)) {
3322                 for (i=0; i<entries; i++) {
3323                     sigar_who_t *who;
3324 
3325                     if (!ptr) {
3326                         break;
3327                     }
3328 
3329                     SIGAR_WHO_LIST_GROW(wholist);
3330                     who = &wholist->data[wholist->number++];
3331 
3332                     who->time = (time(NULL) - ptr->sesi10_time);
3333                     SIGAR_W2A((LPCWSTR)ptr->sesi10_username,
3334                               who->user, sizeof(who->user));
3335                     SIGAR_W2A((LPCWSTR)ptr->