Print this page
NEX-3510 Want "scripted" mode for svcs(1) (fix trailing tab)
NEX-3510 Want "scripted" mode for svcs(1)
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/svc/svcs/svcs.c
+++ new/usr/src/cmd/svc/svcs/svcs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2011, Joyent, Inc. All rights reserved.
25 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 26 * Copyright (c) 2015, 2016 by Delphix. All rights reserved.
26 27 */
27 28
28 29 /*
29 30 * svcs - display attributes of service instances
30 31 *
31 32 * We have two output formats and six instance selection mechanisms. The
32 33 * primary output format is a line of attributes (selected by -o), possibly
33 34 * followed by process description lines (if -p is specified), for each
34 35 * instance selected. The columns available to display are described by the
35 36 * struct column columns array. The columns to actually display are kept in
36 37 * the opt_columns array as indicies into the columns array. The selection
37 38 * mechanisms available for this format are service FMRIs (selects all child
38 39 * instances), instance FMRIs, instance FMRI glob patterns, instances with
39 40 * a certain restarter (-R), dependencies of instances (-d), and dependents of
40 41 * instances (-D). Since the lines must be sorted (per -sS), we'll just stick
41 42 * each into a data structure and print them in order when we're done. To
42 43 * avoid listing the same instance twice (when -d and -D aren't given), we'll
43 44 * use a hash table of FMRIs to record that we've listed (added to the tree)
44 45 * an instance.
45 46 *
46 47 * The secondary output format (-l "long") is a paragraph of text for the
47 48 * services or instances selected. Not needing to be sorted, it's implemented
48 49 * by just calling print_detailed() for each FMRI given.
49 50 */
50 51
51 52 #include "svcs.h"
52 53 #include "notify_params.h"
53 54
54 55 /* Get the byteorder macros to ease sorting. */
55 56 #include <sys/types.h>
56 57 #include <netinet/in.h>
57 58 #include <inttypes.h>
58 59
59 60 #include <sys/contract.h>
60 61 #include <sys/ctfs.h>
61 62 #include <sys/stat.h>
62 63
63 64 #include <assert.h>
64 65 #include <errno.h>
65 66 #include <fcntl.h>
66 67 #include <fnmatch.h>
67 68 #include <libcontract.h>
68 69 #include <libcontract_priv.h>
69 70 #include <libintl.h>
70 71 #include <libscf.h>
71 72 #include <libscf_priv.h>
72 73 #include <libuutil.h>
73 74 #include <libnvpair.h>
74 75 #include <locale.h>
75 76 #include <procfs.h>
76 77 #include <stdarg.h>
77 78 #include <stdio.h>
78 79 #include <stdlib.h>
79 80 #include <strings.h>
80 81 #include <time.h>
81 82 #include <libzonecfg.h>
82 83 #include <zone.h>
83 84
84 85 #ifndef TEXT_DOMAIN
85 86 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
86 87 #endif /* TEXT_DOMAIN */
87 88
88 89 #define LEGACY_UNKNOWN "unknown"
89 90
90 91 /* Flags for pg_get_single_val() */
91 92 #define EMPTY_OK 0x01
92 93 #define MULTI_OK 0x02
93 94
94 95
95 96 /*
96 97 * An AVL-storable node for output lines and the keys to sort them by.
97 98 */
98 99 struct avl_string {
99 100 uu_avl_node_t node;
100 101 char *key;
101 102 char *str;
102 103 };
103 104
104 105 /*
105 106 * For lists of parsed restarter FMRIs.
106 107 */
107 108 struct pfmri_list {
108 109 const char *scope;
109 110 const char *service;
110 111 const char *instance;
111 112 struct pfmri_list *next;
112 113 };
113 114
114 115
115 116 /*
116 117 * Globals
117 118 */
118 119 scf_handle_t *h;
119 120 static scf_propertygroup_t *g_pg;
120 121 static scf_property_t *g_prop;
121 122 static scf_value_t *g_val;
122 123
123 124 static size_t line_sz; /* Bytes in the header line. */
124 125 static size_t sortkey_sz; /* Bytes in sort keys. */
125 126 static uu_avl_pool_t *lines_pool;
126 127 static uu_avl_t *lines; /* Output lines. */
127 128 int exit_status;
128 129 ssize_t max_scf_name_length;
129 130 ssize_t max_scf_value_length;
130 131 ssize_t max_scf_fmri_length;
131 132 static ssize_t max_scf_type_length;
132 133 static time_t now;
133 134 static struct pfmri_list *restarters = NULL;
134 135 static int first_paragraph = 1; /* For -l mode. */
135 136 static char *common_name_buf; /* Sized for maximal length value. */
136 137 char *locale; /* Current locale. */
137 138 char *g_zonename; /* zone being operated upon */
138 139
|
↓ open down ↓ |
104 lines elided |
↑ open up ↑ |
139 140 /*
140 141 * Pathname storage for path generated from the fmri.
141 142 * Used for reading the ctid and (start) pid files for an inetd service.
142 143 */
143 144 static char genfmri_filename[MAXPATHLEN] = "";
144 145
145 146 /* Options */
146 147 static int *opt_columns = NULL; /* Indices into columns to display. */
147 148 static int opt_cnum = 0;
148 149 static int opt_processes = 0; /* Print processes? */
150 +static int opt_scripted = 0; /* No header, tabs as separators. */
149 151 static int *opt_sort = NULL; /* Indices into columns to sort. */
150 152 static int opt_snum = 0;
151 153 static int opt_nstate_shown = 0; /* Will nstate be shown? */
152 154 static int opt_verbose = 0;
153 155 static char *opt_zone; /* zone selected, if any */
154 156
155 157 /* Minimize string constants. */
156 158 static const char * const scf_property_state = SCF_PROPERTY_STATE;
157 159 static const char * const scf_property_next_state = SCF_PROPERTY_NEXT_STATE;
158 160 static const char * const scf_property_contract = SCF_PROPERTY_CONTRACT;
159 161
160 162
161 163 /*
162 164 * Utility functions
163 165 */
164 166
165 167 /*
166 168 * For unexpected libscf errors. The ending newline is necessary to keep
167 169 * uu_die() from appending the errno error.
168 170 */
169 171 #ifndef NDEBUG
170 172 void
171 173 do_scfdie(const char *file, int line)
172 174 {
173 175 uu_die(gettext("%s:%d: Unexpected libscf error: %s. Exiting.\n"),
174 176 file, line, scf_strerror(scf_error()));
175 177 }
176 178 #else
177 179 void
178 180 scfdie(void)
179 181 {
180 182 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
181 183 scf_strerror(scf_error()));
182 184 }
183 185 #endif
184 186
185 187 void *
186 188 safe_malloc(size_t sz)
187 189 {
188 190 void *ptr;
189 191
190 192 ptr = malloc(sz);
191 193 if (ptr == NULL)
192 194 uu_die(gettext("Out of memory"));
193 195
194 196 return (ptr);
195 197 }
196 198
197 199 char *
198 200 safe_strdup(const char *str)
199 201 {
200 202 char *cp;
201 203
202 204 cp = strdup(str);
203 205 if (cp == NULL)
204 206 uu_die(gettext("Out of memory.\n"));
205 207
206 208 return (cp);
207 209 }
208 210
209 211 /*
210 212 * FMRI hashtable. For uniquifing listings.
211 213 */
212 214
213 215 struct ht_elem {
214 216 const char *fmri;
215 217 struct ht_elem *next;
216 218 };
217 219
218 220 static struct ht_elem **ht_buckets = NULL;
219 221 static uint_t ht_buckets_num = 0;
220 222 static uint_t ht_num;
221 223
222 224 static void
223 225 ht_free(void)
224 226 {
225 227 struct ht_elem *elem, *next;
226 228 int i;
227 229
228 230 for (i = 0; i < ht_buckets_num; i++) {
229 231 for (elem = ht_buckets[i]; elem != NULL; elem = next) {
230 232 next = elem->next;
231 233 free((char *)elem->fmri);
232 234 free(elem);
233 235 }
234 236 }
235 237
236 238 free(ht_buckets);
237 239 ht_buckets_num = 0;
238 240 ht_buckets = NULL;
239 241 }
240 242
241 243 static void
242 244 ht_init(void)
243 245 {
244 246 assert(ht_buckets == NULL);
245 247
246 248 ht_buckets_num = 8;
247 249 ht_buckets = safe_malloc(sizeof (*ht_buckets) * ht_buckets_num);
248 250 bzero(ht_buckets, sizeof (*ht_buckets) * ht_buckets_num);
249 251 ht_num = 0;
250 252 }
251 253
252 254 static uint_t
253 255 ht_hash_fmri(const char *fmri)
254 256 {
255 257 uint_t h = 0, g;
256 258 const char *p, *k;
257 259
258 260 /* All FMRIs begin with svc:/, so skip that part. */
259 261 assert(strncmp(fmri, "svc:/", sizeof ("svc:/") - 1) == 0);
260 262 k = fmri + sizeof ("svc:/") - 1;
261 263
262 264 /*
263 265 * Generic hash function from uts/common/os/modhash.c.
264 266 */
265 267 for (p = k; *p != '\0'; ++p) {
266 268 h = (h << 4) + *p;
267 269 if ((g = (h & 0xf0000000)) != 0) {
268 270 h ^= (g >> 24);
269 271 h ^= g;
270 272 }
271 273 }
272 274
273 275 return (h);
274 276 }
275 277
276 278 static void
277 279 ht_grow()
278 280 {
279 281 uint_t new_ht_buckets_num;
280 282 struct ht_elem **new_ht_buckets;
281 283 int i;
282 284
283 285 new_ht_buckets_num = ht_buckets_num * 2;
284 286 assert(new_ht_buckets_num > ht_buckets_num);
285 287 new_ht_buckets =
286 288 safe_malloc(sizeof (*new_ht_buckets) * new_ht_buckets_num);
287 289 bzero(new_ht_buckets, sizeof (*new_ht_buckets) * new_ht_buckets_num);
288 290
289 291 for (i = 0; i < ht_buckets_num; ++i) {
290 292 struct ht_elem *elem, *next;
291 293
292 294 for (elem = ht_buckets[i]; elem != NULL; elem = next) {
293 295 uint_t h;
294 296
295 297 next = elem->next;
296 298
297 299 h = ht_hash_fmri(elem->fmri);
298 300
299 301 elem->next =
300 302 new_ht_buckets[h & (new_ht_buckets_num - 1)];
301 303 new_ht_buckets[h & (new_ht_buckets_num - 1)] = elem;
302 304 }
303 305 }
304 306
305 307 free(ht_buckets);
306 308
307 309 ht_buckets = new_ht_buckets;
308 310 ht_buckets_num = new_ht_buckets_num;
309 311 }
310 312
311 313 /*
312 314 * Add an FMRI to the hash table. Returns 1 if it was already there,
313 315 * 0 otherwise.
314 316 */
315 317 static int
316 318 ht_add(const char *fmri)
317 319 {
318 320 uint_t h;
319 321 struct ht_elem *elem;
320 322
321 323 h = ht_hash_fmri(fmri);
322 324
323 325 elem = ht_buckets[h & (ht_buckets_num - 1)];
324 326
325 327 for (; elem != NULL; elem = elem->next) {
326 328 if (strcmp(elem->fmri, fmri) == 0)
327 329 return (1);
328 330 }
329 331
330 332 /* Grow when average chain length is over 3. */
331 333 if (ht_num > 3 * ht_buckets_num)
332 334 ht_grow();
333 335
334 336 ++ht_num;
335 337
336 338 elem = safe_malloc(sizeof (*elem));
337 339 elem->fmri = strdup(fmri);
338 340 elem->next = ht_buckets[h & (ht_buckets_num - 1)];
339 341 ht_buckets[h & (ht_buckets_num - 1)] = elem;
340 342
341 343 return (0);
342 344 }
343 345
344 346
345 347
346 348 /*
347 349 * Convenience libscf wrapper functions.
348 350 */
349 351
350 352 /*
351 353 * Get the single value of the named property in the given property group,
352 354 * which must have type ty, and put it in *vp. If ty is SCF_TYPE_ASTRING, vp
353 355 * is taken to be a char **, and sz is the size of the buffer. sz is unused
354 356 * otherwise. Return 0 on success, -1 if the property doesn't exist, has the
355 357 * wrong type, or doesn't have a single value. If flags has EMPTY_OK, don't
356 358 * complain if the property has no values (but return nonzero). If flags has
357 359 * MULTI_OK and the property has multiple values, succeed with E2BIG.
358 360 */
359 361 int
360 362 pg_get_single_val(scf_propertygroup_t *pg, const char *propname, scf_type_t ty,
361 363 void *vp, size_t sz, uint_t flags)
362 364 {
363 365 char *buf, root[MAXPATHLEN];
364 366 size_t buf_sz;
365 367 int ret = -1, r;
366 368 boolean_t multi = B_FALSE;
367 369
368 370 assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0);
369 371
370 372 if (scf_pg_get_property(pg, propname, g_prop) == -1) {
371 373 if (scf_error() != SCF_ERROR_NOT_FOUND)
372 374 scfdie();
373 375
374 376 goto out;
375 377 }
376 378
377 379 if (scf_property_is_type(g_prop, ty) != SCF_SUCCESS) {
378 380 if (scf_error() == SCF_ERROR_TYPE_MISMATCH)
379 381 goto misconfigured;
380 382 scfdie();
381 383 }
382 384
383 385 if (scf_property_get_value(g_prop, g_val) != SCF_SUCCESS) {
384 386 switch (scf_error()) {
385 387 case SCF_ERROR_NOT_FOUND:
386 388 if (flags & EMPTY_OK)
387 389 goto out;
388 390 goto misconfigured;
389 391
390 392 case SCF_ERROR_CONSTRAINT_VIOLATED:
391 393 if (flags & MULTI_OK) {
392 394 multi = B_TRUE;
393 395 break;
394 396 }
395 397 goto misconfigured;
396 398
397 399 case SCF_ERROR_PERMISSION_DENIED:
398 400 default:
399 401 scfdie();
400 402 }
401 403 }
402 404
403 405 switch (ty) {
404 406 case SCF_TYPE_ASTRING:
405 407 r = scf_value_get_astring(g_val, vp, sz) > 0 ? SCF_SUCCESS : -1;
406 408 break;
407 409
408 410 case SCF_TYPE_BOOLEAN:
409 411 r = scf_value_get_boolean(g_val, (uint8_t *)vp);
410 412 break;
411 413
412 414 case SCF_TYPE_COUNT:
413 415 r = scf_value_get_count(g_val, (uint64_t *)vp);
414 416 break;
415 417
416 418 case SCF_TYPE_INTEGER:
417 419 r = scf_value_get_integer(g_val, (int64_t *)vp);
418 420 break;
419 421
420 422 case SCF_TYPE_TIME: {
421 423 int64_t sec;
422 424 int32_t ns;
423 425 r = scf_value_get_time(g_val, &sec, &ns);
424 426 ((struct timeval *)vp)->tv_sec = sec;
425 427 ((struct timeval *)vp)->tv_usec = ns / 1000;
426 428 break;
427 429 }
428 430
429 431 case SCF_TYPE_USTRING:
430 432 r = scf_value_get_ustring(g_val, vp, sz) > 0 ? SCF_SUCCESS : -1;
431 433 break;
432 434
433 435 default:
434 436 #ifndef NDEBUG
435 437 uu_warn("%s:%d: Unknown type %d.\n", __FILE__, __LINE__, ty);
436 438 #endif
437 439 abort();
438 440 }
439 441 if (r != SCF_SUCCESS)
440 442 scfdie();
441 443
442 444 ret = multi ? E2BIG : 0;
443 445 goto out;
444 446
445 447 misconfigured:
446 448 buf_sz = max_scf_fmri_length + 1;
447 449 buf = safe_malloc(buf_sz);
448 450 if (scf_property_to_fmri(g_prop, buf, buf_sz) == -1)
449 451 scfdie();
450 452
451 453 uu_warn(gettext("Property \"%s\" is misconfigured.\n"), buf);
452 454
453 455 free(buf);
454 456
455 457 out:
456 458 if (ret != 0 || g_zonename == NULL ||
457 459 (strcmp(propname, SCF_PROPERTY_LOGFILE) != 0 &&
458 460 strcmp(propname, SCF_PROPERTY_ALT_LOGFILE) != 0))
459 461 return (ret);
460 462
461 463 /*
462 464 * If we're here, we have a log file and we have specified a zone.
463 465 * As a convenience, we're going to prepend the zone path to the
464 466 * name of the log file.
465 467 */
466 468 root[0] = '\0';
467 469 (void) zone_get_rootpath(g_zonename, root, sizeof (root));
468 470 (void) strlcat(root, vp, sizeof (root));
469 471 (void) snprintf(vp, sz, "%s", root);
470 472
471 473 return (ret);
472 474 }
473 475
474 476 static scf_snapshot_t *
475 477 get_running_snapshot(scf_instance_t *inst)
476 478 {
477 479 scf_snapshot_t *snap;
478 480
479 481 snap = scf_snapshot_create(h);
480 482 if (snap == NULL)
481 483 scfdie();
482 484
483 485 if (scf_instance_get_snapshot(inst, "running", snap) == 0)
484 486 return (snap);
485 487
486 488 if (scf_error() != SCF_ERROR_NOT_FOUND)
487 489 scfdie();
488 490
489 491 scf_snapshot_destroy(snap);
490 492 return (NULL);
491 493 }
492 494
493 495 /*
494 496 * As pg_get_single_val(), except look the property group up in an
495 497 * instance. If "use_running" is set, and the running snapshot exists,
496 498 * do a composed lookup there. Otherwise, do an (optionally composed)
497 499 * lookup on the current values. Note that lookups using snapshots are
498 500 * always composed.
499 501 */
500 502 int
501 503 inst_get_single_val(scf_instance_t *inst, const char *pgname,
502 504 const char *propname, scf_type_t ty, void *vp, size_t sz, uint_t flags,
503 505 int use_running, int composed)
504 506 {
505 507 scf_snapshot_t *snap = NULL;
506 508 int r;
507 509
508 510 if (use_running)
509 511 snap = get_running_snapshot(inst);
510 512 if (composed || use_running)
511 513 r = scf_instance_get_pg_composed(inst, snap, pgname, g_pg);
512 514 else
513 515 r = scf_instance_get_pg(inst, pgname, g_pg);
514 516 if (snap)
515 517 scf_snapshot_destroy(snap);
516 518 if (r == -1)
517 519 return (-1);
518 520
519 521 r = pg_get_single_val(g_pg, propname, ty, vp, sz, flags);
520 522
521 523 return (r);
522 524 }
523 525
524 526 static int
525 527 instance_enabled(scf_instance_t *inst, boolean_t temp)
526 528 {
527 529 uint8_t b;
528 530
529 531 if (inst_get_single_val(inst,
530 532 temp ? SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
531 533 SCF_TYPE_BOOLEAN, &b, 0, 0, 0, 0) != 0)
532 534 return (-1);
533 535
534 536 return (b ? 1 : 0);
535 537 }
536 538
537 539 /*
538 540 * Get a string property from the restarter property group of the given
539 541 * instance. Return an empty string on normal problems.
540 542 */
541 543 static void
542 544 get_restarter_string_prop(scf_instance_t *inst, const char *pname,
543 545 char *buf, size_t buf_sz)
544 546 {
545 547 if (inst_get_single_val(inst, SCF_PG_RESTARTER, pname,
546 548 SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0)
547 549 *buf = '\0';
548 550 }
549 551
550 552 static int
551 553 get_restarter_time_prop(scf_instance_t *inst, const char *pname,
552 554 struct timeval *tvp, int ok_if_empty)
553 555 {
554 556 int r;
555 557
556 558 r = inst_get_single_val(inst, SCF_PG_RESTARTER, pname, SCF_TYPE_TIME,
557 559 tvp, NULL, ok_if_empty ? EMPTY_OK : 0, 0, 1);
558 560
559 561 return (r == 0 ? 0 : -1);
560 562 }
561 563
562 564 static int
563 565 get_restarter_count_prop(scf_instance_t *inst, const char *pname, uint64_t *cp,
564 566 uint_t flags)
565 567 {
566 568 return (inst_get_single_val(inst, SCF_PG_RESTARTER, pname,
567 569 SCF_TYPE_COUNT, cp, 0, flags, 0, 1));
568 570 }
569 571
570 572
571 573 /*
572 574 * Generic functions
573 575 */
574 576
575 577 /*
576 578 * Return an array of pids associated with the given contract id.
577 579 * Returned pids are added to the end of the pidsp array.
578 580 */
579 581 static void
580 582 ctid_to_pids(uint64_t c, pid_t **pidsp, uint_t *np)
581 583 {
582 584 ct_stathdl_t ctst;
583 585 uint_t m;
584 586 int fd;
585 587 int r, err;
586 588 pid_t *pids;
587 589
588 590 fd = contract_open(c, NULL, "status", O_RDONLY);
589 591 if (fd < 0)
590 592 return;
591 593
592 594 err = ct_status_read(fd, CTD_ALL, &ctst);
593 595 if (err != 0) {
594 596 uu_warn(gettext("Could not read status of contract "
595 597 "%ld: %s.\n"), c, strerror(err));
596 598 (void) close(fd);
597 599 return;
598 600 }
599 601
600 602 (void) close(fd);
601 603
602 604 r = ct_pr_status_get_members(ctst, &pids, &m);
603 605 assert(r == 0);
604 606
605 607 if (m == 0) {
606 608 ct_status_free(ctst);
607 609 return;
608 610 }
609 611
610 612 *pidsp = realloc(*pidsp, (*np + m) * sizeof (*pidsp));
611 613 if (*pidsp == NULL)
612 614 uu_die(gettext("Out of memory"));
613 615
614 616 bcopy(pids, *pidsp + *np, m * sizeof (*pids));
615 617 *np += m;
616 618
617 619 ct_status_free(ctst);
618 620 }
619 621
620 622 static int
621 623 propvals_to_pids(scf_propertygroup_t *pg, const char *pname, pid_t **pidsp,
622 624 uint_t *np, scf_property_t *prop, scf_value_t *val, scf_iter_t *iter)
623 625 {
624 626 scf_type_t ty;
625 627 uint64_t c;
626 628 int r;
627 629
628 630 if (scf_pg_get_property(pg, pname, prop) != 0) {
629 631 if (scf_error() != SCF_ERROR_NOT_FOUND)
630 632 scfdie();
631 633
632 634 return (ENOENT);
633 635 }
634 636
635 637 if (scf_property_type(prop, &ty) != 0)
636 638 scfdie();
637 639
638 640 if (ty != SCF_TYPE_COUNT)
639 641 return (EINVAL);
640 642
641 643 if (scf_iter_property_values(iter, prop) != 0)
642 644 scfdie();
643 645
644 646 for (;;) {
645 647 r = scf_iter_next_value(iter, val);
646 648 if (r == -1)
647 649 scfdie();
648 650 if (r == 0)
649 651 break;
650 652
651 653 if (scf_value_get_count(val, &c) != 0)
652 654 scfdie();
653 655
654 656 ctid_to_pids(c, pidsp, np);
655 657 }
656 658
657 659 return (0);
658 660 }
659 661
660 662 /*
661 663 * Check if instance has general/restarter property that matches
662 664 * given string. Restarter string must be in canonified form.
663 665 * Returns 0 for success; -1 otherwise.
664 666 */
665 667 static int
666 668 check_for_restarter(scf_instance_t *inst, const char *restarter)
667 669 {
668 670 char *fmri_buf;
669 671 char *fmri_buf_canonified = NULL;
670 672 int ret = -1;
671 673
672 674 if (inst == NULL)
673 675 return (-1);
674 676
675 677 /* Get restarter */
676 678 fmri_buf = safe_malloc(max_scf_fmri_length + 1);
677 679 if (inst_get_single_val(inst, SCF_PG_GENERAL,
678 680 SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING, fmri_buf,
679 681 max_scf_fmri_length + 1, 0, 0, 1) != 0)
680 682 goto out;
681 683
682 684 fmri_buf_canonified = safe_malloc(max_scf_fmri_length + 1);
683 685 if (scf_canonify_fmri(fmri_buf, fmri_buf_canonified,
684 686 (max_scf_fmri_length + 1)) < 0)
685 687 goto out;
686 688
687 689 if (strcmp(fmri_buf, restarter) == 0)
688 690 ret = 0;
689 691
690 692 out:
691 693 free(fmri_buf);
692 694 if (fmri_buf_canonified)
693 695 free(fmri_buf_canonified);
694 696 return (ret);
695 697 }
696 698
697 699 /*
698 700 * Common code that is used by ctids_by_restarter and pids_by_restarter.
699 701 * Checks for a common restarter and if one is available, it generates
700 702 * the appropriate filename using wip->fmri and stores that in the
701 703 * global genfmri_filename.
702 704 *
703 705 * Restarters currently supported are: svc:/network/inetd:default
704 706 * If a restarter specific action is available, then restarter_spec
705 707 * is set to 1. If a restarter specific action is not available, then
706 708 * restarter_spec is set to 0 and a -1 is returned.
707 709 *
708 710 * Returns:
709 711 * 0 if success: restarter specific action found and filename generated
710 712 * -1 if restarter specific action not found,
711 713 * if restarter specific action found but an error was encountered
712 714 * during the generation of the wip->fmri based filename
713 715 */
714 716 static int
715 717 common_by_restarter(scf_instance_t *inst, const char *fmri,
716 718 int *restarter_specp)
717 719 {
718 720 int ret = -1;
719 721 int r;
720 722
721 723 /* Check for inetd specific restarter */
722 724 if (check_for_restarter(inst, "svc:/network/inetd:default") != 0) {
723 725 *restarter_specp = 0;
724 726 return (ret);
725 727 }
726 728
727 729 *restarter_specp = 1;
728 730
729 731 /* Get the ctid filename associated with this instance */
730 732 r = gen_filenms_from_fmri(fmri, "ctid", genfmri_filename, NULL);
731 733
732 734 switch (r) {
733 735 case 0:
734 736 break;
735 737
736 738 case -1:
737 739 /*
738 740 * Unable to get filename from fmri. Print warning
739 741 * and return failure with no ctids.
740 742 */
741 743 uu_warn(gettext("Unable to read contract ids for %s -- "
742 744 "FMRI is too long\n"), fmri);
743 745 return (ret);
744 746
745 747 case -2:
746 748 /*
747 749 * The directory didn't exist, so no contracts.
748 750 * Return failure with no ctids.
749 751 */
750 752 return (ret);
751 753
752 754 default:
753 755 uu_warn(gettext("%s:%d: gen_filenms_from_fmri() failed with "
754 756 "unknown error %d\n"), __FILE__, __LINE__, r);
755 757 abort();
756 758 }
757 759
758 760 return (0);
759 761
760 762 }
761 763
762 764 /*
763 765 * Get or print a contract id using a restarter specific action.
764 766 *
765 767 * If the print_flag is not set, this routine gets the single contract
766 768 * id associated with this instance.
767 769 * If the print flag is set, then print each contract id found.
768 770 *
769 771 * Returns:
770 772 * 0 if success: restarter specific action found and used with no error
771 773 * -1 if restarter specific action not found
772 774 * -1 if restarter specific action found, but there was a failure
773 775 * -1 if print flag is not set and no contract id is found or multiple
774 776 * contract ids were found
775 777 * E2BIG if print flag is not set, MULTI_OK bit in flag is set and multiple
776 778 * contract ids were found
777 779 */
778 780 static int
779 781 ctids_by_restarter(scf_walkinfo_t *wip, uint64_t *cp, int print_flag,
780 782 uint_t flags, int *restarter_specp, void (*callback_header)(),
781 783 void (*callback_ctid)(uint64_t))
782 784 {
783 785 FILE *fp;
784 786 int ret = -1;
785 787 int fscanf_ret;
786 788 uint64_t cp2;
787 789 int rest_ret;
788 790
789 791 /* Check if callbacks are needed and were passed in */
790 792 if (print_flag) {
791 793 if ((callback_header == NULL) || (callback_ctid == NULL))
792 794 return (ret);
793 795 }
794 796
795 797 /* Check for restarter specific action and generation of filename */
796 798 rest_ret = common_by_restarter(wip->inst, wip->fmri, restarter_specp);
797 799 if (rest_ret != 0)
798 800 return (rest_ret);
799 801
800 802 /*
801 803 * If fopen fails, then ctid file hasn't been created yet.
802 804 * If print_flag is set, this is ok; otherwise fail.
803 805 */
804 806 if ((fp = fopen(genfmri_filename, "r")) == NULL) {
805 807 if (print_flag)
806 808 return (0);
807 809 goto out;
808 810 }
809 811
810 812 if (print_flag) {
811 813 /*
812 814 * Print all contract ids that are found.
813 815 * First callback to print ctid header.
814 816 */
815 817 callback_header();
816 818
817 819 /* fscanf may not set errno, so be sure to clear it first */
818 820 errno = 0;
819 821 while ((fscanf_ret = fscanf(fp, "%llu", cp)) == 1) {
820 822 /* Callback to print contract id */
821 823 callback_ctid(*cp);
822 824 errno = 0;
823 825 }
824 826 /* EOF is not a failure when no errno. */
825 827 if ((fscanf_ret != EOF) || (errno != 0)) {
826 828 uu_die(gettext("Unable to read ctid file for %s"),
827 829 wip->fmri);
828 830 }
829 831 (void) putchar('\n');
830 832 ret = 0;
831 833 } else {
832 834 /* Must find 1 ctid or fail */
833 835 if (fscanf(fp, "%llu", cp) == 1) {
834 836 /* If 2nd ctid found - fail */
835 837 if (fscanf(fp, "%llu", &cp2) == 1) {
836 838 if (flags & MULTI_OK)
837 839 ret = E2BIG;
838 840 } else {
839 841 /* Success - found only 1 ctid */
840 842 ret = 0;
841 843 }
842 844 }
843 845 }
844 846 (void) fclose(fp);
845 847
846 848 out:
847 849 return (ret);
848 850 }
849 851
850 852 /*
851 853 * Get the process ids associated with an instance using a restarter
852 854 * specific action.
853 855 *
854 856 * Returns:
855 857 * 0 if success: restarter specific action found and used with no error
856 858 * -1 restarter specific action not found or if failure
857 859 */
858 860 static int
859 861 pids_by_restarter(scf_instance_t *inst, const char *fmri,
860 862 pid_t **pids, uint_t *np, int *restarter_specp)
861 863 {
862 864 uint64_t c;
863 865 FILE *fp;
864 866 int fscanf_ret;
865 867 int rest_ret;
866 868
867 869 /* Check for restarter specific action and generation of filename */
868 870 rest_ret = common_by_restarter(inst, fmri, restarter_specp);
869 871 if (rest_ret != 0)
870 872 return (rest_ret);
871 873
872 874 /*
873 875 * If fopen fails with ENOENT then the ctid file hasn't been
874 876 * created yet so return success.
875 877 * For all other errors - fail with uu_die.
876 878 */
877 879 if ((fp = fopen(genfmri_filename, "r")) == NULL) {
878 880 if (errno == ENOENT)
879 881 return (0);
880 882 uu_die(gettext("Unable to open ctid file for %s"), fmri);
881 883 }
882 884
883 885 /* fscanf may not set errno, so be sure to clear it first */
884 886 errno = 0;
885 887 while ((fscanf_ret = fscanf(fp, "%llu", &c)) == 1) {
886 888 if (c == 0) {
887 889 (void) fclose(fp);
888 890 uu_die(gettext("ctid file for %s has corrupt data"),
889 891 fmri);
890 892 }
891 893 ctid_to_pids(c, pids, np);
892 894 errno = 0;
893 895 }
894 896 /* EOF is not a failure when no errno. */
895 897 if ((fscanf_ret != EOF) || (errno != 0)) {
896 898 uu_die(gettext("Unable to read ctid file for %s"), fmri);
897 899 }
898 900
899 901 (void) fclose(fp);
900 902 return (0);
901 903 }
902 904
903 905 static int
904 906 instance_processes(scf_instance_t *inst, const char *fmri,
905 907 pid_t **pids, uint_t *np)
906 908 {
907 909 scf_iter_t *iter;
908 910 int ret;
909 911 int restarter_spec;
910 912
911 913 /* Use the restarter specific get pids routine, if available. */
912 914 ret = pids_by_restarter(inst, fmri, pids, np, &restarter_spec);
913 915 if (restarter_spec == 1)
914 916 return (ret);
915 917
916 918 if ((iter = scf_iter_create(h)) == NULL)
917 919 scfdie();
918 920
919 921 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) == 0) {
920 922 *pids = NULL;
921 923 *np = 0;
922 924
923 925 (void) propvals_to_pids(g_pg, scf_property_contract, pids, np,
924 926 g_prop, g_val, iter);
925 927
926 928 (void) propvals_to_pids(g_pg, SCF_PROPERTY_TRANSIENT_CONTRACT,
927 929 pids, np, g_prop, g_val, iter);
928 930
929 931 ret = 0;
930 932 } else {
931 933 if (scf_error() != SCF_ERROR_NOT_FOUND)
932 934 scfdie();
933 935
934 936 ret = -1;
935 937 }
936 938
937 939 scf_iter_destroy(iter);
938 940
939 941 return (ret);
940 942 }
941 943
942 944 static int
943 945 get_psinfo(pid_t pid, psinfo_t *psip)
944 946 {
945 947 char path[100];
946 948 int fd;
947 949
948 950 (void) snprintf(path, sizeof (path), "/proc/%lu/psinfo", pid);
949 951
950 952 fd = open64(path, O_RDONLY);
951 953 if (fd < 0)
952 954 return (-1);
953 955
954 956 if (read(fd, psip, sizeof (*psip)) < 0)
955 957 uu_die(gettext("Could not read info for process %lu"), pid);
956 958
957 959 (void) close(fd);
958 960
959 961 return (0);
960 962 }
961 963
962 964
963 965
964 966 /*
965 967 * Column sprint and sortkey functions
966 968 */
967 969
968 970 struct column {
969 971 const char *name;
970 972 int width;
971 973
972 974 /*
973 975 * This function should write the value for the column into buf, and
974 976 * grow or allocate buf accordingly. It should always write at least
975 977 * width bytes, blanking unused bytes with spaces. If the field is
976 978 * greater than the column width we allow it to overlap other columns.
977 979 * In particular, it shouldn't write any null bytes. (Though an extra
978 980 * null byte past the end is currently tolerated.) If the property
979 981 * group is non-NULL, then we are dealing with a legacy service.
980 982 */
981 983 void (*sprint)(char **, scf_walkinfo_t *);
982 984
983 985 int sortkey_width;
984 986
985 987 /*
986 988 * This function should write sortkey_width bytes into buf which will
987 989 * cause memcmp() to sort it properly. (Unlike sprint() above,
988 990 * however, an extra null byte may overrun the buffer.) The second
989 991 * argument controls whether the results are sorted in forward or
990 992 * reverse order.
991 993 */
992 994 void (*get_sortkey)(char *, int, scf_walkinfo_t *);
993 995 };
|
↓ open down ↓ |
835 lines elided |
↑ open up ↑ |
994 996
995 997 static void
996 998 reverse_bytes(char *buf, size_t len)
997 999 {
998 1000 int i;
999 1001
1000 1002 for (i = 0; i < len; ++i)
1001 1003 buf[i] = ~buf[i];
1002 1004 }
1003 1005
1006 +static void
1007 +sprint_str(char **buf, const char *str, size_t width)
1008 +{
1009 + char *newbuf;
1010 + size_t newsz = (*buf != NULL ? strlen(*buf) : 0) + 2;
1011 +
1012 + if (opt_scripted)
1013 + newsz += strlen(str);
1014 + else
1015 + newsz += width;
1016 +
1017 + newbuf = safe_malloc(newsz);
1018 +
1019 + if (opt_scripted) {
1020 + (void) snprintf(newbuf, newsz, "%s%s%s",
1021 + *buf != NULL ? *buf : "",
1022 + *buf != NULL ? "\t" : "",
1023 + str);
1024 + } else {
1025 + (void) snprintf(newbuf, newsz, "%s%-*s ",
1026 + *buf != NULL ? *buf : "", width, str);
1027 + }
1028 +
1029 + free(*buf);
1030 + *buf = newbuf;
1031 +}
1032 +
1004 1033 /* CTID */
1005 1034 #define CTID_COLUMN_WIDTH 6
1006 1035 #define CTID_COLUMN_BUFSIZE 20 /* max ctid_t + space + \0 */
1007 1036
1008 1037 static void
1009 1038 sprint_ctid(char **buf, scf_walkinfo_t *wip)
1010 1039 {
1011 1040 int r;
1012 1041 uint64_t c;
1013 - size_t newsize = (*buf ? strlen(*buf) : 0) + CTID_COLUMN_BUFSIZE;
1014 - char *newbuf = safe_malloc(newsize);
1042 + char ctid_buf[CTID_COLUMN_BUFSIZE] = { 0 };
1043 + char *cstr;
1015 1044 int restarter_spec;
1016 1045
1017 1046 /*
1018 1047 * Use the restarter specific get pids routine, if available.
1019 1048 * Only check for non-legacy services (wip->pg == 0).
1020 1049 */
1021 1050 if (wip->pg != NULL) {
1022 1051 r = pg_get_single_val(wip->pg, scf_property_contract,
1023 1052 SCF_TYPE_COUNT, &c, 0, EMPTY_OK | MULTI_OK);
1024 1053 } else {
1025 1054 r = ctids_by_restarter(wip, &c, 0, MULTI_OK, &restarter_spec,
1026 1055 NULL, NULL);
1027 1056 if (restarter_spec == 0) {
1028 1057 /* No restarter specific routine */
1029 1058 r = get_restarter_count_prop(wip->inst,
1030 1059 scf_property_contract, &c, EMPTY_OK | MULTI_OK);
1031 1060 }
1032 1061 }
1033 1062
1034 - if (r == 0)
1035 - (void) snprintf(newbuf, newsize, "%s%*lu ",
1036 - *buf ? *buf : "", CTID_COLUMN_WIDTH, (ctid_t)c);
1037 - else if (r == E2BIG)
1038 - (void) snprintf(newbuf, newsize, "%s%*lu* ",
1039 - *buf ? *buf : "", CTID_COLUMN_WIDTH - 1, (ctid_t)c);
1040 - else
1041 - (void) snprintf(newbuf, newsize, "%s%*s ",
1042 - *buf ? *buf : "", CTID_COLUMN_WIDTH, "-");
1043 - if (*buf)
1044 - free(*buf);
1045 - *buf = newbuf;
1063 + if (r == 0 || r == E2BIG) {
1064 + if (r == E2BIG)
1065 + ctid_buf[CTID_COLUMN_BUFSIZE - 2] = '*';
1066 + cstr = ulltostr(c, &ctid_buf[CTID_COLUMN_BUFSIZE - 2]);
1067 + sprint_str(buf, cstr, CTID_COLUMN_WIDTH);
1068 + } else {
1069 + sprint_str(buf, "-", CTID_COLUMN_WIDTH);
1070 + }
1046 1071 }
1047 1072
1048 1073 #define CTID_SORTKEY_WIDTH (sizeof (uint64_t))
1049 1074
1050 1075 static void
1051 1076 sortkey_ctid(char *buf, int reverse, scf_walkinfo_t *wip)
1052 1077 {
1053 1078 int r;
1054 1079 uint64_t c;
1055 1080 int restarter_spec;
1056 1081
1057 1082 /*
1058 1083 * Use the restarter specific get pids routine, if available.
1059 1084 * Only check for non-legacy services (wip->pg == 0).
1060 1085 */
1061 1086 if (wip->pg != NULL) {
1062 1087 r = pg_get_single_val(wip->pg, scf_property_contract,
1063 1088 SCF_TYPE_COUNT, &c, 0, EMPTY_OK);
1064 1089 } else {
1065 1090 r = ctids_by_restarter(wip, &c, 0, MULTI_OK, &restarter_spec,
1066 1091 NULL, NULL);
1067 1092 if (restarter_spec == 0) {
1068 1093 /* No restarter specific routine */
1069 1094 r = get_restarter_count_prop(wip->inst,
1070 1095 scf_property_contract, &c, EMPTY_OK);
1071 1096 }
1072 1097 }
1073 1098
1074 1099 if (r == 0) {
1075 1100 /*
1076 1101 * Use the id itself, but it must be big-endian for this to
1077 1102 * work.
1078 1103 */
1079 1104 c = BE_64(c);
1080 1105
1081 1106 bcopy(&c, buf, CTID_SORTKEY_WIDTH);
1082 1107 } else {
1083 1108 bzero(buf, CTID_SORTKEY_WIDTH);
1084 1109 }
1085 1110
1086 1111 if (reverse)
|
↓ open down ↓ |
31 lines elided |
↑ open up ↑ |
1087 1112 reverse_bytes(buf, CTID_SORTKEY_WIDTH);
1088 1113 }
1089 1114
1090 1115 /* DESC */
1091 1116 #define DESC_COLUMN_WIDTH 100
1092 1117
1093 1118 static void
1094 1119 sprint_desc(char **buf, scf_walkinfo_t *wip)
1095 1120 {
1096 1121 char *x;
1097 - size_t newsize;
1098 - char *newbuf;
1099 1122
1100 1123 if (common_name_buf == NULL)
1101 1124 common_name_buf = safe_malloc(max_scf_value_length + 1);
1102 1125
1103 1126 bzero(common_name_buf, max_scf_value_length + 1);
1104 1127
1105 1128 if (wip->pg != NULL) {
1106 1129 common_name_buf[0] = '-';
1107 1130 } else if (inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, locale,
1108 1131 SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0,
1109 1132 1, 1) == -1 &&
1110 1133 inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, "C",
1111 1134 SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0,
1112 1135 1, 1) == -1) {
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
1113 1136 common_name_buf[0] = '-';
1114 1137 }
1115 1138
1116 1139 /*
1117 1140 * Collapse multi-line tm_common_name values into a single line.
1118 1141 */
1119 1142 for (x = common_name_buf; *x != '\0'; x++)
1120 1143 if (*x == '\n')
1121 1144 *x = ' ';
1122 1145
1123 - if (strlen(common_name_buf) > DESC_COLUMN_WIDTH)
1124 - newsize = (*buf ? strlen(*buf) : 0) +
1125 - strlen(common_name_buf) + 1;
1126 - else
1127 - newsize = (*buf ? strlen(*buf) : 0) + DESC_COLUMN_WIDTH + 1;
1128 - newbuf = safe_malloc(newsize);
1129 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1130 - DESC_COLUMN_WIDTH, common_name_buf);
1131 - if (*buf)
1132 - free(*buf);
1133 - *buf = newbuf;
1146 + sprint_str(buf, common_name_buf, DESC_COLUMN_WIDTH);
1134 1147 }
1135 1148
1136 1149 /* ARGSUSED */
1137 1150 static void
1138 1151 sortkey_desc(char *buf, int reverse, scf_walkinfo_t *wip)
1139 1152 {
1140 1153 bzero(buf, DESC_COLUMN_WIDTH);
1141 1154 }
1142 1155
1143 1156 /* State columns (STATE, NSTATE, S, N, SN, STA, NSTA) */
1144 1157
1145 1158 static char
1146 1159 state_to_char(const char *state)
1147 1160 {
1148 1161 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0)
1149 1162 return ('u');
1150 1163
1151 1164 if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0)
1152 1165 return ('0');
1153 1166
1154 1167 if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0)
1155 1168 return ('1');
1156 1169
1157 1170 if (strcmp(state, SCF_STATE_STRING_MAINT) == 0)
1158 1171 return ('m');
1159 1172
1160 1173 if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
1161 1174 return ('d');
1162 1175
1163 1176 if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
1164 1177 return ('D');
1165 1178
1166 1179 if (strcmp(state, SCF_STATE_STRING_LEGACY) == 0)
1167 1180 return ('L');
1168 1181
1169 1182 return ('?');
1170 1183 }
1171 1184
1172 1185 /* Return true if inst is transitioning. */
1173 1186 static int
1174 1187 transitioning(scf_instance_t *inst)
1175 1188 {
1176 1189 char nstate_name[MAX_SCF_STATE_STRING_SZ];
1177 1190
1178 1191 get_restarter_string_prop(inst, scf_property_next_state, nstate_name,
1179 1192 sizeof (nstate_name));
1180 1193
1181 1194 return (state_to_char(nstate_name) != '?');
1182 1195 }
1183 1196
1184 1197 /* ARGSUSED */
1185 1198 static void
1186 1199 sortkey_states(const char *pname, char *buf, int reverse, scf_walkinfo_t *wip)
1187 1200 {
1188 1201 char state_name[MAX_SCF_STATE_STRING_SZ];
1189 1202
1190 1203 /*
1191 1204 * Lower numbers are printed first, so these are arranged from least
1192 1205 * interesting ("legacy run") to most interesting (unknown).
1193 1206 */
1194 1207 if (wip->pg == NULL) {
1195 1208 get_restarter_string_prop(wip->inst, pname, state_name,
1196 1209 sizeof (state_name));
1197 1210
1198 1211 if (strcmp(state_name, SCF_STATE_STRING_ONLINE) == 0)
1199 1212 *buf = 2;
1200 1213 else if (strcmp(state_name, SCF_STATE_STRING_DEGRADED) == 0)
1201 1214 *buf = 3;
1202 1215 else if (strcmp(state_name, SCF_STATE_STRING_OFFLINE) == 0)
1203 1216 *buf = 4;
1204 1217 else if (strcmp(state_name, SCF_STATE_STRING_MAINT) == 0)
1205 1218 *buf = 5;
1206 1219 else if (strcmp(state_name, SCF_STATE_STRING_DISABLED) == 0)
1207 1220 *buf = 1;
1208 1221 else if (strcmp(state_name, SCF_STATE_STRING_UNINIT) == 0)
1209 1222 *buf = 6;
1210 1223 else
1211 1224 *buf = 7;
1212 1225 } else
|
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
1213 1226 *buf = 0;
1214 1227
1215 1228 if (reverse)
1216 1229 *buf = 255 - *buf;
1217 1230 }
1218 1231
1219 1232 static void
1220 1233 sprint_state(char **buf, scf_walkinfo_t *wip)
1221 1234 {
1222 1235 char state_name[MAX_SCF_STATE_STRING_SZ + 1];
1223 - size_t newsize;
1224 - char *newbuf;
1225 1236
1226 1237 if (wip->pg == NULL) {
1227 1238 get_restarter_string_prop(wip->inst, scf_property_state,
1228 1239 state_name, sizeof (state_name));
1229 1240
1230 1241 /* Don't print blank fields, to ease parsing. */
1231 1242 if (state_name[0] == '\0') {
1232 1243 state_name[0] = '-';
1233 1244 state_name[1] = '\0';
1234 1245 }
1235 1246
1236 1247 if (!opt_nstate_shown && transitioning(wip->inst)) {
1237 1248 /* Append an asterisk if nstate is valid. */
1238 1249 (void) strcat(state_name, "*");
1239 1250 }
1240 1251 } else
1241 1252 (void) strcpy(state_name, SCF_STATE_STRING_LEGACY);
1242 1253
1243 - newsize = (*buf ? strlen(*buf) : 0) + MAX_SCF_STATE_STRING_SZ + 2;
1244 - newbuf = safe_malloc(newsize);
1245 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1246 - MAX_SCF_STATE_STRING_SZ + 1, state_name);
1247 -
1248 - if (*buf)
1249 - free(*buf);
1250 - *buf = newbuf;
1254 + sprint_str(buf, state_name, MAX_SCF_STATE_STRING_SZ);
1251 1255 }
1252 1256
1253 1257 static void
1254 1258 sortkey_state(char *buf, int reverse, scf_walkinfo_t *wip)
1255 1259 {
1256 1260 sortkey_states(scf_property_state, buf, reverse, wip);
1257 1261 }
1258 1262
1259 1263 static void
1260 1264 sprint_nstate(char **buf, scf_walkinfo_t *wip)
1261 1265 {
1262 - char next_state_name[MAX_SCF_STATE_STRING_SZ];
1266 + char next_state_name[MAX_SCF_STATE_STRING_SZ + 1];
1263 1267 boolean_t blank = 0;
1264 - size_t newsize;
1265 - char *newbuf;
1266 1268
1267 1269 if (wip->pg == NULL) {
1268 1270 get_restarter_string_prop(wip->inst, scf_property_next_state,
1269 1271 next_state_name, sizeof (next_state_name));
1270 1272
1271 1273 /* Don't print blank fields, to ease parsing. */
1272 1274 if (next_state_name[0] == '\0' ||
1273 1275 strcmp(next_state_name, SCF_STATE_STRING_NONE) == 0)
1274 1276 blank = 1;
1275 - } else
1277 + } else {
1276 1278 blank = 1;
1279 + }
1277 1280
1278 1281 if (blank) {
1279 1282 next_state_name[0] = '-';
1280 1283 next_state_name[1] = '\0';
1281 1284 }
1282 1285
1283 - newsize = (*buf ? strlen(*buf) : 0) + MAX_SCF_STATE_STRING_SZ + 1;
1284 - newbuf = safe_malloc(newsize);
1285 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1286 - MAX_SCF_STATE_STRING_SZ - 1, next_state_name);
1287 - if (*buf)
1288 - free(*buf);
1289 - *buf = newbuf;
1286 + sprint_str(buf, next_state_name, MAX_SCF_STATE_STRING_SZ);
1290 1287 }
1291 1288
1292 1289 static void
1293 1290 sortkey_nstate(char *buf, int reverse, scf_walkinfo_t *wip)
1294 1291 {
1295 1292 sortkey_states(scf_property_next_state, buf, reverse, wip);
1296 1293 }
1297 1294
1298 1295 static void
1299 1296 sprint_s(char **buf, scf_walkinfo_t *wip)
1300 1297 {
1301 - char tmp[3];
1302 - char state_name[MAX_SCF_STATE_STRING_SZ];
1303 - size_t newsize = (*buf ? strlen(*buf) : 0) + 4;
1304 - char *newbuf = safe_malloc(newsize);
1298 + char state_name[MAX_SCF_STATE_STRING_SZ + 1];
1299 + char tmp[3] = { 0 };
1305 1300
1306 1301 if (wip->pg == NULL) {
1307 1302 get_restarter_string_prop(wip->inst, scf_property_state,
1308 1303 state_name, sizeof (state_name));
1309 1304 tmp[0] = state_to_char(state_name);
1310 1305
1311 1306 if (!opt_nstate_shown && transitioning(wip->inst))
1312 1307 tmp[1] = '*';
1313 1308 else
1314 1309 tmp[1] = ' ';
1315 1310 } else {
1316 1311 tmp[0] = 'L';
1317 1312 tmp[1] = ' ';
1318 1313 }
1319 1314 tmp[2] = ' ';
1320 - (void) snprintf(newbuf, newsize, "%s%-*s", *buf ? *buf : "",
1321 - 3, tmp);
1322 - if (*buf)
1323 - free(*buf);
1324 - *buf = newbuf;
1315 +
1316 + sprint_str(buf, tmp, 2);
1325 1317 }
1326 1318
1327 1319 static void
1328 1320 sprint_n(char **buf, scf_walkinfo_t *wip)
1329 1321 {
1330 - char tmp[2];
1331 - size_t newsize = (*buf ? strlen(*buf) : 0) + 3;
1332 - char *newbuf = safe_malloc(newsize);
1333 - char nstate_name[MAX_SCF_STATE_STRING_SZ];
1322 + char nstate_name[MAX_SCF_STATE_STRING_SZ + 1];
1323 + char tmp[2] = { 0 };
1334 1324
1335 1325 if (wip->pg == NULL) {
1336 1326 get_restarter_string_prop(wip->inst, scf_property_next_state,
1337 1327 nstate_name, sizeof (nstate_name));
1338 1328
1339 1329 if (strcmp(nstate_name, SCF_STATE_STRING_NONE) == 0)
1340 1330 tmp[0] = '-';
1341 1331 else
1342 1332 tmp[0] = state_to_char(nstate_name);
1343 - } else
1333 + } else {
1344 1334 tmp[0] = '-';
1335 + }
1345 1336
1346 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1347 - 2, tmp);
1348 - if (*buf)
1349 - free(*buf);
1350 - *buf = newbuf;
1337 + sprint_str(buf, tmp, 1);
1351 1338 }
1352 1339
1353 1340 static void
1354 1341 sprint_sn(char **buf, scf_walkinfo_t *wip)
1355 1342 {
1356 - char tmp[3];
1357 - size_t newsize = (*buf ? strlen(*buf) : 0) + 4;
1358 - char *newbuf = safe_malloc(newsize);
1359 - char nstate_name[MAX_SCF_STATE_STRING_SZ];
1360 - char state_name[MAX_SCF_STATE_STRING_SZ];
1343 + char state_name[MAX_SCF_STATE_STRING_SZ + 1];
1344 + char nstate_name[MAX_SCF_STATE_STRING_SZ + 1];
1345 + char tmp[3] = { 0 };
1361 1346
1362 1347 if (wip->pg == NULL) {
1363 1348 get_restarter_string_prop(wip->inst, scf_property_state,
1364 1349 state_name, sizeof (state_name));
1365 1350 get_restarter_string_prop(wip->inst, scf_property_next_state,
1366 1351 nstate_name, sizeof (nstate_name));
1367 1352 tmp[0] = state_to_char(state_name);
1368 1353
1369 1354 if (strcmp(nstate_name, SCF_STATE_STRING_NONE) == 0)
1370 1355 tmp[1] = '-';
1371 1356 else
1372 1357 tmp[1] = state_to_char(nstate_name);
1373 1358 } else {
1374 1359 tmp[0] = 'L';
1375 1360 tmp[1] = '-';
1376 1361 }
1377 1362
1378 - tmp[2] = ' ';
1379 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1380 - 3, tmp);
1381 - if (*buf)
1382 - free(*buf);
1383 - *buf = newbuf;
1363 + sprint_str(buf, tmp, 2);
1384 1364 }
1385 1365
1386 1366 /* ARGSUSED */
1387 1367 static void
1388 1368 sortkey_sn(char *buf, int reverse, scf_walkinfo_t *wip)
1389 1369 {
1390 1370 sortkey_state(buf, reverse, wip);
1391 1371 sortkey_nstate(buf + 1, reverse, wip);
1392 1372 }
1393 1373
1394 1374 static const char *
1395 1375 state_abbrev(const char *state)
1396 1376 {
1397 1377 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0)
1398 1378 return ("UN");
1399 1379 if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0)
1400 1380 return ("OFF");
1401 1381 if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0)
1402 1382 return ("ON");
1403 1383 if (strcmp(state, SCF_STATE_STRING_MAINT) == 0)
1404 1384 return ("MNT");
1405 1385 if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0)
1406 1386 return ("DIS");
1407 1387 if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
1408 1388 return ("DGD");
1409 1389 if (strcmp(state, SCF_STATE_STRING_LEGACY) == 0)
1410 1390 return ("LRC");
1411 1391
1412 1392 return ("?");
1413 1393 }
1414 1394
1415 1395 static void
1416 1396 sprint_sta(char **buf, scf_walkinfo_t *wip)
1417 1397 {
1418 - char state_name[MAX_SCF_STATE_STRING_SZ];
1419 - char sta[5];
1420 - size_t newsize = (*buf ? strlen(*buf) : 0) + 6;
1421 - char *newbuf = safe_malloc(newsize);
1398 + char state_name[MAX_SCF_STATE_STRING_SZ + 1];
1399 + char sta[5] = { 0 };
1422 1400
1423 - if (wip->pg == NULL)
1401 + if (wip->pg == NULL) {
1424 1402 get_restarter_string_prop(wip->inst, scf_property_state,
1425 1403 state_name, sizeof (state_name));
1426 - else
1404 + } else {
1427 1405 (void) strcpy(state_name, SCF_STATE_STRING_LEGACY);
1406 + }
1428 1407
1429 1408 (void) strcpy(sta, state_abbrev(state_name));
1430 1409
1431 1410 if (wip->pg == NULL && !opt_nstate_shown && transitioning(wip->inst))
1432 1411 (void) strcat(sta, "*");
1433 1412
1434 - (void) snprintf(newbuf, newsize, "%s%-4s ", *buf ? *buf : "", sta);
1435 - if (*buf)
1436 - free(*buf);
1437 - *buf = newbuf;
1413 + sprint_str(buf, sta, 4);
1438 1414 }
1439 1415
1440 1416 static void
1441 1417 sprint_nsta(char **buf, scf_walkinfo_t *wip)
1442 1418 {
1443 - char state_name[MAX_SCF_STATE_STRING_SZ];
1444 - size_t newsize = (*buf ? strlen(*buf) : 0) + 6;
1445 - char *newbuf = safe_malloc(newsize);
1419 + char state_name[MAX_SCF_STATE_STRING_SZ + 1];
1446 1420
1447 - if (wip->pg == NULL)
1421 + if (wip->pg == NULL) {
1448 1422 get_restarter_string_prop(wip->inst, scf_property_next_state,
1449 1423 state_name, sizeof (state_name));
1450 - else
1424 + } else {
1451 1425 (void) strcpy(state_name, SCF_STATE_STRING_NONE);
1426 + }
1452 1427
1453 1428 if (strcmp(state_name, SCF_STATE_STRING_NONE) == 0)
1454 - (void) snprintf(newbuf, newsize, "%s%-4s ", *buf ? *buf : "",
1455 - "-");
1429 + sprint_str(buf, "-", 4);
1456 1430 else
1457 - (void) snprintf(newbuf, newsize, "%s%-4s ", *buf ? *buf : "",
1458 - state_abbrev(state_name));
1459 - if (*buf)
1460 - free(*buf);
1461 - *buf = newbuf;
1431 + sprint_str(buf, state_abbrev(state_name), 4);
1462 1432 }
1463 1433
1464 1434 /* FMRI */
1465 1435 #define FMRI_COLUMN_WIDTH 50
1466 1436 static void
1467 1437 sprint_fmri(char **buf, scf_walkinfo_t *wip)
1468 1438 {
1469 1439 char *fmri_buf = safe_malloc(max_scf_fmri_length + 1);
1470 - size_t newsize;
1471 - char *newbuf;
1472 1440
1473 1441 if (wip->pg == NULL) {
1474 1442 if (scf_instance_to_fmri(wip->inst, fmri_buf,
1475 1443 max_scf_fmri_length + 1) == -1)
1476 1444 scfdie();
1477 1445 } else {
1478 1446 (void) strcpy(fmri_buf, SCF_FMRI_LEGACY_PREFIX);
1479 1447 if (pg_get_single_val(wip->pg, SCF_LEGACY_PROPERTY_NAME,
1480 1448 SCF_TYPE_ASTRING, fmri_buf +
1481 1449 sizeof (SCF_FMRI_LEGACY_PREFIX) - 1,
1482 1450 max_scf_fmri_length + 1 -
1483 1451 (sizeof (SCF_FMRI_LEGACY_PREFIX) - 1), 0) != 0)
1484 1452 (void) strcat(fmri_buf, LEGACY_UNKNOWN);
1485 1453 }
1486 1454
1487 - if (strlen(fmri_buf) > FMRI_COLUMN_WIDTH)
1488 - newsize = (*buf ? strlen(*buf) : 0) + strlen(fmri_buf) + 2;
1489 - else
1490 - newsize = (*buf ? strlen(*buf) : 0) + FMRI_COLUMN_WIDTH + 2;
1491 - newbuf = safe_malloc(newsize);
1492 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1493 - FMRI_COLUMN_WIDTH, fmri_buf);
1455 + sprint_str(buf, fmri_buf, FMRI_COLUMN_WIDTH);
1494 1456 free(fmri_buf);
1495 - if (*buf)
1496 - free(*buf);
1497 - *buf = newbuf;
1498 1457 }
1499 1458
1500 1459 static void
1501 1460 sortkey_fmri(char *buf, int reverse, scf_walkinfo_t *wip)
1502 1461 {
1503 1462 char *tmp = NULL;
1504 1463
1505 1464 sprint_fmri(&tmp, wip);
1506 1465 bcopy(tmp, buf, FMRI_COLUMN_WIDTH);
1507 1466 free(tmp);
1508 1467 if (reverse)
1509 1468 reverse_bytes(buf, FMRI_COLUMN_WIDTH);
1510 1469 }
1511 1470
1512 1471 /* Component columns */
1513 1472 #define COMPONENT_COLUMN_WIDTH 20
1514 1473 static void
1515 1474 sprint_scope(char **buf, scf_walkinfo_t *wip)
1516 1475 {
1517 1476 char *scope_buf = safe_malloc(max_scf_name_length + 1);
1518 - size_t newsize = (*buf ? strlen(*buf) : 0) + COMPONENT_COLUMN_WIDTH + 2;
1519 - char *newbuf = safe_malloc(newsize);
1520 1477
1521 1478 assert(wip->scope != NULL);
1522 1479
1523 1480 if (scf_scope_get_name(wip->scope, scope_buf, max_scf_name_length) < 0)
1524 1481 scfdie();
1525 1482
1526 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1527 - COMPONENT_COLUMN_WIDTH, scope_buf);
1528 - if (*buf)
1529 - free(*buf);
1530 - *buf = newbuf;
1483 + sprint_str(buf, scope_buf, COMPONENT_COLUMN_WIDTH);
1531 1484 free(scope_buf);
1532 1485 }
1533 1486
1534 1487 static void
1535 1488 sortkey_scope(char *buf, int reverse, scf_walkinfo_t *wip)
1536 1489 {
1537 1490 char *tmp = NULL;
1538 1491
1539 1492 sprint_scope(&tmp, wip);
1540 1493 bcopy(tmp, buf, COMPONENT_COLUMN_WIDTH);
1541 1494 free(tmp);
1542 1495 if (reverse)
1543 1496 reverse_bytes(buf, COMPONENT_COLUMN_WIDTH);
1544 1497 }
1545 1498
1546 1499 static void
1547 1500 sprint_service(char **buf, scf_walkinfo_t *wip)
1548 1501 {
1549 1502 char *svc_buf = safe_malloc(max_scf_name_length + 1);
1550 - char *newbuf;
1551 - size_t newsize;
1552 1503
1553 1504 if (wip->pg == NULL) {
1554 1505 if (scf_service_get_name(wip->svc, svc_buf,
1555 1506 max_scf_name_length + 1) < 0)
1556 1507 scfdie();
1557 1508 } else {
1558 1509 if (pg_get_single_val(wip->pg, "name", SCF_TYPE_ASTRING,
1559 1510 svc_buf, max_scf_name_length + 1, EMPTY_OK) != 0)
1560 1511 (void) strcpy(svc_buf, LEGACY_UNKNOWN);
1561 1512 }
1562 1513
1563 -
1564 - if (strlen(svc_buf) > COMPONENT_COLUMN_WIDTH)
1565 - newsize = (*buf ? strlen(*buf) : 0) + strlen(svc_buf) + 2;
1566 - else
1567 - newsize = (*buf ? strlen(*buf) : 0) +
1568 - COMPONENT_COLUMN_WIDTH + 2;
1569 - newbuf = safe_malloc(newsize);
1570 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1571 - COMPONENT_COLUMN_WIDTH, svc_buf);
1514 + sprint_str(buf, svc_buf, COMPONENT_COLUMN_WIDTH);
1572 1515 free(svc_buf);
1573 - if (*buf)
1574 - free(*buf);
1575 - *buf = newbuf;
1576 1516 }
1577 1517
1578 1518 static void
1579 1519 sortkey_service(char *buf, int reverse, scf_walkinfo_t *wip)
1580 1520 {
1581 1521 char *tmp = NULL;
1582 1522
1583 1523 sprint_service(&tmp, wip);
1584 1524 bcopy(tmp, buf, COMPONENT_COLUMN_WIDTH);
1585 1525 free(tmp);
1586 1526 if (reverse)
1587 1527 reverse_bytes(buf, COMPONENT_COLUMN_WIDTH);
1588 1528 }
1589 1529
1590 1530 /* INST */
1591 1531 static void
1592 1532 sprint_instance(char **buf, scf_walkinfo_t *wip)
1593 1533 {
1594 - char *tmp = safe_malloc(max_scf_name_length + 1);
1595 - size_t newsize = (*buf ? strlen(*buf) : 0) + COMPONENT_COLUMN_WIDTH + 2;
1596 - char *newbuf = safe_malloc(newsize);
1534 + char *inst_buf = safe_malloc(max_scf_name_length + 1);
1597 1535
1598 1536 if (wip->pg == NULL) {
1599 - if (scf_instance_get_name(wip->inst, tmp,
1537 + if (scf_instance_get_name(wip->inst, inst_buf,
1600 1538 max_scf_name_length + 1) < 0)
1601 1539 scfdie();
1602 1540 } else {
1603 - tmp[0] = '-';
1604 - tmp[1] = '\0';
1541 + inst_buf[0] = '-';
1542 + inst_buf[1] = '\0';
1605 1543 }
1606 1544
1607 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1608 - COMPONENT_COLUMN_WIDTH, tmp);
1609 - if (*buf)
1610 - free(*buf);
1611 - *buf = newbuf;
1612 - free(tmp);
1545 +
1546 + sprint_str(buf, inst_buf, COMPONENT_COLUMN_WIDTH);
1547 + free(inst_buf);
1613 1548 }
1614 1549
1615 1550 static void
1616 1551 sortkey_instance(char *buf, int reverse, scf_walkinfo_t *wip)
1617 1552 {
1618 1553 char *tmp = NULL;
1619 1554
1620 1555 sprint_instance(&tmp, wip);
1621 1556 bcopy(tmp, buf, COMPONENT_COLUMN_WIDTH);
1622 1557 free(tmp);
1623 1558 if (reverse)
1624 1559 reverse_bytes(buf, COMPONENT_COLUMN_WIDTH);
1625 1560 }
1626 1561
1627 1562 /* STIME */
1628 1563 #define STIME_COLUMN_WIDTH 8
1629 1564 #define FORMAT_TIME "%k:%M:%S"
1630 -#define FORMAT_DATE "%b_%d "
1631 -#define FORMAT_YEAR "%Y "
1565 +#define FORMAT_DATE "%b_%d"
1566 +#define FORMAT_YEAR "%Y"
1632 1567
1633 1568 /*
1634 1569 * sprint_stime() will allocate a new buffer and snprintf the services's
1635 1570 * state timestamp. If the timestamp is unavailable for some reason
1636 1571 * a '-' is given instead.
1637 1572 */
1638 1573 static void
1639 1574 sprint_stime(char **buf, scf_walkinfo_t *wip)
1640 1575 {
1641 1576 int r;
1642 1577 struct timeval tv;
1643 1578 time_t then;
1644 1579 struct tm *tm;
1645 1580 char st_buf[STIME_COLUMN_WIDTH + 1];
1646 - size_t newsize = (*buf ? strlen(*buf) : 0) + STIME_COLUMN_WIDTH + 2;
1647 - char *newbuf = safe_malloc(newsize);
1648 1581
1649 1582 if (wip->pg == NULL) {
1650 1583 r = get_restarter_time_prop(wip->inst,
1651 1584 SCF_PROPERTY_STATE_TIMESTAMP, &tv, 0);
1652 1585 } else {
1653 1586 r = pg_get_single_val(wip->pg, SCF_PROPERTY_STATE_TIMESTAMP,
1654 1587 SCF_TYPE_TIME, &tv, NULL, 0);
1655 1588 }
1656 1589
1657 1590 if (r != 0) {
1658 1591 /*
1659 1592 * There's something amiss with our service
1660 1593 * so we'll print a '-' for STIME.
1661 1594 */
1662 - (void) snprintf(newbuf, newsize, "%s%-*s", *buf ? *buf : "",
1663 - STIME_COLUMN_WIDTH + 1, "-");
1595 + sprint_str(buf, "-", STIME_COLUMN_WIDTH);
1664 1596 } else {
1665 1597 /* tv should be valid so we'll format it */
1666 1598 then = (time_t)tv.tv_sec;
1667 1599
1668 1600 tm = localtime(&then);
1669 1601 /*
1670 1602 * Print time if started within the past 24 hours, print date
1671 1603 * if within the past 12 months or, finally, print year if
1672 1604 * started greater than 12 months ago.
1673 1605 */
1674 1606 if (now - then < 24 * 60 * 60) {
1675 1607 (void) strftime(st_buf, sizeof (st_buf),
1676 1608 gettext(FORMAT_TIME), tm);
1677 1609 } else if (now - then < 12 * 30 * 24 * 60 * 60) {
1678 1610 (void) strftime(st_buf, sizeof (st_buf),
1679 1611 gettext(FORMAT_DATE), tm);
1680 1612 } else {
1681 1613 (void) strftime(st_buf, sizeof (st_buf),
1682 1614 gettext(FORMAT_YEAR), tm);
1683 1615 }
1684 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1685 - STIME_COLUMN_WIDTH + 1, st_buf);
1616 + sprint_str(buf, st_buf, STIME_COLUMN_WIDTH);
1686 1617 }
1687 - if (*buf)
1688 - free(*buf);
1689 - *buf = newbuf;
1690 1618 }
1691 1619
1692 1620 #define STIME_SORTKEY_WIDTH (sizeof (uint64_t) + sizeof (uint32_t))
1693 1621
1694 1622 /* ARGSUSED */
1695 1623 static void
1696 1624 sortkey_stime(char *buf, int reverse, scf_walkinfo_t *wip)
1697 1625 {
1698 1626 struct timeval tv;
1699 1627 int r;
1700 1628
1701 1629 if (wip->pg == NULL)
1702 1630 r = get_restarter_time_prop(wip->inst,
1703 1631 SCF_PROPERTY_STATE_TIMESTAMP, &tv, 0);
1704 1632 else
1705 1633 r = pg_get_single_val(wip->pg, SCF_PROPERTY_STATE_TIMESTAMP,
1706 1634 SCF_TYPE_TIME, &tv, NULL, 0);
1707 1635
1708 1636 if (r == 0) {
1709 1637 int64_t sec;
1710 1638 int32_t us;
1711 1639
1712 1640 /* Stick it straight into the buffer. */
1713 1641 sec = tv.tv_sec;
1714 1642 us = tv.tv_usec;
1715 1643
1716 1644 sec = BE_64(sec);
1717 1645 us = BE_32(us);
1718 1646 bcopy(&sec, buf, sizeof (sec));
1719 1647 bcopy(&us, buf + sizeof (sec), sizeof (us));
1720 1648 } else {
1721 1649 bzero(buf, STIME_SORTKEY_WIDTH);
1722 1650 }
1723 1651
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
1724 1652 if (reverse)
1725 1653 reverse_bytes(buf, STIME_SORTKEY_WIDTH);
1726 1654 }
1727 1655
1728 1656 /* ZONE */
1729 1657 #define ZONE_COLUMN_WIDTH 16
1730 1658 /*ARGSUSED*/
1731 1659 static void
1732 1660 sprint_zone(char **buf, scf_walkinfo_t *wip)
1733 1661 {
1734 - size_t newsize;
1735 - char *newbuf, *zonename = g_zonename, b[ZONENAME_MAX];
1662 + char *zonename = g_zonename, b[ZONENAME_MAX];
1736 1663
1737 1664 if (zonename == NULL) {
1738 1665 zoneid_t zoneid = getzoneid();
1739 1666
1740 1667 if (getzonenamebyid(zoneid, b, sizeof (b)) < 0)
1741 1668 uu_die(gettext("could not determine zone name"));
1742 1669
1743 1670 zonename = b;
1744 1671 }
1745 1672
1746 - if (strlen(zonename) > ZONE_COLUMN_WIDTH)
1747 - newsize = (*buf ? strlen(*buf) : 0) + strlen(zonename) + 2;
1748 - else
1749 - newsize = (*buf ? strlen(*buf) : 0) + ZONE_COLUMN_WIDTH + 2;
1750 -
1751 - newbuf = safe_malloc(newsize);
1752 - (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
1753 - ZONE_COLUMN_WIDTH, zonename);
1754 -
1755 - if (*buf)
1756 - free(*buf);
1757 - *buf = newbuf;
1673 + sprint_str(buf, zonename, ZONE_COLUMN_WIDTH);
1758 1674 }
1759 1675
1760 1676 static void
1761 1677 sortkey_zone(char *buf, int reverse, scf_walkinfo_t *wip)
1762 1678 {
1763 1679 char *tmp = NULL;
1764 1680
1765 1681 sprint_zone(&tmp, wip);
1766 1682 bcopy(tmp, buf, ZONE_COLUMN_WIDTH);
1767 1683 free(tmp);
1768 1684 if (reverse)
1769 1685 reverse_bytes(buf, ZONE_COLUMN_WIDTH);
1770 1686 }
1771 1687
1772 1688 /*
1773 1689 * Information about columns which can be displayed. If you add something,
1774 1690 * check MAX_COLUMN_NAME_LENGTH_STR & update description_of_column() below.
1775 1691 */
1776 1692 static const struct column columns[] = {
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
1777 1693 { "CTID", CTID_COLUMN_WIDTH, sprint_ctid,
1778 1694 CTID_SORTKEY_WIDTH, sortkey_ctid },
1779 1695 { "DESC", DESC_COLUMN_WIDTH, sprint_desc,
1780 1696 DESC_COLUMN_WIDTH, sortkey_desc },
1781 1697 { "FMRI", FMRI_COLUMN_WIDTH, sprint_fmri,
1782 1698 FMRI_COLUMN_WIDTH, sortkey_fmri },
1783 1699 { "INST", COMPONENT_COLUMN_WIDTH, sprint_instance,
1784 1700 COMPONENT_COLUMN_WIDTH, sortkey_instance },
1785 1701 { "N", 1, sprint_n, 1, sortkey_nstate },
1786 1702 { "NSTA", 4, sprint_nsta, 1, sortkey_nstate },
1787 - { "NSTATE", MAX_SCF_STATE_STRING_SZ - 1, sprint_nstate,
1703 + { "NSTATE", MAX_SCF_STATE_STRING_SZ, sprint_nstate,
1788 1704 1, sortkey_nstate },
1789 1705 { "S", 2, sprint_s, 1, sortkey_state },
1790 1706 { "SCOPE", COMPONENT_COLUMN_WIDTH, sprint_scope,
1791 1707 COMPONENT_COLUMN_WIDTH, sortkey_scope },
1792 1708 { "SN", 2, sprint_sn, 2, sortkey_sn },
1793 1709 { "SVC", COMPONENT_COLUMN_WIDTH, sprint_service,
1794 1710 COMPONENT_COLUMN_WIDTH, sortkey_service },
1795 1711 { "STA", 4, sprint_sta, 1, sortkey_state },
1796 - { "STATE", MAX_SCF_STATE_STRING_SZ - 1 + 1, sprint_state,
1712 + { "STATE", MAX_SCF_STATE_STRING_SZ, sprint_state,
1797 1713 1, sortkey_state },
1798 1714 { "STIME", STIME_COLUMN_WIDTH, sprint_stime,
1799 1715 STIME_SORTKEY_WIDTH, sortkey_stime },
1800 1716 { "ZONE", ZONE_COLUMN_WIDTH, sprint_zone,
1801 1717 ZONE_COLUMN_WIDTH, sortkey_zone },
1802 1718 };
1803 1719
1804 1720 #define MAX_COLUMN_NAME_LENGTH_STR "6"
1805 1721
1806 1722 static const int ncolumns = sizeof (columns) / sizeof (columns[0]);
1807 1723
1808 1724 /*
1809 1725 * Necessary thanks to gettext() & xgettext.
1810 1726 */
1811 1727 static const char *
1812 1728 description_of_column(int c)
1813 1729 {
1814 1730 const char *s = NULL;
1815 1731
1816 1732 switch (c) {
1817 1733 case 0:
1818 1734 s = gettext("contract ID for service (see contract(4))");
1819 1735 break;
1820 1736 case 1:
1821 1737 s = gettext("human-readable description of the service");
1822 1738 break;
1823 1739 case 2:
1824 1740 s = gettext("Fault Managed Resource Identifier for service");
1825 1741 break;
1826 1742 case 3:
1827 1743 s = gettext("portion of the FMRI indicating service instance");
1828 1744 break;
1829 1745 case 4:
1830 1746 s = gettext("abbreviation for next state (if in transition)");
1831 1747 break;
1832 1748 case 5:
1833 1749 s = gettext("abbreviation for next state (if in transition)");
1834 1750 break;
1835 1751 case 6:
1836 1752 s = gettext("name for next state (if in transition)");
1837 1753 break;
1838 1754 case 7:
1839 1755 s = gettext("abbreviation for current state");
1840 1756 break;
1841 1757 case 8:
1842 1758 s = gettext("name for scope associated with service");
1843 1759 break;
1844 1760 case 9:
1845 1761 s = gettext("abbreviation for current state and next state");
1846 1762 break;
1847 1763 case 10:
1848 1764 s = gettext("portion of the FMRI representing service name");
1849 1765 break;
1850 1766 case 11:
1851 1767 s = gettext("abbreviation for current state");
1852 1768 break;
1853 1769 case 12:
1854 1770 s = gettext("name for current state");
1855 1771 break;
1856 1772 case 13:
1857 1773 s = gettext("time of last state change");
1858 1774 break;
1859 1775 case 14:
1860 1776 s = gettext("name of zone");
1861 1777 break;
|
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
1862 1778 }
1863 1779
1864 1780 assert(s != NULL);
1865 1781 return (s);
1866 1782 }
1867 1783
1868 1784
1869 1785 static void
1870 1786 print_usage(const char *progname, FILE *f, boolean_t do_exit)
1871 1787 {
1872 - (void) fprintf(f, gettext(
1873 - "Usage: %1$s [-aHpv] [-o col[,col ... ]] [-R restarter] "
1874 - "[-sS col] [-Z | -z zone ]\n [<service> ...]\n"
1875 - " %1$s -d | -D [-Hpv] [-o col[,col ... ]] [-sS col] "
1876 - "[-Z | -z zone ]\n [<service> ...]\n"
1877 - " %1$s [-l | -L] [-Z | -z zone] <service> ...\n"
1878 - " %1$s -x [-v] [-Z | -z zone] [<service> ...]\n"
1879 - " %1$s -?\n"), progname);
1788 + (void) fprintf(f, gettext("usage:\n"
1789 + "%1$s\t[-aHpv?] [-o col[,col]...] [-R FMRI-instance]... "
1790 + "[-sS col]...\n\t[-z zone|-Z] [FMRI|pattern]...\n"
1791 + "%1$s\t{-d|-D} -Hpv? [-o col[,col]...] [-sS col]... [-z zone|-Z]\n"
1792 + "\t[FMRI|pattern]...\n"
1793 + "%1$s\t{-l|-L} [-v] [-z zone|-Z] {FMRI|pattern}...\n"
1794 + "%1$s\t-x [-v] [-z zone|-Z] [FMRI]...\n"), progname);
1880 1795
1881 1796 if (do_exit)
1882 1797 exit(UU_EXIT_USAGE);
1883 1798 }
1884 1799
1885 1800 #define argserr(progname) print_usage(progname, stderr, B_TRUE)
1886 1801
1887 1802 static void
1888 1803 print_help(const char *progname)
1889 1804 {
1890 1805 int i;
1891 1806
1892 1807 print_usage(progname, stdout, B_FALSE);
1893 1808
1894 1809 (void) printf(gettext("\n"
1895 1810 "\t-a list all service instances rather than "
1896 1811 "only those that are enabled\n"
1897 1812 "\t-d list dependencies of the specified service(s)\n"
1898 1813 "\t-D list dependents of the specified service(s)\n"
1899 1814 "\t-H omit header line from output\n"
1900 1815 "\t-l list detailed information about the specified service(s)\n"
1901 1816 "\t-L list the log file associated with the specified service(s)\n"
1902 1817 "\t-o list only the specified columns in the output\n"
1903 1818 "\t-p list process IDs and names associated with each service\n"
1904 1819 "\t-R list only those services with the specified restarter\n"
1905 1820 "\t-s sort output in ascending order by the specified column(s)\n"
1906 1821 "\t-S sort output in descending order by the specified column(s)\n"
1907 1822 "\t-v list verbose information appropriate to the type of output\n"
1908 1823 "\t-x explain the status of services that might require maintenance,\n"
1909 1824 "\t or explain the status of the specified service(s)\n"
1910 1825 "\t-z from global zone, show services in a specified zone\n"
1911 1826 "\t-Z from global zone, show services in all zones\n"
1912 1827 "\n\t"
1913 1828 "Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
1914 1829 "\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1915 1830 "\n"
1916 1831 "\t%1$s [opts] svc:/network/smtp:sendmail\n"
1917 1832 "\t%1$s [opts] network/smtp:sendmail\n"
1918 1833 "\t%1$s [opts] network/*mail\n"
1919 1834 "\t%1$s [opts] network/smtp\n"
1920 1835 "\t%1$s [opts] smtp:sendmail\n"
1921 1836 "\t%1$s [opts] smtp\n"
1922 1837 "\t%1$s [opts] sendmail\n"
1923 1838 "\n\t"
1924 1839 "Columns for output or sorting can be specified using these names:\n"
1925 1840 "\n"), progname);
1926 1841
1927 1842 for (i = 0; i < ncolumns; i++) {
1928 1843 (void) printf("\t%-" MAX_COLUMN_NAME_LENGTH_STR "s %s\n",
1929 1844 columns[i].name, description_of_column(i));
1930 1845 }
1931 1846 }
1932 1847
1933 1848
1934 1849 /*
1935 1850 * A getsubopt()-like function which returns an index into the columns table.
1936 1851 * On success, *optionp is set to point to the next sub-option, or the
1937 1852 * terminating null if there are none.
1938 1853 */
1939 1854 static int
1940 1855 getcolumnopt(char **optionp)
1941 1856 {
1942 1857 char *str = *optionp, *cp;
1943 1858 int i;
1944 1859
1945 1860 assert(optionp != NULL);
1946 1861 assert(*optionp != NULL);
1947 1862
1948 1863 cp = strchr(*optionp, ',');
1949 1864 if (cp != NULL)
1950 1865 *cp = '\0';
1951 1866
1952 1867 for (i = 0; i < ncolumns; ++i) {
1953 1868 if (strcasecmp(str, columns[i].name) == 0) {
1954 1869 if (cp != NULL)
1955 1870 *optionp = cp + 1;
1956 1871 else
1957 1872 *optionp = strchr(*optionp, '\0');
1958 1873
1959 1874 return (i);
1960 1875 }
1961 1876 }
1962 1877
1963 1878 return (-1);
1964 1879 }
1965 1880
1966 1881 static void
1967 1882 print_header()
1968 1883 {
1969 1884 int i;
1970 1885 char *line_buf, *cp;
1971 1886
1972 1887 line_buf = safe_malloc(line_sz);
1973 1888 cp = line_buf;
1974 1889 for (i = 0; i < opt_cnum; ++i) {
1975 1890 const struct column * const colp = &columns[opt_columns[i]];
1976 1891
1977 1892 (void) snprintf(cp, colp->width + 1, "%-*s", colp->width,
1978 1893 colp->name);
1979 1894 cp += colp->width;
1980 1895 *cp++ = ' ';
1981 1896 }
1982 1897
1983 1898 /* Trim the trailing whitespace */
1984 1899 --cp;
1985 1900 while (*cp == ' ')
1986 1901 --cp;
1987 1902 *(cp+1) = '\0';
1988 1903 (void) puts(line_buf);
1989 1904
1990 1905 free(line_buf);
1991 1906 }
1992 1907
1993 1908
1994 1909
1995 1910 /*
1996 1911 * Long listing (-l) functions.
1997 1912 */
1998 1913
1999 1914 static int
2000 1915 pidcmp(const void *l, const void *r)
2001 1916 {
2002 1917 pid_t lp = *(pid_t *)l, rp = *(pid_t *)r;
2003 1918
2004 1919 if (lp < rp)
2005 1920 return (-1);
2006 1921 if (lp > rp)
2007 1922 return (1);
2008 1923 return (0);
2009 1924 }
2010 1925
2011 1926 /*
2012 1927 * This is the strlen() of the longest label ("description"), plus intercolumn
2013 1928 * space.
2014 1929 */
2015 1930 #define DETAILED_WIDTH (11 + 2)
2016 1931
2017 1932 /*
2018 1933 * Callback routine to print header for contract id.
2019 1934 * Called by ctids_by_restarter and print_detailed.
2020 1935 */
2021 1936 static void
2022 1937 print_ctid_header()
2023 1938 {
2024 1939 (void) printf("%-*s", DETAILED_WIDTH, "contract_id");
2025 1940 }
2026 1941
2027 1942 /*
2028 1943 * Callback routine to print a contract id.
2029 1944 * Called by ctids_by_restarter and print_detailed.
2030 1945 */
2031 1946 static void
2032 1947 print_ctid_detailed(uint64_t c)
2033 1948 {
2034 1949 (void) printf("%lu ", (ctid_t)c);
2035 1950 }
2036 1951
2037 1952 static void
2038 1953 detailed_list_processes(scf_walkinfo_t *wip)
2039 1954 {
2040 1955 uint64_t c;
2041 1956 pid_t *pids;
2042 1957 uint_t i, n;
2043 1958 psinfo_t psi;
2044 1959
2045 1960 if (get_restarter_count_prop(wip->inst, scf_property_contract, &c,
2046 1961 EMPTY_OK) != 0)
2047 1962 return;
2048 1963
2049 1964 if (instance_processes(wip->inst, wip->fmri, &pids, &n) != 0)
2050 1965 return;
2051 1966
2052 1967 qsort(pids, n, sizeof (*pids), pidcmp);
2053 1968
2054 1969 for (i = 0; i < n; ++i) {
2055 1970 (void) printf("%-*s%lu", DETAILED_WIDTH, gettext("process"),
2056 1971 pids[i]);
2057 1972
2058 1973 if (get_psinfo(pids[i], &psi) == 0)
2059 1974 (void) printf(" %.*s", PRARGSZ, psi.pr_psargs);
2060 1975
2061 1976 (void) putchar('\n');
2062 1977 }
2063 1978
2064 1979 free(pids);
2065 1980 }
2066 1981
2067 1982 /*
2068 1983 * Determines the state of a dependency. If the FMRI specifies a file, then we
2069 1984 * fake up a state based on whether we can access the file.
2070 1985 */
2071 1986 static void
2072 1987 get_fmri_state(char *fmri, char *state, size_t state_sz)
2073 1988 {
2074 1989 char *lfmri;
2075 1990 const char *svc_name, *inst_name, *pg_name, *path;
2076 1991 scf_service_t *svc;
2077 1992 scf_instance_t *inst;
2078 1993 scf_iter_t *iter;
2079 1994
2080 1995 lfmri = safe_strdup(fmri);
2081 1996
2082 1997 /*
2083 1998 * Check for file:// dependencies
2084 1999 */
2085 2000 if (scf_parse_file_fmri(lfmri, NULL, &path) == SCF_SUCCESS) {
2086 2001 struct stat64 statbuf;
2087 2002 const char *msg;
2088 2003
2089 2004 if (stat64(path, &statbuf) == 0)
2090 2005 msg = "online";
2091 2006 else if (errno == ENOENT)
2092 2007 msg = "absent";
2093 2008 else
2094 2009 msg = "unknown";
2095 2010
2096 2011 (void) strlcpy(state, msg, state_sz);
2097 2012 return;
2098 2013 }
2099 2014
2100 2015 /*
2101 2016 * scf_parse_file_fmri() may have overwritten part of the string, so
2102 2017 * copy it back.
2103 2018 */
2104 2019 (void) strcpy(lfmri, fmri);
2105 2020
2106 2021 if (scf_parse_svc_fmri(lfmri, NULL, &svc_name, &inst_name,
2107 2022 &pg_name, NULL) != SCF_SUCCESS) {
2108 2023 free(lfmri);
2109 2024 (void) strlcpy(state, "invalid", state_sz);
2110 2025 return;
2111 2026 }
2112 2027
2113 2028 free(lfmri);
2114 2029
2115 2030 if (svc_name == NULL || pg_name != NULL) {
2116 2031 (void) strlcpy(state, "invalid", state_sz);
2117 2032 return;
2118 2033 }
2119 2034
2120 2035 if (inst_name != NULL) {
2121 2036 /* instance: get state */
2122 2037 inst = scf_instance_create(h);
2123 2038 if (inst == NULL)
2124 2039 scfdie();
2125 2040
2126 2041 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
2127 2042 NULL, SCF_DECODE_FMRI_EXACT) == SCF_SUCCESS)
2128 2043 get_restarter_string_prop(inst, scf_property_state,
2129 2044 state, state_sz);
2130 2045 else {
2131 2046 switch (scf_error()) {
2132 2047 case SCF_ERROR_INVALID_ARGUMENT:
2133 2048 (void) strlcpy(state, "invalid", state_sz);
2134 2049 break;
2135 2050 case SCF_ERROR_NOT_FOUND:
2136 2051 (void) strlcpy(state, "absent", state_sz);
2137 2052 break;
2138 2053
2139 2054 default:
2140 2055 scfdie();
2141 2056 }
2142 2057 }
2143 2058
2144 2059 scf_instance_destroy(inst);
2145 2060 return;
2146 2061 }
2147 2062
2148 2063 /*
2149 2064 * service: If only one instance, use that state. Otherwise, say
2150 2065 * "multiple".
2151 2066 */
2152 2067 if ((svc = scf_service_create(h)) == NULL ||
2153 2068 (inst = scf_instance_create(h)) == NULL ||
2154 2069 (iter = scf_iter_create(h)) == NULL)
2155 2070 scfdie();
2156 2071
2157 2072 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
2158 2073 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
2159 2074 switch (scf_error()) {
2160 2075 case SCF_ERROR_INVALID_ARGUMENT:
2161 2076 (void) strlcpy(state, "invalid", state_sz);
2162 2077 goto out;
2163 2078 case SCF_ERROR_NOT_FOUND:
2164 2079 (void) strlcpy(state, "absent", state_sz);
2165 2080 goto out;
2166 2081
2167 2082 default:
2168 2083 scfdie();
2169 2084 }
2170 2085 }
2171 2086
2172 2087 if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
2173 2088 scfdie();
2174 2089
2175 2090 switch (scf_iter_next_instance(iter, inst)) {
2176 2091 case 0:
2177 2092 (void) strlcpy(state, "absent", state_sz);
2178 2093 goto out;
2179 2094
2180 2095 case 1:
2181 2096 break;
2182 2097
2183 2098 default:
2184 2099 scfdie();
2185 2100 }
2186 2101
2187 2102 /* Get the state in case this is the only instance. */
2188 2103 get_restarter_string_prop(inst, scf_property_state, state, state_sz);
2189 2104
2190 2105 switch (scf_iter_next_instance(iter, inst)) {
2191 2106 case 0:
2192 2107 break;
2193 2108
2194 2109 case 1:
2195 2110 /* Nope, multiple instances. */
2196 2111 (void) strlcpy(state, "multiple", state_sz);
2197 2112 goto out;
2198 2113
2199 2114 default:
2200 2115 scfdie();
2201 2116 }
2202 2117
2203 2118 out:
2204 2119 scf_iter_destroy(iter);
2205 2120 scf_instance_destroy(inst);
2206 2121 scf_service_destroy(svc);
2207 2122 }
2208 2123
2209 2124 static void
2210 2125 print_application_properties(scf_walkinfo_t *wip, scf_snapshot_t *snap)
2211 2126 {
2212 2127 scf_iter_t *pg_iter, *prop_iter, *val_iter;
2213 2128 scf_propertygroup_t *pg;
2214 2129 scf_property_t *prop;
2215 2130 scf_value_t *val;
2216 2131 scf_pg_tmpl_t *pt;
2217 2132 scf_prop_tmpl_t *prt;
2218 2133 char *pg_name_buf = safe_malloc(max_scf_name_length + 1);
2219 2134 char *prop_name_buf = safe_malloc(max_scf_name_length + 1);
2220 2135 char *snap_name = safe_malloc(max_scf_name_length + 1);
2221 2136 char *val_buf = safe_malloc(max_scf_value_length + 1);
2222 2137 char *desc, *cp;
2223 2138 scf_type_t type;
2224 2139 int i, j, k;
2225 2140 uint8_t vis;
2226 2141
2227 2142 if ((pg_iter = scf_iter_create(h)) == NULL ||
2228 2143 (prop_iter = scf_iter_create(h)) == NULL ||
2229 2144 (val_iter = scf_iter_create(h)) == NULL ||
2230 2145 (val = scf_value_create(h)) == NULL ||
2231 2146 (prop = scf_property_create(h)) == NULL ||
2232 2147 (pt = scf_tmpl_pg_create(h)) == NULL ||
2233 2148 (prt = scf_tmpl_prop_create(h)) == NULL ||
2234 2149 (pg = scf_pg_create(h)) == NULL)
2235 2150 scfdie();
2236 2151
2237 2152 if (scf_iter_instance_pgs_typed_composed(pg_iter, wip->inst, snap,
2238 2153 SCF_PG_APP_DEFAULT) == -1)
2239 2154 scfdie();
2240 2155
2241 2156 /*
2242 2157 * Format for output:
2243 2158 * pg (pgtype)
2244 2159 * description
2245 2160 * pg/prop (proptype) = <value> <value>
2246 2161 * description
2247 2162 */
2248 2163 while ((i = scf_iter_next_pg(pg_iter, pg)) == 1) {
2249 2164 int tmpl = 0;
2250 2165
2251 2166 if (scf_pg_get_name(pg, pg_name_buf, max_scf_name_length) < 0)
2252 2167 scfdie();
2253 2168 if (scf_snapshot_get_name(snap, snap_name,
2254 2169 max_scf_name_length) < 0)
2255 2170 scfdie();
2256 2171
2257 2172 if (scf_tmpl_get_by_pg_name(wip->fmri, snap_name, pg_name_buf,
2258 2173 SCF_PG_APP_DEFAULT, pt, 0) == 0)
2259 2174 tmpl = 1;
2260 2175 else
2261 2176 tmpl = 0;
2262 2177
2263 2178 (void) printf("%s (%s)\n", pg_name_buf, SCF_PG_APP_DEFAULT);
2264 2179
2265 2180 if (tmpl == 1 && scf_tmpl_pg_description(pt, NULL, &desc) > 0) {
2266 2181 (void) printf(" %s\n", desc);
2267 2182 free(desc);
2268 2183 }
2269 2184
2270 2185 if (scf_iter_pg_properties(prop_iter, pg) == -1)
2271 2186 scfdie();
2272 2187 while ((j = scf_iter_next_property(prop_iter, prop)) == 1) {
2273 2188 if (scf_property_get_name(prop, prop_name_buf,
2274 2189 max_scf_name_length) < 0)
2275 2190 scfdie();
2276 2191 if (scf_property_type(prop, &type) == -1)
2277 2192 scfdie();
2278 2193
2279 2194 if ((tmpl == 1) &&
2280 2195 (scf_tmpl_get_by_prop(pt, prop_name_buf, prt,
2281 2196 0) != 0))
2282 2197 tmpl = 0;
2283 2198
2284 2199 if (tmpl == 1 &&
2285 2200 scf_tmpl_prop_visibility(prt, &vis) != -1 &&
2286 2201 vis == SCF_TMPL_VISIBILITY_HIDDEN)
2287 2202 continue;
2288 2203
2289 2204 (void) printf("%s/%s (%s) = ", pg_name_buf,
2290 2205 prop_name_buf, scf_type_to_string(type));
2291 2206
2292 2207 if (scf_iter_property_values(val_iter, prop) == -1)
2293 2208 scfdie();
2294 2209
2295 2210 while ((k = scf_iter_next_value(val_iter, val)) == 1) {
2296 2211 if (scf_value_get_as_string(val, val_buf,
2297 2212 max_scf_value_length + 1) < 0)
2298 2213 scfdie();
2299 2214 if (strpbrk(val_buf, " \t\n\"()") != NULL) {
2300 2215 (void) printf("\"");
2301 2216 for (cp = val_buf; *cp != '\0'; ++cp) {
2302 2217 if (*cp == '"' || *cp == '\\')
2303 2218 (void) putc('\\',
2304 2219 stdout);
2305 2220
2306 2221 (void) putc(*cp, stdout);
2307 2222 }
2308 2223 (void) printf("\"");
2309 2224 } else {
2310 2225 (void) printf("%s ", val_buf);
2311 2226 }
2312 2227 }
2313 2228
2314 2229 (void) printf("\n");
2315 2230
2316 2231 if (k == -1)
2317 2232 scfdie();
2318 2233
2319 2234 if (tmpl == 1 && scf_tmpl_prop_description(prt, NULL,
2320 2235 &desc) > 0) {
2321 2236 (void) printf(" %s\n", desc);
2322 2237 free(desc);
2323 2238 }
2324 2239 }
2325 2240 if (j == -1)
2326 2241 scfdie();
2327 2242 }
2328 2243 if (i == -1)
2329 2244 scfdie();
2330 2245
2331 2246
2332 2247 scf_iter_destroy(pg_iter);
2333 2248 scf_iter_destroy(prop_iter);
2334 2249 scf_iter_destroy(val_iter);
2335 2250 scf_value_destroy(val);
2336 2251 scf_property_destroy(prop);
2337 2252 scf_tmpl_pg_destroy(pt);
2338 2253 scf_tmpl_prop_destroy(prt);
2339 2254 scf_pg_destroy(pg);
2340 2255 free(pg_name_buf);
2341 2256 free(prop_name_buf);
2342 2257 free(snap_name);
2343 2258 free(val_buf);
2344 2259 }
2345 2260
2346 2261 static void
2347 2262 print_detailed_dependency(scf_propertygroup_t *pg)
2348 2263 {
2349 2264 scf_property_t *eprop;
2350 2265 scf_iter_t *iter;
2351 2266 scf_type_t ty;
2352 2267 char *val_buf;
2353 2268 int i;
2354 2269
2355 2270 if ((eprop = scf_property_create(h)) == NULL ||
2356 2271 (iter = scf_iter_create(h)) == NULL)
2357 2272 scfdie();
2358 2273
2359 2274 val_buf = safe_malloc(max_scf_value_length + 1);
2360 2275
2361 2276 if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, eprop) !=
2362 2277 SCF_SUCCESS ||
2363 2278 scf_property_type(eprop, &ty) != SCF_SUCCESS ||
2364 2279 ty != SCF_TYPE_FMRI)
2365 2280 return;
2366 2281
2367 2282 (void) printf("%-*s", DETAILED_WIDTH, gettext("dependency"));
2368 2283
2369 2284 /* Print the grouping */
2370 2285 if (pg_get_single_val(pg, SCF_PROPERTY_GROUPING, SCF_TYPE_ASTRING,
2371 2286 val_buf, max_scf_value_length + 1, 0) == 0)
2372 2287 (void) fputs(val_buf, stdout);
2373 2288 else
2374 2289 (void) putchar('?');
2375 2290
2376 2291 (void) putchar('/');
2377 2292
2378 2293 if (pg_get_single_val(pg, SCF_PROPERTY_RESTART_ON, SCF_TYPE_ASTRING,
2379 2294 val_buf, max_scf_value_length + 1, 0) == 0)
2380 2295 (void) fputs(val_buf, stdout);
2381 2296 else
2382 2297 (void) putchar('?');
2383 2298
2384 2299 /* Print the dependency entities. */
2385 2300 if (scf_iter_property_values(iter, eprop) == -1)
2386 2301 scfdie();
2387 2302
2388 2303 while ((i = scf_iter_next_value(iter, g_val)) == 1) {
2389 2304 char state[MAX_SCF_STATE_STRING_SZ];
2390 2305
2391 2306 if (scf_value_get_astring(g_val, val_buf,
2392 2307 max_scf_value_length + 1) < 0)
2393 2308 scfdie();
2394 2309
2395 2310 (void) putchar(' ');
2396 2311 (void) fputs(val_buf, stdout);
2397 2312
2398 2313 /* Print the state. */
2399 2314 state[0] = '-';
2400 2315 state[1] = '\0';
2401 2316
2402 2317 get_fmri_state(val_buf, state, sizeof (state));
2403 2318
2404 2319 (void) printf(" (%s)", state);
2405 2320 }
2406 2321 if (i == -1)
2407 2322 scfdie();
2408 2323
2409 2324 (void) putchar('\n');
2410 2325
2411 2326 free(val_buf);
2412 2327 scf_iter_destroy(iter);
2413 2328 scf_property_destroy(eprop);
2414 2329 }
2415 2330
2416 2331 /* ARGSUSED */
2417 2332 static int
2418 2333 print_detailed(void *unused, scf_walkinfo_t *wip)
2419 2334 {
2420 2335 scf_snapshot_t *snap;
2421 2336 scf_propertygroup_t *rpg;
2422 2337 scf_iter_t *pg_iter;
2423 2338
2424 2339 char *buf;
2425 2340 char *timebuf;
2426 2341 size_t tbsz;
2427 2342 int ret;
2428 2343 uint64_t c;
2429 2344 int temp, perm;
2430 2345 struct timeval tv;
2431 2346 time_t stime;
2432 2347 struct tm *tmp;
2433 2348 int restarter_spec;
2434 2349 int restarter_ret;
2435 2350
2436 2351 const char * const fmt = "%-*s%s\n";
2437 2352
2438 2353 assert(wip->pg == NULL);
2439 2354
2440 2355 rpg = scf_pg_create(h);
2441 2356 if (rpg == NULL)
2442 2357 scfdie();
2443 2358
2444 2359 if (first_paragraph)
2445 2360 first_paragraph = 0;
2446 2361 else
2447 2362 (void) putchar('\n');
2448 2363
2449 2364 buf = safe_malloc(max_scf_fmri_length + 1);
2450 2365
2451 2366 if (scf_instance_to_fmri(wip->inst, buf, max_scf_fmri_length + 1) != -1)
2452 2367 (void) printf(fmt, DETAILED_WIDTH, "fmri", buf);
2453 2368
2454 2369 if (common_name_buf == NULL)
2455 2370 common_name_buf = safe_malloc(max_scf_value_length + 1);
2456 2371
2457 2372 if (inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, locale,
2458 2373 SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0, 1, 1)
2459 2374 == 0)
2460 2375 (void) printf(fmt, DETAILED_WIDTH, gettext("name"),
2461 2376 common_name_buf);
2462 2377 else if (inst_get_single_val(wip->inst, SCF_PG_TM_COMMON_NAME, "C",
2463 2378 SCF_TYPE_USTRING, common_name_buf, max_scf_value_length, 0, 1, 1)
2464 2379 == 0)
2465 2380 (void) printf(fmt, DETAILED_WIDTH, gettext("name"),
2466 2381 common_name_buf);
2467 2382
2468 2383 if (g_zonename != NULL)
2469 2384 (void) printf(fmt, DETAILED_WIDTH, gettext("zone"), g_zonename);
2470 2385
2471 2386 /*
2472 2387 * Synthesize an 'enabled' property that hides the enabled_ovr
2473 2388 * implementation from the user. If the service has been temporarily
2474 2389 * set to a state other than its permanent value, alert the user with
2475 2390 * a '(temporary)' message.
2476 2391 */
2477 2392 perm = instance_enabled(wip->inst, B_FALSE);
2478 2393 temp = instance_enabled(wip->inst, B_TRUE);
2479 2394 if (temp != -1) {
2480 2395 if (temp != perm)
2481 2396 (void) printf(gettext("%-*s%s (temporary)\n"),
2482 2397 DETAILED_WIDTH, gettext("enabled"),
2483 2398 temp ? gettext("true") : gettext("false"));
2484 2399 else
2485 2400 (void) printf(fmt, DETAILED_WIDTH,
2486 2401 gettext("enabled"), temp ? gettext("true") :
2487 2402 gettext("false"));
2488 2403 } else if (perm != -1) {
2489 2404 (void) printf(fmt, DETAILED_WIDTH, gettext("enabled"),
2490 2405 perm ? gettext("true") : gettext("false"));
2491 2406 }
2492 2407
2493 2408 /*
2494 2409 * Property values may be longer than max_scf_fmri_length, but these
2495 2410 * shouldn't be, so we'll just reuse buf. The user can use svcprop if
2496 2411 * they suspect something fishy.
2497 2412 */
2498 2413 if (scf_instance_get_pg(wip->inst, SCF_PG_RESTARTER, rpg) != 0) {
2499 2414 if (scf_error() != SCF_ERROR_NOT_FOUND)
2500 2415 scfdie();
2501 2416
2502 2417 scf_pg_destroy(rpg);
2503 2418 rpg = NULL;
2504 2419 }
2505 2420
2506 2421 if (rpg) {
2507 2422 if (pg_get_single_val(rpg, scf_property_state, SCF_TYPE_ASTRING,
2508 2423 buf, max_scf_fmri_length + 1, 0) == 0)
2509 2424 (void) printf(fmt, DETAILED_WIDTH, gettext("state"),
2510 2425 buf);
2511 2426
2512 2427 if (pg_get_single_val(rpg, scf_property_next_state,
2513 2428 SCF_TYPE_ASTRING, buf, max_scf_fmri_length + 1, 0) == 0)
2514 2429 (void) printf(fmt, DETAILED_WIDTH,
2515 2430 gettext("next_state"), buf);
2516 2431
2517 2432 if (pg_get_single_val(rpg, SCF_PROPERTY_STATE_TIMESTAMP,
2518 2433 SCF_TYPE_TIME, &tv, NULL, 0) == 0) {
2519 2434 stime = tv.tv_sec;
2520 2435 tmp = localtime(&stime);
2521 2436 for (tbsz = 50; ; tbsz *= 2) {
2522 2437 timebuf = safe_malloc(tbsz);
2523 2438 if (strftime(timebuf, tbsz, NULL, tmp) != 0)
2524 2439 break;
2525 2440 free(timebuf);
2526 2441 }
2527 2442 (void) printf(fmt, DETAILED_WIDTH,
2528 2443 gettext("state_time"),
2529 2444 timebuf);
2530 2445 free(timebuf);
2531 2446 }
2532 2447
2533 2448 if (pg_get_single_val(rpg, SCF_PROPERTY_ALT_LOGFILE,
2534 2449 SCF_TYPE_ASTRING, buf, max_scf_fmri_length + 1, 0) == 0)
2535 2450 (void) printf(fmt, DETAILED_WIDTH,
2536 2451 gettext("alt_logfile"), buf);
2537 2452
2538 2453 if (pg_get_single_val(rpg, SCF_PROPERTY_LOGFILE,
2539 2454 SCF_TYPE_ASTRING, buf, max_scf_fmri_length + 1, 0) == 0)
2540 2455 (void) printf(fmt, DETAILED_WIDTH, gettext("logfile"),
2541 2456 buf);
2542 2457 }
2543 2458
2544 2459 if (inst_get_single_val(wip->inst, SCF_PG_GENERAL,
2545 2460 SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING, buf,
2546 2461 max_scf_fmri_length + 1, 0, 0, 1) == 0)
2547 2462 (void) printf(fmt, DETAILED_WIDTH, gettext("restarter"), buf);
2548 2463 else
2549 2464 (void) printf(fmt, DETAILED_WIDTH, gettext("restarter"),
2550 2465 SCF_SERVICE_STARTD);
2551 2466
2552 2467 free(buf);
2553 2468
2554 2469 /*
2555 2470 * Use the restarter specific routine to print the ctids, if available.
2556 2471 * If restarter specific action is available and it fails, then die.
2557 2472 */
2558 2473 restarter_ret = ctids_by_restarter(wip, &c, 1, 0,
2559 2474 &restarter_spec, print_ctid_header, print_ctid_detailed);
2560 2475 if (restarter_spec == 1) {
2561 2476 if (restarter_ret != 0)
2562 2477 uu_die(gettext("Unable to get restarter for %s"),
2563 2478 wip->fmri);
2564 2479 goto restarter_common;
2565 2480 }
2566 2481
2567 2482 if (rpg) {
2568 2483 scf_iter_t *iter;
2569 2484
2570 2485 if ((iter = scf_iter_create(h)) == NULL)
2571 2486 scfdie();
2572 2487
2573 2488 if (scf_pg_get_property(rpg, scf_property_contract, g_prop) ==
2574 2489 0) {
2575 2490 if (scf_property_is_type(g_prop, SCF_TYPE_COUNT) == 0) {
2576 2491
2577 2492 /* Callback to print ctid header */
2578 2493 print_ctid_header();
2579 2494
2580 2495 if (scf_iter_property_values(iter, g_prop) != 0)
2581 2496 scfdie();
2582 2497
2583 2498 for (;;) {
2584 2499 ret = scf_iter_next_value(iter, g_val);
2585 2500 if (ret == -1)
2586 2501 scfdie();
2587 2502 if (ret == 0)
2588 2503 break;
2589 2504
2590 2505 if (scf_value_get_count(g_val, &c) != 0)
2591 2506 scfdie();
2592 2507
2593 2508 /* Callback to print contract id. */
2594 2509 print_ctid_detailed(c);
2595 2510 }
2596 2511
2597 2512 (void) putchar('\n');
2598 2513 } else {
2599 2514 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
2600 2515 scfdie();
2601 2516 }
2602 2517 } else {
2603 2518 if (scf_error() != SCF_ERROR_NOT_FOUND)
2604 2519 scfdie();
2605 2520 }
2606 2521
2607 2522 scf_iter_destroy(iter);
2608 2523 } else {
2609 2524 if (scf_error() != SCF_ERROR_NOT_FOUND)
2610 2525 scfdie();
2611 2526 }
2612 2527
2613 2528 restarter_common:
2614 2529 scf_pg_destroy(rpg);
2615 2530
2616 2531 /* Dependencies. */
2617 2532 if ((pg_iter = scf_iter_create(h)) == NULL)
2618 2533 scfdie();
2619 2534
2620 2535 snap = get_running_snapshot(wip->inst);
2621 2536
2622 2537 if (scf_iter_instance_pgs_typed_composed(pg_iter, wip->inst, snap,
2623 2538 SCF_GROUP_DEPENDENCY) != SCF_SUCCESS)
2624 2539 scfdie();
2625 2540
2626 2541 while ((ret = scf_iter_next_pg(pg_iter, g_pg)) == 1)
2627 2542 print_detailed_dependency(g_pg);
2628 2543 if (ret == -1)
2629 2544 scfdie();
2630 2545
2631 2546 scf_iter_destroy(pg_iter);
2632 2547
2633 2548 if (opt_processes)
2634 2549 detailed_list_processes(wip);
2635 2550
2636 2551 /* "application" type property groups */
2637 2552 if (opt_verbose == 1)
2638 2553 print_application_properties(wip, snap);
2639 2554
2640 2555 scf_snapshot_destroy(snap);
2641 2556
2642 2557 return (0);
2643 2558 }
2644 2559
2645 2560 /* ARGSUSED */
2646 2561 static int
2647 2562 print_log(void *unused, scf_walkinfo_t *wip)
2648 2563 {
2649 2564 scf_propertygroup_t *rpg;
2650 2565 char buf[MAXPATHLEN];
2651 2566
2652 2567 if ((rpg = scf_pg_create(h)) == NULL)
2653 2568 scfdie();
2654 2569
2655 2570 if (scf_instance_get_pg(wip->inst, SCF_PG_RESTARTER, rpg) != 0) {
2656 2571 if (scf_error() != SCF_ERROR_NOT_FOUND)
2657 2572 scfdie();
2658 2573
2659 2574 goto out;
2660 2575 }
2661 2576
2662 2577 if (pg_get_single_val(rpg, SCF_PROPERTY_LOGFILE,
2663 2578 SCF_TYPE_ASTRING, buf, sizeof (buf), 0) == 0) {
2664 2579 (void) printf("%s\n", buf);
2665 2580 }
2666 2581
2667 2582 out:
2668 2583 scf_pg_destroy(rpg);
2669 2584
2670 2585 return (0);
2671 2586 }
2672 2587
2673 2588 int
2674 2589 qsort_str_compare(const void *p1, const void *p2)
2675 2590 {
2676 2591 return (strcmp((const char *)p1, (const char *)p2));
2677 2592 }
2678 2593
2679 2594 /*
2680 2595 * get_notify_param_classes()
2681 2596 * return the fma classes that don't have a tag in fma_tags[], otherwise NULL
2682 2597 */
2683 2598 static char **
2684 2599 get_notify_param_classes()
2685 2600 {
2686 2601 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION);
2687 2602 scf_instance_t *inst = scf_instance_create(h);
2688 2603 scf_snapshot_t *snap = scf_snapshot_create(h);
2689 2604 scf_snaplevel_t *slvl = scf_snaplevel_create(h);
2690 2605 scf_propertygroup_t *pg = scf_pg_create(h);
2691 2606 scf_iter_t *iter = scf_iter_create(h);
2692 2607 int size = 4;
2693 2608 int n = 0;
2694 2609 size_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2695 2610 int err;
2696 2611 char *pgname = safe_malloc(sz);
2697 2612 char **buf = safe_malloc(size * sizeof (char *));
2698 2613
2699 2614 if (h == NULL || inst == NULL || snap == NULL || slvl == NULL ||
2700 2615 pg == NULL || iter == NULL) {
2701 2616 uu_die(gettext("Failed object creation: %s\n"),
2702 2617 scf_strerror(scf_error()));
2703 2618 }
2704 2619
2705 2620 if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, NULL, inst,
2706 2621 NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
2707 2622 uu_die(gettext("Failed to decode %s: %s\n"),
2708 2623 SCF_NOTIFY_PARAMS_INST, scf_strerror(scf_error()));
2709 2624
2710 2625 if (scf_instance_get_snapshot(inst, "running", snap) != 0)
2711 2626 uu_die(gettext("Failed to get snapshot: %s\n"),
2712 2627 scf_strerror(scf_error()));
2713 2628
2714 2629 if (scf_snapshot_get_base_snaplevel(snap, slvl) != 0)
2715 2630 uu_die(gettext("Failed to get base snaplevel: %s\n"),
2716 2631 scf_strerror(scf_error()));
2717 2632
2718 2633 if (scf_iter_snaplevel_pgs_typed(iter, slvl,
2719 2634 SCF_NOTIFY_PARAMS_PG_TYPE) != 0)
2720 2635 uu_die(gettext("Failed to get iterator: %s\n"),
2721 2636 scf_strerror(scf_error()));
2722 2637
2723 2638 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
2724 2639 char *c;
2725 2640
2726 2641 if (scf_pg_get_name(pg, pgname, sz) == -1)
2727 2642 uu_die(gettext("Failed to get pg name: %s\n"),
2728 2643 scf_strerror(scf_error()));
2729 2644 if ((c = strrchr(pgname, ',')) != NULL)
2730 2645 *c = '\0';
2731 2646 if (has_fma_tag(pgname))
2732 2647 continue;
2733 2648 if (!is_fma_token(pgname))
2734 2649 /*
2735 2650 * We don't emmit a warning here so that we don't
2736 2651 * pollute the output
2737 2652 */
2738 2653 continue;
2739 2654
2740 2655 if (n + 1 >= size) {
2741 2656 size *= 2;
2742 2657 buf = realloc(buf, size * sizeof (char *));
2743 2658 if (buf == NULL)
2744 2659 uu_die(gettext("Out of memory.\n"));
2745 2660 }
2746 2661 buf[n] = safe_strdup(pgname);
2747 2662 ++n;
2748 2663 }
2749 2664 /*
2750 2665 * NULL terminate buf
2751 2666 */
2752 2667 buf[n] = NULL;
2753 2668 if (err == -1)
2754 2669 uu_die(gettext("Failed to iterate pgs: %s\n"),
2755 2670 scf_strerror(scf_error()));
2756 2671
2757 2672 /* sort the classes */
2758 2673 qsort((void *)buf, n, sizeof (char *), qsort_str_compare);
2759 2674
2760 2675 free(pgname);
2761 2676 scf_iter_destroy(iter);
2762 2677 scf_pg_destroy(pg);
2763 2678 scf_snaplevel_destroy(slvl);
2764 2679 scf_snapshot_destroy(snap);
2765 2680 scf_instance_destroy(inst);
2766 2681 scf_handle_destroy(h);
2767 2682
2768 2683 return (buf);
2769 2684 }
2770 2685
2771 2686 /*
2772 2687 * get_fma_notify_params()
2773 2688 * populates an nvlist_t with notifycation parameters for a given FMA class
2774 2689 * returns 0 if the nvlist is populated, 1 otherwise;
2775 2690 */
2776 2691 int
2777 2692 get_fma_notify_params(nvlist_t *nvl, const char *class)
2778 2693 {
2779 2694 if (_scf_get_fma_notify_params(class, nvl, 0) != 0) {
2780 2695 /*
2781 2696 * if the preferences have just been deleted
2782 2697 * or does not exist, just skip.
2783 2698 */
2784 2699 if (scf_error() != SCF_ERROR_NOT_FOUND &&
2785 2700 scf_error() != SCF_ERROR_DELETED)
2786 2701 uu_warn(gettext(
2787 2702 "Failed get_fma_notify_params %s\n"),
2788 2703 scf_strerror(scf_error()));
2789 2704
2790 2705 return (1);
2791 2706 }
2792 2707
2793 2708 return (0);
2794 2709 }
2795 2710
2796 2711 /*
2797 2712 * print_notify_fma()
2798 2713 * outputs the notification paramets of FMA events.
2799 2714 * It first outputs classes in fma_tags[], then outputs the other classes
2800 2715 * sorted alphabetically
2801 2716 */
2802 2717 static void
2803 2718 print_notify_fma(void)
2804 2719 {
2805 2720 nvlist_t *nvl;
2806 2721 char **tmp = NULL;
2807 2722 char **classes, *p;
2808 2723 const char *class;
2809 2724 uint32_t i;
2810 2725
2811 2726 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
2812 2727 uu_die(gettext("Out of memory.\n"));
2813 2728
2814 2729 for (i = 0; (class = get_fma_class(i)) != NULL; ++i) {
2815 2730 if (get_fma_notify_params(nvl, class) == 0)
2816 2731 listnotify_print(nvl, get_fma_tag(i));
2817 2732 }
2818 2733
2819 2734 if ((classes = get_notify_param_classes()) == NULL)
2820 2735 goto cleanup;
2821 2736
2822 2737 tmp = classes;
2823 2738 for (p = *tmp; p; ++tmp, p = *tmp) {
2824 2739 if (get_fma_notify_params(nvl, p) == 0)
2825 2740 listnotify_print(nvl, re_tag(p));
2826 2741
2827 2742 free(p);
2828 2743 }
2829 2744
2830 2745 free(classes);
2831 2746
2832 2747 cleanup:
2833 2748 nvlist_free(nvl);
2834 2749 }
2835 2750
2836 2751 /*
2837 2752 * print_notify_fmri()
2838 2753 * prints notifycation parameters for an SMF instance.
2839 2754 */
2840 2755 static void
2841 2756 print_notify_fmri(const char *fmri)
2842 2757 {
2843 2758 nvlist_t *nvl;
2844 2759
2845 2760 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
2846 2761 uu_die(gettext("Out of memory.\n"));
2847 2762
2848 2763 if (_scf_get_svc_notify_params(fmri, nvl, SCF_TRANSITION_ALL, 0, 0) !=
2849 2764 SCF_SUCCESS) {
2850 2765 if (scf_error() != SCF_ERROR_NOT_FOUND &&
2851 2766 scf_error() != SCF_ERROR_DELETED)
2852 2767 uu_warn(gettext(
2853 2768 "Failed _scf_get_svc_notify_params: %s\n"),
2854 2769 scf_strerror(scf_error()));
2855 2770 } else {
2856 2771 if (strcmp(SCF_INSTANCE_GLOBAL, fmri) == 0)
2857 2772 safe_printf(
2858 2773 gettext("System wide notification parameters:\n"));
2859 2774 safe_printf("%s:\n", fmri);
2860 2775 listnotify_print(nvl, NULL);
2861 2776 }
2862 2777 nvlist_free(nvl);
2863 2778 }
2864 2779
2865 2780 /*
2866 2781 * print_notify_special()
2867 2782 * prints notification parameters for FMA events and system wide SMF state
2868 2783 * transitions parameters
2869 2784 */
2870 2785 static void
2871 2786 print_notify_special()
2872 2787 {
2873 2788 safe_printf("Notification parameters for FMA Events\n");
2874 2789 print_notify_fma();
2875 2790 print_notify_fmri(SCF_INSTANCE_GLOBAL);
2876 2791 }
2877 2792
2878 2793 /*
2879 2794 * print_notify()
2880 2795 * callback function to print notification parameters for SMF state transition
2881 2796 * instances. It skips global and notify-params instances as they should be
2882 2797 * printed by print_notify_special()
2883 2798 */
2884 2799 /* ARGSUSED */
2885 2800 static int
2886 2801 print_notify(void *unused, scf_walkinfo_t *wip)
2887 2802 {
2888 2803 if (strcmp(SCF_INSTANCE_GLOBAL, wip->fmri) == 0 ||
2889 2804 strcmp(SCF_NOTIFY_PARAMS_INST, wip->fmri) == 0)
2890 2805 return (0);
2891 2806
2892 2807 print_notify_fmri(wip->fmri);
2893 2808
2894 2809 return (0);
2895 2810 }
2896 2811
2897 2812 /*
2898 2813 * Append a one-lined description of each process in inst's contract(s) and
2899 2814 * return the augmented string.
2900 2815 */
2901 2816 static char *
2902 2817 add_processes(scf_walkinfo_t *wip, char *line, scf_propertygroup_t *lpg)
2903 2818 {
2904 2819 pid_t *pids = NULL;
2905 2820 uint_t i, n = 0;
2906 2821
2907 2822 if (lpg == NULL) {
2908 2823 if (instance_processes(wip->inst, wip->fmri, &pids, &n) != 0)
2909 2824 return (line);
2910 2825 } else {
2911 2826 /* Legacy services */
2912 2827 scf_iter_t *iter;
2913 2828
2914 2829 if ((iter = scf_iter_create(h)) == NULL)
2915 2830 scfdie();
2916 2831
2917 2832 (void) propvals_to_pids(lpg, scf_property_contract, &pids, &n,
2918 2833 g_prop, g_val, iter);
2919 2834
2920 2835 scf_iter_destroy(iter);
2921 2836 }
2922 2837
2923 2838 if (n == 0)
2924 2839 return (line);
2925 2840
2926 2841 qsort(pids, n, sizeof (*pids), pidcmp);
2927 2842
2928 2843 for (i = 0; i < n; ++i) {
2929 2844 char *cp, stime[9];
2930 2845 psinfo_t psi;
2931 2846 struct tm *tm;
2932 2847 int len = 1 + 15 + 8 + 3 + 6 + 1 + PRFNSZ;
2933 2848
2934 2849 if (get_psinfo(pids[i], &psi) != 0)
2935 2850 continue;
2936 2851
2937 2852 line = realloc(line, strlen(line) + len);
2938 2853 if (line == NULL)
2939 2854 uu_die(gettext("Out of memory.\n"));
2940 2855
2941 2856 cp = strchr(line, '\0');
2942 2857
2943 2858 tm = localtime(&psi.pr_start.tv_sec);
2944 2859
2945 2860 /*
2946 2861 * Print time if started within the past 24 hours, print date
2947 2862 * if within the past 12 months, print year if started greater
2948 2863 * than 12 months ago.
2949 2864 */
2950 2865 if (now - psi.pr_start.tv_sec < 24 * 60 * 60)
2951 2866 (void) strftime(stime, sizeof (stime),
2952 2867 gettext(FORMAT_TIME), tm);
2953 2868 else if (now - psi.pr_start.tv_sec < 12 * 30 * 24 * 60 * 60)
2954 2869 (void) strftime(stime, sizeof (stime),
2955 2870 gettext(FORMAT_DATE), tm);
2956 2871 else
2957 2872 (void) strftime(stime, sizeof (stime),
2958 2873 gettext(FORMAT_YEAR), tm);
2959 2874
2960 2875 (void) snprintf(cp, len, "\n %-8s %6ld %.*s",
2961 2876 stime, pids[i], PRFNSZ, psi.pr_fname);
2962 2877 }
2963 2878
2964 2879 free(pids);
2965 2880
2966 2881 return (line);
2967 2882 }
2968 2883
2969 2884 /*ARGSUSED*/
2970 2885 static int
2971 2886 list_instance(void *unused, scf_walkinfo_t *wip)
2972 2887 {
2973 2888 struct avl_string *lp;
2974 2889 char *cp;
2975 2890 int i;
2976 2891 uu_avl_index_t idx;
2977 2892
2978 2893 /*
2979 2894 * If the user has specified a restarter, check for a match first
2980 2895 */
2981 2896 if (restarters != NULL) {
2982 2897 struct pfmri_list *rest;
2983 2898 int match;
2984 2899 char *restarter_fmri;
2985 2900 const char *scope_name, *svc_name, *inst_name, *pg_name;
2986 2901
2987 2902 /* legacy services don't have restarters */
2988 2903 if (wip->pg != NULL)
2989 2904 return (0);
2990 2905
2991 2906 restarter_fmri = safe_malloc(max_scf_fmri_length + 1);
2992 2907
2993 2908 if (inst_get_single_val(wip->inst, SCF_PG_GENERAL,
2994 2909 SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING, restarter_fmri,
2995 2910 max_scf_fmri_length + 1, 0, 0, 1) != 0)
2996 2911 (void) strcpy(restarter_fmri, SCF_SERVICE_STARTD);
2997 2912
2998 2913 if (scf_parse_svc_fmri(restarter_fmri, &scope_name, &svc_name,
2999 2914 &inst_name, &pg_name, NULL) != SCF_SUCCESS) {
3000 2915 free(restarter_fmri);
3001 2916 return (0);
3002 2917 }
3003 2918
3004 2919 match = 0;
3005 2920 for (rest = restarters; rest != NULL; rest = rest->next) {
3006 2921 if (strcmp(rest->scope, scope_name) == 0 &&
3007 2922 strcmp(rest->service, svc_name) == 0 &&
3008 2923 strcmp(rest->instance, inst_name) == 0)
3009 2924 match = 1;
3010 2925 }
3011 2926
3012 2927 free(restarter_fmri);
3013 2928
3014 2929 if (!match)
3015 2930 return (0);
3016 2931 }
3017 2932
3018 2933 if (wip->pg == NULL && ht_buckets != NULL && ht_add(wip->fmri)) {
3019 2934 /* It was already there. */
3020 2935 return (0);
3021 2936 }
3022 2937
3023 2938 lp = safe_malloc(sizeof (*lp));
3024 2939
3025 2940 lp->str = NULL;
3026 2941 for (i = 0; i < opt_cnum; ++i) {
3027 2942 columns[opt_columns[i]].sprint(&lp->str, wip);
3028 2943 }
3029 2944 cp = lp->str + strlen(lp->str);
3030 2945 cp--;
3031 2946 while (*cp == ' ')
3032 2947 cp--;
3033 2948 *(cp+1) = '\0';
3034 2949
3035 2950 /* If we're supposed to list the processes, too, do that now. */
3036 2951 if (opt_processes)
3037 2952 lp->str = add_processes(wip, lp->str, wip->pg);
3038 2953
3039 2954 /* Create the sort key. */
3040 2955 cp = lp->key = safe_malloc(sortkey_sz);
3041 2956 for (i = 0; i < opt_snum; ++i) {
3042 2957 int j = opt_sort[i] & 0xff;
3043 2958
3044 2959 assert(columns[j].get_sortkey != NULL);
3045 2960 columns[j].get_sortkey(cp, opt_sort[i] & ~0xff, wip);
3046 2961 cp += columns[j].sortkey_width;
3047 2962 }
3048 2963
3049 2964 /* Insert into AVL tree. */
3050 2965 uu_avl_node_init(lp, &lp->node, lines_pool);
3051 2966 (void) uu_avl_find(lines, lp, NULL, &idx);
3052 2967 uu_avl_insert(lines, lp, idx);
3053 2968
3054 2969 return (0);
3055 2970 }
3056 2971
3057 2972 static int
3058 2973 list_if_enabled(void *unused, scf_walkinfo_t *wip)
3059 2974 {
3060 2975 if (wip->pg != NULL ||
3061 2976 instance_enabled(wip->inst, B_FALSE) == 1 ||
3062 2977 instance_enabled(wip->inst, B_TRUE) == 1)
3063 2978 return (list_instance(unused, wip));
3064 2979
3065 2980 return (0);
3066 2981 }
3067 2982
3068 2983 /*
3069 2984 * Service FMRI selection: Lookup and call list_instance() for the instances.
3070 2985 * Instance FMRI selection: Lookup and call list_instance().
3071 2986 *
3072 2987 * Note: This is shoehorned into a walk_dependencies() callback prototype so
3073 2988 * it can be used in list_dependencies.
3074 2989 */
3075 2990 static int
3076 2991 list_svc_or_inst_fmri(void *complain, scf_walkinfo_t *wip)
3077 2992 {
3078 2993 char *fmri;
3079 2994 const char *svc_name, *inst_name, *pg_name, *save;
3080 2995 scf_iter_t *iter;
3081 2996 int ret;
3082 2997
3083 2998 fmri = safe_strdup(wip->fmri);
3084 2999
3085 3000 if (scf_parse_svc_fmri(fmri, NULL, &svc_name, &inst_name, &pg_name,
3086 3001 NULL) != SCF_SUCCESS) {
3087 3002 if (complain)
3088 3003 uu_warn(gettext("FMRI \"%s\" is invalid.\n"),
3089 3004 wip->fmri);
3090 3005 exit_status = UU_EXIT_FATAL;
3091 3006 free(fmri);
3092 3007 return (0);
3093 3008 }
3094 3009
3095 3010 /*
3096 3011 * Yes, this invalidates *_name, but we only care whether they're NULL
3097 3012 * or not.
3098 3013 */
3099 3014 free(fmri);
3100 3015
3101 3016 if (svc_name == NULL || pg_name != NULL) {
3102 3017 if (complain)
3103 3018 uu_warn(gettext("FMRI \"%s\" does not designate a "
3104 3019 "service or instance.\n"), wip->fmri);
3105 3020 return (0);
3106 3021 }
3107 3022
3108 3023 if (inst_name != NULL) {
3109 3024 /* instance */
3110 3025 if (scf_handle_decode_fmri(h, wip->fmri, wip->scope, wip->svc,
3111 3026 wip->inst, NULL, NULL, 0) != SCF_SUCCESS) {
3112 3027 if (scf_error() != SCF_ERROR_NOT_FOUND)
3113 3028 scfdie();
3114 3029
3115 3030 if (complain)
3116 3031 uu_warn(gettext(
3117 3032 "Instance \"%s\" does not exist.\n"),
3118 3033 wip->fmri);
3119 3034 return (0);
3120 3035 }
3121 3036
3122 3037 return (list_instance(NULL, wip));
3123 3038 }
3124 3039
3125 3040 /* service: Walk the instances. */
3126 3041 if (scf_handle_decode_fmri(h, wip->fmri, wip->scope, wip->svc, NULL,
3127 3042 NULL, NULL, 0) != SCF_SUCCESS) {
3128 3043 if (scf_error() != SCF_ERROR_NOT_FOUND)
3129 3044 scfdie();
3130 3045
3131 3046 if (complain)
3132 3047 uu_warn(gettext("Service \"%s\" does not exist.\n"),
3133 3048 wip->fmri);
3134 3049
3135 3050 exit_status = UU_EXIT_FATAL;
3136 3051
3137 3052 return (0);
3138 3053 }
3139 3054
3140 3055 iter = scf_iter_create(h);
3141 3056 if (iter == NULL)
3142 3057 scfdie();
3143 3058
3144 3059 if (scf_iter_service_instances(iter, wip->svc) != SCF_SUCCESS)
3145 3060 scfdie();
3146 3061
3147 3062 if ((fmri = malloc(max_scf_fmri_length + 1)) == NULL) {
3148 3063 scf_iter_destroy(iter);
3149 3064 exit_status = UU_EXIT_FATAL;
3150 3065 return (0);
3151 3066 }
3152 3067
3153 3068 save = wip->fmri;
3154 3069 wip->fmri = fmri;
3155 3070 while ((ret = scf_iter_next_instance(iter, wip->inst)) == 1) {
3156 3071 if (scf_instance_to_fmri(wip->inst, fmri,
3157 3072 max_scf_fmri_length + 1) <= 0)
3158 3073 scfdie();
3159 3074 (void) list_instance(NULL, wip);
3160 3075 }
3161 3076 free(fmri);
3162 3077 wip->fmri = save;
3163 3078 if (ret == -1)
3164 3079 scfdie();
3165 3080
3166 3081 exit_status = UU_EXIT_OK;
3167 3082
3168 3083 scf_iter_destroy(iter);
3169 3084
3170 3085 return (0);
3171 3086 }
3172 3087
3173 3088 /*
3174 3089 * Dependency selection: Straightforward since each instance lists the
3175 3090 * services it depends on.
3176 3091 */
3177 3092
3178 3093 static void
3179 3094 walk_dependencies(scf_walkinfo_t *wip, scf_walk_callback callback, void *data)
3180 3095 {
3181 3096 scf_snapshot_t *snap;
3182 3097 scf_iter_t *iter, *viter;
3183 3098 int ret, vret;
3184 3099 char *dep;
3185 3100
3186 3101 assert(wip->inst != NULL);
3187 3102
3188 3103 if ((iter = scf_iter_create(h)) == NULL ||
3189 3104 (viter = scf_iter_create(h)) == NULL)
3190 3105 scfdie();
3191 3106
3192 3107 snap = get_running_snapshot(wip->inst);
3193 3108
3194 3109 if (scf_iter_instance_pgs_typed_composed(iter, wip->inst, snap,
3195 3110 SCF_GROUP_DEPENDENCY) != SCF_SUCCESS)
3196 3111 scfdie();
3197 3112
3198 3113 dep = safe_malloc(max_scf_value_length + 1);
3199 3114
3200 3115 while ((ret = scf_iter_next_pg(iter, g_pg)) == 1) {
3201 3116 scf_type_t ty;
3202 3117
3203 3118 /* Ignore exclude_any dependencies. */
3204 3119 if (scf_pg_get_property(g_pg, SCF_PROPERTY_GROUPING, g_prop) !=
3205 3120 SCF_SUCCESS) {
3206 3121 if (scf_error() != SCF_ERROR_NOT_FOUND)
3207 3122 scfdie();
3208 3123
3209 3124 continue;
3210 3125 }
3211 3126
3212 3127 if (scf_property_type(g_prop, &ty) != SCF_SUCCESS)
3213 3128 scfdie();
3214 3129
3215 3130 if (ty != SCF_TYPE_ASTRING)
3216 3131 continue;
3217 3132
3218 3133 if (scf_property_get_value(g_prop, g_val) != SCF_SUCCESS) {
3219 3134 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
3220 3135 scfdie();
3221 3136
3222 3137 continue;
3223 3138 }
3224 3139
3225 3140 if (scf_value_get_astring(g_val, dep,
3226 3141 max_scf_value_length + 1) < 0)
3227 3142 scfdie();
3228 3143
3229 3144 if (strcmp(dep, SCF_DEP_EXCLUDE_ALL) == 0)
3230 3145 continue;
3231 3146
3232 3147 if (scf_pg_get_property(g_pg, SCF_PROPERTY_ENTITIES, g_prop) !=
3233 3148 SCF_SUCCESS) {
3234 3149 if (scf_error() != SCF_ERROR_NOT_FOUND)
3235 3150 scfdie();
3236 3151
3237 3152 continue;
3238 3153 }
3239 3154
3240 3155 if (scf_iter_property_values(viter, g_prop) != SCF_SUCCESS)
3241 3156 scfdie();
3242 3157
3243 3158 while ((vret = scf_iter_next_value(viter, g_val)) == 1) {
3244 3159 if (scf_value_get_astring(g_val, dep,
3245 3160 max_scf_value_length + 1) < 0)
3246 3161 scfdie();
3247 3162
3248 3163 wip->fmri = dep;
3249 3164 if (callback(data, wip) != 0)
3250 3165 goto out;
3251 3166 }
3252 3167 if (vret == -1)
3253 3168 scfdie();
3254 3169 }
3255 3170 if (ret == -1)
3256 3171 scfdie();
3257 3172
3258 3173 out:
3259 3174 scf_iter_destroy(viter);
3260 3175 scf_iter_destroy(iter);
3261 3176 scf_snapshot_destroy(snap);
3262 3177 }
3263 3178
3264 3179 static int
3265 3180 list_dependencies(void *data, scf_walkinfo_t *wip)
3266 3181 {
3267 3182 walk_dependencies(wip, list_svc_or_inst_fmri, data);
3268 3183 return (0);
3269 3184 }
3270 3185
3271 3186
3272 3187 /*
3273 3188 * Dependent selection: The "providing" service's or instance's FMRI is parsed
3274 3189 * into the provider_* variables, the instances are walked, and any instance
3275 3190 * which lists an FMRI which parses to these components is selected. This is
3276 3191 * inefficient in the face of multiple operands, but that should be uncommon.
3277 3192 */
3278 3193
3279 3194 static char *provider_scope;
3280 3195 static char *provider_svc;
3281 3196 static char *provider_inst; /* NULL for services */
3282 3197
3283 3198 /*ARGSUSED*/
3284 3199 static int
3285 3200 check_against_provider(void *arg, scf_walkinfo_t *wip)
3286 3201 {
3287 3202 char *cfmri;
3288 3203 const char *scope_name, *svc_name, *inst_name, *pg_name;
3289 3204 int *matchp = arg;
3290 3205
3291 3206 cfmri = safe_strdup(wip->fmri);
3292 3207
3293 3208 if (scf_parse_svc_fmri(cfmri, &scope_name, &svc_name, &inst_name,
3294 3209 &pg_name, NULL) != SCF_SUCCESS) {
3295 3210 free(cfmri);
3296 3211 return (0);
3297 3212 }
3298 3213
3299 3214 if (svc_name == NULL || pg_name != NULL) {
3300 3215 free(cfmri);
3301 3216 return (0);
3302 3217 }
3303 3218
3304 3219 /*
3305 3220 * If the user has specified an instance, then also match dependencies
3306 3221 * on the service itself.
3307 3222 */
3308 3223 *matchp = (strcmp(provider_scope, scope_name) == 0 &&
3309 3224 strcmp(provider_svc, svc_name) == 0 &&
3310 3225 (provider_inst == NULL ? (inst_name == NULL) :
3311 3226 (inst_name == NULL || strcmp(provider_inst, inst_name) == 0)));
3312 3227
3313 3228 free(cfmri);
3314 3229
3315 3230 /* Stop on matches. */
3316 3231 return (*matchp);
3317 3232 }
3318 3233
3319 3234 static int
3320 3235 list_if_dependent(void *unused, scf_walkinfo_t *wip)
3321 3236 {
3322 3237 /* Only proceed if this instance depends on provider_*. */
3323 3238 int match = 0;
3324 3239
3325 3240 (void) walk_dependencies(wip, check_against_provider, &match);
3326 3241
3327 3242 if (match)
3328 3243 return (list_instance(unused, wip));
3329 3244
3330 3245 return (0);
3331 3246 }
3332 3247
3333 3248 /*ARGSUSED*/
3334 3249 static int
3335 3250 list_dependents(void *unused, scf_walkinfo_t *wip)
3336 3251 {
3337 3252 char *save;
3338 3253 int ret;
3339 3254
3340 3255 if (scf_scope_get_name(wip->scope, provider_scope,
3341 3256 max_scf_fmri_length) <= 0 ||
3342 3257 scf_service_get_name(wip->svc, provider_svc,
3343 3258 max_scf_fmri_length) <= 0)
3344 3259 scfdie();
3345 3260
3346 3261 save = provider_inst;
3347 3262 if (wip->inst == NULL)
3348 3263 provider_inst = NULL;
3349 3264 else if (scf_instance_get_name(wip->inst, provider_inst,
3350 3265 max_scf_fmri_length) <= 0)
3351 3266 scfdie();
3352 3267
3353 3268 ret = scf_walk_fmri(h, 0, NULL, 0, list_if_dependent, NULL, NULL,
3354 3269 uu_warn);
3355 3270
3356 3271 provider_inst = save;
3357 3272
3358 3273 return (ret);
3359 3274 }
3360 3275
3361 3276 /*
3362 3277 * main() & helpers
3363 3278 */
3364 3279
3365 3280 static void
3366 3281 add_sort_column(const char *col, int reverse)
3367 3282 {
3368 3283 int i;
3369 3284
3370 3285 ++opt_snum;
3371 3286
3372 3287 opt_sort = realloc(opt_sort, opt_snum * sizeof (*opt_sort));
3373 3288 if (opt_sort == NULL)
3374 3289 uu_die(gettext("Too many sort criteria: out of memory.\n"));
3375 3290
3376 3291 for (i = 0; i < ncolumns; ++i) {
3377 3292 if (strcasecmp(col, columns[i].name) == 0)
3378 3293 break;
3379 3294 }
3380 3295
3381 3296 if (i < ncolumns)
3382 3297 opt_sort[opt_snum - 1] = (reverse ? i | 0x100 : i);
3383 3298 else
3384 3299 uu_die(gettext("Unrecognized sort column \"%s\".\n"), col);
3385 3300
3386 3301 sortkey_sz += columns[i].sortkey_width;
3387 3302 }
3388 3303
3389 3304 static void
3390 3305 add_restarter(const char *fmri)
3391 3306 {
3392 3307 char *cfmri;
3393 3308 const char *pg_name;
3394 3309 struct pfmri_list *rest;
3395 3310
3396 3311 cfmri = safe_strdup(fmri);
3397 3312 rest = safe_malloc(sizeof (*rest));
3398 3313
3399 3314 if (scf_parse_svc_fmri(cfmri, &rest->scope, &rest->service,
3400 3315 &rest->instance, &pg_name, NULL) != SCF_SUCCESS)
3401 3316 uu_die(gettext("Restarter FMRI \"%s\" is invalid.\n"), fmri);
3402 3317
3403 3318 if (rest->instance == NULL || pg_name != NULL)
3404 3319 uu_die(gettext("Restarter FMRI \"%s\" does not designate an "
3405 3320 "instance.\n"), fmri);
3406 3321
3407 3322 rest->next = restarters;
3408 3323 restarters = rest;
3409 3324 return;
3410 3325
3411 3326 err:
3412 3327 free(cfmri);
3413 3328 free(rest);
3414 3329 }
3415 3330
3416 3331 /* ARGSUSED */
3417 3332 static int
3418 3333 line_cmp(const void *l_arg, const void *r_arg, void *private)
3419 3334 {
3420 3335 const struct avl_string *l = l_arg;
3421 3336 const struct avl_string *r = r_arg;
3422 3337
3423 3338 return (memcmp(l->key, r->key, sortkey_sz));
3424 3339 }
3425 3340
3426 3341 /* ARGSUSED */
3427 3342 static int
3428 3343 print_line(void *e, void *private)
3429 3344 {
3430 3345 struct avl_string *lp = e;
3431 3346
3432 3347 (void) puts(lp->str);
3433 3348
3434 3349 return (UU_WALK_NEXT);
3435 3350 }
3436 3351
3437 3352 /* ARGSUSED */
3438 3353 static void
3439 3354 errignore(const char *str, ...)
3440 3355 {}
3441 3356
3442 3357 int
3443 3358 main(int argc, char **argv)
3444 3359 {
3445 3360 char opt, opt_mode;
3446 3361 int i, n;
|
↓ open down ↓ |
1557 lines elided |
↑ open up ↑ |
3447 3362 char *columns_str = NULL;
3448 3363 char *cp;
3449 3364 const char *progname;
3450 3365 int err, missing = 1, ignored, *errarg;
3451 3366 uint_t nzents = 0, zent = 0;
3452 3367 zoneid_t *zids = NULL;
3453 3368 char zonename[ZONENAME_MAX];
3454 3369 void (*errfunc)(const char *, ...);
3455 3370
3456 3371 int show_all = 0;
3457 - int show_header = 1;
3458 3372 int show_zones = 0;
3459 3373
3460 3374 const char * const options = "aHpvno:R:s:S:dDlL?xZz:";
3461 3375
3462 3376 (void) setlocale(LC_ALL, "");
3463 3377
3464 3378 locale = setlocale(LC_MESSAGES, NULL);
3465 3379 if (locale) {
3466 3380 locale = safe_strdup(locale);
3467 3381 _scf_sanitize_locale(locale);
3468 3382 }
3469 3383
3470 3384 (void) textdomain(TEXT_DOMAIN);
3471 3385 progname = uu_setpname(argv[0]);
3472 3386
3473 3387 exit_status = UU_EXIT_OK;
3474 3388
3475 3389 max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
3476 3390 max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3477 3391 max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
3478 3392 max_scf_type_length = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH);
3479 3393
3480 3394 if (max_scf_name_length == -1 || max_scf_value_length == -1 ||
3481 3395 max_scf_fmri_length == -1 || max_scf_type_length == -1)
3482 3396 scfdie();
3483 3397
3484 3398 now = time(NULL);
3485 3399 assert(now != -1);
3486 3400
3487 3401 /*
3488 3402 * opt_mode is the mode of operation. 0 for plain, 'd' for
3489 3403 * dependencies, 'D' for dependents, and 'l' for detailed (long). We
3490 3404 * need to know now so we know which options are valid.
3491 3405 */
3492 3406 opt_mode = 0;
3493 3407 while ((opt = getopt(argc, argv, options)) != -1) {
3494 3408 switch (opt) {
3495 3409 case '?':
3496 3410 if (optopt == '?') {
3497 3411 print_help(progname);
3498 3412 return (UU_EXIT_OK);
3499 3413 } else {
3500 3414 argserr(progname);
3501 3415 /* NOTREACHED */
3502 3416 }
3503 3417
3504 3418 case 'd':
3505 3419 case 'D':
3506 3420 case 'l':
3507 3421 case 'L':
3508 3422 if (opt_mode != 0)
3509 3423 argserr(progname);
3510 3424
3511 3425 opt_mode = opt;
3512 3426 break;
3513 3427
3514 3428 case 'n':
3515 3429 if (opt_mode != 0)
3516 3430 argserr(progname);
3517 3431
3518 3432 opt_mode = opt;
3519 3433 break;
3520 3434
3521 3435 case 'x':
3522 3436 if (opt_mode != 0)
3523 3437 argserr(progname);
3524 3438
3525 3439 opt_mode = opt;
3526 3440 break;
3527 3441
3528 3442 default:
3529 3443 break;
3530 3444 }
3531 3445 }
3532 3446
3533 3447 sortkey_sz = 0;
3534 3448
3535 3449 optind = 1; /* Reset getopt() */
3536 3450 while ((opt = getopt(argc, argv, options)) != -1) {
|
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
3537 3451 switch (opt) {
3538 3452 case 'a':
3539 3453 if (opt_mode != 0)
3540 3454 argserr(progname);
3541 3455 show_all = 1;
3542 3456 break;
3543 3457
3544 3458 case 'H':
3545 3459 if (opt_mode == 'l' || opt_mode == 'x')
3546 3460 argserr(progname);
3547 - show_header = 0;
3461 + opt_scripted = 1;
3548 3462 break;
3549 3463
3550 3464 case 'p':
3551 3465 if (opt_mode == 'x')
3552 3466 argserr(progname);
3553 3467 opt_processes = 1;
3554 3468 break;
3555 3469
3556 3470 case 'v':
3557 3471 opt_verbose = 1;
3558 3472 break;
3559 3473
3560 3474 case 'o':
3561 3475 if (opt_mode == 'l' || opt_mode == 'x')
3562 3476 argserr(progname);
3563 3477 columns_str = optarg;
3564 3478 break;
3565 3479
3566 3480 case 'R':
3567 3481 if (opt_mode != 0 || opt_mode == 'x')
3568 3482 argserr(progname);
3569 3483
3570 3484 add_restarter(optarg);
3571 3485 break;
3572 3486
3573 3487 case 's':
3574 3488 case 'S':
3575 3489 if (opt_mode != 0)
3576 3490 argserr(progname);
3577 3491
3578 3492 add_sort_column(optarg, optopt == 'S');
3579 3493 break;
3580 3494
3581 3495 case 'd':
3582 3496 case 'D':
3583 3497 case 'l':
3584 3498 case 'L':
3585 3499 case 'n':
3586 3500 case 'x':
3587 3501 assert(opt_mode == optopt);
3588 3502 break;
3589 3503
3590 3504 case 'z':
3591 3505 if (getzoneid() != GLOBAL_ZONEID)
3592 3506 uu_die(gettext("svcs -z may only be used from "
3593 3507 "the global zone\n"));
3594 3508 if (show_zones)
3595 3509 argserr(progname);
3596 3510
3597 3511 opt_zone = optarg;
3598 3512 break;
3599 3513
3600 3514 case 'Z':
3601 3515 if (getzoneid() != GLOBAL_ZONEID)
3602 3516 uu_die(gettext("svcs -Z may only be used from "
3603 3517 "the global zone\n"));
3604 3518 if (opt_zone != NULL)
3605 3519 argserr(progname);
3606 3520
3607 3521 show_zones = 1;
3608 3522 break;
3609 3523
3610 3524 case '?':
3611 3525 argserr(progname);
3612 3526 /* NOTREACHED */
3613 3527
3614 3528 default:
3615 3529 assert(0);
3616 3530 abort();
3617 3531 }
3618 3532 }
3619 3533
3620 3534 /*
3621 3535 * -a is only meaningful when given no arguments
3622 3536 */
3623 3537 if (show_all && optind != argc)
3624 3538 uu_warn(gettext("-a ignored when used with arguments.\n"));
3625 3539
3626 3540 while (show_zones) {
3627 3541 uint_t found;
3628 3542
3629 3543 if (zone_list(NULL, &nzents) != 0)
3630 3544 uu_die(gettext("could not get number of zones"));
3631 3545
3632 3546 if ((zids = malloc(nzents * sizeof (zoneid_t))) == NULL) {
3633 3547 uu_die(gettext("could not allocate array for "
3634 3548 "%d zone IDs"), nzents);
3635 3549 }
3636 3550
3637 3551 found = nzents;
3638 3552
3639 3553 if (zone_list(zids, &found) != 0)
3640 3554 uu_die(gettext("could not get zone list"));
3641 3555
3642 3556 /*
3643 3557 * If the number of zones has not changed between our calls to
3644 3558 * zone_list(), we're done -- otherwise, we must free our array
3645 3559 * of zone IDs and take another lap.
3646 3560 */
3647 3561 if (found == nzents)
3648 3562 break;
3649 3563
3650 3564 free(zids);
3651 3565 }
3652 3566
3653 3567 argc -= optind;
3654 3568 argv += optind;
3655 3569
3656 3570 again:
3657 3571 h = scf_handle_create(SCF_VERSION);
3658 3572 if (h == NULL)
3659 3573 scfdie();
3660 3574
3661 3575 if (opt_zone != NULL || zids != NULL) {
3662 3576 scf_value_t *zone;
3663 3577
3664 3578 assert(opt_zone == NULL || zids == NULL);
3665 3579
3666 3580 if (opt_zone == NULL) {
3667 3581 if (getzonenamebyid(zids[zent++],
3668 3582 zonename, sizeof (zonename)) < 0) {
3669 3583 uu_warn(gettext("could not get name for "
3670 3584 "zone %d; ignoring"), zids[zent - 1]);
3671 3585 goto nextzone;
3672 3586 }
3673 3587
3674 3588 g_zonename = zonename;
3675 3589 } else {
3676 3590 g_zonename = opt_zone;
3677 3591 }
3678 3592
3679 3593 if ((zone = scf_value_create(h)) == NULL)
3680 3594 scfdie();
3681 3595
3682 3596 if (scf_value_set_astring(zone, g_zonename) != SCF_SUCCESS)
3683 3597 scfdie();
3684 3598
3685 3599 if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS)
3686 3600 uu_die(gettext("invalid zone '%s'\n"), g_zonename);
3687 3601
3688 3602 scf_value_destroy(zone);
3689 3603 }
3690 3604
3691 3605 if (scf_handle_bind(h) == -1) {
3692 3606 if (g_zonename != NULL) {
3693 3607 uu_warn(gettext("Could not bind to repository "
3694 3608 "server for zone %s: %s\n"), g_zonename,
3695 3609 scf_strerror(scf_error()));
3696 3610
3697 3611 if (!show_zones)
3698 3612 return (UU_EXIT_FATAL);
3699 3613
3700 3614 goto nextzone;
3701 3615 }
3702 3616
3703 3617 uu_die(gettext("Could not bind to repository server: %s. "
3704 3618 "Exiting.\n"), scf_strerror(scf_error()));
3705 3619 }
3706 3620
3707 3621 if ((g_pg = scf_pg_create(h)) == NULL ||
3708 3622 (g_prop = scf_property_create(h)) == NULL ||
3709 3623 (g_val = scf_value_create(h)) == NULL)
3710 3624 scfdie();
3711 3625
3712 3626 if (show_zones) {
3713 3627 /*
3714 3628 * It's hard to avoid editorializing here, but suffice it to
3715 3629 * say that scf_walk_fmri() takes an error handler, the
3716 3630 * interface to which has been regrettably misdesigned: the
3717 3631 * handler itself takes exclusively a string -- even though
3718 3632 * scf_walk_fmri() has detailed, programmatic knowledge
3719 3633 * of the error condition at the time it calls its errfunc.
3720 3634 * That is, only the error message and not the error semantics
3721 3635 * are given to the handler. This is poor interface at best,
3722 3636 * but it is particularly problematic when we are talking to
3723 3637 * multiple repository servers (as when we are iterating over
3724 3638 * all zones) as we do not want to treat failure to find a
3725 3639 * match in one zone as overall failure. Ideally, we would
3726 3640 * simply ignore SCF_MSG_PATTERN_NOINSTANCE and correctly
3727 3641 * process the others, but alas, no such interface exists --
3728 3642 * and we must settle for instead ignoring all errfunc-called
3729 3643 * errors in the case that we are iterating over all zones...
3730 3644 */
3731 3645 errfunc = errignore;
3732 3646 errarg = missing ? &missing : &ignored;
3733 3647 missing = 0;
3734 3648 } else {
3735 3649 errfunc = uu_warn;
3736 3650 errarg = &exit_status;
3737 3651 }
3738 3652
3739 3653 /*
3740 3654 * If we're in long mode, take care of it now before we deal with the
3741 3655 * sorting and the columns, since we won't use them anyway.
3742 3656 */
3743 3657 if (opt_mode == 'l') {
3744 3658 if (argc == 0)
3745 3659 argserr(progname);
3746 3660
3747 3661 if ((err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
3748 3662 print_detailed, NULL, errarg, errfunc)) != 0) {
3749 3663 uu_warn(gettext("failed to iterate over "
3750 3664 "instances: %s\n"), scf_strerror(err));
3751 3665 exit_status = UU_EXIT_FATAL;
3752 3666 }
3753 3667
3754 3668 goto nextzone;
3755 3669 }
3756 3670
3757 3671 if (opt_mode == 'L') {
3758 3672 if ((err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
3759 3673 print_log, NULL, &exit_status, uu_warn)) != 0) {
3760 3674 uu_warn(gettext("failed to iterate over "
3761 3675 "instances: %s\n"), scf_strerror(err));
3762 3676 exit_status = UU_EXIT_FATAL;
3763 3677 }
3764 3678
3765 3679 goto nextzone;
3766 3680 }
3767 3681
3768 3682 if (opt_mode == 'n') {
3769 3683 print_notify_special();
3770 3684 if ((err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
3771 3685 print_notify, NULL, errarg, errfunc)) != 0) {
3772 3686 uu_warn(gettext("failed to iterate over "
3773 3687 "instances: %s\n"), scf_strerror(err));
3774 3688 exit_status = UU_EXIT_FATAL;
3775 3689 }
3776 3690
3777 3691 goto nextzone;
3778 3692 }
3779 3693
3780 3694 if (opt_mode == 'x') {
3781 3695 explain(opt_verbose, argc, argv);
3782 3696 goto nextzone;
3783 3697 }
3784 3698
3785 3699 if (columns_str == NULL) {
3786 3700 if (opt_snum == 0) {
3787 3701 if (show_zones)
3788 3702 add_sort_column("zone", 0);
3789 3703
3790 3704 /* Default sort. */
3791 3705 add_sort_column("state", 0);
3792 3706 add_sort_column("stime", 0);
3793 3707 add_sort_column("fmri", 0);
3794 3708 }
3795 3709
3796 3710 if (!opt_verbose) {
3797 3711 columns_str = safe_strdup(show_zones ?
3798 3712 "zone,state,stime,fmri" : "state,stime,fmri");
3799 3713 } else {
3800 3714 columns_str = safe_strdup(show_zones ?
3801 3715 "zone,state,nstate,stime,ctid,fmri" :
3802 3716 "state,nstate,stime,ctid,fmri");
3803 3717 }
3804 3718 }
3805 3719
3806 3720 if (opt_columns == NULL) {
3807 3721 /* Decode columns_str into opt_columns. */
3808 3722 line_sz = 0;
3809 3723
3810 3724 opt_cnum = 1;
3811 3725 for (cp = columns_str; *cp != '\0'; ++cp)
3812 3726 if (*cp == ',')
3813 3727 ++opt_cnum;
3814 3728
3815 3729 if (*columns_str == '\0')
3816 3730 uu_die(gettext("No columns specified.\n"));
3817 3731
3818 3732 opt_columns = malloc(opt_cnum * sizeof (*opt_columns));
3819 3733 if (opt_columns == NULL)
3820 3734 uu_die(gettext("Too many columns.\n"));
3821 3735
3822 3736 for (n = 0; *columns_str != '\0'; ++n) {
3823 3737 i = getcolumnopt(&columns_str);
3824 3738 if (i == -1)
3825 3739 uu_die(gettext("Unknown column \"%s\".\n"),
3826 3740 columns_str);
3827 3741
3828 3742 if (strcmp(columns[i].name, "N") == 0 ||
3829 3743 strcmp(columns[i].name, "SN") == 0 ||
3830 3744 strcmp(columns[i].name, "NSTA") == 0 ||
3831 3745 strcmp(columns[i].name, "NSTATE") == 0)
3832 3746 opt_nstate_shown = 1;
3833 3747
3834 3748 opt_columns[n] = i;
3835 3749 line_sz += columns[i].width + 1;
3836 3750 }
3837 3751
3838 3752 if ((lines_pool = uu_avl_pool_create("lines_pool",
3839 3753 sizeof (struct avl_string), offsetof(struct avl_string,
3840 3754 node), line_cmp, UU_AVL_DEBUG)) == NULL ||
3841 3755 (lines = uu_avl_create(lines_pool, NULL, 0)) == NULL)
3842 3756 uu_die(gettext("Unexpected libuutil error: %s\n"),
3843 3757 uu_strerror(uu_error()));
3844 3758 }
3845 3759
3846 3760 switch (opt_mode) {
3847 3761 case 0:
3848 3762 /*
3849 3763 * If we already have a hash table (e.g., because we are
3850 3764 * processing multiple zones), destroy it before creating
3851 3765 * a new one.
3852 3766 */
3853 3767 if (ht_buckets != NULL)
3854 3768 ht_free();
3855 3769
3856 3770 ht_init();
3857 3771
3858 3772 /* Always show all FMRIs when given arguments or restarters */
3859 3773 if (argc != 0 || restarters != NULL)
3860 3774 show_all = 1;
3861 3775
3862 3776 if ((err = scf_walk_fmri(h, argc, argv,
3863 3777 SCF_WALK_MULTIPLE | SCF_WALK_LEGACY,
3864 3778 show_all ? list_instance : list_if_enabled, NULL,
3865 3779 errarg, errfunc)) != 0) {
3866 3780 uu_warn(gettext("failed to iterate over "
3867 3781 "instances: %s\n"), scf_strerror(err));
3868 3782 exit_status = UU_EXIT_FATAL;
3869 3783 }
3870 3784 break;
3871 3785
3872 3786 case 'd':
3873 3787 if (argc == 0)
3874 3788 argserr(progname);
3875 3789
3876 3790 if ((err = scf_walk_fmri(h, argc, argv,
3877 3791 SCF_WALK_MULTIPLE, list_dependencies, NULL,
3878 3792 errarg, errfunc)) != 0) {
3879 3793 uu_warn(gettext("failed to iterate over "
3880 3794 "instances: %s\n"), scf_strerror(err));
3881 3795 exit_status = UU_EXIT_FATAL;
3882 3796 }
3883 3797 break;
3884 3798
3885 3799 case 'D':
3886 3800 if (argc == 0)
3887 3801 argserr(progname);
3888 3802
3889 3803 provider_scope = safe_malloc(max_scf_fmri_length);
3890 3804 provider_svc = safe_malloc(max_scf_fmri_length);
3891 3805 provider_inst = safe_malloc(max_scf_fmri_length);
3892 3806
3893 3807 if ((err = scf_walk_fmri(h, argc, argv,
3894 3808 SCF_WALK_MULTIPLE | SCF_WALK_SERVICE,
3895 3809 list_dependents, NULL, &exit_status, uu_warn)) != 0) {
3896 3810 uu_warn(gettext("failed to iterate over "
3897 3811 "instances: %s\n"), scf_strerror(err));
3898 3812 exit_status = UU_EXIT_FATAL;
3899 3813 }
3900 3814
3901 3815 free(provider_scope);
3902 3816 free(provider_svc);
3903 3817 free(provider_inst);
3904 3818 break;
3905 3819
3906 3820 case 'n':
3907 3821 break;
3908 3822
3909 3823 default:
3910 3824 assert(0);
3911 3825 abort();
3912 3826 }
3913 3827
3914 3828 nextzone:
3915 3829 if (show_zones && zent < nzents && exit_status == 0) {
|
↓ open down ↓ |
358 lines elided |
↑ open up ↑ |
3916 3830 scf_handle_destroy(h);
3917 3831 goto again;
3918 3832 }
3919 3833
3920 3834 if (show_zones && exit_status == 0)
3921 3835 exit_status = missing;
3922 3836
3923 3837 if (opt_columns == NULL)
3924 3838 return (exit_status);
3925 3839
3926 - if (show_header)
3840 + if (!opt_scripted)
3927 3841 print_header();
3928 3842
3929 3843 (void) uu_avl_walk(lines, print_line, NULL, 0);
3930 3844
3931 3845 return (exit_status);
3932 3846 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX