7020631 Convert create-service.c to python Build161
authorSue Sohn <Susan.Sohn@Oracle.COM>
Wed, 02 Mar 2011 11:14:19 -0800
changeset 1023 67ab1aaf8229
parent 1022 77720c98ac8d
child 1024 ad95c9e886ee
7020631 Convert create-service.c to python 7014777 installadm create-service ignores options after targetdir argument
usr/src/cmd/Makefile
usr/src/cmd/installadm/Makefile
usr/src/cmd/installadm/ai_smf_service.py
usr/src/cmd/installadm/create-service.c
usr/src/cmd/installadm/create_client.py
usr/src/cmd/installadm/create_service.py
usr/src/cmd/installadm/installadm.h
usr/src/cmd/installadm/installadm.py
usr/src/cmd/installadm/installadm_common.py
usr/src/cmd/installadm/installadm_util.c
usr/src/cmd/installadm/smf_test/test_ai_smf_service.py
usr/src/cmd/installadm/test/installadm_test.c
usr/src/lib/libaiscf_pymod/libaiscf.py
usr/src/pkg/manifests/install-installadm.mf
--- a/usr/src/cmd/Makefile	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/Makefile	Wed Mar 02 11:14:19 2011 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -29,9 +29,8 @@
 
 include $(SRC)/Makefile.master
 
-SUBDIRS= auto-install gui-install gui-aux installadm rbac slim-install \
-    system-config
-PYTHONSUBDIRS= ai-webserver distro_const js2ai text-install
+SUBDIRS= auto-install gui-aux gui-install rbac slim-install system-config
+PYTHONSUBDIRS= ai-webserver distro_const installadm js2ai text-install
 TOOLSSUBDIRS= install-tools
 
 .PARALLEL:
--- a/usr/src/cmd/installadm/Makefile	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/installadm/Makefile	Wed Mar 02 11:14:19 2011 -0800
@@ -26,13 +26,8 @@
 all:=		TARGET=	all
 clean:=		TARGET=	clean
 clobber:=	TARGET=	clobber
-install_h:=	TARGET=	install_h
 install:=	TARGET=	install
 
-SRCS	=	create-service.c \
-		installadm_util.c
-
-OBJS	=	${SRCS:%.c=${ARCH}/%.o}
 
 SCRIPTS	=	check-server-setup \
 		installadm-common \
@@ -42,10 +37,6 @@
 		setup-sparc \
 		setup-tftp-links
 
-HDRS	=	installadm.h
-
-PROGS	=	create-service
-
 CONF	=	ai-httpd.conf
 
 MANIFESTSRC =	server.xml
@@ -55,6 +46,7 @@
 PYMODULES=	ai_smf_service.py \
 		aimdns_mod.py \
 		create_client.py \
+		create_service.py \
 		delete_client.py \
 		delete_service.py \
 		installadm_common.py \
@@ -70,8 +62,6 @@
 
 ROOTPYCMODULES= $(PYCMODULES:%=$(ROOTPYTHONVENDORINSTALLAI)/%)
 
-ROOTPROGS=	$(PROGS:%=$(ROOTUSRSBIN)/%) 
-
 ROOTPYPROGS=	$(PYTHON_EXECS:%=$(ROOTUSRSBIN)/%)
 
 ROOTSCRIPTS=	$(SCRIPTS:%=$(ROOTUSRLIBINSTALLADM)/%)
@@ -84,61 +74,33 @@
 SVCMETHODS=	$(SVCMETHODSRC:%=$(ROOTLIBSVCMETHOD)/%)
 $(SVCMETHODS) :=	FILEMODE= 0555
 
-LIBDIR  = $(ROOTADMINLIB)
-LIBDIRS = -L${LIBDIR} -L$(SFWLIBDIR) -R$(SFWLIBRDIR) -L$(ROOTUSRLIB)
-
-CFLAGS	  += $(DEBUG_CFLAGS) -Xa
-LINTFLAGS  = -umx ${CPPFLAGS}
-
-LDFLAGS  +=	$(DEBUG_CFLAGS) \
-		-R$(ROOTADMINLIB:$(ROOT)%=%) $(LIBDIRS)
-APPLIBS  +=	-Bdynamic -lsocket -lnsl -lelf
-
-LDLIBS   =	-lscf -laiscf ${APPLIBS}
-
 MSG_DOMAIN = SUNW_INSTALL_INSTALLADM
 
-${ARCH}/%.o: %.c
-	${COMPILE.c} -o $@ $<
-
 .KEEP_STATE: 
 
 
-all: ${ARCH} .WAIT python $(PROGS) $(PYTHON_EXECS) \
+all: python $(PYTHON_EXECS) \
 	$(SCRIPTS) $(CONF) 
 	@true
 
-${ARCH}:
-	@[ -d ${@} ] || (${RM} ${@} ;mkdir -p ${@})
-
 python:
 	$(PYTHON) -m compileall -l $(@D)
 
 installadm:	installadm.py
 		cp installadm.py installadm
 
-
-$(PROGS):  $(OBJS) $(HDRS) .WAIT $(LIBDEP)
-	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
-	cp $@ ${ARCH}
-	$(POST_PROCESS)
-
-lint: ${SRCS} ${HDRS}
-	${LINT.c} ${SRCS}
-
 msgs: ${MSG_DOMAIN}.po
 
 clean:
-	rm -f $(PROGS) $(SCRIPTS) *.pyc $(PYTHON_EXECS)
+	rm -f $(SCRIPTS) *.pyc $(PYTHON_EXECS)
 
 clobber: clean
 
-install_h: 
 
 install: all .WAIT $(ROOTPYPROGS) $(ROOTPYMODULES) \
 	$(ROOTPYCMODULES) $(ROOTPYSCRIPTS) $(SYSMANIFESTS) \
-        $(PROGS) $(ROOTPROGS) $(ROOTSCRIPTS) $(ROOTMANSYS) \
-	$(ROOTLIBSVCMETHOD) $(SVCMETHODS) $(ROOTPYTHONVENDORINSTALLAI) \
+        $(ROOTSCRIPTS) $(ROOTMANSYS) $(ROOTLIBSVCMETHOD) \
+	$(SVCMETHODS) $(ROOTPYTHONVENDORINSTALLAI) \
 	$(SYSMANIFESTS) $(VARWEB)
 
 include ../Makefile.targ
--- a/usr/src/cmd/installadm/ai_smf_service.py	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/installadm/ai_smf_service.py	Wed Mar 02 11:14:19 2011 -0800
@@ -35,23 +35,23 @@
 import sys
 import time
 
-import osol_install.libaiscf as smf
-
+import osol_install.libaiscf as libaiscf
 from osol_install.auto_install.installadm_common import _, \
-    InstalladmCommonExit, SERVICE_REGISTER, SETUP_SERVICE_SCRIPT, \
-    STATUS_OFF, STATUS_ON
+    SERVICE_REGISTER, SETUP_SERVICE_SCRIPT 
 from solaris_install import CalledProcessError, Popen
 
 AI_SVC_FMRI = 'system/install/server'
 
 MAX_WAIT_TIME = 45 # Max wait time in seconds for service to transition states
 
-# AI service property group keys
+# AI service property group keys and values
 PROP_BOOT_FILE = 'boot_file'
 PROP_IMAGE_PATH = 'image_path'
 PROP_SERVICE_NAME = 'service_name'
 PROP_STATUS = 'status'
 PROP_TXT_RECORD = 'txt_record'
+STATUS_OFF = 'off'
+STATUS_ON = 'on'
 
 # From /usr/include/libscf.h
 SCF_STATE_STRING_MAINT = 'maintenance'
@@ -68,6 +68,7 @@
     '''
     pass
 
+
 def is_pg(pg_name):
     '''Checks if a property group is configured
 
@@ -80,11 +81,12 @@
     '''
     logging.debug('**** START ai_smf_service.is_pg ****')
 
-    if pg_name in smf.AISCF(FMRI=AI_SVC_FMRI).services:
+    if pg_name in libaiscf.AISCF(FMRI=AI_SVC_FMRI).services:
         return True
     else:
         return False
 
+
 def get_pg_props(pg_name):
     ''' Get property group properties
 
@@ -106,8 +108,8 @@
 
     props = {}
 
-    smf_inst = smf.AISCF(FMRI=AI_SVC_FMRI)
-    svc_obj = smf.AIservice(smf_inst, pg_name)
+    smf_inst = libaiscf.AISCF(FMRI=AI_SVC_FMRI)
+    svc_obj = libaiscf.AIservice(smf_inst, pg_name)
     for prop in svc_obj.keys():
         logging.debug('   property: ' + prop + ' value: ' + svc_obj[prop])
         props[prop] = svc_obj[prop]
@@ -119,6 +121,25 @@
 
     return props
 
+
+def create_pg(pg_name, props=None):
+    '''Create the property group, setting the properties, if provided.
+       Note: libaiscf.new_service() prepends the "AI" to the pg name.
+
+    Input:
+        pg_name - An AI service name 
+        props - (optional) A dictionary of properties to set when 
+                creating the pg.
+
+    '''
+    logging.debug("*** START ai_smf_service.create_pg ***")
+    inst = libaiscf.AISCF(FMRI=AI_SVC_FMRI)
+    inst.new_service(pg_name)
+    
+    if props:
+        set_pg_props(pg_name, props)
+
+
 def set_pg_props(pg_name, props):
     '''
     Set the property values, as specified in dictionary, props, for a
@@ -139,11 +160,15 @@
         # Work around the fact that AIServices currently only supports
         # string objects.
         if props[prop] == False:
-            smf.AIservice(smf.AISCF(), pg_name)[prop] = 'FALSE'
+            libaiscf.AIservice(libaiscf.AISCF(FMRI=AI_SVC_FMRI),
+                               pg_name)[prop] = 'FALSE'
         elif props[prop] == True:
-            smf.AIservice(smf.AISCF(), pg_name)[prop] = 'TRUE'
+            libaiscf.AIservice(libaiscf.AISCF(FMRI=AI_SVC_FMRI),
+                               pg_name)[prop] = 'TRUE'
         else:
-            smf.AIservice(smf.AISCF(), pg_name)[prop] = props[prop]
+            libaiscf.AIservice(libaiscf.AISCF(FMRI=AI_SVC_FMRI),
+                               pg_name)[prop] = props[prop]
+
 
 def get_all_pg_props():
     '''
@@ -160,12 +185,13 @@
     logging.debug('**** START ai_smf_service.get_all_pg_props ****')
 
     prop_groups = {}
-    for prop_group in smf.AISCF(FMRI=AI_SVC_FMRI).services:
+    for prop_group in libaiscf.AISCF(FMRI=AI_SVC_FMRI).services:
         logging.debug('service: AI' + prop_group)
         prop_groups[prop_group] = get_pg_props(prop_group)
 
     return prop_groups
 
+
 def get_state():
     ''' Return the state of the Automated Installer SMF service.
 
@@ -182,10 +208,11 @@
     logging.debug('**** START ai_smf_service.get_state ****')
 
     try:
-        return smf.AISCF(FMRI=AI_SVC_FMRI).state
+        return libaiscf.AISCF(FMRI=AI_SVC_FMRI).state
     except SystemError:
         return None
 
+
 def maintain_instance():
     ''' Move the Automated Installer SMF service to the maintenance state.
 
@@ -203,11 +230,11 @@
     '''
     logging.debug('**** START ai_smf_service.maintain_instance ****')
 
-    smf.AISCF(FMRI=AI_SVC_FMRI).state='MAINTENANCE'
+    libaiscf.AISCF(FMRI=AI_SVC_FMRI).state = 'MAINTENANCE'
 
     # Wait a reasonable amount of time to confirm state change.
     wait_cnt = 0
-    while smf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'MAINTENANCE':
+    while libaiscf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'MAINTENANCE':
         if wait_cnt >= MAX_WAIT_TIME:
             logging.debug("Wait time exceeded on attempt to move "
                           "installadm SMF service to maintenance.")
@@ -224,6 +251,7 @@
                      "the last install service has been disabled or "
                      "deleted.\n")
 
+
 def disable_instance():
     ''' Move the Automated Installer SMF service to the disabled state.
 
@@ -242,11 +270,11 @@
     logging.debug('**** START ai_smf_service.disable_instance ****')
     sys.stderr.write("The installadm SMF service is being taken offline.\n")
 
-    smf.AISCF(FMRI=AI_SVC_FMRI).state='DISABLE'
+    libaiscf.AISCF(FMRI=AI_SVC_FMRI).state = 'DISABLE'
 
     # Wait a reasonable amount of time to confirm state change.
     wait_cnt = 0
-    while smf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'DISABLED':
+    while libaiscf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'DISABLED':
         if wait_cnt >= MAX_WAIT_TIME:
             logging.debug("Wait time exceeded on attempt to move "
                           "installadm SMF service to disabled.")
@@ -259,6 +287,7 @@
     logging.debug("Time to move installadm SMF service to disabled is "
                   "%i seconds", wait_cnt)
 
+
 def enable_instance():
     ''' Enable the Automated Installer SMF service.
 
@@ -276,11 +305,11 @@
     '''
     logging.debug('**** START ai_smf_service.enable_instance ****')
 
-    smf.AISCF(FMRI=AI_SVC_FMRI).state='ENABLE'
+    libaiscf.AISCF(FMRI=AI_SVC_FMRI).state = 'ENABLE'
 
     # Wait a reasonable amount of time to confirm state change.
     wait_cnt = 0
-    while smf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'ONLINE':
+    while libaiscf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'ONLINE':
         if wait_cnt >= MAX_WAIT_TIME:
             logging.debug("Wait time exceeded on attempt to enable "
                           "installadm SMF service.")
@@ -293,6 +322,7 @@
     logging.debug("Time to enable installadm SMF service is %i seconds", 
                   wait_cnt)
 
+
 def restore_instance():
     ''' Restore the Automated Installer SMF service.
 
@@ -310,11 +340,11 @@
     '''
     logging.debug('**** START ai_smf_service.restore_instance ****')
 
-    smf.AISCF(FMRI=AI_SVC_FMRI).state='RESTORE'
+    libaiscf.AISCF(FMRI=AI_SVC_FMRI).state = 'RESTORE'
 
     # Wait a reasonable amount of time to confirm state change.
     wait_cnt = 0
-    while smf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'DISABLED':
+    while libaiscf.AISCF(FMRI=AI_SVC_FMRI).state.upper() != 'DISABLED':
         if wait_cnt >= MAX_WAIT_TIME:
             logging.debug("Wait time exceeded on attempt to restore "
                           "installadm SMF service.")
@@ -327,6 +357,7 @@
     logging.debug("Time to restore installadm SMF service is %i seconds", 
                   wait_cnt)
 
+
 def service_enable_attempt():
     ''' Attempt to enable the Automated Installer SMF service.
 
@@ -353,28 +384,29 @@
         enable_instance()
     elif orig_state == SCF_STATE_STRING_ONLINE:
         # Instance is online and running - do nothing.
-        logging.debug ("Current smf service state already online")
+        logging.debug("Current smf service state already online")
         return
     elif orig_state == SCF_STATE_STRING_OFFLINE:
-        logging.debug ("Current smf service state offline")
+        logging.debug("Current smf service state offline")
         return
     elif orig_state == SCF_STATE_STRING_DISABLED:
-        logging.debug ("Current smf service state disabled, enabling "
+        logging.debug("Current smf service state disabled, enabling "
                        "instance")
         enable_instance()
     elif orig_state == SCF_STATE_STRING_MAINT:
-        logging.debug ("Current smf service state is maintenance, "
+        logging.debug("Current smf service state is maintenance, "
                        "restoring instance")
         restore_instance()
  
         # Instance is now disabled - try to enable it.
-        logging.debug ("Current smf service state is disabled, "
+        logging.debug("Current smf service state is disabled, "
                        "enabling instance")
         enable_instance()
     else:
         raise InstalladmAISmfServicesError(
             _('Error: unexpected state for install server: %s') % orig_state)
 
+
 def enable_install_service(svcname):
     ''' Enable an install service
 
@@ -424,7 +456,7 @@
 
     # Actually register service
     cmd = [SETUP_SERVICE_SCRIPT, SERVICE_REGISTER, svcname,
-            pg_data[PROP_TXT_RECORD], pg_data[PROP_IMAGE_PATH]]
+           pg_data[PROP_TXT_RECORD], pg_data[PROP_IMAGE_PATH]]
     logging.debug("enable_install_service: register command is %s", cmd)
     try:
         Popen.check_call(cmd)
@@ -434,6 +466,7 @@
         set_pg_props(svcname, props)
         raise InstalladmAISmfServicesError()
 
