sigar 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1967 @@
1
+ /*
2
+ * Copyright (c) 2006-2008 Hyperic, Inc.
3
+ * Copyright (c) 2009 SpringSource, Inc.
4
+ * Copyright (c) 2010 VMware, Inc.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include "sigar.h"
20
+ #include "sigar_private.h"
21
+ #include "sigar_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->lookup->type == PTQL_VALUE_TYPE_ANY)) &&
551
+ !(branch->op_flags & PTQL_OP_FLAG_REF))
552
+ {
553
+ if (branch->value.str) {
554
+ branch->value_free(branch->value.str);
555
+ }
556
+ }
557
+ }
558
+
559
+ free(branches->data);
560
+ branches->number = branches->size = 0;
561
+ }
562
+
563
+ return SIGAR_OK;
564
+ }
565
+
566
+ #ifdef WIN32
567
+ #define vsnprintf _vsnprintf
568
+ #endif
569
+
570
+ #define PTQL_ERRNAN \
571
+ ptql_error(error, "Query value '%s' is not a number", parsed->value)
572
+
573
+ static int ptql_error(sigar_ptql_error_t *error, const char *format, ...)
574
+ {
575
+ va_list args;
576
+
577
+ if (error != NULL) {
578
+ va_start(args, format);
579
+ vsnprintf(error->message, sizeof(error->message), format, args);
580
+ va_end(args);
581
+ }
582
+
583
+ return SIGAR_PTQL_MALFORMED_QUERY;
584
+ }
585
+
586
+ static int ptql_branch_init_any(ptql_parse_branch_t *parsed,
587
+ ptql_branch_t *branch,
588
+ sigar_ptql_error_t *error)
589
+ {
590
+ branch->data.str = sigar_strdup(parsed->attr);
591
+ branch->data_size = strlen(parsed->attr);
592
+ return SIGAR_OK;
593
+ }
594
+
595
+ static int ptql_str_match(sigar_t *sigar, ptql_branch_t *branch, char *value)
596
+ {
597
+ if (!branch->value.str) {
598
+ return 0;
599
+ }
600
+ #ifndef SIGAR_HAS_PCRE
601
+ if (branch->op_name == PTQL_OP_RE) {
602
+ if (sigar->ptql_re_impl) {
603
+ return sigar->ptql_re_impl(sigar->ptql_re_data,
604
+ value,
605
+ branch->value.str);
606
+ }
607
+ else {
608
+ return 0;
609
+ }
610
+ }
611
+ #endif
612
+ return branch->match.str(branch,
613
+ value,
614
+ branch->value.str);
615
+ }
616
+
617
+ static int ptql_branch_match(ptql_branch_t *branch)
618
+ {
619
+ switch (branch->lookup->type) {
620
+ case PTQL_VALUE_TYPE_UI64:
621
+ return branch->match.ui64(branch,
622
+ *(sigar_uint64_t *)DATA_PTR(branch),
623
+ branch->value.ui64);
624
+ case PTQL_VALUE_TYPE_UI32:
625
+ return branch->match.ui32(branch,
626
+ *(sigar_uint32_t *)DATA_PTR(branch),
627
+ branch->value.ui32);
628
+ case PTQL_VALUE_TYPE_DBL:
629
+ return branch->match.dbl(branch,
630
+ *(double *)DATA_PTR(branch),
631
+ branch->value.dbl);
632
+ case PTQL_VALUE_TYPE_CHR:
633
+ return branch->match.chr(branch,
634
+ *(char *)DATA_PTR(branch),
635
+ branch->value.chr[0]);
636
+ case PTQL_VALUE_TYPE_STR:
637
+ case PTQL_VALUE_TYPE_ANY:
638
+ if (!branch->value.str) {
639
+ return 0;
640
+ }
641
+ return branch->match.str(branch,
642
+ (char *)DATA_PTR(branch),
643
+ branch->value.str);
644
+ default:
645
+ return 0;
646
+ }
647
+ }
648
+
649
+ static int ptql_branch_match_ref(ptql_branch_t *branch, ptql_branch_t *ref)
650
+ {
651
+ switch (branch->lookup->type) {
652
+ case PTQL_VALUE_TYPE_UI64:
653
+ return branch->match.ui64(branch,
654
+ *(sigar_uint64_t *)DATA_PTR(branch),
655
+ *(sigar_uint64_t *)DATA_PTR(ref));
656
+ case PTQL_VALUE_TYPE_UI32:
657
+ return branch->match.ui32(branch,
658
+ *(sigar_uint32_t *)DATA_PTR(branch),
659
+ *(sigar_uint32_t *)DATA_PTR(ref));
660
+ case PTQL_VALUE_TYPE_DBL:
661
+ return branch->match.dbl(branch,
662
+ *(double *)DATA_PTR(branch),
663
+ *(double *)DATA_PTR(ref));
664
+ case PTQL_VALUE_TYPE_CHR:
665
+ return branch->match.chr(branch,
666
+ *(char *)DATA_PTR(branch),
667
+ *(char *)DATA_PTR(ref));
668
+ case PTQL_VALUE_TYPE_STR:
669
+ case PTQL_VALUE_TYPE_ANY:
670
+ return branch->match.str(branch,
671
+ (char *)DATA_PTR(branch),
672
+ (char *)DATA_PTR(ref));
673
+ default:
674
+ return 0;
675
+ }
676
+ }
677
+
678
+ enum {
679
+ PTQL_PID_PID,
680
+ PTQL_PID_FILE,
681
+ PTQL_PID_SUDO_FILE,
682
+ PTQL_PID_TCP_PORT,
683
+ PTQL_PID_UDP_PORT,
684
+ PTQL_PID_SERVICE_NAME,
685
+ PTQL_PID_SERVICE_DISPLAY,
686
+ PTQL_PID_SERVICE_PATH,
687
+ PTQL_PID_SERVICE_EXE,
688
+ PTQL_PID_SERVICE_PID
689
+ };
690
+
691
+ #ifdef SIGAR_64BIT
692
+
693
+ #define str2pid(value, ptr) strtoull(value, &ptr, 10)
694
+
695
+ #define pid_branch_match(branch, pid, match_pid) \
696
+ ptql_op_ui64[branch->op_name](branch, pid, match_pid)
697
+
698
+ #else
699
+
700
+ #define str2pid(value, ptr) strtoul(value, &ptr, 10)
701
+
702
+ #define pid_branch_match(branch, pid, match_pid) \
703
+ ptql_op_ui32[branch->op_name](branch, pid, match_pid)
704
+
705
+ #endif
706
+
707
+ #ifndef WIN32
708
+ #include <sys/stat.h>
709
+ int sigar_sudo_file2str(const char *fname, char *buffer, int buflen)
710
+ {
711
+ FILE *fp;
712
+ struct stat sb;
713
+
714
+ if (stat(fname, &sb) < 0) {
715
+ return errno;
716
+ }
717
+ if (sb.st_size > buflen) {
718
+ return ENOMEM;
719
+ }
720
+ snprintf(buffer, buflen, "sudo cat %s", fname);
721
+ if (!(fp = popen(buffer, "r"))) {
722
+ return errno;
723
+ }
724
+ (void)fgets(buffer, buflen, fp);
725
+ pclose(fp);
726
+
727
+ return SIGAR_OK;
728
+ }
729
+ #endif
730
+
731
+ static int ptql_branch_init_service(ptql_parse_branch_t *parsed,
732
+ ptql_branch_t *branch,
733
+ sigar_ptql_error_t *error)
734
+ {
735
+ branch->op_flags |= PTQL_OP_FLAG_PID;
736
+
737
+ if (strEQ(parsed->attr, "Name")) {
738
+ branch->flags = PTQL_PID_SERVICE_NAME;
739
+ }
740
+ else if (strEQ(parsed->attr, "DisplayName")) {
741
+ branch->flags = PTQL_PID_SERVICE_DISPLAY;
742
+ }
743
+ else if (strEQ(parsed->attr, "Path")) {
744
+ branch->flags = PTQL_PID_SERVICE_PATH;
745
+ }
746
+ else if (strEQ(parsed->attr, "Exe")) {
747
+ /* basename of Path */
748
+ branch->flags = PTQL_PID_SERVICE_EXE;
749
+ }
750
+ else if (strEQ(parsed->attr, "Pid")) {
751
+ branch->flags = PTQL_PID_SERVICE_PID;
752
+ }
753
+ else {
754
+ return ptql_error(error, "Unsupported %s attribute: %s",
755
+ parsed->name, parsed->attr);
756
+ }
757
+
758
+ #ifdef WIN32
759
+ branch->data.str = sigar_strdup(parsed->value);
760
+ branch->data_size = strlen(parsed->value);
761
+ #endif
762
+ return SIGAR_OK;
763
+ }
764
+
765
+ static int ptql_branch_init_pid(ptql_parse_branch_t *parsed,
766
+ ptql_branch_t *branch,
767
+ sigar_ptql_error_t *error)
768
+ {
769
+ int use_sudo = 0;
770
+ branch->op_flags |= PTQL_OP_FLAG_PID;
771
+
772
+ if (strEQ(parsed->attr, "Pid")) {
773
+ branch->flags = PTQL_PID_PID;
774
+ if (strEQ(parsed->value, "$$")) {
775
+ branch->data.pid = getpid();
776
+ }
777
+ else {
778
+ char *ptr;
779
+ SIGAR_CLEAR_ERRNO();
780
+ branch->data.pid = str2pid(parsed->value, ptr);
781
+ if (strtonum_failed(parsed->value, ptr)) {
782
+ return PTQL_ERRNAN;
783
+ }
784
+ }
785
+ return SIGAR_OK;
786
+ }
787
+ else if (strEQ(parsed->attr, "PidFile") ||
788
+ (use_sudo = strEQ(parsed->attr, "SudoPidFile")))
789
+ {
790
+ branch->flags = use_sudo ? PTQL_PID_SUDO_FILE : PTQL_PID_FILE;
791
+ branch->data.str = sigar_strdup(parsed->value);
792
+ branch->data_size = strlen(parsed->value);
793
+ return SIGAR_OK;
794
+ }
795
+
796
+ return ptql_error(error, "Unsupported %s attribute: %s",
797
+ parsed->name, parsed->attr);
798
+ }
799
+
800
+ #ifdef WIN32
801
+ #define QUERY_SC_SIZE 8192
802
+
803
+ static int ptql_service_query_config(SC_HANDLE scm_handle,
804
+ char *name,
805
+ LPQUERY_SERVICE_CONFIG config)
806
+ {
807
+ int status;
808
+ DWORD bytes;
809
+ SC_HANDLE handle =
810
+ OpenService(scm_handle, name, SERVICE_QUERY_CONFIG);
811
+
812
+ if (!handle) {
813
+ return GetLastError();
814
+ }
815
+
816
+ if (QueryServiceConfig(handle, config, QUERY_SC_SIZE, &bytes)) {
817
+ status = SIGAR_OK;
818
+ }
819
+ else {
820
+ status = GetLastError();
821
+ }
822
+
823
+ CloseServiceHandle(handle);
824
+ return status;
825
+ }
826
+
827
+ static int sigar_services_walk(sigar_services_walker_t *walker,
828
+ ptql_branch_t *branch)
829
+ {
830
+ sigar_services_status_t ss;
831
+ char buffer[QUERY_SC_SIZE];
832
+ char exe[SIGAR_CMDLINE_MAX];
833
+ LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer;
834
+ DWORD i, status;
835
+
836
+ SIGAR_ZERO(&ss);
837
+ status = sigar_services_status_get(&ss, walker->flags);
838
+ if (status != SIGAR_OK) {
839
+ return status;
840
+ }
841
+ for (i=0; i<ss.count; i++) {
842
+ sigar_pid_t service_pid = 0;
843
+ int status;
844
+ char *value = NULL;
845
+ char *name = ss.services[i].lpServiceName;
846
+
847
+ if (branch == NULL) {
848
+ /* no query, return all */
849
+ if (walker->add_service(walker, name) != SIGAR_OK) {
850
+ break;
851
+ }
852
+ continue;
853
+ }
854
+
855
+ switch (branch->flags) {
856
+ case PTQL_PID_SERVICE_DISPLAY:
857
+ value = ss.services[i].lpDisplayName;
858
+ break;
859
+ case PTQL_PID_SERVICE_PATH:
860
+ case PTQL_PID_SERVICE_EXE:
861
+ status = ptql_service_query_config(ss.handle, name, config);
862
+ if (status == SIGAR_OK) {
863
+ if (branch->flags == PTQL_PID_SERVICE_EXE) {
864
+ value =
865
+ sigar_service_exe_get(config->lpBinaryPathName,
866
+ exe, 1);
867
+ }
868
+ else {
869
+ value = config->lpBinaryPathName;
870
+ }
871
+ }
872
+ else {
873
+ continue;
874
+ }
875
+ break;
876
+ case PTQL_PID_SERVICE_PID:
877
+ sigar_service_pid_get(walker->sigar,
878
+ name,
879
+ &service_pid);
880
+ break;
881
+ case PTQL_PID_SERVICE_NAME:
882
+ default:
883
+ value = name;
884
+ break;
885
+ }
886
+
887
+ if ((value && ptql_str_match(walker->sigar, branch, value)) ||
888
+ (service_pid &&
889
+ pid_branch_match(branch, service_pid, atoi(branch->data.str))))
890
+ {
891
+ if (walker->add_service(walker, name) != SIGAR_OK) {
892
+ break;
893
+ }
894
+ }
895
+ }
896
+
897
+ sigar_services_status_close(&ss);
898
+
899
+ return SIGAR_OK;
900
+ }
901
+
902
+ static int ptql_pid_service_add(sigar_services_walker_t *walker,
903
+ char *name)
904
+ {
905
+ sigar_pid_t service_pid;
906
+ sigar_proc_list_t *proclist =
907
+ (sigar_proc_list_t *)walker->data;
908
+ int status =
909
+ sigar_service_pid_get(walker->sigar,
910
+ name,
911
+ &service_pid);
912
+
913
+ if (status == SIGAR_OK) {
914
+ SIGAR_PROC_LIST_GROW(proclist);
915
+ proclist->data[proclist->number++] = service_pid;
916
+ }
917
+
918
+ return SIGAR_OK;
919
+ }
920
+
921
+ static int ptql_pid_service_list_get(sigar_t *sigar,
922
+ ptql_branch_t *branch,
923
+ sigar_proc_list_t *proclist)
924
+ {
925
+ sigar_services_walker_t walker;
926
+ walker.sigar = sigar;
927
+ walker.flags = SERVICE_ACTIVE;
928
+ walker.data = proclist;
929
+ walker.add_service = ptql_pid_service_add;
930
+
931
+ return sigar_services_walk(&walker, branch);
932
+ }
933
+
934
+ int sigar_services_query(char *ptql,
935
+ sigar_ptql_error_t *error,
936
+ sigar_services_walker_t *walker)
937
+ {
938
+ int status;
939
+ sigar_ptql_query_t *query;
940
+
941
+ if (ptql == NULL) {
942
+ return sigar_services_walk(walker, NULL);
943
+ }
944
+
945
+ status = sigar_ptql_query_create(&query, (char *)ptql, error);
946
+ if (status != SIGAR_OK) {
947
+ return status;
948
+ }
949
+
950
+ if (query->branches.number == 1) {
951
+ ptql_branch_t *branch = &query->branches.data[0];
952
+
953
+ if (IS_PID_SERVICE_QUERY(branch)) {
954
+ status = sigar_services_walk(walker, branch);
955
+ }
956
+ else {
957
+ ptql_error(error, "Invalid Service query: %s", ptql);
958
+ status = SIGAR_PTQL_MALFORMED_QUERY;
959
+ }
960
+ }
961
+ else {
962
+ ptql_error(error, "Too many queries (%d), must be (1)",
963
+ query->branches.number);
964
+ status = SIGAR_PTQL_MALFORMED_QUERY;
965
+ }
966
+
967
+ sigar_ptql_query_destroy(query);
968
+
969
+ return status;
970
+ }
971
+ #endif
972
+
973
+ static int ptql_pid_port_get(sigar_t *sigar,
974
+ ptql_branch_t *branch,
975
+ sigar_pid_t *pid)
976
+ {
977
+ unsigned long port =
978
+ branch->data.ui32;
979
+ int status;
980
+ int proto =
981
+ branch->flags == PTQL_PID_UDP_PORT ?
982
+ SIGAR_NETCONN_UDP : SIGAR_NETCONN_TCP;
983
+
984
+ status =
985
+ sigar_proc_port_get(sigar, proto, port, pid);
986
+
987
+ return status;
988
+ }
989
+
990
+ static int ptql_pid_get(sigar_t *sigar,
991
+ ptql_branch_t *branch,
992
+ sigar_pid_t *pid)
993
+ {
994
+ if ((branch->flags == PTQL_PID_FILE) ||
995
+ (branch->flags == PTQL_PID_SUDO_FILE))
996
+ {
997
+ char *ptr, buffer[SIGAR_PATH_MAX+1];
998
+ const char *fname = (const char *)branch->data.str;
999
+ int status, len = sizeof(buffer)-1;
1000
+
1001
+ if (branch->flags == PTQL_PID_FILE) {
1002
+ status = sigar_file2str(fname, buffer, len);
1003
+ }
1004
+ else {
1005
+ #ifdef WIN32
1006
+ return SIGAR_ENOTIMPL;
1007
+ #else
1008
+ status = sigar_sudo_file2str(fname, buffer, len);
1009
+ #endif
1010
+ }
1011
+ if (status != SIGAR_OK) {
1012
+ return status;
1013
+ }
1014
+ SIGAR_CLEAR_ERRNO();
1015
+ *pid = str2pid(buffer, ptr);
1016
+ if ((buffer == ptr) || (errno == ERANGE)) {
1017
+ return errno;
1018
+ }
1019
+ }
1020
+ else if (branch->flags == PTQL_PID_SERVICE_NAME) {
1021
+ #ifdef WIN32
1022
+ int status =
1023
+ sigar_service_pid_get(sigar,
1024
+ branch->data.str, pid);
1025
+ if (status != SIGAR_OK) {
1026
+ return status;
1027
+ }
1028
+ #else
1029
+ return SIGAR_ENOTIMPL;
1030
+ #endif
1031
+ }
1032
+ else if ((branch->flags == PTQL_PID_UDP_PORT) ||
1033
+ (branch->flags == PTQL_PID_TCP_PORT))
1034
+ {
1035
+ int status = ptql_pid_port_get(sigar, branch, pid);
1036
+ if (status != SIGAR_OK) {
1037
+ return status;
1038
+ }
1039
+ }
1040
+ else {
1041
+ *pid = branch->data.pid;
1042
+ }
1043
+
1044
+ return SIGAR_OK;
1045
+ }
1046
+
1047
+ static int ptql_pid_list_get(sigar_t *sigar,
1048
+ ptql_branch_t *branch,
1049
+ sigar_proc_list_t *proclist)
1050
+ {
1051
+ int status, i;
1052
+ sigar_pid_t match_pid;
1053
+
1054
+ if (IS_PID_SERVICE_QUERY(branch)) {
1055
+ if ((branch->flags > PTQL_PID_SERVICE_NAME) ||
1056
+ (branch->op_name != PTQL_OP_EQ))
1057
+ {
1058
+ #ifdef WIN32
1059
+ return ptql_pid_service_list_get(sigar, branch, proclist);
1060
+ #else
1061
+ return SIGAR_OK; /* no matches */
1062
+ #endif
1063
+ }
1064
+ }
1065
+
1066
+ status = ptql_pid_get(sigar, branch, &match_pid);
1067
+
1068
+ if (status != SIGAR_OK) {
1069
+ /* XXX treated as non-match but would be nice to propagate */
1070
+ return SIGAR_OK;
1071
+ }
1072
+
1073
+ status = sigar_proc_list_get(sigar, NULL);
1074
+ if (status != SIGAR_OK) {
1075
+ return status;
1076
+ }
1077
+ for (i=0; i<sigar->pids->number; i++) {
1078
+ sigar_pid_t pid = sigar->pids->data[i];
1079
+ if (pid_branch_match(branch, pid, match_pid)) {
1080
+ SIGAR_PROC_LIST_GROW(proclist);
1081
+ proclist->data[proclist->number++] = pid;
1082
+ }
1083
+ }
1084
+
1085
+ return SIGAR_OK;
1086
+ }
1087
+
1088
+ static int SIGAPI ptql_pid_match(sigar_t *sigar,
1089
+ sigar_pid_t pid,
1090
+ void *data)
1091
+ {
1092
+ /* query already used to filter proc_list */
1093
+ return SIGAR_OK;
1094
+ }
1095
+
1096
+ static int ptql_args_branch_init(ptql_parse_branch_t *parsed,
1097
+ ptql_branch_t *branch,
1098
+ sigar_ptql_error_t *error)
1099
+ {
1100
+ if (strEQ(parsed->attr, "*")) {
1101
+ branch->op_flags |= PTQL_OP_FLAG_GLOB;
1102
+ }
1103
+ else {
1104
+ char *end;
1105
+
1106
+ SIGAR_CLEAR_ERRNO();
1107
+ branch->data.ui32 =
1108
+ strtol(parsed->attr, &end, 10);
1109
+
1110
+ if (strtonum_failed(parsed->attr, end)) {
1111
+ /* conversion failed */
1112
+ return ptql_error(error, "%s is not a number", parsed->attr);
1113
+ }
1114
+ }
1115
+ return SIGAR_OK;
1116
+ }
1117
+
1118
+ static int SIGAPI ptql_args_match(sigar_t *sigar,
1119
+ sigar_pid_t pid,
1120
+ void *data)
1121
+ {
1122
+ ptql_branch_t *branch =
1123
+ (ptql_branch_t *)data;
1124
+ int status, matched=0;
1125
+ sigar_proc_args_t args;
1126
+
1127
+ status = sigar_proc_args_get(sigar, pid, &args);
1128
+ if (status != SIGAR_OK) {
1129
+ return status;
1130
+ }
1131
+
1132
+ if (branch->op_flags & PTQL_OP_FLAG_GLOB) {
1133
+ int i;
1134
+ for (i=0; i<args.number; i++) {
1135
+ matched =
1136
+ ptql_str_match(sigar, branch, args.data[i]);
1137
+
1138
+ if (matched) {
1139
+ break;
1140
+ }
1141
+ }
1142
+ }
1143
+ else {
1144
+ int num = branch->data.ui32;
1145
+
1146
+ /* e.g. find last element of args: Args.-1.eq=weblogic.Server */
1147
+ if (num < 0) {
1148
+ num += args.number;
1149
+ }
1150
+ if ((num >= 0) && (num < args.number)) {
1151
+ matched =
1152
+ ptql_str_match(sigar, branch, args.data[num]);
1153
+ }
1154
+ }
1155
+
1156
+ sigar_proc_args_destroy(sigar, &args);
1157
+
1158
+ return matched ? SIGAR_OK : !SIGAR_OK;
1159
+ }
1160
+
1161
+ typedef struct {
1162
+ sigar_t *sigar;
1163
+ ptql_branch_t *branch;
1164
+ sigar_uint32_t ix;
1165
+ int matched;
1166
+ } proc_modules_match_t;
1167
+
1168
+ static int proc_modules_match(void *data, char *name, int len)
1169
+ {
1170
+ proc_modules_match_t *matcher =
1171
+ (proc_modules_match_t *)data;
1172
+ ptql_branch_t *branch = matcher->branch;
1173
+
1174
+ if (branch->op_flags & PTQL_OP_FLAG_GLOB) { /* Modules.*.ct=libc */
1175
+ matcher->matched =
1176
+ ptql_str_match(matcher->sigar, branch, name);
1177
+
1178
+ if (matcher->matched) {
1179
+ return !SIGAR_OK; /* stop iterating */
1180
+ }
1181
+ }
1182
+ else {
1183
+ if (matcher->ix++ == branch->data.ui32) { /* Modules.3.ct=libc */
1184
+ matcher->matched =
1185
+ ptql_str_match(matcher->sigar, branch, name);
1186
+ return !SIGAR_OK; /* stop iterating */
1187
+ }
1188
+ }
1189
+
1190
+ return SIGAR_OK;
1191
+ }
1192
+
1193
+ static int SIGAPI ptql_modules_match(sigar_t *sigar,
1194
+ sigar_pid_t pid,
1195
+ void *data)
1196
+ {
1197
+ ptql_branch_t *branch =
1198
+ (ptql_branch_t *)data;
1199
+ int status;
1200
+ sigar_proc_modules_t procmods;
1201
+ proc_modules_match_t matcher;
1202
+
1203
+ matcher.sigar = sigar;
1204
+ matcher.branch = branch;
1205
+ matcher.ix = 0;
1206
+ matcher.matched = 0;
1207
+
1208
+ procmods.module_getter = proc_modules_match;
1209
+ procmods.data = &matcher;
1210
+
1211
+ status = sigar_proc_modules_get(sigar, pid, &procmods);
1212
+
1213
+ if (status != SIGAR_OK) {
1214
+ return status;
1215
+ }
1216
+
1217
+ return matcher.matched ? SIGAR_OK : !SIGAR_OK;
1218
+ }
1219
+
1220
+ typedef struct {
1221
+ const char *key;
1222
+ int klen;
1223
+ char *val;
1224
+ int vlen;
1225
+ } sigar_proc_env_entry_t;
1226
+
1227
+ static int sigar_proc_env_get_key(void *data,
1228
+ const char *key, int klen,
1229
+ char *val, int vlen)
1230
+ {
1231
+ sigar_proc_env_entry_t *entry =
1232
+ (sigar_proc_env_entry_t *)data;
1233
+
1234
+ if ((entry->klen == klen) &&
1235
+ (strcmp(entry->key, key) == 0))
1236
+ {
1237
+ entry->val = val;
1238
+ entry->vlen = vlen;
1239
+ return !SIGAR_OK; /* foundit; stop iterating */
1240
+ }
1241
+
1242
+ return SIGAR_OK;
1243
+ }
1244
+
1245
+ static int SIGAPI ptql_env_match(sigar_t *sigar,
1246
+ sigar_pid_t pid,
1247
+ void *data)
1248
+ {
1249
+ ptql_branch_t *branch =
1250
+ (ptql_branch_t *)data;
1251
+ int status, matched=0;
1252
+ sigar_proc_env_t procenv;
1253
+ sigar_proc_env_entry_t entry;
1254
+
1255
+ /* XXX ugh this is klunky */
1256
+ entry.key = branch->data.str;
1257
+ entry.klen = branch->data_size;
1258
+ entry.val = NULL;
1259
+
1260
+ procenv.type = SIGAR_PROC_ENV_KEY;
1261
+ procenv.key = branch->data.str;
1262
+ procenv.klen = branch->data_size;
1263
+ procenv.env_getter = sigar_proc_env_get_key;
1264
+ procenv.data = &entry;
1265
+
1266
+ status = sigar_proc_env_get(sigar, pid, &procenv);
1267
+ if (status != SIGAR_OK) {
1268
+ return status;
1269
+ }
1270
+ else {
1271
+ if (entry.val) {
1272
+ matched =
1273
+ ptql_str_match(sigar, branch, entry.val);
1274
+ }
1275
+ }
1276
+
1277
+ return matched ? SIGAR_OK : !SIGAR_OK;
1278
+ }
1279
+
1280
+ static int ptql_branch_init_port(ptql_parse_branch_t *parsed,
1281
+ ptql_branch_t *branch,
1282
+ sigar_ptql_error_t *error)
1283
+ {
1284
+ char *ptr;
1285
+
1286
+ /* only 'eq' is supported here */
1287
+ if (branch->op_name != PTQL_OP_EQ) {
1288
+ return ptql_error(error, "%s requires 'eq' operator",
1289
+ parsed->name);
1290
+ }
1291
+
1292
+ if (strEQ(parsed->attr, "tcp")) {
1293
+ branch->flags = PTQL_PID_TCP_PORT;
1294
+ }
1295
+ else if (strEQ(parsed->attr, "udp")) {
1296
+ branch->flags = PTQL_PID_TCP_PORT;
1297
+ }
1298
+ else {
1299
+ return ptql_error(error, "Unsupported %s protocol: %s",
1300
+ parsed->name, parsed->attr);
1301
+ }
1302
+
1303
+ branch->op_flags |= PTQL_OP_FLAG_PID;
1304
+ SIGAR_CLEAR_ERRNO();
1305
+ branch->data.ui32 = strtoul(parsed->value, &ptr, 10);
1306
+ if (strtonum_failed(parsed->value, ptr)) {
1307
+ return PTQL_ERRNAN;
1308
+ }
1309
+
1310
+ return SIGAR_OK;
1311
+ }
1312
+
1313
+ #define PTQL_LOOKUP_ENTRY(cname, member, type) \
1314
+ (ptql_get_t)sigar_##cname##_get, \
1315
+ sigar_offsetof(sigar_##cname##_t, member), \
1316
+ sizeof(sigar_##cname##_t), \
1317
+ PTQL_VALUE_TYPE_##type, \
1318
+ NULL
1319
+
1320
+ /* XXX uid/pid can be larger w/ 64bit mode */
1321
+ #define PTQL_VALUE_TYPE_PID PTQL_VALUE_TYPE_UI32
1322
+ #define PTQL_VALUE_TYPE_UID PTQL_VALUE_TYPE_UI32
1323
+
1324
+ static ptql_lookup_t PTQL_Time[] = {
1325
+ { "StartTime", PTQL_LOOKUP_ENTRY(proc_time, start_time, UI64) },
1326
+ { "User", PTQL_LOOKUP_ENTRY(proc_time, user, UI64) },
1327
+ { "Sys", PTQL_LOOKUP_ENTRY(proc_time, sys, UI64) },
1328
+ { "Total", PTQL_LOOKUP_ENTRY(proc_time, total, UI64) },
1329
+ { NULL }
1330
+ };
1331
+
1332
+ static ptql_lookup_t PTQL_Cpu[] = {
1333
+ { "StartTime", PTQL_LOOKUP_ENTRY(proc_cpu, start_time, UI64) },
1334
+ { "User", PTQL_LOOKUP_ENTRY(proc_cpu, user, UI64) },
1335
+ { "Sys", PTQL_LOOKUP_ENTRY(proc_cpu, sys, UI64) },
1336
+ { "Total", PTQL_LOOKUP_ENTRY(proc_cpu, total, UI64) },
1337
+ { "Percent", PTQL_LOOKUP_ENTRY(proc_cpu, percent, DBL) },
1338
+ { NULL }
1339
+ };
1340
+
1341
+ static ptql_lookup_t PTQL_CredName[] = {
1342
+ { "User", PTQL_LOOKUP_ENTRY(proc_cred_name, user, STR) },
1343
+ { "Group", PTQL_LOOKUP_ENTRY(proc_cred_name, group, STR) },
1344
+ { NULL }
1345
+ };
1346
+
1347
+ static ptql_lookup_t PTQL_Mem[] = {
1348
+ { "Size", PTQL_LOOKUP_ENTRY(proc_mem, size, UI64) },
1349
+ { "Resident", PTQL_LOOKUP_ENTRY(proc_mem, resident, UI64) },
1350
+ { "Share", PTQL_LOOKUP_ENTRY(proc_mem, share, UI64) },
1351
+ { "MinorFaults", PTQL_LOOKUP_ENTRY(proc_mem, minor_faults, UI64) },
1352
+ { "MajorFaults", PTQL_LOOKUP_ENTRY(proc_mem, major_faults, UI64) },
1353
+ { "PageFaults", PTQL_LOOKUP_ENTRY(proc_mem, page_faults, UI64) },
1354
+ { NULL }
1355
+ };
1356
+
1357
+ static ptql_lookup_t PTQL_Exe[] = {
1358
+ { "Name", PTQL_LOOKUP_ENTRY(proc_exe, name, STR) },
1359
+ { "Cwd", PTQL_LOOKUP_ENTRY(proc_exe, cwd, STR) },
1360
+ { NULL }
1361
+ };
1362
+
1363
+ static ptql_lookup_t PTQL_Cred[] = {
1364
+ { "Uid", PTQL_LOOKUP_ENTRY(proc_cred, uid, UID) },
1365
+ { "Gid", PTQL_LOOKUP_ENTRY(proc_cred, gid, UID) },
1366
+ { "Euid", PTQL_LOOKUP_ENTRY(proc_cred, euid, UID) },
1367
+ { "Egid", PTQL_LOOKUP_ENTRY(proc_cred, egid, UID) },
1368
+ { NULL }
1369
+ };
1370
+
1371
+ static ptql_lookup_t PTQL_State[] = {
1372
+ { "State", PTQL_LOOKUP_ENTRY(proc_state, state, CHR) },
1373
+ { "Name", PTQL_LOOKUP_ENTRY(proc_state, name, STR) },
1374
+ { "Ppid", PTQL_LOOKUP_ENTRY(proc_state, ppid, PID) },
1375
+ { "Tty", PTQL_LOOKUP_ENTRY(proc_state, tty, UI32) },
1376
+ { "Nice", PTQL_LOOKUP_ENTRY(proc_state, nice, UI32) },
1377
+ { "Priority", PTQL_LOOKUP_ENTRY(proc_state, priority, UI32) },
1378
+ { "Threads", PTQL_LOOKUP_ENTRY(proc_state, threads, UI64) },
1379
+ { "Processor", PTQL_LOOKUP_ENTRY(proc_state, processor, UI32) },
1380
+ { NULL }
1381
+ };
1382
+
1383
+ static ptql_lookup_t PTQL_Fd[] = {
1384
+ { "Total", PTQL_LOOKUP_ENTRY(proc_fd, total, UI64) },
1385
+ { NULL }
1386
+ };
1387
+
1388
+ static ptql_lookup_t PTQL_Args[] = {
1389
+ { NULL, ptql_args_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init }
1390
+ };
1391
+
1392
+ static ptql_lookup_t PTQL_Modules[] = {
1393
+ { NULL, ptql_modules_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init }
1394
+ };
1395
+
1396
+ static ptql_lookup_t PTQL_Env[] = {
1397
+ { NULL, ptql_env_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_any }
1398
+ };
1399
+
1400
+ static ptql_lookup_t PTQL_Port[] = {
1401
+ { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_port }
1402
+ };
1403
+
1404
+ static ptql_lookup_t PTQL_Pid[] = {
1405
+ { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_pid }
1406
+ };
1407
+
1408
+ static ptql_lookup_t PTQL_Service[] = {
1409
+ { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_service }
1410
+ };
1411
+
1412
+ static ptql_entry_t ptql_map[] = {
1413
+ { "Time", PTQL_Time },
1414
+ { "Cpu", PTQL_Cpu },
1415
+ { "CredName", PTQL_CredName },
1416
+ { "Mem", PTQL_Mem },
1417
+ { "Exe", PTQL_Exe },
1418
+ { "Cred", PTQL_Cred },
1419
+ { "State", PTQL_State },
1420
+ { "Fd", PTQL_Fd },
1421
+ { "Args", PTQL_Args },
1422
+ { "Modules", PTQL_Modules },
1423
+ { "Env", PTQL_Env },
1424
+ { "Port", PTQL_Port },
1425
+ { "Pid", PTQL_Pid },
1426
+ { "Service", PTQL_Service },
1427
+ { NULL }
1428
+ };
1429
+
1430
+ static int ptql_branch_parse(char *query, ptql_parse_branch_t *branch,
1431
+ sigar_ptql_error_t *error)
1432
+ {
1433
+ char *ptr = strchr(query, '=');
1434
+ if (!ptr) {
1435
+ return ptql_error(error, "Missing '='");
1436
+ }
1437
+
1438
+ branch->op_flags = 0;
1439
+
1440
+ *ptr = '\0';
1441
+ branch->value = ++ptr;
1442
+
1443
+ if ((ptr = strchr(query, '.'))) {
1444
+ *ptr = '\0';
1445
+ branch->name = query;
1446
+ query = ++ptr;
1447
+ }
1448
+ else {
1449
+ return ptql_error(error, "Missing '.'");
1450
+ }
1451
+
1452
+ if ((ptr = strchr(query, '.'))) {
1453
+ *ptr = '\0';
1454
+ branch->attr = query;
1455
+ query = ++ptr;
1456
+ }
1457
+ else {
1458
+ return ptql_error(error, "Missing '.'");
1459
+ }
1460
+
1461
+ if (*query) {
1462
+ char flag;
1463
+
1464
+ while (sigar_isupper((flag = *query))) {
1465
+ switch (flag) {
1466
+ case 'P':
1467
+ branch->op_flags |= PTQL_OP_FLAG_PARENT;
1468
+ break;
1469
+ case 'I':
1470
+ branch->op_flags |= PTQL_OP_FLAG_ICASE;
1471
+ break;
1472
+ default:
1473
+ return ptql_error(error, "Unsupported modifier: %c", flag);
1474
+ }
1475
+
1476
+ ++query;
1477
+ }
1478
+
1479
+ branch->op = query;
1480
+ }
1481
+ else {
1482
+ return ptql_error(error, "Missing query");
1483
+ }
1484
+
1485
+ /* Pid.Service -> Service.Name */
1486
+ if (strEQ(branch->attr, "Service")) {
1487
+ branch->name = branch->attr;
1488
+ branch->attr = "Name";
1489
+ }
1490
+
1491
+ return SIGAR_OK;
1492
+ }
1493
+
1494
+ static int ptql_branch_add(ptql_parse_branch_t *parsed,
1495
+ ptql_branch_list_t *branches,
1496
+ sigar_ptql_error_t *error)
1497
+ {
1498
+ ptql_branch_t *branch;
1499
+ ptql_entry_t *entry = NULL;
1500
+ ptql_lookup_t *lookup = NULL;
1501
+ int i, is_set=0;
1502
+ char *ptr;
1503
+
1504
+ PTQL_BRANCH_LIST_GROW(branches);
1505
+
1506
+ branch = &branches->data[branches->number++];
1507
+ SIGAR_ZERO(branch);
1508
+ branch->data_free = data_free;
1509
+ branch->value_free = data_free;
1510
+ branch->op_flags = parsed->op_flags;
1511
+
1512
+ branch->op_name = ptql_op_code_get(parsed->op);
1513
+ if (branch->op_name == PTQL_OP_MAX) {
1514
+ return ptql_error(error, "Unsupported operator: %s", parsed->op);
1515
+ }
1516
+
1517
+ for (i=0; ptql_map[i].name; i++) {
1518
+ if (strEQ(ptql_map[i].name, parsed->name)) {
1519
+ entry = &ptql_map[i];
1520
+ break;
1521
+ }
1522
+ }
1523
+
1524
+ if (!entry) {
1525
+ return ptql_error(error, "Unsupported method: %s", parsed->name);
1526
+ }
1527
+
1528
+ for (i=0; entry->members[i].name; i++) {
1529
+ if (strEQ(entry->members[i].name, parsed->attr)) {
1530
+ lookup = &entry->members[i];
1531
+ break;
1532
+ }
1533
+ }
1534
+
1535
+ if (!lookup) {
1536
+ if (entry->members[0].type == PTQL_VALUE_TYPE_ANY) {
1537
+ /* Args, Env, etc. */
1538
+ lookup = &entry->members[0];
1539
+ }
1540
+ else {
1541
+ return ptql_error(error, "Unsupported %s attribute: %s",
1542
+ parsed->name, parsed->attr);
1543
+ }
1544
+ }
1545
+
1546
+ if (lookup->init) {
1547
+ int status = lookup->init(parsed, branch, error);
1548
+ if (status != SIGAR_OK) {
1549
+ return status;
1550
+ }
1551
+ }
1552
+
1553
+ branch->lookup = lookup;
1554
+
1555
+ if ((lookup->type < PTQL_VALUE_TYPE_STR) &&
1556
+ (branch->op_name > PTQL_OP_MAX_NSTR))
1557
+ {
1558
+ return ptql_error(error, "Unsupported operator '%s' for %s.%s",
1559
+ parsed->op, parsed->name, parsed->attr);
1560
+ }
1561
+
1562
+ if (*parsed->value == '$') {
1563
+ is_set = 1;
1564
+
1565
+ if (branch->op_name == PTQL_OP_RE) {
1566
+ /* not for use with .re */
1567
+ return ptql_error(error, "Unsupported operator '%s' with variable %s",
1568
+ parsed->op, parsed->value);
1569
+ }
1570
+
1571
+ if (sigar_isdigit(*(parsed->value+1))) {
1572
+ branch->op_flags |= PTQL_OP_FLAG_REF;
1573
+ parsed->op_flags = branch->op_flags; /* for use by caller */
1574
+ branch->value.ui32 = atoi(parsed->value+1) - 1;
1575
+
1576
+ if (branch->value.ui32 >= branches->number) {
1577
+ /* out-of-range */
1578
+ return ptql_error(error, "Variable %s out of range (%d)",
1579
+ parsed->value, branches->number);
1580
+ }
1581
+ else if (branch->value.ui32 == branches->number-1) {
1582
+ /* self reference */
1583
+ return ptql_error(error, "Variable %s self reference",
1584
+ parsed->value);
1585
+ }
1586
+ }
1587
+ else {
1588
+ if ((ptr = getenv(parsed->value+1))) {
1589
+ branch->value.str = sigar_strdup(ptr);
1590
+ }
1591
+ else {
1592
+ branch->value.str = NULL;
1593
+ }
1594
+ }
1595
+ }
1596
+ else if (branch->op_name == PTQL_OP_RE) {
1597
+ #ifdef SIGAR_HAS_PCRE
1598
+ const char *error;
1599
+ int offset;
1600
+ pcre *re =
1601
+ pcre_compile(parsed->value, 0,
1602
+ &error, &offset, NULL);
1603
+ if (!re) {
1604
+ /* XXX pcre_error ? */
1605
+ return ptql_error(error, "Invalid regex");
1606
+ }
1607
+ is_set = 1;
1608
+ branch->value.ptr = re;
1609
+ branch->value_free = pcre_free;
1610
+ #endif
1611
+ }
1612
+
1613
+ switch (lookup->type) {
1614
+ case PTQL_VALUE_TYPE_UI64:
1615
+ branch->match.ui64 = ptql_op_ui64[branch->op_name];
1616
+ if (!is_set) {
1617
+ SIGAR_CLEAR_ERRNO();
1618
+ branch->value.ui64 = strtoull(parsed->value, &ptr, 10);
1619
+ if (strtonum_failed(parsed->value, ptr)) {
1620
+ return PTQL_ERRNAN;
1621
+ }
1622
+ }
1623
+ break;
1624
+ case PTQL_VALUE_TYPE_UI32:
1625
+ branch->match.ui32 = ptql_op_ui32[branch->op_name];
1626
+ if (!is_set) {
1627
+ SIGAR_CLEAR_ERRNO();
1628
+ branch->value.ui32 = strtoul(parsed->value, &ptr, 10);
1629
+ if (strtonum_failed(parsed->value, ptr)) {
1630
+ return PTQL_ERRNAN;
1631
+ }
1632
+ }
1633
+ break;
1634
+ case PTQL_VALUE_TYPE_DBL:
1635
+ branch->match.dbl = ptql_op_dbl[branch->op_name];
1636
+ if (!is_set) {
1637
+ SIGAR_CLEAR_ERRNO();
1638
+ branch->value.dbl = strtod(parsed->value, &ptr);
1639
+ if (strtonum_failed(parsed->value, ptr)) {
1640
+ return PTQL_ERRNAN;
1641
+ }
1642
+ }
1643
+ break;
1644
+ case PTQL_VALUE_TYPE_CHR:
1645
+ branch->match.chr = ptql_op_chr[branch->op_name];
1646
+ if (!is_set) {
1647
+ if (strlen(parsed->value) != 1) {
1648
+ return ptql_error(error, "%s is not a char", parsed->value);
1649
+ }
1650
+ branch->value.chr[0] = parsed->value[0];
1651
+ }
1652
+ break;
1653
+ case PTQL_VALUE_TYPE_STR:
1654
+ case PTQL_VALUE_TYPE_ANY:
1655
+ branch->match.str = ptql_op_str[branch->op_name];
1656
+ if (!is_set) {
1657
+ branch->value.str = sigar_strdup(parsed->value);
1658
+ }
1659
+ break;
1660
+ }
1661
+
1662
+ return SIGAR_OK;
1663
+ }
1664
+
1665
+ static int ptql_branch_compare(const void *b1, const void *b2)
1666
+ {
1667
+ /* XXX can do better */
1668
+ ptql_branch_t *branch1 = (ptql_branch_t *)b1;
1669
+ ptql_branch_t *branch2 = (ptql_branch_t *)b2;
1670
+ return
1671
+ branch1->lookup->type -
1672
+ branch2->lookup->type;
1673
+ }
1674
+
1675
+ SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **queryp,
1676
+ char *ptql,
1677
+ sigar_ptql_error_t *error)
1678
+ {
1679
+ char *ptr, *ptql_copy = sigar_strdup(ptql);
1680
+ int status = SIGAR_OK;
1681
+ int has_ref = 0;
1682
+ sigar_ptql_query_t *query =
1683
+ *queryp = malloc(sizeof(*query));
1684
+
1685
+ (void)ptql_error(error, "Malformed query");
1686
+
1687
+ #ifdef PTQL_DEBUG
1688
+ query->ptql = sigar_strdup(ptql);
1689
+ #endif
1690
+
1691
+ ptql = ptql_copy;
1692
+
1693
+ ptql_branch_list_create(&query->branches);
1694
+
1695
+ do {
1696
+ ptql_parse_branch_t parsed;
1697
+
1698
+ if ((ptr = strchr(ptql, ','))) {
1699
+ *ptr = '\0';
1700
+ }
1701
+
1702
+ status = ptql_branch_parse(ptql, &parsed, error);
1703
+ if (status == SIGAR_OK) {
1704
+ status =
1705
+ ptql_branch_add(&parsed, &query->branches, error);
1706
+
1707
+ if (status != SIGAR_OK) {
1708
+ break;
1709
+ }
1710
+ if (parsed.op_flags & PTQL_OP_FLAG_REF) {
1711
+ has_ref = 1;
1712
+ }
1713
+ }
1714
+ else {
1715
+ break;
1716
+ }
1717
+
1718
+ if (ptr) {
1719
+ ptql = ++ptr;
1720
+ }
1721
+ else {
1722
+ break;
1723
+ }
1724
+ } while (*ptql);
1725
+
1726
+ free(ptql_copy);
1727
+
1728
+ if (status != SIGAR_OK) {
1729
+ sigar_ptql_query_destroy(query);
1730
+ *queryp = NULL;
1731
+ }
1732
+ else if (!has_ref && (query->branches.number > 1)) {
1733
+ qsort(query->branches.data,
1734
+ query->branches.number,
1735
+ sizeof(query->branches.data[0]),
1736
+ ptql_branch_compare);
1737
+ }
1738
+
1739
+ if (status == SIGAR_OK) {
1740
+ (void)ptql_error(error, "OK");
1741
+ }
1742
+ return status;
1743
+ }
1744
+
1745
+ SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query)
1746
+ {
1747
+ #ifdef PTQL_DEBUG
1748
+ free(query->ptql);
1749
+ #endif
1750
+ ptql_branch_list_destroy(&query->branches);
1751
+ free(query);
1752
+ return SIGAR_OK;
1753
+ }
1754
+
1755
+ SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data,
1756
+ sigar_ptql_re_impl_t impl)
1757
+ {
1758
+ sigar->ptql_re_data = data;
1759
+ sigar->ptql_re_impl = impl;
1760
+ }
1761
+
1762
+ SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar,
1763
+ sigar_ptql_query_t *query,
1764
+ sigar_pid_t query_pid)
1765
+ {
1766
+ int i;
1767
+
1768
+ for (i=0; i<query->branches.number; i++) {
1769
+ sigar_pid_t pid = query_pid;
1770
+ int status, matched=0;
1771
+ ptql_branch_t *branch = &query->branches.data[i];
1772
+ ptql_lookup_t *lookup = branch->lookup;
1773
+
1774
+ if (branch->op_flags & PTQL_OP_FLAG_PARENT) {
1775
+ sigar_proc_state_t state;
1776
+
1777
+ status = sigar_proc_state_get(sigar, pid, &state);
1778
+ if (status != SIGAR_OK) {
1779
+ return status;
1780
+ }
1781
+
1782
+ pid = state.ppid;
1783
+ }
1784
+
1785
+ if (lookup->type == PTQL_VALUE_TYPE_ANY) {
1786
+ /* Args, Env, etc. */
1787
+ status = lookup->get(sigar, pid, branch);
1788
+ if (status == SIGAR_OK) {
1789
+ matched = 1;
1790
+ }
1791
+ }
1792
+ else {
1793
+ /* standard sigar_proc_*_get / structptr + offset */
1794
+ if (!branch->data.ptr) {
1795
+ branch->data_size = lookup->data_size;
1796
+ branch->data.ptr = malloc(branch->data_size);
1797
+ }
1798
+ status = lookup->get(sigar, pid, branch->data.ptr);
1799
+ if (status != SIGAR_OK) {
1800
+ return status;
1801
+ }
1802
+
1803
+ if (branch->op_flags & PTQL_OP_FLAG_REF) {
1804
+ ptql_branch_t *ref =
1805
+ &query->branches.data[branch->value.ui32];
1806
+
1807
+ matched = ptql_branch_match_ref(branch, ref);
1808
+ }
1809
+ #ifndef SIGAR_HAS_PCRE
1810
+ else if (branch->lookup->type == PTQL_VALUE_TYPE_STR) {
1811
+ matched = ptql_str_match(sigar, branch, (char *)DATA_PTR(branch));
1812
+ }
1813
+ #endif
1814
+ else {
1815
+ matched = ptql_branch_match(branch);
1816
+ }
1817
+ }
1818
+
1819
+ if (!matched) {
1820
+ return 1;
1821
+ }
1822
+ }
1823
+
1824
+ return SIGAR_OK;
1825
+ }
1826
+
1827
+ static int ptql_proc_list_get(sigar_t *sigar,
1828
+ sigar_ptql_query_t *query,
1829
+ sigar_proc_list_t **proclist)
1830
+ {
1831
+ int status;
1832
+ int i;
1833
+
1834
+ *proclist = NULL;
1835
+
1836
+ for (i=0; i<query->branches.number; i++) {
1837
+ ptql_branch_t *branch = &query->branches.data[i];
1838
+
1839
+ if (branch->op_flags & PTQL_OP_FLAG_PID) {
1840
+ /* pre-filter pid list for Pid.* queries */
1841
+ /* XXX multiple Pid.* may result in dups */
1842
+ if (*proclist == NULL) {
1843
+ *proclist = malloc(sizeof(**proclist));
1844
+ SIGAR_ZERO(*proclist);
1845
+ sigar_proc_list_create(*proclist);
1846
+ }
1847
+ status = ptql_pid_list_get(sigar, branch, *proclist);
1848
+ if (status != SIGAR_OK) {
1849
+ sigar_proc_list_destroy(sigar, *proclist);
1850
+ free(*proclist);
1851
+ return status;
1852
+ }
1853
+ }
1854
+ }
1855
+
1856
+ if (*proclist) {
1857
+ return SIGAR_OK;
1858
+ }
1859
+
1860
+ status = sigar_proc_list_get(sigar, NULL);
1861
+ if (status != SIGAR_OK) {
1862
+ return status;
1863
+ }
1864
+ *proclist = sigar->pids;
1865
+ return SIGAR_OK;
1866
+ }
1867
+
1868
+ static int ptql_proc_list_destroy(sigar_t *sigar,
1869
+ sigar_proc_list_t *proclist)
1870
+ {
1871
+ if (proclist != sigar->pids) {
1872
+ sigar_proc_list_destroy(sigar, proclist);
1873
+ free(proclist);
1874
+ }
1875
+
1876
+ return SIGAR_OK;
1877
+ }
1878
+
1879
+ SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar,
1880
+ sigar_ptql_query_t *query,
1881
+ sigar_pid_t *pid)
1882
+ {
1883
+ int status;
1884
+ int i, matches=0;
1885
+ sigar_proc_list_t *pids;
1886
+
1887
+ status = ptql_proc_list_get(sigar, query, &pids);
1888
+ if (status != SIGAR_OK) {
1889
+ return status;
1890
+ }
1891
+
1892
+ for (i=0; i<pids->number; i++) {
1893
+ int query_status =
1894
+ sigar_ptql_query_match(sigar, query, pids->data[i]);
1895
+
1896
+ if (query_status == SIGAR_OK) {
1897
+ *pid = pids->data[i];
1898
+ matches++;
1899
+ }
1900
+ else if (query_status == SIGAR_ENOTIMPL) {
1901
+ /* let caller know query is invalid. */
1902
+ status = query_status;
1903
+ break;
1904
+ } /* else ok, e.g. permission denied */
1905
+ }
1906
+
1907
+ ptql_proc_list_destroy(sigar, pids);
1908
+
1909
+ if (status != SIGAR_OK) {
1910
+ return status;
1911
+ }
1912
+
1913
+ if (matches == 1) {
1914
+ return SIGAR_OK;
1915
+ }
1916
+ else if (matches == 0) {
1917
+ sigar_strerror_set(sigar,
1918
+ "Query did not match any processes");
1919
+ }
1920
+ else {
1921
+ sigar_strerror_printf(sigar,
1922
+ "Query matched multiple processes (%d)",
1923
+ matches);
1924
+ }
1925
+
1926
+ return -1;
1927
+ }
1928
+
1929
+ SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar,
1930
+ sigar_ptql_query_t *query,
1931
+ sigar_proc_list_t *proclist)
1932
+ {
1933
+ int status;
1934
+ int i;
1935
+ sigar_proc_list_t *pids;
1936
+
1937
+ status = ptql_proc_list_get(sigar, query, &pids);
1938
+ if (status != SIGAR_OK) {
1939
+ return status;
1940
+ }
1941
+
1942
+ sigar_proc_list_create(proclist);
1943
+
1944
+ for (i=0; i<pids->number; i++) {
1945
+ int query_status =
1946
+ sigar_ptql_query_match(sigar, query, pids->data[i]);
1947
+
1948
+ if (query_status == SIGAR_OK) {
1949
+ SIGAR_PROC_LIST_GROW(proclist);
1950
+ proclist->data[proclist->number++] = pids->data[i];
1951
+ }
1952
+ else if (query_status == SIGAR_ENOTIMPL) {
1953
+ /* let caller know query is invalid. */
1954
+ status = query_status;
1955
+ break;
1956
+ }
1957
+ }
1958
+
1959
+ ptql_proc_list_destroy(sigar, pids);
1960
+
1961
+ if (status != SIGAR_OK) {
1962
+ sigar_proc_list_destroy(sigar, proclist);
1963
+ return status;
1964
+ }
1965
+
1966
+ return SIGAR_OK;
1967
+ }