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,1966 @@
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_util.h"
22
+ #include "sigar_ptql.h"
23
+ #include "sigar_os.h"
24
+
25
+ #include <stdio.h>
26
+
27
+ #ifdef SIGAR_HAS_PCRE
28
+ #include "pcre.h"
29
+ #endif
30
+
31
+ /* See http://gcc.gnu.org/ml/libstdc++/2002-03/msg00164.html */
32
+ #if defined(WIN32) || (defined(__hpux) && defined(SIGAR_64BIT))
33
+ #define strtoull strtoul
34
+ #elif (defined(__hpux) && !defined(SIGAR_64BIT))
35
+ #define strtoull __strtoull
36
+ #else
37
+ #include <errno.h>
38
+ #endif
39
+
40
+ #define SIGAR_CLEAR_ERRNO() errno = 0
41
+
42
+ #define strtonum_failed(src, ptr) \
43
+ ((src == ptr) || (errno == ERANGE) || (*ptr != '\0'))
44
+
45
+ typedef struct ptql_parse_branch_t ptql_parse_branch_t;
46
+ typedef struct ptql_branch_t ptql_branch_t;
47
+
48
+ /* adhere to calling convention, else risk stack corruption */
49
+ #ifdef WIN32
50
+ #define SIGAPI WINAPI
51
+ #else
52
+ #define SIGAPI
53
+ #endif
54
+
55
+ typedef int (SIGAPI *ptql_get_t)(sigar_t *sigar, sigar_pid_t pid, void *data);
56
+ typedef int (*ptql_branch_init_t)(ptql_parse_branch_t *parsed, ptql_branch_t *branch,
57
+ sigar_ptql_error_t *error);
58
+
59
+ typedef int (*ptql_op_ui64_t)(ptql_branch_t *branch,
60
+ sigar_uint64_t haystack,
61
+ sigar_uint64_t needle);
62
+
63
+ typedef int (*ptql_op_ui32_t)(ptql_branch_t *branch,
64
+ sigar_uint32_t haystack,
65
+ sigar_uint32_t needle);
66
+
67
+ typedef int (*ptql_op_dbl_t)(ptql_branch_t *branch,
68
+ double haystack,
69
+ double needle);
70
+
71
+ typedef int (*ptql_op_str_t)(ptql_branch_t *branch,
72
+ char *haystack,
73
+ char *needle);
74
+
75
+ typedef int (*ptql_op_chr_t)(ptql_branch_t *branch,
76
+ char haystack,
77
+ char needle);
78
+
79
+ typedef enum {
80
+ PTQL_VALUE_TYPE_UI64,
81
+ PTQL_VALUE_TYPE_UI32,
82
+ PTQL_VALUE_TYPE_DBL,
83
+ PTQL_VALUE_TYPE_CHR,
84
+ PTQL_VALUE_TYPE_STR,
85
+ PTQL_VALUE_TYPE_ANY
86
+ } ptql_value_type_t;
87
+
88
+ typedef enum {
89
+ PTQL_OP_EQ,
90
+ PTQL_OP_NE,
91
+ PTQL_OP_GT,
92
+ PTQL_OP_GE,
93
+ PTQL_OP_LT,
94
+ PTQL_OP_LE,
95
+ #define PTQL_OP_MAX_NSTR PTQL_OP_LE
96
+ PTQL_OP_EW, /* rest are string only */
97
+ PTQL_OP_SW,
98
+ PTQL_OP_RE,
99
+ PTQL_OP_CT,
100
+ PTQL_OP_MAX
101
+ } ptql_op_name_t;
102
+
103
+ #define PTQL_OP_FLAG_PARENT 1
104
+ #define PTQL_OP_FLAG_REF 2
105
+ #define PTQL_OP_FLAG_GLOB 4
106
+ #define PTQL_OP_FLAG_PID 8
107
+ #define PTQL_OP_FLAG_ICASE 16
108
+
109
+ struct ptql_parse_branch_t {
110
+ char *name;
111
+ char *attr;
112
+ char *op;
113
+ char *value;
114
+ unsigned int op_flags;
115
+ };
116
+
117
+ typedef struct {
118
+ char *name;
119
+ ptql_get_t get;
120
+ size_t offset;
121
+ unsigned int data_size;
122
+ ptql_value_type_t type;
123
+ ptql_branch_init_t init;
124
+ } ptql_lookup_t;
125
+
126
+ #define DATA_PTR(branch) \
127
+ ((char *)branch->data.ptr + branch->lookup->offset)
128
+
129
+ #define IS_ICASE(branch) \
130
+ (branch->op_flags & PTQL_OP_FLAG_ICASE)
131
+
132
+ #define branch_strcmp(branch, s1, s2) \
133
+ (IS_ICASE(branch) ? strcasecmp(s1, s2) : strcmp(s1, s2))
134
+
135
+ #define branch_strncmp(branch, s1, s2, n) \
136
+ (IS_ICASE(branch) ? strncasecmp(s1, s2, n) : strncmp(s1, s2, n))
137
+
138
+ #define branch_strEQ(branch, s1, s2) \
139
+ (branch_strcmp(branch, s1, s2) == 0)
140
+
141
+ #define branch_strnEQ(branch, s1, s2, n) \
142
+ (branch_strncmp(branch, s1, s2, n) == 0)
143
+
144
+ #define branch_strstr(branch, s1, s2) \
145
+ (IS_ICASE(branch) ? sigar_strcasestr(s1, s2) : strstr(s1, s2))
146
+
147
+ #define IS_PID_SERVICE_QUERY(branch) \
148
+ (branch->flags >= PTQL_PID_SERVICE_NAME)
149
+
150
+ static void data_free(void *data)
151
+ {
152
+ free(data);
153
+ }
154
+
155
+ typedef union {
156
+ sigar_pid_t pid;
157
+ sigar_uint64_t ui64;
158
+ sigar_uint32_t ui32;
159
+ double dbl;
160
+ char chr[4];
161
+ char *str;
162
+ void *ptr;
163
+ } any_value_t;
164
+
165
+ struct ptql_branch_t {
166
+ ptql_lookup_t *lookup;
167
+ any_value_t data;
168
+ unsigned int data_size;
169
+ void (*data_free)(void *);
170
+ unsigned int flags;
171
+ unsigned int op_flags;
172
+ ptql_op_name_t op_name;
173
+ union {
174
+ ptql_op_ui64_t ui64;
175
+ ptql_op_ui32_t ui32;
176
+ ptql_op_dbl_t dbl;
177
+ ptql_op_chr_t chr;
178
+ ptql_op_str_t str;
179
+ } match;
180
+ any_value_t value;
181
+ void (*value_free)(void *);
182
+ };
183
+
184
+ typedef struct {
185
+ char *name;
186
+ ptql_lookup_t *members;
187
+ } ptql_entry_t;
188
+
189
+ typedef struct {
190
+ unsigned long number;
191
+ unsigned long size;
192
+ ptql_branch_t *data;
193
+ } ptql_branch_list_t;
194
+
195
+ struct sigar_ptql_query_t {
196
+ ptql_branch_list_t branches;
197
+ #ifdef PTQL_DEBUG
198
+ char *ptql;
199
+ #endif
200
+ };
201
+
202
+ /* XXX optimize */
203
+ static ptql_op_name_t ptql_op_code_get(char *op)
204
+ {
205
+ if (strEQ(op, "eq")) {
206
+ return PTQL_OP_EQ;
207
+ }
208
+ else if (strEQ(op, "ne")) {
209
+ return PTQL_OP_NE;
210
+ }
211
+ else if (strEQ(op, "gt")) {
212
+ return PTQL_OP_GT;
213
+ }
214
+ else if (strEQ(op, "ge")) {
215
+ return PTQL_OP_GE;
216
+ }
217
+ else if (strEQ(op, "lt")) {
218
+ return PTQL_OP_LT;
219
+ }
220
+ else if (strEQ(op, "le")) {
221
+ return PTQL_OP_LE;
222
+ }
223
+ else if (strEQ(op, "ew")) {
224
+ return PTQL_OP_EW;
225
+ }
226
+ else if (strEQ(op, "sw")) {
227
+ return PTQL_OP_SW;
228
+ }
229
+ else if (strEQ(op, "re")) {
230
+ return PTQL_OP_RE;
231
+ }
232
+ else if (strEQ(op, "ct")) {
233
+ return PTQL_OP_CT;
234
+ }
235
+ else {
236
+ return PTQL_OP_MAX;
237
+ }
238
+ }
239
+
240
+ static int ptql_op_ui64_eq(ptql_branch_t *branch,
241
+ sigar_uint64_t haystack, sigar_uint64_t needle)
242
+ {
243
+ return haystack == needle;
244
+ }
245
+
246
+ static int ptql_op_ui64_ne(ptql_branch_t *branch,
247
+ sigar_uint64_t haystack, sigar_uint64_t needle)
248
+ {
249
+ return haystack != needle;
250
+ }
251
+
252
+ static int ptql_op_ui64_gt(ptql_branch_t *branch,
253
+ sigar_uint64_t haystack, sigar_uint64_t needle)
254
+ {
255
+ return haystack > needle;
256
+ }
257
+
258
+ static int ptql_op_ui64_ge(ptql_branch_t *branch,
259
+ sigar_uint64_t haystack, sigar_uint64_t needle)
260
+ {
261
+ return haystack >= needle;
262
+ }
263
+
264
+ static int ptql_op_ui64_lt(ptql_branch_t *branch,
265
+ sigar_uint64_t haystack, sigar_uint64_t needle)
266
+ {
267
+ return haystack < needle;
268
+ }
269
+
270
+ static int ptql_op_ui64_le(ptql_branch_t *branch,
271
+ sigar_uint64_t haystack, sigar_uint64_t needle)
272
+ {
273
+ return haystack <= needle;
274
+ }
275
+
276
+ static ptql_op_ui64_t ptql_op_ui64[] = {
277
+ ptql_op_ui64_eq,
278
+ ptql_op_ui64_ne,
279
+ ptql_op_ui64_gt,
280
+ ptql_op_ui64_ge,
281
+ ptql_op_ui64_lt,
282
+ ptql_op_ui64_le
283
+ };
284
+
285
+ static int ptql_op_ui32_eq(ptql_branch_t *branch,
286
+ sigar_uint32_t haystack, sigar_uint32_t needle)
287
+ {
288
+ return haystack == needle;
289
+ }
290
+
291
+ static int ptql_op_ui32_ne(ptql_branch_t *branch,
292
+ sigar_uint32_t haystack, sigar_uint32_t needle)
293
+ {
294
+ return haystack != needle;
295
+ }
296
+
297
+ static int ptql_op_ui32_gt(ptql_branch_t *branch,
298
+ sigar_uint32_t haystack, sigar_uint32_t needle)
299
+ {
300
+ return haystack > needle;
301
+ }
302
+
303
+ static int ptql_op_ui32_ge(ptql_branch_t *branch,
304
+ sigar_uint32_t haystack, sigar_uint32_t needle)
305
+ {
306
+ return haystack >= needle;
307
+ }
308
+
309
+ static int ptql_op_ui32_lt(ptql_branch_t *branch,
310
+ sigar_uint32_t haystack, sigar_uint32_t needle)
311
+ {
312
+ return haystack < needle;
313
+ }
314
+
315
+ static int ptql_op_ui32_le(ptql_branch_t *branch,
316
+ sigar_uint32_t haystack, sigar_uint32_t needle)
317
+ {
318
+ return haystack <= needle;
319
+ }
320
+
321
+ static ptql_op_ui32_t ptql_op_ui32[] = {
322
+ ptql_op_ui32_eq,
323
+ ptql_op_ui32_ne,
324
+ ptql_op_ui32_gt,
325
+ ptql_op_ui32_ge,
326
+ ptql_op_ui32_lt,
327
+ ptql_op_ui32_le
328
+ };
329
+
330
+ static int ptql_op_dbl_eq(ptql_branch_t *branch,
331
+ double haystack, double needle)
332
+ {
333
+ return haystack == needle;
334
+ }
335
+
336
+ static int ptql_op_dbl_ne(ptql_branch_t *branch,
337
+ double haystack, double needle)
338
+ {
339
+ return haystack != needle;
340
+ }
341
+
342
+ static int ptql_op_dbl_gt(ptql_branch_t *branch,
343
+ double haystack, double needle)
344
+ {
345
+ return haystack > needle;
346
+ }
347
+
348
+ static int ptql_op_dbl_ge(ptql_branch_t *branch,
349
+ double haystack, double needle)
350
+ {
351
+ return haystack >= needle;
352
+ }
353
+
354
+ static int ptql_op_dbl_lt(ptql_branch_t *branch,
355
+ double haystack, double needle)
356
+ {
357
+ return haystack < needle;
358
+ }
359
+
360
+ static int ptql_op_dbl_le(ptql_branch_t *branch,
361
+ double haystack, double needle)
362
+ {
363
+ return haystack <= needle;
364
+ }
365
+
366
+ static ptql_op_dbl_t ptql_op_dbl[] = {
367
+ ptql_op_dbl_eq,
368
+ ptql_op_dbl_ne,
369
+ ptql_op_dbl_gt,
370
+ ptql_op_dbl_ge,
371
+ ptql_op_dbl_lt,
372
+ ptql_op_dbl_le
373
+ };
374
+
375
+ static int ptql_op_str_eq(ptql_branch_t *branch,
376
+ char *haystack, char *needle)
377
+ {
378
+ return branch_strEQ(branch, haystack, needle);
379
+ }
380
+
381
+ static int ptql_op_str_ne(ptql_branch_t *branch,
382
+ char *haystack, char *needle)
383
+ {
384
+ return !branch_strEQ(branch, haystack, needle);
385
+ }
386
+
387
+ static int ptql_op_str_gt(ptql_branch_t *branch,
388
+ char *haystack, char *needle)
389
+ {
390
+ return branch_strcmp(branch, haystack, needle) > 0;
391
+ }
392
+
393
+ static int ptql_op_str_ge(ptql_branch_t *branch,
394
+ char *haystack, char *needle)
395
+ {
396
+ return branch_strcmp(branch, haystack, needle) >= 0;
397
+ }
398
+
399
+ static int ptql_op_str_lt(ptql_branch_t *branch,
400
+ char *haystack, char *needle)
401
+ {
402
+ return branch_strcmp(branch, haystack, needle) < 0;
403
+ }
404
+
405
+ static int ptql_op_str_le(ptql_branch_t *branch,
406
+ char *haystack, char *needle)
407
+ {
408
+ return branch_strcmp(branch, haystack, needle) <= 0;
409
+ }
410
+
411
+ static int ptql_op_str_ew(ptql_branch_t *branch,
412
+ char *haystack, char *needle)
413
+ {
414
+ int nlen = strlen(needle);
415
+ int hlen = strlen(haystack);
416
+ int diff = hlen - nlen;
417
+ if (diff < 0) {
418
+ return 0;
419
+ }
420
+ return branch_strnEQ(branch, haystack + diff, needle, nlen);
421
+ }
422
+
423
+ static int ptql_op_str_sw(ptql_branch_t *branch,
424
+ char *haystack, char *needle)
425
+ {
426
+ return branch_strnEQ(branch, haystack, needle, strlen(needle));
427
+ }
428
+
429
+ static int ptql_op_str_re(ptql_branch_t *branch,
430
+ char *haystack, char *needle)
431
+ {
432
+ #ifdef SIGAR_HAS_PCRE
433
+ pcre *re = (pcre *)branch->value.ptr;
434
+ int len = strlen(haystack);
435
+ int rc =
436
+ pcre_exec(re, NULL, haystack, len, 0, 0, NULL, 0);
437
+ return rc >= 0;
438
+ #else
439
+ return 0;
440
+ #endif
441
+ }
442
+
443
+ static int ptql_op_str_ct(ptql_branch_t *branch,
444
+ char *haystack, char *needle)
445
+ {
446
+ return branch_strstr(branch, haystack, needle) != NULL;
447
+ }
448
+
449
+ static ptql_op_str_t ptql_op_str[] = {
450
+ ptql_op_str_eq,
451
+ ptql_op_str_ne,
452
+ ptql_op_str_gt,
453
+ ptql_op_str_ge,
454
+ ptql_op_str_lt,
455
+ ptql_op_str_le,
456
+ ptql_op_str_ew,
457
+ ptql_op_str_sw,
458
+ ptql_op_str_re,
459
+ ptql_op_str_ct
460
+ };
461
+
462
+ static int ptql_op_chr_eq(ptql_branch_t *branch,
463
+ char haystack, char needle)
464
+ {
465
+ return haystack == needle;
466
+ }
467
+
468
+ static int ptql_op_chr_ne(ptql_branch_t *branch,
469
+ char haystack, char needle)
470
+ {
471
+ return haystack != needle;
472
+ }
473
+
474
+ static int ptql_op_chr_gt(ptql_branch_t *branch,
475
+ char haystack, char needle)
476
+ {
477
+ return haystack > needle;
478
+ }
479
+
480
+ static int ptql_op_chr_ge(ptql_branch_t *branch,
481
+ char haystack, char needle)
482
+ {
483
+ return haystack >= needle;
484
+ }
485
+
486
+ static int ptql_op_chr_lt(ptql_branch_t *branch,
487
+ char haystack, char needle)
488
+ {
489
+ return haystack < needle;
490
+ }
491
+
492
+ static int ptql_op_chr_le(ptql_branch_t *branch,
493
+ char haystack, char needle)
494
+ {
495
+ return haystack <= needle;
496
+ }
497
+
498
+ static ptql_op_chr_t ptql_op_chr[] = {
499
+ ptql_op_chr_eq,
500
+ ptql_op_chr_ne,
501
+ ptql_op_chr_gt,
502
+ ptql_op_chr_ge,
503
+ ptql_op_chr_lt,
504
+ ptql_op_chr_le
505
+ };
506
+
507
+ #define PTQL_BRANCH_LIST_MAX 3
508
+
509
+ #define PTQL_BRANCH_LIST_GROW(branches) \
510
+ if ((branches)->number >= (branches)->size) { \
511
+ ptql_branch_list_grow(branches); \
512
+ }
513
+
514
+ static int ptql_branch_list_create(ptql_branch_list_t *branches)
515
+ {
516
+ branches->number = 0;
517
+ branches->size = PTQL_BRANCH_LIST_MAX;
518
+ branches->data = malloc(sizeof(*(branches->data)) *
519
+ branches->size);
520
+
521
+ return SIGAR_OK;
522
+ }
523
+
524
+ static int ptql_branch_list_grow(ptql_branch_list_t *branches)
525
+ {
526
+ branches->data =
527
+ realloc(branches->data,
528
+ sizeof(*(branches->data)) *
529
+ (branches->size + PTQL_BRANCH_LIST_MAX));
530
+ branches->size += PTQL_BRANCH_LIST_MAX;
531
+
532
+ return SIGAR_OK;
533
+ }
534
+
535
+ static int ptql_branch_list_destroy(ptql_branch_list_t *branches)
536
+ {
537
+ if (branches->size) {
538
+ int i;
539
+
540
+ for (i=0; i<branches->number; i++) {
541
+ ptql_branch_t *branch =
542
+ &branches->data[i];
543
+
544
+ if (branch->data_size && branch->data.ptr) {
545
+ branch->data_free(branch->data.ptr);
546
+ }
547
+
548
+ if (branch->lookup &&
549
+ (branch->lookup->type == PTQL_VALUE_TYPE_STR) &&
550
+ !(branch->op_flags & PTQL_OP_FLAG_REF))
551
+ {
552
+ if (branch->value.str) {
553
+ branch->value_free(branch->value.str);
554
+ }
555
+ }
556
+ }
557
+
558
+ free(branches->data);
559
+ branches->number = branches->size = 0;
560
+ }
561
+
562
+ return SIGAR_OK;
563
+ }
564
+
565
+ #ifdef WIN32
566
+ #define vsnprintf _vsnprintf
567
+ #endif
568
+
569
+ #define PTQL_ERRNAN \
570
+ ptql_error(error, "Query value '%s' is not a number", parsed->value)
571
+
572
+ static int ptql_error(sigar_ptql_error_t *error, const char *format, ...)
573
+ {
574
+ va_list args;
575
+
576
+ if (error != NULL) {
577
+ va_start(args, format);
578
+ vsnprintf(error->message, sizeof(error->message), format, args);
579
+ va_end(args);
580
+ }
581
+
582
+ return SIGAR_PTQL_MALFORMED_QUERY;
583
+ }
584
+
585
+ static int ptql_branch_init_any(ptql_parse_branch_t *parsed,
586
+ ptql_branch_t *branch,
587
+ sigar_ptql_error_t *error)
588
+ {
589
+ branch->data.str = sigar_strdup(parsed->attr);
590
+ branch->data_size = strlen(parsed->attr);
591
+ return SIGAR_OK;
592
+ }
593
+
594
+ static int ptql_str_match(sigar_t *sigar, ptql_branch_t *branch, char *value)
595
+ {
596
+ if (!branch->value.str) {
597
+ return 0;
598
+ }
599
+ #ifndef SIGAR_HAS_PCRE
600
+ if (branch->op_name == PTQL_OP_RE) {
601
+ if (sigar->ptql_re_impl) {
602
+ return sigar->ptql_re_impl(sigar->ptql_re_data,
603
+ value,
604
+ branch->value.str);
605
+ }
606
+ else {
607
+ return 0;
608
+ }
609
+ }
610
+ #endif
611
+ return branch->match.str(branch,
612
+ value,
613
+ branch->value.str);
614
+ }
615
+
616
+ static int ptql_branch_match(ptql_branch_t *branch)
617
+ {
618
+ switch (branch->lookup->type) {
619
+ case PTQL_VALUE_TYPE_UI64:
620
+ return branch->match.ui64(branch,
621
+ *(sigar_uint64_t *)DATA_PTR(branch),
622
+ branch->value.ui64);
623
+ case PTQL_VALUE_TYPE_UI32:
624
+ return branch->match.ui32(branch,
625
+ *(sigar_uint32_t *)DATA_PTR(branch),
626
+ branch->value.ui32);
627
+ case PTQL_VALUE_TYPE_DBL:
628
+ return branch->match.dbl(branch,
629
+ *(double *)DATA_PTR(branch),
630
+ branch->value.dbl);
631
+ case PTQL_VALUE_TYPE_CHR:
632
+ return branch->match.chr(branch,
633
+ *(char *)DATA_PTR(branch),
634
+ branch->value.chr[0]);
635
+ case PTQL_VALUE_TYPE_STR:
636
+ case PTQL_VALUE_TYPE_ANY:
637
+ if (!branch->value.str) {
638
+ return 0;
639
+ }
640
+ return branch->match.str(branch,
641
+ (char *)DATA_PTR(branch),
642
+ branch->value.str);
643
+ default:
644
+ return 0;
645
+ }
646
+ }
647
+
648
+ static int ptql_branch_match_ref(ptql_branch_t *branch, ptql_branch_t *ref)
649
+ {
650
+ switch (branch->lookup->type) {
651
+ case PTQL_VALUE_TYPE_UI64:
652
+ return branch->match.ui64(branch,
653
+ *(sigar_uint64_t *)DATA_PTR(branch),
654
+ *(sigar_uint64_t *)DATA_PTR(ref));
655
+ case PTQL_VALUE_TYPE_UI32:
656
+ return branch->match.ui32(branch,
657
+ *(sigar_uint32_t *)DATA_PTR(branch),
658
+ *(sigar_uint32_t *)DATA_PTR(ref));
659
+ case PTQL_VALUE_TYPE_DBL:
660
+ return branch->match.dbl(branch,
661
+ *(double *)DATA_PTR(branch),
662
+ *(double *)DATA_PTR(ref));
663
+ case PTQL_VALUE_TYPE_CHR:
664
+ return branch->match.chr(branch,
665
+ *(char *)DATA_PTR(branch),
666
+ *(char *)DATA_PTR(ref));
667
+ case PTQL_VALUE_TYPE_STR:
668
+ case PTQL_VALUE_TYPE_ANY:
669
+ return branch->match.str(branch,
670
+ (char *)DATA_PTR(branch),
671
+ (char *)DATA_PTR(ref));
672
+ default:
673
+ return 0;
674
+ }
675
+ }
676
+
677
+ enum {
678
+ PTQL_PID_PID,
679
+ PTQL_PID_FILE,
680
+ PTQL_PID_SUDO_FILE,
681
+ PTQL_PID_TCP_PORT,
682
+ PTQL_PID_UDP_PORT,
683
+ PTQL_PID_SERVICE_NAME,
684
+ PTQL_PID_SERVICE_DISPLAY,
685
+ PTQL_PID_SERVICE_PATH,
686
+ PTQL_PID_SERVICE_EXE,
687
+ PTQL_PID_SERVICE_PID
688
+ };
689
+
690
+ #ifdef SIGAR_64BIT
691
+
692
+ #define str2pid(value, ptr) strtoull(value, &ptr, 10)
693
+
694
+ #define pid_branch_match(branch, pid, match_pid) \
695
+ ptql_op_ui64[branch->op_name](branch, pid, match_pid)
696
+
697
+ #else
698
+
699
+ #define str2pid(value, ptr) strtoul(value, &ptr, 10)
700
+
701
+ #define pid_branch_match(branch, pid, match_pid) \
702
+ ptql_op_ui32[branch->op_name](branch, pid, match_pid)
703
+
704
+ #endif
705
+
706
+ #ifndef WIN32
707
+ #include <sys/stat.h>
708
+ int sigar_sudo_file2str(const char *fname, char *buffer, int buflen)
709
+ {
710
+ FILE *fp;
711
+ struct stat sb;
712
+
713
+ if (stat(fname, &sb) < 0) {
714
+ return errno;
715
+ }
716
+ if (sb.st_size > buflen) {
717
+ return ENOMEM;
718
+ }
719
+ snprintf(buffer, buflen, "sudo cat %s", fname);
720
+ if (!(fp = popen(buffer, "r"))) {
721
+ return errno;
722
+ }
723
+ (void)fgets(buffer, buflen, fp);
724
+ pclose(fp);
725
+
726
+ return SIGAR_OK;
727
+ }
728
+ #endif
729
+
730
+ static int ptql_branch_init_service(ptql_parse_branch_t *parsed,
731
+ ptql_branch_t *branch,
732
+ sigar_ptql_error_t *error)
733
+ {
734
+ branch->op_flags |= PTQL_OP_FLAG_PID;
735
+
736
+ if (strEQ(parsed->attr, "Name")) {
737
+ branch->flags = PTQL_PID_SERVICE_NAME;
738
+ }
739
+ else if (strEQ(parsed->attr, "DisplayName")) {
740
+ branch->flags = PTQL_PID_SERVICE_DISPLAY;
741
+ }
742
+ else if (strEQ(parsed->attr, "Path")) {
743
+ branch->flags = PTQL_PID_SERVICE_PATH;
744
+ }
745
+ else if (strEQ(parsed->attr, "Exe")) {
746
+ /* basename of Path */
747
+ branch->flags = PTQL_PID_SERVICE_EXE;
748
+ }
749
+ else if (strEQ(parsed->attr, "Pid")) {
750
+ branch->flags = PTQL_PID_SERVICE_PID;
751
+ }
752
+ else {
753
+ return ptql_error(error, "Unsupported %s attribute: %s",
754
+ parsed->name, parsed->attr);
755
+ }
756
+
757
+ #ifdef WIN32
758
+ branch->data.str = sigar_strdup(parsed->value);
759
+ branch->data_size = strlen(parsed->value);
760
+ #endif
761
+ return SIGAR_OK;
762
+ }
763
+
764
+ static int ptql_branch_init_pid(ptql_parse_branch_t *parsed,
765
+ ptql_branch_t *branch,
766
+ sigar_ptql_error_t *error)
767
+ {
768
+ int use_sudo = 0;
769
+ branch->op_flags |= PTQL_OP_FLAG_PID;
770
+
771
+ if (strEQ(parsed->attr, "Pid")) {
772
+ branch->flags = PTQL_PID_PID;
773
+ if (strEQ(parsed->value, "$$")) {
774
+ branch->data.pid = getpid();
775
+ }
776
+ else {
777
+ char *ptr;
778
+ SIGAR_CLEAR_ERRNO();
779
+ branch->data.pid = str2pid(parsed->value, ptr);
780
+ if (strtonum_failed(parsed->value, ptr)) {
781
+ return PTQL_ERRNAN;
782
+ }
783
+ }
784
+ return SIGAR_OK;
785
+ }
786
+ else if (strEQ(parsed->attr, "PidFile") ||
787
+ (use_sudo = strEQ(parsed->attr, "SudoPidFile")))
788
+ {
789
+ branch->flags = use_sudo ? PTQL_PID_SUDO_FILE : PTQL_PID_FILE;
790
+ branch->data.str = sigar_strdup(parsed->value);
791
+ branch->data_size = strlen(parsed->value);
792
+ return SIGAR_OK;
793
+ }
794
+
795
+ return ptql_error(error, "Unsupported %s attribute: %s",
796
+ parsed->name, parsed->attr);
797
+ }
798
+
799
+ #ifdef WIN32
800
+ #define QUERY_SC_SIZE 8192
801
+
802
+ static int ptql_service_query_config(SC_HANDLE scm_handle,
803
+ char *name,
804
+ LPQUERY_SERVICE_CONFIG config)
805
+ {
806
+ int status;
807
+ DWORD bytes;
808
+ SC_HANDLE handle =
809
+ OpenService(scm_handle, name, SERVICE_QUERY_CONFIG);
810
+
811
+ if (!handle) {
812
+ return GetLastError();
813
+ }
814
+
815
+ if (QueryServiceConfig(handle, config, QUERY_SC_SIZE, &bytes)) {
816
+ status = SIGAR_OK;
817
+ }
818
+ else {
819
+ status = GetLastError();
820
+ }
821
+
822
+ CloseServiceHandle(handle);
823
+ return status;
824
+ }
825
+
826
+ static int sigar_services_walk(sigar_services_walker_t *walker,
827
+ ptql_branch_t *branch)
828
+ {
829
+ sigar_services_status_t ss;
830
+ char buffer[QUERY_SC_SIZE];
831
+ char exe[SIGAR_CMDLINE_MAX];
832
+ LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer;
833
+ DWORD i, status;
834
+
835
+ SIGAR_ZERO(&ss);
836
+ status = sigar_services_status_get(&ss, walker->flags);
837
+ if (status != SIGAR_OK) {
838
+ return status;
839
+ }
840
+ for (i=0; i<ss.count; i++) {
841
+ sigar_pid_t service_pid = 0;
842
+ int status;
843
+ char *value = NULL;
844
+ char *name = ss.services[i].lpServiceName;
845
+
846
+ if (branch == NULL) {
847
+ /* no query, return all */
848
+ if (walker->add_service(walker, name) != SIGAR_OK) {
849
+ break;
850
+ }
851
+ continue;
852
+ }
853
+
854
+ switch (branch->flags) {
855
+ case PTQL_PID_SERVICE_DISPLAY:
856
+ value = ss.services[i].lpDisplayName;
857
+ break;
858
+ case PTQL_PID_SERVICE_PATH:
859
+ case PTQL_PID_SERVICE_EXE:
860
+ status = ptql_service_query_config(ss.handle, name, config);
861
+ if (status == SIGAR_OK) {
862
+ if (branch->flags == PTQL_PID_SERVICE_EXE) {
863
+ value =
864
+ sigar_service_exe_get(config->lpBinaryPathName,
865
+ exe, 1);
866
+ }
867
+ else {
868
+ value = config->lpBinaryPathName;
869
+ }
870
+ }
871
+ else {
872
+ continue;
873
+ }
874
+ break;
875
+ case PTQL_PID_SERVICE_PID:
876
+ sigar_service_pid_get(walker->sigar,
877
+ name,
878
+ &service_pid);
879
+ break;
880
+ case PTQL_PID_SERVICE_NAME:
881
+ default:
882
+ value = name;
883
+ break;
884
+ }
885
+
886
+ if ((value && ptql_str_match(walker->sigar, branch, value)) ||
887
+ (service_pid &&
888
+ pid_branch_match(branch, service_pid, atoi(branch->data.str))))
889
+ {
890
+ if (walker->add_service(walker, name) != SIGAR_OK) {
891
+ break;
892
+ }
893
+ }
894
+ }
895
+
896
+ sigar_services_status_close(&ss);
897
+
898
+ return SIGAR_OK;
899
+ }
900
+
901
+ static int ptql_pid_service_add(sigar_services_walker_t *walker,
902
+ char *name)
903
+ {
904
+ sigar_pid_t service_pid;
905
+ sigar_proc_list_t *proclist =
906
+ (sigar_proc_list_t *)walker->data;
907
+ int status =
908
+ sigar_service_pid_get(walker->sigar,
909
+ name,
910
+ &service_pid);
911
+
912
+ if (status == SIGAR_OK) {
913
+ SIGAR_PROC_LIST_GROW(proclist);
914
+ proclist->data[proclist->number++] = service_pid;
915
+ }
916
+
917
+ return SIGAR_OK;
918
+ }
919
+
920
+ static int ptql_pid_service_list_get(sigar_t *sigar,
921
+ ptql_branch_t *branch,
922
+ sigar_proc_list_t *proclist)
923
+ {
924
+ sigar_services_walker_t walker;
925
+ walker.sigar = sigar;
926
+ walker.flags = SERVICE_ACTIVE;
927
+ walker.data = proclist;
928
+ walker.add_service = ptql_pid_service_add;
929
+
930
+ return sigar_services_walk(&walker, branch);
931
+ }
932
+
933
+ int sigar_services_query(char *ptql,
934
+ sigar_ptql_error_t *error,
935
+ sigar_services_walker_t *walker)
936
+ {
937
+ int status;
938
+ sigar_ptql_query_t *query;
939
+
940
+ if (ptql == NULL) {
941
+ return sigar_services_walk(walker, NULL);
942
+ }
943
+
944
+ status = sigar_ptql_query_create(&query, (char *)ptql, error);
945
+ if (status != SIGAR_OK) {
946
+ return status;
947
+ }
948
+
949
+ if (query->branches.number == 1) {
950
+ ptql_branch_t *branch = &query->branches.data[0];
951
+
952
+ if (IS_PID_SERVICE_QUERY(branch)) {
953
+ status = sigar_services_walk(walker, branch);
954
+ }
955
+ else {
956
+ ptql_error(error, "Invalid Service query: %s", ptql);
957
+ status = SIGAR_PTQL_MALFORMED_QUERY;
958
+ }
959
+ }
960
+ else {
961
+ ptql_error(error, "Too many queries (%d), must be (1)",
962
+ query->branches.number);
963
+ status = SIGAR_PTQL_MALFORMED_QUERY;
964
+ }
965
+
966
+ sigar_ptql_query_destroy(query);
967
+
968
+ return status;
969
+ }
970
+ #endif
971
+
972
+ static int ptql_pid_port_get(sigar_t *sigar,
973
+ ptql_branch_t *branch,
974
+ sigar_pid_t *pid)
975
+ {
976
+ unsigned long port =
977
+ branch->data.ui32;
978
+ int status;
979
+ int proto =
980
+ branch->flags == PTQL_PID_UDP_PORT ?
981
+ SIGAR_NETCONN_UDP : SIGAR_NETCONN_TCP;
982
+
983
+ status =
984
+ sigar_proc_port_get(sigar, proto, port, pid);
985
+
986
+ return status;
987
+ }
988
+
989
+ static int ptql_pid_get(sigar_t *sigar,
990
+ ptql_branch_t *branch,
991
+ sigar_pid_t *pid)
992
+ {
993
+ if ((branch->flags == PTQL_PID_FILE) ||
994
+ (branch->flags == PTQL_PID_SUDO_FILE))
995
+ {
996
+ char *ptr, buffer[SIGAR_PATH_MAX+1];
997
+ const char *fname = (const char *)branch->data.str;
998
+ int status, len = sizeof(buffer)-1;
999
+
1000
+ if (branch->flags == PTQL_PID_FILE) {
1001
+ status = sigar_file2str(fname, buffer, len);
1002
+ }
1003
+ else {
1004
+ #ifdef WIN32
1005
+ return SIGAR_ENOTIMPL;
1006
+ #else
1007
+ status = sigar_sudo_file2str(fname, buffer, len);
1008
+ #endif
1009
+ }
1010
+ if (status != SIGAR_OK) {
1011
+ return status;
1012
+ }
1013
+ SIGAR_CLEAR_ERRNO();
1014
+ *pid = str2pid(buffer, ptr);
1015
+ if ((buffer == ptr) || (errno == ERANGE)) {
1016
+ return errno;
1017
+ }
1018
+ }
1019
+ else if (branch->flags == PTQL_PID_SERVICE_NAME) {
1020
+ #ifdef WIN32
1021
+ int status =
1022
+ sigar_service_pid_get(sigar,
1023
+ branch->data.str, pid);
1024
+ if (status != SIGAR_OK) {
1025
+ return status;
1026
+ }
1027
+ #else
1028
+ return SIGAR_ENOTIMPL;
1029
+ #endif
1030
+ }
1031
+ else if ((branch->flags == PTQL_PID_UDP_PORT) ||
1032
+ (branch->flags == PTQL_PID_TCP_PORT))
1033
+ {
1034
+ int status = ptql_pid_port_get(sigar, branch, pid);
1035
+ if (status != SIGAR_OK) {
1036
+ return status;
1037
+ }
1038
+ }
1039
+ else {
1040
+ *pid = branch->data.pid;
1041
+ }
1042
+
1043
+ return SIGAR_OK;
1044
+ }
1045
+
1046
+ static int ptql_pid_list_get(sigar_t *sigar,
1047
+ ptql_branch_t *branch,
1048
+ sigar_proc_list_t *proclist)
1049
+ {
1050
+ int status, i;
1051
+ sigar_pid_t match_pid;
1052
+
1053
+ if (IS_PID_SERVICE_QUERY(branch)) {
1054
+ if ((branch->flags > PTQL_PID_SERVICE_NAME) ||
1055
+ (branch->op_name != PTQL_OP_EQ))
1056
+ {
1057
+ #ifdef WIN32
1058
+ return ptql_pid_service_list_get(sigar, branch, proclist);
1059
+ #else
1060
+ return SIGAR_OK; /* no matches */
1061
+ #endif
1062
+ }
1063
+ }
1064
+
1065
+ status = ptql_pid_get(sigar, branch, &match_pid);
1066
+
1067
+ if (status != SIGAR_OK) {
1068
+ /* XXX treated as non-match but would be nice to propagate */
1069
+ return SIGAR_OK;
1070
+ }
1071
+
1072
+ status = sigar_proc_list_get(sigar, NULL);
1073
+ if (status != SIGAR_OK) {
1074
+ return status;
1075
+ }
1076
+ for (i=0; i<sigar->pids->number; i++) {
1077
+ sigar_pid_t pid = sigar->pids->data[i];
1078
+ if (pid_branch_match(branch, pid, match_pid)) {
1079
+ SIGAR_PROC_LIST_GROW(proclist);
1080
+ proclist->data[proclist->number++] = pid;
1081
+ }
1082
+ }
1083
+
1084
+ return SIGAR_OK;
1085
+ }
1086
+
1087
+ static int SIGAPI ptql_pid_match(sigar_t *sigar,
1088
+ sigar_pid_t pid,
1089
+ void *data)
1090
+ {
1091
+ /* query already used to filter proc_list */
1092
+ return SIGAR_OK;
1093
+ }
1094
+
1095
+ static int ptql_args_branch_init(ptql_parse_branch_t *parsed,
1096
+ ptql_branch_t *branch,
1097
+ sigar_ptql_error_t *error)
1098
+ {
1099
+ if (strEQ(parsed->attr, "*")) {
1100
+ branch->op_flags |= PTQL_OP_FLAG_GLOB;
1101
+ }
1102
+ else {
1103
+ char *end;
1104
+
1105
+ SIGAR_CLEAR_ERRNO();
1106
+ branch->data.ui32 =
1107
+ strtol(parsed->attr, &end, 10);
1108
+
1109
+ if (strtonum_failed(parsed->attr, end)) {
1110
+ /* conversion failed */
1111
+ return ptql_error(error, "%s is not a number", parsed->attr);
1112
+ }
1113
+ }
1114
+ return SIGAR_OK;
1115
+ }
1116
+
1117
+ static int SIGAPI ptql_args_match(sigar_t *sigar,
1118
+ sigar_pid_t pid,
1119
+ void *data)
1120
+ {
1121
+ ptql_branch_t *branch =
1122
+ (ptql_branch_t *)data;
1123
+ int status, matched=0;
1124
+ sigar_proc_args_t args;
1125
+
1126
+ status = sigar_proc_args_get(sigar, pid, &args);
1127
+ if (status != SIGAR_OK) {
1128
+ return status;
1129
+ }
1130
+
1131
+ if (branch->op_flags & PTQL_OP_FLAG_GLOB) {
1132
+ int i;
1133
+ for (i=0; i<args.number; i++) {
1134
+ matched =
1135
+ ptql_str_match(sigar, branch, args.data[i]);
1136
+
1137
+ if (matched) {
1138
+ break;
1139
+ }
1140
+ }
1141
+ }
1142
+ else {
1143
+ int num = branch->data.ui32;
1144
+
1145
+ /* e.g. find last element of args: Args.-1.eq=weblogic.Server */
1146
+ if (num < 0) {
1147
+ num += args.number;
1148
+ }
1149
+ if ((num >= 0) && (num < args.number)) {
1150
+ matched =
1151
+ ptql_str_match(sigar, branch, args.data[num]);
1152
+ }
1153
+ }
1154
+
1155
+ sigar_proc_args_destroy(sigar, &args);
1156
+
1157
+ return matched ? SIGAR_OK : !SIGAR_OK;
1158
+ }
1159
+
1160
+ typedef struct {
1161
+ sigar_t *sigar;
1162
+ ptql_branch_t *branch;
1163
+ sigar_uint32_t ix;
1164
+ int matched;
1165
+ } proc_modules_match_t;
1166
+
1167
+ static int proc_modules_match(void *data, char *name, int len)
1168
+ {
1169
+ proc_modules_match_t *matcher =
1170
+ (proc_modules_match_t *)data;
1171
+ ptql_branch_t *branch = matcher->branch;
1172
+
1173
+ if (branch->op_flags & PTQL_OP_FLAG_GLOB) { /* Modules.*.ct=libc */
1174
+ matcher->matched =
1175
+ ptql_str_match(matcher->sigar, branch, name);
1176
+
1177
+ if (matcher->matched) {
1178
+ return !SIGAR_OK; /* stop iterating */
1179
+ }
1180
+ }
1181
+ else {
1182
+ if (matcher->ix++ == branch->data.ui32) { /* Modules.3.ct=libc */
1183
+ matcher->matched =
1184
+ ptql_str_match(matcher->sigar, branch, name);
1185
+ return !SIGAR_OK; /* stop iterating */
1186
+ }
1187
+ }
1188
+
1189
+ return SIGAR_OK;
1190
+ }
1191
+
1192
+ static int SIGAPI ptql_modules_match(sigar_t *sigar,
1193
+ sigar_pid_t pid,
1194
+ void *data)
1195
+ {
1196
+ ptql_branch_t *branch =
1197
+ (ptql_branch_t *)data;
1198
+ int status;
1199
+ sigar_proc_modules_t procmods;
1200
+ proc_modules_match_t matcher;
1201
+
1202
+ matcher.sigar = sigar;
1203
+ matcher.branch = branch;
1204
+ matcher.ix = 0;
1205
+ matcher.matched = 0;
1206
+
1207
+ procmods.module_getter = proc_modules_match;
1208
+ procmods.data = &matcher;
1209
+
1210
+ status = sigar_proc_modules_get(sigar, pid, &procmods);
1211
+
1212
+ if (status != SIGAR_OK) {
1213
+ return status;
1214
+ }
1215
+
1216
+ return matcher.matched ? SIGAR_OK : !SIGAR_OK;
1217
+ }
1218
+
1219
+ typedef struct {
1220
+ const char *key;
1221
+ int klen;
1222
+ char *val;
1223
+ int vlen;
1224
+ } sigar_proc_env_entry_t;
1225
+
1226
+ static int sigar_proc_env_get_key(void *data,
1227
+ const char *key, int klen,
1228
+ char *val, int vlen)
1229
+ {
1230
+ sigar_proc_env_entry_t *entry =
1231
+ (sigar_proc_env_entry_t *)data;
1232
+
1233
+ if ((entry->klen == klen) &&
1234
+ (strcmp(entry->key, key) == 0))
1235
+ {
1236
+ entry->val = val;
1237
+ entry->vlen = vlen;
1238
+ return !SIGAR_OK; /* foundit; stop iterating */
1239
+ }
1240
+
1241
+ return SIGAR_OK;
1242
+ }
1243
+
1244
+ static int SIGAPI ptql_env_match(sigar_t *sigar,
1245
+ sigar_pid_t pid,
1246
+ void *data)
1247
+ {
1248
+ ptql_branch_t *branch =
1249
+ (ptql_branch_t *)data;
1250
+ int status, matched=0;
1251
+ sigar_proc_env_t procenv;
1252
+ sigar_proc_env_entry_t entry;
1253
+
1254
+ /* XXX ugh this is klunky */
1255
+ entry.key = branch->data.str;
1256
+ entry.klen = branch->data_size;
1257
+ entry.val = NULL;
1258
+
1259
+ procenv.type = SIGAR_PROC_ENV_KEY;
1260
+ procenv.key = branch->data.str;
1261
+ procenv.klen = branch->data_size;
1262
+ procenv.env_getter = sigar_proc_env_get_key;
1263
+ procenv.data = &entry;
1264
+
1265
+ status = sigar_proc_env_get(sigar, pid, &procenv);
1266
+ if (status != SIGAR_OK) {
1267
+ return status;
1268
+ }
1269
+ else {
1270
+ if (entry.val) {
1271
+ matched =
1272
+ ptql_str_match(sigar, branch, entry.val);
1273
+ }
1274
+ }
1275
+
1276
+ return matched ? SIGAR_OK : !SIGAR_OK;
1277
+ }
1278
+
1279
+ static int ptql_branch_init_port(ptql_parse_branch_t *parsed,
1280
+ ptql_branch_t *branch,
1281
+ sigar_ptql_error_t *error)
1282
+ {
1283
+ char *ptr;
1284
+
1285
+ /* only 'eq' is supported here */
1286
+ if (branch->op_name != PTQL_OP_EQ) {
1287
+ return ptql_error(error, "%s requires 'eq' operator",
1288
+ parsed->name);
1289
+ }
1290
+
1291
+ if (strEQ(parsed->attr, "tcp")) {
1292
+ branch->flags = PTQL_PID_TCP_PORT;
1293
+ }
1294
+ else if (strEQ(parsed->attr, "udp")) {
1295
+ branch->flags = PTQL_PID_TCP_PORT;
1296
+ }
1297
+ else {
1298
+ return ptql_error(error, "Unsupported %s protocol: %s",
1299
+ parsed->name, parsed->attr);
1300
+ }
1301
+
1302
+ branch->op_flags |= PTQL_OP_FLAG_PID;
1303
+ SIGAR_CLEAR_ERRNO();
1304
+ branch->data.ui32 = strtoul(parsed->value, &ptr, 10);
1305
+ if (strtonum_failed(parsed->value, ptr)) {
1306
+ return PTQL_ERRNAN;
1307
+ }
1308
+
1309
+ return SIGAR_OK;
1310
+ }
1311
+
1312
+ #define PTQL_LOOKUP_ENTRY(cname, member, type) \
1313
+ (ptql_get_t)sigar_##cname##_get, \
1314
+ sigar_offsetof(sigar_##cname##_t, member), \
1315
+ sizeof(sigar_##cname##_t), \
1316
+ PTQL_VALUE_TYPE_##type, \
1317
+ NULL
1318
+
1319
+ /* XXX uid/pid can be larger w/ 64bit mode */
1320
+ #define PTQL_VALUE_TYPE_PID PTQL_VALUE_TYPE_UI32
1321
+ #define PTQL_VALUE_TYPE_UID PTQL_VALUE_TYPE_UI32
1322
+
1323
+ static ptql_lookup_t PTQL_Time[] = {
1324
+ { "StartTime", PTQL_LOOKUP_ENTRY(proc_time, start_time, UI64) },
1325
+ { "User", PTQL_LOOKUP_ENTRY(proc_time, user, UI64) },
1326
+ { "Sys", PTQL_LOOKUP_ENTRY(proc_time, sys, UI64) },
1327
+ { "Total", PTQL_LOOKUP_ENTRY(proc_time, total, UI64) },
1328
+ { NULL }
1329
+ };
1330
+
1331
+ static ptql_lookup_t PTQL_Cpu[] = {
1332
+ { "StartTime", PTQL_LOOKUP_ENTRY(proc_cpu, start_time, UI64) },
1333
+ { "User", PTQL_LOOKUP_ENTRY(proc_cpu, user, UI64) },
1334
+ { "Sys", PTQL_LOOKUP_ENTRY(proc_cpu, sys, UI64) },
1335
+ { "Total", PTQL_LOOKUP_ENTRY(proc_cpu, total, UI64) },
1336
+ { "Percent", PTQL_LOOKUP_ENTRY(proc_cpu, percent, DBL) },
1337
+ { NULL }
1338
+ };
1339
+
1340
+ static ptql_lookup_t PTQL_CredName[] = {
1341
+ { "User", PTQL_LOOKUP_ENTRY(proc_cred_name, user, STR) },
1342
+ { "Group", PTQL_LOOKUP_ENTRY(proc_cred_name, group, STR) },
1343
+ { NULL }
1344
+ };
1345
+
1346
+ static ptql_lookup_t PTQL_Mem[] = {
1347
+ { "Size", PTQL_LOOKUP_ENTRY(proc_mem, size, UI64) },
1348
+ { "Resident", PTQL_LOOKUP_ENTRY(proc_mem, resident, UI64) },
1349
+ { "Share", PTQL_LOOKUP_ENTRY(proc_mem, share, UI64) },
1350
+ { "MinorFaults", PTQL_LOOKUP_ENTRY(proc_mem, minor_faults, UI64) },
1351
+ { "MajorFaults", PTQL_LOOKUP_ENTRY(proc_mem, major_faults, UI64) },
1352
+ { "PageFaults", PTQL_LOOKUP_ENTRY(proc_mem, page_faults, UI64) },
1353
+ { NULL }
1354
+ };
1355
+
1356
+ static ptql_lookup_t PTQL_Exe[] = {
1357
+ { "Name", PTQL_LOOKUP_ENTRY(proc_exe, name, STR) },
1358
+ { "Cwd", PTQL_LOOKUP_ENTRY(proc_exe, cwd, STR) },
1359
+ { NULL }
1360
+ };
1361
+
1362
+ static ptql_lookup_t PTQL_Cred[] = {
1363
+ { "Uid", PTQL_LOOKUP_ENTRY(proc_cred, uid, UID) },
1364
+ { "Gid", PTQL_LOOKUP_ENTRY(proc_cred, gid, UID) },
1365
+ { "Euid", PTQL_LOOKUP_ENTRY(proc_cred, euid, UID) },
1366
+ { "Egid", PTQL_LOOKUP_ENTRY(proc_cred, egid, UID) },
1367
+ { NULL }
1368
+ };
1369
+
1370
+ static ptql_lookup_t PTQL_State[] = {
1371
+ { "State", PTQL_LOOKUP_ENTRY(proc_state, state, CHR) },
1372
+ { "Name", PTQL_LOOKUP_ENTRY(proc_state, name, STR) },
1373
+ { "Ppid", PTQL_LOOKUP_ENTRY(proc_state, ppid, PID) },
1374
+ { "Tty", PTQL_LOOKUP_ENTRY(proc_state, tty, UI32) },
1375
+ { "Nice", PTQL_LOOKUP_ENTRY(proc_state, nice, UI32) },
1376
+ { "Priority", PTQL_LOOKUP_ENTRY(proc_state, priority, UI32) },
1377
+ { "Threads", PTQL_LOOKUP_ENTRY(proc_state, threads, UI64) },
1378
+ { "Processor", PTQL_LOOKUP_ENTRY(proc_state, processor, UI32) },
1379
+ { NULL }
1380
+ };
1381
+
1382
+ static ptql_lookup_t PTQL_Fd[] = {
1383
+ { "Total", PTQL_LOOKUP_ENTRY(proc_fd, total, UI64) },
1384
+ { NULL }
1385
+ };
1386
+
1387
+ static ptql_lookup_t PTQL_Args[] = {
1388
+ { NULL, ptql_args_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init }
1389
+ };
1390
+
1391
+ static ptql_lookup_t PTQL_Modules[] = {
1392
+ { NULL, ptql_modules_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init }
1393
+ };
1394
+
1395
+ static ptql_lookup_t PTQL_Env[] = {
1396
+ { NULL, ptql_env_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_any }
1397
+ };
1398
+
1399
+ static ptql_lookup_t PTQL_Port[] = {
1400
+ { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_port }
1401
+ };
1402
+
1403
+ static ptql_lookup_t PTQL_Pid[] = {
1404
+ { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_pid }
1405
+ };
1406
+
1407
+ static ptql_lookup_t PTQL_Service[] = {
1408
+ { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_service }
1409
+ };
1410
+
1411
+ static ptql_entry_t ptql_map[] = {
1412
+ { "Time", PTQL_Time },
1413
+ { "Cpu", PTQL_Cpu },
1414
+ { "CredName", PTQL_CredName },
1415
+ { "Mem", PTQL_Mem },
1416
+ { "Exe", PTQL_Exe },
1417
+ { "Cred", PTQL_Cred },
1418
+ { "State", PTQL_State },
1419
+ { "Fd", PTQL_Fd },
1420
+ { "Args", PTQL_Args },
1421
+ { "Modules", PTQL_Modules },
1422
+ { "Env", PTQL_Env },
1423
+ { "Port", PTQL_Port },
1424
+ { "Pid", PTQL_Pid },
1425
+ { "Service", PTQL_Service },
1426
+ { NULL }
1427
+ };
1428
+
1429
+ static int ptql_branch_parse(char *query, ptql_parse_branch_t *branch,
1430
+ sigar_ptql_error_t *error)
1431
+ {
1432
+ char *ptr = strchr(query, '=');
1433
+ if (!ptr) {
1434
+ return ptql_error(error, "Missing '='");
1435
+ }
1436
+
1437
+ branch->op_flags = 0;
1438
+
1439
+ *ptr = '\0';
1440
+ branch->value = ++ptr;
1441
+
1442
+ if ((ptr = strchr(query, '.'))) {
1443
+ *ptr = '\0';
1444
+ branch->name = query;
1445
+ query = ++ptr;
1446
+ }
1447
+ else {
1448
+ return ptql_error(error, "Missing '.'");
1449
+ }
1450
+
1451
+ if ((ptr = strchr(query, '.'))) {
1452
+ *ptr = '\0';
1453
+ branch->attr = query;
1454
+ query = ++ptr;
1455
+ }
1456
+ else {
1457
+ return ptql_error(error, "Missing '.'");
1458
+ }
1459
+
1460
+ if (*query) {
1461
+ char flag;
1462
+
1463
+ while (sigar_isupper((flag = *query))) {
1464
+ switch (flag) {
1465
+ case 'P':
1466
+ branch->op_flags |= PTQL_OP_FLAG_PARENT;
1467
+ break;
1468
+ case 'I':
1469
+ branch->op_flags |= PTQL_OP_FLAG_ICASE;
1470
+ break;
1471
+ default:
1472
+ return ptql_error(error, "Unsupported modifier: %c", flag);
1473
+ }
1474
+
1475
+ ++query;
1476
+ }
1477
+
1478
+ branch->op = query;
1479
+ }
1480
+ else {
1481
+ return ptql_error(error, "Missing query");
1482
+ }
1483
+
1484
+ /* Pid.Service -> Service.Name */
1485
+ if (strEQ(branch->attr, "Service")) {
1486
+ branch->name = branch->attr;
1487
+ branch->attr = "Name";
1488
+ }
1489
+
1490
+ return SIGAR_OK;
1491
+ }
1492
+
1493
+ static int ptql_branch_add(ptql_parse_branch_t *parsed,
1494
+ ptql_branch_list_t *branches,
1495
+ sigar_ptql_error_t *error)
1496
+ {
1497
+ ptql_branch_t *branch;
1498
+ ptql_entry_t *entry = NULL;
1499
+ ptql_lookup_t *lookup = NULL;
1500
+ int i, is_set=0;
1501
+ char *ptr;
1502
+
1503
+ PTQL_BRANCH_LIST_GROW(branches);
1504
+
1505
+ branch = &branches->data[branches->number++];
1506
+ SIGAR_ZERO(branch);
1507
+ branch->data_free = data_free;
1508
+ branch->value_free = data_free;
1509
+ branch->op_flags = parsed->op_flags;
1510
+
1511
+ branch->op_name = ptql_op_code_get(parsed->op);
1512
+ if (branch->op_name == PTQL_OP_MAX) {
1513
+ return ptql_error(error, "Unsupported operator: %s", parsed->op);
1514
+ }
1515
+
1516
+ for (i=0; ptql_map[i].name; i++) {
1517
+ if (strEQ(ptql_map[i].name, parsed->name)) {
1518
+ entry = &ptql_map[i];
1519
+ break;
1520
+ }
1521
+ }
1522
+
1523
+ if (!entry) {
1524
+ return ptql_error(error, "Unsupported method: %s", parsed->name);
1525
+ }
1526
+
1527
+ for (i=0; entry->members[i].name; i++) {
1528
+ if (strEQ(entry->members[i].name, parsed->attr)) {
1529
+ lookup = &entry->members[i];
1530
+ break;
1531
+ }
1532
+ }
1533
+
1534
+ if (!lookup) {
1535
+ if (entry->members[0].type == PTQL_VALUE_TYPE_ANY) {
1536
+ /* Args, Env, etc. */
1537
+ lookup = &entry->members[0];
1538
+ }
1539
+ else {
1540
+ return ptql_error(error, "Unsupported %s attribute: %s",
1541
+ parsed->name, parsed->attr);
1542
+ }
1543
+ }
1544
+
1545
+ if (lookup->init) {
1546
+ int status = lookup->init(parsed, branch, error);
1547
+ if (status != SIGAR_OK) {
1548
+ return status;
1549
+ }
1550
+ }
1551
+
1552
+ branch->lookup = lookup;
1553
+
1554
+ if ((lookup->type < PTQL_VALUE_TYPE_STR) &&
1555
+ (branch->op_name > PTQL_OP_MAX_NSTR))
1556
+ {
1557
+ return ptql_error(error, "Unsupported operator '%s' for %s.%s",
1558
+ parsed->op, parsed->name, parsed->attr);
1559
+ }
1560
+
1561
+ if (*parsed->value == '$') {
1562
+ is_set = 1;
1563
+
1564
+ if (branch->op_name == PTQL_OP_RE) {
1565
+ /* not for use with .re */
1566
+ return ptql_error(error, "Unsupported operator '%s' with variable %s",
1567
+ parsed->op, parsed->value);
1568
+ }
1569
+
1570
+ if (sigar_isdigit(*(parsed->value+1))) {
1571
+ branch->op_flags |= PTQL_OP_FLAG_REF;
1572
+ parsed->op_flags = branch->op_flags; /* for use by caller */
1573
+ branch->value.ui32 = atoi(parsed->value+1) - 1;
1574
+
1575
+ if (branch->value.ui32 >= branches->number) {
1576
+ /* out-of-range */
1577
+ return ptql_error(error, "Variable %s out of range (%d)",
1578
+ parsed->value, branches->number);
1579
+ }
1580
+ else if (branch->value.ui32 == branches->number-1) {
1581
+ /* self reference */
1582
+ return ptql_error(error, "Variable %s self reference",
1583
+ parsed->value);
1584
+ }
1585
+ }
1586
+ else {
1587
+ if ((ptr = getenv(parsed->value+1))) {
1588
+ branch->value.str = sigar_strdup(ptr);
1589
+ }
1590
+ else {
1591
+ branch->value.str = NULL;
1592
+ }
1593
+ }
1594
+ }
1595
+ else if (branch->op_name == PTQL_OP_RE) {
1596
+ #ifdef SIGAR_HAS_PCRE
1597
+ const char *error;
1598
+ int offset;
1599
+ pcre *re =
1600
+ pcre_compile(parsed->value, 0,
1601
+ &error, &offset, NULL);
1602
+ if (!re) {
1603
+ /* XXX pcre_error ? */
1604
+ return ptql_error(error, "Invalid regex");
1605
+ }
1606
+ is_set = 1;
1607
+ branch->value.ptr = re;
1608
+ branch->value_free = pcre_free;
1609
+ #endif
1610
+ }
1611
+
1612
+ switch (lookup->type) {
1613
+ case PTQL_VALUE_TYPE_UI64:
1614
+ branch->match.ui64 = ptql_op_ui64[branch->op_name];
1615
+ if (!is_set) {
1616
+ SIGAR_CLEAR_ERRNO();
1617
+ branch->value.ui64 = strtoull(parsed->value, &ptr, 10);
1618
+ if (strtonum_failed(parsed->value, ptr)) {
1619
+ return PTQL_ERRNAN;
1620
+ }
1621
+ }
1622
+ break;
1623
+ case PTQL_VALUE_TYPE_UI32:
1624
+ branch->match.ui32 = ptql_op_ui32[branch->op_name];
1625
+ if (!is_set) {
1626
+ SIGAR_CLEAR_ERRNO();
1627
+ branch->value.ui32 = strtoul(parsed->value, &ptr, 10);
1628
+ if (strtonum_failed(parsed->value, ptr)) {
1629
+ return PTQL_ERRNAN;
1630
+ }
1631
+ }
1632
+ break;
1633
+ case PTQL_VALUE_TYPE_DBL:
1634
+ branch->match.dbl = ptql_op_dbl[branch->op_name];
1635
+ if (!is_set) {
1636
+ SIGAR_CLEAR_ERRNO();
1637
+ branch->value.dbl = strtod(parsed->value, &ptr);
1638
+ if (strtonum_failed(parsed->value, ptr)) {
1639
+ return PTQL_ERRNAN;
1640
+ }
1641
+ }
1642
+ break;
1643
+ case PTQL_VALUE_TYPE_CHR:
1644
+ branch->match.chr = ptql_op_chr[branch->op_name];
1645
+ if (!is_set) {
1646
+ if (strlen(parsed->value) != 1) {
1647
+ return ptql_error(error, "%s is not a char", parsed->value);
1648
+ }
1649
+ branch->value.chr[0] = parsed->value[0];
1650
+ }
1651
+ break;
1652
+ case PTQL_VALUE_TYPE_STR:
1653
+ case PTQL_VALUE_TYPE_ANY:
1654
+ branch->match.str = ptql_op_str[branch->op_name];
1655
+ if (!is_set) {
1656
+ branch->value.str = sigar_strdup(parsed->value);
1657
+ }
1658
+ break;
1659
+ }
1660
+
1661
+ return SIGAR_OK;
1662
+ }
1663
+
1664
+ static int ptql_branch_compare(const void *b1, const void *b2)
1665
+ {
1666
+ /* XXX can do better */
1667
+ ptql_branch_t *branch1 = (ptql_branch_t *)b1;
1668
+ ptql_branch_t *branch2 = (ptql_branch_t *)b2;
1669
+ return
1670
+ branch1->lookup->type -
1671
+ branch2->lookup->type;
1672
+ }
1673
+
1674
+ SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **queryp,
1675
+ char *ptql,
1676
+ sigar_ptql_error_t *error)
1677
+ {
1678
+ char *ptr, *ptql_copy = sigar_strdup(ptql);
1679
+ int status = SIGAR_OK;
1680
+ int has_ref = 0;
1681
+ sigar_ptql_query_t *query =
1682
+ *queryp = malloc(sizeof(*query));
1683
+
1684
+ (void)ptql_error(error, "Malformed query");
1685
+
1686
+ #ifdef PTQL_DEBUG
1687
+ query->ptql = sigar_strdup(ptql);
1688
+ #endif
1689
+
1690
+ ptql = ptql_copy;
1691
+
1692
+ ptql_branch_list_create(&query->branches);
1693
+
1694
+ do {
1695
+ ptql_parse_branch_t parsed;
1696
+
1697
+ if ((ptr = strchr(ptql, ','))) {
1698
+ *ptr = '\0';
1699
+ }
1700
+
1701
+ status = ptql_branch_parse(ptql, &parsed, error);
1702
+ if (status == SIGAR_OK) {
1703
+ status =
1704
+ ptql_branch_add(&parsed, &query->branches, error);
1705
+
1706
+ if (status != SIGAR_OK) {
1707
+ break;
1708
+ }
1709
+ if (parsed.op_flags & PTQL_OP_FLAG_REF) {
1710
+ has_ref = 1;
1711
+ }
1712
+ }
1713
+ else {
1714
+ break;
1715
+ }
1716
+
1717
+ if (ptr) {
1718
+ ptql = ++ptr;
1719
+ }
1720
+ else {
1721
+ break;
1722
+ }
1723
+ } while (*ptql);
1724
+
1725
+ free(ptql_copy);
1726
+
1727
+ if (status != SIGAR_OK) {
1728
+ sigar_ptql_query_destroy(query);
1729
+ *queryp = NULL;
1730
+ }
1731
+ else if (!has_ref && (query->branches.number > 1)) {
1732
+ qsort(query->branches.data,
1733
+ query->branches.number,
1734
+ sizeof(query->branches.data[0]),
1735
+ ptql_branch_compare);
1736
+ }
1737
+
1738
+ if (status == SIGAR_OK) {
1739
+ (void)ptql_error(error, "OK");
1740
+ }
1741
+ return status;
1742
+ }
1743
+
1744
+ SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query)
1745
+ {
1746
+ #ifdef PTQL_DEBUG
1747
+ free(query->ptql);
1748
+ #endif
1749
+ ptql_branch_list_destroy(&query->branches);
1750
+ free(query);
1751
+ return SIGAR_OK;
1752
+ }
1753
+
1754
+ SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data,
1755
+ sigar_ptql_re_impl_t impl)
1756
+ {
1757
+ sigar->ptql_re_data = data;
1758
+ sigar->ptql_re_impl = impl;
1759
+ }
1760
+
1761
+ SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar,
1762
+ sigar_ptql_query_t *query,
1763
+ sigar_pid_t query_pid)
1764
+ {
1765
+ int i;
1766
+
1767
+ for (i=0; i<query->branches.number; i++) {
1768
+ sigar_pid_t pid = query_pid;
1769
+ int status, matched=0;
1770
+ ptql_branch_t *branch = &query->branches.data[i];
1771
+ ptql_lookup_t *lookup = branch->lookup;
1772
+
1773
+ if (branch->op_flags & PTQL_OP_FLAG_PARENT) {
1774
+ sigar_proc_state_t state;
1775
+
1776
+ status = sigar_proc_state_get(sigar, pid, &state);
1777
+ if (status != SIGAR_OK) {
1778
+ return status;
1779
+ }
1780
+
1781
+ pid = state.ppid;
1782
+ }
1783
+
1784
+ if (lookup->type == PTQL_VALUE_TYPE_ANY) {
1785
+ /* Args, Env, etc. */
1786
+ status = lookup->get(sigar, pid, branch);
1787
+ if (status == SIGAR_OK) {
1788
+ matched = 1;
1789
+ }
1790
+ }
1791
+ else {
1792
+ /* standard sigar_proc_*_get / structptr + offset */
1793
+ if (!branch->data.ptr) {
1794
+ branch->data_size = lookup->data_size;
1795
+ branch->data.ptr = malloc(branch->data_size);
1796
+ }
1797
+ status = lookup->get(sigar, pid, branch->data.ptr);
1798
+ if (status != SIGAR_OK) {
1799
+ return status;
1800
+ }
1801
+
1802
+ if (branch->op_flags & PTQL_OP_FLAG_REF) {
1803
+ ptql_branch_t *ref =
1804
+ &query->branches.data[branch->value.ui32];
1805
+
1806
+ matched = ptql_branch_match_ref(branch, ref);
1807
+ }
1808
+ #ifndef SIGAR_HAS_PCRE
1809
+ else if (branch->lookup->type == PTQL_VALUE_TYPE_STR) {
1810
+ matched = ptql_str_match(sigar, branch, (char *)DATA_PTR(branch));
1811
+ }
1812
+ #endif
1813
+ else {
1814
+ matched = ptql_branch_match(branch);
1815
+ }
1816
+ }
1817
+
1818
+ if (!matched) {
1819
+ return 1;
1820
+ }
1821
+ }
1822
+
1823
+ return SIGAR_OK;
1824
+ }
1825
+
1826
+ static int ptql_proc_list_get(sigar_t *sigar,
1827
+ sigar_ptql_query_t *query,
1828
+ sigar_proc_list_t **proclist)
1829
+ {
1830
+ int status;
1831
+ int i;
1832
+
1833
+ *proclist = NULL;
1834
+
1835
+ for (i=0; i<query->branches.number; i++) {
1836
+ ptql_branch_t *branch = &query->branches.data[i];
1837
+
1838
+ if (branch->op_flags & PTQL_OP_FLAG_PID) {
1839
+ /* pre-filter pid list for Pid.* queries */
1840
+ /* XXX multiple Pid.* may result in dups */
1841
+ if (*proclist == NULL) {
1842
+ *proclist = malloc(sizeof(**proclist));
1843
+ SIGAR_ZERO(*proclist);
1844
+ sigar_proc_list_create(*proclist);
1845
+ }
1846
+ status = ptql_pid_list_get(sigar, branch, *proclist);
1847
+ if (status != SIGAR_OK) {
1848
+ sigar_proc_list_destroy(sigar, *proclist);
1849
+ free(*proclist);
1850
+ return status;
1851
+ }
1852
+ }
1853
+ }
1854
+
1855
+ if (*proclist) {
1856
+ return SIGAR_OK;
1857
+ }
1858
+
1859
+ status = sigar_proc_list_get(sigar, NULL);
1860
+ if (status != SIGAR_OK) {
1861
+ return status;
1862
+ }
1863
+ *proclist = sigar->pids;
1864
+ return SIGAR_OK;
1865
+ }
1866
+
1867
+ static int ptql_proc_list_destroy(sigar_t *sigar,
1868
+ sigar_proc_list_t *proclist)
1869
+ {
1870
+ if (proclist != sigar->pids) {
1871
+ sigar_proc_list_destroy(sigar, proclist);
1872
+ free(proclist);
1873
+ }
1874
+
1875
+ return SIGAR_OK;
1876
+ }
1877
+
1878
+ SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar,
1879
+ sigar_ptql_query_t *query,
1880
+ sigar_pid_t *pid)
1881
+ {
1882
+ int status;
1883
+ int i, matches=0;
1884
+ sigar_proc_list_t *pids;
1885
+
1886
+ status = ptql_proc_list_get(sigar, query, &pids);
1887
+ if (status != SIGAR_OK) {
1888
+ return status;
1889
+ }
1890
+
1891
+ for (i=0; i<pids->number; i++) {
1892
+ int query_status =
1893
+ sigar_ptql_query_match(sigar, query, pids->data[i]);
1894
+
1895
+ if (query_status == SIGAR_OK) {
1896
+ *pid = pids->data[i];
1897
+ matches++;
1898
+ }
1899
+ else if (query_status == SIGAR_ENOTIMPL) {
1900
+ /* let caller know query is invalid. */
1901
+ status = query_status;
1902
+ break;
1903
+ } /* else ok, e.g. permission denied */
1904
+ }
1905
+
1906
+ ptql_proc_list_destroy(sigar, pids);
1907
+
1908
+ if (status != SIGAR_OK) {
1909
+ return status;
1910
+ }
1911
+
1912
+ if (matches == 1) {
1913
+ return SIGAR_OK;
1914
+ }
1915
+ else if (matches == 0) {
1916
+ sigar_strerror_set(sigar,
1917
+ "Query did not match any processes");
1918
+ }
1919
+ else {
1920
+ sigar_strerror_printf(sigar,
1921
+ "Query matched multiple processes (%d)",
1922
+ matches);
1923
+ }
1924
+
1925
+ return -1;
1926
+ }
1927
+
1928
+ SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar,
1929
+ sigar_ptql_query_t *query,
1930
+ sigar_proc_list_t *proclist)
1931
+ {
1932
+ int status;
1933
+ int i;
1934
+ sigar_proc_list_t *pids;
1935
+
1936
+ status = ptql_proc_list_get(sigar, query, &pids);
1937
+ if (status != SIGAR_OK) {
1938
+ return status;
1939
+ }
1940
+
1941
+ sigar_proc_list_create(proclist);
1942
+
1943
+ for (i=0; i<pids->number; i++) {
1944
+ int query_status =
1945
+ sigar_ptql_query_match(sigar, query, pids->data[i]);
1946
+
1947
+ if (query_status == SIGAR_OK) {
1948
+ SIGAR_PROC_LIST_GROW(proclist);
1949
+ proclist->data[proclist->number++] = pids->data[i];
1950
+ }
1951
+ else if (query_status == SIGAR_ENOTIMPL) {
1952
+ /* let caller know query is invalid. */
1953
+ status = query_status;
1954
+ break;
1955
+ }
1956
+ }
1957
+
1958
+ ptql_proc_list_destroy(sigar, pids);
1959
+
1960
+ if (status != SIGAR_OK) {
1961
+ sigar_proc_list_destroy(sigar, proclist);
1962
+ return status;
1963
+ }
1964
+
1965
+ return SIGAR_OK;
1966
+ }