+
 def check_for_enabled_services():
     ''' 
     Check to see if any of the install services are enabled. 
@@ -470,7 +503,7 @@
             return
 
     service_state = get_state()
-    logging.debug ("Current state of smf service is %s", service_state)
+    logging.debug("Current state of smf service is %s", service_state)
     if service_state != SCF_STATE_STRING_MAINT:
         logging.debug("Disabling installadm SMF service") 
         disable_instance()
--- a/usr/src/cmd/installadm/create-service.c	Wed Mar 02 10:11:44 2011 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,657 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <locale.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <errno.h>
-
-#include "installadm.h"
-
-static boolean_t is_multihomed(void);
-
-char	instance[sizeof (INSTALL_SERVER_FMRI_BASE) +
-	    sizeof (INSTALL_SERVER_DEF_INST) + 1];
-
-static char *cmd_usage = {
-	"\tcreate-service\t[-b <property>=<value>,...] \n"
-	"\t\t\t[-f <bootfile>] [-n <svcname>]\n"
-	"\t\t\t[-i <dhcp_ip_start> -c <count_of_ipaddr>]\n"
-	"\t\t\t[-s <srcimage>] <targetdir>"
-};
-
-int
-main(int argc, char *argv[])
-{
-	scfutilhandle_t	*handle;
-	int ret = 0;
-
-	(void) setlocale(LC_ALL, "");
-
-	(void) snprintf(instance, sizeof (instance), "%s:%s",
-	    INSTALL_SERVER_FMRI_BASE, INSTALL_SERVER_DEF_INST);
-
-	/*
-	 * Check for privileges
-	 */
-	if (geteuid() > 0) {
-		(void) fprintf(stderr, MSG_ROOT_PRIVS_REQD,
-		    "installadm", "create-service");
-		exit(INSTALLADM_FAILURE);
-	}
-
-	handle = ai_scf_init();
-	if (handle == NULL) {
-		(void) fprintf(stderr, MSG_AI_SMF_INIT_FAIL);
-		exit(INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * set the umask, for all subcommands to inherit
-	 */
-	(void) umask(022);
-
-	if (do_create_service(argc , &argv[0], handle, cmd_usage)) {
-		ret = INSTALLADM_FAILURE;
-	} else {
-		ret = INSTALLADM_SUCCESS;
-	}
-
-	/* clean-up SMF handle */
-	ai_scf_fini(handle);
-	exit(ret);
-}
-
-/*
- * get_ip_from_hostname:
- *
- * Description:
- *   Resolves given hostname to IPv4 address. Result is stored as string
- *   into given buffer. If more than one IP address is returned, the first
- *   one is picked.
- *
- * parameters:
- *   name        - simple or fully qualified hostname to be resolved
- *   ip_string   - pointer to string buffer where IP address will
- *                 be stored
- *   buffer_size - size of ip_string
- *
- * return:
- *   0  - success
- *   -1 - resolve process failed - string buffer is left untouched
- */
-static int
-get_ip_from_hostname(char *name, char *ip_string, int buffer_size)
-{
-	struct hostent	*hp;
-	struct in_addr	in;
-
-	hp = gethostbyname(name);
-	if (hp == NULL) {
-		return (-1);
-	} else {
-		(void) memcpy(&in.s_addr, hp->h_addr_list[0],
-		    sizeof (in.s_addr));
-
-		(void) snprintf(ip_string, buffer_size, "%s", inet_ntoa(in));
-	}
-
-	return (0);
-}
-
-
-/*
- * smf_service_enable_attempt
- * Description:
- *		Attempt to enable the designated smf service.
- *		If the service goes into maintenance mode,
- *		return an error to the caller.
- * Parameters:
- *		instance - The instance to attempt to enable
- * Return:
- *		None
- * Scope:
- *		Private
- */
-static void
-smf_service_enable_attempt(char *instance)
-{
-	char		*orig_state = NULL;
-	int		enable_tried = 0;
-
-	/*
-	 * Check the service status here.
-	 * Algorithm:
-	 *	If the service is online, everything is OK. return.
-	 *	If the service is offline, SMF is settling. Return
-	 *	    or we get caught in recursion.
-	 * 	If the service is disabled, try to enable it.
-	 *	If the service is in maintenance, try to clear it and
-	 *	    then enable it.
-	 */
-	orig_state = smf_get_state(instance);
-	if (orig_state == NULL) {
-		(void) smf_enable_instance(instance, 0);
-	} else if (strcmp(orig_state, SCF_STATE_STRING_ONLINE) == 0) {
-		/*
-		 * Instance is online and running.
-		 */
-		free(orig_state);
-		return;
-	} else if (strcmp(orig_state, SCF_STATE_STRING_OFFLINE) == 0) {
-		free(orig_state);
-		return;
-	} else if (strcmp(orig_state, SCF_STATE_STRING_DISABLED) == 0) {
-		/*
-		 * Instance is disabled try to enable it.
-		 */
-		(void) smf_enable_instance(instance, 0);
-	} else if (strcmp(orig_state, SCF_STATE_STRING_MAINT) == 0) {
-		(void) smf_restore_instance(instance);
-		/*
-		 * Instance is now disabled try to enable it.
-		 */
-		(void) smf_enable_instance(instance, 0);
-	}
-	free(orig_state);
-
-}
-
-/*
- * Function:    is_multihomed
- * Description:
- *              Check the if the machine is multihomed or not
- * Parameters:
- *		None
- * Return:
- *		B_TRUE  - Machine is multihomed
- *		B_FALSE - Machine is not multihomed
- * Scope:
- *              Private
- */
-static boolean_t
-is_multihomed(void)
-{
-	char	cmd[MAXPATHLEN];
-
-	/*
-	 * use the shell to see if system is multihomed by calling
-	 * valid_networks() from installadm-common and using wc(1) to count
-	 */
-	(void) snprintf(cmd, sizeof (cmd),
-	    "/usr/bin/test `%s -c 'source %s; valid_networks' | "
-	    "%s -l` -eq '1' ]",
-	    KSH93, INSTALLADM_COMMON_SCRIPT, WC);
-
-	if (installadm_system(cmd) != 0) {
-		return (B_TRUE);
-	}
-	return (B_FALSE);
-}
-
-/*
- * do_create_service:
- * This function parses the command line arguments and sets up
- * the image, the DNS service, the network configuration for the
- * the clients to boot from this image (/tftpboot) and dhcp if desired.
- * This function calls shell scripts to handle each of the tasks
- */
-static int
-do_create_service(
-	int argc,
-	char *argv[],
-	scfutilhandle_t *handle,
-	const char *use)
-{
-	int		opt;
-	boolean_t	named_service = B_FALSE;
-	boolean_t	named_boot_file = B_FALSE;
-	boolean_t	dhcp_setup_needed = B_FALSE;
-	boolean_t	create_netimage = B_FALSE;
-	boolean_t	create_service = B_FALSE;
-	boolean_t	have_sparc = B_FALSE;
-	boolean_t	compatibility_port = B_FALSE;
-
-	char		*bootargs = NULL;
-	char		*boot_file = NULL;
-	char		*ip_start = NULL;
-	short		ip_count = 0;
-	char		*service_name = NULL;
-	char		*source_path = NULL;
-	char		*target_directory = NULL;
-
-	struct stat	stat_buf;
-	struct stat 	sb;
-	char		cmd[MAXPATHLEN];
-	char		mpath[MAXPATHLEN];
-	char		bfile[MAXPATHLEN];
-	char		server_hostname[DATALEN];
-	char		server_ip[DATALEN];
-	char		srv_name[MAXPATHLEN];
-	char		srv_address[DATALEN] = "unknown";
-	char		txt_record[DATALEN];
-	char		dhcp_macro[MAXNAMELEN+12]; /* dhcp_macro_<filename> */
-	int		size;
-	service_data_t	data;
-	char		*pg_name;
-	int		port;
-	int		http_port;
-
-	while ((opt = getopt(argc, argv, ":b:f:n:i:c:s:")) != -1) {
-		switch (opt) {
-		/*
-		 * Create a boot file for this service with the supplied name
-		 */
-		case 'b':
-			bootargs = optarg;
-			break;
-		case 'f':
-			named_boot_file = B_TRUE;
-			boot_file = optarg;
-			break;
-		/*
-		 * The name of the service is supplied.
-		 */
-		case 'n':
-			if (!validate_service_name(optarg)) {
-				(void) fprintf(stderr, MSG_BAD_SERVICE_NAME);
-				return (INSTALLADM_FAILURE);
-			}
-			named_service = B_TRUE;
-			service_name = optarg;
-			break;
-		/*
-		 * The starting IP address is supplied.
-		 */
-		case 'i':
-			dhcp_setup_needed = B_TRUE;
-			ip_start = optarg;
-			break;
-		/*
-		 * Number of IP addresses to be setup
-		 */
-		case 'c':
-			ip_count = atoi(optarg);
-			if (ip_count < 1)  {
-				(void) fprintf(stderr, "%s\n", gettext(use));
-				return (INSTALLADM_FAILURE);
-			}
-			break;
-		/*
-		 * Source image is supplied.
-		 */
-		case 's':
-			create_netimage = B_TRUE;
-			source_path = optarg;
-			break;
-		default:
-			(void) fprintf(stderr, "%s\n", gettext(use));
-			return (INSTALLADM_FAILURE);
-		}
-	}
-
-	/*
-	 * The last argument is the target directory.
-	 */
-	target_directory = argv[optind++];
-
-	if (target_directory == NULL) {
-		(void) fprintf(stderr, "%s\n", gettext(use));
-		return (INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * Verify that the server settings are not obviously broken.
-	 * These checks cannot be complete, but check for things which will
-	 * definitely cause failure.
-	 */
-	(void) snprintf(cmd, sizeof (cmd), "%s %s",
-	    CHECK_SETUP_SCRIPT, ((ip_start != NULL) ? ip_start : ""));
-	if (installadm_system(cmd) != 0) {
-		(void) fprintf(stderr, MSG_BAD_SERVER_SETUP);
-		return (INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * The options -i and -c should either both be set or
-	 * neither argument should be set.
-	 */
-	if (((ip_count != 0) && (ip_start == NULL)) ||
-	    ((ip_count == 0) && (ip_start != NULL))) {
-		(void) fprintf(stderr, MSG_MISSING_OPTIONS, argv[0]);
-		(void) fprintf(stderr, "%s\n", gettext(use));
-		return (INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * The options -i and -c are not to be allowed when the system is
-	 * multi-homed, see if we're asked to do dhcp_setup
-	 */
-	if (dhcp_setup_needed && is_multihomed() == B_TRUE) {
-		(void) fprintf(stderr, MSG_MULTIHOMED_DHCP_DENY);
-		return (INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * obtain server hostname and resolve it to IP address
-	 * If this operation fails, something is wrong with network
-	 * configuration - exit
-	 */
-	if (gethostname(server_hostname, sizeof (server_hostname)) != 0) {
-		(void) fprintf(stderr, MSG_GET_HOSTNAME_FAIL);
-		return (INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * if the machine is multihomed, use the keyword $serverIP for
-	 * server_ip; otherwise, set server_ip to the IP address resolved
-	 * for the machine's hostname -- which may or may not resolve to
-	 * something sensible
-	 */
-	if (is_multihomed() == B_TRUE) {
-		(void) snprintf(server_ip, sizeof (server_ip), "$serverIP");
-	} else {
-		if (get_ip_from_hostname(server_hostname, server_ip,
-		    sizeof (server_ip)) != 0) {
-			(void) fprintf(stderr, MSG_GET_HOSTNAME_FAIL);
-			return (INSTALLADM_FAILURE);
-		}
-	}
-
-	/*
-	 * Check to see if service exists -- error if it does
-	 */
-	if (named_service) {
-		if (service_exists(handle, service_name)) {
-			(void) fprintf(stderr, MSG_SERVICE_EXISTS,
-			    service_name);
-			return (INSTALLADM_FAILURE);
-		}
-		/* service does not exist use the provided name */
-		strlcpy(srv_name, service_name, sizeof (srv_name));
-	}
-
-	/*
-	 * Check whether target exists
-	 * If it doesn't exist, the setup-image script will
-	 * create the directory.
-	 * If it exists, check whether it has a valid net image
-	 */
-	if (access(target_directory, F_OK) == 0) {
-		if (stat(target_directory, &stat_buf) == 0) {
-			char	path[MAXPATHLEN];
-			/*
-			 * If the directory is empty, then it is okay
-			 */
-			if (stat_buf.st_nlink > 2) {
-				/*
-				 * Check whether it has valid file solaris.zlib
-				 */
-				(void) snprintf(path, sizeof (path), "%s/%s",
-				    target_directory,
-				    AI_NETIMAGE_REQUIRED_FILE);
-				if (access(path, R_OK) != 0) {
-					(void) fprintf(stderr,
-					    MSG_TARGET_NOT_EMPTY);
-					return (INSTALLADM_FAILURE);
-				}
-				/*
-				 * Already have an image. We can't create a
-				 * new one w/o removing the old one.
-				 * Display error
-				 */
-				if (create_netimage) {
-					(void) fprintf(stderr,
-					    MSG_VALID_IMAGE_ERR,
-					    target_directory);
-					return (INSTALLADM_FAILURE);
-				}
-			}
-		} else {
-			(void) fprintf(stderr,
-			    MSG_DIRECTORY_ACCESS_ERR,
-			    target_directory, errno);
-			return (INSTALLADM_FAILURE);
-		}
-	}
-
-	/*
-	 * call the script to create the netimage
-	 */
-	if (create_netimage) {
-		(void) snprintf(cmd, sizeof (cmd), "%s %s %s %s",
-		    SETUP_IMAGE_SCRIPT, IMAGE_CREATE,
-		    source_path, target_directory);
-		if (installadm_system(cmd) != 0) {
-			(void) fprintf(stderr, MSG_CREATE_IMAGE_ERR);
-			return (INSTALLADM_FAILURE);
-		}
-		(void) snprintf(cmd, sizeof (cmd), "%s %s %s",
-		    SETUP_IMAGE_SCRIPT, CHECK_IMAGE_VERSION,
-		    target_directory);
-		if (installadm_system(cmd) != 0)
-			compatibility_port = B_TRUE;
-	}
-
-	/*
-	 * Check whether image is sparc or x86 by checking existence
-	 * of key directories
-	 */
-	(void) snprintf(mpath, sizeof (mpath), "%s/%s", target_directory,
-	    "platform/sun4v");
-	if ((stat(mpath, &sb) == 0) && S_ISDIR(sb.st_mode)) {
-		have_sparc = B_TRUE;
-	} else {
-		(void) snprintf(mpath, sizeof (mpath), "%s/%s",
-		    target_directory, "platform/i86pc");
-		if (stat(mpath, &sb) || !S_ISDIR(sb.st_mode)) {
-			(void) fprintf(stderr, MSG_UNABLE_TO_DETERMINE_ARCH);
-			return (INSTALLADM_FAILURE);
-		}
-	}
-
-	/*
-	 * The net-image is created, now setup the port and service name
-	 */
-	txt_record[0] = '\0';
-	srv_name[0] = '\0';
-
-	http_port = get_http_port(handle);
-	if (compatibility_port == B_TRUE) {
-		port = (int)get_a_free_tcp_port(handle, START_WEB_SERVER_PORT);
-		if (port == 0) {
-			(void) fprintf(stderr, MSG_CANNOT_FIND_PORT);
-			return (INSTALLADM_FAILURE);
-		}
-	} else {
-		port = http_port;
-	}
-
-	/*
-	 * set text record to "aiwebserver=$serverIP:<port>"
-	 * (if multihomed) or to "aiwebserver=<server hostname>:<port>"
-	 * (if single-homed)
-	 */
-	snprintf(txt_record, sizeof (txt_record), "%s=%s:%u",
-	    AIWEBSERVER, server_hostname, port);
-	if (!named_service) {
-		int count = 1;
-
-		snprintf(srv_name, sizeof (srv_name),
-		    "_install_service_%d", count);
-		while (service_exists(handle, srv_name)) {
-			count++;
-			snprintf(srv_name, sizeof (srv_name),
-			    "_install_service_%d", count);
-		}
-	} else {
-		strlcpy(srv_name, service_name, sizeof (srv_name));
-	}
-
-	/*
-	 * save location of service in format <server_ip_address>:<port>
-	 * It will be used later for setting service discovery fallback
-	 * mechanism
-	 */
-
-	snprintf(srv_address, sizeof (srv_address), "%s:%u",
-	    is_multihomed()?"\\$serverIP":server_ip, port);
-
-	bfile[0] = '\0';
-	if (named_boot_file) {
-		strlcpy(bfile, boot_file, sizeof (bfile));
-	} else {
-		strlcpy(bfile, srv_name, sizeof (bfile));
-	}
-
-	/*
-	 * Register the information about the service, image and boot file
-	 * so that it can be used later
-	 */
-	pg_name = ai_make_pg_name(srv_name);
-	if (pg_name == NULL) {
-		(void) fprintf(stderr, MSG_GET_PG_NAME_FAILED, srv_name);
-		return (INSTALLADM_FAILURE);
-	}
-	if (ai_create_pg(handle, pg_name) != AI_SUCCESS) {
-		free(pg_name);
-		(void) fprintf(stderr, MSG_CREATE_INSTALL_SERVICE_FAILED,
-		    srv_name);
-		return (INSTALLADM_FAILURE);
-	}
-	free(pg_name);
-
-	strlcpy(data.svc_name, srv_name, DATALEN);
-	strlcpy(data.image_path, target_directory, MAXPATHLEN);
-	strlcpy(data.boot_file, bfile, MAXNAMELEN);
-	strlcpy(data.txt_record, txt_record, MAX_TXT_RECORD_LEN);
-	strlcpy(data.status, STATUS_ON, STATUSLEN);
-
-	if (save_service_data(handle, data) != B_TRUE) {
-		(void) fprintf(stderr, MSG_SAVE_SERVICE_PROPS_FAIL,
-		    data.svc_name);
-		return (INSTALLADM_FAILURE);
-	}
-
-	/* if needed, enable install service */
-	smf_service_enable_attempt(instance);
-
-	/*
-	 * Register service
-	 */
-	snprintf(cmd, sizeof (cmd), "%s %s %s %s %s",
-	    SETUP_SERVICE_SCRIPT, SERVICE_REGISTER,
-	    srv_name, txt_record, target_directory);
-	if (installadm_system(cmd) != 0) {
-		(void) fprintf(stderr,
-		    MSG_REGISTER_SERVICE_FAIL, srv_name);
-		return (INSTALLADM_FAILURE);
-	}
-
-	/*
-	 * Setup dhcp
-	 */
-	if (dhcp_setup_needed && create_netimage) {
-		snprintf(cmd, sizeof (cmd), "%s %s %s %d",
-		    SETUP_DHCP_SCRIPT, DHCP_SERVER, ip_start, ip_count);
-		if (installadm_system(cmd) != 0) {
-			(void) fprintf(stderr,
-			    MSG_CREATE_DHCP_SERVER_ERR);
-			return (INSTALLADM_FAILURE);
-		}
-	}
-
-	if (create_netimage) {
-		char	dhcpbfile[MAXPATHLEN];
-
-		snprintf(dhcp_macro, sizeof (dhcp_macro),
-		    "dhcp_macro_%s", bfile);
-
-		/*
-		 * determine contents of bootfile info passed to dhcp script
-		 * as well as rootpath for sparc
-		 */
-		if (have_sparc) {
-			/*
-			 * Always use $serverIP keyword as setup-dhcp will
-			 * substitute the correct IP addresses in
-			 */
-			snprintf(dhcpbfile, sizeof (dhcpbfile),
-			    "http://%s:%u/%s", "\\$serverIP",
-			    http_port, WANBOOTCGI);
-		} else {
-			strlcpy(dhcpbfile, bfile, sizeof (dhcpbfile));
-		}
-
-		snprintf(cmd, sizeof (cmd), "%s %s %s %s %s",
-		    SETUP_DHCP_SCRIPT, DHCP_MACRO, have_sparc?"sparc":"x86",
-		    dhcp_macro, dhcpbfile);
-		/*
-		 * The setup-dhcp script takes care of printing output for the
-		 * user so there is no need to print anything for non-zero
-		 * return value.
-		 */
-		installadm_system(cmd);
-	}
-
-	if (dhcp_setup_needed && create_netimage) {
-		snprintf(cmd, sizeof (cmd), "%s %s %s %d %s",
-		    SETUP_DHCP_SCRIPT, DHCP_ASSIGN,
-		    ip_start, ip_count, dhcp_macro);
-		if (installadm_system(cmd) != 0) {
-			(void) fprintf(stderr,
-			    MSG_ASSIGN_DHCP_MACRO_ERR);
-		}
-	}
-
-	/*
-	 * Perform sparc/x86 specific actions.
-	 */
-	if (have_sparc) {
-		/* sparc only */
-		snprintf(cmd, sizeof (cmd), "%s %s %s %s %s",
-		    SETUP_SPARC_SCRIPT, SPARC_SERVER, target_directory,
-		    srv_name, srv_address);
-
-		if (installadm_system(cmd) != 0) {
-			(void) fprintf(stderr, MSG_SETUP_SPARC_FAIL);
-			return (INSTALLADM_FAILURE);
-		}
-	} else {
-		/* x86 only */
-		snprintf(cmd, sizeof (cmd), "%s %s %s %s %s %s",
-		    SETUP_TFTP_LINKS_SCRIPT, TFTP_SERVER, srv_name,
-		    target_directory, bfile,
-		    bootargs == NULL ? "null" : bootargs);
-
-		if (installadm_system(cmd) != 0) {
-			(void) fprintf(stderr, MSG_CREATE_TFTPBOOT_FAIL);
-			return (INSTALLADM_FAILURE);
-		}
-	}
-
-	return (INSTALLADM_SUCCESS);
-}
--- a/usr/src/cmd/installadm/create_client.py	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/installadm/create_client.py	Wed Mar 02 11:14:19 2011 -0800
@@ -104,6 +104,7 @@
     # Verify that the server settings are not obviously broken.
     # These checks cannot be complete, but check for things which 
     # will definitely cause failure.
+    logging.debug("Calling %s", CHECK_SETUP_SCRIPT)
     ret = Popen([CHECK_SETUP_SCRIPT]).wait()
     if ret:
         raise SystemExit(1)
@@ -139,14 +140,14 @@
         try:
             # set options.image to be an AIImage object
             image = com.AIImage(dir_path=options.image_path)
-        except com.AIImageError, err:
+        except com.AIImage.AIImageError as err:
             parser.error(err)
     # else, an image path was passed in, ensure it is the same architecture
     # as the service
     else:
         try:
             image = com.AIImage(dir_path=options.image_path)
-        except com.AIImageError, err:
+        except com.AIImage.AIImageError as err:
             parser.error(err)
         try:
             service_image = com.AIImage(dir_path=options.service['image_path'])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/installadm/create_service.py	Wed Mar 02 11:14:19 2011 -0800
@@ -0,0 +1,469 @@
+#!/usr/bin/python2.6
+
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+
+AI create-service
+
+'''
+
+import gettext
+import logging
+from optparse import OptionParser, OptionValueError
+import os
+import socket
+import sys
+
+import osol_install.auto_install.ai_smf_service as aismf
+import osol_install.auto_install.installadm_common as com
+import osol_install.libaimdns as libaimdns
+import osol_install.libaiscf as libaiscf
+
+from solaris_install import CalledProcessError, Popen
+
+
+_ = com._
+BASE_DEF_SVC_NAME = "_install_service_"
+
+
+def check_ip_address(option, opt_str, value, parser):
+    '''Check IP address as an OptionParser callback
+    Postcondition: sets value to proper option if check passes
+    Raises: OptionValueError if IP address is malformed
+    
+    '''
+    segments = value.split(".")
+    if len(segments) != 4:
+        raise OptionValueError(_("Malformed IP address: '%s'") % value)
+    for segment in segments:
+        try:
+            segment = int(segment)
+            if segment < 0 or segment > 255:
+                raise OptionValueError(_("Malformed IP address: '%s'") % value)
+        except ValueError, TypeError:
+            raise OptionValueError(_("Malformed IP address: '%s'") % value)
+    setattr(parser.values, option.dest, value)
+
+
+def check_targetdir(srcimage, targetdir):
+    '''
+    Check if target dir exists.  If it exists, check whether it has 
+    a valid net image. An empty dir is ok.
+
+    Raises: ValueError if a problem exists with targetdir
+
+    '''
+    req_file = os.path.join(targetdir, com.AI_NETIMAGE_REQUIRED_FILE)
+    
+    if srcimage:
+        # targetdir must not exist, or must be empty
+        if os.path.exists(targetdir):
+            try:
+                dirlist = os.listdir(targetdir)
+            except OSError as err:
+                raise ValueError(err)
+            
+            if dirlist:
+                if com.AI_NETIMAGE_REQUIRED_FILE in dirlist:
+                    raise ValueError(_("There is a valid image at (%s). "
+                                       "Please delete the image and try "
+                                       "again.") % targetdir)
+                else:
+                    raise ValueError(_("Target directory is not empty."))
+    else:
+        if not os.path.exists(targetdir):
+            raise ValueError(_("The specified target, %s, does not exist") %
+                             targetdir)
+        if not os.path.exists(req_file):
+            raise ValueError(_("The specified target, %s, does not contain"
+                               " a valid existing image.") % targetdir)
+
+
+def get_usage():
+    ''' get usage for create-service'''
+    return(_(
+        'create-service\t[-b|--boot-args <boot property>=<value>,...] \n'
+        '\t\t[-f|--bootfile <bootfile>] \n'
+        '\t\t[-n|--service <svcname>] \n'
+        '\t\t[-c|--ip-count <count_of_ipaddr>] \n'
+        '\t\t[-i|--ip-start <dhcp_ip_start>] \n'
+        '\t\t[-s|--source <srcimage>] \n'
+        '\t\t<targetdir>'))
+
+
+def parse_options(cmd_options=None):
+    '''
+    Parse and validate options
+    Args: sub-command, target directory
+    
+    Returns: An options record containing
+        bootargs
+        bootfile
+        dhcp_ip_count
+        dhcp_ip_start
+        srcimage
+        svcname
+        targetdir
+    
+    '''
+    logging.debug('**** START installadm.create_service.parse_options ****\n')
+    
+    usage = '\n' + get_usage()
+    description = _('Establishes an Automated Install network service.')
+    parser = OptionParser(usage=usage, prog="create-service",
+                          description=description)
+    parser.add_option('-b', '--boot-args', dest='bootargs', action='append',
+                      default=[],
+                      help=_('Comma separated list of <property>=<value>'
+                             ' pairs to add to the x86 Grub menu entry'))
+    parser.add_option('-f', '--bootfile', dest='bootfile', help=_('boot file'))
+    parser.add_option('-n', '--service', dest='svcname',
+                      help=_('service name'))
+    parser.add_option('-i', '--ip-start', dest='dhcp_ip_start', type='string',
+                      help=_('DHCP Starting IP Address'), action="callback",
+                      callback=check_ip_address)
+    parser.add_option('-c', '--ip-count', dest='dhcp_ip_count',
+                      type='int', help=_('DHCP Count of IP Addresses'))
+    parser.add_option('-s', '--source', dest='srcimage', type='string',
+                      help=_('Image ISO file'))
+    
+    options, args = parser.parse_args(cmd_options)
+    
+    # check that we have a target dir
+    if not args:
+        parser.error(_("Missing required argument, <targetdir>"))
+    elif len(args) > 1:
+        parser.error(_('Too many arguments: %s') % args)
+    
+    options.targetdir = args[0]
+    
+    # if service name provided, validate it
+    if options.svcname:
+        try:
+            com.validate_service_name(options.svcname)
+        except ValueError as err:
+            parser.error(err)
+
+        # Give error is service already exists
+        if aismf.is_pg(options.svcname):
+            parser.error(_('Service already exists: %s') % options.svcname)
+
+    # check dhcp related options
+    # don't allow DHCP setup if multihomed
+    if options.dhcp_ip_start or options.dhcp_ip_count:
+        if com.is_multihomed():
+            msg = _('DHCP server setup is not available on machines '
+                    'with multiple network interfaces (-i and -c options '
+                    'are disallowed).')
+            parser.error(msg)
+        
+        # Confirm options -i and -c are both provided 
+        if options.dhcp_ip_count is None:
+            parser.error(_('If -i option is provided, -c option must '
+                           'also be provided'))
+        if not options.dhcp_ip_start:
+            parser.error(_('If -c option is provided, -i option must '
+                           'also be provided'))
+        
+        # Confirm count of ip addresses is positive
+        if options.dhcp_ip_count < 1:
+            parser.error('"-c <count_of_ipaddr>" must be greater than zero.')
+    
+    # Make sure targetdir meets requirements
+    try:
+        check_targetdir(options.srcimage, options.targetdir)
+    except ValueError as error:
+        raise SystemExit(error)
+    
+    return options
+
+
+def setup_dhcp_server(ip_start, ip_count, dhcp_macro, dhcpbfile, arch):
+    '''Set-up DHCP server for given AI service, IP addresses and clients'''
+    
+    # dhcp setup script calls ripped from C implementation of create-service
+    
+    logging.debug("setup_dhcp_server: ip_start=%s, ip_count=%s, "
+                  "dhcp_macro=%s, dhcpbfile=%s, arch=%s" % 
+                  (ip_start, ip_count, dhcp_macro, dhcpbfile, arch))
+    if ip_count:
+        logging.debug("Calling %s %s %s %s", com.SETUP_DHCP_SCRIPT,
+                      com.DHCP_SERVER, ip_start, str(ip_count))
+        # The setup-dhcp server call takes care of printing output for
+        # the user so there is no need to check the result. If the call
+        # returns an error code, an exception is thrown, which the caller
+        # of this function should handle.
+        Popen.check_call([com.SETUP_DHCP_SCRIPT, com.DHCP_SERVER, ip_start,
+                         str(ip_count)])
+    
+    # The setup-dhcp macro call takes care of printing output for the
+    # user so there is no need to check the result.
+    logging.debug("Calling %s %s %s %s %s", com.SETUP_DHCP_SCRIPT,
+                  com.DHCP_MACRO, arch, dhcp_macro, dhcpbfile)
+    Popen([com.SETUP_DHCP_SCRIPT, com.DHCP_MACRO, arch, dhcp_macro,
+           dhcpbfile]).wait()
+    
+    if ip_count:
+        logging.debug("Calling %s %s %s %s %s", com.SETUP_DHCP_SCRIPT,
+                      com.DHCP_ASSIGN, ip_start, str(ip_count), dhcp_macro)
+        # The setup-dhcp assign call takes care of printing output for
+        # the user. A failure is not considered fatal, so just print an
+        # additional message for the user.
+        try:
+            Popen.check_call([com.SETUP_DHCP_SCRIPT, com.DHCP_ASSIGN, ip_start,
+                             str(ip_count), dhcp_macro])
+        except CalledProcessError:
+            print >> sys.stderr, _("Failed to assign DHCP macro to IP "
+                                   "address. Please assign manually.\n")
+
+
+def get_default_service_name():
+    ''' get default service name
+
+        Returns: default name for service, _install_service_<num>
+
+    '''
+    count = 1
+    svc_name = BASE_DEF_SVC_NAME + str(count)
+    while aismf.is_pg(svc_name):
+        count += 1
+        svc_name = BASE_DEF_SVC_NAME + str(count)
+    return svc_name
+
+
+def get_a_free_tcp_port(service_instance, hostname):
+    ''' get next free tcp port 
+
+        Looks for next free tcp port number, starting from 46501
+
+        Input: smf install server instance, hostname
+        Returns: next free tcp port number if one found or 
+                 None if no free port found
+             
+    '''
+    # determine ports in use by other install services
+    existing_ports = set()
+    for name in service_instance.services:
+        service = libaiscf.AIservice(service_instance, name)
+        svckeys = service.keys()
+        if aismf.PROP_TXT_RECORD in svckeys:
+            port = service[aismf.PROP_TXT_RECORD].split(':')[-1]
+            existing_ports.add(int(port))
+
+    logging.debug("get_a_free_tcp_port, existing_ports=%s", existing_ports)
+
+    starting_port = 46501
+    ending_port = socket.SOL_SOCKET  # last socket is 65535
+    mysock = None
+    for port in xrange(starting_port, ending_port):
+        try:
+            # skip ports of existing install services
+            if port in existing_ports:
+                continue
+            mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            mysock.bind((hostname, port))
+        except socket.error: 
+            continue
+        else: 
+            logging.debug("found free tcp port: %s" % port)
+            mysock.close()
+            break
+    else:
+        logging.debug("no available tcp port found")
+        return None
+            
+    return port
+
+
+def do_create_service(cmd_options=None):
+    '''
+    This method sets up the install service by:
+        - checking the network configuration
+        - creating the target image directory from an iso
+        - creating the smf property group
+        - enabling tftp service or configuring wanboot
+        - configuring dhcp if desired
+    
+    '''
+    # check that we are root
+    if os.geteuid() != 0:
+        raise SystemExit(_("Error: Root privileges are required"
+                           " for this command."))
+
+    logging.debug('**** START do_create_service ****')
+
+    # make sure we have the installadm smf service
+    try:
+        inst = libaiscf.AISCF(FMRI="system/install/server")
+    except KeyError:
+        raise SystemExit(_("Error: The system does not have the "
+                           "system/install/server SMF service"))
+
+    options = parse_options(cmd_options)
+
+    logging.debug('options: %s', options)
+    
+    # Verify that the server settings are not obviously broken
+    # (i.e., check for things which will definitely cause failure).
+    logging.debug('Check if the host server can support AI Install services.')
+    cmd = [com.CHECK_SETUP_SCRIPT, 
+           options.dhcp_ip_start if options.dhcp_ip_start else '']
+    logging.debug('Calling %s', cmd)
+    if Popen(cmd).wait():
+        raise SystemExit(1)
+    
+    # Obtain the host server hostname and IP address
+    options.server_hostname = socket.gethostname()
+    logging.debug("options.server_hostname=%s", options.server_hostname)
+
+    if com.is_multihomed():
+        options.server_ip = "$serverIP"
+    else:
+        options.server_ip = socket.gethostbyname(options.server_hostname)
+    
+    logging.debug("options.server_ip=%s", options.server_ip)
+
+    options.status = aismf.STATUS_ON
+    
+    # Setup the image
+    # If the targetdir doesn't exist, the script creates it
+    if options.srcimage:
+        cmd = [com.SETUP_IMAGE_SCRIPT, com.IMAGE_CREATE, options.srcimage,
+               options.targetdir]
+        logging.debug('Calling %s', cmd)
+        if Popen(cmd).wait():
+            raise SystemExit(1)
+    
+    # Check for compatibility with old service setup
+    cmd = [com.SETUP_IMAGE_SCRIPT, com.CHECK_IMAGE_VERSION, 
+           options.targetdir]
+    logging.debug('Calling %s', cmd)
+    compatibility_port = bool(Popen(cmd).wait())
+
+    logging.debug("compatibility port=%s", compatibility_port)
+
+    # Check whether image is sparc or x86 by checking existence
+    # of key directories
+    try:
+        image_arch = com.get_image_arch(options.targetdir)
+    except ValueError as err:
+        raise SystemExit(err)
+    logging.debug("image_arch=%s", image_arch)
+    
+    # Determine port information
+    http_port = libaimdns.getinteger_property(com.SRVINST, com.PORTPROP)
+
+    if compatibility_port:
+        port = get_a_free_tcp_port(inst, options.server_hostname)
+        if not port:
+            raise SystemExit(_("Cannot find a free port to start the "
+                               "web server."))
+    else:
+        port = http_port
+
+    # set text record to:
+    #   (if multihomed)   "aiwebserver=$serverIP:<port>"
+    #   (if single-homed) "aiwebserver=<server hostname>:<port>"
+    options.txt_record = '%s=%s:%u' % (com.AIWEBSERVER,
+                                       options.server_hostname,
+                                       port)
+
+    logging.debug("options.txt_record=%s", options.txt_record)
+
+    # get default service name, if needed
+    if not options.svcname:
+        options.svcname = get_default_service_name()
+
+    logging.debug("options.svcname=%s", options.svcname)
+
+    # Save location of service in format <server_ip_address>:<port>
+    # It will be used later for setting service discovery fallback
+    # mechanism. For multihomed, options.server_ip is: "$serverIP"
+    srv_address = '%s:%u' % (options.server_ip, port)
+
+    logging.debug("srv_address=%s", srv_address)
+
+    # if no bootfile provided, use the svcname
+    if not options.bootfile:
+        options.bootfile = options.svcname
+    
+    # Configure SMF
+    service_data = {aismf.PROP_SERVICE_NAME: options.svcname,
+                    aismf.PROP_IMAGE_PATH: options.targetdir,
+                    aismf.PROP_BOOT_FILE: options.bootfile,
+                    aismf.PROP_TXT_RECORD: options.txt_record,
+                    aismf.PROP_STATUS: aismf.STATUS_ON}
+    logging.debug("service_data=%s", service_data)
+    aismf.create_pg(options.svcname, service_data)
+    
+    # Register & enable service
+    # (Also enables system/install/server, as needed)
+    try:
+        aismf.enable_install_service(options.svcname)
+    except aismf.InstalladmAISmfServicesError as err:
+        raise SystemExit(err)
+
+    if image_arch == 'sparc':
+        # Always use $serverIP keyword as setup-dhcp will
+        # substitute in the correct IP addresses. 
+        dhcpbfile = 'http://%s:%u/%s' % ("$serverIP", http_port,
+                                         com.WANBOOTCGI)
+    else:
+        dhcpbfile = options.bootfile
+    
+    # Configure DHCP
+    if options.srcimage:
+        dhcp_macro = 'dhcp_macro_' + options.bootfile
+        logging.debug('Calling setup_dhcp_server %s %s %s %s %s', 
+                       options.dhcp_ip_start, options.dhcp_ip_count,
+                       dhcp_macro, dhcpbfile, image_arch)
+        try:
+            setup_dhcp_server(options.dhcp_ip_start, options.dhcp_ip_count,
+                              dhcp_macro, dhcpbfile, image_arch)
+        except CalledProcessError:
+            raise SystemExit(1)
+    
+    # Setup wanboot for SPARC or TFTP for x86
+    if image_arch == 'sparc':
+        cmd = [com.SETUP_SPARC_SCRIPT, com.SPARC_SERVER, options.targetdir,
+               options.svcname, srv_address]
+        logging.debug('Calling %s', cmd)
+        if Popen(cmd).wait():
+            raise SystemExit(1)
+    else:
+        if not options.bootargs:
+            options.bootargs.append("null")
+        cmd = [com.SETUP_TFTP_LINKS_SCRIPT, com.TFTP_SERVER, options.svcname,
+               options.targetdir, options.bootfile]
+        cmd.extend(options.bootargs)
+        logging.debug('Calling %s', cmd)
+        if Popen(cmd).wait():
+            raise SystemExit(1)
+
+
+if __name__ == '__main__':
+    # initialize gettext
+    gettext.install('ai', '/usr/lib/locale')
+    do_create_service()
--- a/usr/src/cmd/installadm/installadm.h	Wed Mar 02 10:11:44 2011 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
- */
-
-#ifndef	_INSTALLADM_H
-#define	_INSTALLADM_H
-
-#include <libaiscf.h>
-
-#define	INSTALLADM_SUCCESS 	0
-#define	INSTALLADM_FAILURE 	-1
-
-#define	AI_NETIMAGE_REQUIRED_FILE "solaris.zlib"
-#define	SETUP_IMAGE_SCRIPT	"/usr/lib/installadm/setup-image"
-#define	IMAGE_CREATE		"create"
-#define	CHECK_IMAGE_VERSION	"check_image_version"
-
-#define	AIWEBSERVER		"aiwebserver"
-#define	SETUP_SERVICE_SCRIPT	"/usr/lib/installadm/setup-service"
-#define	SERVICE_REGISTER	"register"
-
-#define	CHECK_SETUP_SCRIPT	"/usr/lib/installadm/check-server-setup"
-
-#define	SETUP_DHCP_SCRIPT	"/usr/lib/installadm/setup-dhcp"
-#define	DHCP_SERVER		"server"
-#define	DHCP_MACRO		"macro"
-#define	DHCP_ASSIGN		"assign"
-
-#define	SETUP_TFTP_LINKS_SCRIPT	"/usr/lib/installadm/setup-tftp-links"
-#define	TFTP_SERVER		"server"
-
-#define	SETUP_SPARC_SCRIPT	"/usr/lib/installadm/setup-sparc"
-#define	SPARC_SERVER		"server"
-#define	WANBOOTCGI		"cgi-bin/wanboot-cgi"
-
-#define	INSTALLADM_COMMON_SCRIPT	"/usr/lib/installadm/installadm-common"
-#define	KSH93	"/usr/bin/ksh93"
-#define	WC	"/usr/bin/wc"
-
-#define	SRV_INSTANCE		"svc:/system/install/server:default"
-#define	PORT_PROP		"all_services/port"
-#define	DEFAULT_HTTP_PORT	5555
-
-#define	MAXSERVICENAMELEN	63
-
-/*
- * For each service, we start a webserver at a port and register the port with
- * the service. We start looking at the port number from 46501
- */
-#define	START_WEB_SERVER_PORT	46501
-
-#define	MAX_TXT_RECORD_LEN	1024
-#define	DATALEN			256
-#define	STATUSLEN		16
-#define	INSTALL_SERVER_FMRI_BASE	"svc:/system/install/server"
-#define	INSTALL_SERVER_DEF_INST	"default"
-
-/*
- * For each service, store service data in the SMF repository. Use the
- * following keys to locate and store the data:
- */
-#define	SERVICE			"service_name"
-#define	IMAGE_PATH		"image_path"
-#define	BOOT_FILE		"boot_file"
-#define	TXT_RECORD		"txt_record"
-#define	SERVICE_STATUS		"status"
-
-#define	STATUS_ON		"on"
-
-typedef struct service_data {
-	char	svc_name[DATALEN];
-	char	image_path[MAXPATHLEN];
-	char	boot_file[MAXNAMELEN];
-	char	txt_record[MAX_TXT_RECORD_LEN];
-	char	status[STATUSLEN];
-} service_data_t;
-
-/*
- * function prototypes
- */
-boolean_t validate_service_name(char *);
-boolean_t save_service_data(scfutilhandle_t *, service_data_t);
-boolean_t get_service_data(scfutilhandle_t *, char *, service_data_t *);
-boolean_t service_exists(scfutilhandle_t *, char *);
-uint16_t get_a_free_tcp_port(scfutilhandle_t *, uint16_t);
-int installadm_system(char *);
-
-/*
- * installadm messages
- */
-#define	TEXT_DOMAIN		"SUNW_INSTALL_INSTALLADM"
-#define	INSTALLADMSTR(x)	dgettext(TEXT_DOMAIN, x)
-
-#define	MSG_MISSING_OPTIONS	INSTALLADMSTR(\
-	"%s: missing one or more required options.\nusage:\n")
-#define	MSG_OPTION_UNRECOGNIZED	INSTALLADMSTR(\
-	"unrecognized option '-%c'\nusage: %s.\n")
-#define	MSG_TARGET_NOT_EMPTY	INSTALLADMSTR(\
-	"Target directory is not empty.\n")
-#define	MSG_VALID_IMAGE_ERR	INSTALLADMSTR(\
-	"There is a valid image at (%s)." \
-	" Please delete the image and try again.\n")
-#define	MSG_DIRECTORY_ACCESS_ERR	INSTALLADMSTR(\
-	"Cannot access directory %s, error = %d.\n")
-#define	MSG_CREATE_IMAGE_ERR	INSTALLADMSTR(\
-	"Create image failed.\n")
-#define	MSG_UNABLE_TO_DETERMINE_ARCH	INSTALLADMSTR(\
-	"Unable to determine Oracle Solaris install image type.\n")
-#define	MSG_REGISTER_SERVICE_FAIL	INSTALLADMSTR(\
-	"Failed to register Install Service %s.\n")
-#define	MSG_SERVICE_EXISTS	INSTALLADMSTR(\
-	"The service %s already exists\n")
-#define	MSG_CREATE_DHCP_SERVER_ERR	INSTALLADMSTR(\
-	"Failed to setup DHCP server.\n")
-#define	MSG_CREATE_DHCP_MACRO_ERR	INSTALLADMSTR(\
-	"Failed to setup DHCP macro.\n")
-#define	MSG_GET_HOSTNAME_FAIL	INSTALLADMSTR(\
-	"Failed to get the hostname of the server.\n")
-#define	MSG_ASSIGN_DHCP_MACRO_ERR	INSTALLADMSTR(\
-	"Failed to assign DHCP macro to IP address. Please assign manually.\n")
-#define	MSG_CREATE_TFTPBOOT_FAIL	INSTALLADMSTR(\
-	"Failed to setup the TFTP bootfile.\n")
-#define	MSG_SETUP_SPARC_FAIL	INSTALLADMSTR(\
-	"Failed to setup the SPARC configuration file.\n")
-#define	MSG_AI_SMF_INIT_FAIL	INSTALLADMSTR(\
-	"AI SMF initialization failed\n")
-#define	MSG_GET_PG_NAME_FAILED	INSTALLADMSTR(\
-	"Failed to get the SMF property group for service %s\n")
-#define	MSG_GET_SMF_INSTANCE_FAILED	INSTALLADMSTR(\
-	"Failed to get the SMF instance.\n")
-#define	MSG_CREATE_INSTALL_SERVICE_FAILED	INSTALLADMSTR(\
-	"Failed to create Install Service : %s\n")
-#define	MSG_GET_SERVICE_PROPS_FAIL	INSTALLADMSTR(\
-	"Failed to get SMF properties for service %s\n")
-#define	MSG_SET_SERVICE_PROPS_FAIL	INSTALLADMSTR(\
-	"Failed to set SMF properties for service %s\n")
-#define	MSG_SAVE_SERVICE_PROPS_FAIL	INSTALLADMSTR(\
-	"Failed to save SMF properties for service %s\n")
-#define	MSG_CANNOT_FIND_PORT	INSTALLADMSTR(\
-	"Cannot find a free port to start the web server.\n")
-#define	MSG_ROOT_PRIVS_REQD	INSTALLADMSTR(\
-	"Root privileges are required to run the %s %s command.\n")
-#define	MSG_BAD_SERVICE_NAME    INSTALLADMSTR(\
-	"Service name must contain only alphanumeric chars, \"_\" and \"-\" " \
-	"and shorter then 64 characters in length\n")
-#define	MSG_BAD_SERVER_SETUP	INSTALLADMSTR(\
-	"Please check server network settings and try again.\n")
-#define	MSG_MULTIHOMED_DHCP_DENY	INSTALLADMSTR(\
-	"Setting up a DHCP server is not available on machines with " \
-	"multiple network interfaces (-i and -c options unavailable).\n")
-
-#endif /* _INSTALLADM_H */
--- a/usr/src/cmd/installadm/installadm.py	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/installadm/installadm.py	Wed Mar 02 11:14:19 2011 -0800
@@ -33,6 +33,7 @@
 from optparse import OptionParser, SUPPRESS_HELP
 
 from osol_install.auto_install import create_client
+from osol_install.auto_install import create_service
 from osol_install.auto_install import delete_client
 from osol_install.auto_install import delete_manifest 
 from osol_install.auto_install import delete_service 
@@ -40,11 +41,12 @@
 from osol_install.auto_install import publish_manifest
 from osol_install.auto_install import set_criteria
 from osol_install.auto_install.ai_smf_service import \
-    PROP_STATUS, InstalladmAISmfServicesError, check_for_enabled_services, \
-    enable_install_service, get_pg_props, is_pg, set_pg_props
+    PROP_STATUS, STATUS_OFF, InstalladmAISmfServicesError, \
+    check_for_enabled_services, enable_install_service, \
+    get_pg_props, is_pg, set_pg_props
 from osol_install.auto_install.installadm_common import _,  \
-    CHECK_SETUP_SCRIPT, CREATE_SERVICE_BINARY, SERVICE_DISABLE, \
-    SETUP_SERVICE_SCRIPT, STATUS_OFF, validate_service_name
+    CHECK_SETUP_SCRIPT, SERVICE_DISABLE, SETUP_SERVICE_SCRIPT, \
+    validate_service_name
 from solaris_install import Popen
 
 
@@ -53,33 +55,24 @@
 LOG_FORMAT = ("%(filename)s:%(lineno)d %(message)s")
 
 
-def get_cs_usage():
-    ''' get usage for create-service'''
-    usage = _(
-        'create-service\t[-b <boot property>=<value>,...]\n'
-        '\t\t[-f <bootfile>]\n'
-        '\t\t[-n <svcname>]\n'
-        '\t\t[-i <dhcp_ip_start>]\n'
-        '\t\t[-c <count_of_ipaddr>]\n'
-        '\t\t[-s <image ISO file>]\n'
-        '\t\t<targetdir>')
-    return(usage)
-
 def get_enable_usage():
     ''' get usage for enable'''
     usage = _('enable\t<svcname>')
     return(usage)
 
+
 def get_disable_usage():
     ''' get usage for disable'''
     usage = _('disable\t[-t|--temporary] <svcname>')
     return(usage)
 
+
 def get_help_usage():
     ''' get usage for help'''
     usage = _('help\t[<subcommand>]')
     return(usage)
 
+
 def setup_logging(log_level):
     '''Initialize the logger, logging to stderr at log_level,
        log_level defaults to warn
@@ -100,7 +93,8 @@
 
     # set up logging to stderr
     logging.basicConfig(stream=sys.stderr, level=log_level, format=LOG_FORMAT)
-    
+
+
 def do_enable_service(cmd_options=None):
     ''' Enable a service
 
@@ -145,6 +139,7 @@
     # Verify that the server settings are not obviously broken.
     # These checks cannot be complete, but do check for things
     # which will definitely cause failure.
+    logging.debug('Calling %s', CHECK_SETUP_SCRIPT)
     ret = Popen([CHECK_SETUP_SCRIPT]).wait()
     if ret:
         return 1
@@ -223,6 +218,7 @@
     cmd = [SETUP_SERVICE_SCRIPT, SERVICE_DISABLE, svcname]
 
     logging.debug("Disabling install service %s", svcname)
+    logging.debug("Calling %s", cmd)
     ret = Popen(cmd).wait()
     if ret:
         return 1
@@ -238,18 +234,6 @@
         except InstalladmAISmfServicesError as err:
             raise SystemExit(err)
 
-def do_create_service(cmdargs):
-    '''
-    Create a service
-
-    Pass all command line options to create_service binary.
-    '''
-    logging.debug("**** START do_create_service ****")
-
-    cmdargs.insert(0, CREATE_SERVICE_BINARY)
-    logging.debug("Calling %s", cmdargs)
-    return Popen(cmdargs).wait()
-
 
 def main():
     ''' installadm main
@@ -264,31 +248,31 @@
     # is a tuple consisting of the method to call to invoke the 
     # subcommand and the method to call to get usage for the subcommand. 
     sub_cmds = {
-        'create-service'   : (do_create_service, 
-                              get_cs_usage()),
-        'delete-service'   : (delete_service.do_delete_service, 
+        'create-service'   : (create_service.do_create_service,
+                              create_service.get_usage()),
+        'delete-service'   : (delete_service.do_delete_service,
                               delete_service.get_usage()),
-        'list'             : (ai_list.do_list, 
-                              ai_list.get_usage()), 
-        'enable'           : (do_enable_service, 
+        'list'             : (ai_list.do_list,
+                              ai_list.get_usage()),
+        'enable'           : (do_enable_service,
                               get_enable_usage()),
-        'disable'          : (do_disable_service, 
+        'disable'          : (do_disable_service,
                               get_disable_usage()),
-        'create-client'    : (create_client.do_create_client, 
+        'create-client'    : (create_client.do_create_client,
                               create_client.get_usage()),
-        'delete-client'    : (delete_client.do_delete_client, 
+        'delete-client'    : (delete_client.do_delete_client,
                               delete_client.get_usage()),
-        'add-manifest'     : (publish_manifest.do_publish_manifest, 
+        'add-manifest'     : (publish_manifest.do_publish_manifest,
                               publish_manifest.get_usage()),
         'add'              : (publish_manifest.do_publish_manifest,  # alias
-                              publish_manifest.get_usage()), 
-        'delete-manifest'  : (delete_manifest.do_delete_manifest, 
+                              publish_manifest.get_usage()),
+        'delete-manifest'  : (delete_manifest.do_delete_manifest,
                               delete_manifest.get_usage()),
         'remove'           : (delete_manifest.do_delete_manifest,  # alias
-                              delete_manifest.get_usage()),  
-        'set-criteria'     : (set_criteria.do_set_criteria, 
+                              delete_manifest.get_usage()),
+        'set-criteria'     : (set_criteria.do_set_criteria,
                               set_criteria.get_usage()),
-        'help'             : (None, get_help_usage())      
+        'help'             : (None, get_help_usage())
         }
 
     # cmds is a list of subcommands used to dictate the order of
@@ -367,11 +351,10 @@
         except Exception:
             sys.stderr.write(_("%s:\n"
                                "\tUnhandled error encountered:\n") % sub_cmd)
-            traceback.print_exc(limit=2, file=sys.stderr)
+            traceback.print_exc(file=sys.stderr)
             sys.stderr.write(_("\tPlease report this as a bug at "
                                "http://defect.opensolaris.org\n"))
 
+
 if __name__ == '__main__':
-
     sys.exit(main())
-
--- a/usr/src/cmd/installadm/installadm_common.py	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/installadm/installadm_common.py	Wed Mar 02 11:14:19 2011 -0800
@@ -37,8 +37,8 @@
 import subprocess
 import sys
 import time
-from subprocess import Popen, PIPE
 
+from solaris_install import Popen
 import osol_install.libaiscf as smf
 
 
@@ -55,42 +55,94 @@
 REGTYPE = '_OSInstall._tcp'
 DOMAIN = 'local'
 
+# Maximum service name length
+MAX_SERVICE_NAME_LEN = 63
+
 # FMRI for AI service and select properties, private
 SRVINST = 'svc:/system/install/server:default'
 EXCLPROP = 'all_services/exclude_networks'
 NETSPROP = 'all_services/networks'
 PORTPROP = 'all_services/port'
 
+# File used to verify that image is ai netimage
+AI_NETIMAGE_REQUIRED_FILE = "solaris.zlib"
+
 # Default port for the webserver
 DEFAULT_PORT = 5555
 
-STATUS_ON = 'on'
-STATUS_OFF = 'off'
+# Location of wanboot-cgi file for sparc dhcp setup
+WANBOOTCGI = 'cgi-bin/wanboot-cgi'
+
+# Directory for per service information
 AI_SERVICE_DIR_PATH = '/var/ai/'
-SERVICE_REGISTER = 'register'
-SERVICE_DISABLE = 'disable'
+
+# Script paths and arguments
+AIWEBSERVER = "aiwebserver"
+CHECK_IMAGE_VERSION = "check_image_version"
+CHECK_SETUP_SCRIPT = "/usr/lib/installadm/check-server-setup"
+DHCP_ASSIGN = "assign"
+DHCP_CLIENT = "client"
+DHCP_MACRO = "macro"
+DHCP_SERVER = "server"
+IMAGE_CREATE = "create"
+SERVICE_DISABLE = "disable"
+SERVICE_LIST = "list"
+SERVICE_REGISTER = "register"
+SETUP_DHCP_SCRIPT = "/usr/lib/installadm/setup-dhcp"
+SETUP_IMAGE_SCRIPT = "/usr/lib/installadm/setup-image"
+SETUP_SERVICE_SCRIPT = "/usr/lib/installadm/setup-service"
+SETUP_SPARC_SCRIPT = "/usr/lib/installadm/setup-sparc"
+SETUP_TFTP_LINKS_SCRIPT = "/usr/lib/installadm/setup-tftp-links"
+SPARC_SERVER = "server"
+TFTP_SERVER = "server"
+
+# Needed for the is_multihomed()
+INSTALLADM_COMMON_SH = "/usr/lib/installadm/installadm-common"
+KSH93 = "/usr/bin/ksh93"
+VALID_NETWORKS = "valid_networks"
+WC = "/usr/bin/wc"
 
-CREATE_SERVICE_BINARY = '/usr/sbin/create-service'
-CHECK_SETUP_SCRIPT = '/usr/lib/installadm/check-server-setup'
-SETUP_SERVICE_SCRIPT = '/usr/lib/installadm/setup-service'
+# Ripped from installadm.c for now
+MULTIHOMED_TEST = ("/usr/bin/test `%(ksh93)s -c 'source %(com-script)s;"
+                   " %(valid_net)s | %(wc)s -l'` -eq 1" %
+                   {"ksh93" : KSH93, "com-script" : INSTALLADM_COMMON_SH,
+                    "valid_net" : VALID_NETWORKS, "wc" : WC})
+
+
+def is_multihomed():
+    ''' Determines if system is multihomed
+    Returns True if multihomed, False if not
+
+    '''
+
+    logging.debug("is_multihomed(): Calling %s", MULTIHOMED_TEST)
+    multihomed = Popen(MULTIHOMED_TEST, shell=True).wait()
+    return (multihomed != 0)
+
 
-# Maximum service name length
-MAX_SERVICE_NAME_LEN = 63
+def get_image_arch(path):
+    ''' get architecture of image
+
+        Input: Path to image
+        Returns: 'sparc' or 'x86'
+        Raises: ValueError if unable to determine architecture of image
+
+    '''
+    sparc_path = os.path.join(path, "platform/sun4v")
+    x86_path = os.path.join(path, "platform/i86pc")
+    if os.path.exists(sparc_path):
+        return "sparc"
+    elif os.path.exists(x86_path):
+        return "x86"
+    else:
+        raise ValueError(_("Unable to determine Oracle Solaris install "
+                           "image type."))
+
 
 #
 # General classes below
 #
 
-class InstalladmCommonExit(SystemExit):
-    '''
-    An unrecoverable error occurred. Exit this program without a traceback.
-    The exact cause of the error should have been logged.
-
-    This error is raised if the input arguments are not valid.
-    '''
-    pass
-
-
 class AIImage(object):
     """
     Class to hold Auto Installer boot image properties and functions
@@ -519,14 +571,14 @@
                 # represent the fields available if wrapped_function is just
                 # returning this function
                 self = obj.headers
-
+            
             def __getattr__(self, key):
                 """
                 Provide an interface so one can run:
                 _object_instance.ATTRIBUTE:
                 """
                 return wrapped_function(self.obj, key)
-
+            
             def __call__(self):
                 """
                 Return valid keys if the class is simply called to avoid
@@ -1285,10 +1337,12 @@
     if len(svcname) > MAX_SERVICE_NAME_LEN:
         raise ValueError(error)
 
-    # accept alphanumeric chars, '-', and '_'
-    for char in svcname:
-        if not (char.isalnum() or char == '-' or char == '_'):
-            raise ValueError(error)
+    # Accept alphanumeric chars, '-', and '_'. By removing '-' and
+    # '_' from the string, isalnum can be used to test the rest 
+    # of the characters.
+    svcname = svcname.replace("-", "").replace("_", "")
+    if not svcname.isalnum():
+        raise ValueError(error)
 
 
 def find_TFTP_root():
@@ -1345,8 +1399,9 @@
         basedir = svcprop_out[2].rstrip("\n")
         if not basedir:
             basedir = defaultbasedir
+    
+    return basedir
 
-    return basedir
 
 if __name__ == "__main__":
     import doctest
--- a/usr/src/cmd/installadm/installadm_util.c	Wed Mar 02 10:11:44 2011 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,544 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <stdio.h>
-#include <locale.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <strings.h>
-
-#include "installadm.h"
-
-/*
- * Installadm utility functions
- */
-boolean_t get_service_props(scfutilhandle_t *, char *, service_data_t *);
-boolean_t set_service_props(scfutilhandle_t *, char *, service_data_t);
-boolean_t is_port_in_use(scfutilhandle_t *, uint16_t);
-
-/*
- * validate_service_name()
- * Verify that the string being used is shorter then 64 characters long
- * and that the characters used in the string are limited to alphanumerics,
- * hyphen and underscore.
- *
- * Input:
- * char *check_this	- String to check
- *
- * Returns:
- * boolean:
- *	B_TRUE: string verifies.
- *	B_FALSE: string doesn't verify or is NULL.
- */
-boolean_t
-validate_service_name(char *check_this)
-{
-	char *cchr;
-
-	if (check_this == NULL) {
-		return (B_FALSE);
-	}
-
-	if (strlen(check_this) > MAXSERVICENAMELEN) {
-		return (B_FALSE);
-	}
-
-	for (cchr = check_this; *cchr != '\0'; cchr++) {
-		/* isalnum can return non-std ASCII when locale is not C */
-		if (!((isalnum(*cchr) && isascii(*cchr)) ||
-		    (*cchr == '_') || (*cchr == '-'))) {
-			return (B_FALSE);
-		}
-	}
-	return (B_TRUE);
-}
-
-/*
- * get_http_port
- * Retrieves the default http port property associated with the automated
- * install services stored in the SMF properties.
- *
- * Input:
- * scfutilhandle *handle - The handle to the aiscf utility library.
- *
- * Output:
- * None
- *
- * Returns:
- * http_port number
- */
-int
-get_http_port(scfutilhandle_t *hdl)
-{
-	int http_port = DEFAULT_HTTP_PORT;
-	scf_handle_t *handle = hdl->handle;
-	scf_property_t *prop = NULL;
-	scf_value_t *value = NULL;
-	char buf[MAXPATHLEN];
-	int decoded;
-	int64_t out;
-	char *fmri = SRV_INSTANCE;
-	char *propname = PORT_PROP;
-
-	if (scf_handle_bind(handle) < 0 ||
-	    (prop = scf_property_create(handle)) == NULL) {
-		goto cleanup;
-	}
-	snprintf(buf, MAXPATHLEN, "%s/:properties/%s", fmri, propname);
-
-	decoded = scf_handle_decode_fmri(handle, buf, NULL, NULL, NULL,
-	    NULL, prop, SCF_DECODE_FMRI_EXACT);
-	if (decoded < 0 || (value = scf_value_create(handle)) == NULL ||
-	    scf_property_get_value(prop, value) != 0 ||
-	    scf_value_get_integer(value, &out) != 0) {
-		goto cleanup;
-	}
-	http_port = (int)out;
-
-cleanup:
-	if (value != NULL)
-		scf_value_destroy(value);
-	if (prop != NULL)
-		scf_property_destroy(prop);
-
-	return (http_port);
-}
-
-/*
- * get_a_free_tcp_port
- * This returns the next available tcp port
- *
- * Input:
- * scfutilhandle *handle	- The handle to the aiscf utility library.
- * uint16_t start		- Find a free port starting from this port
- *
- * Returns:
- * uint16_t port	- An unused port
- */
-uint16_t
-get_a_free_tcp_port(scfutilhandle_t *handle, uint16_t start)
-{
-	uint16_t port;
-	int	sock;
-	struct sockaddr_in addr;
-	boolean_t found_free_port = B_FALSE;
-
-	port = start;
-
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0) {
-		return (0);
-	}
-
-	addr.sin_addr.s_addr = INADDR_ANY;
-	addr.sin_family = AF_INET;
-
-	while (!found_free_port) {
-		/*
-		 * check whether this port is used by a service that is not
-		 * active now. If so, find a new port
-		 */
-		while (is_port_in_use(handle, port)) {
-			port++;
-		}
-		addr.sin_port = htons(port);
-		if (bind(sock, (struct sockaddr *)&addr,
-		    sizeof (addr)) == 0) {
-			found_free_port = B_TRUE;
-		} else {
-			port++;
-		}
-	}
-
-	/*
-	 * Now close the socket and use the port
-	 */
-	close(sock);
-	return (port);
-}
-
-/*
- * is_port_in_use
- * This checks if a port is in use (i.e., is contained in the txt_record
- *	in one of the service properties)
- *
- * Input:
- * scfutilhandle *handle	- The handle to the aiscf utility library.
- * uint16_t port		- port to check
- *
- * Returns:
- * B_TRUE		If the port is in use
- * B_FALSE		If the port is not in use
- */
-boolean_t
-is_port_in_use(scfutilhandle_t *handle, uint16_t port)
-{
-	service_data_t	service_data;
-	char		*str;
-	uint16_t	service_port;
-	ai_pg_list_t	*pg = NULL;
-	ai_pg_list_t	*pgs = NULL;
-
-	if (ai_get_pgs(handle, &pgs) != AI_SUCCESS)
-		return (B_FALSE);
-
-	if (pgs == NULL)
-		return (B_FALSE);
-	pg = pgs;
-	while (pg != NULL && pg->pg_name != NULL) {
-		/*
-		 * Get the service data from the SMF properies for this
-		 * property group.
-		 */
-		if (get_service_props(handle, pg->pg_name,
-		    &service_data) != B_TRUE) {
-			(void) fprintf(stderr, MSG_GET_SERVICE_PROPS_FAIL,
-			    pg->pg_name);
-			ai_free_pg_list(pgs);
-			return (B_FALSE);
-		}
-
-		/*
-		 * Strip the port number out of the text-record property.
-		 */
-		if (service_data.txt_record != NULL) {
-			str = strrchr(service_data.txt_record, ':');
-			if (str == NULL) {
-				pg = pg->next;
-				continue;
-			}
-			str++;
-			/*
-			 * If the service port equals the port we're looking
-			 * for then it's in use.
-			 */
-			errno = 0;
-			service_port = strtol(str, (char **)NULL, 10);
-			if (errno != 0) {
-				pg = pg->next;
-				continue;
-			}
-			if (port == service_port) {
-				ai_free_pg_list(pgs);
-				return (B_TRUE);
-			}
-		}
-		pg = pg->next;
-	}
-	ai_free_pg_list(pgs);
-	return (B_FALSE);
-}
-
-/*
- * get_service_props
- * Retrieves the properties associated with the service stored in the
- * SMF property group when the service is started.
- *
- * Input:
- * scfutilhandle *handle - The handle to the aiscf utility library.
- * char		*pg_name - The service name we're looking for.
- * service_data_t *data  - The service property data structure used to
- *			   pass back the property values.
- *
- * Output:
- * service_data_t *data	- The values are copied to the structure service_data_t
- *
- * Returns:
- * B_TRUE		If the retrieval is successful
- * B_FALSE		If there is a failure
- */
-boolean_t
-get_service_props(
-	scfutilhandle_t *handle,
-	char *pg_name,
-	service_data_t *data)
-{
-	ai_prop_list_t *prop_list = NULL;
-	ai_prop_list_t *prop_head = NULL;
-
-	if (handle == NULL || pg_name == NULL || data == NULL)
-		return (B_FALSE);
-
-	if (ai_read_all_props_in_pg(handle, pg_name, &prop_head) != 0 ||
-	    prop_head == NULL)
-		return (B_FALSE);
-
-	/*
-	 * The service property group has a number of properties with each
-	 * property containing a key-value pair for each of the service
-	 * properties as follows:
-	 * service_name=<service_name>
-	 * image_path=<image_path>
-	 * boot_file=<boot_file>
-	 * txt_record=<txt_record>
-	 * status=on|off
-	 */
-
-	prop_list = prop_head;
-	while (prop_list != NULL) {
-		if (strstr(prop_list->name, SERVICE) != NULL) {
-			strlcpy(data->svc_name, prop_list->valstr, DATALEN);
-		} else if (strstr(prop_list->name, IMAGE_PATH) != NULL) {
-			strlcpy(data->image_path, prop_list->valstr,
-			    MAXPATHLEN);
-		} else if (strstr(prop_list->name, BOOT_FILE) != NULL) {
-			strlcpy(data->boot_file, prop_list->valstr, MAXNAMELEN);
-		} else if (strstr(prop_list->name, TXT_RECORD) != NULL) {
-			strlcpy(data->txt_record, prop_list->valstr,
-			    MAX_TXT_RECORD_LEN);
-		} else if (strstr(prop_list->name, SERVICE_STATUS) != NULL) {
-			strlcpy(data->status, prop_list->valstr, STATUSLEN);
-		}
-		prop_list = prop_list->next;
-	}
-	ai_free_prop_list(prop_head);
-	return (B_TRUE);
-}
-
-/*
- * set_service_props
- * This function sets the properties associated with the service
- * passed in the service_data_t structure
- *
- * Input:
- * scfutilhandle_t *handle	- The handle to the aiscf utility library.
- * char *pg_name 		- The property group name for this automated
- *				  installer service.
- * service_data_t data		- The values are passed in the structure
- *				  service_data_t
- *
- * Output:
- * None
- *
- * Returns:
- * B_TRUE		If setting the propeties is successful
- * B_FALSE		If there is a failure
- */
-boolean_t
-set_service_props(scfutilhandle_t *handle, char *pg_name, service_data_t data)
-{
-	/*
-	 * The service property group has a number of properties with each
-	 * property containing key-value pair for each of the service
-	 * properties as follows:
-	 * service_name=<service_name>
-	 * image_path=<image_path>
-	 * boot_file=<boot_file>
-	 * txt_record=<txt_record>
-	 * status=on/off
-	 */
-	if (pg_name == NULL) {
-		return (B_FALSE);
-	}
-
-	if (data.svc_name != NULL) {
-		if (ai_set_property(handle, pg_name, SERVICE,
-		    data.svc_name) != AI_SUCCESS) {
-			return (B_FALSE);
-		}
-	}
-
-	if (data.image_path != NULL) {
-		if (ai_set_property(handle, pg_name, IMAGE_PATH,
-		    data.image_path) != AI_SUCCESS) {
-			return (B_FALSE);
-		}
-	}
-
-	if (data.boot_file != NULL) {
-		if (ai_set_property(handle, pg_name, BOOT_FILE,
-		    data.boot_file) != AI_SUCCESS) {
-			return (B_FALSE);
-		}
-	}
-
-	if (data.txt_record != NULL) {
-		if (ai_set_property(handle, pg_name, TXT_RECORD,
-		    data.txt_record) != AI_SUCCESS) {
-			return (B_FALSE);
-		}
-	}
-
-	if (data.status != NULL) {
-		if (ai_set_property(handle, pg_name, SERVICE_STATUS,
-		    data.status) != AI_SUCCESS) {
-			return (B_FALSE);
-		}
-	}
-
-	return (B_TRUE);
-}
-
-/*
- * get_service_data
- * Obtain the information about the service passed as the first parameter
- *
- * Input:
- * scfutilhandle_t *handle	- The handle to the aiscf utility library.
- * char *service		- Name of the service
- * service_data_t data		- The values are passed in the structure
- *				  service_data_t
- *
- * Output:
- * scfutilhandle *handle - The handle to the aiscf utility library.
- * service_data_t *data	 - The info about the service is copied to the
- *			   structure service_data_t
- * Return:
- * B_TRUE		- If the service is found
- * B_FALSE		- If the service cannot be found or an error occurs
- */
-boolean_t
-get_service_data(scfutilhandle_t *handle, char *service, service_data_t *data)
-{
-	char		*ai_name = NULL;
-
-	if (handle == NULL || service == NULL || data == NULL) {
-			return (B_FALSE);
-	}
-
-	ai_name = ai_make_pg_name(service);
-	if (ai_name == NULL) {
-		(void) fprintf(stderr, MSG_GET_PG_NAME_FAILED,
-		    service);
-		return (B_FALSE);
-	}
-
-	if (get_service_props(handle, ai_name, data) != B_TRUE) {
-		(void) fprintf(stderr, MSG_GET_SERVICE_PROPS_FAIL,
-		    ai_name);
-		free(ai_name);
-		return (B_FALSE);
-	}
-	free(ai_name);
-	return (B_TRUE);
-}
-
-
-/*
- * save_service_data
- *
- * The passed in information about a service is saved to a smf property group.
- *
- * Input:
- * scfutilhandle_t *handle	- The handle to the aiscf utility library.
- * service_data_t data		- Service data in structure service_data_t
- *
- * Return:
- * B_TRUE		- If the property is saved
- * B_FALSE		- If there is a problem saving the property
- */
-boolean_t
-save_service_data(scfutilhandle_t *handle, service_data_t data)
-{
-	char	*ai_name;
-
-	ai_name = ai_make_pg_name(data.svc_name);
-	if (ai_name == NULL) {
-		(void) fprintf(stderr, MSG_GET_PG_NAME_FAILED,
-		    data.svc_name);
-		return (B_FALSE);
-	}
-
-	if (set_service_props(handle, ai_name, data) != B_TRUE) {
-		(void) fprintf(stderr, MSG_SET_SERVICE_PROPS_FAIL,
-		    ai_name);
-		free(ai_name);
-		return (B_FALSE);
-	}
-
-	free(ai_name);
-	return (B_TRUE);
-}
-
-
-/*
- * service_exists
- *
- * Checks if an install service exists.
- *
- * Input:
- * scfutilhandle_t *handle	- The handle to the aiscf utility library.
- * char *service_name 		- Service name of install service to check
- *
- * Return:
- * B_TRUE	- If the install service exists
- * B_FALSE	- If the install service does not exist
- */
-boolean_t
-service_exists(scfutilhandle_t *handle, char *service_name)
-{
-	char	*ai_name;
-
-	if (service_name == NULL || handle == NULL) {
-		return (B_FALSE);
-	}
-
-	ai_name = ai_make_pg_name(service_name);
-	if (ai_name == NULL) {
-		(void) fprintf(stderr, MSG_GET_PG_NAME_FAILED,
-		    service_name);
-		return (B_FALSE);
-	}
-
-	if (ai_get_instance(handle, "default") != AI_SUCCESS) {
-		(void) fprintf(stderr, MSG_GET_SMF_INSTANCE_FAILED);
-		free(ai_name);
-		return (B_FALSE);
-	}
-
-	if (ai_get_pg(handle, ai_name) != AI_SUCCESS) {
-		free(ai_name);
-		return (B_FALSE);
-	}
-
-	free(ai_name);
-	return (B_TRUE);
-}
-
-
-/*
- * installadm_system()
- *
- * Function to execute shell commands in a thread-safe manner
- * Parameters:
- *	cmd - the command to execute
- * Return:
- *	return code from command
- *	if popen() fails, -1
- * Status:
- *	private
- */
-int
-installadm_system(char *cmd)
-{
-	FILE	*p;
-
-	if ((p = popen(cmd, "w")) == NULL)
-		return (-1);
-
-	return (pclose(p));
-}
--- a/usr/src/cmd/installadm/smf_test/test_ai_smf_service.py	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/cmd/installadm/smf_test/test_ai_smf_service.py	Wed Mar 02 11:14:19 2011 -0800
@@ -33,10 +33,7 @@
 import unittest
 from subprocess import Popen, PIPE
 
-import osol_install.libaiscf as smf
-
-from  osol_install.auto_install.ai_smf_service import is_pg, \
-    get_pg_props, set_pg_props, get_all_pg_props
+import osol_install.auto_install.ai_smf_service as aismf 
 
 
 AI_SVC = 'svc:/system/install/server:default'
@@ -93,9 +90,13 @@
     @classmethod
     def setUpClass(cls):
         '''class test set up '''
-        cls.pgname = os.path.basename(tempfile.mkstemp()[1])
+        cls.name = tempfile.mkstemp()[1]
+        cls.name2 = tempfile.mkstemp()[1]
+        cls.name3 = tempfile.mkstemp()[1]
+        cls.pgname = os.path.basename(cls.name)
+        cls.pgname2 = os.path.basename(cls.name2)
+        cls.pgname3 = os.path.basename(cls.name3)
         add_prop_group(cls.pgname)
-        cls.pgname2 = os.path.basename(tempfile.mkstemp()[1])
         add_prop_group(cls.pgname2)
 
     @classmethod
@@ -103,33 +104,52 @@
         '''class test tear down '''
         del_prop_group(cls.pgname)
         del_prop_group(cls.pgname2)
+        os.remove(cls.name)
+        os.remove(cls.name2)
+        os.remove(cls.name3)
 
     def test_is_pg(self):
         ''' test ai_smf_service is_pg'''
-        self.assertTrue(is_pg(self.pgname))
+        self.assertTrue(aismf.is_pg(self.pgname))
 
         # Exercise is_pg()
         pg_tst_name = '_zippy_the_pin_head'
-        self.assertFalse(is_pg(pg_tst_name))
+        self.assertFalse(aismf.is_pg(pg_tst_name))
 
     def test_set_get_pg_props(self):
         ''' test set_pg_props, get_pg_props and get_all_pg_props'''
         props = {'hair': 'blond', 'eyes': 'hazel'}
-        set_pg_props(self.pgname, props)
+        aismf.set_pg_props(self.pgname, props)
         props = {'teeth': 'chipped', 'nose': 'crooked'}
-        set_pg_props(self.pgname2, props)
+        aismf.set_pg_props(self.pgname2, props)
 
         # Exercise get_pg_props()
-        ret_props = get_pg_props(self.pgname)
+        ret_props = aismf.get_pg_props(self.pgname)
         self.assertTrue(ret_props['hair'] == 'blond')
         self.assertTrue(ret_props['eyes'] == 'hazel')
 
-        prop_dict = get_all_pg_props()
+        prop_dict = aismf.get_all_pg_props()
         self.assertTrue(prop_dict[self.pgname]['hair'] == 'blond')
         self.assertTrue(prop_dict[self.pgname]['eyes'] == 'hazel')
         self.assertTrue(prop_dict[self.pgname2]['teeth'] == 'chipped')
         self.assertTrue(prop_dict[self.pgname2]['nose'] == 'crooked')
 
+    def test_create_pg(self):
+        ''' test ai_smf_service create_pg'''
+        aismf.create_pg(self.pgname3)
+        self.assertTrue(aismf.is_pg(self.pgname3))
+        del_prop_group(self.pgname3)
+
+        props = {'knees': 'wobbly', 'back': 'aching', 'eyesight': 'failing'}
+        aismf.create_pg(self.pgname3, props)
+        self.assertTrue(aismf.is_pg(self.pgname3))
+        prop_dict = aismf.get_all_pg_props()
+        self.assertTrue(prop_dict[self.pgname3]['knees'] == 'wobbly')
+        self.assertTrue(prop_dict[self.pgname3]['back'] == 'aching')
+        self.assertTrue(prop_dict[self.pgname3]['eyesight'] == 'failing')
+        del_prop_group(self.pgname3)
+
+
 if __name__ == '__main__':
 
     unittest.main()
--- a/usr/src/cmd/installadm/test/installadm_test.c	Wed Mar 02 10:11:44 2011 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-#include <libscf.h>
-#include <libaiscf.h>
-
-#include "installadm.h"
-
-static void
-usage(void)
-{
-	printf("Usage: \n" \
-	    "\tcreate_pg <pg name> \n" \
-	    "\tdelete_pg <pg name> \n" \
-	    "\tadd_prop_to_pg <pg name> <prop name> <prop value> \n" \
-	    "\tchange_prop <pg name> <prop name> <prop value> \n" \
-	    "\tread_props <pg name> \n" \
-	    "\tread_property <pg_name> <prop name> \n" \
-	    "\tlist_pgs \n");
-}
-
-int
-create_pg(char *argv[], scfutilhandle_t *handle)
-{
-	char	*pg_name;
-
-	if ((pg_name = ai_make_pg_name(argv[2])) == NULL) {
-		return (1);
-	}
-	printf("Creating property group %s\n", pg_name);
-	ai_create_install_service(handle, pg_name);
-	return (0);
-}
-
-int
-delete_pg(char *argv[], scfutilhandle_t *handle)
-{
-	char	*pg_name;
-
-	if ((pg_name = ai_make_pg_name(argv[2])) == NULL) {
-		return (1);
-	}
-	printf("Deleting property group %s\n", argv[2]);
-	if (ai_delete_install_service(handle, pg_name) != 0) {
-		printf("Unable to delete %s\n", argv[2]);
-		return (1);
-	}
-	return (0);
-}
-
-int
-add_prop_to_pg(char *argv[], scfutilhandle_t *handle)
-{
-	char	*pg_name;
-	char	*prop_name;
-	char	*prop_value;
-
-	if ((pg_name = ai_make_pg_name(argv[2])) == NULL) {
-		return (1);
-	}
-	prop_name = argv[3];
-	prop_value = argv[4];
-
-	printf("Adding property %s with value %s to property group %s\n",
-	    prop_name, prop_value, pg_name);
-
-	if (ai_set_property(handle, pg_name, prop_name, prop_value) !=
-	    AI_SUCCESS) {
-		return (1);
-	}
-
-	return (0);
-}
-
-int
-change_prop(char *argv[], scfutilhandle_t *handle)
-{
-	char	*pg_name;
-	char	*prop_name;
-	char	*prop_value;
-
-	int ret = 0;
-	scf_value_t *value;
-	scf_transaction_entry_t *entry;
-
-	if ((pg_name = ai_make_pg_name(argv[2])) == NULL) {
-		return (1);
-	}
-	prop_name = argv[3];
-	prop_value = argv[4];
-
-	printf("Changing property %s to value %s in property group %s\n",
-	    prop_name, prop_value, pg_name);
-
-	if (ai_change_property(handle, pg_name, prop_name, prop_value) !=
-	    AI_SUCCESS) {
-		return (1);
-	}
-
-	return (0);
-}
-
-int
-read_props(char *argv[], scfutilhandle_t *handle)
-{
-	char	*pg_name;
-
-	if ((pg_name = ai_make_pg_name(argv[2])) == NULL) {
-		return (1);
-	}
-	printf("Reading properties from property group %s\n", pg_name);
-
-	if (ai_read_all_props_in_pg(handle, pg_name) != AI_SUCCESS) {
-		return (1);
-	}
-
-	return (0);
-}
-
-int
-read_property(char *argv[], scfutilhandle_t *handle)
-{
-	char	*pg_name;
-	char	*prop_name;
-	char	*property;
-
-	if ((pg_name = ai_make_pg_name(argv[2])) == NULL) {
-		return (1);
-	}
-	prop_name = argv[3];
-
-	printf("Reading property %s from property group %s\n", prop_name,
-	    pg_name);
-
-	if ((property = ai_read_property(handle, pg_name, prop_name)) == NULL) {
-		return (1);
-	}
-	printf("%s = %s\n", prop_name, property);
-
-	return (0);
-}
-
-int
-list_pgs(scfutilhandle_t *handle)
-{
-	scf_iter_t	*iter = NULL;
-	char		*buff = NULL;
-	int		ret = 0;
-
-	printf("Listing property groups\n");
-
-	buff = malloc(ai_get_scf_limit(SCF_LIMIT_MAX_NAME_LENGTH));
-	if (buff == NULL) {
-		printf("Unable to malloc buffer\n");
-		return (1);
-	}
-
-	iter = scf_iter_create(handle->handle);
-	if (iter == NULL) {
-		printf("Unable to setup to iterate through property groups\n");
-		ret = 1;
-		goto out;
-	}
-
-	if (ai_get_instance(handle, "default") != AI_SUCCESS) {
-		printf("Unable to get default instance\n");
-		ret = 1;
-		goto out;
-	}
-
-	if (scf_iter_instance_pgs(iter, handle->instance) != 0) {
-		printf("Unable to get memory to iterate\n");
-		ret = 1;
-		goto out;
-	}
-
-	while (scf_iter_next_pg(iter, handle->pg) > 0) {
-		if (scf_pg_get_name(handle->pg, buff,
-		    ai_get_scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) >= 0) {
-			if (strncmp("AI", buff, 2) == 0) {
-				printf("%s\n", &buff[2]);
-			}
-		}
-	}
-out:
-	if (buff != NULL)
-		free(buff);
-	if (iter != NULL)
-		scf_iter_destroy(iter);
-
-	return (ret);
-}
-
-int
-main(int argc, char *argv[])
-{
-	char *subcommand;
-	scfutilhandle_t	*handle;
-
-	handle = ai_scf_init();
-	if (handle == NULL) {
-		printf("ai_scf_init failed\n");
-		return (1);
-	}
-	subcommand = argv[1];
-	if (strcmp(subcommand, "create_pg") == 0) {
-		if (create_pg(argv, handle) != 0) {
-			printf("create_pg failed\n");
-			return (1);
-		}
-	} else if (strcmp(subcommand, "delete_pg") == 0) {
-		if (delete_pg(argv, handle) != 0) {
-			printf("delete_pg failed\n");
-			return (1);
-		}
-	} else if (strcmp(subcommand, "add_prop_to_pg") == 0) {
-		if (add_prop_to_pg(argv, handle) != 0) {
-			printf("add_prop_to_pg failed\n");
-			return (1);
-		}
-	} else if (strcmp(subcommand, "change_prop") == 0) {
-		if (change_prop(argv, handle) != 0) {
-			printf("change_prop failed\n");
-			return (1);
-		}
-	} else if (strcmp(subcommand, "read_props") == 0) {
-		if (read_props(argv, handle) != 0) {
-			printf("read_props failed\n");
-			return (1);
-		}
-	} else if (strcmp(subcommand, "read_property") == 0) {
-		if (read_property(argv, handle) != 0) {
-			printf("read_property failed\n");
-			return (1);
-		}
-	} else if (strcmp(subcommand, "list_pgs") == 0) {
-		if (list_pgs(handle) != 0) {
-			printf("list_pgs failed\n");
-			return (1);
-		}
-	} else {
-		usage();
-		return (1);
-	}
-
-	return (0);
-}
--- a/usr/src/lib/libaiscf_pymod/libaiscf.py	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/lib/libaiscf_pymod/libaiscf.py	Wed Mar 02 11:14:19 2011 -0800
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
 #
 ''' AI SCF Library and Object Types
 
