Print this page
1565 svccfg cleanup needs to suck it up and finish the job
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/svccfg/svccfg_engine.c
+++ new/usr/src/cmd/svc/svccfg/svccfg_engine.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]
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 */
25 25
26 26
27 27 /*
28 28 * svccfg(1) interpreter and command execution engine.
29 29 */
30 30
31 31 #include <sys/mman.h>
32 32 #include <sys/stat.h>
33 33 #include <sys/types.h>
34 34 #include <assert.h>
35 35 #include <errno.h>
36 36 #include <fcntl.h>
37 37 #include <libintl.h>
38 38 #include <libtecla.h>
39 39 #include <md5.h>
40 40 #include <string.h>
41 41 #include <stdlib.h>
42 42 #include <unistd.h>
43 43
44 44 #include "manifest_find.h"
45 45 #include "manifest_hash.h"
46 46 #include "svccfg.h"
47 47
48 48 #define MS_PER_US 1000
49 49
50 50 engine_state_t *est;
51 51
52 52 /*
53 53 * Replacement lex(1) character retrieval routines.
54 54 */
55 55 int
56 56 engine_cmd_getc(engine_state_t *E)
57 57 {
58 58 if (E->sc_cmd_file != NULL)
59 59 return (getc(E->sc_cmd_file));
60 60
61 61 if (E->sc_cmd_flags & SC_CMD_EOF)
62 62 return (EOF);
63 63
64 64 if (E->sc_cmd_bufoff < E->sc_cmd_bufsz)
65 65 return (*(E->sc_cmd_buf + E->sc_cmd_bufoff++));
66 66
67 67 if (!(E->sc_cmd_flags & SC_CMD_IACTIVE)) {
68 68 E->sc_cmd_flags |= SC_CMD_EOF;
69 69
70 70 return (EOF);
71 71 } else {
72 72 #ifdef NATIVE_BUILD
73 73 return (EOF);
74 74 #else
75 75 extern int parens;
76 76
77 77 if (parens <= 0) {
78 78 E->sc_cmd_flags |= SC_CMD_EOF;
79 79 return (EOF);
80 80 }
81 81
82 82 for (;;) {
83 83 E->sc_cmd_buf = gl_get_line(E->sc_gl, "> ", NULL, -1);
84 84 if (E->sc_cmd_buf != NULL)
85 85 break;
86 86
87 87 switch (gl_return_status(E->sc_gl)) {
88 88 case GLR_SIGNAL:
89 89 gl_abandon_line(E->sc_gl);
90 90 continue;
91 91
92 92 case GLR_EOF:
93 93 E->sc_cmd_flags |= SC_CMD_EOF;
94 94 return (EOF);
95 95
96 96 case GLR_ERROR:
97 97 uu_die(gettext("Error reading terminal: %s.\n"),
98 98 gl_error_message(E->sc_gl, NULL, 0));
99 99 /* NOTREACHED */
100 100
101 101 default:
102 102 #ifndef NDEBUG
103 103 (void) fprintf(stderr, "%s:%d: gl_get_line() "
104 104 "returned unexpected value %d.\n", __FILE__,
105 105 __LINE__, gl_return_status(E->sc_gl));
106 106 #endif
107 107 abort();
108 108 }
109 109 }
110 110
111 111 E->sc_cmd_bufsz = strlen(E->sc_cmd_buf);
112 112 E->sc_cmd_bufoff = 1;
113 113
114 114 return (E->sc_cmd_buf[0]);
115 115 #endif /* NATIVE_BUILD */
116 116 }
117 117 }
118 118
119 119 int
120 120 engine_cmd_ungetc(engine_state_t *E, char c)
121 121 {
122 122 if (E->sc_cmd_file != NULL)
123 123 return (ungetc(c, E->sc_cmd_file));
124 124
125 125 if (E->sc_cmd_buf != NULL)
126 126 *(E->sc_cmd_buf + --E->sc_cmd_bufoff) = c;
127 127
128 128 return (c);
129 129 }
130 130
131 131 /*ARGSUSED*/
132 132 void
133 133 engine_cmd_nputs(engine_state_t *E, char *c, size_t n)
134 134 {
135 135 /* our lexer shouldn't need this state */
136 136 exit(11);
137 137 }
138 138
139 139 int
140 140 engine_exec(char *cmd)
141 141 {
142 142 est->sc_cmd_buf = cmd;
143 143 est->sc_cmd_bufsz = strlen(cmd) + 1;
144 144 est->sc_cmd_bufoff = 0;
145 145
146 146 (void) yyparse();
147 147
148 148 return (0);
149 149 }
150 150
151 151 #ifndef NATIVE_BUILD
152 152 /* ARGSUSED */
153 153 static
154 154 CPL_CHECK_FN(check_xml)
155 155 {
156 156 const char *ext;
157 157
158 158 if (strlen(pathname) < 4)
159 159 return (0);
160 160
161 161 ext = pathname + strlen(pathname) - 4;
162 162
163 163 return (strcmp(ext, ".xml") == 0 ? 1 : 0);
164 164 }
165 165
166 166 static const char * const whitespace = " \t";
167 167
168 168 static
169 169 CPL_MATCH_FN(complete_single_xml_file_arg)
170 170 {
171 171 const char *arg1 = data;
172 172 int arg1end_i, ret;
173 173 CplFileConf *cfc;
174 174
175 175 arg1end_i = arg1 + strcspn(arg1, whitespace) - line;
176 176 if (arg1end_i < word_end)
177 177 return (0);
178 178
179 179 cfc = new_CplFileConf();
180 180 if (cfc == NULL) {
181 181 cpl_record_error(cpl, "Out of memory.");
182 182 return (1);
183 183 }
184 184
185 185 cfc_set_check_fn(cfc, check_xml, NULL);
186 186
187 187 ret = cpl_file_completions(cpl, cfc, line, word_end);
188 188
189 189 (void) del_CplFileConf(cfc);
190 190 return (ret);
191 191 }
192 192
193 193 static struct cmd_info {
194 194 const char *name;
195 195 uint32_t flags;
196 196 CplMatchFn *complete_args_f;
197 197 } cmds[] = {
198 198 { "validate", CS_GLOBAL, complete_single_xml_file_arg },
199 199 { "import", CS_GLOBAL, complete_single_xml_file_arg },
200 200 { "cleanup", CS_GLOBAL, NULL},
201 201 { "export", CS_GLOBAL, NULL },
202 202 { "archive", CS_GLOBAL, NULL },
203 203 { "apply", CS_GLOBAL, complete_single_xml_file_arg },
204 204 { "extract", CS_GLOBAL, NULL },
205 205 { "repository", CS_GLOBAL, NULL },
206 206 { "inventory", CS_GLOBAL, complete_single_xml_file_arg },
207 207 { "set", CS_GLOBAL, NULL },
208 208 { "end", CS_GLOBAL, NULL },
209 209 { "exit", CS_GLOBAL, NULL },
210 210 { "quit", CS_GLOBAL, NULL },
211 211 { "help", CS_GLOBAL, NULL },
212 212 { "delete", CS_GLOBAL, NULL },
213 213 { "select", CS_GLOBAL, complete_select },
214 214 { "unselect", CS_SVC | CS_INST | CS_SNAP, NULL },
215 215 { "list", CS_SCOPE | CS_SVC | CS_SNAP, NULL },
216 216 { "add", CS_SCOPE | CS_SVC, NULL },
217 217 { "listpg", CS_SVC | CS_INST | CS_SNAP, NULL },
218 218 { "addpg", CS_SVC | CS_INST, NULL },
219 219 { "delpg", CS_SVC | CS_INST, NULL },
220 220 { "delhash", CS_GLOBAL, complete_single_xml_file_arg },
221 221 { "listprop", CS_SVC | CS_INST | CS_SNAP, NULL },
222 222 { "setprop", CS_SVC | CS_INST, NULL },
223 223 { "delprop", CS_SVC | CS_INST, NULL },
224 224 { "editprop", CS_SVC | CS_INST, NULL },
225 225 { "describe", CS_SVC | CS_INST | CS_SNAP, NULL },
226 226 { "listsnap", CS_INST | CS_SNAP, NULL },
227 227 { "selectsnap", CS_INST | CS_SNAP, NULL },
228 228 { "revert", CS_INST | CS_SNAP, NULL },
229 229 { "refresh", CS_INST, NULL },
230 230 { NULL }
231 231 };
232 232
233 233 int
234 234 add_cmd_matches(WordCompletion *cpl, const char *line, int word_end,
235 235 uint32_t scope)
236 236 {
237 237 int word_start, err;
238 238 size_t len;
239 239 const char *bol;
240 240 struct cmd_info *cip;
241 241
242 242 word_start = strspn(line, whitespace);
243 243 len = word_end - word_start;
244 244 bol = line + word_end - len;
245 245
246 246 for (cip = cmds; cip->name != NULL; ++cip) {
247 247 if ((cip->flags & scope) == 0)
248 248 continue;
249 249
250 250 if (strncmp(cip->name, bol, len) == 0) {
251 251 err = cpl_add_completion(cpl, line, word_start,
252 252 word_end, cip->name + len, "", " ");
253 253 if (err != 0)
254 254 return (err);
255 255 }
256 256 }
257 257
258 258 return (0);
259 259 }
260 260
261 261 /*
262 262 * Suggest completions. We must first determine if the cursor is in command
263 263 * position or in argument position. If the former, complete_command() finds
264 264 * matching commands. If the latter, we tail-call the command-specific
265 265 * argument-completion routine in the cmds table.
266 266 */
267 267 /* ARGSUSED */
268 268 static
269 269 CPL_MATCH_FN(complete)
270 270 {
271 271 const char *arg0, *arg1;
272 272 size_t arg0len;
273 273 struct cmd_info *cip;
274 274
275 275 arg0 = line + strspn(line, whitespace);
276 276 arg0len = strcspn(arg0, whitespace);
277 277 if ((arg0 + arg0len) - line >= word_end ||
278 278 (arg0[arg0len] != ' ' && arg0[arg0len] != '\t'))
279 279 return (complete_command(cpl, (void *)arg0, line, word_end));
280 280
281 281 arg1 = arg0 + arg0len;
282 282 arg1 += strspn(arg1, whitespace);
283 283
284 284 for (cip = cmds; cip->name != NULL; ++cip) {
285 285 if (strlen(cip->name) != arg0len)
286 286 continue;
287 287
288 288 if (strncmp(cip->name, arg0, arg0len) != 0)
289 289 continue;
290 290
291 291 if (cip->complete_args_f == NULL)
292 292 break;
293 293
294 294 return (cip->complete_args_f(cpl, (void *)arg1, line,
295 295 word_end));
296 296 }
297 297
298 298 return (0);
299 299 }
300 300 #endif /* NATIVE_BUILD */
301 301
302 302 int
303 303 engine_interp()
304 304 {
305 305 #ifdef NATIVE_BUILD
306 306 uu_die("native build does not support interactive mode.");
307 307 #else
308 308 char *selfmri;
309 309 size_t sfsz;
310 310 int r;
311 311
312 312 extern int parens;
313 313
314 314 (void) sigset(SIGINT, SIG_IGN);
315 315
316 316 est->sc_gl = new_GetLine(512, 8000);
317 317 if (est->sc_gl == NULL)
318 318 uu_die(gettext("Out of memory.\n"));
319 319
320 320 /* The longest string is "[snapname]fmri[:instname]> ". */
321 321 sfsz = 1 + max_scf_name_len + 1 + max_scf_fmri_len + 2 +
322 322 max_scf_name_len + 1 + 2 + 1;
323 323 selfmri = safe_malloc(sfsz);
324 324
325 325 r = gl_customize_completion(est->sc_gl, NULL, complete);
326 326 assert(r == 0);
327 327
328 328 for (;;) {
329 329 lscf_get_selection_str(selfmri, sfsz - 2);
330 330 (void) strcat(selfmri, "> ");
331 331 est->sc_cmd_buf = gl_get_line(est->sc_gl, selfmri, NULL, -1);
332 332
333 333 if (est->sc_cmd_buf == NULL) {
334 334 switch (gl_return_status(est->sc_gl)) {
335 335 case GLR_SIGNAL:
336 336 gl_abandon_line(est->sc_gl);
337 337 continue;
338 338
339 339 case GLR_EOF:
340 340 break;
341 341
342 342 case GLR_ERROR:
343 343 uu_die(gettext("Error reading terminal: %s.\n"),
344 344 gl_error_message(est->sc_gl, NULL, 0));
345 345 /* NOTREACHED */
346 346
347 347 default:
348 348 #ifndef NDEBUG
349 349 (void) fprintf(stderr, "%s:%d: gl_get_line() "
350 350 "returned unexpected value %d.\n", __FILE__,
351 351 __LINE__, gl_return_status(est->sc_gl));
352 352 #endif
353 353 abort();
354 354 }
355 355
356 356 break;
357 357 }
358 358
359 359 parens = 0;
360 360 est->sc_cmd_bufsz = strlen(est->sc_cmd_buf);
361 361 est->sc_cmd_bufoff = 0;
362 362 est->sc_cmd_flags = SC_CMD_IACTIVE;
363 363
364 364 (void) yyparse();
365 365 }
366 366
367 367 free(selfmri);
368 368 est->sc_gl = del_GetLine(est->sc_gl); /* returns NULL */
369 369
370 370 #endif /* NATIVE_BUILD */
371 371 return (0);
372 372 }
373 373
374 374 int
375 375 engine_source(const char *name, boolean_t dont_exit)
376 376 {
377 377 engine_state_t *old = est;
378 378 struct stat st;
379 379 int ret;
380 380
381 381 est = uu_zalloc(sizeof (engine_state_t));
382 382
383 383 /* first, copy the stuff set up in engine_init */
384 384 est->sc_repo_pid = old->sc_repo_pid;
385 385 if (old->sc_repo_filename != NULL)
386 386 est->sc_repo_filename = safe_strdup(old->sc_repo_filename);
387 387 if (old->sc_repo_doordir != NULL)
388 388 est->sc_repo_doordir = safe_strdup(old->sc_repo_doordir);
389 389 if (old->sc_repo_doorname != NULL)
390 390 est->sc_repo_doorname = safe_strdup(old->sc_repo_doorname);
391 391 if (old->sc_repo_server != NULL)
392 392 est->sc_repo_server = safe_strdup(old->sc_repo_server);
393 393
394 394 /* set up the new guy */
395 395 est->sc_cmd_lineno = 1;
396 396
397 397 if (dont_exit)
398 398 est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
399 399
400 400 if (strcmp(name, "-") == 0) {
401 401 est->sc_cmd_file = stdin;
402 402 est->sc_cmd_filename = "<stdin>";
403 403 } else {
404 404 errno = 0;
405 405 est->sc_cmd_filename = name;
406 406 est->sc_cmd_file = fopen(name, "r");
407 407 if (est->sc_cmd_file == NULL) {
408 408 if (errno == 0)
409 409 semerr(gettext("No free stdio streams.\n"));
410 410 else
411 411 semerr(gettext("Could not open %s"), name);
412 412
413 413 ret = -1;
414 414 goto fail;
415 415 }
416 416
417 417 do {
418 418 ret = fstat(fileno(est->sc_cmd_file), &st);
419 419 } while (ret != 0 && errno == EINTR);
420 420 if (ret != 0) {
421 421 (void) fclose(est->sc_cmd_file);
422 422 est->sc_cmd_file = NULL; /* for semerr() */
423 423
424 424 semerr(gettext("Could not stat %s"), name);
425 425
426 426 ret = -1;
427 427 goto fail;
428 428 }
429 429
430 430 if (!S_ISREG(st.st_mode)) {
431 431 (void) fclose(est->sc_cmd_file);
432 432 est->sc_cmd_file = NULL; /* for semerr() */
433 433
434 434 semerr(gettext("%s is not a regular file.\n"), name);
435 435
436 436 ret = -1;
437 437 goto fail;
438 438 }
439 439 }
440 440
441 441 (void) yyparse();
442 442
443 443 if (est->sc_cmd_file != stdin)
444 444 (void) fclose(est->sc_cmd_file);
445 445
446 446 ret = 0;
447 447
448 448 fail:
449 449 if (est->sc_repo_pid != old->sc_repo_pid)
450 450 lscf_cleanup(); /* clean up any new repository */
451 451
452 452 if (est->sc_repo_filename != NULL)
453 453 free((void *)est->sc_repo_filename);
454 454 if (est->sc_repo_doordir != NULL)
455 455 free((void *)est->sc_repo_doordir);
456 456 if (est->sc_repo_doorname != NULL)
457 457 free((void *)est->sc_repo_doorname);
458 458 if (est->sc_repo_server != NULL)
459 459 free((void *)est->sc_repo_server);
460 460 free(est);
461 461
462 462 est = old;
463 463
464 464 return (ret);
465 465 }
466 466
467 467 /*
468 468 * Initialize svccfg state. We recognize four environment variables:
469 469 *
470 470 * SVCCFG_REPOSITORY Create a private instance of svc.configd(1M) to answer
471 471 * requests for the specified repository file.
472 472 * SVCCFG_DOOR_PATH Directory for door creation.
473 473 *
474 474 * SVCCFG_DOOR Rendezvous via an alternative repository door.
475 475 *
476 476 * SVCCFG_CONFIGD_PATH Resolvable path to alternative svc.configd(1M) binary.
477 477 */
478 478 void
479 479 engine_init()
480 480 {
481 481 const char *cp;
482 482
483 483 est = uu_zalloc(sizeof (engine_state_t));
484 484
485 485 est->sc_cmd_lineno = 1;
486 486 est->sc_repo_pid = -1;
487 487
488 488 cp = getenv("SVCCFG_REPOSITORY");
489 489 est->sc_repo_filename = cp ? safe_strdup(cp) : NULL;
490 490
491 491 cp = getenv("SVCCFG_DOOR_PATH");
492 492 est->sc_repo_doordir = cp ? cp : "/var/run";
493 493
494 494 cp = getenv("SVCCFG_DOOR");
495 495 if (cp != NULL) {
496 496 if (est->sc_repo_filename != NULL) {
497 497 uu_warn(gettext("SVCCFG_DOOR unused when "
498 498 "SVCCFG_REPOSITORY specified\n"));
499 499 } else {
500 500 est->sc_repo_doorname = safe_strdup(cp);
501 501 }
502 502 }
503 503
504 504 cp = getenv("SVCCFG_CONFIGD_PATH");
505 505 est->sc_repo_server = cp ? cp : "/lib/svc/bin/svc.configd";
506 506
507 507 est->sc_miss_type = B_FALSE;
508 508 est->sc_in_emi = 0;
509 509 cp = getenv("SMF_FMRI");
510 510 if ((cp != NULL) && (strcmp(cp, SCF_INSTANCE_EMI) == 0))
511 511 est->sc_in_emi = 1;
512 512
513 513 cp = smf_get_state(SCF_INSTANCE_FS_MINIMAL);
514 514 if (cp && (strcmp(cp, SCF_STATE_STRING_ONLINE) == 0))
515 515 est->sc_fs_minimal = B_TRUE;
516 516 free((void *) cp);
517 517 }
518 518
519 519 static int
520 520 import_manifest_file(manifest_info_t *info, boolean_t validate, FILE *pout,
521 521 uint_t flags)
522 522 {
523 523 bundle_t *b;
524 524 tmpl_errors_t *errs;
525 525 const char *file;
526 526 tmpl_validate_status_t vr;
527 527
528 528 file = info->mi_path;
529 529
530 530 /* Load the manifest */
531 531 b = internal_bundle_new();
532 532
533 533 if (lxml_get_bundle_file(b, file, SVCCFG_OP_IMPORT) != 0) {
534 534 internal_bundle_free(b);
535 535 return (-1);
536 536 }
537 537
538 538 /* Validate */
539 539 if ((vr = tmpl_validate_bundle(b, &errs)) != TVS_SUCCESS) {
540 540 char *prefix;
541 541
542 542 if ((validate == 0) || (vr == TVS_WARN)) {
543 543 prefix = gettext("Warning: ");
544 544 } else {
545 545 prefix = "";
546 546 }
547 547 tmpl_errors_print(stderr, errs, prefix);
548 548 if (validate && (vr != TVS_WARN)) {
549 549 tmpl_errors_destroy(errs);
550 550 semerr(gettext("Import of %s failed.\n"),
551 551 info->mi_path);
552 552 if (pout != NULL) {
553 553 (void) fprintf(pout, gettext("WARNING: svccfg "
554 554 "import of %s failed.\n"), info->mi_path);
555 555 }
556 556
557 557 return (-1);
558 558 }
559 559 }
560 560 tmpl_errors_destroy(errs);
561 561
562 562 /* Import */
563 563 if (lscf_bundle_import(b, file, flags) != 0) {
564 564 internal_bundle_free(b);
565 565 semerr(gettext("Import of %s failed.\n"), info->mi_path);
566 566 if (pout != NULL) {
567 567 (void) fprintf(pout, gettext("WARNING: svccfg import "
568 568 "of %s failed.\n"), info->mi_path);
569 569 }
570 570 return (-1);
571 571 }
572 572
573 573 internal_bundle_free(b);
574 574
575 575 if (info->mi_prop) {
576 576 char *errstr;
577 577
578 578 if (mhash_store_entry(g_hndl, info->mi_prop, file,
579 579 info->mi_hash, APPLY_NONE, &errstr)) {
580 580 if (errstr)
581 581 semerr(gettext("Could not store hash for %s. "
582 582 "%s\n"), info->mi_path, errstr);
583 583 else
584 584 semerr(gettext("Unknown error from "
585 585 "mhash_store_entry() for %s\n"),
586 586 info->mi_path);
587 587 }
588 588
589 589 }
590 590
591 591 return (0);
592 592 }
593 593
594 594 /*
595 595 * Return values:
596 596 * 1 No manifests need to be imported.
597 597 * 0 Success
598 598 * -1 Error
599 599 * -2 Syntax error
600 600 */
601 601 int
602 602 engine_import(uu_list_t *args)
603 603 {
604 604 int argc, i, o;
605 605 int dont_exit;
606 606 int failed_manifests;
607 607 int total_manifests;
608 608 char *file;
609 609 char **argv = NULL;
610 610 string_list_t *slp;
611 611 boolean_t validate = B_FALSE;
612 612 uint_t flags = SCI_GENERALLAST;
613 613 int dirarg = 0;
614 614 int isdir;
615 615 int rc = -1;
616 616 struct stat sb;
617 617 char **paths;
618 618 manifest_info_t ***manifest_sets = NULL;
619 619 manifest_info_t **manifests;
620 620 char *progress_file = NULL;
621 621 FILE *progress_out = NULL;
622 622 int progress_count;
623 623 int back_count;
624 624 int count;
625 625 int fm_flags;
626 626
627 627 argc = uu_list_numnodes(args);
628 628 if (argc < 1)
629 629 return (-2);
630 630
631 631 argv = calloc(argc + 1, sizeof (char *));
632 632 if (argv == NULL)
633 633 uu_die(gettext("Out of memory.\n"));
634 634
635 635 for (slp = uu_list_first(args), i = 0;
636 636 slp != NULL;
637 637 slp = uu_list_next(args, slp), ++i)
638 638 argv[i] = slp->str;
639 639
640 640 argv[i] = NULL;
641 641
642 642 opterr = 0;
643 643 optind = 0; /* Remember, no argv[0]. */
644 644 for (;;) {
645 645 o = getopt(argc, argv, "np:V");
646 646 if (o == -1)
647 647 break;
648 648
649 649 switch (o) {
650 650 case 'n':
651 651 flags |= SCI_NOREFRESH;
652 652 break;
653 653
654 654 case 'p':
655 655 progress_file = optarg;
656 656 break;
657 657
658 658 case 'V':
659 659 validate = B_TRUE;
660 660 break;
661 661
662 662 case '?':
663 663 free(argv);
664 664 return (-2);
665 665
666 666 default:
667 667 bad_error("getopt", o);
668 668 }
669 669 }
670 670
671 671 argc -= optind;
672 672 if (argc < 1) {
673 673 free(argv);
674 674 return (-2);
675 675 }
676 676
677 677 /* Open device for progress messages */
678 678 if (progress_file != NULL) {
679 679 if (strcmp(progress_file, "-") == 0) {
680 680 progress_out = stdout;
681 681 } else {
682 682 progress_out = fopen(progress_file, "w");
683 683 if (progress_out == NULL) {
684 684 semerr(gettext("Unable to open %s for "
685 685 "progress reporting. %s\n"),
686 686 progress_file, strerror(errno));
687 687 goto out;
688 688 }
689 689 setbuf(progress_out, NULL);
690 690 }
691 691 }
692 692
693 693 paths = argv+optind;
694 694 manifest_sets = safe_malloc(argc * sizeof (*manifest_sets));
695 695
696 696 /* If we're in interactive mode, force strict validation. */
697 697 if (est->sc_cmd_flags & SC_CMD_IACTIVE)
698 698 validate = B_TRUE;
699 699
700 700 lscf_prep_hndl();
701 701
702 702 /* Determine which manifests must be imported. */
703 703
704 704 total_manifests = 0;
705 705 for (i = 0; i < argc; i++) {
706 706 file = *(paths + i);
707 707 fm_flags = CHECKHASH;
708 708
709 709 /* Determine if argument is a directory or file. */
710 710 if (stat(file, &sb) == -1) {
711 711 semerr(gettext("Unable to stat file %s. %s\n"), file,
712 712 strerror(errno));
713 713 goto out;
714 714 }
715 715 if (sb.st_mode & S_IFDIR) {
716 716 fm_flags |= CHECKEXT;
717 717 dirarg = 1;
718 718 isdir = 1;
719 719 } else if (sb.st_mode & S_IFREG) {
720 720 isdir = 0;
721 721 } else {
722 722 semerr(gettext("%s is not a directory or regular "
723 723 "file\n"), file);
724 724 goto out;
725 725 }
726 726
727 727 /* Get list of manifests that we should import for this path. */
728 728 if ((count = find_manifests(g_hndl, file, &manifests,
729 729 fm_flags)) < 0) {
730 730 if (isdir) {
731 731 semerr(gettext("Could not hash directory %s\n"),
732 732 file);
733 733 } else {
734 734 semerr(gettext("Could not hash file %s\n"),
735 735 file);
736 736 }
737 737 free_manifest_array(manifests);
738 738 goto out;
739 739 }
740 740 total_manifests += count;
741 741 manifest_sets[i] = manifests;
742 742 }
743 743
744 744 if (total_manifests == 0) {
745 745 /* No manifests to process. */
746 746 if (g_verbose) {
747 747 warn(gettext("No changes were necessary\n"));
748 748 }
749 749 rc = 1;
750 750 goto out;
751 751 }
752 752
753 753 /*
754 754 * If we're processing more than one file, we don't want to exit if
755 755 * we encounter an error. We should go ahead and process all of
756 756 * the manifests.
757 757 */
758 758 dont_exit = est->sc_cmd_flags & SC_CMD_DONT_EXIT;
759 759 if (total_manifests > 1)
760 760 est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
761 761
762 762 if (progress_out != NULL)
763 763 (void) fprintf(progress_out,
764 764 "Loading smf(5) service descriptions: ");
765 765
766 766 failed_manifests = 0;
767 767 progress_count = 0;
768 768 for (i = 0; i < argc; i++) {
769 769 manifests = manifest_sets[i];
770 770 if (manifests == NULL)
771 771 continue;
772 772 for (; *manifests != NULL; manifests++) {
773 773 progress_count++;
774 774 if (progress_out != NULL) {
775 775 back_count = fprintf(progress_out, "%d/%d",
776 776 progress_count, total_manifests);
777 777 while (back_count-- > 0) {
778 778 (void) fputc('\b', progress_out);
779 779 }
780 780 }
781 781 if (import_manifest_file(*manifests, validate,
782 782 progress_out, flags) != 0) {
783 783 failed_manifests++;
784 784 }
785 785 }
786 786 }
787 787 if (progress_out != NULL)
788 788 (void) fputc('\n', progress_out);
789 789
790 790 if ((total_manifests > 1) && (dont_exit == 0))
791 791 est->sc_cmd_flags &= ~SC_CMD_DONT_EXIT;
792 792
793 793 if (dirarg && total_manifests > 0) {
794 794 char *msg;
795 795
796 796 msg = "Loaded %d smf(5) service descriptions\n";
797 797 warn(gettext(msg), progress_count);
798 798
799 799 if (failed_manifests) {
800 800 msg = "%d smf(5) service descriptions failed to load\n";
801 801 warn(gettext(msg), failed_manifests);
802 802 }
803 803 }
804 804
805 805 if (failed_manifests > 0)
806 806 goto out;
807 807
808 808 if (g_verbose)
809 809 warn(gettext("Successful import.\n"));
810 810 rc = 0;
811 811
812 812 out:
813 813 if ((progress_out != NULL) && (progress_out != stdout))
814 814 (void) fclose(progress_out);
815 815 free(argv);
816 816 if (manifest_sets != NULL) {
817 817 for (i = 0; i < argc; i++) {
818 818 free_manifest_array(manifest_sets[i]);
819 819 }
820 820 free(manifest_sets);
821 821 }
822 822 return (rc);
823 823 }
824 824
825 825 /*
826 826 * Walk each service and get its manifest file.
827 827 *
↓ open down ↓ |
827 lines elided |
↑ open up ↑ |
828 828 * If the file exists check instance support, and cleanup any
829 829 * stale instances.
830 830 *
831 831 * If the file doesn't exist tear down the service and/or instances
832 832 * that are no longer supported by files.
833 833 */
834 834 int
835 835 engine_cleanup(int flags)
836 836 {
837 837 boolean_t activity = B_TRUE;
838 + int dont_exit;
838 839 int r = -1;
839 840
840 841 lscf_prep_hndl();
841 842
842 843 if (flags == 1) {
843 844 activity = B_FALSE;
844 845 }
845 846
847 + dont_exit = est->sc_cmd_flags & SC_CMD_DONT_EXIT;
848 + est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
849 +
846 850 if (scf_walk_fmri(g_hndl, 0, NULL, SCF_WALK_SERVICE|SCF_WALK_NOINSTANCE,
847 851 lscf_service_cleanup, (void *)activity, NULL,
848 852 uu_warn) == SCF_SUCCESS)
849 853 r = 0;
854 +
855 + if (dont_exit == 0)
856 + est->sc_cmd_flags &= ~SC_CMD_DONT_EXIT;
850 857
851 858 (void) lscf_hash_cleanup();
852 859
853 860 return (r);
854 861 }
855 862
856 863 static int
857 864 apply_profile(manifest_info_t *info, int apply_changes)
858 865 {
859 866 bundle_t *b = internal_bundle_new();
860 867
861 868 if (lxml_get_bundle_file(b, info->mi_path, SVCCFG_OP_APPLY) != 0) {
862 869 internal_bundle_free(b);
863 870 return (-1);
864 871 }
865 872
866 873 if (!apply_changes) { /* we don't want to apply, just test */
867 874 internal_bundle_free(b);
868 875 return (0);
869 876 }
870 877
871 878 if (lscf_bundle_apply(b, info->mi_path) != 0) {
872 879 internal_bundle_free(b);
873 880 return (-1);
874 881 }
875 882
876 883 internal_bundle_free(b);
877 884
878 885 if (info->mi_prop) {
879 886 apply_action_t apply;
880 887 char *errstr;
881 888
882 889 apply = (est->sc_in_emi == 1) ? APPLY_LATE : APPLY_NONE;
883 890 if (mhash_store_entry(g_hndl, info->mi_prop, info->mi_path,
884 891 info->mi_hash, apply, &errstr)) {
885 892 semerr(errstr);
886 893 }
887 894 }
888 895
889 896 return (0);
890 897 }
891 898
892 899 int
893 900 engine_apply(const char *file, int apply_changes)
894 901 {
895 902 int rc = 0;
896 903 int isdir;
897 904 int dont_exit;
898 905 int profile_count;
899 906 int fm_flags;
900 907 struct stat sb;
901 908 manifest_info_t **profiles = NULL;
902 909 manifest_info_t **entry;
903 910 manifest_info_t *pfile;
904 911
905 912 lscf_prep_hndl();
906 913
907 914 /* Determine which profile(s) must be applied. */
908 915
909 916 profile_count = 0;
910 917 fm_flags = BUNDLE_PROF | CHECKHASH;
911 918
912 919 /* Determine if argument is a directory or file. */
913 920 if (stat(file, &sb) == -1) {
914 921 semerr(gettext("Unable to stat file %s. %s\n"), file,
915 922 strerror(errno));
916 923 rc = -1;
917 924 goto out;
918 925 }
919 926
920 927 if (sb.st_mode & S_IFDIR) {
921 928 fm_flags |= CHECKEXT;
922 929 isdir = 1;
923 930 } else if (sb.st_mode & S_IFREG) {
924 931 isdir = 0;
925 932 } else {
926 933 semerr(gettext("%s is not a directory or regular "
927 934 "file\n"), file);
928 935 rc = -1;
929 936 goto out;
930 937 }
931 938
932 939 /* Get list of profiles to be applied. */
933 940 if ((profile_count = find_manifests(g_hndl, file, &profiles,
934 941 fm_flags)) < 0) {
935 942
936 943 if (isdir) {
937 944 semerr(gettext("Could not hash directory %s\n"), file);
938 945 } else {
939 946 semerr(gettext("Could not hash file %s\n"), file);
940 947 }
941 948 rc = -1;
942 949 goto out;
943 950 }
944 951
945 952 if (profile_count == 0) {
946 953 /* No profiles to process. */
947 954 if (g_verbose) {
948 955 warn(gettext("No changes were necessary\n"));
949 956 }
950 957 goto out;
951 958 }
952 959
953 960 /*
954 961 * We don't want to exit if we encounter an error. We should go ahead
955 962 * and process all of the profiles.
956 963 */
957 964 dont_exit = est->sc_cmd_flags & SC_CMD_DONT_EXIT;
958 965 est->sc_cmd_flags |= SC_CMD_DONT_EXIT;
959 966
960 967 for (entry = profiles; *entry != NULL; entry++) {
961 968 pfile = *entry;
962 969
963 970 if (apply_profile(pfile, apply_changes) == 0) {
964 971 if (g_verbose) {
965 972 warn(gettext("Successfully applied: %s\n"),
966 973 pfile->mi_path);
967 974 }
968 975 } else {
969 976 warn(gettext("WARNING: Failed to apply %s\n"),
970 977 pfile->mi_path);
971 978 rc = -1;
972 979 }
973 980 }
974 981
975 982 if (dont_exit == 0)
976 983 est->sc_cmd_flags &= ~SC_CMD_DONT_EXIT;
977 984
978 985 /* exit(1) appropriately if any profile failed to be applied. */
979 986 if ((rc == -1) &&
980 987 (est->sc_cmd_flags & (SC_CMD_IACTIVE | SC_CMD_DONT_EXIT)) == 0) {
981 988 free_manifest_array(profiles);
982 989 exit(1);
983 990 }
984 991
985 992 out:
986 993 free_manifest_array(profiles);
987 994 return (rc);
988 995 }
989 996
990 997 int
991 998 engine_restore(const char *file)
992 999 {
993 1000 bundle_t *b;
994 1001
995 1002 lscf_prep_hndl();
996 1003
997 1004 b = internal_bundle_new();
998 1005
999 1006 if (lxml_get_bundle_file(b, file, SVCCFG_OP_RESTORE) != 0) {
1000 1007 internal_bundle_free(b);
1001 1008 return (-1);
1002 1009 }
1003 1010
1004 1011 if (lscf_bundle_import(b, file, SCI_NOSNAP) != 0) {
1005 1012 internal_bundle_free(b);
1006 1013 return (-1);
1007 1014 }
1008 1015
1009 1016 internal_bundle_free(b);
1010 1017
1011 1018 return (0);
1012 1019 }
1013 1020
1014 1021 int
1015 1022 engine_set(uu_list_t *args)
1016 1023 {
1017 1024 uu_list_walk_t *walk;
1018 1025 string_list_t *slp;
1019 1026
1020 1027 if (uu_list_first(args) == NULL) {
1021 1028 /* Display current options. */
1022 1029 if (!g_verbose)
1023 1030 (void) fputs("no", stdout);
1024 1031 (void) puts("verbose");
1025 1032
1026 1033 return (0);
1027 1034 }
1028 1035
1029 1036 walk = uu_list_walk_start(args, UU_DEFAULT);
1030 1037 if (walk == NULL)
1031 1038 uu_die(gettext("Couldn't read arguments"));
1032 1039
1033 1040 /* Use getopt? */
1034 1041 for (slp = uu_list_walk_next(walk);
1035 1042 slp != NULL;
1036 1043 slp = uu_list_walk_next(walk)) {
1037 1044 if (slp->str[0] == '-') {
1038 1045 char *op;
1039 1046
1040 1047 for (op = &slp->str[1]; *op != '\0'; ++op) {
1041 1048 switch (*op) {
1042 1049 case 'v':
1043 1050 g_verbose = 1;
1044 1051 break;
1045 1052
1046 1053 case 'V':
1047 1054 g_verbose = 0;
1048 1055 break;
1049 1056
1050 1057 default:
1051 1058 warn(gettext("Unknown option -%c.\n"),
1052 1059 *op);
1053 1060 }
1054 1061 }
1055 1062 } else {
1056 1063 warn(gettext("No non-flag arguments defined.\n"));
1057 1064 }
1058 1065 }
1059 1066
1060 1067 return (0);
1061 1068 }
1062 1069
1063 1070 void
1064 1071 help(int com)
1065 1072 {
1066 1073 int i;
1067 1074
1068 1075 if (com == 0) {
1069 1076 warn(gettext("General commands: help set repository end\n"
1070 1077 "Manifest commands: inventory validate import export "
1071 1078 "archive\n"
1072 1079 "Profile commands: apply extract\n"
1073 1080 "Entity commands: list select unselect add delete "
1074 1081 "describe\n"
1075 1082 "Snapshot commands: listsnap selectsnap revert\n"
1076 1083 "Instance commands: refresh\n"
1077 1084 "Property group commands: listpg addpg delpg\n"
1078 1085 "Property commands: listprop setprop delprop editprop\n"
1079 1086 "Property value commands: addpropvalue delpropvalue "
1080 1087 "setenv unsetenv\n"
1081 1088 "Notification parameters: "
1082 1089 "listnotify setnotify delnotify\n"));
1083 1090 return;
1084 1091 }
1085 1092
1086 1093 for (i = 0; help_messages[i].message != NULL; ++i) {
1087 1094 if (help_messages[i].token == com) {
1088 1095 warn(gettext("Usage: %s\n"),
1089 1096 gettext(help_messages[i].message));
1090 1097 return;
1091 1098 }
1092 1099 }
1093 1100
1094 1101 warn(gettext("Unknown command.\n"));
1095 1102 }
↓ open down ↓ |
236 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX