Print this page
12721 would like svcadm disable -c

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/svc/svcadm/svcadm.c
          +++ new/usr/src/cmd/svc/svcadm/svcadm.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  /*
  27      - * Copyright 2015, Joyent, Inc. All rights reserved.
       27 + * Copyright 2020, Joyent, Inc. All rights reserved.
  28   28   */
  29   29  
  30   30  /*
  31   31   * svcadm - request adminstrative actions for service instances
  32   32   */
  33   33  
  34   34  #include <locale.h>
  35   35  #include <libintl.h>
  36   36  #include <libscf.h>
  37   37  #include <libscf_priv.h>
↓ open down ↓ 37 lines elided ↑ open up ↑
  75   75          uu_panic("%s:%d: %s() failed with unexpected error %d.\n",      \
  76   76              __FILE__, __LINE__, (func), (err));
  77   77  
  78   78  struct ht_elt {
  79   79          struct ht_elt   *next;
  80   80          boolean_t       active;
  81   81          char            str[1];
  82   82  };
  83   83  
  84   84  
       85 +/*
       86 + * Callback data for enable/disable.
       87 + */
       88 +#define SET_ENABLED     0x1
       89 +#define SET_TEMPORARY   0x2
       90 +#define SET_RECURSIVE   0x4
       91 +
       92 +typedef struct {
       93 +        char ed_comment[SCF_COMMENT_MAX_LENGTH];
       94 +        int ed_flags;
       95 +} enable_data_t;
       96 +
       97 +
  85   98  scf_handle_t *h;
  86   99  ssize_t max_scf_fmri_sz;
  87  100  static const char *emsg_permission_denied;
  88  101  static const char *emsg_nomem;
  89  102  static const char *emsg_create_pg_perm_denied;
  90  103  static const char *emsg_pg_perm_denied;
  91  104  static const char *emsg_prop_perm_denied;
  92  105  static const char *emsg_no_service;
  93  106  
  94  107  static int exit_status = 0;
↓ open down ↓ 44 lines elided ↑ open up ↑
 139  152  }
 140  153  
 141  154  #define scfdie()        do_scfdie(__LINE__)
 142  155  
 143  156  static void
 144  157  usage()
 145  158  {
 146  159          (void) fprintf(stderr, gettext(
 147  160          "Usage: %1$s [-S <state>] [-v] [-Z | -z zone] [cmd [args ... ]]\n\n"
 148  161          "\t%1$s enable [-rst] [<service> ...]\t- enable and online service(s)\n"
 149      -        "\t%1$s disable [-st] [<service> ...]\t- disable and offline "
      162 +        "\t%1$s disable [-c comment] [-st] [<service> ...] - disable "
 150  163          "service(s)\n"
 151  164          "\t%1$s restart [-d] [<service> ...]\t- restart specified service(s)\n"
 152  165          "\t%1$s refresh [<service> ...]\t\t- re-read service configuration\n"
 153  166          "\t%1$s mark [-It] <state> [<service> ...] - set maintenance state\n"
 154  167          "\t%1$s clear [<service> ...]\t\t- clear maintenance state\n"
 155  168          "\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
 156  169          "\n\t"
 157  170          "Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
 158  171          "\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
 159  172          "\n"
↓ open down ↓ 400 lines elided ↑ open up ↑
 560  573                  uu_warn(gettext("%s: Could not set %s/%s: "
 561  574                      "my_ct_name failed.\n"), fmri,
 562  575                      SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI);
 563  576          }
 564  577  
 565  578  out:
 566  579          scf_pg_destroy(pg);
 567  580          return (ret);
 568  581  }
 569  582  
      583 +static int
      584 +delete_prop(const char *fmri, scf_instance_t *inst, const char *pgname,
      585 +    const char *propname)
      586 +{
      587 +        int r = scf_instance_delete_prop(inst, pgname, propname);
      588 +
      589 +        switch (r) {
      590 +        case 0:
      591 +                break;
      592 +
      593 +        case ECANCELED:
      594 +                uu_warn(emsg_no_service, fmri);
      595 +                break;
      596 +
      597 +        case EACCES:
      598 +                uu_warn(gettext("Could not delete %s/%s "
      599 +                    "property of %s: backend access denied.\n"),
      600 +                    pgname, propname, fmri);
      601 +                break;
      602 +
      603 +        case EROFS:
      604 +                uu_warn(gettext("Could not delete %s/%s "
      605 +                    "property of %s: backend is read-only.\n"),
      606 +                    pgname, propname, fmri);
      607 +                break;
      608 +
      609 +        default:
      610 +                bad_error("scf_instance_delete_prop", r);
      611 +        }
      612 +
      613 +        return (r);
      614 +}
      615 +
 570  616  /*
 571      - * Enable or disable inst, per enable.  If temp is true, set
 572      - * general_ovr/enabled.  Otherwise set general/enabled and delete
 573      - * general_ovr/enabled if it exists (order is important here: we don't want the
 574      - * enabled status to glitch).
      617 + * Returns 0, EPERM, or EROFS.
 575  618   */
      619 +static int
      620 +set_enabled_props(scf_propertygroup_t *pg, enable_data_t *ed)
      621 +{
      622 +        scf_transaction_entry_t *ent1;
      623 +        scf_transaction_entry_t *ent2;
      624 +        scf_transaction_t *tx;
      625 +        scf_value_t *v2;
      626 +        scf_value_t *v1;
      627 +        int ret = 0, r;
      628 +
      629 +        if ((tx = scf_transaction_create(h)) == NULL ||
      630 +            (ent1 = scf_entry_create(h)) == NULL ||
      631 +            (ent2 = scf_entry_create(h)) == NULL ||
      632 +            (v1 = scf_value_create(h)) == NULL ||
      633 +            (v2 = scf_value_create(h)) == NULL)
      634 +                scfdie();
      635 +
      636 +        for (;;) {
      637 +                if (scf_transaction_start(tx, pg) == -1) {
      638 +                        switch (scf_error()) {
      639 +                        case SCF_ERROR_PERMISSION_DENIED:
      640 +                                ret = EPERM;
      641 +                                goto out;
      642 +
      643 +                        case SCF_ERROR_BACKEND_READONLY:
      644 +                                ret = EROFS;
      645 +                                goto out;
      646 +
      647 +                        default:
      648 +                                scfdie();
      649 +                        }
      650 +                }
      651 +
      652 +                if (scf_transaction_property_change_type(tx, ent1,
      653 +                    SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN) != 0) {
      654 +                        if (scf_error() != SCF_ERROR_NOT_FOUND)
      655 +                                scfdie();
      656 +
      657 +                        if (scf_transaction_property_new(tx, ent1,
      658 +                            SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN) != 0)
      659 +                                scfdie();
      660 +                }
      661 +
      662 +                scf_value_set_boolean(v1, !!(ed->ed_flags & SET_ENABLED));
      663 +
      664 +                r = scf_entry_add_value(ent1, v1);
      665 +                assert(r == 0);
      666 +
      667 +                if (scf_transaction_property_change_type(tx, ent2,
      668 +                    SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0) {
      669 +                        if (scf_error() != SCF_ERROR_NOT_FOUND)
      670 +                                scfdie();
      671 +
      672 +                        if (scf_transaction_property_new(tx, ent2,
      673 +                            SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0)
      674 +                                scfdie();
      675 +                }
      676 +
      677 +                if (scf_value_set_astring(v2, ed->ed_comment) != SCF_SUCCESS)
      678 +                        scfdie();
      679 +
      680 +                if (scf_entry_add_value(ent2, v2) != SCF_SUCCESS)
      681 +                        scfdie();
      682 +
      683 +                r = scf_transaction_commit(tx);
      684 +                if (r == 1)
      685 +                        break;
      686 +
      687 +                scf_transaction_reset(tx);
      688 +
      689 +                if (r != 0) {
      690 +                        switch (scf_error()) {
      691 +                        case SCF_ERROR_PERMISSION_DENIED:
      692 +                                ret = EPERM;
      693 +                                goto out;
      694 +
      695 +                        case SCF_ERROR_BACKEND_READONLY:
      696 +                                ret = EROFS;
      697 +                                goto out;
      698 +
      699 +                        default:
      700 +                                scfdie();
      701 +                        }
      702 +                }
      703 +
      704 +                if (scf_pg_update(pg) == -1)
      705 +                        scfdie();
      706 +        }
      707 +
      708 +out:
      709 +        scf_transaction_destroy(tx);
      710 +        scf_entry_destroy(ent1);
      711 +        scf_entry_destroy(ent2);
      712 +        scf_value_destroy(v1);
      713 +        scf_value_destroy(v2);
      714 +        return (ret);
      715 +}
      716 +
      717 +/*
      718 + * Enable or disable an instance.  SET_TEMPORARY modifications apply to
      719 + * general_ovr/ property group.
      720 + */
 576  721  static void
 577      -set_inst_enabled(const char *fmri, scf_instance_t *inst, boolean_t temp,
 578      -    boolean_t enable)
      722 +set_inst_enabled(const char *fmri, scf_instance_t *inst, enable_data_t *ed)
 579  723  {
 580  724          scf_propertygroup_t *pg;
 581  725          uint8_t b;
 582  726          const char *pgname = NULL;      /* For emsg_pg_perm_denied */
 583      -        int r;
 584  727  
 585  728          pg = scf_pg_create(h);
 586  729          if (pg == NULL)
 587  730                  scfdie();
 588  731  
 589  732          if (restarter_setup(fmri, inst))
 590  733                  goto out;
 591  734  
 592  735          /*
 593  736           * An instance's configuration is incomplete if general/enabled
↓ open down ↓ 24 lines elided ↑ open up ↑
 618  761                                      "(repository read-only).\n"), fmri,
 619  762                                      SCF_PG_GENERAL, SCF_PROPERTY_ENABLED);
 620  763                          goto out;
 621  764  
 622  765                  default:
 623  766                          assert(0);
 624  767                          abort();
 625  768                  }
 626  769          }
 627  770  
 628      -        if (temp) {
 629      -                /* Set general_ovr/enabled */
      771 +        if (ed->ed_flags & SET_TEMPORARY) {
 630  772                  pgname = SCF_PG_GENERAL_OVR;
 631  773                  if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
 632  774                      SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
 633  775                          goto eperm;
 634  776  
 635      -                switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
      777 +                switch (set_enabled_props(pg, ed)) {
 636  778                  case 0:
 637  779                          break;
 638  780  
 639  781                  case EPERM:
 640  782                          goto eperm;
 641  783  
 642  784                  case EROFS:
 643  785                          /* Shouldn't happen, but it can. */
 644  786                          if (!verbose)
 645  787                                  uu_warn(gettext("%s: Repository read-only.\n"),
↓ open down ↓ 3 lines elided ↑ open up ↑
 649  791                                      "(repository read-only).\n"), fmri,
 650  792                                      SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
 651  793                          goto out;
 652  794  
 653  795                  default:
 654  796                          assert(0);
 655  797                          abort();
 656  798                  }
 657  799  
 658  800                  if (verbose)
 659      -                        (void) printf(enable ?
      801 +                        (void) printf((ed->ed_flags & SET_ENABLED) ?
 660  802                              gettext("%s temporarily enabled.\n") :
 661  803                              gettext("%s temporarily disabled.\n"), fmri);
 662  804          } else {
 663  805  again:
 664  806                  /*
 665  807                   * Both pg and property should exist since we created
 666  808                   * them earlier. However, there's still a chance that
 667  809                   * someone may have deleted the property out from under
 668  810                   * us.
 669  811                   */
 670  812                  if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
 671  813                      SCF_PG_GENERAL_FLAGS, pg) != 0)
 672  814                          goto eperm;
 673  815  
 674      -                switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
      816 +                switch (set_enabled_props(pg, ed)) {
 675  817                  case 0:
 676  818                          break;
 677  819  
 678  820                  case EPERM:
 679  821                          goto eperm;
 680  822  
 681  823                  case EROFS:
 682  824                          /*
 683  825                           * If general/enabled is already set the way we want,
 684  826                           * proceed.
 685  827                           */
 686  828                          switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
 687  829                          case 0:
 688      -                                if ((b != 0) == (enable != B_FALSE))
      830 +                                if (!(b) == !(ed->ed_flags & SET_ENABLED))
 689  831                                          break;
 690  832                                  /* FALLTHROUGH */
 691  833  
 692  834                          case ENOENT:
 693  835                          case EINVAL:
 694  836                          case E2BIG:
 695  837                                  if (!verbose)
 696  838                                          uu_warn(gettext("%s: Repository "
 697  839                                              "read-only.\n"), fmri);
 698  840                                  else
↓ open down ↓ 10 lines elided ↑ open up ↑
 709  851                                  assert(0);
 710  852                                  abort();
 711  853                          }
 712  854                          break;
 713  855  
 714  856                  default:
 715  857                          assert(0);
 716  858                          abort();
 717  859                  }
 718  860  
 719      -                pgname = SCF_PG_GENERAL_OVR;
 720      -                r = scf_instance_delete_prop(inst, pgname,
 721      -                    SCF_PROPERTY_ENABLED);
 722      -                switch (r) {
      861 +                switch (delete_prop(fmri, inst, SCF_PG_GENERAL_OVR,
      862 +                    SCF_PROPERTY_ENABLED)) {
 723  863                  case 0:
 724  864                          break;
 725  865  
 726      -                case ECANCELED:
 727      -                        uu_warn(emsg_no_service, fmri);
 728      -                        goto out;
 729      -
 730  866                  case EPERM:
 731  867                          goto eperm;
 732  868  
 733      -                case EACCES:
 734      -                        uu_warn(gettext("Could not delete %s/%s "
 735      -                            "property of %s: backend access denied.\n"),
 736      -                            pgname, SCF_PROPERTY_ENABLED, fmri);
      869 +                default:
 737  870                          goto out;
      871 +                }
 738  872  
 739      -                case EROFS:
 740      -                        uu_warn(gettext("Could not delete %s/%s "
 741      -                            "property of %s: backend is read-only.\n"),
 742      -                            pgname, SCF_PROPERTY_ENABLED, fmri);
 743      -                        goto out;
      873 +                switch (delete_prop(fmri, inst, SCF_PG_GENERAL_OVR,
      874 +                    SCF_PROPERTY_COMMENT)) {
      875 +                case 0:
      876 +                        break;
 744  877  
      878 +                case EPERM:
      879 +                        goto eperm;
      880 +
 745  881                  default:
 746      -                        bad_error("scf_instance_delete_prop", r);
      882 +                        goto out;
 747  883                  }
 748  884  
 749      -                if (verbose)
 750      -                        (void) printf(enable ?  gettext("%s enabled.\n") :
      885 +                if (verbose) {
      886 +                        (void) printf((ed->ed_flags & SET_ENABLED) ?
      887 +                            gettext("%s enabled.\n") :
 751  888                              gettext("%s disabled.\n"), fmri);
      889 +                }
 752  890          }
 753  891  
 754  892          scf_pg_destroy(pg);
 755  893          return;
 756  894  
 757  895  eperm:
 758  896          assert(pgname != NULL);
 759  897          if (!verbose)
 760  898                  uu_warn(emsg_permission_denied, fmri);
 761  899          else
↓ open down ↓ 245 lines elided ↑ open up ↑
1007 1145   * "active", so that if we come upon it again, we know we've hit a cycle.
1008 1146   * exclude_all and optional_all dependencies are ignored.  require_any
1009 1147   * dependencies are followed only if they comprise a single service; otherwise
1010 1148   * the user is warned.
1011 1149   *
1012 1150   * fmri must point to a writable max_scf_fmri_sz buffer.  Returns EINVAL if fmri
1013 1151   * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
1014 1152   * on cycle detection, or 0 on success.
1015 1153   */
1016 1154  static int
1017      -enable_fmri_rec(char *fmri, boolean_t temp)
     1155 +enable_fmri_rec(char *fmri, enable_data_t *ed)
1018 1156  {
1019 1157          scf_instance_t *inst;
1020 1158          scf_snapshot_t *snap;
1021 1159          scf_propertygroup_t *pg;
1022 1160          scf_property_t *prop;
1023 1161          scf_value_t *v;
1024 1162          scf_iter_t *pg_iter, *val_iter;
1025 1163          scf_type_t ty;
1026 1164          char *buf, *pgname;
1027 1165          ssize_t name_sz, len, sz;
↓ open down ↓ 33 lines elided ↑ open up ↑
1061 1199  
1062 1200          case E2BIG:
1063 1201                  he->active = B_FALSE;
1064 1202                  return (E2BIG);
1065 1203  
1066 1204          default:
1067 1205                  he->active = B_FALSE;
1068 1206                  return (0);
1069 1207          }
1070 1208  
1071      -        set_inst_enabled(fmri, inst, temp, B_TRUE);
     1209 +        set_inst_enabled(fmri, inst, ed);
1072 1210  
1073 1211          if ((snap = scf_snapshot_create(h)) == NULL ||
1074 1212              (pg = scf_pg_create(h)) == NULL ||
1075 1213              (prop = scf_property_create(h)) == NULL ||
1076 1214              (v = scf_value_create(h)) == NULL ||
1077 1215              (pg_iter = scf_iter_create(h)) == NULL ||
1078 1216              (val_iter = scf_iter_create(h)) == NULL)
1079 1217                  scfdie();
1080 1218  
1081 1219          buf = malloc(max_scf_fmri_sz);
↓ open down ↓ 29 lines elided ↑ open up ↑
1111 1249  
1112 1250          sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
1113 1251              max_scf_fmri_sz);
1114 1252          if (sz > max_scf_fmri_sz) {
1115 1253                  uu_warn(gettext("\"%s\" is misconfigured (the value of "
1116 1254                      "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
1117 1255                      SCF_PROPERTY_RESTARTER);
1118 1256                  ret = 0;
1119 1257                  goto out;
1120 1258          } else if (sz >= 0) {
1121      -                switch (enable_fmri_rec(buf, temp)) {
     1259 +                switch (enable_fmri_rec(buf, ed)) {
1122 1260                  case 0:
1123 1261                          break;
1124 1262  
1125 1263                  case EINVAL:
1126 1264                          uu_warn(gettext("Restarter FMRI for \"%s\" is "
1127 1265                              "invalid.\n"), fmri);
1128 1266                          break;
1129 1267  
1130 1268                  case E2BIG:
1131 1269                          uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
↓ open down ↓ 130 lines elided ↑ open up ↑
1262 1400                          ret = scf_iter_next_value(val_iter, v);
1263 1401                          if (ret == 0)
1264 1402                                  break;
1265 1403                          if (ret != 1)
1266 1404                                  scfdie();
1267 1405  
1268 1406                          if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
1269 1407                              -1)
1270 1408                                  scfdie();
1271 1409  
1272      -                        switch (enable_fmri_rec(buf, temp)) {
     1410 +                        switch (enable_fmri_rec(buf, ed)) {
1273 1411                          case 0:
1274 1412                                  break;
1275 1413  
1276 1414                          case EINVAL:
1277 1415                                  uu_warn(gettext("\"%s\" dependency of \"%s\" "
1278 1416                                      "has invalid FMRI \"%s\".\n"), pgname,
1279 1417                                      fmri, buf);
1280 1418                                  break;
1281 1419  
1282 1420                          case E2BIG:
↓ open down ↓ 378 lines elided ↑ open up ↑
1661 1799  out:
1662 1800          scf_transaction_destroy(tx);
1663 1801          scf_entry_destroy(txent);
1664 1802          scf_value_destroy(val);
1665 1803          scf_property_destroy(prop);
1666 1804          scf_pg_destroy(pg);
1667 1805          scf_instance_destroy(inst);
1668 1806  }
1669 1807  
1670 1808  
1671      -/*
1672      - * Flags to control enable and disable actions.
1673      - */
1674      -#define SET_ENABLED     0x1
1675      -#define SET_TEMPORARY   0x2
1676      -#define SET_RECURSIVE   0x4
1677      -
1678 1809  static int
1679 1810  set_fmri_enabled(void *data, scf_walkinfo_t *wip)
1680 1811  {
1681      -        int flags = (int)data;
     1812 +        enable_data_t *ed = data;
1682 1813  
1683 1814          assert(wip->inst != NULL);
1684 1815          assert(wip->pg == NULL);
1685 1816  
1686 1817          if (svcsearch) {
1687 1818                  char state[MAX_SCF_STATE_STRING_SZ];
1688 1819  
1689 1820                  if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
1690 1821                          return (0);
1691 1822                  if (strcmp(state, svcstate) != 0)
1692 1823                          return (0);
1693 1824          }
1694 1825  
1695      -        if (flags & SET_RECURSIVE) {
     1826 +        if (ed->ed_flags & SET_RECURSIVE) {
1696 1827                  char *fmri_buf = malloc(max_scf_fmri_sz);
1697 1828                  if (fmri_buf == NULL)
1698 1829                          uu_die(emsg_nomem);
1699 1830  
1700 1831                  visited = calloc(HT_BUCKETS, sizeof (*visited));
1701 1832                  if (visited == NULL)
1702 1833                          uu_die(emsg_nomem);
1703 1834  
1704 1835                  /* scf_walk_fmri() guarantees that fmri isn't too long */
1705 1836                  assert(strlen(wip->fmri) <= max_scf_fmri_sz);
1706 1837                  (void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
1707 1838  
1708      -                switch (enable_fmri_rec(fmri_buf, (flags & SET_TEMPORARY))) {
     1839 +                switch (enable_fmri_rec(fmri_buf, ed)) {
1709 1840                  case E2BIG:
1710 1841                          uu_warn(gettext("operation on service %s is ambiguous; "
1711 1842                              "instance specification needed.\n"), fmri_buf);
1712 1843                          break;
1713 1844  
1714 1845                  case ELOOP:
1715 1846                          uu_warn(gettext("%s: Dependency cycle detected.\n"),
1716 1847                              fmri_buf);
1717 1848                  }
1718 1849  
1719 1850                  free(visited);
1720 1851                  free(fmri_buf);
1721 1852  
1722 1853          } else {
1723      -                set_inst_enabled(wip->fmri, wip->inst,
1724      -                    (flags & SET_TEMPORARY) != 0, (flags & SET_ENABLED) != 0);
     1854 +                set_inst_enabled(wip->fmri, wip->inst, ed);
1725 1855          }
1726 1856  
1727 1857          return (0);
1728 1858  }
1729 1859  
1730 1860  /* ARGSUSED */
1731 1861  static int
1732 1862  wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
1733 1863  {
1734 1864          scf_propertygroup_t *pg = NULL;
↓ open down ↓ 230 lines elided ↑ open up ↑
1965 2095          set_inst_action(wip->fmri, wip->inst, prop);
1966 2096  
1967 2097          return (0);
1968 2098  }
1969 2099  
1970 2100  static void
1971 2101  set_milestone(const char *fmri, boolean_t temporary)
1972 2102  {
1973 2103          scf_instance_t *inst;
1974 2104          scf_propertygroup_t *pg;
1975      -        int r;
1976 2105  
1977 2106          if (temporary) {
1978 2107                  set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
1979 2108                      SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
1980 2109                      SCF_PROPERTY_MILESTONE, fmri);
1981 2110                  return;
1982 2111          }
1983 2112  
1984 2113          if ((inst = scf_instance_create(h)) == NULL ||
1985 2114              (pg = scf_pg_create(h)) == NULL)
↓ open down ↓ 5 lines elided ↑ open up ↑
1991 2120          }
1992 2121  
1993 2122          /*
1994 2123           * Set the persistent milestone before deleting the override so we don't
1995 2124           * glitch.
1996 2125           */
1997 2126          set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
1998 2127              SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
1999 2128              fmri);
2000 2129  
2001      -        r = scf_instance_delete_prop(inst, SCF_PG_OPTIONS_OVR,
2002      -            SCF_PROPERTY_MILESTONE);
2003      -        switch (r) {
2004      -        case 0:
2005      -                break;
2006      -
2007      -        case ECANCELED:
2008      -                uu_warn(emsg_no_service, fmri);
     2130 +        if (delete_prop(SCF_SERVICE_STARTD, inst, SCF_PG_OPTIONS_OVR,
     2131 +            SCF_PROPERTY_MILESTONE) != 0)
2009 2132                  exit_status = 1;
2010      -                goto out;
2011 2133  
2012      -        case EPERM:
2013      -                uu_warn(gettext("Could not delete %s/%s property of "
2014      -                    "%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
2015      -                    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
2016      -                exit_status = 1;
2017      -                goto out;
2018      -
2019      -        case EACCES:
2020      -                uu_warn(gettext("Could not delete %s/%s property of "
2021      -                    "%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
2022      -                    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
2023      -                exit_status = 1;
2024      -                goto out;
2025      -
2026      -        case EROFS:
2027      -                uu_warn(gettext("Could not delete %s/%s property of "
2028      -                    "%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
2029      -                    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
2030      -                exit_status = 1;
2031      -                goto out;
2032      -
2033      -        default:
2034      -                bad_error("scf_instance_delete_prop", r);
2035      -        }
2036      -
2037      -out:
2038 2134          scf_pg_destroy(pg);
2039 2135          scf_instance_destroy(inst);
2040 2136  }
2041 2137  
2042 2138  static char const *milestones[] = {
2043 2139          SCF_MILESTONE_SINGLE_USER,
2044 2140          SCF_MILESTONE_MULTI_USER,
2045 2141          SCF_MILESTONE_MULTI_USER_SERVER,
2046 2142          NULL
2047 2143  };
↓ open down ↓ 260 lines elided ↑ open up ↑
2308 2404          }
2309 2405  
2310 2406          optind = orig_optind;
2311 2407          argc = orig_argc;
2312 2408          argv = orig_argv;
2313 2409  
2314 2410          if (optind >= argc)
2315 2411                  usage();
2316 2412  
2317 2413          if (strcmp(argv[optind], "enable") == 0) {
2318      -                int flags = SET_ENABLED;
     2414 +                enable_data_t ed = {
     2415 +                        .ed_flags = SET_ENABLED,
     2416 +                        .ed_comment = ""
     2417 +                };
2319 2418                  int wait = 0;
2320 2419                  int error = 0;
2321 2420  
2322 2421                  ++optind;
2323 2422  
2324 2423                  while ((o = getopt(argc, argv, "rst")) != -1) {
2325 2424                          if (o == 'r')
2326      -                                flags |= SET_RECURSIVE;
     2425 +                                ed.ed_flags |= SET_RECURSIVE;
2327 2426                          else if (o == 't')
2328      -                                flags |= SET_TEMPORARY;
     2427 +                                ed.ed_flags |= SET_TEMPORARY;
2329 2428                          else if (o == 's')
2330 2429                                  wait = 1;
2331 2430                          else if (o == '?')
2332 2431                                  usage();
2333 2432                          else {
2334 2433                                  assert(0);
2335 2434                                  abort();
2336 2435                          }
2337 2436                  }
2338 2437                  argc -= optind;
↓ open down ↓ 5 lines elided ↑ open up ↑
2344 2443                  if (argc > 0 && svcsearch)
2345 2444                          usage();
2346 2445  
2347 2446                  /*
2348 2447                   * We want to continue with -s processing if we had
2349 2448                   * invalid options, but not if an enable failed.  We
2350 2449                   * squelch output the second time we walk fmris; we saw
2351 2450                   * the errors the first time.
2352 2451                   */
2353 2452                  if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2354      -                    set_fmri_enabled, (void *)flags, &error, pr_warn)) != 0) {
     2453 +                    set_fmri_enabled, &ed, &error, pr_warn)) != 0) {
2355 2454  
2356 2455                          pr_warn(gettext("failed to iterate over "
2357 2456                              "instances: %s\n"), scf_strerror(err));
2358 2457                          exit_status = UU_EXIT_FATAL;
2359 2458  
2360 2459                  } else if (wait && exit_status == 0 &&
2361 2460                      (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2362      -                    wait_fmri_enabled, (void *)flags, &error, quiet)) != 0) {
     2461 +                    wait_fmri_enabled, NULL, &error, quiet)) != 0) {
2363 2462  
2364 2463                          pr_warn(gettext("failed to iterate over "
2365 2464                              "instances: %s\n"), scf_strerror(err));
2366 2465                          exit_status = UU_EXIT_FATAL;
2367 2466                  }
2368 2467  
2369 2468                  if (error > 0)
2370 2469                          exit_status = error;
2371 2470  
2372 2471          } else if (strcmp(argv[optind], "disable") == 0) {
2373      -                int flags = 0;
     2472 +                enable_data_t ed = {
     2473 +                        .ed_flags = 0,
     2474 +                        .ed_comment = ""
     2475 +                };
2374 2476                  int wait = 0;
2375 2477                  int error = 0;
2376 2478  
2377 2479                  ++optind;
2378 2480  
2379      -                while ((o = getopt(argc, argv, "st")) != -1) {
2380      -                        if (o == 't')
2381      -                                flags |= SET_TEMPORARY;
     2481 +                while ((o = getopt(argc, argv, "c:st")) != -1) {
     2482 +                        if (o == 'c') {
     2483 +                                if (strlcpy(ed.ed_comment, optarg,
     2484 +                                    sizeof (ed.ed_comment)) >=
     2485 +                                    sizeof (ed.ed_comment)) {
     2486 +                                        uu_die(gettext("disable -c comment "
     2487 +                                            "too long.\n"));
     2488 +                                }
     2489 +                        } else if (o == 't')
     2490 +                                ed.ed_flags |= SET_TEMPORARY;
2382 2491                          else if (o == 's')
2383 2492                                  wait = 1;
2384 2493                          else if (o == '?')
2385 2494                                  usage();
2386 2495                          else {
2387 2496                                  assert(0);
2388 2497                                  abort();
2389 2498                          }
2390 2499                  }
2391 2500                  argc -= optind;
↓ open down ↓ 5 lines elided ↑ open up ↑
2397 2506                  if (argc > 0 && svcsearch)
2398 2507                          usage();
2399 2508  
2400 2509                  /*
2401 2510                   * We want to continue with -s processing if we had
2402 2511                   * invalid options, but not if a disable failed.  We
2403 2512                   * squelch output the second time we walk fmris; we saw
2404 2513                   * the errors the first time.
2405 2514                   */
2406 2515                  if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2407      -                    set_fmri_enabled, (void *)flags, &exit_status,
     2516 +                    set_fmri_enabled, &ed, &exit_status,
2408 2517                      pr_warn)) != 0) {
2409 2518  
2410 2519                          pr_warn(gettext("failed to iterate over "
2411 2520                              "instances: %s\n"), scf_strerror(err));
2412 2521                          exit_status = UU_EXIT_FATAL;
2413 2522  
2414 2523                  } else if (wait && exit_status == 0 &&
2415 2524                      (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2416      -                    wait_fmri_disabled, (void *)flags, &error, quiet)) != 0) {
     2525 +                    wait_fmri_disabled, NULL, &error, quiet)) != 0) {
2417 2526  
2418 2527                          pr_warn(gettext("failed to iterate over "
2419 2528                              "instances: %s\n"), scf_strerror(err));
2420 2529                          exit_status = UU_EXIT_FATAL;
2421 2530                  }
2422 2531  
2423 2532                  if (error > 0)
2424 2533                          exit_status = error;
2425 2534  
2426 2535          } else if (strcmp(argv[optind], "restart") == 0) {
↓ open down ↓ 258 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX