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> -t <imagepath> -n <svcname>",
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) || (imagepath == 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 }