sigar 0.7.0

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