sigar 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }