2 * Copyright (c) 2014 Red Hat.
3 * Copyright (c) 1995-2005 Silicon Graphics, Inc. All Rights Reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 int pid
= PM_LOG_NO_PID
;
25 int port
= PM_LOG_NO_PORT
;
26 int is_unix
; /* host spec is a unix: url. */
27 int is_local
; /* host spec is a local: url. */
28 int is_socket_path
; /* host spec is a url with a path. */
29 char *tz
; /* for -Z timezone */
30 int tztype
= TZ_LOCAL
; /* timezone for status cmd */
34 extern int parse_stmt
;
37 static char title
[] = "Performance Co-Pilot Logger Control (pmlc), Version %s\n\n%s\n";
40 " show loggers [@<host>] display <pid>s of running pmloggers\n"
41 " connect _logger_id [@<host>] connect to designated pmlogger\n"
42 " status information about connected pmlogger\n"
43 " query metric-list show logging state of metrics\n"
44 " new volume start a new log volume\n"
46 " log { mandatory | advisory } on <interval> _metric-list\n"
47 " log { mandatory | advisory } off _metric-list\n"
48 " log mandatory maybe _metric-list\n"
50 " timezone local|logger|'<timezone>' change reporting timezone\n"
51 " help print this help message\n"
52 " quit exit from pmlc\n"
54 " _logger_id is primary | <pid> | port <n>\n"
55 " _metric-list is _metric-spec | { _metric-spec ... }\n"
56 " _metric-spec is <metric-name> | <metric-name> [ <instance> ... ]\n";
58 static int overrides(int, pmOptions
*);
60 static pmLongOptions longopts
[] = {
61 PMAPI_OPTIONS_HEADER("Options"),
63 { "echo", 0, 'e', 0, "echo input" },
64 { "host", 1, 'h', "HOST", "connect to pmlogger using host specification" },
65 { "interactive", 0, 'i', 0, "be interactive and prompt" },
67 { "primary", 0, 'P', 0, "connect to primary pmlogger" },
68 { "port", 1, 'p', "N", "connect to pmlogger on this TCP/IP port" },
70 { "logzone", 0, 'z', 0, "set reporting timezone to local time for pmlogger" },
75 static pmOptions opts
= {
76 .short_options
= "D:eh:in:Pp:zZ:?",
77 .long_options
= longopts
,
78 .short_usage
= "[options] [pid]",
79 .override
= overrides
,
83 overrides(int opt
, pmOptions
*opts
)
85 if (opt
== 'h' || opt
== 'p')
91 main(int argc
, char **argv
)
94 int sts
= 0; /* initialize to pander to gcc */
103 while ((c
= pmGetOptions(argc
, argv
, &opts
)) != EOF
) {
106 case 'e': /* echo input */
110 case 'h': /* hostspec */
112 * We need to know if a socket path has been specified.
115 prefix_end
= strchr(host
, ':');
116 if (prefix_end
!= NULL
) {
117 prefix_len
= prefix_end
- host
+ 1;
118 if (prefix_len
== 6 && strncmp(host
, "local:", prefix_len
) == 0)
120 else if (prefix_len
== 5 && strncmp(host
, "unix:", prefix_len
) == 0)
122 if (is_local
|| is_unix
) {
125 * Find out is a path was specified.
126 * Skip any initial path separators.
128 for (p
= host
+ prefix_len
; *p
== __pmPathSeparator(); ++p
)
136 case 'i': /* be interactive */
140 case 'P': /* connect to primary logger */
141 if (port
!= PM_LOG_NO_PORT
|| (is_unix
&& is_socket_path
)) {
142 pmprintf("%s: at most one of -P, -p, unix socket, or PID may be specified\n",
146 port
= PM_LOG_PRIMARY_PORT
;
150 case 'p': /* connect via port */
151 if (port
!= PM_LOG_NO_PORT
|| is_unix
) {
152 pmprintf("%s: at most one of -P, -p, unix socket, or PID may be specified\n",
156 port
= (int)strtol(opts
.optarg
, &endnum
, 10);
157 if (*endnum
!= '\0' || port
<= PM_LOG_PRIMARY_PORT
) {
158 pmprintf("%s: port must be numeric and greater than %d\n",
159 pmProgname
, PM_LOG_PRIMARY_PORT
);
167 if (opts
.optind
< argc
- 1)
169 else if (opts
.optind
== argc
- 1) {
170 /* pid was specified */
171 if (port
!= PM_LOG_NO_PORT
|| (is_unix
&& is_socket_path
)) {
172 pmprintf("%s: at most one of -P, -p, unix socket, or PID may be specified\n",
177 pid
= (int)strtol(argv
[opts
.optind
], &endnum
, 10);
178 if (*endnum
!= '\0' || pid
<= PM_LOG_PRIMARY_PID
) {
179 pmprintf("%s: PID must be a numeric process ID and greater than %d\n",
180 pmProgname
, PM_LOG_PRIMARY_PID
);
186 if (!opts
.errors
&& host
&& pid
== PM_LOG_NO_PID
&&
187 port
== PM_LOG_NO_PORT
&& !is_socket_path
) {
188 pmprintf("%s: -h may not be used without -P or -p or a socket path or a PID\n",
194 pmUsageMessage(&opts
);
201 } else if (opts
.timezone
) {
211 if (port
== PM_LOG_PRIMARY_PORT
|| pid
== PM_LOG_PRIMARY_PID
)
214 if (pid
!= PM_LOG_NO_PID
|| port
!= PM_LOG_NO_PORT
|| is_socket_path
)
215 sts
= ConnectLogger(host
, &pid
, &port
);
218 printf(title
, PCP_VERSION
, menu
);
220 if (pid
!= PM_LOG_NO_PID
|| port
!= PM_LOG_NO_PORT
|| is_socket_path
) {
223 fprintf(stderr
, "Unable to connect to primary pmlogger at %s: ",
225 if (still_connected(sts
))
226 fprintf(stderr
, "%s\n", pmErrStr(sts
));
228 else if (is_socket_path
) {
229 fprintf(stderr
, "Unable to connect to pmlogger via the local socket at %s: ",
231 if (still_connected(sts
))
232 fprintf(stderr
, "%s\n", pmErrStr(sts
));
234 else if (port
!= PM_LOG_NO_PORT
) {
235 fprintf(stderr
, "Unable to connect to pmlogger on port %d at %s: ",
237 if (still_connected(sts
))
238 fprintf(stderr
, "%s\n", pmErrStr(sts
));
241 fprintf(stderr
, "Unable to connect to pmlogger pid %d at %s: ",
243 if (still_connected(sts
))
244 fprintf(stderr
, "%s\n", pmErrStr(sts
));
249 printf("Connected to primary pmlogger at %s\n", host
);
250 else if (is_socket_path
)
251 printf("Connected to pmlogger via local socket at %s\n", host
);
252 else if (port
!= PM_LOG_NO_PORT
)
253 printf("Connected to pmlogger on port %d at %s\n", port
, host
);
255 printf("Connected to pmlogger pid %d at %s\n", pid
, host
);
276 if (pmDebug
& DBG_TRACE_APPL1
)
277 printf("stmt=%d, state=%d, control=%d, hostspec=%s, pid=%d, port=%d\n",
278 parse_stmt
, state
, control
, hostname
, pid
, port
);
281 realhost
= (hostname
== NULL
) ? host
: hostname
;
282 switch (parse_stmt
) {
285 ShowLoggers(realhost
);
289 /* The unix: url requres either 'primary', a pid or a socket path. */
290 if (is_unix
&& pid
== PM_LOG_NO_PID
&& ! is_socket_path
) {
291 fprintf(stderr
, "The 'unix:' url requires either 'primary', a pid or a socket path");
292 if (still_connected(sts
))
293 fprintf(stderr
, "\n");
296 /* The local: url requres either 'primary', a pid a port or a socket path. */
297 if (is_local
&& pid
== PM_LOG_NO_PID
&& port
== PM_LOG_NO_PORT
&& ! is_socket_path
) {
298 fprintf(stderr
, "The 'local:' url requires either 'primary', a pid, a port or a socket path");
299 if (still_connected(sts
))
300 fprintf(stderr
, "\n");
304 if (port
== PM_LOG_PRIMARY_PORT
|| pid
== PM_LOG_PRIMARY_PID
)
306 if ((sts
= ConnectLogger(realhost
, &pid
, &port
)) < 0) {
308 fprintf(stderr
, "Unable to connect to primary pmlogger at %s: ",
311 else if (is_socket_path
) {
312 fprintf(stderr
, "Unable to connect to pmlogger via local socket at %s: ",
315 else if (port
!= PM_LOG_NO_PORT
) {
316 fprintf(stderr
, "Unable to connect to pmlogger on port %d at %s: ",
320 fprintf(stderr
, "Unable to connect to pmlogger pid %d at %s: ",
323 if (still_connected(sts
))
324 fprintf(stderr
, "%s\n", pmErrStr(sts
));
327 /* if the timezone is "logger time", it has changed
328 * because the logger may be in a different zone
329 * (note that tzchange may already be set (e.g. -Z and
330 * this connect is the first).
332 tzchange
|= (tztype
== TZ_LOGGER
);
340 if (state
== PM_LOG_ENQUIRE
) {
346 if (state
== PM_LOG_ON
) {
348 fprintf(stderr
, "Logging delta (%d msec) must be positive\n", logfreq
);
351 else if (logfreq
> PMLC_MAX_DELTA
) {
352 fprintf(stderr
, "Logging delta (%d msec) cannot be bigger than %d msec\n", logfreq
, PMLC_MAX_DELTA
);
356 LogCtl(control
, state
, logfreq
);
366 Status(pid
, primary
);
383 fprintf(stderr
, "QA Test Case deactivated\n");
385 fprintf(stderr
, "QA Test Case #%d activated\n", qa_case
);
389 if (hostname
!= NULL
) {