4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2019 Joyent, Inc.
25 * Copyright (c) 2015, 2016 by Delphix. All rights reserved.
26 */
27
28 /*
29 * svcs - display attributes of service instances
30 *
31 * We have two output formats and six instance selection mechanisms. The
32 * primary output format is a line of attributes (selected by -o), possibly
33 * followed by process description lines (if -p is specified), for each
34 * instance selected. The columns available to display are described by the
35 * struct column columns array. The columns to actually display are kept in
36 * the opt_columns array as indicies into the columns array. The selection
37 * mechanisms available for this format are service FMRIs (selects all child
38 * instances), instance FMRIs, instance FMRI glob patterns, instances with
39 * a certain restarter (-R), dependencies of instances (-d), and dependents of
40 * instances (-D). Since the lines must be sorted (per -sS), we'll just stick
41 * each into a data structure and print them in order when we're done. To
42 * avoid listing the same instance twice (when -d and -D aren't given), we'll
43 * use a hash table of FMRIs to record that we've listed (added to the tree)
44 * an instance.
70 #include <libscf.h>
71 #include <libscf_priv.h>
72 #include <libuutil.h>
73 #include <libnvpair.h>
74 #include <libproc.h>
75 #include <locale.h>
76 #include <stdarg.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <strings.h>
80 #include <time.h>
81 #include <libzonecfg.h>
82 #include <zone.h>
83
84 #ifndef TEXT_DOMAIN
85 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
86 #endif /* TEXT_DOMAIN */
87
88 #define LEGACY_UNKNOWN "unknown"
89
90 /* Flags for pg_get_single_val() */
91 #define EMPTY_OK 0x01
92 #define MULTI_OK 0x02
93
94 /*
95 * Per proc(4) when pr_nlwp, pr_nzomb, and pr_lwp.pr_lwpid are all 0,
96 * the process is a zombie.
97 */
98 #define IS_ZOMBIE(_psip) \
99 ((_psip)->pr_nlwp == 0 && (_psip)->pr_nzomb == 0 && \
100 (_psip)->pr_lwp.pr_lwpid == 0)
101
102 /*
103 * An AVL-storable node for output lines and the keys to sort them by.
104 */
105 struct avl_string {
106 uu_avl_node_t node;
107 char *key;
108 char *str;
109 };
110
111 /*
112 * For lists of parsed restarter FMRIs.
113 */
392 case SCF_ERROR_NOT_FOUND:
393 if (flags & EMPTY_OK)
394 goto out;
395 goto misconfigured;
396
397 case SCF_ERROR_CONSTRAINT_VIOLATED:
398 if (flags & MULTI_OK) {
399 multi = B_TRUE;
400 break;
401 }
402 goto misconfigured;
403
404 case SCF_ERROR_PERMISSION_DENIED:
405 default:
406 scfdie();
407 }
408 }
409
410 switch (ty) {
411 case SCF_TYPE_ASTRING:
412 r = scf_value_get_astring(g_val, vp, sz) > 0 ? SCF_SUCCESS : -1;
413 break;
414
415 case SCF_TYPE_BOOLEAN:
416 r = scf_value_get_boolean(g_val, (uint8_t *)vp);
417 break;
418
419 case SCF_TYPE_COUNT:
420 r = scf_value_get_count(g_val, (uint64_t *)vp);
421 break;
422
423 case SCF_TYPE_INTEGER:
424 r = scf_value_get_integer(g_val, (int64_t *)vp);
425 break;
426
427 case SCF_TYPE_TIME: {
428 int64_t sec;
429 int32_t ns;
430 r = scf_value_get_time(g_val, &sec, &ns);
431 ((struct timeval *)vp)->tv_sec = sec;
432 ((struct timeval *)vp)->tv_usec = ns / 1000;
2460 * implementation from the user. If the service has been temporarily
2461 * set to a state other than its permanent value, alert the user with
2462 * a '(temporary)' message.
2463 */
2464 perm = instance_enabled(wip->inst, B_FALSE);
2465 temp = instance_enabled(wip->inst, B_TRUE);
2466 if (temp != -1) {
2467 if (temp != perm)
2468 (void) printf(gettext("%-*s%s (temporary)\n"),
2469 DETAILED_WIDTH, gettext("enabled"),
2470 temp ? gettext("true") : gettext("false"));
2471 else
2472 (void) printf(fmt, DETAILED_WIDTH,
2473 gettext("enabled"), temp ? gettext("true") :
2474 gettext("false"));
2475 } else if (perm != -1) {
2476 (void) printf(fmt, DETAILED_WIDTH, gettext("enabled"),
2477 perm ? gettext("true") : gettext("false"));
2478 }
2479
2480 /*
2481 * Property values may be longer than max_scf_fmri_length, but these
2482 * shouldn't be, so we'll just reuse buf. The user can use svcprop if
2483 * they suspect something fishy.
2484 */
2485 if (scf_instance_get_pg(wip->inst, SCF_PG_RESTARTER, rpg) != 0) {
2486 if (scf_error() != SCF_ERROR_NOT_FOUND)
2487 scfdie();
2488
2489 scf_pg_destroy(rpg);
2490 rpg = NULL;
2491 }
2492
2493 if (rpg) {
2494 if (pg_get_single_val(rpg, scf_property_state, SCF_TYPE_ASTRING,
2495 buf, max_scf_fmri_length + 1, 0) == 0)
2496 (void) printf(fmt, DETAILED_WIDTH, gettext("state"),
2497 buf);
2498
2499 if (pg_get_single_val(rpg, scf_property_next_state,
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2020 Joyent, Inc.
25 * Copyright (c) 2015, 2016 by Delphix. All rights reserved.
26 */
27
28 /*
29 * svcs - display attributes of service instances
30 *
31 * We have two output formats and six instance selection mechanisms. The
32 * primary output format is a line of attributes (selected by -o), possibly
33 * followed by process description lines (if -p is specified), for each
34 * instance selected. The columns available to display are described by the
35 * struct column columns array. The columns to actually display are kept in
36 * the opt_columns array as indicies into the columns array. The selection
37 * mechanisms available for this format are service FMRIs (selects all child
38 * instances), instance FMRIs, instance FMRI glob patterns, instances with
39 * a certain restarter (-R), dependencies of instances (-d), and dependents of
40 * instances (-D). Since the lines must be sorted (per -sS), we'll just stick
41 * each into a data structure and print them in order when we're done. To
42 * avoid listing the same instance twice (when -d and -D aren't given), we'll
43 * use a hash table of FMRIs to record that we've listed (added to the tree)
44 * an instance.
70 #include <libscf.h>
71 #include <libscf_priv.h>
72 #include <libuutil.h>
73 #include <libnvpair.h>
74 #include <libproc.h>
75 #include <locale.h>
76 #include <stdarg.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <strings.h>
80 #include <time.h>
81 #include <libzonecfg.h>
82 #include <zone.h>
83
84 #ifndef TEXT_DOMAIN
85 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
86 #endif /* TEXT_DOMAIN */
87
88 #define LEGACY_UNKNOWN "unknown"
89
90 /*
91 * Per proc(4) when pr_nlwp, pr_nzomb, and pr_lwp.pr_lwpid are all 0,
92 * the process is a zombie.
93 */
94 #define IS_ZOMBIE(_psip) \
95 ((_psip)->pr_nlwp == 0 && (_psip)->pr_nzomb == 0 && \
96 (_psip)->pr_lwp.pr_lwpid == 0)
97
98 /*
99 * An AVL-storable node for output lines and the keys to sort them by.
100 */
101 struct avl_string {
102 uu_avl_node_t node;
103 char *key;
104 char *str;
105 };
106
107 /*
108 * For lists of parsed restarter FMRIs.
109 */
388 case SCF_ERROR_NOT_FOUND:
389 if (flags & EMPTY_OK)
390 goto out;
391 goto misconfigured;
392
393 case SCF_ERROR_CONSTRAINT_VIOLATED:
394 if (flags & MULTI_OK) {
395 multi = B_TRUE;
396 break;
397 }
398 goto misconfigured;
399
400 case SCF_ERROR_PERMISSION_DENIED:
401 default:
402 scfdie();
403 }
404 }
405
406 switch (ty) {
407 case SCF_TYPE_ASTRING:
408 r = scf_value_get_astring(g_val, vp, sz);
409 if (r == 0 && !(flags & EMPTY_OK)) {
410 uu_die(gettext("Unexpected empty string for property "
411 "%s. Exiting.\n"), propname);
412 }
413 if (r >= 0)
414 r = SCF_SUCCESS;
415 break;
416
417 case SCF_TYPE_BOOLEAN:
418 r = scf_value_get_boolean(g_val, (uint8_t *)vp);
419 break;
420
421 case SCF_TYPE_COUNT:
422 r = scf_value_get_count(g_val, (uint64_t *)vp);
423 break;
424
425 case SCF_TYPE_INTEGER:
426 r = scf_value_get_integer(g_val, (int64_t *)vp);
427 break;
428
429 case SCF_TYPE_TIME: {
430 int64_t sec;
431 int32_t ns;
432 r = scf_value_get_time(g_val, &sec, &ns);
433 ((struct timeval *)vp)->tv_sec = sec;
434 ((struct timeval *)vp)->tv_usec = ns / 1000;
2462 * implementation from the user. If the service has been temporarily
2463 * set to a state other than its permanent value, alert the user with
2464 * a '(temporary)' message.
2465 */
2466 perm = instance_enabled(wip->inst, B_FALSE);
2467 temp = instance_enabled(wip->inst, B_TRUE);
2468 if (temp != -1) {
2469 if (temp != perm)
2470 (void) printf(gettext("%-*s%s (temporary)\n"),
2471 DETAILED_WIDTH, gettext("enabled"),
2472 temp ? gettext("true") : gettext("false"));
2473 else
2474 (void) printf(fmt, DETAILED_WIDTH,
2475 gettext("enabled"), temp ? gettext("true") :
2476 gettext("false"));
2477 } else if (perm != -1) {
2478 (void) printf(fmt, DETAILED_WIDTH, gettext("enabled"),
2479 perm ? gettext("true") : gettext("false"));
2480 }
2481
2482 if (temp == 0 || (temp == -1 && perm == 0)) {
2483 char comment[SCF_COMMENT_MAX_LENGTH] = "";
2484 const char *pg = (temp != -1 && temp != perm) ?
2485 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL;
2486
2487 (void) inst_get_single_val(wip->inst, pg, SCF_PROPERTY_COMMENT,
2488 SCF_TYPE_ASTRING, &comment, sizeof (comment),
2489 EMPTY_OK, 0, 0);
2490
2491 if (comment[0] != '\0') {
2492 printf(fmt, DETAILED_WIDTH, gettext("comment"),
2493 comment);
2494 }
2495 }
2496
2497 /*
2498 * Property values may be longer than max_scf_fmri_length, but these
2499 * shouldn't be, so we'll just reuse buf. The user can use svcprop if
2500 * they suspect something fishy.
2501 */
2502 if (scf_instance_get_pg(wip->inst, SCF_PG_RESTARTER, rpg) != 0) {
2503 if (scf_error() != SCF_ERROR_NOT_FOUND)
2504 scfdie();
2505
2506 scf_pg_destroy(rpg);
2507 rpg = NULL;
2508 }
2509
2510 if (rpg) {
2511 if (pg_get_single_val(rpg, scf_property_state, SCF_TYPE_ASTRING,
2512 buf, max_scf_fmri_length + 1, 0) == 0)
2513 (void) printf(fmt, DETAILED_WIDTH, gettext("state"),
2514 buf);
2515
2516 if (pg_get_single_val(rpg, scf_property_next_state,
|