@@ -102,7 +102,8 @@
         '''
         Create an AI service associated with the SMF instance
         '''
-        return (AIservice(super(AISCF, self).new_service(self, service_name)))
+        super(AISCF, self).new_service(service_name)
+        return (AIservice(self, service_name))
 
 
 class AIservice(_libaiscf._AIservice):
--- a/usr/src/pkg/manifests/install-installadm.mf	Wed Mar 02 10:11:44 2011 -0800
+++ b/usr/src/pkg/manifests/install-installadm.mf	Wed Mar 02 11:14:19 2011 -0800
@@ -82,6 +82,8 @@
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/ai_smf_service.pyc group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/create_client.py group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/create_client.pyc group=sys
+file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/create_service.py group=sys
+file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/create_service.pyc group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/delete_client.py group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/delete_client.pyc group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/delete_manifest.py group=sys
@@ -96,7 +98,6 @@
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/set_criteria.pyc group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/verifyXML.py group=sys
 file path=usr/lib/python2.6/vendor-packages/osol_install/auto_install/verifyXML.pyc group=sys
-file path=usr/sbin/create-service mode=0555
 file path=usr/sbin/installadm mode=0555
 file path=usr/share/auto_install/criteria_schema.rng group=sys
 file path=usr/share/man/man1m/installadm.1m mode=0444