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