Print this page
10703 smatch unreachable code checking needs reworking
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/svcprop/svcprop.c
+++ new/usr/src/cmd/svc/svcprop/svcprop.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.
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]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 - * Copyright (c) 2011, Joyent, Inc. All rights reserved.
28 + * Copyright 2019 Joyent, Inc.
29 29 */
30 30
31 31 /*
32 32 * svcprop - report service configuration properties
33 33 */
34 34
35 35 #include <locale.h>
36 36 #include <libintl.h>
37 37 #include <libscf.h>
38 38 #include <libscf_priv.h>
39 39 #include <libuutil.h>
40 40 #include <stddef.h>
41 41 #include <stdio.h>
42 42 #include <stdlib.h>
43 43 #include <unistd.h>
44 44 #include <strings.h>
45 45 #include <assert.h>
46 46 #include <zone.h>
47 47
48 48 #ifndef TEXT_DOMAIN
49 49 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
50 50 #endif /* TEXT_DOMAIN */
51 51
52 52 /*
53 53 * Error functions. These can change if the quiet (-q) option is used.
54 54 */
55 55 static void (*warn)(const char *, ...) = uu_warn;
56 56 static __NORETURN void (*die)(const char *, ...) = uu_die;
57 57
58 58 /*
59 59 * Entity encapsulation. This allows me to treat services and instances
60 60 * similarly, and avoid duplicating process_ent().
61 61 */
62 62 typedef struct {
63 63 char type; /* !=0: service, 0: instance */
64 64 union {
65 65 scf_service_t *svc;
66 66 scf_instance_t *inst;
67 67 } u;
68 68 } scf_entityp_t;
69 69
70 70 #define ENT_INSTANCE 0
71 71
72 72 #define SCF_ENTITY_SET_TO_SERVICE(ent, s) { ent.type = 1; ent.u.svc = s; }
73 73
74 74 #define SCF_ENTITY_SET_TO_INSTANCE(ent, i) \
75 75 { ent.type = ENT_INSTANCE; ent.u.inst = i; }
76 76
77 77 #define scf_entity_get_pg(ent, name, pg) \
78 78 (ent.type ? scf_service_get_pg(ent.u.svc, name, pg) : \
79 79 scf_instance_get_pg(ent.u.inst, name, pg))
80 80
81 81 #define scf_entity_to_fmri(ent, buf, buf_sz) \
82 82 (ent.type ? scf_service_to_fmri(ent.u.svc, buf, buf_sz) : \
83 83 scf_instance_to_fmri(ent.u.inst, buf, buf_sz))
84 84
85 85 #define SCF_ENTITY_TYPE_NAME(ent) (ent.type ? "service" : "instance")
86 86
87 87 /*
88 88 * Data structure for -p arguments. Since they may be name or name/name, we
89 89 * just track the components.
90 90 */
91 91 typedef struct svcprop_prop_node {
92 92 uu_list_node_t spn_list_node;
93 93 const char *spn_comp1;
94 94 const char *spn_comp2;
95 95 } svcprop_prop_node_t;
96 96
97 97 static uu_list_pool_t *prop_pool;
98 98 static uu_list_t *prop_list;
99 99
100 100 static scf_handle_t *hndl;
101 101 static ssize_t max_scf_name_length;
102 102 static ssize_t max_scf_value_length;
103 103 static ssize_t max_scf_fmri_length;
104 104
105 105 /* Options */
106 106 static int quiet = 0; /* No output. Nothing found, exit(1) */
107 107 static int types = 0; /* Display types of properties. */
108 108 static int verbose = 0; /* Print not found errors to stderr. */
109 109 static int fmris = 0; /* Display full FMRIs for properties. */
110 110 static int wait = 0; /* Wait mode. */
111 111 static char *snapshot = "running"; /* Snapshot to use. */
112 112 static int Cflag = 0; /* C option supplied */
113 113 static int cflag = 0; /* c option supplied */
114 114 static int sflag = 0; /* s option supplied */
115 115 static int return_code; /* main's return code */
116 116
117 117 #define PRINT_NOPROP_ERRORS (!quiet || verbose)
118 118
119 119 /*
120 120 * For unexpected libscf errors. The ending newline is necessary to keep
121 121 * uu_die() from appending the errno error.
122 122 */
123 123 static void
124 124 scfdie(void)
125 125 {
126 126 die(gettext("Unexpected libscf error: %s. Exiting.\n"),
127 127 scf_strerror(scf_error()));
128 128 }
129 129
130 130 static void *
131 131 safe_malloc(size_t sz)
132 132 {
133 133 void *p;
134 134
135 135 p = malloc(sz);
136 136 if (p == NULL)
137 137 die(gettext("Could not allocate memory"));
138 138
139 139 return (p);
140 140 }
141 141
142 142 static void
143 143 usage(void)
144 144 {
145 145 (void) fprintf(stderr, gettext("Usage: %1$s [-fqtv] "
146 146 "[-C | -c | -s snapshot] [-z zone] "
147 147 "[-p [name/]name]... \n"
148 148 " {FMRI | pattern}...\n"
149 149 " %1$s -w [-fqtv] [-z zone] [-p [name/]name] "
150 150 "{FMRI | pattern}\n"), uu_getpname());
151 151 exit(UU_EXIT_USAGE);
152 152 }
153 153
154 154 /*
155 155 * Return an allocated copy of str, with the Bourne shell's metacharacters
156 156 * escaped by '\'.
157 157 *
158 158 * What about unicode?
159 159 */
160 160 static char *
161 161 quote_for_shell(const char *str)
162 162 {
163 163 const char *sp;
164 164 char *dst, *dp;
165 165 size_t dst_len;
166 166
167 167 const char * const metachars = ";&()|^<>\n \t\\\"\'`";
168 168
169 169 if (str[0] == '\0')
170 170 return (strdup("\"\""));
171 171
172 172 dst_len = 0;
173 173 for (sp = str; *sp != '\0'; ++sp) {
174 174 ++dst_len;
175 175
176 176 if (strchr(metachars, *sp) != NULL)
177 177 ++dst_len;
178 178 }
179 179
180 180 if (sp - str == dst_len)
181 181 return (strdup(str));
182 182
183 183 dst = safe_malloc(dst_len + 1);
184 184
185 185 for (dp = dst, sp = str; *sp != '\0'; ++dp, ++sp) {
186 186 if (strchr(metachars, *sp) != NULL)
187 187 *dp++ = '\\';
188 188
189 189 *dp = *sp;
190 190 }
191 191 *dp = '\0';
192 192
193 193 return (dst);
194 194 }
195 195
196 196 static void
197 197 print_value(scf_value_t *val)
198 198 {
199 199 char *buf, *qbuf;
200 200 ssize_t bufsz, r;
201 201
202 202 bufsz = scf_value_get_as_string(val, NULL, 0) + 1;
203 203 if (bufsz - 1 < 0)
204 204 scfdie();
205 205
206 206 buf = safe_malloc(bufsz);
207 207
208 208 r = scf_value_get_as_string(val, buf, bufsz);
209 209 assert(r + 1 == bufsz);
210 210
211 211 qbuf = quote_for_shell(buf);
212 212 (void) fputs(qbuf, stdout);
213 213
214 214 free(qbuf);
215 215 free(buf);
216 216 }
217 217
218 218 /*
219 219 * Display a property's values on a line. If types is true, prepend
220 220 * identification (the FMRI if fmris is true, pg/prop otherwise) and the type
221 221 * of the property.
222 222 */
223 223 static void
224 224 display_prop(scf_propertygroup_t *pg, scf_property_t *prop)
225 225 {
226 226 scf_value_t *val;
227 227 scf_iter_t *iter;
228 228 int ret, first, err;
229 229
230 230 const char * const permission_denied_emsg =
231 231 gettext("Permission denied.\n");
232 232
233 233 if (types) {
234 234 scf_type_t ty;
235 235 char *buf;
236 236 size_t buf_sz;
237 237
238 238 if (fmris) {
239 239 buf_sz = max_scf_fmri_length + 1;
240 240 buf = safe_malloc(buf_sz);
241 241
242 242 if (scf_property_to_fmri(prop, buf, buf_sz) == -1)
243 243 scfdie();
244 244 (void) fputs(buf, stdout);
245 245
246 246 free(buf);
247 247 } else {
248 248 buf_sz = max_scf_name_length + 1;
249 249 buf = safe_malloc(buf_sz);
250 250
251 251 if (scf_pg_get_name(pg, buf, buf_sz) < 0)
252 252 scfdie();
253 253 (void) fputs(buf, stdout);
254 254 (void) putchar('/');
255 255
256 256 if (scf_property_get_name(prop, buf, buf_sz) < 0)
257 257 scfdie();
258 258 (void) fputs(buf, stdout);
259 259
260 260 free(buf);
261 261 }
262 262
263 263 (void) putchar(' ');
264 264
265 265 if (scf_property_type(prop, &ty) == -1)
266 266 scfdie();
267 267 (void) fputs(scf_type_to_string(ty), stdout);
268 268 (void) putchar(' ');
269 269 }
270 270
271 271 if ((iter = scf_iter_create(hndl)) == NULL ||
272 272 (val = scf_value_create(hndl)) == NULL)
273 273 scfdie();
274 274
275 275 if (scf_iter_property_values(iter, prop) == -1)
276 276 scfdie();
277 277
278 278 first = 1;
279 279 while ((ret = scf_iter_next_value(iter, val)) == 1) {
280 280 if (first)
281 281 first = 0;
282 282 else
283 283 (void) putchar(' ');
284 284 print_value(val);
285 285 }
286 286 if (ret == -1) {
287 287 err = scf_error();
288 288 if (err == SCF_ERROR_PERMISSION_DENIED) {
289 289 if (uu_list_numnodes(prop_list) > 0)
290 290 die(permission_denied_emsg);
291 291 } else {
292 292 scfdie();
293 293 }
294 294 }
295 295
296 296 (void) putchar('\n');
297 297
298 298 scf_iter_destroy(iter);
299 299 (void) scf_value_destroy(val);
300 300 }
301 301
302 302 /*
303 303 * display_prop() all of the properties in the given property group. Force
304 304 * types to true so identification will be displayed.
305 305 */
306 306 static void
307 307 display_pg(scf_propertygroup_t *pg)
308 308 {
309 309 scf_property_t *prop;
310 310 scf_iter_t *iter;
311 311 int ret;
312 312
313 313 types = 1; /* Always display types for whole propertygroups. */
314 314
315 315 if ((prop = scf_property_create(hndl)) == NULL ||
316 316 (iter = scf_iter_create(hndl)) == NULL)
317 317 scfdie();
318 318
319 319 if (scf_iter_pg_properties(iter, pg) == -1)
320 320 scfdie();
321 321
322 322 while ((ret = scf_iter_next_property(iter, prop)) == 1)
323 323 display_prop(pg, prop);
324 324 if (ret == -1)
325 325 scfdie();
326 326
327 327 scf_iter_destroy(iter);
328 328 scf_property_destroy(prop);
329 329 }
330 330
331 331 /*
332 332 * Common code to execute when a nonexistant property is encountered.
333 333 */
334 334 static void
335 335 noprop_common_action()
336 336 {
337 337 if (!PRINT_NOPROP_ERRORS)
338 338 /* We're not printing errors, so we can cut out early. */
339 339 exit(UU_EXIT_FATAL);
340 340
341 341 return_code = UU_EXIT_FATAL;
342 342 }
343 343
344 344 /*
345 345 * Iterate the properties of a service or an instance when no snapshot
346 346 * is specified.
347 347 */
348 348 static int
349 349 scf_iter_entity_pgs(scf_iter_t *iter, scf_entityp_t ent)
350 350 {
351 351 int ret = 0;
352 352
353 353 if (ent.type) {
354 354 /*
355 355 * If we are displaying properties for a service,
356 356 * treat it as though it were a composed, current
357 357 * lookup. (implicit cflag) However, if a snapshot
358 358 * was specified, fail.
359 359 */
360 360 if (sflag)
361 361 die(gettext("Only instances have "
362 362 "snapshots.\n"));
363 363 ret = scf_iter_service_pgs(iter, ent.u.svc);
364 364 } else {
365 365 if (Cflag)
366 366 ret = scf_iter_instance_pgs(iter, ent.u.inst);
367 367 else
368 368 ret = scf_iter_instance_pgs_composed(iter, ent.u.inst,
369 369 NULL);
370 370 }
371 371 return (ret);
372 372 }
373 373
374 374 /*
375 375 * Return a snapshot for the supplied instance and snapshot name.
376 376 */
377 377 static scf_snapshot_t *
378 378 get_snapshot(const scf_instance_t *inst, const char *snapshot)
379 379 {
380 380 scf_snapshot_t *snap = scf_snapshot_create(hndl);
381 381
382 382 if (snap == NULL)
383 383 scfdie();
384 384
385 385 if (scf_instance_get_snapshot(inst, snapshot, snap) == -1) {
386 386 switch (scf_error()) {
387 387 case SCF_ERROR_INVALID_ARGUMENT:
388 388 die(gettext("Invalid snapshot name.\n"));
389 389 /* NOTREACHED */
390 390
391 391 case SCF_ERROR_NOT_FOUND:
392 392 if (sflag == 0) {
393 393 scf_snapshot_destroy(snap);
394 394 snap = NULL;
395 395 } else
396 396 die(gettext("No such snapshot.\n"));
397 397 break;
398 398
399 399 default:
400 400 scfdie();
401 401 }
402 402 }
403 403
404 404 return (snap);
405 405 }
406 406
407 407 /*
408 408 * Entity (service or instance): If there are -p options,
409 409 * display_{pg,prop}() the named property groups and/or properties. Otherwise
410 410 * display_pg() all property groups.
411 411 */
412 412 static void
413 413 process_ent(scf_entityp_t ent)
414 414 {
415 415 scf_snapshot_t *snap = NULL;
416 416 scf_propertygroup_t *pg;
417 417 scf_property_t *prop;
418 418 scf_iter_t *iter;
419 419 svcprop_prop_node_t *spn;
420 420 int ret, err;
421 421
422 422 if (uu_list_numnodes(prop_list) == 0) {
423 423 if (quiet)
424 424 return;
425 425
426 426 if ((pg = scf_pg_create(hndl)) == NULL ||
427 427 (iter = scf_iter_create(hndl)) == NULL)
428 428 scfdie();
429 429
430 430 if (cflag || Cflag || ent.type != ENT_INSTANCE) {
431 431 if (scf_iter_entity_pgs(iter, ent) == -1)
432 432 scfdie();
433 433 } else {
434 434 if (snapshot != NULL)
435 435 snap = get_snapshot(ent.u.inst, snapshot);
436 436
437 437 if (scf_iter_instance_pgs_composed(iter, ent.u.inst,
438 438 snap) == -1)
439 439 scfdie();
440 440 if (snap)
441 441 scf_snapshot_destroy(snap);
442 442 }
443 443
444 444 while ((ret = scf_iter_next_pg(iter, pg)) == 1)
445 445 display_pg(pg);
446 446 if (ret == -1)
447 447 scfdie();
448 448
449 449 /*
450 450 * In normal usage, i.e. against the running snapshot,
451 451 * we must iterate over the current non-persistent
452 452 * pg's.
453 453 */
454 454 if (sflag == 0 && snap != NULL) {
455 455 scf_iter_reset(iter);
456 456 if (scf_iter_instance_pgs_composed(iter, ent.u.inst,
457 457 NULL) == -1)
458 458 scfdie();
459 459 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
460 460 uint32_t flags;
461 461
462 462 if (scf_pg_get_flags(pg, &flags) == -1)
463 463 scfdie();
464 464 if (flags & SCF_PG_FLAG_NONPERSISTENT)
465 465 display_pg(pg);
466 466 }
467 467 }
468 468 if (ret == -1)
469 469 scfdie();
470 470
471 471 scf_iter_destroy(iter);
472 472 scf_pg_destroy(pg);
473 473
474 474 return;
475 475 }
476 476
477 477 if ((pg = scf_pg_create(hndl)) == NULL ||
478 478 (prop = scf_property_create(hndl)) == NULL)
479 479 scfdie();
480 480
481 481 if (ent.type == ENT_INSTANCE && snapshot != NULL)
482 482 snap = get_snapshot(ent.u.inst, snapshot);
483 483
484 484 for (spn = uu_list_first(prop_list);
485 485 spn != NULL;
486 486 spn = uu_list_next(prop_list, spn)) {
487 487 if (ent.type == ENT_INSTANCE) {
488 488 if (Cflag)
489 489 ret = scf_instance_get_pg(ent.u.inst,
490 490 spn->spn_comp1, pg);
491 491 else
492 492 ret = scf_instance_get_pg_composed(ent.u.inst,
493 493 snap, spn->spn_comp1, pg);
494 494 err = scf_error();
495 495
496 496 /*
497 497 * If we didn't find it in the specified snapshot, use
498 498 * the current values if the pg is nonpersistent.
499 499 */
500 500 if (ret == -1 && !Cflag &&snap != NULL && err ==
501 501 SCF_ERROR_NOT_FOUND) {
502 502 ret = scf_instance_get_pg_composed(
503 503 ent.u.inst, NULL, spn->spn_comp1,
504 504 pg);
505 505
506 506 if (ret == 0) {
507 507 uint32_t flags;
508 508
509 509 if (scf_pg_get_flags(pg, &flags) == -1)
510 510 scfdie();
511 511 if ((flags & SCF_PG_FLAG_NONPERSISTENT)
512 512 == 0) {
513 513 ret = -1;
514 514 }
515 515 }
516 516 }
517 517 } else {
518 518 /*
519 519 * If we are displaying properties for a service,
520 520 * treat it as though it were a composed, current
521 521 * lookup. (implicit cflag) However, if a snapshot
522 522 * was specified, fail.
523 523 */
524 524 if (sflag)
525 525 die(gettext("Only instances have "
526 526 "snapshots.\n"));
527 527 ret = scf_entity_get_pg(ent, spn->spn_comp1, pg);
528 528 err = scf_error();
529 529 }
530 530 if (ret == -1) {
531 531 if (err != SCF_ERROR_NOT_FOUND)
532 532 scfdie();
533 533
534 534 if (PRINT_NOPROP_ERRORS) {
535 535 char *buf;
536 536
537 537 buf = safe_malloc(max_scf_fmri_length + 1);
538 538 if (scf_entity_to_fmri(ent, buf,
539 539 max_scf_fmri_length + 1) == -1)
540 540 scfdie();
541 541
542 542 uu_warn(gettext("Couldn't find property group "
543 543 "`%s' for %s `%s'.\n"), spn->spn_comp1,
544 544 SCF_ENTITY_TYPE_NAME(ent), buf);
545 545
546 546 free(buf);
547 547 }
548 548
549 549 noprop_common_action();
550 550
551 551 continue;
552 552 }
553 553
554 554 if (spn->spn_comp2 == NULL) {
555 555 if (!quiet)
556 556 display_pg(pg);
557 557 continue;
558 558 }
559 559
560 560 if (scf_pg_get_property(pg, spn->spn_comp2, prop) == -1) {
561 561 if (scf_error() != SCF_ERROR_NOT_FOUND)
562 562 scfdie();
563 563
564 564 if (PRINT_NOPROP_ERRORS) {
565 565 char *buf;
566 566
567 567 buf = safe_malloc(max_scf_fmri_length + 1);
568 568 if (scf_entity_to_fmri(ent, buf,
569 569 max_scf_fmri_length + 1) == -1)
570 570 scfdie();
571 571
572 572 /* FMRI syntax knowledge */
573 573 uu_warn(gettext("Couldn't find property "
574 574 "`%s/%s' for %s `%s'.\n"), spn->spn_comp1,
575 575 spn->spn_comp2, SCF_ENTITY_TYPE_NAME(ent),
576 576 buf);
577 577
578 578 free(buf);
579 579 }
580 580
581 581 noprop_common_action();
582 582
583 583 continue;
584 584 }
585 585
586 586 if (!quiet)
587 587 display_prop(pg, prop);
588 588 }
589 589
590 590 scf_property_destroy(prop);
591 591 scf_pg_destroy(pg);
592 592 if (snap)
593 593 scf_snapshot_destroy(snap);
594 594 }
595 595
596 596 /*
597 597 * Without -p options, just call display_pg(). Otherwise display_prop() the
598 598 * named properties of the property group.
599 599 */
600 600 static void
601 601 process_pg(scf_propertygroup_t *pg)
602 602 {
603 603 scf_property_t *prop;
604 604 svcprop_prop_node_t *spn;
605 605
606 606 if (uu_list_first(prop_list) == NULL) {
607 607 if (quiet)
608 608 return;
609 609
610 610 display_pg(pg);
611 611 return;
612 612 }
613 613
614 614 prop = scf_property_create(hndl);
615 615 if (prop == NULL)
616 616 scfdie();
617 617
618 618 for (spn = uu_list_first(prop_list);
619 619 spn != NULL;
620 620 spn = uu_list_next(prop_list, spn)) {
621 621 if (spn->spn_comp2 != NULL) {
622 622 char *buf;
↓ open down ↓ |
584 lines elided |
↑ open up ↑ |
623 623
624 624 buf = safe_malloc(max_scf_fmri_length + 1);
625 625 if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) ==
626 626 -1)
627 627 scfdie();
628 628
629 629 uu_xdie(UU_EXIT_USAGE, gettext("-p argument `%s/%s' "
630 630 "has too many components for property "
631 631 "group `%s'.\n"), spn->spn_comp1, spn->spn_comp2,
632 632 buf);
633 -
634 - free(buf);
635 633 }
636 634
637 635 if (scf_pg_get_property(pg, spn->spn_comp1, prop) == 0) {
638 636 if (!quiet)
639 637 display_prop(pg, prop);
640 638 continue;
641 639 }
642 640
643 641 if (scf_error() != SCF_ERROR_NOT_FOUND)
644 642 scfdie();
645 643
646 644 if (PRINT_NOPROP_ERRORS) {
647 645 char *buf;
648 646
649 647 buf = safe_malloc(max_scf_fmri_length + 1);
650 648 if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) ==
651 649 -1)
652 650 scfdie();
653 651
654 652 uu_warn(gettext("Couldn't find property `%s' in "
655 653 "property group `%s'.\n"), spn->spn_comp1, buf);
656 654
657 655 free(buf);
658 656 }
659 657
660 658 noprop_common_action();
661 659 }
662 660 }
663 661
664 662 /*
665 663 * If there are -p options, show the error. Otherwise just call
666 664 * display_prop().
667 665 */
668 666 static void
669 667 process_prop(scf_propertygroup_t *pg, scf_property_t *prop)
670 668 {
671 669 if (uu_list_first(prop_list) != NULL) {
672 670 uu_warn(gettext("The -p option cannot be used with property "
673 671 "operands.\n"));
674 672 usage();
675 673 }
676 674
677 675 if (quiet)
678 676 return;
679 677
680 678 display_prop(pg, prop);
681 679 }
682 680
683 681 /* Decode an operand & dispatch. */
684 682 /* ARGSUSED */
685 683 static int
686 684 process_fmri(void *unused, scf_walkinfo_t *wip)
687 685 {
688 686 scf_entityp_t ent;
689 687
690 688 /* Multiple matches imply multiple entities. */
691 689 if (wip->count > 1)
692 690 types = fmris = 1;
693 691
694 692 if (wip->prop != NULL) {
695 693 process_prop(wip->pg, wip->prop);
696 694 } else if (wip->pg != NULL) {
697 695 process_pg(wip->pg);
698 696 } else if (wip->inst != NULL) {
699 697 SCF_ENTITY_SET_TO_INSTANCE(ent, wip->inst);
700 698 process_ent(ent);
701 699 } else {
702 700 /* scf_walk_fmri() won't let this happen */
703 701 assert(wip->svc != NULL);
704 702 SCF_ENTITY_SET_TO_SERVICE(ent, wip->svc);
705 703 process_ent(ent);
706 704 }
707 705
708 706 return (0);
709 707 }
710 708
711 709 static void
712 710 add_prop(char *property)
713 711 {
714 712 svcprop_prop_node_t *p, *last;
715 713 char *slash;
716 714
717 715 const char * const invalid_component_emsg =
718 716 gettext("Invalid component name `%s'.\n");
719 717
720 718 /* FMRI syntax knowledge. */
721 719 slash = strchr(property, '/');
722 720 if (slash != NULL) {
723 721 if (strchr(slash + 1, '/') != NULL) {
724 722 uu_warn(gettext("-p argument `%s' has too many "
725 723 "components.\n"), property);
726 724 usage();
727 725 }
728 726 }
729 727
730 728 if (slash != NULL)
731 729 *slash = '\0';
732 730
733 731 p = safe_malloc(sizeof (svcprop_prop_node_t));
734 732 uu_list_node_init(p, &p->spn_list_node, prop_pool);
735 733
736 734 p->spn_comp1 = property;
737 735 p->spn_comp2 = (slash == NULL) ? NULL : slash + 1;
738 736
739 737 if (uu_check_name(p->spn_comp1, UU_NAME_DOMAIN) == -1)
740 738 uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp1);
741 739 if (p->spn_comp2 != NULL &&
742 740 uu_check_name(p->spn_comp2, UU_NAME_DOMAIN) == -1)
743 741 uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp2);
744 742
745 743 last = uu_list_last(prop_list);
746 744 if (last != NULL) {
747 745 if ((last->spn_comp2 == NULL) ^ (p->spn_comp2 == NULL)) {
748 746 /*
749 747 * The -p options have mixed numbers of components.
750 748 * If they both turn out to be valid, then the
751 749 * single-component ones will specify property groups,
752 750 * so we need to turn on types to keep the output of
753 751 * display_prop() consistent with display_pg().
754 752 */
755 753 types = 1;
756 754 }
757 755 }
758 756
759 757 (void) uu_list_insert_after(prop_list, NULL, p);
760 758 }
761 759
762 760
763 761 /*
764 762 * Wait for a property group or property change.
765 763 *
766 764 * Extract a pg and optionally a property name from fmri & prop_list.
767 765 * _scf_pg_wait() for the pg, and display_pg(pg) or display_prop(pg, prop)
768 766 * when it returns.
769 767 */
770 768 /* ARGSUSED */
771 769 static int
772 770 do_wait(void *unused, scf_walkinfo_t *wip)
773 771 {
774 772 scf_property_t *prop;
775 773 scf_propertygroup_t *lpg, *pg;
776 774 const char *propname;
777 775 svcprop_prop_node_t *p;
778 776
779 777 const char *emsg_not_found = gettext("Not found.\n");
780 778
781 779 if ((lpg = scf_pg_create(hndl)) == NULL ||
782 780 (prop = scf_property_create(hndl)) == NULL)
783 781 scfdie();
784 782
785 783 if (wip->prop != NULL) {
786 784 if (uu_list_numnodes(prop_list) > 0)
787 785 uu_xdie(UU_EXIT_USAGE, gettext("-p cannot be used with "
788 786 "property FMRIs.\n"));
789 787 pg = wip->pg;
790 788
791 789 assert(strrchr(wip->fmri, '/') != NULL);
792 790 propname = strrchr(wip->fmri, '/') + 1;
793 791
794 792 } else if (wip->pg != NULL) {
795 793 p = uu_list_first(prop_list);
796 794
797 795 if (p != NULL) {
798 796 if (p->spn_comp2 != NULL)
799 797 uu_xdie(UU_EXIT_USAGE, gettext("-p argument "
800 798 "\"%s/%s\" has too many components for "
801 799 "property group %s.\n"),
802 800 p->spn_comp1, p->spn_comp2, wip->fmri);
803 801
804 802 propname = p->spn_comp1;
805 803
806 804 if (scf_pg_get_property(wip->pg, propname, prop) !=
807 805 SCF_SUCCESS) {
808 806 switch (scf_error()) {
809 807 case SCF_ERROR_INVALID_ARGUMENT:
810 808 uu_xdie(UU_EXIT_USAGE,
811 809 gettext("Invalid property name "
812 810 "\"%s\".\n"), propname);
813 811
814 812 /* NOTREACHED */
815 813
816 814 case SCF_ERROR_NOT_FOUND:
817 815 die(emsg_not_found);
818 816
819 817 default:
820 818 scfdie();
821 819 }
822 820 }
823 821 } else {
824 822 propname = NULL;
825 823 }
826 824
827 825 pg = wip->pg;
828 826
829 827 } else if (wip->inst != NULL) {
830 828
831 829 p = uu_list_first(prop_list);
832 830 if (p == NULL)
833 831 uu_xdie(UU_EXIT_USAGE,
834 832 gettext("Cannot wait for an instance.\n"));
835 833
836 834 if (scf_instance_get_pg(wip->inst, p->spn_comp1, lpg) !=
837 835 SCF_SUCCESS) {
838 836 switch (scf_error()) {
839 837 case SCF_ERROR_INVALID_ARGUMENT:
840 838 uu_xdie(UU_EXIT_USAGE, gettext("Invalid "
841 839 "property group name \"%s\".\n"),
842 840 p->spn_comp1);
843 841 /* NOTREACHED */
844 842
845 843 case SCF_ERROR_NOT_FOUND:
846 844 die(emsg_not_found);
847 845
848 846 default:
849 847 scfdie();
850 848 }
851 849 }
852 850
853 851 propname = p->spn_comp2;
854 852
855 853 if (propname != NULL) {
856 854 if (scf_pg_get_property(lpg, propname, prop) !=
857 855 SCF_SUCCESS) {
858 856 switch (scf_error()) {
859 857 case SCF_ERROR_INVALID_ARGUMENT:
860 858 uu_xdie(UU_EXIT_USAGE,
861 859 gettext("Invalid property name "
862 860 "\"%s\".\n"), propname);
863 861 /* NOTREACHED */
864 862
865 863 case SCF_ERROR_NOT_FOUND:
866 864 die(emsg_not_found);
867 865
868 866 default:
869 867 scfdie();
870 868 }
871 869 }
872 870 }
873 871
874 872 pg = lpg;
875 873
876 874 } else if (wip->svc != NULL) {
877 875
878 876 p = uu_list_first(prop_list);
879 877 if (p == NULL)
880 878 uu_xdie(UU_EXIT_USAGE,
881 879 gettext("Cannot wait for a service.\n"));
882 880
883 881 if (scf_service_get_pg(wip->svc, p->spn_comp1, lpg) !=
884 882 SCF_SUCCESS) {
885 883 switch (scf_error()) {
886 884 case SCF_ERROR_INVALID_ARGUMENT:
887 885 uu_xdie(UU_EXIT_USAGE, gettext("Invalid "
888 886 "property group name \"%s\".\n"),
889 887 p->spn_comp1);
890 888 /* NOTREACHED */
891 889
892 890 case SCF_ERROR_NOT_FOUND:
893 891 die(emsg_not_found);
894 892
895 893 default:
896 894 scfdie();
897 895 }
898 896 }
899 897
900 898 propname = p->spn_comp2;
901 899
902 900 if (propname != NULL) {
903 901 if (scf_pg_get_property(lpg, propname, prop) !=
904 902 SCF_SUCCESS) {
905 903 switch (scf_error()) {
906 904 case SCF_ERROR_INVALID_ARGUMENT:
907 905 uu_xdie(UU_EXIT_USAGE,
908 906 gettext("Invalid property name "
909 907 "\"%s\".\n"), propname);
910 908
911 909 /* NOTREACHED */
912 910
913 911 case SCF_ERROR_NOT_FOUND:
914 912 die(emsg_not_found);
915 913
916 914 default:
917 915 scfdie();
918 916 }
919 917 }
920 918 }
921 919
922 920 pg = lpg;
923 921
924 922 } else {
925 923 uu_xdie(UU_EXIT_USAGE, gettext("FMRI must specify an entity, "
926 924 "property group, or property.\n"));
927 925 }
928 926
929 927 for (;;) {
930 928 int ret;
931 929
932 930 ret = _scf_pg_wait(pg, -1);
933 931 if (ret != SCF_SUCCESS)
934 932 scfdie();
935 933
936 934 ret = scf_pg_update(pg);
937 935 if (ret < 0) {
938 936 if (scf_error() != SCF_ERROR_DELETED)
939 937 scfdie();
940 938
941 939 die(emsg_not_found);
942 940 }
943 941 if (ret == SCF_COMPLETE)
944 942 break;
945 943 }
946 944
947 945 if (propname != NULL) {
948 946 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) {
949 947 if (!quiet)
950 948 display_prop(pg, prop);
951 949 } else {
952 950 if (scf_error() != SCF_ERROR_NOT_FOUND)
953 951 scfdie();
954 952
955 953 if (PRINT_NOPROP_ERRORS)
956 954 uu_warn(emsg_not_found);
957 955
958 956 return_code = UU_EXIT_FATAL;
959 957 }
960 958 } else {
961 959 if (!quiet)
962 960 display_pg(pg);
963 961 }
964 962
965 963 scf_property_destroy(prop);
966 964 scf_pg_destroy(lpg);
967 965
968 966 return (0);
969 967 }
970 968
971 969 /*
972 970 * These functions replace uu_warn() and uu_die() when the quiet (-q) option is
973 971 * used, and silently ignore any output.
974 972 */
975 973
976 974 /*ARGSUSED*/
977 975 static void
978 976 quiet_warn(const char *fmt, ...)
979 977 {
980 978 /* Do nothing */
981 979 }
982 980
983 981 /*ARGSUSED*/
984 982 static __NORETURN void
985 983 quiet_die(const char *fmt, ...)
986 984 {
987 985 exit(UU_EXIT_FATAL);
988 986 }
989 987
990 988 int
991 989 main(int argc, char *argv[])
992 990 {
993 991 int c;
994 992 scf_walk_callback callback;
995 993 int flags;
996 994 int err;
997 995
998 996 (void) setlocale(LC_ALL, "");
999 997 (void) textdomain(TEXT_DOMAIN);
1000 998
1001 999 return_code = UU_EXIT_OK;
1002 1000
1003 1001 (void) uu_setpname(argv[0]);
1004 1002
1005 1003 prop_pool = uu_list_pool_create("properties",
1006 1004 sizeof (svcprop_prop_node_t),
1007 1005 offsetof(svcprop_prop_node_t, spn_list_node), NULL, 0);
1008 1006 if (prop_pool == NULL)
1009 1007 uu_die("%s\n", uu_strerror(uu_error()));
1010 1008
1011 1009 prop_list = uu_list_create(prop_pool, NULL, 0);
1012 1010
1013 1011 hndl = scf_handle_create(SCF_VERSION);
1014 1012 if (hndl == NULL)
1015 1013 scfdie();
1016 1014
1017 1015 while ((c = getopt(argc, argv, "Ccfp:qs:tvwz:")) != -1) {
1018 1016 switch (c) {
1019 1017 case 'C':
1020 1018 if (cflag || sflag || wait)
1021 1019 usage(); /* Not with -c, -s or -w */
1022 1020 Cflag++;
1023 1021 snapshot = NULL;
1024 1022 break;
1025 1023
1026 1024 case 'c':
1027 1025 if (Cflag || sflag || wait)
1028 1026 usage(); /* Not with -C, -s or -w */
1029 1027 cflag++;
1030 1028 snapshot = NULL;
1031 1029 break;
1032 1030
1033 1031 case 'f':
1034 1032 types = 1;
1035 1033 fmris = 1;
1036 1034 break;
1037 1035
1038 1036 case 'p':
1039 1037 add_prop(optarg);
1040 1038 break;
1041 1039
1042 1040 case 'q':
1043 1041 quiet = 1;
1044 1042 warn = quiet_warn;
1045 1043 die = quiet_die;
1046 1044 break;
1047 1045
1048 1046 case 's':
1049 1047 if (Cflag || cflag || wait)
1050 1048 usage(); /* Not with -C, -c or -w */
1051 1049 snapshot = optarg;
1052 1050 sflag++;
1053 1051 break;
1054 1052
1055 1053 case 't':
1056 1054 types = 1;
1057 1055 break;
1058 1056
1059 1057 case 'v':
1060 1058 verbose = 1;
1061 1059 break;
1062 1060
1063 1061 case 'w':
1064 1062 if (Cflag || cflag || sflag)
1065 1063 usage(); /* Not with -C, -c or -s */
1066 1064 wait = 1;
1067 1065 break;
1068 1066
1069 1067 case 'z': {
1070 1068 scf_value_t *zone;
1071 1069 scf_handle_t *h = hndl;
1072 1070
1073 1071 if (getzoneid() != GLOBAL_ZONEID)
1074 1072 uu_die(gettext("svcprop -z may only be used "
1075 1073 "from the global zone\n"));
1076 1074
1077 1075 if ((zone = scf_value_create(h)) == NULL)
1078 1076 scfdie();
1079 1077
1080 1078 if (scf_value_set_astring(zone, optarg) != SCF_SUCCESS)
1081 1079 scfdie();
1082 1080
1083 1081 if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS)
1084 1082 uu_die(gettext("invalid zone '%s'\n"), optarg);
1085 1083
1086 1084 scf_value_destroy(zone);
1087 1085 break;
1088 1086 }
1089 1087
1090 1088 case '?':
1091 1089 switch (optopt) {
1092 1090 case 'p':
1093 1091 usage();
1094 1092
1095 1093 default:
1096 1094 break;
1097 1095 }
1098 1096
1099 1097 /* FALLTHROUGH */
1100 1098
1101 1099 default:
1102 1100 usage();
1103 1101 }
1104 1102 }
1105 1103
1106 1104 if (optind == argc)
1107 1105 usage();
1108 1106
1109 1107 max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1110 1108 max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1111 1109 max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1112 1110 if (max_scf_name_length == -1 || max_scf_value_length == -1 ||
1113 1111 max_scf_fmri_length == -1)
1114 1112 scfdie();
1115 1113
1116 1114 if (scf_handle_bind(hndl) == -1)
1117 1115 die(gettext("Could not connect to configuration repository: "
1118 1116 "%s.\n"), scf_strerror(scf_error()));
1119 1117
1120 1118 flags = SCF_WALK_PROPERTY | SCF_WALK_SERVICE | SCF_WALK_EXPLICIT;
1121 1119
1122 1120 if (wait) {
1123 1121 if (uu_list_numnodes(prop_list) > 1)
1124 1122 usage();
1125 1123
1126 1124 if (argc - optind > 1)
1127 1125 usage();
1128 1126
1129 1127 callback = do_wait;
1130 1128
1131 1129 } else {
1132 1130 callback = process_fmri;
1133 1131
1134 1132 flags |= SCF_WALK_MULTIPLE;
1135 1133 }
1136 1134
1137 1135 if ((err = scf_walk_fmri(hndl, argc - optind, argv + optind, flags,
1138 1136 callback, NULL, &return_code, warn)) != 0) {
1139 1137 warn(gettext("failed to iterate over instances: %s\n"),
1140 1138 scf_strerror(err));
1141 1139 return_code = UU_EXIT_FATAL;
1142 1140 }
1143 1141
1144 1142 scf_handle_destroy(hndl);
1145 1143
1146 1144 return (return_code);
1147 1145 }
↓ open down ↓ |
503 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX