Skip to content

Commit c859311

Browse files
committed
Fixed bug in parsing process_select for Windows
The USER field from process_select on Windows may contain spaces. Now, the parser continues until it finds something that looks like a PID. This approach is not bullet proof, because the USER field could contain something that looks like a PID. However, a proper fix would require rewriting the entire parser. Hence, this will do for now. Ticket: ENT-12751 Changelog: Title Signed-off-by: Lars Erik Wik <[email protected]>
1 parent 25c49fb commit c859311

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

libpromises/processes_select.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,17 @@ static bool SplitProcLine(const char *line,
778778
779779
Take these two examples:
780780
781+
Windows:
782+
User field can contain spaces. E.g.:
783+
784+
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
785+
NETWORK SERVICE 540 0.0 0.3 5092 11180 ? ? Apr28 00:00 C:\\Windows\\system32\\svchost.exe -k RPCSS -p
786+
etc.
787+
788+
There is really no good way to do this with the current parsing logic. We
789+
know that the next field will be a PID, so we can parse until we find a
790+
number.
791+
781792
AIX:
782793
USER PID PPID PGID %CPU %MEM VSZ NI S STIME TIME COMMAND
783794
root 1 0 0 0.0 0.0 784 20 A Nov 28 00:00:00 /etc/init
@@ -891,6 +902,7 @@ Solaris 9:
891902
bool cmd = (strcmp(names[field], "CMD") == 0 ||
892903
strcmp(names[field], "COMMAND") == 0);
893904
bool stime = !cmd && (strcmp(names[field], "STIME") == 0);
905+
bool is_user_field = StringEqual(names[field], "USER");
894906

895907
// Equal boolean results, either both must be true, or both must be
896908
// false. IOW we must either both be at the last field, and it must be
@@ -981,6 +993,41 @@ Solaris 9:
981993
last++;
982994
}
983995
}
996+
else if (is_user_field)
997+
{
998+
bool done = false;
999+
while (!done)
1000+
{
1001+
while (line[last] != '\0' && !isspace(line[last]))
1002+
{
1003+
last++;
1004+
}
1005+
1006+
/* On windows the USER field can contain spaces. We know that
1007+
* the next field will be PID. Hence, we seek past the spaces
1008+
* to see if the next thing is a number. If this is not the
1009+
* case, we assume it is still the USER field. This is not
1010+
* bulletproof. However, this parser never was. */
1011+
int seek_past = last;
1012+
while (line[seek_past] != '\0' && isspace(line[seek_past]))
1013+
{
1014+
seek_past++;
1015+
}
1016+
1017+
if (line[seek_past] == '\0')
1018+
{
1019+
done = true;
1020+
}
1021+
else if (isdigit(line[seek_past]))
1022+
{
1023+
done = true;
1024+
}
1025+
else
1026+
{
1027+
last = seek_past;
1028+
}
1029+
}
1030+
}
9841031
else
9851032
{
9861033
// Generic fields

tests/unit/Makefile.am

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ libdb_la_LIBADD = ../../libntech/libutils/libutils.la
8686
libdb_la_CFLAGS = $(AM_CFLAGS)
8787

8888
check_PROGRAMS = \
89+
processes_select_test \
8990
arg_split_test \
9091
assoc_test \
9192
getopt_test \
@@ -187,6 +188,10 @@ if HPUX
187188
XFAIL_TESTS = mon_load_test # Redmine #3569
188189
endif
189190

191+
192+
processes_select_test_SOURCES = processes_select_test.c
193+
processes_select_test_LDADD = libtest.la ../../libpromises/libpromises.la
194+
190195
#
191196
# OS X uses real system calls instead of our stubs unless this option is used
192197
#

tests/unit/processes_select_test.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include <test.h>
2+
3+
#include <item_lib.h>
4+
#include <cf3.defs.h>
5+
#include <processes_select.c>
6+
7+
static void test_SplitProcLine_windows(void)
8+
{
9+
10+
char buf[CF_BUFSIZE];
11+
snprintf(buf, sizeof(buf), "%-20s %5s %s %s %8s %8s %-3s %s %s %5s %s",
12+
"USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "STAT", "START", "TIME", "COMMAND");
13+
14+
char *names[CF_PROCCOLS] = {0};
15+
int start[CF_PROCCOLS];
16+
int end[CF_PROCCOLS];
17+
18+
GetProcessColumnNames(buf, names, start, end);
19+
20+
const char *const proc_line = "NETWORK SERVICE 540 0.0 0.3 5092 11180 ? ? Apr28 00:00 C:\\Windows\\system32\\svchost.exe -k RPCSS -p";
21+
time_t pstime = time(NULL);
22+
23+
char *column[CF_PROCCOLS] = {0};
24+
25+
bool ret = SplitProcLine(proc_line, pstime, names, start, end, PCA_AllColumnsPresent, column);
26+
assert_true(ret);
27+
assert_string_equal(column[0], "NETWORK SERVICE");
28+
29+
for (int i = 0; i < CF_PROCCOLS; i++)
30+
{
31+
free(names[i]);
32+
free(column[i]);
33+
}
34+
}
35+
36+
int main()
37+
{
38+
PRINT_TEST_BANNER();
39+
const UnitTest tests[] =
40+
{
41+
unit_test(test_SplitProcLine_windows),
42+
};
43+
44+
return run_tests(tests);
45+
}

0 commit comments

Comments
 (0)