1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <stdio.h>
  28 #include <stdlib.h>
  29 #include <locale.h>
  30 #include <sys/param.h>
  31 #include <fcntl.h>
  32 #include <sys/types.h>
  33 #include <sys/stat.h>
  34 #include <unistd.h>
  35 #include <string.h>
  36 #include <sys/socket.h>
  37 #include <netinet/in.h>
  38 #include <arpa/inet.h>
  39 #include <netdb.h>
  40 #include <errno.h>
  41 
  42 #include "installadm.h"
  43 
  44 typedef int cmdfunc_t(int, char **, scfutilhandle_t *, const char *);
  45 
  46 static cmdfunc_t do_create_service, do_delete_service;
  47 static cmdfunc_t do_list, do_enable, do_disable;
  48 static cmdfunc_t do_create_client, do_delete_client;
  49 static cmdfunc_t do_add, do_remove, do_help;
  50 static void do_opterr(int, int, const char *);
  51 static char *progname;
  52 static void smf_service_enable_attempt(char *);
  53 static boolean_t check_for_enabled_install_services(scfutilhandle_t *);
  54 static boolean_t enable_install_service(scfutilhandle_t *, char *);
  55 
  56 char    instance[sizeof (INSTALL_SERVER_FMRI_BASE) +
  57             sizeof (INSTALL_SERVER_DEF_INST) + 1];
  58 
  59 typedef struct cmd {
  60         char            *c_name;
  61         cmdfunc_t       *c_fn;
  62         const char      *c_usage;
  63         boolean_t       c_priv_reqd;
  64 } cmd_t;
  65 
  66 static cmd_t    cmds[] = {
  67         { "create-service",             do_create_service,
  68             "\tcreate-service\t[-f <bootfile>] [-n <svcname>]\n"
  69             "\t\t\t[-i <dhcp_ip_start>] [-c <count_of_ipaddr>]\n"
  70             "\t\t\t[-s <srcimage>] <targetdir>",
  71             PRIV_REQD                                                   },
  72 
  73         { "delete-service",     do_delete_service,
  74             "\tdelete-service\t[-x] <svcname>",
  75             PRIV_REQD                                                   },
  76 
  77         { "list",       do_list,
  78             "\tlist\t[-n <svcname>]",
  79             PRIV_NOT_REQD                                               },
  80 
  81         { "enable",     do_enable,
  82             "\tenable\t<svcname>",
  83             PRIV_REQD                                                   },
  84 
  85         { "disable",    do_disable,
  86             "\tdisable\t[-t] <svcname>",
  87             PRIV_REQD                                                   },
  88 
  89         { "create-client",      do_create_client,
  90             "\tcreate-client\t[-b <property>=<value>,...] \n"
  91             "\t\t\t-e <macaddr> -n <svcname> [-t <imagepath>]",
  92             PRIV_REQD                                                   },
  93 
  94         { "delete-client",      do_delete_client,
  95             "\tdelete-client\t<macaddr>",
  96             PRIV_REQD                                                   },
  97 
  98         { "add",        do_add,
  99             "\tadd\t-m <manifest> -n <svcname>",
 100             PRIV_REQD                                                   },
 101 
 102         { "remove",     do_remove,
 103             "\tremove\t-m <manifest> -n <svcname>",
 104             PRIV_REQD                                                   },
 105 
 106         { "help",       do_help,
 107             "\thelp\t[<subcommand>]",
 108             PRIV_NOT_REQD                                               }
 109 };
 110 
 111 static void
 112 usage(void)
 113 {
 114         int     i;
 115         cmd_t   *cmdp;
 116 
 117         (void) fprintf(stderr, MSG_INSTALLADM_USAGE);
 118         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
 119                 cmdp = &cmds[i];
 120                 if (cmdp->c_usage != NULL)
 121                         (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
 122         }
 123         exit(INSTALLADM_FAILURE);
 124 }
 125 
 126 
 127 int
 128 main(int argc, char *argv[])
 129 {
 130         int             i;
 131         cmd_t           *cmdp;
 132         scfutilhandle_t *handle;
 133 
 134         (void) setlocale(LC_ALL, "");
 135 
 136         /*
 137          * Must have at least one additional argument to installadm
 138          */
 139         if (argc < 2) {
 140                 usage();
 141         }
 142 
 143         progname = argv[0];
 144         (void) snprintf(instance, sizeof (instance), "%s:%s",
 145             INSTALL_SERVER_FMRI_BASE, INSTALL_SERVER_DEF_INST);
 146         /*
 147          * If it is valid subcommand, call the do_subcommand function
 148          * found in cmds. Pass it the subcommand's argc and argv, as
 149          * well as the smf handle and the subcommand specific usage.
 150          */
 151         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
 152                 int ret = 0;
 153                 cmdp = &cmds[i];
 154                 if (strcmp(argv[1], cmdp->c_name) == 0) {
 155                         if ((cmdp->c_priv_reqd) && (geteuid() > 0)) {
 156                                 (void) fprintf(stderr, MSG_ROOT_PRIVS_REQD,
 157                                     argv[0], cmdp->c_name);
 158                                 exit(INSTALLADM_FAILURE);
 159                         }
 160 
 161                         handle = ai_scf_init();
 162                         if (handle == NULL) {
 163                                 (void) fprintf(stderr, MSG_AI_SMF_INIT_FAIL);
 164                                 exit(INSTALLADM_FAILURE);
 165                         }
 166 
 167                         /*
 168                          * set the umask, for all subcommands to inherit
 169                          */
 170                         (void) umask(022);
 171 
 172                         if (cmdp->c_fn(argc - 1, &argv[1], handle,
 173                             cmdp->c_usage)) {
 174                                 ret = INSTALLADM_FAILURE;
 175                         } else {
 176                                 ret = INSTALLADM_SUCCESS;
 177                         }
 178 
 179                         /* clean-up SMF handle */
 180                         ai_scf_fini(handle);
 181                         exit(ret);
 182                 }
 183         }
 184 
 185         /*
 186          * Otherwise, give error and print usage
 187          */
 188         (void) fprintf(stderr, MSG_UNKNOWN_SUBCOMMAND,
 189             progname, argv[1]);
 190         usage();
 191 
 192         exit(INSTALLADM_FAILURE);
 193 }
 194 
 195 /*
 196  * get_ip_from_hostname:
 197  *
 198  * Description:
 199  *   Resolves given hostname to IPv4 address. Result is stored as string
 200  *   into given buffer. If more than one IP address is returned, the first
 201  *   one is picked.
 202  *
 203  * parameters:
 204  *   name        - simple or fully qualified hostname to be resolved
 205  *   ip_string   - pointer to string buffer where IP address will
 206  *                 be stored
 207  *   buffer_size - size of ip_string
 208  *
 209  * return:
 210  *   0  - success
 211  *   -1 - resolve process failed - string buffer is left untouched
 212  */
 213 static int
 214 get_ip_from_hostname(char *name, char *ip_string, int buffer_size)
 215 {
 216         struct hostent  *hp;
 217         struct in_addr  in;
 218 
 219         hp = gethostbyname(name);
 220         if (hp == NULL) {
 221                 return (-1);
 222         } else {
 223                 (void) memcpy(&in.s_addr, hp->h_addr_list[0],
 224                     sizeof (in.s_addr));
 225 
 226                 (void) snprintf(ip_string, buffer_size, "%s", inet_ntoa(in));
 227         }
 228 
 229         return (0);
 230 }
 231 
 232 static int
 233 call_script(char *scriptname, int argc, char *argv[])
 234 {
 235         int     i;
 236         char    cmd[BUFSIZ];
 237         char    cmdargs[BUFSIZ];
 238 
 239 
 240         cmdargs[0] = '\0';
 241         for (i = 0; i < argc; i++) {
 242                 (void) strcat(cmdargs, argv[i]);
 243                 (void) strcat(cmdargs, " ");
 244         }
 245 
 246         (void) snprintf(cmd, sizeof (cmd), "%s %s",
 247             scriptname, cmdargs);
 248 
 249         return (installadm_system(cmd));
 250 
 251 }
 252 
 253 /*
 254  * Function:    check_for_enabled_install_services
 255  * Description:
 256  *              Check to see if any of the install services are
 257  *              enabled. If not, the smf install/server service
 258  *              should be placed in maintenance.
 259  * Parameters:
 260  *              handle - scfutilhandle_t * for use with scf calls
 261  * Return:
 262  *              B_FALSE - Service not placed in maintenance.
 263  *              B_TRUE - No enabled services found. SMF service in maint.
 264  * Scope:
 265  *              Private
 266  */
 267 static boolean_t
 268 check_for_enabled_install_services(scfutilhandle_t *handle)
 269 {
 270         char            *value;
 271         ai_pg_list_t    *pg_list = NULL;
 272         ai_pg_list_t    *pg = NULL;
 273         char            *state;
 274 
 275         /*
 276          * Are there any install services still with status "on"?
 277          */
 278 
 279         /* get the list of property groups */
 280         if (ai_get_pgs(handle, &pg_list) != AI_SUCCESS) {
 281                 return (B_FALSE);
 282         }
 283         if ((pg = pg_list) == NULL) {
 284                 /*
 285                  * No property groups for install services. Put smf
 286                  * instance into maintenance.
 287                  */
 288                 goto out;
 289         }
 290         while (pg != NULL && pg->pg_name != NULL) {
 291                 /*
 292                  * for each property group read the status
 293                  */
 294                 if (ai_read_property(handle, pg->pg_name, SERVICE_STATUS,
 295                     &value) == AI_SUCCESS) {
 296                         if (strcmp(value, STATUS_ON) == 0) {
 297                                 /*
 298                                  * At least one is enabled. Return
 299                                  * without putting in maint.
 300                                  */
 301                                 free(value);
 302                                 ai_free_pg_list(pg_list);
 303                                 return (B_FALSE);
 304                         }
 305                 }
 306                 free(value);
 307                 pg = pg->next;
 308         }
 309         /*
 310          * No enabled install services. Put smf
 311          * instance into maintenance.
 312          */
 313         ai_free_pg_list(pg_list);
 314 out:
 315         state = smf_get_state(instance);
 316         if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
 317                 /*
 318                  * If the service is already in maintenance don't try
 319                  * to put it there and don't send the message saying
 320                  * you're doing so.
 321                  */
 322                 (void) fprintf(stderr, MSG_SERVER_SMF_DISABLED, instance);
 323                 return (B_FALSE);
 324         }
 325         (void) fprintf(stderr, MSG_SERVER_SMF_OFFLINE, instance);
 326 
 327         smf_maintain_instance(instance, SMF_IMMEDIATE);
 328         /*
 329          * Wait for it to really go into maintenance state.
 330          */
 331         do {
 332                 state = smf_get_state(instance);
 333         } while (strcmp(state, SCF_STATE_STRING_MAINT) != 0);
 334 
 335         (void) fprintf(stderr, MSG_SERVER_SMF_DISABLED, instance);
 336 
 337         return (B_TRUE);
 338 }
 339 
 340 /*
 341  * smf_service_enable_attempt
 342  * Description:
 343  *              Attempt to enable the designated smf service.
 344  *              If the service goes into maintenance mode,
 345  *              return an error to the caller.
 346  * Parameters:
 347  *              instance - The instance to attempt to enable
 348  * Return:
 349  *              None
 350  * Scope:
 351  *              Private
 352  */
 353 static void
 354 smf_service_enable_attempt(char *instance)
 355 {
 356         char            *orig_state = NULL;
 357         int             enable_tried = 0;
 358 
 359         /*
 360          * Check the service status here.
 361          * Algorithm:
 362          *      If the service is online, everything is OK. return.
 363          *      If the service is offline, SMF is settling. Return
 364          *          or we get caught in recursion.
 365          *      If the service is disabled, try to enable it.
 366          *      If the service is in maintenance, try to clear it.
 367          */
 368         orig_state = smf_get_state(instance);
 369         if (orig_state == NULL) {
 370                 (void) smf_enable_instance(instance, 0);
 371         } else if (strcmp(orig_state, SCF_STATE_STRING_ONLINE) == 0) {
 372                 /*
 373                  * Instance is online and running.
 374                  */
 375                 free(orig_state);
 376                 return;
 377         } else if (strcmp(orig_state, SCF_STATE_STRING_OFFLINE) == 0) {
 378                 free(orig_state);
 379                 return;
 380         } else if (strcmp(orig_state, SCF_STATE_STRING_DISABLED) == 0) {
 381                 /*
 382                  * Instance is disabled try to enable it.
 383                  */
 384                 (void) smf_enable_instance(instance, 0);
 385         } else if (strcmp(orig_state, SCF_STATE_STRING_MAINT) == 0) {
 386                 (void) smf_restore_instance(instance);
 387         }
 388         free(orig_state);
 389 
 390 }
 391 
 392 
 393 /*
 394  * Function:    enable_install_service
 395  * Description:
 396  *              Enable the specified install service and update the
 397  *              service's property group.
 398  * Parameters:
 399  *              handle - scfutilhandle_t * for use with scf calls
 400  *              service_name   - service to enable
 401  * Return:
 402  *              B_TRUE  - Service enabled
 403  *              B_FALSE - If there is a failure
 404  * Scope:
 405  *              Private
 406  */
 407 static boolean_t
 408 enable_install_service(scfutilhandle_t *handle, char *service_name)
 409 {
 410         char            *port;
 411         service_data_t  data;
 412         char            cmd[MAXPATHLEN];
 413 
 414         if (service_name == NULL || handle == NULL) {
 415                 return (B_FALSE);
 416         }
 417 
 418         /*
 419          * get the data for the service
 420          */
 421         if (get_service_data(handle, service_name, &data) != B_TRUE) {
 422                 (void) fprintf(stderr, MSG_SERVICE_DOESNT_EXIST,
 423                     service_name);
 424                 return (B_FALSE);
 425         }
 426 
 427         /*
 428          * txt_record should be of the form
 429          * "aiwebserver=<host_ip>:<port>" and the directory location
 430          * will be AI_SERVICE_DIR_PATH/<port>
 431          */
 432         port = strrchr(data.txt_record, ':');
 433 
 434         if (port == NULL) {
 435                 (void) fprintf(stderr, MSG_SERVICE_PORT_MISSING,
 436                     service_name, data.txt_record);
 437                 return (B_FALSE);
 438         }
 439 
 440         /*
 441          * Exclude colon from string (so advance one character)
 442          */
 443 
 444         port++;
 445         snprintf(cmd, sizeof (cmd), "%s %s %s %s %s %s %s %s",
 446             SETUP_SERVICE_SCRIPT, SERVICE_REGISTER,
 447             service_name, INSTALL_TYPE,
 448             LOCAL_DOMAIN, port, data.txt_record, data.image_path);
 449         if (installadm_system(cmd) != 0) {
 450                 (void) fprintf(stderr, MSG_REGISTER_SERVICE_FAIL,
 451                     service_name);
 452                 return (B_FALSE);
 453         }
 454 
 455         /*
 456          * Update status in service's property group
 457          */
 458         strlcpy(data.status, STATUS_ON, STATUSLEN);
 459         if (save_service_data(handle, data) != B_TRUE) {
 460                 (void) fprintf(stderr, MSG_SAVE_SERVICE_PROPS_FAIL,
 461                     service_name);
 462                 return (B_FALSE);
 463         }
 464 
 465         /* ensure install service is online */
 466         smf_service_enable_attempt(instance);
 467 
 468         return (B_TRUE);
 469 }
 470 
 471 /*
 472  * do_create_service:
 473  * This function parses the command line arguments and sets up
 474  * the image, the DNS service, the network configuration for the
 475  * the clients to boot from this image (/tftpboot) and dhcp if desired.
 476  * This function calls shell scripts to handle each of the tasks
 477  */
 478 static int
 479 do_create_service(
 480         int argc,
 481         char *argv[],
 482         scfutilhandle_t *handle,
 483         const char *use)
 484 {
 485         int             opt;
 486         boolean_t       named_service = B_FALSE;
 487         boolean_t       named_boot_file = B_FALSE;
 488         boolean_t       dhcp_setup_needed = B_FALSE;
 489         boolean_t       create_netimage = B_FALSE;
 490         boolean_t       create_service = B_FALSE;
 491         boolean_t       have_sparc = B_FALSE;
 492 
 493         char            *boot_file = NULL;
 494         char            *ip_start = NULL;
 495         short           ip_count;
 496         char            *service_name = NULL;
 497         char            *source_path = NULL;
 498         char            *target_directory = NULL;
 499 
 500         struct stat     stat_buf;
 501         struct stat     sb;
 502         char            cmd[MAXPATHLEN];
 503         char            mpath[MAXPATHLEN];
 504         char            bfile[MAXPATHLEN];
 505         char            server_hostname[DATALEN];
 506         char            server_ip[DATALEN];
 507         char            srv_name[MAXPATHLEN];
 508         char            srv_address[DATALEN] = "unknown";
 509         char            txt_record[DATALEN];
 510         char            dhcp_macro[MAXNAMELEN+12]; /* dhcp_macro_<filename> */
 511         int             size;
 512         service_data_t  data;
 513         char            *pg_name;
 514 
 515         while ((opt = getopt(argc, argv, ":f:n:i:c:s:")) != -1) {
 516                 switch (opt) {
 517                 /*
 518                  * Create a boot file for this service with the supplied name
 519                  */
 520                 case 'f':
 521                         named_boot_file = B_TRUE;
 522                         boot_file = optarg;
 523                         break;
 524                 /*
 525                  * The name of the service is supplied.
 526                  */
 527                 case 'n':
 528                         if (!validate_service_name(optarg)) {
 529                                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
 530                                 return (INSTALLADM_FAILURE);
 531                         }
 532                         named_service = B_TRUE;
 533                         service_name = optarg;
 534                         break;
 535                 /*
 536                  * The starting IP address is supplied.
 537                  */
 538                 case 'i':
 539                         dhcp_setup_needed = B_TRUE;
 540                         ip_start = optarg;
 541                         break;
 542                 /*
 543                  * Number of IP addresses to be setup
 544                  */
 545                 case 'c':
 546                         ip_count = atoi(optarg);
 547                         break;
 548                 /*
 549                  * Source image is supplied.
 550                  */
 551                 case 's':
 552                         create_netimage = B_TRUE;
 553                         source_path = optarg;
 554                         break;
 555                 default:
 556                         (void) fprintf(stderr, "%s\n", gettext(use));
 557                         return (INSTALLADM_FAILURE);
 558                 }
 559         }
 560 
 561         /*
 562          * The last argument is the target directory.
 563          */
 564         target_directory = argv[optind++];
 565 
 566         if (target_directory == NULL) {
 567                 (void) fprintf(stderr, "%s\n", gettext(use));
 568                 return (INSTALLADM_FAILURE);
 569         }
 570 
 571         /*
 572          * Verify that the server settings are not obviously broken.
 573          * These checks cannot be complete, but check for things which will
 574          * definitely cause failure.
 575          */
 576         (void) snprintf(cmd, sizeof (cmd), "%s %s",
 577             CHECK_SETUP_SCRIPT, ((ip_start != NULL) ? ip_start : ""));
 578         if (installadm_system(cmd) != 0) {
 579                 (void) fprintf(stderr, MSG_BAD_SERVER_SETUP);
 580                 return (INSTALLADM_FAILURE);
 581         }
 582 
 583         /*
 584          * obtain server hostname and resolve it to IP address
 585          * If this operation fails, something is wrong with network
 586          * configuration - exit
 587          */
 588         if (gethostname(server_hostname, sizeof (server_hostname)) != 0) {
 589                 (void) fprintf(stderr, MSG_GET_HOSTNAME_FAIL);
 590                 return (INSTALLADM_FAILURE);
 591         }
 592 
 593         /* resolve host name to IP address */
 594         if (get_ip_from_hostname(server_hostname, server_ip,
 595             sizeof (server_ip)) != 0) {
 596                 (void) fprintf(stderr, MSG_GET_HOSTNAME_FAIL);
 597                 return (INSTALLADM_FAILURE);
 598         }
 599 
 600         /*
 601          * Check whether target exists
 602          * If it doesn't exist, the setup-image script will
 603          * create the directory.
 604          * If it exists, check whether it has a valid net image
 605          */
 606         if (access(target_directory, F_OK) == 0) {
 607                 if (stat(target_directory, &stat_buf) == 0) {
 608                         char    path[MAXPATHLEN];
 609                         /*
 610                          * If the directory is empty, then it is okay
 611                          */
 612                         if (stat_buf.st_nlink > 2) {
 613                                 /*
 614                                  * Check whether it has valid file solaris.zlib
 615                                  */
 616                                 (void) snprintf(path, sizeof (path), "%s/%s",
 617                                     target_directory,
 618                                     AI_NETIMAGE_REQUIRED_FILE);
 619                                 if (access(path, R_OK) != 0) {
 620                                         (void) fprintf(stderr,
 621                                             MSG_TARGET_NOT_EMPTY);
 622                                         return (INSTALLADM_FAILURE);
 623                                 }
 624                                 /*
 625                                  * Already have an image. We can't create a
 626                                  * new one w/o removing the old one.
 627                                  * Display error
 628                                  */
 629                                 if (create_netimage) {
 630                                         (void) fprintf(stderr,
 631                                             MSG_VALID_IMAGE_ERR,
 632                                             target_directory);
 633                                         return (INSTALLADM_FAILURE);
 634                                 }
 635                         }
 636                 } else {
 637                         (void) fprintf(stderr,
 638                             MSG_DIRECTORY_ACCESS_ERR,
 639                             target_directory, errno);
 640                         return (INSTALLADM_FAILURE);
 641                 }
 642         }
 643 
 644         /*
 645          * call the script to create the netimage
 646          */
 647         if (create_netimage) {
 648                 (void) snprintf(cmd, sizeof (cmd), "%s %s %s %s",
 649                     SETUP_IMAGE_SCRIPT, IMAGE_CREATE,
 650                     source_path, target_directory);
 651                 if (installadm_system(cmd) != 0) {
 652                         (void) fprintf(stderr, MSG_CREATE_IMAGE_ERR);
 653                         return (INSTALLADM_FAILURE);
 654                 }
 655         }
 656 
 657         /*
 658          * Check whether image is sparc or x86 by checking existence
 659          * of key directories
 660          */
 661         (void) snprintf(mpath, sizeof (mpath), "%s/%s", target_directory,
 662             "platform/sun4v");
 663         if ((stat(mpath, &sb) == 0) && S_ISDIR(sb.st_mode)) {
 664                 have_sparc = B_TRUE;
 665         } else {
 666                 (void) snprintf(mpath, sizeof (mpath), "%s/%s",
 667                     target_directory, "platform/i86pc");
 668                 if (stat(mpath, &sb) || !S_ISDIR(sb.st_mode)) {
 669                         (void) fprintf(stderr, MSG_UNABLE_TO_DETERMINE_ARCH);
 670                         return (INSTALLADM_FAILURE);
 671                 }
 672         }
 673 
 674         /*
 675          * The net-image is created, now start the service
 676          * If the user provided the name of the service, use it
 677          */
 678         txt_record[0] = '\0';
 679         srv_name[0] = '\0';
 680         if (named_service) {
 681                 /*
 682                  * Check to see if service exists
 683                  */
 684                 if (service_exists(handle, service_name)) {
 685                         if (!have_sparc) {
 686                                 /*
 687                                  * We need to remove the existing entry in
 688                                  * /etc/vfstab before adding the new entry
 689                                  * and updating the smf information.
 690                                  * X86 only
 691                                  */
 692                                 snprintf(cmd, sizeof (cmd), "%s %s %s",
 693                                     SETUP_TFTP_LINKS_SCRIPT, TFTP_REMOVE_VFSTAB,
 694                                     service_name);
 695 
 696                                 if (installadm_system(cmd) != 0) {
 697                                         (void) fprintf(stderr,
 698                                             MSG_SERVICE_REMOVE_VFSTAB_FAILED,
 699                                             service_name);
 700                                         return (INSTALLADM_FAILURE);
 701                                 }
 702                         }
 703                         /*
 704                          * Service exists. Make sure it is enabled.
 705                          */
 706                         if (!enable_install_service(handle, service_name)) {
 707                                 return (INSTALLADM_FAILURE);
 708                         }
 709 
 710                         /*
 711                          * Service now running, save txt record info
 712                          */
 713                         if (get_service_data(handle, service_name, &data) !=
 714                             B_TRUE) {
 715                                 (void) fprintf(stderr, MSG_SERVICE_DOESNT_EXIST,
 716                                     service_name);
 717                                 return (INSTALLADM_FAILURE);
 718                         }
 719                         strlcpy(txt_record, data.txt_record,
 720                             sizeof (txt_record));
 721                 } else {
 722                         /*
 723                          * Named service does not exist, create it below
 724                          */
 725                         create_service = B_TRUE;
 726                 }
 727                 strlcpy(srv_name, service_name, sizeof (srv_name));
 728         } else {
 729                 /*
 730                  * The service is not given as input. We will generate
 731                  * a service name and start the service.
 732                  */
 733                 create_service = B_TRUE;
 734         }
 735 
 736         if (create_service) {
 737                 uint16_t        wsport;
 738 
 739                 wsport = get_a_free_tcp_port(handle, START_WEB_SERVER_PORT);
 740                 if (wsport == 0) {
 741                         (void) fprintf(stderr, MSG_CANNOT_FIND_PORT);
 742                         return (INSTALLADM_FAILURE);
 743                 }
 744                 snprintf(txt_record, sizeof (txt_record), "%s=%s:%u",
 745                     AIWEBSERVER, server_hostname, wsport);
 746                 if (!named_service) {
 747                         snprintf(srv_name, sizeof (srv_name),
 748                             "_install_service_%u", wsport);
 749                 }
 750 
 751                 snprintf(cmd, sizeof (cmd), "%s %s %s %s %s %u %s %s",
 752                     SETUP_SERVICE_SCRIPT, SERVICE_REGISTER,
 753                     srv_name, INSTALL_TYPE,
 754                     LOCAL_DOMAIN, wsport, txt_record, target_directory);
 755                 if (installadm_system(cmd) != 0) {
 756                         (void) fprintf(stderr,
 757                             MSG_REGISTER_SERVICE_FAIL, srv_name);
 758                         return (INSTALLADM_FAILURE);
 759                 }
 760 
 761                 /*
 762                  * save location of service in format <server_ip_address>:<port>
 763                  * It will be used later for setting service discovery fallback
 764                  * mechanism
 765                  */
 766 
 767                 snprintf(srv_address, sizeof (srv_address), "%s:%u",
 768                     server_ip, wsport);
 769         }
 770 
 771         bfile[0] = '\0';
 772         if (named_boot_file) {
 773                 strlcpy(bfile, boot_file, sizeof (bfile));
 774         } else {
 775                 strlcpy(bfile, srv_name, sizeof (bfile));
 776         }
 777 
 778         /*
 779          * Register the information about the service, image and boot file
 780          * so that it can be used later
 781          */
 782         pg_name = ai_make_pg_name(srv_name);
 783         if (pg_name == NULL) {
 784                 (void) fprintf(stderr, MSG_GET_PG_NAME_FAILED, srv_name);
 785                 return (INSTALLADM_FAILURE);
 786         }
 787         if (ai_create_pg(handle, pg_name) != AI_SUCCESS) {
 788                 free(pg_name);
 789                 (void) fprintf(stderr, MSG_CREATE_INSTALL_SERVICE_FAILED,
 790                     srv_name);
 791                 return (INSTALLADM_FAILURE);
 792         }
 793         free(pg_name);
 794 
 795         strlcpy(data.svc_name, srv_name, DATALEN);
 796         strlcpy(data.image_path, target_directory, MAXPATHLEN);
 797         strlcpy(data.boot_file, bfile, MAXNAMELEN);
 798         strlcpy(data.txt_record, txt_record, MAX_TXT_RECORD_LEN);
 799         strlcpy(data.status, STATUS_ON, STATUSLEN);
 800 
 801         if (save_service_data(handle, data) != B_TRUE) {
 802                 (void) fprintf(stderr, MSG_SAVE_SERVICE_PROPS_FAIL,
 803                     data.svc_name);
 804                 return (INSTALLADM_FAILURE);
 805         }
 806 
 807         /*
 808          * Setup dhcp
 809          */
 810         if (dhcp_setup_needed && create_netimage) {
 811                 snprintf(cmd, sizeof (cmd), "%s %s %s %d",
 812                     SETUP_DHCP_SCRIPT, DHCP_SERVER, ip_start, ip_count);
 813                 if (installadm_system(cmd) != 0) {
 814                         (void) fprintf(stderr,
 815                             MSG_CREATE_DHCP_SERVER_ERR);
 816                         return (INSTALLADM_FAILURE);
 817                 }
 818         }
 819 
 820         if (create_netimage) {
 821                 char    dhcpbfile[MAXPATHLEN];
 822                 char    dhcprpath[MAXPATHLEN];
 823 
 824                 snprintf(dhcp_macro, sizeof (dhcp_macro),
 825                     "dhcp_macro_%s", bfile);
 826 
 827                 /*
 828                  * determine contents of bootfile info passed to dhcp script
 829                  * as well as rootpath for sparc
 830                  */
 831                 if (have_sparc) {
 832                         snprintf(dhcpbfile, sizeof (dhcpbfile),
 833                             "http://%s:%s/%s", server_ip, HTTP_PORT,
 834                             WANBOOTCGI);
 835                         snprintf(dhcprpath, sizeof (dhcprpath),
 836                             "http://%s:%s%s", server_ip, HTTP_PORT,
 837                             target_directory);
 838                 } else {
 839                         strlcpy(dhcpbfile, bfile, sizeof (dhcpbfile));
 840                 }
 841 
 842                 snprintf(cmd, sizeof (cmd), "%s %s %s %s %s %s",
 843                     SETUP_DHCP_SCRIPT, DHCP_MACRO, have_sparc?"sparc":"x86",
 844                     server_ip, dhcp_macro, dhcpbfile);
 845                 /*
 846                  * The setup-dhcp script takes care of printing output for the
 847                  * user so there is no need to print anything for non-zero
 848                  * return value.
 849                  */
 850                 installadm_system(cmd);
 851         }
 852 
 853         if (dhcp_setup_needed && create_netimage) {
 854                 snprintf(cmd, sizeof (cmd), "%s %s %s %d %s",
 855                     SETUP_DHCP_SCRIPT, DHCP_ASSIGN,
 856                     ip_start, ip_count, dhcp_macro);
 857                 if (installadm_system(cmd) != 0) {
 858                         (void) fprintf(stderr,
 859                             MSG_ASSIGN_DHCP_MACRO_ERR);
 860                 }
 861         }
 862 
 863         /*
 864          * Perform sparc/x86 specific actions.
 865          */
 866         if (have_sparc) {
 867                 /* sparc only */
 868                 snprintf(cmd, sizeof (cmd), "%s %s %s %s %s",
 869                     SETUP_SPARC_SCRIPT, SPARC_SERVER, target_directory,
 870                     srv_name, srv_address);
 871 
 872                 if (installadm_system(cmd) != 0) {
 873                         (void) fprintf(stderr, MSG_SETUP_SPARC_FAIL);
 874                         return (INSTALLADM_FAILURE);
 875                 }
 876         } else {
 877                 /* x86 only */
 878                 snprintf(cmd, sizeof (cmd), "%s %s %s %s %s %s",
 879                     SETUP_TFTP_LINKS_SCRIPT, TFTP_SERVER, srv_name,
 880                     srv_address, target_directory, bfile);
 881 
 882                 if (installadm_system(cmd) != 0) {
 883                         (void) fprintf(stderr, MSG_CREATE_TFTPBOOT_FAIL);
 884                         return (INSTALLADM_FAILURE);
 885                 }
 886         }
 887 
 888         /* if needed, enable install service */
 889         smf_service_enable_attempt(instance);
 890 
 891         return (INSTALLADM_SUCCESS);
 892 }
 893 
 894 /*
 895  * do_delete_service:
 896  * Simply call SERVICE_DELETE_SCRIPT
 897  * All service deletion is handled and done in the SERVICE_DELETE_SCRIPT
 898  */
 899 static int
 900 do_delete_service(
 901         int argc,
 902         char *argv[],
 903         scfutilhandle_t *handle,
 904         const char *use)
 905 {
 906         char            cmd[MAXPATHLEN];
 907         char            *service;
 908         boolean_t       delete_image = B_FALSE;
 909 
 910         if (argc != 2 && argc != 3) {
 911                 (void) fprintf(stderr, "%s\n", gettext(use));
 912                 return (INSTALLADM_FAILURE);
 913         }
 914 
 915         if (argc == 3) {
 916                 if (strcmp(argv[1], "-x") != 0) {
 917                         (void) fprintf(stderr, "%s\n", gettext(use));
 918                         return (INSTALLADM_FAILURE);
 919                 }
 920                 delete_image = B_TRUE;
 921                 service = argv[2];
 922         } else {
 923                 service = argv[1];
 924         }
 925 
 926         if (!validate_service_name(service)) {
 927                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
 928                 return (INSTALLADM_FAILURE);
 929         }
 930 
 931         /* if delete_image is true we are removing the image, pass -x flag */
 932         if (delete_image == B_TRUE) {
 933                 snprintf(cmd, sizeof (cmd), "%s -x %s",
 934                     SERVICE_DELETE_SCRIPT, service);
 935         }
 936         /* if delete_image is false we are not removing the image */
 937         else {
 938                 snprintf(cmd, sizeof (cmd), "%s %s",
 939                     SERVICE_DELETE_SCRIPT, service);
 940         }
 941         if (installadm_system(cmd) == 0) {
 942                 return (INSTALLADM_SUCCESS);
 943         }
 944         return (INSTALLADM_FAILURE);
 945 }
 946 
 947 /*
 948  * do_list:
 949  * List A/I services or print service manifests and criteria
 950  * Parse the command line for service name; if we do not have one, then
 951  * print a list of installed services; if we have a service name, get the
 952  * service directory path from that service name; then pass service directory
 953  * path to list-manifests(1) (if the internal -c option is provided pass it
 954  * to list-manifests(1) as well).
 955  */
 956 static int
 957 do_list(int argc, char *argv[], scfutilhandle_t *handle, const char *use)
 958 {
 959         int             opt;
 960         char            *port = NULL;
 961         char            *service_name = NULL;
 962         boolean_t       print_criteria = B_FALSE;
 963         char            cmd[MAXPATHLEN];
 964         int             ret;
 965         service_data_t  data;
 966 
 967         /*
 968          * The -c option is an internal option
 969          */
 970         while ((opt = getopt(argc, argv, "n:c")) != -1) {
 971                 switch (opt) {
 972                 /*
 973                  * The name of the service is supplied.
 974                  */
 975                 case 'n':
 976                         if (!validate_service_name(optarg)) {
 977                                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
 978                                 return (INSTALLADM_FAILURE);
 979                         }
 980                         service_name = optarg;
 981                         break;
 982                 case 'c':
 983                         print_criteria = B_TRUE;
 984                         break;
 985                 default:
 986                         (void) fprintf(stderr, "%s\n", gettext(use));
 987                         return (INSTALLADM_FAILURE);
 988                 }
 989         }
 990 
 991         /*
 992          * Make sure correct option combinations
 993          */
 994         if ((print_criteria == B_TRUE) && (service_name == NULL)) {
 995                 (void) fprintf(stderr, MSG_MISSING_OPTIONS, argv[0]);
 996                 (void) fprintf(stderr, "%s\n", gettext(use));
 997                 return (INSTALLADM_FAILURE);
 998         }
 999 
1000         if (service_name != NULL) {
1001                 /*
1002                  * Get the list of published manifests from the service
1003                  */
1004                 /*
1005                  * Gather the directory location of the service
1006                  */
1007                 if (get_service_data(handle, service_name, &data) != B_TRUE) {
1008                         (void) fprintf(stderr, MSG_SERVICE_PROP_FAIL);
1009                         return (INSTALLADM_FAILURE);
1010                 }
1011                 /*
1012                  * txt_record should be of the form
1013                  * "aiwebserver=<host_ip>:<port>" and the directory location
1014                  * will be AI_SERVICE_DIR_PATH/<port>
1015                  */
1016                 port = strrchr(data.txt_record, ':');
1017 
1018                 if (port == NULL) {
1019                         (void) fprintf(stderr, MSG_SERVICE_PORT_MISSING,
1020                             service_name, data.txt_record);
1021                         return (INSTALLADM_FAILURE);
1022                 }
1023 
1024                 /*
1025                  * Exclude colon from string (so advance one character)
1026                  */
1027                 port++;
1028 
1029                 /*
1030                  * Print criteria if requested
1031                  */
1032                 if (print_criteria == B_TRUE) {
1033                         (void) snprintf(cmd, sizeof (cmd), "%s %s %s%s",
1034                             MANIFEST_LIST_SCRIPT, "-c", AI_SERVICE_DIR_PATH,
1035                             port);
1036                 } else {
1037                         (void) snprintf(cmd, sizeof (cmd), "%s %s%s",
1038                             MANIFEST_LIST_SCRIPT, AI_SERVICE_DIR_PATH,
1039                             port);
1040                 }
1041 
1042                 ret = installadm_system(cmd);
1043 
1044                 /*
1045                  * Ensure we return an error if ret != 0.
1046                  * If ret == 1 then the Python handled the error, do not print a
1047                  * new error.
1048                  */
1049                 if (ret != 0) {
1050                         if (ret == 256) {
1051                                 return (INSTALLADM_FAILURE);
1052                         }
1053                         (void) fprintf(stderr, MSG_SUBCOMMAND_FAILED, argv[0]);
1054                         return (INSTALLADM_FAILURE);
1055                 }
1056 
1057         } else {
1058                 /*
1059                  * Get the list of services running on this system
1060                  */
1061 
1062                 snprintf(cmd, sizeof (cmd), "%s %s %s %s",
1063                     SETUP_SERVICE_SCRIPT, SERVICE_LIST,
1064                     INSTALL_TYPE, LOCAL_DOMAIN);
1065                 ret = installadm_system(cmd);
1066                 if (ret != 0) {
1067                         (void) fprintf(stderr, MSG_LIST_SERVICE_FAIL);
1068                         return (INSTALLADM_FAILURE);
1069                 }
1070         }
1071 
1072         return (INSTALLADM_SUCCESS);
1073 }
1074 
1075 /*
1076  * do_enable:
1077  * do_enable verifies syntax and then calls enable_install_service to
1078  * enable the service.
1079  */
1080 static int
1081 do_enable(int argc, char *argv[], scfutilhandle_t *handle, const char *use)
1082 {
1083         char            *service_name;
1084 
1085         if (argc != 2) {
1086                 (void) fprintf(stderr, "%s\n", gettext(use));
1087                 return (INSTALLADM_FAILURE);
1088         }
1089 
1090         if (!validate_service_name(argv[1])) {
1091                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
1092                 return (INSTALLADM_FAILURE);
1093         }
1094         service_name = argv[1];
1095 
1096         if (! enable_install_service(handle, service_name)) {
1097                 return (INSTALLADM_FAILURE);
1098         }
1099 
1100         return (INSTALLADM_SUCCESS);
1101 }
1102 
1103 /*
1104  * do_disable:
1105  *      Disable the specified service and optionally update the service's
1106  *      properties to reflect the new status.
1107  *      If the -t flag is specified, the service property group should not
1108  *      be updated to status=off. If -t is not specified it should be.
1109  */
1110 static int
1111 do_disable(int argc, char *argv[], scfutilhandle_t *handle, const char *use)
1112 {
1113         char            cmd[MAXPATHLEN];
1114         char            *service_name;
1115         service_data_t  data;
1116         boolean_t       transient = B_FALSE;
1117         int             option;
1118 
1119         while ((option = getopt(argc, argv, "t")) != -1) {
1120                 switch (option) {
1121                 case 't':
1122                         transient = B_TRUE;
1123                         break;
1124                 default:
1125                         do_opterr(optopt, option, use);
1126                         return (INSTALLADM_FAILURE);
1127                 }
1128         }
1129 
1130         service_name = argv[optind++];
1131         if (service_name == NULL) {
1132                 (void) fprintf(stderr, "%s\n", gettext(use));
1133                 return (INSTALLADM_FAILURE);
1134         }
1135         if (!validate_service_name(service_name)) {
1136                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
1137                 return (INSTALLADM_FAILURE);
1138         }
1139 
1140         /*
1141          * make sure the service exists
1142          */
1143         if (get_service_data(handle, service_name, &data) != B_TRUE) {
1144                 (void) fprintf(stderr, MSG_SERVICE_DOESNT_EXIST,
1145                     service_name);
1146                 return (INSTALLADM_FAILURE);
1147         }
1148 
1149         if (strcasecmp(data.status, STATUS_OFF) == 0) {
1150                 (void) fprintf(stderr, MSG_SERVICE_NOT_RUNNING,
1151                     service_name);
1152                 return (INSTALLADM_FAILURE);
1153         }
1154 
1155         if (transient == B_FALSE) {
1156                 /*
1157                  * Update status in service's property group
1158                  */
1159                 strlcpy(data.status, STATUS_OFF, STATUSLEN);
1160                 if (save_service_data(handle, data) != B_TRUE) {
1161                         (void) fprintf(stderr, MSG_SAVE_SERVICE_PROPS_FAIL,
1162                             service_name);
1163                         return (INSTALLADM_FAILURE);
1164                 }
1165 
1166                 /*
1167                  * if no longer needed, puts install instance into
1168                  * maintenance
1169                  */
1170                 (void) check_for_enabled_install_services(handle);
1171         }
1172 
1173         /*
1174          * Stop the service
1175          */
1176         snprintf(cmd, sizeof (cmd), "%s %s %s %s %s",
1177             SETUP_SERVICE_SCRIPT, SERVICE_DISABLE,
1178             service_name, INSTALL_TYPE, LOCAL_DOMAIN);
1179         if (installadm_system(cmd) != 0) {
1180                 /*
1181                  * Print informational message. This
1182                  * will happen if service was already stopped.
1183                  */
1184                 (void) fprintf(stderr,
1185                     MSG_SERVICE_WASNOT_RUNNING, service_name);
1186                 return (INSTALLADM_FAILURE);
1187         }
1188 
1189         return (INSTALLADM_SUCCESS);
1190 
1191 }
1192 
1193 static int
1194 do_create_client(
1195         int argc,
1196         char *argv[],
1197         scfutilhandle_t *handle,
1198         const char *use)
1199 {
1200 
1201         int     option;
1202         int     ret;
1203         char    *mac_addr = NULL;
1204         char    *bootargs = NULL;
1205         char    *imagepath = NULL;
1206         char    *svcname = NULL;
1207 
1208         while ((option = getopt(argc, argv, ":b:e:n:t:")) != -1) {
1209                 switch (option) {
1210                 case 'b':
1211                         bootargs = optarg;
1212                         break;
1213                 case 'e':
1214                         mac_addr = optarg;
1215                         break;
1216                 case 'n':
1217                         svcname = optarg;
1218                         break;
1219                 case 't':
1220                         imagepath = optarg;
1221                         break;
1222                 default:
1223                         do_opterr(optopt, option, use);
1224                         return (INSTALLADM_FAILURE);
1225                 }
1226         }
1227 
1228         /*
1229          * Make sure required options are there
1230          */
1231         if ((mac_addr == NULL) || (svcname == NULL)) {
1232                 (void) fprintf(stderr, MSG_MISSING_OPTIONS, argv[0]);
1233                 (void) fprintf(stderr, "%s\n", gettext(use));
1234                 return (INSTALLADM_FAILURE);
1235         }
1236 
1237         if (!validate_service_name(svcname)) {
1238                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
1239                 return (INSTALLADM_FAILURE);
1240         }
1241 
1242         ret = call_script(CREATE_CLIENT_SCRIPT, argc-1, &argv[1]);
1243         if (ret != 0) {
1244                 return (INSTALLADM_FAILURE);
1245         }
1246 
1247         /* if not enabled, enable install service */
1248         if (!check_for_enabled_install_services(handle)) {
1249                 smf_service_enable_attempt(instance);
1250         }
1251 
1252         return (INSTALLADM_SUCCESS);
1253 }
1254 
1255 
1256 static int
1257 do_delete_client(
1258         int argc,
1259         char *argv[],
1260         scfutilhandle_t *handle,
1261         const char *use)
1262 {
1263         int     ret;
1264         char    cmd[MAXPATHLEN];
1265 
1266         /*
1267          * There is one required argument, mac_addr of client
1268          */
1269         if (argc != 2) {
1270                 (void) fprintf(stderr, "%s\n", gettext(use));
1271                 return (INSTALLADM_FAILURE);
1272         }
1273 
1274         snprintf(cmd, sizeof (cmd), "%s %s",
1275             DELETE_CLIENT_SCRIPT, argv[1]);
1276         if (installadm_system(cmd) == 0) {
1277                 return (INSTALLADM_SUCCESS);
1278         }
1279         return (INSTALLADM_FAILURE);
1280 }
1281 
1282 /*
1283  * do_add:
1284  * Add manifests to an A/I service
1285  * Parse command line for criteria manifest and service name; get service
1286  * directory path from service name; then pass manifest and service directory
1287  * path to publish-manifest(1)
1288  */
1289 static int
1290 do_add(int argc, char *argv[], scfutilhandle_t *handle, const char *use)
1291 {
1292         int     option = NULL;
1293         char    *port = NULL;
1294         char    *manifest = NULL;
1295         char    *svcname = NULL;
1296         char    cmd[MAXPATHLEN];
1297         int     ret;
1298         service_data_t  data;
1299 
1300         /*
1301          * Check for valid number of arguments
1302          */
1303         if (argc != 5) {
1304                 (void) fprintf(stderr, "%s\n", gettext(use));
1305                 return (INSTALLADM_FAILURE);
1306         }
1307 
1308         while ((option = getopt(argc, argv, ":n:m:")) != -1) {
1309                 switch (option) {
1310                         case 'n':
1311                                 svcname = optarg;
1312                                 break;
1313                         case 'm':
1314                                 manifest = optarg;
1315                                 break;
1316                         default:
1317                                 do_opterr(optopt, option, use);
1318                                 return (INSTALLADM_FAILURE);
1319                 }
1320         }
1321 
1322         /*
1323          * Make sure required options are there
1324          */
1325         if ((svcname == NULL) || (manifest == NULL)) {
1326                 (void) fprintf(stderr, MSG_MISSING_OPTIONS, argv[0]);
1327                 (void) fprintf(stderr, "%s\n", gettext(use));
1328                 return (INSTALLADM_FAILURE);
1329         }
1330 
1331         if (!validate_service_name(svcname)) {
1332                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
1333                 return (INSTALLADM_FAILURE);
1334         }
1335 
1336         /*
1337          * Gather the directory location of the service
1338          */
1339         if (get_service_data(handle, svcname, &data) != B_TRUE) {
1340                 (void) fprintf(stderr, MSG_SERVICE_PROP_FAIL);
1341                 return (INSTALLADM_FAILURE);
1342         }
1343         /*
1344          * txt_record should be of the form
1345          *      "aiwebserver=<host_ip>:<port>"
1346          * and the directory location will be AI_SERVICE_DIR_PATH/<port>
1347          */
1348         port = strrchr(data.txt_record, ':');
1349 
1350         if (port == NULL) {
1351                 (void) fprintf(stderr, MSG_SERVICE_PORT_MISSING,
1352                     svcname, data.txt_record);
1353                 return (INSTALLADM_FAILURE);
1354         }
1355         /*
1356          * Exclude colon from string (so advance one character)
1357          */
1358         port++;
1359         (void) snprintf(cmd, sizeof (cmd), "%s %s %s %s%s %s",
1360             MANIFEST_MODIFY_SCRIPT, "-c",
1361             manifest, AI_SERVICE_DIR_PATH, port, data.image_path);
1362 
1363         ret = installadm_system(cmd);
1364 
1365         /*
1366          * Ensure we return an error if ret != 0.
1367          * If ret == 1 then the Python handled the error, do not print a
1368          * new error.
1369          */
1370         if (ret != 0) {
1371                 if (ret == 256) {
1372                         return (INSTALLADM_FAILURE);
1373                 }
1374                 (void) fprintf(stderr, MSG_SUBCOMMAND_FAILED, argv[0]);
1375                 return (INSTALLADM_FAILURE);
1376         }
1377         return (INSTALLADM_SUCCESS);
1378 }
1379 
1380 /*
1381  * do_remove:
1382  * Remove manifests from an A/I service
1383  * Parse the command line for service name and manifest name (and if
1384  * provided, internal instance name); then, get the service directory
1385  * path from the provided service name; then pass the manifest name
1386  * (instance name if provided) and service directory path to
1387  * delete-manifest(1)
1388  */
1389 static int
1390 do_remove(int argc, char *argv[], scfutilhandle_t *handle, const char *use)
1391 {
1392         int     option;
1393         char    *port = NULL;
1394         char    *manifest = NULL;
1395         char    *serv_instance = NULL;
1396         char    *svcname = NULL;
1397         char    cmd[MAXPATHLEN];
1398         int     ret;
1399         service_data_t  data;
1400 
1401         /*
1402          * Check for valid number of arguments
1403          */
1404         if (argc != 5 && argc != 7) {
1405                 (void) fprintf(stderr, "%s\n", gettext(use));
1406                 return (INSTALLADM_FAILURE);
1407         }
1408 
1409         /*
1410          * The -i option is an internal option
1411          */
1412         while ((option = getopt(argc, argv, ":n:m:i")) != -1) {
1413                 switch (option) {
1414                         case 'n':
1415                                 svcname = optarg;
1416                                 break;
1417                         case 'm':
1418                                 manifest = optarg;
1419                                 break;
1420                         case 'i':
1421                                 serv_instance = optarg;
1422                                 break;
1423                         default:
1424                                 do_opterr(optopt, option, use);
1425                                 return (INSTALLADM_FAILURE);
1426                 }
1427         }
1428 
1429         /*
1430          * Make sure required options are there
1431          */
1432         if ((svcname == NULL) || (manifest == NULL)) {
1433                 (void) fprintf(stderr, MSG_MISSING_OPTIONS, argv[0]);
1434                 (void) fprintf(stderr, "%s\n", gettext(use));
1435                 return (INSTALLADM_FAILURE);
1436         }
1437 
1438         if (!validate_service_name(svcname)) {
1439                 (void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
1440                 return (INSTALLADM_FAILURE);
1441         }
1442 
1443         /*
1444          * Gather the directory location of the service
1445          */
1446         if (get_service_data(handle, svcname, &data) != B_TRUE) {
1447                 (void) fprintf(stderr, MSG_SERVICE_PROP_FAIL);
1448                 return (INSTALLADM_FAILURE);
1449         }
1450 
1451         /*
1452          * txt_record should be of the form "aiwebserver=<host_ip>:<port>"
1453          * and the directory location will be AI_SERVICE_DIR_PATH/<port>
1454          */
1455         port = strrchr(data.txt_record, ':');
1456 
1457         if (port == NULL) {
1458                 (void) fprintf(stderr, MSG_SERVICE_PORT_MISSING,
1459                     svcname, data.txt_record);
1460                 return (INSTALLADM_FAILURE);
1461         }
1462         /*
1463          * Exclude colon from string (so advance one character)
1464          */
1465         port++;
1466 
1467         /*
1468          * See if we're removing a single instance or a whole manifest
1469          */
1470         if (serv_instance == NULL) {
1471                 (void) snprintf(cmd, sizeof (cmd), "%s %s %s%s",
1472                     MANIFEST_REMOVE_SCRIPT,
1473                     manifest, AI_SERVICE_DIR_PATH, port);
1474         } else {
1475                 (void) snprintf(cmd, sizeof (cmd), "%s %s %s %s %s%s",
1476                     MANIFEST_REMOVE_SCRIPT,
1477                     manifest, "-i", serv_instance,
1478                     AI_SERVICE_DIR_PATH, port);
1479         }
1480         ret = installadm_system(cmd);
1481 
1482         /*
1483          * Ensure we return an error if ret != 0.
1484          * If ret == 1 then the Python handled the error, do not print a
1485          * new error.
1486          */
1487         if (ret != 0) {
1488                 if (ret == 256) {
1489                         return (INSTALLADM_FAILURE);
1490                 }
1491                 (void) fprintf(stderr, MSG_SUBCOMMAND_FAILED, argv[0]);
1492                 return (INSTALLADM_FAILURE);
1493         }
1494 
1495         return (INSTALLADM_SUCCESS);
1496 }
1497 
1498 static int
1499 do_help(int argc, char *argv[], scfutilhandle_t *handle, const char *use)
1500 {
1501         int     i;
1502         int     numcmds;
1503         cmd_t   *cmdp;
1504 
1505         if (argc == 1) {
1506                 usage();
1507                 return (INSTALLADM_FAILURE);
1508         }
1509 
1510         numcmds = sizeof (cmds) / sizeof (cmds[0]);
1511         for (i = 0; i < numcmds; i++) {
1512                 cmdp = &cmds[i];
1513                 if (strcmp(argv[1], cmdp->c_name) == 0) {
1514                         if (cmdp->c_usage != NULL) {
1515                                 (void) fprintf(stdout, "%s\n",
1516                                     gettext(cmdp->c_usage));
1517                         } else {
1518                                 (void) fprintf(stdout,
1519                                     MSG_OPTION_NOHELP, progname,
1520                                     argv[0], cmdp->c_name);
1521                         }
1522                         return (INSTALLADM_SUCCESS);
1523                 }
1524         }
1525 
1526         (void) fprintf(stderr, MSG_UNKNOWN_HELPSUBCOMMAND,
1527             progname, argv[0], argv[1]);
1528         usage();
1529         return (INSTALLADM_FAILURE);
1530 }
1531 
1532 
1533 static void
1534 do_opterr(int opt, int opterr, const char *usage)
1535 {
1536         switch (opterr) {
1537                 case ':':
1538                         (void) fprintf(stderr,
1539                             MSG_OPTION_VALUE_MISSING, opt, gettext(usage));
1540                 break;
1541                 case '?':
1542                 default:
1543                         (void) fprintf(stderr,
1544                             MSG_OPTION_UNRECOGNIZED, opt, gettext(usage));
1545                 break;
1546         }
1547 }