hyperic-sigar 1.7.0

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