#!/bin/ksh -p # # Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. # # Micro version replaced by makefile. Micro value set by applying # Solaris version and changeset id. VERSION="1.0.5-11-38993" unset LD_LIBRARY_PATH PATH=/usr/bin:/usr/sbin:/usr/ccs/bin export PATH unalias -a # Use separate text domain to allow translations to be included with unbundled # version for s10. export TEXTDOMAIN=SUNW_OST_ZONEP2VCHK m_usage=$(gettext "\ Usage:\n\ zonep2vchk -V\n\ \n\ zonep2vchk [ -T release ] -c\n\ \n\ zonep2vchk [ -T release ] [ -P ] [ -b ]\n\ [ -s path[,path...] ] [ -S file ]\n\ [ -r {time}(h|m|s) ] [ -x ]\n\ [ -e execname[,execname...] ] [ -E file ]\n\ \n\ Options:\n\ -V Output command version and exit.\n\ -T Specify the target release such as \"S10\" or \"S11\".\n\ -c Output a template zone configuration based on the system's\n\ configuration.\n\ -P Output machine parsable output.\n\ -b Perform basic system configuration checks.\n\ -r Perform runtime checks for specified duration.\n\ -x Perform runtime checks until terminated with SIGINT/ctrl-c.\n\ -e Limit runtime checks to specified execnames.\n\ -E Limit runtime checks to execnames specified in \"file\".\n\ -s Perform static binary analysis on the specified files and\n\ directories. Directories are recursed.\n\ -S Perform static binary analysis on files and directories\n\ listed in \"file\". Directories are recursed.\n") m_cancel=$(gettext "Analysis cancelled due to interrupt.") e_bad_opt=$(gettext "Error: Invalid option: %s") e_opt_arg=$(gettext "Error: Option missing operand: %s") e_incompat_options=$(gettext "Error: mutually exclusive options.\n%s") e_needroot=$(gettext "Error: root required to execute zonep2vchk.") e_unsupported=$(gettext "\ Error: zonep2vchk requires Solaris 8 or newer.") e_nonglobal_zone=$(gettext "\ Error: zonep2vchk must be run in the global zone.") e_release=$(gettext "\ Error: invalid target release: \"%s\". For the current release on this host, it must be one of: \"%s\"") e_trusted_extensions=$(gettext "\ Error: migration of a system running Trusted Extensions is not supported.") e_badtime=$(gettext "Error: invalid time (%s) for dynamic analysis") e_nodyn=$(gettext "\ Error: this option uses DTrace which is not available on the current release.") e_no_cmd=$(gettext "Error: missing required command %s.") e_no_tmpfile=$(gettext "Error: unable to create temporary file.") e_s10_or_s11=$(gettext "S10 or S11") e_file_in=$(gettext "File does not exist or is not readable: %s") w_indented1=" %s" w_indented2=" %s %s" w_formatted2=" %-36s %s" w_etcsystemfmt=" %s\n %s\n %s %s" w_tune_noinfo=$(gettext "zonep2vchk has no information on tunable") w_tune_obsolete=$(gettext "Tunable is obsolete on target host") w_tune_replaced=$(gettext "Replacement tunable exists on target host:") w_tune_alternate=$(gettext "Alternate tunable exists inside a non-global zone:") w_tune_noalternate=$(gettext "No alternate tunable exists.") w_be_header=$(gettext "\ - The following boot environments will not be usable. Only the active\n\ boot environment will be usable in the target non-global zone:") w_zones_header=$(gettext "\ - The following zones will be unusable. Each zone should be migrated\n\ separately to the target host using detach and attach. See zoneadm(1M),\n\ solaris(5) and solaris10(5):") c_zone=$(gettext "Zone") c_state=$(gettext "State") w_lofi_header=$(gettext "\ - The system has the following lofi devices configured.\n\ Lofi devices cannot be configured in the destination zone. Lofi devices\n\ must be created in the global zone and added to the zone using\n\ \"zonecfg add device\". See lofiadm(1M) and zonecfg(1M) for details:") c_device=$(gettext "Device") c_file=$(gettext "File") w_nfs_header=$(gettext "\ - The system is sharing file systems with NFS. This is not possible in\n\ the destination zone. The shares should be evaluated to determine if\n\ they are necessary. If so, this system may not be suitable for\n\ consolidation into a zone, or an alternate approach for supporting the\n\ shares will need to be used, such as sharing via the global zone or\n\ another host. Use \"zonep2vchk -P\" to get a list of the shared\n\ file systems.") w_smb_header=$(gettext "\ - The system is sharing file systems with SMB/CIFS. This is not possible\n\ in the destination zone. The shares should be evaluated to determine if\n\ they are necessary. If so, this system may not be suitable for\n\ consolidation into a zone, or an alternate approach for supporting the\n\ shares will need to be used, such as sharing via the global zone or\n\ another host. Use \"zonep2vchk -P \" to get a list of the shared\n\ filesytems.") w_dhcp_server_header=$(gettext "\ - The following dhcp server service is enabled. In order to provide dhcp\n\ service, a zone must have ip-type=exclusive, or have the privilege\n\ \"net_rawaccess\" and the device \"/dev/ip\". Note that the latter\n\ will allow a shared stack zone to read and write raw ip packets on\n\ the network, similar to an exclusive stack zone or global zone. See\n\ zonecfg(1m) for description of the \"limitpriv\" property and\n\ \"add device\" resource":) w_ntp_header_s10=$(gettext "\ - The following ntp client service is enabled. This service updates\n\ the system clock. Since all zones share the same system clock, it is\n\ recommended that this service be disabled after p2v. If it is\n\ desired that the zone update the system clock on the target host,\n\ the zone will need the privilege \"sys_time\", and the service will\n\ need to be enabled inside the zone after p2v. See the description\n\ of the \"limitpriv\" property in zonecfg(1m):") w_ntp_header_s11=$(gettext "\ - The following ntp client service is enabled. This service updates\n\ the system clock. Since all zones share the same system clock, this\n\ service is disabled automatically during p2v. If it is desired\n\ that the zone update the system clock on the target host, the\n\ zone will need the privilege \"sys_time\", and the service will\n\ need to be enabled inside the zone after p2v. See the description\n\ of the \"limitpriv\" property in zonecfg(1m):") w_vfstab_header=$(gettext "\ - If needed, the following non-standard vfstab entries will impact\n\ the zone configuration:") c_mountpount=$(gettext "Mountpoint") w_svc_header=$(gettext "\ - The following SMF services will not work in a zone:") w_svcpriv_header=$(gettext "\ - The following SMF service(s) require the listed privileges to work in\n\ a zone. See zonecfg(1M) for a description of the limitpriv property:") c_service=$(gettext "Service") c_privs=$(gettext "Privileges") w_svcexclip_header=$(gettext "\ - The following SMF services require ip-type \"exclusive\" to work in\n\ a zone. If they are needed to support communication after migrating\n\ to a shared-IP zone, configure them in the destination system's global\n\ zone instead:") w_pkg_header=$(gettext " - The software in the following packages is not usable in a zone:") w_etcsystem_header=$(gettext "\ - The following /etc/system tunables exist. These tunables will not\n\ function inside a zone. The /etc/system tunable may be transfered to\n\ the target global zone, but it will affect the entire system,\n\ including all zones and the global zone. If there is an\n\ alternate tunable that can be configured from within the zone,\n\ this tunable is described:") w_zpool_header=$(gettext "\ - The system is configured with the following non-root ZFS pools.\n\ Pools cannot be configured inside a zone, but a zone can be configured\n\ to use a pool that was set up in the global zone:") w_resourcepool_header=$(gettext "\ - The system is configured with the following resource pools.\n\ Pools cannot be configured inside a zone but a zone can be configured\n\ to use a pool that was set up in the global zone. See pooladm(1M) for\n\ details:") w_pset_header_10=$(gettext "\ - The system is configured with the following processor sets. Processor\n\ sets cannot be configured inside a zone:") c_pset=$(gettext "Processor Set") c_cpulist=$(gettext "CPU List") w_pset_header_11=$(gettext "\ - The system is configured with the following processor sets. Processor\n\ sets cannot be configured inside a zone. Processor sets can be\n\ configured in the global zone, and a non-global zone may bind to them if\n\ given the privilege \"sys_res_bind\" via the zonecfg(1M) limitpriv\n\ property:") w_ramdisk_header=$(gettext "\ - The system is configured with the following ramdisk devices. A zone\n\ cannot configure ramdisk devices. Ramdisk devices must be configured\n\ from the global zone, and can be made available to a zone via\n\ zonecfg(1M) \"add device\" or \"add fs\":") w_sched=$(gettext "\ - The system sets the following default scheduling class. To set the\n\ default scheduling class for a zone, use the \"scheduler\" zonecfg(1M)\n\ property:") w_svm_header=$(gettext "\ - The system is configured with SVM metadevices.\n\ A zone cannot configure SVM metadevices, but a zone can be configured\n\ to use existing metadevices. See metastat(1M) for details") w_iscsi_initiator_header=$(gettext "\ - The system is configured with the following ISCSI initiators. A zone\n\ cannot access ISCSI targets. ISCSI targets must be discovered and\n\ configured from the global zone. See iscsiadm(1M) for details:") w_iscsi_target_header_10=$(gettext "\ - The system is configured with the following ISCSI targets. A zone\n\ cannot share iscsi targets. ISCSI targets must be shared from the\n\ global zone. See iscsitadm(1m) for details:") w_iscsi_target_header_11=$(gettext "\ - The system is configured with the following ISCSI targets. A zone\n\ cannot share iscsi targets. ISCSI targets must be shared from the\n\ global zone. See itadm(1m) for details:") w_fcoe_initiator_header=$(gettext "\ - The system is configured with the following FCOE initiators. A zone\n\ cannot configure FCOE initiators. They must be configured from the\n\ global zone. See fcadm(1M) for details:") w_fcoe_target_header=$(gettext "\ - The system is configured with the following FCOE targets. A zone cannot\n\ configure FCOE targets. They must be configured from the global zone.\n\ See fcadm(1M) for details:") w_npiv_header=$(gettext "\ - The system is configured with the following virtual NPIV fiberchannel\n\ ports. A zone cannot configure NPIV ports. They must be configured from\n\ the global zone. See fcadm(1M) for details:") w_fc_target_header=$(gettext "\ - The system is configured with the following fiberchannel targets. A\n\ zone cannot configure fiberchannel targets. They must be configured\n\ from the global zone. See fcadm(1M) for details:") w_fc_initiator_header=$(gettext "\ - The system has the following hba fiberchannel ports online. If\n\ fiberchannel storage is connected, it must be migrated to the target\n\ global zone. The storage can then be added to the zone using\n\ zonecfg(1M) \"add fs\", \"add dataset\", or \"add device\":") w_comstar_header=$(gettext "\ - The system has configured the following objects as SCSI targets. A zone\n\ cannot configure SCSI targets. They must be configured from the global\n\ zone. See sbdadm(1M) for details:") w_ndd_header_s10=$(gettext "\ - System startup scripts were modified to set network driver parameters\n\ with ndd(1M). These commands are not supported in shared-IP zones. Apply\n\ network parameter changes in the global zone if needed to support\n\ communication after migration to a shared-IP zone. ndd commands to modify\n\ IP and transport layer parameters will work in the startup scripts of an\n\ exclusive-IP zone. Physical device and datalink level parameters may\n\ only be changed in the global zone:") c_script_file=$(gettext "Script File") c_driver=$(gettext "Driver") c_parameter=$(gettext "Parameter") w_ndd_header_s11=$(gettext "\ - System startup scripts were modified to set network driver parameters\n\ with ndd(1M). These ndd commands will fail when run in a zone. Use\n\ dladm(1M) to apply physical device and datalink level parameters in\n\ the global zone of the destination system if needed to support\n\ communication after migration:") w_ndd_fmt=" %-27s %-11s %s" w_patch=$(gettext "\ - The system does not have the required minimum patch %s.") run_header=$(gettext "\ --Executing Version: %s\n\ \n\ - Source System: %s\n\ Solaris Version: %s\n\ Solaris Kernel: %s\n\ Platform: %s\n\ \n\ - Target System:\n\ Solaris Version: %s\n\ Zone Brand: %s\n\ IP type: %s") basic_header=$(gettext "--Executing basic checks") basic_footer=$(gettext " Basic checks complete. Issue(s) detected: %s") static_header=$(gettext "--Executing static binary checks") static_footer=$(gettext " Static binary checks complete. Issue(s) detected: %s") dyn_header=$(gettext "--Executing run-time checks for %s") dyn_int_header=$(gettext "--Executing run-time checks until interrupted...") dyn_footer=$(gettext " Run-time checks complete, %s issue(s) detected") total_header=$(gettext "--Total issue(s) detected: %s") w_dyn_privna_header=$(gettext "\ - The following programs were found using privileges that cannot be added\n\ to a zone. The use of these privileges may be related to the program\n\ command line options or configuration:") c_program=$(gettext "Program") c_disallowed=$(gettext "Disallowed Privilege") w_dyn_privex_header=$(gettext "\ - The following programs were found using privileges that require an\n\ exclusive IP stack. The use of these privileges may be related to the\n\ program command line options or configuration. See zonecfg(1M) for a\n\ description of the ip-type property:") c_exippriv=$(gettext "Exclusive IP Privilege") w_dyn_privopt_header=$(gettext "\ - The following programs were found using privileges that are not\n\ available in a zone by default. The use of these privileges may be\n\ related to the program command line options or configuration. See\n\ zonecfg(1M) for a description of the limitpriv property:") c_opt_priv=$(gettext "Optional Privilege") w_dyn_devna_header=$(gettext "\ - The following programs were found using devices that cannot be added to\n\ a zone. The use of these devices may be related to the program command\n\ line options or configuration:") c_disallowed_dev=$(gettext "Disallowed Device") w_dyn_devex_header=$(gettext "\ - The following programs were found using devices which require an\n\ exclusive IP stack to access. The use of these devices may be related\n\ to the program command line options or configuration. See zonecfg(1M)\n\ for a description of the ip-type property:") c_exip_device=$(gettext "Exclusive IP Device") w_dyn_devopt_header=$(gettext "\ - The following programs were found using devices that are not available\n\ in a zone by default. If any of these devices is a network device, then\n\ access will require an exclusive IP stack. The use of these devices may\n\ be related to the program command line options or configuration. See\n\ zonecfg(1M) for a description of the \"add device\" resource:") c_optional_dev=$(gettext "Optional Device") w_unsupported_header=$(gettext "\ - The following Solaris features are configured, and will not function in\n\ a non-global zone:"); w_physif_header=$(gettext "\ - When migrating to an exclusive-IP zone, the target system must have an\n\ available physical interface for each of the following source system\n\ interfaces:") w_ifname_header=$(gettext "\ - When migrating to an exclusive-IP zone, interface name changes may\n\ impact the following configuration files:") w_dynaddr_header_s10=$(gettext "\ - Dynamically assigned IP addresses are configured on the following\n\ interfaces. These addresses are not supported with shared-IP zones.\n\ Use an exclusive-IP zone or replace any dynamically assigned addresses\n\ with statically assigned addresses. These IP addresses could change\n\ as a result of MAC address changes. You may need to modify this\n\ system's address information on the DHCP server and on the DNS,\n\ LDAP, or NIS name servers:") w_dynaddr_header_s11=$(gettext "\ - Dynamically assigned IP addresses are configured on the following\n\ interfaces. These IP addresses could change as a result of MAC\n\ address changes. You may need to modify this system's address\n\ information on the DHCP server and on the DNS, LDAP, or NIS name\n\ servers:") w_datalink_header_s10=$(gettext "\ - The following datalink features will not be configured automatically\n\ on the destination system. Edit the target zone's configuration with\n\ zonecfg(1M) or configure these features on the global zone's datalink\n\ interfaces if needed for target zone communication:") w_datalink_header_s11=$(gettext "\ - The following datalink features will not be configured automatically\n\ on the destination system. Edit the target zone's configuration with\n\ zonecfg(1M) or use dladm(1M) to configure these features on the global\n\ zone's datalink interfaces if needed for target zone communication:") w_netdevalloc_header_s10=$(gettext "\ - The following networking features are not supported for use with a\n\ shared-IP zone. They require an exclusive-IP zone with the underlying\n\ device allocated to the zone. See zonecfg(1M) for information on how\n\ to allocate a device resource:") w_netdevalloc_header_s11=$(gettext "\ - The following networking features require an exclusive-IP zone with the\n\ underlying device allocated to the zone. See zonecfg(1M) for\n\ information on how to allocate a device resource:") w_exclusiveonly_header=$(gettext "\ - The following networking features are not supported for use with\n\ a shared-IP zone.") w_sharedonly_header=$(gettext "\ - The following networking features are not supported for use with\n\ an exclusive-IP zone. When migrating to a shared-IP zone, the\n\ feature must be configured in the global zone to support\n\ communication:") w_sharedip_header=$(gettext "\ - When migrating to a shared-IP zone, the following network features must\n\ be configured in the global zone if needed to support communication.\n\ They will not be configured automatically during migration. Nothing\n\ needs to be done for these features when migrating to an exclusive-IP\n\ zone where the configuration inside the migrated system image will be\n\ used:") w_driverconf_header_s10=$(gettext "\ - The following driver configuration files were modified after\n\ installation. These files will not be used after migration to a zone.\n\ Any changes will have to be applied in the destination system's global\n\ zone if needed to support processing in a zone after migration:") w_driverconf_header_s11=$(gettext "\ - The following driver configuration files were modified after\n\ installation. These files will not be used after migration to a zone.\n\ Any changes will have to be applied in the destination system's global\n\ zone if needed to support processing in a zone after migration. It may\n\ also be possible to migrate settings via dladm(1M) properties:") w_linkprop_header=$(gettext "\ - Some datalink interfaces were configured with non-default properties.\n\ These properties must be configured in the global zone if needed to\n\ support non-global zone communication. They will not be configured\n\ automatically during migration. See the parsable output from\n\ \"zonep2vchk -P\" for a complete list of non-default properties.") w_mobile_ip=$(gettext "Mobile IP") w_dhcp_assigned=$(gettext "DHCP assigned address on:") w_rarp_assigned=$(gettext "Reverse ARP assigned address on:") w_ipv6_autoconf=$(gettext "Autoconfigured IPv6 addresses on:") w_link_aggregation=$(gettext "Link aggregation") w_etherstub=$(gettext "Ethernet stub") w_bridge=$(gettext "LAN bridge") w_ibiface=$(gettext "Infiniband interface") w_ibpart=$(gettext "Infiniband partition") w_secobj=$(gettext "WPA or WEP secure object") w_vnic=$(gettext "VNIC interface") w_vlan=$(gettext "VLAN interface") w_simnet=$(gettext "Simnet interface") w_ipv4_forwarding=$(gettext "IPv4 forwarding on") w_ipv6_forwarding=$(gettext "IPv6 forwarding on") w_ipmp_group=$(gettext "IP Multipath group") w_iptun=$(gettext "IP tunnel interface") w_vni=$(gettext "Virtual network interface") w_cgtp=$(gettext "CGTP interface") w_ppp=$(gettext "Point to Point Protocol (PPP)") w_static_routes=$(gettext "Static routes") c_version=$(gettext "Version: %s") c_hostid=$(gettext "# Uncomment the following to retain original host hostid:") c_sched=$(gettext "# A non-default scheduling class on source host") c_max_procs_11=$(gettext "# maximum processes and lwps based on max_uproc/v_proc") c_max_procs_10=$(gettext "# maximum lwps based on max_uproc/v_proc") c_capped_cpu1=$(gettext "# Only one of dedicated or capped CPU can be used.") c_capped_cpu2=$(gettext "# Uncomment the following to use capped CPU:") c_ded_cpu=$(gettext "# Uncomment the following to use dedicated CPU:") c_capped_mem1=$(gettext "# Uncomment the following to use memory caps.") c_capped_mem2=$(gettext "# Values based on physical memory plus swap devices:") c_original_config=$(gettext "# Original configuration for interface: %s:") c_dhcp_address=$(gettext "# DHCP assigned ip address: %s") c_dhcp_address_x=$(gettext "# * DHCP assigned ip address: %s") c_dhcp_clientid=$(gettext "# DHCP Client ID %s (CID type %s)") c_rarp_enabled=$(gettext "# Reverse ARP is enabled") c_static_address=$(gettext "# Statically defined ip address: %s") c_autoconf_address=$(gettext "# Autoconfigured ip address: %s") c_autoconf_address_x=$(gettext "# * Autoconfigured ip address: %s") c_test_address=$(gettext "# IPMP test address: %s") c_ipmp_member_ip=$(gettext "# Member of IP multipath group: %s") c_ipmp_member_ipv4=$(gettext "# Member of IPv4 multipath group: %s") c_ipmp_member_ipv6=$(gettext "# Member of IPv6 Multipath group: %s") c_mac_address=$(gettext "# MAC address: %s: %s") c_mac_addr_fixed=$(gettext "Manually defined") c_mac_addr_factory=$(gettext "Factory assigned") c_mac_addr_random=$(gettext "Randomly assigned") c_mac_addr_infiniband=$(gettext "Infiniband") c_mac_addr_vrrp=$(gettext "VRRP based") c_dynamic_addr_notice=$(gettext "\ # Unable to migrate addresses marked with \"*\".\n\ # Shared IP zones require statically assigned addresses.") c_uncomment_linkprop=$(gettext "\ # Uncomment the following to retain original link configuration:") w_syscall_header=$(gettext "\ - System or library calls used by the following programs will not work in\n\ a zone:") w_syscallargs_header=$(gettext "\ - System or library calls used by the following programs will not work in\n\ a zone if called with the following parameters:") w_syscallpriv_header=$(gettext "\ - System or library calls used in the following programs will require\n\ modifications to the zone configuration for the application to work in\n\ a zone. See zonecfg(1M) for a description of the limitpriv property:") w_syscallexclip_header=$(gettext "\ - System or library calls used in the following programs will require an\n\ an exclusive ip stack to function in a zone. See zonecfg(1M) for a\n\ description of the ip-type property:") w_file_header=$(gettext "File: ") w_syscall=$(gettext "System call not allowed:") w_pool_set_binding_sys=$(gettext "\ pool_set_binding: libpool.so library call not allowed") w_p_online_args=$(gettext "\ p_online: System call not permitted if second argument other\n\ than P_STATUS") w_uadmin_args=$(gettext "\ uadmin: System call not permitted if first argument other than\n\ A_SHUTDOWN or A_REBOOT") w_pset_assign_args=$(gettext "\ pset_assign: System call not permitted if first argument other\n\ than PS_QUERY") w_swapctl_args=$(gettext "\ swapctl: System call not permitted if first argument SC_ADD or\n\ SC_REMOVE") w_pset_bind_args=$(gettext "\ pset_bind: System call not permitted if first argument other\n\ than PS_QUERY") w_pool_conf_open_args=$(gettext "\ pool_conf_open: libpool.so library call not permitted if second\n\ argument is \"pool_dynamic_location()\" and third argument\n\ includes flag PO_RDWR") w_pool_conf_commit_args=$(gettext "\ pool_conf_commit: libpool.so library call not permitted if\n\ second argument is non-zero") w_priocntl_priv=$(gettext "\ priocntl: System call requires privilege \"proc_priocntl\" if\n\ called with third argument of PC_SETPARAMS, PC_SETXPARAMS,\n\ or PC_ADMIN") w_priocntlset_priv=$(gettext "\ priocntlset: System call requires privilege \"proc_priocntl\"\n\ if called with second argument of PC_SETPARAMS,\n\ PC_SETXPARAMS, or PC_ADMIN") w_time_priv=$(gettext "System call requires privilege: \"sys_time\"") w_adjtime_priv="\ adjtime: $w_time_priv" w_ntp_adjtime_priv="\ ntp_adjtime: $w_time_priv" w_stime_priv="\ stime_adjtime: $w_time_priv" w_settimeofday_priv="\ settimeofday: $w_time_priv" w_clock_settime_priv="\ clock_settime: $w_time_priv" w_cpc_bind_cpu_priv=$(gettext "\ cpc_bind_cpu: System call requires privilege: \"cpc_cpu\"") w_msgctl_priv=$(gettext "\ msgctl: System call requires privilege \"sys_ipc_config\" if\n\ called with second argument IPC_SET to raise the value of\n\ msg_qbytes") w_timer_create_priv=$(gettext "\ timer_create: System call requires privilege\n\ \"proc_clock_highres\" if first argument is CLOCK_HIGHRES") w_pset_bind_priv=$(gettext "\ pset_bind: System call requires privilege \"sys_res_bind\" if\n\ first argument is other than PS_QUERY") w_t_open_arg=$(gettext "\ t_open: System call requires zone setting ip-type=exclusive") w_lib_header=$(gettext " - Libraries used by the following programs will not work in a zone:") b_s10_container=$(gettext "(Solaris 10 Container)") b_default=$(gettext "(default)") # # Counts the checks for a particular mode # function setup_mode { # Save number of checks fired so far (( g_total_fired = g_total_fired + g_check_fired )) (( g_check_count = 0 )) (( g_check_fired = 0 )) } # # Set up the correct header and msg info for each specific check. function setup_chk { (( g_check_count = g_check_count + 1 )) case "$1" in "etcsystem") category="incompatible" issue="etcsystem" header="$w_etcsystem_header" itemfmt="$w_etcsystemfmt" ;; "unsupported") category="incompatible" issue="unsupported" header="$w_unsupported_header" itemfmt="$w_indented1" ;; "be") category="incompatible" issue="be" header="$w_be_header" itemfmt="$w_indented1" ;; "nfs") category="incompatible" issue="nfs" header="$w_nfs_header" itemfmt="$w_indented1" ;; "smb") category="incompatible" issue="smb" header="$w_smb_header" itemfmt="$w_indented1" ;; "pkg") category="incompatible" issue="pkg" header="$w_pkg_header" itemfmt="$w_indented1" ;; "iscsi-initiator") category="incompatible" issue="iscsi-initiator" header="$w_iscsi_initiator_header" itemfmt="$w_indented1" ;; "iscsi-target") category="incompatible" issue="iscsi-target" if (( g_source_release >= 11 )) ; then header="$w_iscsi_target_header_11" else header="$w_iscsi_target_header_10" fi itemfmt="$w_indented1" ;; "fcoe-initiator") category="incompatible" issue="fcoe-initiator" header="$w_fcoe_initiator_header" itemfmt="$w_indented2" ;; "fcoe-target") category="incompatible" issue="fcoe-target" header="$w_fcoe_target_header" itemfmt="$w_indented2" ;; "npiv") category="incompatible" issue="npiv" header="$w_npiv_header" itemfmt="$w_indented2" ;; "fc-initiator") category="configuration" issue="fc-initiator" header="$w_fc_initiator_header" itemfmt="$w_indented1" ;; "fc-target") category="incompatible" issue="fc-target" header="$w_fc_target_header" itemfmt="$w_indented1" ;; "scsi") category="incompatible" issue="scsi-block-device" header="$w_comstar_header" itemfmt="$w_indented1" ;; "svcnotallowed") category="incompatible" issue="svcnotallowed" header="$w_svc_header" itemfmt="$w_indented1" ;; "lofi") category="incompatible" issue="lofi" header=$(printf "$w_lofi_header\n\n$w_formatted2" "$c_device" "$c_file") itemfmt="$w_formatted2" ;; "ramdisk") category="configuration" issue="ramdisk" header="$w_ramdisk_header" itemfmt="$w_indented1" ;; "zones") category="incompatible" issue="zones" header=$(printf "$w_zones_header\n\n$w_formatted2" $c_zone $c_state) itemfmt="$w_formatted2" ;; "datalink") category="configuration" issue="datalink" if (( g_target_release >= 11 )) ; then header="$w_datalink_header_s11" else header="$w_datalink_header_s10" fi itemfmt="$w_indented2" ;; "driverconf") category="configuration" issue="driverconf" if (( g_target_release >= 11 )) ; then header="$w_driverconf_header_s11" else header="$w_driverconf_header_s10" fi itemfmt="$w_indented2" ;; "ifname") category="configuration" issue="ifname" header="$w_ifname_header" itemfmt="$w_indented2" ;; "linkprop") category="configuration" issue="linkprop" header="$w_linkprop_header" itemfmt="$w_indented2" ;; "ndd") category="configuration" issue="ndd" if (( g_target_release >= 11 )) ; then header="$w_ndd_header_s11" else header="$w_ndd_header_s10" fi header=$(printf "$header\n\n$w_ndd_fmt" "$c_script_file" "$c_driver" "$c_parameter") itemfmt="$w_ndd_fmt" ;; "dynaddr") category="configuration" issue="dynaddr" if (( g_target_release >= 11 )) ; then header="$w_dynaddr_header_s11" else header="$w_dynaddr_header_s10" fi itemfmt="$w_indented2" ;; "patch") category="configuration" issue="patch" header="PATCH" ;; "physif") category="configuration" issue="physif" header="$w_physif_header" itemfmt="$w_indented2" ;; "svcpriv") category="configuration" issue="svcpriv" header=$(printf "$w_svcpriv_header\n\n$w_formatted2" "$c_service" "$c_privs") itemfmt="$w_formatted2" ;; "ntp-client") category="configuration" issue="ntp-client" if (( g_target_release >= 11 )) ; then header="$w_ntp_header_s11" else header="$w_ntp_header_s10" fi itemfmt="$w_indented1" ;; "dhcp-server") category="configuration" issue="dhcp-server" header="$w_dhcp_server_header" itemfmt="$w_indented1" ;; "sched") category="configuration" issue="sched" header="$w_sched" itemfmt="$w_indented1" ;; "sharedip") category="configuration" issue="sharedip" header="$w_sharedip_header" itemfmt="$w_indented2" ;; "netdevalloc") category="configuration" issue="netdevalloc" if (( g_target_release >= 11 )) ; then header="$w_netdevalloc_header_s11" else header="$w_netdevalloc_header_s10" fi itemfmt="$w_indented1" ;; "sharedonly") category="configuration" issue="sharedonly" header="$w_sharedonly_header" itemfmt="$w_indented2" ;; "exclusiveonly") category="configuration" issue="exclusiveonly" header="$w_exclusiveonly_header" itemfmt="$w_indented2" ;; "svcexclip") category="configuration" issue="svcexclip" header="$w_svcexclip_header" itemfmt="$w_indented1" ;; "svm") category="configuration" issue="svm" header="$w_svm_header" itemfmt="$w_indented1" ;; "vfstab") category="configuration" issue="vfstab" header=$(printf "$w_vfstab_header\n\n$w_formatted2" \ "$c_device" "$c_mountpoint") itemfmt="$w_formatted2" ;; "zpool") category="configuration" issue="zpool" header="$w_zpool_header" itemfmt="$w_indented1" ;; "resourcepool") category="incompatible" issue="resourcepool" header="$w_resourcepool_header" itemfmt="$w_indented1" ;; "pset") category="incompatible" issue="pset" if (( g_target_release >= 11 )) ; then header="$w_pset_header_11" else header="$w_pset_header_10" fi header=$(printf "$header\n\n$w_formatted2" "$c_pset" \ "$c_cpulist") itemfmt="$w_formatted2" ;; "syscall") category="incompatible" issue="syscall" header="$w_syscall_header" last_file="" ;; "syscallargs") category="incompatible" issue="syscallargs" header="$w_syscallargs_header" last_file="" ;; "syscallpriv") category="configuration" issue="syscallpriv" header="$w_syscallpriv_header" last_file="" ;; "syscallexclip") category="configuration" issue="syscallexclip" header="$w_syscallexclip_header" last_file="" ;; "lib") category="incomaptible" issue="lib" header="$w_lib_header" last_file="" ;; "privna") category="incompatible" issue="privnotallowed" header=$(printf \ "$w_dyn_privna_header\n\n$w_formatted2" \ "$c_program" "$c_disallowed") itemfmt="$w_formatted2" ;; "privex") category="configuration" issue="privexclip" header=$(printf \ "$w_dyn_privex_header\n\n$w_formatted2" \ "$c_program" "$c_exip_priv") itemfmt="$w_formatted2" ;; "privopt") category="configuration" issue="privoptional" header=$(printf \ "$w_dyn_privopt_header\n\n$w_formatted2" \ "$c_program" "$c_opt_priv") itemfmt="$w_formatted2" ;; "devna") category="incompatible" issue="devnotallowed" header=$(printf \ "$w_dyn_devna_header\n\n$w_formatted2" \ "$c_program" "$c_disallowed_device") itemfmt="$w_formatted2" ;; "devex") category="configuration" issue="devexclip" header=$(printf \ "$w_dyn_devex_header\n\n$w_formatted2" \ "$c_program" "$c_exip_dev") itemfmt="$w_formatted2" ;; "devopt") category="configuration" issue="devoptional" header=$(printf \ "$w_dyn_devopt_header\n\n$w_formatted2" \ "$c_program" "$c_optional_dev") itemfmt="$w_formatted2" ;; *) fatal "Internal error: unknown error code $1" ;; esac } # Clean up on interrupt function trap_cleanup { # Dynamic mode can be interrupted if (( opt_dynamic_mode == 1 )) ; then (( g_interrupted = 1 )) (( g_dtrace_pid != 0 )) && kill -15 $g_dtrace_pid >/dev/null 2>&1 return fi (( opt_parse_mode == 0 )) && fatal "$m_cancel" } function fatal { typeset fmt="$1" shift printf "${fmt}\n" "$@" >&2 exit 1 } # # Concatenate arguments into a parsable string using ":" as the # field separator. Any ":" characters embedded within an argument # will be escaped with a backslash. # function parsable { [[ -z $1 ]] && return print -n "$( print $1 | sed -e "s/:/\\\\:/g" )" shift while [[ -n "$1" ]]; do print -n ":$( print $1 | sed -e "s/:/\\\\:/g" )" shift done } # # This function displays a single item related to the current issue in # either parsable format or human readable format. The human readable # "header" will exist if this is the first item found relative to the # issue. If needed, print the header then clear it so that will not # be printed for subsequent items. # function warn_item { (( g_check_fired = g_check_fired + 1 )) if (( opt_parse_mode == 1 )) ; then print -- "$category:$issue:$(parsable "$@")" return fi if [[ -n "$header" ]]; then # Put a blank line before header printf "\n$header\n\n" header="" fi printf "$itemfmt\n" "$@" } # # This function is similar to the warn_item function in that it outputs # each issue when generating machine-parsable output. However, when # generating human-readable output it doesn't output each line, just the # header. The idea here is we use this function when there is potentially # many lines of output which won't each be useful to the user. For example, # we don't want to list each ZFS dataset or NFS share to the user, just tell # them that these could be an issue. But, for machine parsable output we will # list each one since they may be collecting that data for other processing. # function warn_item_compact { (( g_check_fired = g_check_fired + 1 )) if (( opt_parse_mode == 1 )) ; then print -- "$category:$issue:$(parsable "$@")" return fi if [[ -n "$header" ]]; then # Put a blank line before header printf "\n$header\n" header="" fi } # # This function displays a network feature with its optional list of # impacted interfaces as either: # - A single item in human-readable form. # - A series of items in parsable form. # function warn_feature { typeset feature_code="$1" typeset feature_text="$2" typeset interfaces="${3#\ }" typeset interface typeset iface_count if (( opt_parse_mode == 1 )) ; then if [[ -z $interfaces ]]; then warn_item "$feature_code" else # Print one parsable item line per interface. for interface in $interfaces; do warn_item "$feature_code" "$interface" done fi else if [[ -z $interfaces ]]; then warn_item "$feature_text" else # Print all interfaces as a comma separated list # in a single item. Split the interface list into # multiple indented lines if it exceeds fifty # characters. Use a temporary "prefix" string # during the fmt operation to provide # extra space on the first line for "feature_text". typeset -i prefixlen prefixlen=$(( ${#feature_text} - 10 )) (( prefixlen < 2 )) && prefixlen=2 prefix=$(printf "%${prefixlen}.${prefixlen}s" \ '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') interfaces=$( print "$prefix" $interfaces | \ sed -e 's/ /, /g' | \ fmt -s -w 50 | \ sed -e "s/${prefix}, //" | \ sed -e '2,$s/^/ /' ) warn_item "$feature_text" "$interfaces" iface_count=$( print $interfaces | wc -w ) (( g_check_fired = g_check_fired + iface_count - 1 )) fi fi } # # This function takes a message parameter along with 1 or more additional # parameters. These are used to generate the message to the user. # function warn_issue { typeset text="$1" shift (( g_check_fired = g_check_fired + 1 )) # Clobber header to inform setup_chk that check has fired if [[ -n "$header" ]]; then # Put a blank line before first issue in current mode (( opt_parse_mode == 0 )) && print header="" fi if (( opt_parse_mode == 1 )) ; then print -- "$category:$issue:$(parsable "$@")" else printf "$text\n" "$@" fi } # # This function takes a disallowed syscall and generates the human readable # output. # function warn_syscall { typeset s=$1 typeset f=$2 if (( opt_parse_mode == 1 )) ; then warn_item $f $s return fi (( g_check_fired = g_check_fired + 1 )) if [[ -n "$header" ]]; then # Put a blank line before header printf "\n$header\n" header="" fi if [[ $last_file != "$f" ]] ; then printf "\n %s%s\n" "$w_file_header" "$f" last_file="$f" fi # See if there is a message specific call eval m=\"\$w_${s}_sys\" if [[ $m == "" ]] ; then printf " %s: %s\n" "$s" "$w_syscall" else print "$m" fi } # # This function takes a disallowed library and generates the human readable # output. # function warn_lib { typeset l=$1 typeset f=$2 if (( opt_parse_mode == 1 )) ; then warn_item $f $l return fi (( g_check_fired = g_check_fired + 1 )) if [[ -n "$header" ]]; then # Put a blank line before header printf "\n$header\n" header="" fi if [[ $last_file != "$f" ]] ; then printf "\n %s%s\n" "$w_file_header" "$f" last_file="$f" fi printf " %s\n" "$l" } # # This function takes a syscall with disallowed args and generates the human # readable output. Third argument is used to specify to use messages related # to required privileges. # function warn_syscallargs { typeset s=$1 typeset f=$2 typeset p=$3 if (( opt_parse_mode == 1 )) ; then warn_item $f $s $p return fi (( g_check_fired = g_check_fired + 1 )) if [[ -n "$header" ]]; then # Put a blank line before header printf "\n$header\n" header="" fi if [[ $last_file != $f ]] ; then printf "\n %s%s\n" "$w_file_header" $f last_file=$f fi # print the warning associated with the particular system call if [[ -n "$p" ]] ; then eval print \"\$w_${s}_priv\" else eval print \"\$w_${s}_args\" fi } # # Returns 0 if the active NCP has a "fixed" management-type, 1 otherwise. # function active_ncp_is_fixed { ncp=$(svcprop -p netcfg/active_ncp svc:/network/physical:default) mgmt=$(netcfg "select ncp \"$ncp\"; get -V management-type" 2>/dev/null) [[ "$mgmt" == "fixed" ]] && return 0 return 1 } # # Generate the list of privileges to watch. Since the privs vary based on # which kernel we're running, we use ppriv to see which privs are available # then match those up to the current latest list of privileges that we know # about. # function gen_priv_names { ppriv -l | nawk ' { printf("privnames[%d] = \"%s\";\n", NR - 1, $1); } ' } # # Generate a list of execnames specified by user For each execname specified, # an element in the execnames array will have value 1. # function gen_execnames { typeset -i i=1 while (( i <= g_execname_count )) ; do print "execnames[\"${g_execname_list[$i]}\"] = 1;" (( i = i + 1 )) done } function gen_dyn_script { typeset open typeset arg if (( g_source_release == 10 )) ; then open="open" arg="arg0" elif (( g_source_release >= 11 )) ; then open="openat" arg="arg1" fi cat <<- ENDD #!/usr/sbin/dtrace -s #pragma D option quiet BEGIN { seconds = $g_dynamic_seconds; ENDD gen_priv_names gen_execnames cat <<- ENDD /* * The following list of privileges are not available in a zone. */ privna["dtrace_kernel"] = 1; privna["proc_zone"] = 1; privna["sys_config"] = 1; privna["sys_devices"] = 1; privna["sys_linkdir"] = 1; privna["sys_net_config"] = 1; privna["sys_res_config"] = 1; privna["sys_suser_compat"] = 1; privna["xvm_control"] = 1; privna["virt_manage"] = 1; /* * The following list of privileges are only available * in an exclusive IP stack zone. */ privex["sys_ip_config"] = 1; privex["sys_iptun_config"] = 1; privex["net_rawaccess"] = 1; privex["sys_ppp_config"] = 1; /* * The following list of privileges are available by default * in a zone. */ privdefault["contract_event"] = 1; privdefault["contract_identity"] = 1; privdefault["contract_observer"] = 1; privdefault["file_chown"] = 1; privdefault["file_chown_self"] = 1; privdefault["file_dac_execute"] = 1; privdefault["file_dac_read"] = 1; privdefault["file_dac_search"] = 1; privdefault["file_dac_write"] = 1; privdefault["file_owner"] = 1; privdefault["file_setid"] = 1; privdefault["ipc_dac_read"] = 1; privdefault["ipc_dac_write"] = 1; privdefault["ipc_owner"] = 1; privdefault["net_bindmlp"] = 1; privdefault["net_icmpaccess"] = 1; privdefault["net_mac_aware"] = 1; privdefault["net_observability"] = 1; privdefault["net_privaddr"] = 1; privdefault["proc_audit"] = 1; privdefault["proc_chroot"] = 1; privdefault["proc_exec"] = 1; privdefault["proc_fork"] = 1; privdefault["proc_info"] = 1; privdefault["proc_lock_memory"] = 1; privdefault["proc_owner"] = 1; privdefault["proc_setid"] = 1; privdefault["proc_taskid"] = 1; privdefault["sys_acct"] = 1; privdefault["sys_admin"] = 1; privdefault["sys_audit"] = 1; privdefault["sys_mount"] = 1; privdefault["sys_nfs"] = 1; privdefault["sys_resource"] = 1; /* * The following list of device nodes are available by * default in a zone. */ devdefault["/dev/arp"] = 1; devdefault["/dev/conslog"] = 1; devdefault["/dev/console"] = 1; devdefault["/dev/cpu"] = 1; devdefault["/dev/cpu/self"] = 1; devdefault["/dev/cpu/self/cpuid"] = 1; devdefault["/dev/crypto"] = 1; devdefault["/dev/cryptoadm"] = 1; devdefault["/dev/dtrace"] = 1; devdefault["/dev/dtremote"] = 1; devdefault["/dev/fd"] = 1; devdefault["/dev/kstat"] = 1; devdefault["/dev/log"] = 1; devdefault["/dev/logindmux"] = 1; devdefault["/dev/msglog"] = 1; devdefault["/dev/null"] = 1; devdefault["/dev/openprom"] = 1; devdefault["/dev/poll"] = 1; devdefault["/dev/pool"] = 1; devdefault["/dev/ptmx"] = 1; devdefault["/dev/pts"] = 1; devdefault["/dev/random"] = 1; devdefault["/dev/rdsk"] = 1; devdefault["/dev/rmt"] = 1; devdefault["/dev/sad"] = 1; devdefault["/dev/sad/user"] = 1; devdefault["/dev/stderr"] = 1; devdefault["/dev/stdin"] = 1; devdefault["/dev/stdout"] = 1; devdefault["/dev/swap"] = 1; devdefault["/dev/syscon"] = 1; devdefault["/dev/sysevent"] = 1; devdefault["/dev/sysmsg"] = 1; devdefault["/dev/systty"] = 1; devdefault["/dev/tcp"] = 1; devdefault["/dev/tcp6"] = 1; devdefault["/dev/term"] = 1; devdefault["/dev/ticlts"] = 1; devdefault["/dev/ticots"] = 1; devdefault["/dev/ticotsord"] = 1; devdefault["/dev/tty"] = 1; devdefault["/dev/udp"] = 1; devdefault["/dev/udp6"] = 1; devdefault["/dev/urandom"] = 1; devdefault["/dev/zconsole"] = 1; devdefault["/dev/zero"] = 1; devdefault["/dev/zfs"] = 1; /* * These devices are in an exclusive ip zone by default */ devex["/dev/icmp"] = 1; devex["/dev/icmp6"] = 1; devex["/dev/ip"] = 1; devex["/dev/ip6"] = 1; devex["/dev/ipauth"] = 1; devex["/dev/ipf"] = 1; devex["/dev/ipl"] = 1; devex["/dev/iplookup"] = 1; devex["/dev/ipmpstub"] = 1; devex["/dev/ipnat"] = 1; devex["/dev/ipscan"] = 1; devex["/dev/ipsecah"] = 1; devex["/dev/ipsecesp"] = 1; devex["/dev/ipstate"] = 1; devex["/dev/ipsync"] = 1; devex["/dev/keysock"] = 1; devex["/dev/rawip"] = 1; devex["/dev/rawip6"] = 1; devex["/dev/rts"] = 1; devex["/dev/spdsock"] = 1; devex["/dev/sppp"] = 1; devex["/dev/sppptun"] = 1; /* * These devices are not permitted in a zone */ devna["/dev/mem"] = 1; devna["/dev/kmem"] = 1; devna["/dev/allkmem"] = 1; devna["/dev/poolctl"] = 1; } BEGIN / $g_source_release <= 10 / { /* Available in exclusive ip zones on S10 */ devex["/dev/sctp"] = 1; devex["/dev/sctp6"] = 1; } BEGIN / $g_target_release == 10 / { /* Not allowed inside a zone on S10 */ devna["/dev/lofictl"] = 1; } BEGIN / $g_source_release >= 11 / { /* In a zone by default on S11 */ devdefault["/dev/bpf"] = 1; devdefault["/dev/ipnet"] = 1; devdefault["/dev/ipnet/lo0"] = 1; devdefault["/dev/lo0"] = 1; devdefault["/dev/lofi"] = 1; devdefault["/dev/lofictl"] = 1; devdefault["/dev/nsmb"] = 1; devdefault["/dev/rlofi"] = 1; devdefault["/dev/zvol"] = 1; /* In an exclusive ip zone by default on S11 */ devex["/dev/dld"] = 1; devex["/dev/net"] = 1; devex["/dev/vni"] = 1; } ENDD if [[ $arg_dynamic_time != "inf" ]] ; then cat <<- ENDD /* Counting */ profile:::tick-1sec { seconds--; } /* End */ profile:::tick-1sec /seconds < 1/ { exit(0); } ENDD fi # check for execname match if necessary if (( opt_execnames == 1 )) ; then cat <<- ENDD /* * Check for execname match. Only match processes in global * zone. If no match, then turn off the remaining probes */ syscall::$open:entry / curpsinfo->pr_zoneid == 0 && pid != \$pid && execnames[execname] == 1 / { self->in_open = 1; self->open_done = 0; } fbt::priv_policy:entry / curpsinfo->pr_zoneid == 0 && pid != \$pid && execnames[execname] == 1 / { self->in_priv = 1; self->priv_done = 0; } ENDD else cat <<-ENDD /* * No execnames specified. Always treat as match if in * global zone. */ syscall::$open:entry / curpsinfo->pr_zoneid == 0 && pid != \$pid / { self->in_open = 1; self->open_done = 0; } fbt::priv_policy:entry / curpsinfo->pr_zoneid == 0 && pid != \$pid / { self->in_priv = 1; self->priv_done = 0; } ENDD fi cat <<- ENDD /* * log privilege that is not permitted in a zone. */ fbt::priv_policy:entry / self->in_priv && privna[privnames[arg1]] == 1 / { @priv_na[curpsinfo->pr_psargs, privnames[arg1]] = count(); self->priv_done = 1; } /* * log privilege that requires an exclusive ip stack. */ fbt::priv_policy:entry / self->in_priv && self->priv_done != 1 && privex[privnames[arg1]] == 1 / { @priv_ex[curpsinfo->pr_psargs, privnames[arg1]] = count(); self->priv_done = 1; } /* * If a privilege is not in the default list, log it as one that * needs to be added to the zone to support the calling program. */ fbt::priv_policy:entry / self->in_priv && self->priv_done != 1 && privdefault[privnames[arg1]] != 1 / { @priv_opt[curpsinfo->pr_psargs, privnames[arg1]] = count(); self->priv_done = 1; } /* * Clear the thread for the next privilege call. */ fbt::priv_policy:entry / self->in_priv / { self->priv_done = 0; self->in_priv = 0; } /* * Save arg for return call so that a mapping to the user address will * exist. */ syscall::$open:entry / self->in_open && $arg != NULL / { self->in = $arg; } /* * Get the path of the opened file. */ syscall::$open:return / self->in_open && self->in != NULL / { self->arg = cleanpath(copyinstr(self->in)); } syscall::$open:return / self->in_open && self->arg == NULL / { self->open_done = 1; } /* * Ignore fd or pts devices. */ syscall::$open:return / self->in_open && self->open_done != 1 && ( substr(self->arg, 0, 8) == "/dev/fd/" || substr(self->arg, 0, 9) == "/dev/pts/" ) / { self->open_done = 1; } /* /dev/net devices require exclusive ip stack. */ syscall::$open:return / self->in_open && self->open_done != 1 && ( substr(self->arg, 0, 9) == "/dev/net/" || devex[self->arg] == 1 ) / { @open_ex[curpsinfo->pr_psargs, self->arg] = count(); self->open_done = 1; } /* Check for not allowed devices. */ syscall::$open:return / self->in_open && self->open_done != 1 && ( substr(self->arg, 0, 9) == "/devices/" || devna[self->arg] == 1 )/ { @open_na[curpsinfo->pr_psargs, self->arg] = count(); self->open_done = 1; } /* * Check for default devices. If the device is not in the default * device list, than save it to report as a device that needs to be * added to the zone to support the calling program. */ syscall::$open:return / self->in_open && self->open_done != 1 && substr(self->arg, 0, 5) == "/dev/" && devdefault[self->arg] != 1 / { @open_opt[curpsinfo->pr_psargs, self->arg] = count(); self->open_done = 1; } /* Clear thread for next call to open. */ syscall::$open:return / self->in_open / { self->in_open = 0; self->open_done = 0; self->arg = NULL; } /* * Output logged privileges and devices in the parsable format. */ END { printa("incompatible|privnotallowed|%s|%s\n", @priv_na); printa("configuration|privoptional|%s|%s\n", @priv_opt); printa("incompatible|devnotallowed|%s|%s\n", @open_na); printa("configuration|devoptional|%s|%s\n", @open_opt); } END / $g_target_release == 10 / { printa("configuration|privexclip|%s|%s\n", @priv_ex); printa("configuration|devexclip|%s|%s\n", @open_ex); } ENDD } function is_elf { typeset taste=$(od -N 4 -x $1) if [[ "$g_arch" == "sparc" ]]; then [[ ${taste##0000000 7f45 4c46} != "$taste" ]] && return 0 else [[ ${taste##0000000 457f 464c} != "$taste" ]] && return 0 fi return 1 } function static_check { typeset static_check typeset file # # We don't support statically linked x86 apps inside a solaris10 # branded zone because we don't interpose on the LCALL trap. Flag to # check if the app is statically linked with libc so report an issue. # static_check=0 (( g_source_release == 10 && g_target_release == 11 )) && [[ "$g_arch" == "i386" ]] && static_check=1 file="$1" # Inspect elf file and produce parsable output for zonep2vchk elfdump -d -s -N .dynsym "$file" | nawk -v targ="$g_target_release" \ -v schk="$static_check" -v file="$file" ' BEGIN { # # Parseable output for each zone-incompatible system # call # line="incompatible|syscall|" file sym["pset_create", "libc.so.1"]=line "|pset_create" sym["pset_destroy", "libc.so.1"]=line "|pset_destroy" sym["pset_setattr", "libc.so.1"]=line "|pset_setattr" sym["mknod", "libc.so.1"]=line "|mknod" sym["_xmknod", "libc.so.1"]=line "|mknod" sym["pool_set_binding", "libpool.so.1"]=line "|pool_set_binding" # # Parseable output for system calls not allowing certain args # inside zones # line="incompatible|syscallargs|" file sym["p_online", "libc.so.1"]=line "|p_online" sym["uadmin", "libc.so.1"]=line "|uadmin" sym["pset_assign", "libc.so.1"]=line "|pset_assign" sym["swapctl", "libc.so.1"]=line "|swapctl" sym["pool_conf_open", "libpool.so.1"]=line "|pool_conf_open" sym["pool_conf_commit", "libpool.so.1"]=line "|pool_conf_commit" if (targ == 10) sym["pset_bind", "libc.so.1"]=line "|pset_bind" # # Parseable output for each system call requiring additional # privilege in a zone. # line="configuration|syscallpriv|" file sym["priocntl", "libc.so.1"]=\ line "|priocntl|proc_priocntl" sym["priocntlset", "libc.so.1"]=\ line "|priocntlset|proc_priocntl" sym["adjtime", "libc.so.1"]=\ line "|adjtime|sys_time" sym["ntp_adjtime", "libc.so.1"]=\ line "|ntp_adjtime|sys_time" sym["stime", "libc.so.1"]=\ line "|stime|sys_time" sym["settimeofday", "libc.so.1"]=\ line "|settimeofday|sys_time" sym["clock_settime", "libc.so.1"]=\ line "|clock_settime|sys_time" sym["clock_settime", "librt.so.1"]=\ line "|clock_settime|sys_time" sym["clock_settime", "libposix4.so.1"]=\ line "|clock_settime|sys_time" sym["cpc_bind_cpu", "libcpc.so.1"]=\ line "|cpc_bind_cpu|cpc_cpu" sym["msgctl", "libc.so.1"]=\ line "|msgctl|sys_ipc_config" sym["timer_create", "libc.so.1"]=\ line "|timer_create|proc_clock_highres" sym["timer_create", "librt.so.1"]=\ line "|timer_create|proc_clock_highres" sym["timer_create", "libposix4.so.1"]=\ line "|timer_create|proc_clock_highres" if (targ >= 11) sym["pset_bind", "libc.so.1"]=\ line "|pset_bind|sys_res_bind" if (targ == 10 ) { # Parseable output for calls requiring exclusive ip line="configuration|syscallexclip|" file sym["t_open", "libnsl.so.1"]=\ line "|t_open" } # Parseable output for zones-incompatible libraries line="incompatible|lib|" file # List of libraries to report lib["libdevinfo.so.1"]=line "|libdevinfo.so.1" lib["libcfgadm.so.1"]=line "|libcfgadm.so.1" lib["libtnfctl.so.1"]=line "|libtnfctl.so.1" lib["libkvm.so.1"]=line "|libkvm.so.1" lib["libsysevent.so.1"]=line "|libsysevent.so.1" } { # extract UNDEF symbol names: # (-s -N .dynsym option in elfdump) if ($4 == "FUNC" || $4 == "OBJT" || $4 == "NOTY") { if ($5 == "GLOB" || $5 == "WEAK") { if ($8 == "UNDEF") { found_sym[$9]=1 next } } } if ($2 == "NEEDED") { found_lib[$4]=1 next } } END { # # Report any of the listed symbols or libraries that are used # by the binary. # saw_dyn_libc=0 for (s in found_sym) { for (l in found_lib) { if ((s, l) in sym) { printf("%s\n", sym[s, l]); break } } } for (l in found_lib) { if (l in lib) printf("%s\n", lib[l]); if (l == "libc.so.1") saw_dyn_libc=1 } if (schk && !saw_dyn_libc) printf("incompatible|staticlink|" file); }' } function process_file { typeset file="$1" is_elf "$file" (( $? != 0 )) && return static_check "$file" } function process_arg { typeset file="$1" typeset i if [[ -f "$file" ]]; then process_file "$file" elif [[ -d "$file" ]]; then find "$file" -type f -print 2>/dev/null | while read i ; do # skip if not executable & not a *.so file [[ ! -x "$i" && "${i%*.so}" == "$i" ]] && continue # skip if not readable [[ ! -r "$i" ]] && continue process_file "$i" done fi } function static_check_files { typeset i typeset category typeset issue typeset file typeset syscall typeset priv typeset lib typeset tmpfile=$(mktemp -t) (( $? == 1 )) && fatal "$e_no_tmpfile" setup_mode "static" (( opt_parse_mode == 0 )) && printf -- "$static_header\n"; printf "" > $tmpfile if [[ "$1" == "-" ]]; then # Read file|dir list from standard input. cat | while read i ; do process_arg "$i" >> $tmpfile done elif [[ "$1" != "" ]] ; then cat "$1" | while read i ; do process_arg "$i" >> $tmpfile done fi shift for i in "$@" do process_arg "$i" >> $tmpfile done # Convert parsable output to human readable messages setup_chk "syscall" grep '^incompatible|syscall|' $tmpfile | while IFS='|' read category issue file syscall ; do warn_syscall "$syscall" "$file" done setup_chk "syscallargs" grep '^incompatible|syscallargs|' $tmpfile | while IFS='|' read category issue file syscall ; do warn_syscallargs "$syscall" "$file" done setup_chk "syscallpriv" grep '^configuration|syscallpriv|' $tmpfile | while IFS='|' read category issue file syscall priv ; do warn_syscallargs "$syscall" "$file" $priv done setup_chk "syscallexclip" grep '^configuration|syscallexclip|' $tmpfile | while IFS='|' read category issue file syscall ; do warn_syscallargs "$syscall" "$file" done setup_chk "lib" grep '^incompatible|lib|' $tmpfile | while IFS='|' read category issue file lib ; do warn_lib "$lib" "$file" done rm -f $tmpfile # Add a blank line after last message if (( opt_parse_mode == 0 )) ; then (( g_check_fired > 0 )) && print printf -- "$static_footer\n\n" $g_check_fired; fi } # # Get physical IP interface names on an S10 system by scanning the # existing /etc/hostname[6].* file names. Suppress duplicate interface # names. Each VLAN is considered a separate interface. # function get_s10_interfaces { typeset interface typeset interface_list="" typeset file for file in /etc/hostname.* /etc/hostname6.*; do # Handle case where no files exist. [[ ! -e $file ]] && continue # Sanity check the interface name. interface=${file#/etc/hostname?(6).} interface=${interface%:+([0-9])} [[ $interface != \ @([a-z|A-Z])*([a-z|A-Z|0-9|.])@([0-9]) ]] && continue # Skip duplicate interface names. [[ " $interface_list " == *\ $interface\ * ]] && continue interface_list="$interface_list $interface" done print "$interface_list" } # # Get physical IP interface names on an S11 system. # function get_s11_interfaces { typeset interface_list="" typeset interface typeset persistent # Scan for permanently defined interfaces in ipadm. # Skip duplicates. ipadm show-if -p -o ifname,persistent | \ while IFS=":" read interface persistent; do if [[ ( $persistent == *4* || $persistent == *6* ) && \ " $interface_list " != *\ $interface\ * ]] ; then interface_list="$interface_list $interface" fi done print "$interface_list" } # # Get online physical IP interface names on an S11 source system that # has nwam enabled. # function get_s11_nwam { typeset profile="" typeset interface_list="" typeset p_type typeset p_name typeset p_state # Scan each line of netadm output for interface information # on the active network configuration profile. netadm list -p ncp | \ { # Find the active ncp. while read p_type p_name p_state; do if [[ $p_type == ncp && $p_state == online ]]; then break fi done # Build list of online interface ncu's under the active ncp. while read p_type p_name p_state; do if [[ $p_type == ncu:ip && $p_state == online ]]; then interface_list="$interface_list $p_name" fi # Stop scanning on the next ncp line we find. if [[ $p_type == ncp ]]; then break fi done } print "$interface_list" } # # Convert an IPv4 netmask to a prefix length. # The base address is passed to support "+" syntax. # # Print nothing if any errors are encountered. # function netmask_to_prefixlen { typeset address="$1" typeset netmask="$2" typeset prefixlen=0 typeset newnetmask typeset scratch1 typeset scratch2 # convert to lower caes netmask=$(echo $netmask | tr '[A-Z]' '[a-z]') # If netmask is "+", lookup address in /etc/netmasks for the netmask if [[ "$netmask" == "+" ]]; then getent netmasks "$address" | read scratch1 netmask fi # If a netmask name was specified, lookup the name in /etc/hosts # first. If not found, try /etc/networks. if [[ "$netmask" == @([a-z])*([a-z|0-9|-]) ]]; then getent hosts "$netmask" | read newnetmask scratch1 if [[ -z $newnetmask ]]; then getent networks "$netmask" | \ read scratch1 newnetmask scratch2 fi netmask="$newnetmask" fi # If the above logic failed to provide a netmask string, # return now without displaying a prefix. [[ -z $netmask ]] && return case $netmask in # Hexadecimal netmask. e.g., 0xfffffc00 -> 22 0x+([f|e|c|8|0]) ) netmask="${netmask#0x}" while [[ $netmask == f* ]]; do prefixlen=$(( $prefixlen + 4 )) netmask="${netmask#f}" done case $netmask in e*) prefixlen=$(( $prefixlen + 3 ));; c*) prefixlen=$(( $prefixlen + 2 ));; 8*) prefixlen=$(( $prefixlen + 1 ));; esac ;; # IPv4 dotted notation. e.g., 255.255.254.0 -> 22 +([0-9.]) ) while [[ $netmask == 255\.* ]]; do prefixlen=$(( $prefixlen + 8 )) netmask="${netmask#255\.}" done case $netmask in 255* ) prefixlen=$(( $prefixlen + 8 ));; 254* ) prefixlen=$(( $prefixlen + 7 ));; 252* ) prefixlen=$(( $prefixlen + 6 ));; 248* ) prefixlen=$(( $prefixlen + 5 ));; 240* ) prefixlen=$(( $prefixlen + 4 ));; 224* ) prefixlen=$(( $prefixlen + 3 ));; 192* ) prefixlen=$(( $prefixlen + 2 ));; 128* ) prefixlen=$(( $prefixlen + 1 ));; 0* ) prefixlen=$(( $prefixlen + 0 ));; # Anything else here is a bogus netmask * ) return;; esac # Make sure the remaining octets contain nothing but zeros. if [[ "$netmask" == *\.* ]]; then netmask="${netmask#*\.}" [[ "$netmask" != +([0.]) ]] && return fi ;; # Anything else is an error. * ) return ;; esac print -n "$prefixlen" return } # # Lookup a hostname or address in the currently active name services and # output the information gathered in one of the following formats: # #
/ (hostname) # When no switch is specified. This string is inteded for display # on a zonecfg file net or anet resource comment line. # #
/ # / # When the -a switch was specified. This string is intended for # use on a net resource's address property. # function lookup_host { typeset switch="" if [[ "$1" == -* ]] ; then switch="$1" shift fi typeset family="$1" typeset address="$2" typeset prefix="$3" typeset ip_address="" typeset ip_hostname="" typeset txt1 typeset SP='(^| | |$)' # Lookup the address and hostname from name services. # # When a hostname is used in /etc/hostname. or the "ipadm # create-addr" command, we expect a one-to-one mapping of hostname # to address, but there is no guarantee this is always true. Only # one address will be configured by ifconfig or ipadm. We therefore # use the first address we find for the requested address family. # It is possible with ipadm to have a hostname and not know the # address family before this lookup. For that case, we use the # first address returned for either address family. # # When an address is provided, we want to get the hostname to # help identify the address in the zonecfg file comments. Once # again, we only display the first hostname returned. The format # of addresses found in /etc/hostname* files can vary widely. Use # the address returned by getent if possible for a more consistent # display format. getent ipnodes $address | \ while read ip_address ip_hostname txt1 2>/dev/null do [[ -z $family ]] && break [[ $family == inet && $ip_address == +([0-9|.]) ]] && break [[ $family == inet6 && $ip_address == *:* ]] && break ip_address="" ip_hostname="" done # Use original addr if nothing found in nameservers. if [[ -z $ip_address ]]; then ip_address="$address" fi # Build output based on available information. if [[ "$switch" == "-a" ]]; then # Build output for a net resource address property # in the form
/ # # If original address was specified as a hostname # (not a numeric IPv4 or IPv6 address), and the # hostname definition exits in local files, then # use the original hostname instead of the IP address. # This is a very effective way to make it so that you # don't have multiple places where the system's IP # address is configured on the destination system. if [[ "$address" != +([0-9.]) && "$address" != *:* ]] && egrep "$SP($address)$SP" /etc/inet/hosts \ > /dev/null 2>&1 ; then print -n "${address}" else print -n "${ip_address}" fi if [[ -n $prefix ]]; then print -n "/${prefix}" fi else # Build output for a zonecfg file comment line in # the form / (ip-hostname) print -n "${ip_address}" if [[ -n $prefix ]]; then print -n "/${prefix}" fi if [[ -n $ip_hostname ]]; then print -n " (${ip_hostname})" fi fi } # # Display DHCP assigned address currently configured on the interface. # This function is intended for use on Solaris 10 or earlier. # function pdhcp_addrs { typeset interface="$1" typeset family="$2" typeset logical_interface typeset output="" typeset ip_address="" typeset ip_hostname="" typeset ip_prefixlen="" typeset ip_nextmask typeset switch="-a4" typeset txt1 typeset txt2 typeset txt3 # Scan ifconfig command output to find all currently running # logical DHCP client interfaces. [[ $family == inet6 ]] && switch="-a6" for logical_interface in \ $( ifconfig $switch 2>/dev/null | \ grep "^${interface}:.*RUNNING.*DHCP" | \ sed -e 's/: flags.*$//' ); do if [[ $family == inet ]]; then # Extract address and netmask from ifconfig's # inet line. ifconfig "$logical_interface" \ "$family" 2>/dev/null | \ grep "^ inet " | \ read txt1 ip_address txt2 ip_netmask txt3 # Convert prefix hexstring to prefix length. ip_prefixlen=$( \ netmask_to_prefixlen "" "0x${ip_netmask}" ) else # Extract address and prefix from ifconfig's # inet6 line. ifconfig "$logical_interface" \ "$family" 2>/dev/null | \ grep "^ inet6 " | \ read txt1 output txt2 ip_address="${output%/*}" ip_prefixlen="${output##*/}" fi if [[ $g_target_ip_type == exclusive ]]; then printf "$c_dhcp_address\n" "$( lookup_host \ "$family" "$ip_address" "$ip_prefixlen" )" else # Dynamically assigned IP addresses are not used # when configuring shared-IP zone addresses. Set # this flag to support generating a meaningful # explanation later. g_ip_dynamic="true" printf "$c_dhcp_address_x\n" "$( lookup_host \ "$family" "$ip_address" "$ip_prefixlen" )" fi done } # # Display IPv6 autoconfigured addresses currently configured on the interface. # This function is intended for use on Solaris 10 or earlier. # function pautoconf_addrs { typeset interface="$1" ip_address="" ip_hostname="" typeset logical_interface typeset output="" typeset txt1 typeset txt2 # The first IPv6 address configured on the interface is # always a kernel-generated link-local address. This # address is not flagged "AUTOCONF" even though it was # generated according to rfc 4862 rules. Extract the # address and prefix from ifconfig's inet6 line. ifconfig $interface inet6 2>/dev/null | \ grep "^ inet6 " | read txt1 output txt2 [[ -z $output ]] && return ip_address="${output%/*}" ip_prefixlen="${output##*/}" if [[ $ip_address == fe80:* ]]; then if [[ $g_target_ip_type == exclusive ]] ; then printf "$c_autoconf_address\n" "$( lookup_host \ inet6 "$ip_address" "$ip_prefixlen" )" else # Dynamically assigned IP addresses are not used # when configuring shared-IP zone addresses. Set # this flag to support generating a meaningful # explanation later. g_ip_dynamic="true" printf "$c_autoconf_address_x\n" "$( lookup_host \ inet6 "$ip_address" "$ip_prefixlen" )" fi fi # Scan ifconfig output to find all currently running logical # autoconfigured interfaces. for logical_interface in \ $( ifconfig -a6 2>/dev/null | \ grep "^${interface}:.*RUNNING.*ADDRCONF" | \ sed -e 's/: flags.*$//' ); do # Extract address and prefix from ifconfig's inet6 line. ifconfig "$logical_interface" \ inet6 2>/dev/null | \ grep "^ inet6 " | \ read txt1 output txt2 ip_address="${output%/*}" ip_prefixlen="${output##*/}" if [[ $g_target_ip_type == exclusive ]]; then printf "$c_autoconf_address\n" "$( lookup_host \ inet6 "$ip_address" "$ip_prefixlen" )" else # Dynamically assigned IP addresses are not used # when configuring shared-IP zone addresses. Set # this flag to support generating a meaningful # explanation later. g_ip_dynamic="true" printf "$c_autoconf_address_x\n" "$( lookup_host \ inet6 "$ip_address" "$ip_prefixlen" )" fi done } # Scan lines in a /etc/hostname.* file for a keyword or keyword/value pair. # The following options are supported. The keyword may occur multiple # times. The last setting found will be used. # # value Parameter Search For Output on Success # --------------- ---------- ----------------- # not provided keyword only keyword # set to '*' keyword with non-blank value value found # set to any string keyword with specific value value found # function scan_hostname { typeset keyword="$1" typeset value="$2" typeset line typeset result="" while read line; do set -- $line while [[ -n $1 ]]; do if [[ "$1" == $keyword && -z "$value" ]]; then result="$1" elif [[ "$1" == $keyword && -n $2 ]]; then if [[ "$2" == $value ]]; then result="$2" fi shift fi shift done done print "$result" } # # Display a single address from a hostname file. # # This function appends any statically defined addresses found # to ${g_ip_addr_list} for the caller. # function paddr { typeset addr="$1" typeset prefixlen="$2" typeset ipmp_group="$3" typeset deprecated="$4" typeset failover="$5" # If we found an address, it could be a numeric IP address or # an IP hostname. Lookup the address in the name servers # and output the results in a zonecfg command comment line. if [[ -n $addr ]]; then outstr="$( lookup_host "$family" \ "$addr" "$prefixlen" )" if [[ -n $ipmp_group && \ -n $deprecated && -z $failover ]] then printf "$c_test_address\n" "$outstr" else printf "$c_static_address\n" "$outstr" # Remember statically defined addresses for # potential use in zonecfg net resources. outstr="$( lookup_host -a "$family" \ "$addr" "$prefixlen" )" g_ip_addr_list="$g_ip_addr_list $outstr" fi fi } # # Display static addresses configured in a /etc/hostname.* or # /etc/hostname6.* file. The caller sets up the hostname.* # file on stdin for this function. # # This script appends any statically defined addresses found # to ${g_ip_addr_list} for the caller. # function phostname_addrs { typeset interface="$1" typeset family="$2" typeset args typeset outstr typeset file typeset ipmp_group="" if [[ $family == inet ]]; then file=/etc/hostname.${interface} else file=/etc/hostname6.${interface} fi # Find and display the IPMP group name first. The # IPMP group name may reside in the main file or # in the zeroth logical interface file. Since the # last group name found replaces all others during # startup, any group name found in the logical # interface file takes precedence. if [[ -r $file:0 ]]; then ipmp_group=$( scan_hostname "group" '*' < $file:0 2>/dev/null ) fi if [[ -z $ipmp_group && -r $file ]]; then ipmp_group=$( scan_hostname "group" '*' < $file 2>/dev/null ) fi if [[ -n $ipmp_group ]]; then if [[ $family == inet ]]; then printf "$c_ipmp_member_ipv4\n" $ipmp_group else printf "$c_ipmp_member_ipv6\n" $ipmp_group fi fi # Read each line of the /etc/hostname.* files. Cover both the # physical and the logical interfaces. cat $file $file:+([0-9]) 2>/dev/null | while read args ; do typeset addr="" typeset dest="" typeset prefixlen="" typeset deprecated="" set -- $args # For IPMP enabled interfaces: each address is allowed to # failover to another interface by default. typeset failover="true" # Process each token in the line while [[ -n $1 ]]; do case "$1" in # Keywords to be ignored that have no arguments. all-zones | anycast | "-anycast" | qarp | \ "-arp" | down | forever | inet | inet6 | local | \ "-local" | nud | "-nud" | plumb | preferred | \ "-preferred" | private | "-private" | router | \ "-router" | standby | "-standby" | trailers | \ "-trailers" | up | xmit | "-xmit" | "-zone" ) ;; # Keywords to be ignored that have one argument. auth_algs | broadcast | destination | encaplimit | \ encr_algs | encr_auth_algs | index | metric | \ modinsert | modremove | mtu | tdst | thoplimit | \ token | tsrc | usesrc ) shift ;; # Keywords that do not make sense in a hostname.* # file. Drop the entire line. modlist | removeif | unplumb ) continue 2 ;; # Ignore lines with this keyword. # Any attempt to define a non-global zone # address before the zone boots would fail. zone ) continue 2 ;; # Commands to configure a DHCP interface. Handle # the remainder of this line as if it occurred # in a /etc/dhcp. file. We currently ignore # the contents of /etc/dhcp. files. # # Note that the following ifconfig keywords # are only recognized as keywords when preceded # by "auto-dhcp" or "dhcp". They therefore # should be treated as a hostname if encountered # during processing by this case statement: # "drop", "extend", "inform", "ping", "primary" # "release", "start", "status", "wait". auto-dhcp | dhcp ) pdhcp_addrs "$interface" "$family" continue 2 ;; # Flag the interface as a reverse-ARP interface. # There is no way to find which addresses were # configured with reverse-ARP. auto-revarp ) print "$c_rarp_enabled" ;; # Set the address on the current logical interface. set ) # Must have an argument after "set". # We may have multiple set subcommands on one # line. The last set overwrites any previous # addresses for the logical interface. if [[ -z $2 ]]; then continue 2 fi addr="$2" # We could have "addr/prefixlen". if [[ "$addr" == */* ]]; then prefixlen="${addr#*/}" addr="${addr%/*}" fi shift ;; # Start definition of a new logical interface. addif ) # Display any address defined before this # point. if [[ -n $addr ]]; then paddr "$addr" "$prefixlen" \ "$ipmp_group" "$deprecated" \ "$failover" fi # Must have an argument after "addif". # May have multiple addif blocks on one line. # Cannot have multiple addresses per addif. if [[ -z $2 ]]; then continue 2 fi addr="$2" prefixlen="" deprecated="" failover="true" # We could have "addr/prefixlen". if [[ "$addr" == */* ]]; then prefixlen="${addr#*/}" addr="${addr%/*}" fi shift ;; # Remember manually defined ethernet address # for use by caler of this function. ether ) if [[ "$2" == *([0-9a-fA-F:]) ]]; then g_mac_address="$2" g_mac_addr_type="$c_mac_addr_fixed" shift fi ;; # Remember deprecated and failover state for # this line. These flags are used on IPMP # interfaces. deprecated ) deprecated="true" ;; "-deprecated" ) deprecated="" ;; failover ) failover="true" ;; "-failover" ) failover="" ;; # We already did a pre-scan for IPMP group names. # Ignore the keyword on this detailed scan. group ) # Must have an argument for "group" keyword. if [[ -z $2 ]]; then break 2 fi shift ;; # Convert netmask argument to prefix length. netmask ) # Must have an argument after "netmask". # Can't have netmask without address first. # We can have multiple netmasks. Each one # overrides any previous value. if [[ -z $2 || -z $addr ]]; then continue 2 fi prefixlen="$( \ netmask_to_prefixlen "$addr" "$2" )" shift ;; # Subnets are specified as /. # ifconfig ignores the address part of the subnet. # Extract the prefixlen. subnet ) # Must have an argument after "subnet". # Can't have netmask without address first. # We can have multiple subnets. Each one # overrides any previous value. if [[ -z $2 || -z $addr || \ "$2" != */+([0-9]) ]]; then continue 2 fi prefixlen=${2#*/} shift ;; # What remains is not a recognized keyword. # Assume we have an address of some form. * ) # The first addr on the line is a local addr if [[ -z $addr ]]; then addr="$1" # We could have "addr/prefixlen". if [[ "$addr" == */* ]]; then prefixlen="${addr#*/}" addr="${addr%/*}" fi # The second addr is a destination addr. elif [[ -z $dest ]]; then dest="$1" # Anything else is an error. else break 2 fi esac shift done # We reached the end of the current line. # If we found an address, print it. if [[ -n $addr ]]; then paddr "$addr" "$prefixlen" "$ipmp_group" \ "$deprecated" "$failover" fi done } # # Scan s10 interface configuration files to generate a network # interface definition for an S10 or S11 zonecfg script. # function pnetconfig_s10_interface { typeset interface="$1" typeset if_type typeset if_num typeset vlan_id typeset txt1 typeset ipaddr # MAC address and IP address list may get set by one of the # called functions. g_mac_address="" g_mac_addr_type="" g_ip_addr_list="" # Flag to indicate a dynamically assigned IP address was found. g_ip_dynamic="false" # # Deconstruct the interface name into it's component parts. # For example, the name "e1000g5001" provides # interface type = e1000g # interface number = 1 # vlan id = 5 # if_type="${interface%%+([0-9])}" vlan_id="" typeset -i if_num if_num="${interface#${if_type}}" if (( if_num >= 1000 )) ; then vlan_id=$(( $if_num / 1000 )) if_num=$(( $if_num % 1000 )) fi printf "$c_original_config\n" "$interface" # Scan the /etc/hostname.* file for statically defined addresses. phostname_addrs "$interface" "inet" # If there is a /etc/dhcp.* file, scan running interface # for an address assigned by DHCP. if [[ -e /etc/dhcp.${interface} ]]; then pdhcp_addrs "$interface" "inet" fi # Scan the /etc/hostname6.* file for statically defined addresses. phostname_addrs "$interface" "inet6" pautoconf_addrs "$interface" # If we did not find a persistently defined MAC address, # get the hardware defined ethernet or infiniband mac address # if possible. # "ifconfig -a" appears to be the only way to display # ethernet addresses on inet6 interfaces. if [[ -z $g_mac_address ]]; then ifconfig -a | awk ' /^[a-zA-Z]/ { iface = $1 } /^\tether / { print iface " " $2 } /^\tipib / { print iface " " $2 }' | \ grep "^${interface}:" | \ read txt1 g_mac_address if [[ -n $g_mac_address ]]; then # The MAC address could have been manually changed in # other ways. Verify the "locally administered" bit # is clear before calling it factory assigned. typeset -i firstbyte=16#${g_mac_address%%:*} if [[ $interface == ibd* ]] ; then g_mac_addr_type="$c_mac_addr_infiniband" elif (( (firstbyte & 2) == 0 )) && [[ $interface != ibd* ]] ; then g_mac_addr_type="$c_mac_addr_factory" else g_mac_addr_type="$c_mac_addr_fixed" fi fi fi if [[ -n $g_mac_address ]]; then printf "$c_mac_address\n" "$g_mac_addr_type" "$g_mac_address" fi # Notice that dynamically assigned addresses do not work on shared-IP. if [[ $g_ip_dynamic == true ]]; then printf "$c_dynamic_addr_notice\n" fi if (( g_target_release >= 11 )) ; then if [[ $interface == ibd* ]] ; then # Infiniband partitions must be allocated to the # zone through a net resource. printf "add net\n" printf "\tset physical=%s\n" "$interface" printf "\tend\n" else # Generate an exclusive-IP style anet resource # for the interface. printf "add anet\n" printf "\tset linkname=%s\n" "$interface" printf "\tset lower-link=change-me\n" if [[ -n $g_mac_address || -n $vlan_id ]]; then printf "\t$c_uncomment_linkprop\n" fi if [[ -n $g_mac_address ]]; then printf "\t# set mac-address=%s\n" \ "$g_mac_address" fi if [[ -n $vlan_id ]]; then printf "\t# set vlan-id=%s\n" "$vlan_id" fi printf "\tend\n" fi else # (( g_target_release == 10 )) # Generate shared-IP style net resources for each statically # defined IP address found. for ipaddr in $g_ip_addr_list; do printf "add net\n" printf "\tset address=%s\n" "$ipaddr" printf "\tset physical=change-me\n" printf "\tend\n" done fi } # # Display addresses that are configured under ipadm, including: # - persistently configured static addresses # - dhcp assigned addresses # - IPv6 autoconfigured addresses # function pipadm_addrs { typeset interface="$1" typeset netsvc="$2" typeset ip_addrobj typeset ip_type typeset ip_flags typeset ip_addr typeset pflags typeset ipmp_group typeset ip_prefixlen typeset output_str typeset cid_type typeset cid_value # Exit if this interface was not persistently defined. pflags=$(ipadm show-if -po persistent,group $interface 2>/dev/null) if [[ $netsvc == default && "$pflags" == +(-) ]]; then return fi # Determine if the interface is a member of an IPMP group. ipmp_group=$(ipadm show-ifprop \ -co persistent -m ip -p group $interface 2>/dev/null) if [[ -n $ipmp_group ]]; then printf "$c_ipmp_member_ip\n" "$ipmp_group" fi # Walk the addresses on the interface. ipadm show-addr -p \ -o addrobj,type,persistent,addr ${interface}/ 2>/dev/null | \ while IFS=":" read ip_addrobj ip_type ip_flags ip_addr; do # Skip to next address if we only have "?". # This can happen on dhcp interfaces that have not # aquired an address yet. [[ $ip_addr == \? ]] && continue # We expect "address" followed by optional "/prefixlen". ip_prefixlen="${ip_addr##*/}" if [[ $ip_prefixlen == $ip_addr ]]; then ip_prefixlen="" else ip_addr="${ip_addr%/${ip_prefixlen}}" fi # The address could be a numeric IP address or an IP hostname. # Lookup the address in the name servers and output the # results in a zonecfg command comment line. output_str="$( lookup_host "" "$ip_addr" "$ip_prefixlen" )" case $ip_type in static) # Use only persistently defined static addresses # when running under network/physical:default if [[ $netsvc != default || $ip_flags != +(-) ]]; then # Addresses on IPMP member interfaces are # used as test addresses. This function is # never called with an IPMP interface. if [[ -n $ipmp_group ]]; then printf "$c_test_address\n" \ "$output_str" else printf "$c_static_address\n" \ "$output_str" fi fi ;; dhcp) printf "$c_dhcp_address\n" "$output_str" ipadm show-addr -p \ -o cid-type,cid-value $ip_addrobj | IFS=":" read cid_type cid_value 2> /dev/null printf "$c_dhcp_clientid\n" "$cid_value" "$cid_type" ;; addrconf) printf "$c_autoconf_address\n" "$output_str" ;; esac done } # # Scan s11 interface configuration files and persistent information in dladm # and ipadm on an S11 source system to generate a network interface definition # for an S11 zonecfg script. # function pnetconfig_s11_interface { typeset interface="$1" typeset attr_name typeset netsvc="$2" typeset class="" typeset device typeset if_type typeset hostname_found typeset vlan_id typeset link typeset over typeset mac_link typeset mac_type # MAC address and IP address list may get set by one of the # called functions. g_mac_address="" g_mac_addr_type="" g_ip_addr_list="" # This flag is a noop under this function. It exists to mirror # the environment set up by pnetconfig_s10_interface() g_ip_dynamic="false" # Skip virtual interfaces types. class=$(ipadm show-if -po class $interface) if [[ $class == @(loopback|vni|ipmp) ]]; then return fi # Skip IP Tunnel interfaces. # We prefer the persistent configuration information, but will use # temporary for dynamically configured addresses. class=$(dladm show-link -Ppo class $interface 2>/dev/null) if [[ -z $class ]]; then class=$(dladm show-link -po class $interface 2>/dev/null) fi if [[ $class == iptun ]]; then return fi # Skip cgtp interfaces if [[ $class == "phys" ]]; then device==$(dladm show-phys -Ppo device $interface) if [[ ${device%%+([0-9])} == cgtp ]]; then return fi fi # Skip ppp interfaces. if_type="${interface%%+([0-9])}" if [[ $if_type == ppp ]]; then return fi printf "$c_original_config\n" "$interface" # Scan addresses under ipadm. pipadm_addrs "$interface" "$netsvc" # Get the persistently defined generic MAC address property if any. # This overrides any link-specific MAC address property. if [[ -z $g_mac_address ]]; then g_mac_address=$(dladm show-linkprop \ -Pco value -p mac-address $interface) if [[ -n $g_mac_address ]]; then g_mac_addr_type="$c_mac_addr_fixed" fi fi # Collect datalink parameters based on link type. vlan_id="" dladm show-link -Ppo link,class,over $interface | \ IFS=":" read link class over case $class in aggr ) if [[ -z $g_mac_address ]]; then # dladm show-aggr provides the MAC address policy # used when creating the aggregation. g_mac_address="$(dladm show-linkprop \ -Pco default -p mac-address $link)" case $( dladm show-aggr -Ppo addrpolicy $link ) in auto ) g_mac_addr_type="$c_mac_addr_factory" ;; fixed ) g_mac_addr_type="$c_mac_addr_fixed" ;; esac fi ;; vlan ) # VLANs always use the MAC address of the physical link. vlan_id="$(dladm show-vlan -Ppo vid $link)" g_mac_address="$(dladm show-linkprop \ -Pco value -p mac-address $over)" if [[ -n $g_mac_address ]]; then g_mac_addr_type="$c_mac_addr_fixed" else g_mac_address="$(dladm show-linkprop \ -Pco default -p mac-address $over)" g_mac_addr_type="$c_mac_addr_factory" fi ;; vnic ) # VNICs offer the most flexible MAC assignment policies. vlan_id="$(dladm show-vnic -Ppo vid $link)" if [[ -z $g_mac_address ]]; then dladm show-vnic \ -Ppo macaddress,macaddrtype $link | \ IFS=":" read g_mac_address mac_type case $mac_type in factory ) g_mac_addr_type="$c_mac_addr_factory" ;; fixed ) g_mac_addr_type="$c_mac_addr_fixed" ;; random ) g_mac_addr_type="$c_mac_addr_random" ;; vrrp ) g_mac_addr_type="$c_mac_addr_vrrp" ;; esac fi ;; simnet ) # simnet is an undocumented feature with uncommitted stability if [[ -z $g_mac_address ]]; then g_mac_address="$( dladm show-simnet \ -Ppo macaddress $link 2>/dev/null )" g_mac_addr_type="$c_mac_addr_random" fi ;; part ) # Inifiband partition if [[ -z $g_mac_address ]]; then # MAC addresses on infiniband are dynamically # generated and can change from one boot to another. # Grab the current value of the MAC address. g_mac_address="$(dladm show-linkprop \ -co value -p mac-address $interface 2>/dev/null)" g_mac_addr_type="$c_mac_addr_infiniband" fi ;; * ) # The remaining interface types may not have a MAC # address. If they do, assume the default MAC is "factory". if [[ -z $g_mac_address ]]; then g_mac_address="$(dladm show-linkprop \ -Pco default -p mac-address $interface)" g_mac_addr_type="$c_mac_addr_factory" fi ;; esac if [[ -n $g_mac_address ]]; then # The MAC address could have been manually changed in # other ways. Verify the "locally administered" bit on # a MAC address we think is factory assigned is clear # before officially calling it factory assigned. typeset -i firstbyte=16#${g_mac_address%%:*} if [[ $g_mac_addr_type == $c_mac_addr_factory ]] && \ (( (firstbyte & 2) != 0 )) ; then g_mac_addr_type="$c_mac_addr_fixed" fi # Display MAC address from datalink information. printf "$c_mac_address\n" "$g_mac_addr_type" "$g_mac_address" fi if [[ "$class" == "part" ]] ; then # Infiniband partitions must be allocated to the # zone through a net resource. printf "add net\n" printf "\tset physical=%s\n" "$interface" printf "\tend\n" else # All other types if interfaces are handled as # anet resources. printf "add anet\n" printf "\tset linkname=%s\n" "$interface" if (( opt_xml_mode == 0 )); then printf "\tset lower-link=change-me\n" fi if [[ -n $g_mac_address ]] || [[ -n $vlan_id && $vlan_id != 0 ]]; then printf "\t$c_uncomment_linkprop\n" fi if [[ -n $g_mac_address ]]; then if (( opt_xml_mode )); then if (( opt_recovery_mode )); then printf "\tset mac-address=%s\n" \ "$g_mac_address" fi else printf "\t# set mac-address=%s\n" \ "$g_mac_address" fi fi if [[ -n $vlan_id && $vlan_id != 0 ]]; then printf "\t# set vlan-id=%s\n" "$vlan_id" fi printf "\tend\n" if (( opt_xml_mode )); then # # Ensure saved interface name does not contain any # characters invalid for a zonecfg attr name # attr_name=$(echo $interface | sed 's/[^a-zA-Z0-9._-]/-/g') printf "add attr\n" printf "\tset name=zonep2vchk-net-%s\n" "$attr_name" printf "\tset type=string\n" printf "\tset value=\"interface %s has lower-link " \ "$interface" printf "set to 'auto'. Consider changing to match " printf "the name of a global zone link." if [[ -n $vlan_id && $vlan_id != 0 ]]; then printf " Original vlan-id was %d" "$vlan_id" fi printf "\"\n\tend\n" fi fi } # # Print zonecfg commands to support existing network configuration. # function pnetconfig { typeset interface typeset tunnel_ifs="ip.tun ip6.tun ip.6to4tun" if (( g_source_release >= 11 )) ; then # Must have read access to smf repository. [[ ! -r /etc/svc/repository.db ]] && return if active_ncp_is_fixed ; then for interface in $( get_s11_interfaces ); do pnetconfig_s11_interface "$interface" "default" done else for interface in $( get_s11_nwam ); do pnetconfig_s11_interface "$interface" "nwam" done fi elif (( g_target_release >= 11 )) ; then for interface in $( get_s10_interfaces ); do # Skip virtual, tunnel, cgtp, and ppp interfaces. if [[ " xx lo vni $tunnel_ifs cgtp ppp " != \ *\ ${interface%%+([0-9])}\ * ]]; then pnetconfig_s10_interface "$interface" fi done else for interface in $( get_s10_interfaces ); do # Skip loopback, ppp, and tunnel interfaces. # vni addresses do need to be configured # with shared-IP net resources. if [[ " xx lo ppp $tunnel_ifs " != \ *\ ${interface%%+([0-9])}\ * ]]; then pnetconfig_s10_interface "$interface" fi done fi } function pdatasetconfig { typeset rootpool typeset pool rootpool=$(zfs list -Ho name / | cut -d/ -f1) for pool in $(zpool list -Ho name); do # Root pool does not need a dataset resource. [[ $pool == $rootpool ]] && continue # Skip pools that were excluded by command line options [[ -n ${exclude_pools[$pool]} ]] && continue # Skip any pool that belongs entirely to a zone. [[ $(zfs list -Ho zoned "$pool") == on ]] && continue printf "add dataset\n" printf "\tset name=__change_me__/%s\n" "$pool" printf "\tset alias=%s\n" "$pool" printf "\tend\n" done } # # Print the system configuration as an exported zonecfg on stdout. If # opt_xml_mode is non-zero, a temporary zone is configured then the XML # configuration (as in zoneadm detach -n) of that zone is printed. # # XML mode is for the private use of archiveadm(1M), which uses it to generate # a zone configuration that can be used for P2V operations of the archived # global zone. archiveadm(1M) may be operating in recovery archive mode, which # means that it tries to preserve as much configuration as possible. If it is # not running in recovery mode, less information is preserved. The statement # "less information is preserved" can also be taken to mean "less information # is leaked". # function pconfig { typeset brand typeset sched typeset procs typeset cpu_val typeset -i mem_val typeset -i swap_val typeset v typeset tmpzonename typeset stdout if (( g_source_release == 10 && g_target_release == 11 )); then brand="solaris10" elif (( g_source_release == 9 )); then brand="solaris9" elif (( g_source_release == 8 )); then brand="solaris8" else brand="none" fi if (( opt_xml_mode )); then if (( g_source_release < 11 )); then print -u2 "Only Solaris 11 and later are supported" \ "for XML output" exit 1 fi stdout=$(mktemp -t zonep2vchk.XXXXXX) tmpzonename=$(basename $stdout) # Save stdout for later, for now redirecting it to a file that # will be used with zonecfg. exec 3>&1 exec >$stdout fi printf "create -b\n" printf "set zonepath=/system/zones/%%{zonename}\n" if [[ $brand != "none" ]]; then printf "set brand=%s\n" "$brand" fi # attr that identifies source system if (( opt_xml_mode == 0 || opt_recovery_mode )); then printf "add attr\n" printf "\tset name=\"zonep2vchk-info\"\n" printf "\tset type=string\n" printf "\tset value=\"p2v of host %s\"\n" "$g_hname" printf "\tend\n" fi printf "set ip-type=%s\n" "$g_target_ip_type" # hostid - set for recovery mode; comment in config mode. if (( opt_xml_mode )); then if (( opt_recovery_mode )); then print "set hostid=$(hostid)" fi else print $c_hostid printf "# set hostid=%s\n" "$(hostid)" fi # # Get configured scheduling class # if [[ -s /etc/dispadmin.conf ]] ; then sched=$(grep '^DEFAULT_SCHEDULER=' \ /etc/dispadmin.conf 2>/dev/null | awk -F= '{ print $2 }') fi if [[ -n $sched ]] ; then print $c_sched printf "set scheduling-class=%s\n" "$sched" fi # Get number of processes procs=$(kstat -p unix:0:var:v_proc | awk '{ print $2 }') # Reduce max-processes if it is a modern default (( procs >= 30000 )) && (( procs = procs - 10000 )) # S11 supports max-processes rctl if (( g_target_release >= 11 )) ; then print $c_max_procs_11 printf "set max-processes=%s\n" "$procs" else print $c_max_procs_10 fi (( procs = procs * 2 )) printf "set max-lwps=%s\n" "$procs" # # Get number of CPUs # typeset -i cpu_val=$(psrinfo | wc -l) printf "add attr\n" printf "\tset name=zonep2vchk-num-cpus\n" printf "\tset type=string\n" printf "\tset value=\"original system had %d cpus: " "$cpu_val" printf "consider capped-cpu (ncpus=%3.1f) " "$cpu_val" printf "or dedicated-cpu (ncpus=%d)\"\n" "$cpu_val" printf "\tend\n" print $c_capped_cpu1 print $c_capped_cpu2 printf "# add capped-cpu\n" printf "#\tset ncpus=%3.1f\n" "$cpu_val" printf "#\tend\n" print $c_ded_cpu printf "# add dedicated-cpu\n" printf "#\tset ncpus=%d\n" "$cpu_val" printf "#\tend\n" # # Get memory info. # mem_val=$(LC_ALL=C prtconf | nawk '$0 ~ /^Memory size:/ { if ($NF == "Gigabytes") { $3 *= 1024 } if ($NF == "Terabytes") { $3 *= 1024 * 1024 } print $3 exit }') # compute swap as memory plus disk swap swap_val=0 swap -l | tail +2 | awk '{ print $4 }' | while read v ; do # convert blocks to kilobytes (( swap_val = swap_val * 2 )) # Add size of swap device to total swap (( swap_val = swap_val + v )) done # Convert swap from kb to mb (( swap_val = swap_val / 1024 )) printf "add attr\n" printf "\tset name=zonep2vchk-memory\n" printf "\tset type=string\n" printf "\tset value=\"original system had %d MB RAM and %d MB swap: " \ "$mem_val" "$swap_val" # The term "swap" is ambiguous and thus confusing. Here we transition # from the aggregate amount of space in swap devices to the amount of # virtual memory that can be reserved. (( swap_val = swap_val + mem_val )) printf "consider capped-memory (physical=%dM swap=%dM)\"\n" \ "$mem_val" "$swap_val" printf "\tend\n"; print $c_capped_mem1 print $c_capped_mem2 printf "# add capped-memory\n" printf "#\tset physical=%dM\n" "$mem_val" printf "#\tset swap=%dM\n" "$swap_val" printf "#\tend\n" pnetconfig if (( opt_xml_mode )); then pdatasetconfig fi # # All done # printf "exit\n" if (( opt_xml_mode )); then # Restore stdout exec 1>&3 zonecfg -z "$tmpzonename" -f "$stdout" if (( $? != 0 )); then print -u2 "Internal error: could not create temporary" \ "zone configuration from file $stdout. Please" \ "report this error to Oracle support." exit 1 fi typeset xmlout xmlout=$(zoneadm -z $tmpzonename detach -n) if (( $? != 0 )); then print -u2 "Internal error: could not generate XML" \ "zone configuration from file $stdout. Please" \ "report this error to Oracle support." exit 1 fi print -- "$xmlout" | sed "s/$tmpzonename/global/g" zonecfg -z $tmpzonename delete -F rm -f "$stdout" fi } function warn_be { typeset be_active="" typeset be_list="" typeset i setup_chk "be" # Check only valid on s10+ (( g_source_release < 10 )) && return # "lustatus" can only be run as root. Since we want the basic checks # to work for a non-privileged user, we look at the lutab directly. # Check for any lu stuff on solaris 10. if (( g_source_release == 10 )) ; then [[ ! -f /etc/lutab || ! -f /etc/lu/.BE_CONFIG ]] && return fi # # Get the name of the current boot environment and the list of # boot environments # if (( g_source_release == 10 )) ; then # Active be from .BE_CONFIG be_active=$(grep LUBECF_BE_NAME /etc/lu/.BE_CONFIG | cut -d'=' -f 2) be_list=$(grep ':C:0$' /etc/lutab | cut -d':' -f2) else # Active be marked with "N" be_active=$(beadm list -H | cut -d';' -f 1,3 | grep ';.*N.*' | cut -d';' -f 1) be_list=$(beadm list -H | cut -d';' -f 1) fi for i in $be_list ; do [[ $i == "$be_active" ]] && continue warn_item "$i" done } # # Identify physical interfaces that would have to be available on # the destination system with exclusive-IP zones. # This is not an issue with Solaris 11 destinations. # function warn_physif { typeset if_list="$1" typeset impacted_ifs typeset if_type typeset if_num typeset vlan_id typeset if_num typeset interface impacted_ifs="" for interface in $if_list; do # Skip loopback, vni, cgtp, and tunnel interfaces if_type="${interface%%+([0-9])}" if [[ " xx lo vni cgtp ip.tun ip6.tun ip.6to4tun " == \ *\ $if_type\ * ]]; then continue fi # There is no need to have a separate physical interface for # each VLAN. Remove the vlan-id from the interface name. if [[ "$interface" == *[0-9][0-9][0-9][0-9] ]]; then if_type="${interface%%+([0-9])}" if_num="${interface#${if_type}}" vlan_id=${if_num%[0-9][0-9][0-9]} if_num="${if_num##${vlan_id}?(0)?(0)}" interface="${if_type}${if_num}" fi # Skip duplicate interface names. if [[ " $impacted_ifs " != *\ $interface\ * ]]; then impacted_ifs="$impacted_ifs $interface" warn_item "$interface" fi done } # # Identify configuration files that would be impacted by changing # the interface names in an exclusive-IP zone. # This is not an issue with Solaris 11 destinations. # function warn_ifname { typeset if_list="$1" typeset if_type typeset impacted_ifs typeset prefix typeset interface typeset dirs typeset tmpfile typeset SP='(^| | |:|$)' typeset pattern typeset patterns typeset file if (( g_target_release >= 11 )) ; then return fi # Collect list of interfaces to search for. # Skip loopback, vni, cgtp, and tunnel interfaces tmpfile="/tmp/zonep2vchk_ifs.$$" for interface in $if_list; do if_type="${interface%%+([0-9])}" if [[ " xx lo vni cgtp ip.tun ip6.tun ip.6to4tun " \ != *\ $if_type\ * ]]; then impacted_ifs="$impacted_ifs $interface" print "$SP($interface)$SP" >> $tmpfile fi done if_list="$impacted_ifs" # Display names of files that have an embeded interface # name in the file name. set -A patterns \ "/etc/hostname.*" \ "/etc/dhcp.*" \ "/etc/hostname6.*" \ "/etc/inet/gnome-system-tools/defaultrouter.*" \ "/etc/inet/gnome-system-tools/hostname.*" for pattern in "${patterns[@]}"; do prefix="${pattern%\*}" for file in ${pattern}; do [[ ! -e $file ]] && continue interface=${file#$prefix} interface=${interface%:+([0-9])} if [[ " $if_list " == *\ $interface\ * ]]; then warn_item "$file" fi done done # Display names of files that contain an interface # name inside the file. dirs=" /etc/inet /etc/ipf /etc/gateways" for dir in $dirs; do find $dir -type f -print 2>/dev/null done | while read file; do if ( egrep -f $tmpfile $file > /dev/null 2>&1 ); then warn_item "$file" fi done # Clean up our file litter. rm $tmpfile } # Check if Mobile-IP is configured. function warn_mobile_ip { if [[ -e /etc/inet/mipagent.conf ]]; then warn_feature "mobileip" "$w_mobile_ip" fi } # Identify interfaces that obtain their IPv4 addresses from a DHCP server. function warn_dhcp_assigned { typeset if_list="$1" typeset impacted_ifs typeset interface typeset SP='(^| | |$)' typeset pflags typeset addrtype # Get list of interfaces that have DHCP client enabled. impacted_ifs="" for interface in $if_list; do if (( g_source_release < 11 )) ; then # Look for "dhcp" keywords in the /etc/hostname.* file # or for existance of a /etc/dhcp.* file. if [[ -e /etc/hostname.${interface} ]]; then if [[ -e /etc/dhcp.${interface} ]] || \ egrep "$SP(auto-dhcp|dhcp)$SP" \ /etc/hostname.${interface} \ > /dev/null 2>&1; then impacted_ifs="$impacted_ifs $interface" continue fi fi else # (( g_source_release >= 11 )) # Look for dhcp addresses that are persistently # defined by ipadm on the interface, or by nwam ipadm show-addr -p -o current,persistent,type \ ${interface}/ 2>/dev/null | \ while IFS=":" read cflags pflags addrtype; do if [[ ("$cflags" == U* || "$pflags" != +(-)) \ && "$addrtype" == "dhcp" ]]; then impacted_ifs="$impacted_ifs $interface" continue 2 fi done fi done if [[ -n $impacted_ifs ]]; then warn_feature "dhcp" "$w_dhcp_assigned" "$impacted_ifs" fi } # Identify interfaces with reverse-ARP enabled. # Persistently defined reverse ARP interfaces are not supported on S11. function warn_rarp_assigned { typeset if_list="$1" typeset impacted_ifs typeset interface typeset SP='(^| | |$)' # Get list of interfaces that have reverse-ARP enabled. impacted_ifs="" for interface in $if_list; do # Look for "auto-revarp" keyword in the /etc/hostname.* file. if (egrep "$SP(auto-revarp)$SP" /etc/hostname.${interface} ) \ > /dev/null 2>&1; then impacted_ifs="$impacted_ifs $interface" continue fi done if [[ -n $impacted_ifs ]]; then warn_feature "rarp" "$w_rarp_assigned" "$impacted_ifs" fi } # Scan the ndpd.conf file for the value of a keyword associated with # the specified interface. Look for the "ifdefault" line if no interface # is specified. function scan_ndpd_conf { typeset interface="$1" typeset keyword="$2" typeset found_interface="" typeset line while read line; do set -- $line while [[ -n $1 ]]; do case $1 in "ifdefault") if [[ -z $interface ]]; then found_interface=true fi ;; "if") if [[ -n "$2" && "$2" == "$interface" ]] then found_interface=true fi shift ;; "prefixdefault") found_interface="" ;; "prefix") found_interface="" ;; "$keyword") if [[ -n $2 ]]; then if [[ -n $found_interface ]]; then print "$2" return fi shift fi ;; \#*) continue 2 ;; esac shift done done } # Identify interfaces that have IPv6 stateless address autoconfiguration # enabled. function warn_ipv6_autoconf { typeset if_list="$1" typeset ndpd_conf typeset autoconf_default typeset impacted_ifs typeset autoconf_value typeset device typeset pflags typeset addrtype typeset interface typeset files # in.ndpd must be enabled for autoconfiguration to work. if [[ "$(svcs -Ho state svc:/network/routing/ndp:default 2>/dev/null)" \ != online ]] then return fi # Get the location of the ndpd.conf file. ndpd_conf="$( \ svccfg -s svc:/network/routing/ndp:default \ listprop routing/config_file 2>/dev/null | awk '{print $3}')" if [[ -z $ndpd_conf ]]; then ndpd_conf="/etc/inet/ndpd.conf" fi # Get the default StatelessAddrConf setting if any from ndp.conf. if [[ -e $ndpd_conf ]]; then autoconf_default="$( scan_ndpd_conf \ "" "StatelessAddrConf" < $ndpd_conf )" fi # The StatelessAddrConf setting of the ndp service overrides # the default setting in ndp.conf. if [[ -z $autoconf_default && \ "$(svccfg -s svc:/network/routing/ndp:default \ listprop routing/stateless_addr_conf 2> /dev/null)" \ == *true ]]; then autoconf_default=true fi # Get list of interfaces that have autoconfiguration enabled. impacted_ifs="" for interface in $if_list; do autoconf_value="" if (( g_source_release < 11 )); then # Skip loopback, vni, and tunnel interfaces device="${interface%%+([0-9])}" [[ " xx lo vni ip.tun ip6.tun ip.6to4tun " \ == *\ $device\ * ]] && continue files=$( ls /etc/hostname6.${interface} \ /etc/hostname6.${interface}:+([0-9]) 2>/dev/null ) if [[ -n $files ]]; then # Does the ndpd.conf file have a # StatelessAddrConf setting for the current # interface? if [[ -e $ndpd_conf ]]; then autoconf_value="$( scan_ndpd_conf \ "$interface" "StatelessAddrConf" \ < $ndpd_conf )" fi # Use the setting of the interface # StatelessAddrConf value if one exists, # otherwise follow the default setting. if [[ "$autoconf_value" == "true" ]]; then impacted_ifs="$impacted_ifs $interface" elif [[ -z "$autoconf_value" && \ "$autoconf_default" == "true" ]]; then autoconf_value="true" impacted_ifs="$impacted_ifs $interface" fi fi else # (( g_source_release >= 11 )) # Look for autoconfigured addresses that are # persistently defined by ipadm on the interface. ipadm show-addr -p -o current,persistent,type \ ${interface}/ 2> /dev/null | \ while IFS=":" read cflags pflags addrtype; do if [[ ("$cflags" == U* || "$pflags" != +(-)) \ && "$addrtype" == "addrconf" ]]; then impacted_ifs="$impacted_ifs $interface" continue 2 fi done fi done if [[ -n $impacted_ifs ]]; then warn_feature "v6autoconf" "$w_ipv6_autoconf" "$impacted_ifs" fi } # Identify link aggregation interfaces. # warn_datalink() is used instead of this function on Solaris 11 systems. function warn_aggregation { impacted_ifs="" aggr="" typeset line # Parsable form of dladm show-aggr command contains # zero or more aggregation definitions. Each definition # consists of an "aggr" line followed by one or more # "dev" lines. dladm show-aggr -p 2>/dev/null | \ while read line; do set $line if [[ $1 == aggr ]]; then shift # The aggregation interface name available to # the IP layer is the interger value of the # aggregation key appended to the string "aggr". while [[ -n $1 ]]; do if [[ "${1%%=*}" == key ]]; then aggr="aggr${1#*=}" break fi shift done impacted_ifs="$impacted_ifs $aggr" fi done if [[ -n $impacted_ifs ]]; then warn_feature "aggr" "$w_link_aggregation" "$impacted_ifs" fi } # Identify datalink features that must be configured in the global zone. # Skip physical links because they automatically exist when hardware exists. # Skip vlan links because their special checks are handled by warn_vlan. # Skip iptun links because they can be configured in a zone. # This function is called on S11 systems or later. function warn_datalink { typeset class typeset ifs typeset secobjs typeset impacted_ifs for class in aggr part vnic simnet etherstub bridge; do ifs=$( dladm show-link -pPo link,class | \ grep ":$class" | sed 's/:.*//' ) [[ -z $ifs ]] && continue case $class in aggr) warn_feature "aggr" "$w_link_aggregation" "$ifs";; part) warn_feature "ibpart" "$w_ibpart" "$ifs";; vnic) warn_feature "vnic" "$w_vnic" "$ifs" ;; simnet ) # simnet is an undocumented feature # with uncommitted stability warn_feature "simnet" "$w_simnet" "$ifs" ;; etherstub) warn_feature "etherstub" "$w_etherstub" "$ifs" ;; bridge) warn_feature "bridge" "$w_bridge" "$ifs" ;; esac done } # Identify Wireless WPA or WEP secure objects. # Wireless interfaces do not exist before Solaris 11. function warn_secobj { # Extract secure object names from the dladm output. if (( g_source_release >= 11 )) ; then secobjs=$( dladm show-secobj -Ppo object ) fi if [[ -n $secobjs ]]; then impacted_ifs=$( print $secobjs ) warn_feature "secobj" "$w_secobj" "$secobjs" fi } # Identify VLAN interfaces. function warn_vlan { typeset if_list="$1" typeset impacted_ifs typeset if_type typeset interface typeset vlan typeset vid impacted_ifs="" if (( g_source_release >= 11 )) ; then # Extract vlan names from the dladm output. dladm show-vlan -Ppo link,vid | \ while IFS=":" read vlan vid; do impacted_ifs="$impacted_ifs $vlan" done else # S8, S9, S10 for interface in $if_list; do # Skip loopback, vni, cgtp, and tunnel interfaces if_type="${interface%%+([0-9])}" if [[ " xx lo vni cgtp ip.tun ip6.tun ip.6to4tun " \ == *\ $if_type\ * ]]; then continue fi if [[ "$interface" == *[0-9][0-9][0-9][0-9] ]]; then impacted_ifs="$impacted_ifs $interface" fi done fi if [[ -n $impacted_ifs ]]; then warn_feature "vlan" "$w_vlan" "$impacted_ifs" fi } # Identify IPv4 and IPv6 interfaces that have IP forwarding enabled. # This is not an issue with Solaris 11 destinations that primarily # use exclusive IP zones. function warn_forwarding { typeset if_list="$1" typeset forwarding_default typeset impacted_ifs typeset if_type typeset SP='(^| | |$)' typeset ipv typeset interface typeset files # Repeat for IPv4 and IPv6. for ipv in 4 6; do # Get default setting for forwarding from the # the forwarding service definition. forwarding_default="" if [[ "$(svccfg -s \ svc:/network/ipv${ipv}-forwarding:default \ listprop general/enabled 2> /dev/null)" == *true ]]; then forwarding_default=true fi # Get list of interfaces that have forwarding enabled. impacted_ifs="" for interface in $if_list; do # Skip loopback and vni interfaces. if_type="${interface%%+([0-9])}" if [[ " xx lo vni " == *\ $if_type\ * ]]; then continue fi # Identify hostname files to search. if [[ $ipv == 4 ]]; then files=$( ls /etc/hostname.${interface} \ /etc/hostname.${interface}:+([0-9]) \ 2>/dev/null ) else files=$( ls /etc/hostname6.${interface} \ /etc/hostname.${interface}6:+([0-9]) \ 2>/dev/null ) fi [[ -z $files ]] && continue # The interface forwarding is determined by the # following (in order of priority): # 1) "router" keyword setting in /etc/hostname* file # 2) default setting from forwarding service # 3) false if ( cat $files | egrep "$SP(router)$SP" ) \ >/dev/null 2>&1; then impacted_ifs="$impacted_ifs $interface" elif ( cat $files | egrep "$SP(-router)$SP" ) \ >/dev/null 2>&1; then true elif [[ $forwarding_default == true ]]; then impacted_ifs="$impacted_ifs $interface" fi done # Write list of impacted interfaces. if [[ -n $impacted_ifs ]]; then if [[ $ipv == 4 ]]; then warn_feature "v4forward" \ "$w_ipv4_forwarding" "$impacted_ifs" else warn_feature "v6forward" \ "$w_ipv6_forwarding" "$impacted_ifs" fi fi done } # Determine if any static routes other than a default route are # configured on the system. # This is not an issue with Solaris 11 destinations # that primarily use exclusive IP zones. function warn_static_routes { typeset SP='(^| | |$)' if ( route -p show 2>/dev/null | \ grep -v "No persistent routes are defined" | grep -v "$SP(default)$SP" > /dev/null ); then warn_feature "staticroute" "$w_static_routes" fi } # Identify IPMP groups. # This is not an issue with Solaris 11 destinations # that primarily use exclusive IP zones. function warn_ipmp_group { typeset if_list="$1" typeset group typeset group_list typeset interface typeset files # Find all IPMP group names. typeset group_list="" for interface in $if_list; do files=$( ls /etc/hostname.${interface} \ /etc/hostname.${interface}:0 \ /etc/hostname6.${interface} \ /etc/hostname6.${interface}:0 2>/dev/null ) if [[ -n $files ]]; then group=$( cat $files | scan_hostname "group" '*' ) if [[ -n $group && \ " $group_list " != *\ $group\ * ]]; then group_list="$ipmp_group_list $group" fi fi done if [[ -n "$group_list" ]]; then warn_feature "ipmpgroup" "$w_ipmp_group" "$group_list" fi } # Identify IP tunnel interfaces. # This is not an issue with Solaris 11 destinations # that primarily use exclusive IP zones. function warn_iptun { typeset if_list="$1" typeset impacted_ifs typeset interface impacted_ifs="" for interface in $if_list; do if [[ "$interface" == ip.tun*([0-9]) || "$interface" == ip6.tun*([0-9]) || "$interface" == ip.6to4tun*([0-9]) ]]; then impacted_ifs="$impacted_ifs $interface" fi done if [[ -n $impacted_ifs ]]; then warn_feature "iptun" "$w_iptun" "$impacted_ifs" fi } # Identify VNI interfaces. # VNI is not an issue with Solaris 11 destinations # that primarily use exclusive IP zones. function warn_vni { typeset if_list="$1" typeset impacted_ifs typeset interface impacted_ifs="" for interface in $if_list; do if [[ "$interface" == vni*([0-9]) ]]; then impacted_ifs="$impacted_ifs $interface" fi done if [[ -n $impacted_ifs ]]; then warn_feature "vni" "$w_vni" "$impacted_ifs" fi } # Identify cgtp interfaces. function warn_cgtp { typeset if_list="$1" typeset impacted_ifs typeset interface typeset device typeset flags impacted_ifs="" if (( g_source_release >= 11 )) ; then dladm show-phys -Ppo link,device,flags | \ while IFS=":" read interface device flags; do if [[ "$device" == cgtp*([0-9]) && \ "$flags" != *r* ]]; then impacted_ifs="$impacted_ifs $interface" fi done else for interface in $if_list; do if [[ "$interface" == cgtp*([0-9]) ]]; then impacted_ifs="$impacted_ifs $interface" fi done fi if [[ -n $impacted_ifs ]]; then warn_feature "cgtp" "$w_cgtp" "$impacted_ifs" fi } # # warn_datalink() is used instead of this function on Solaris 11 systems. # On Solaris 10, IP is configured directly on infiniband interfaces. # On Solaris 11, IP is configured on infiniband partitions, with multiple # partitions supported over a physical infiniband interface. function warn_ibiface { typeset if_list="$1" typeset impacted_ifs typeset interface typeset device typeset flags impacted_ifs="" for interface in $if_list; do if [[ "$interface" == ibd*([0-9]) ]]; then impacted_ifs="$impacted_ifs $interface" fi done if [[ -n $impacted_ifs ]]; then warn_feature "ibiface" "$w_ibiface" "$impacted_ifs" fi } # Identify if ppp is configured. function warn_ppp { typeset files files="$(ls /etc/ppp/options /etc/ppp/options.* /etc/ppp/peers/* \ 2>/dev/null | grep -v ".tmpl")" if [[ -n $files ]]; then warn_feature "ppp" "$w_ppp" fi } # Simulate function of Solaris 10's pkgchk using Solaris 11's pkg utility. # Return 1 (fail) if the file specified in the argument was changed since # installation. function pkg_check { typeset file="$1" typeset pkgname="" # Was the file installed by an IPS package? if (( g_source_release >= 11 )); then pkgname=$( pkg search -l "$file" 2>/dev/null | \ tail -1 | awk '{print $4}' ) fi if [[ -n $pkgname ]] then # File installed by IPS, pkg verify will list file if changed. if ( pkg verify $pkgname | \ grep ${file#/} ) >/dev/null 2>&1; then return 1 fi elif grep "^${file}[= ]" /var/sadm/install/contents >/dev/null 2>&1; then # File is from a system-V package, # pkgchk returns error status if changed. if ! pkgchk -p $file >/dev/null 2>&1 ; then return 1 fi else # Treat all other files same as changed files. return 1 fi return 0 } # Identify changed network driver configuration files. function warn_driverconf { typeset if_list="$1" typeset device_list typeset device typeset interface typeset file if (( g_source_release >= 11 )) ; then device_list=" " for interface in $( dladm show-phys -Ppo device ); do # Skip interface if device already seen. device="${interface%%+([0-9])}" [[ "$device_list" == *\ $device\ * ]] && continue device_list="${device_list}${device} " # Warn if device.conf exists and was changed # since installation. for file in \ /kernel/drv/${device}.conf \ /usr/kernel/drv/${device}.conf; do if [[ -e $file ]] && \ ! pkg_check $file; then warn_item "$file" fi done done else # Solaris 8, 9, 10 device_list=" " for interface in $if_list; do # Skip loopback, vni, cgtp, and tunnel interfaces device="${interface%%+([0-9])}" [[ " xx lo vni cgtp ip.tun ip6.tun ip.6to4tun " \ == *\ $device\ * ]] && continue # Skip interface if device already seen. [[ "$device_list" == *\ $device\ * ]] && continue device_list="${device_list}${device} " # Warn if device.conf exists and was changed # since installation. for file in \ /kernel/drv/${device}.conf \ /usr/kernel/drv/${device}.conf; do if [[ -e $file ]] && \ ! pkg_check $file > /dev/null 2>&1; then warn_item "$file" fi done done fi } # Identify datalink properties with non-default values. # dladm linkprop is a new feature with Solaris 11. function warn_linkprop { typeset found_links="" typeset dl_link typeset dl_class typeset dl_prop typeset dl_value typeset dl_def # Scan all permanently defined properties of all links. dladm show-link -pPo link,class | \ while IFS=":" read dl_link dl_class; do # Skip over iptun links, they can be configured in a zone. [[ "$dl_class" == "iptun" ]] && continue dladm show-linkprop \ -Pco property,value,default $dl_link 2>/dev/null | \ while IFS=":" read dl_prop dl_value dl_def; do # A property is considered non-default if its # persistent value is not equal to null, "?", or # the default value. if [[ -n "$dl_value" && \ "$dl_value" != "?" && \ "$dl_value" != "$dl_def" ]]; then warn_item_compact "$dl_link" \ "$dl_prop" "$dl_value" fi done done } # Identify potential issues with the network configuration. # The list of relevant issues depends on the capabilities # of both the source system and the target system. function warn_net { typeset interface_list # Get a list of configured IP interface names. if (( g_source_release >= 11 )) ; then # Must have read access to smf repository. [[ ! -r /etc/svc/repository.db ]] && return if active_ncp_is_fixed ; then interface_list="$( get_s11_interfaces )" else interface_list="$( get_s11_nwam )" fi else interface_list="$( get_s10_interfaces )" fi # S11 destination if (( g_target_release >= 11 )) ; then setup_chk "sharedonly" warn_cgtp "$interface_list" setup_chk "datalink" warn_vlan "$interface_list" if (( g_source_release >= 11 )) ; then warn_datalink "$interface_list" warn_secobj "$interface_list" else warn_ibiface "$interface_list" warn_aggregation "$interface_list" fi if (( g_source_release >= 11 )) ; then setup_chk "linkprop" warn_linkprop "$interface_list" fi setup_chk "dynaddr" warn_dhcp_assigned "$interface_list" if (( g_source_release < 11 )) ; then warn_rarp_assigned "$interface_list" fi warn_ipv6_autoconf "$interface_list" setup_chk "netdevalloc" warn_ppp if (( opt_fast_mode == 0 )) ; then setup_chk "driverconf" warn_driverconf "$interface_list" fi # S10 destination else setup_chk "physif" warn_physif "$interface_list" setup_chk "ifname" warn_ifname "$interface_list" setup_chk "dynaddr" warn_dhcp_assigned "$interface_list" warn_rarp_assigned "$interface_list" warn_ipv6_autoconf "$interface_list" setup_chk "sharedip" warn_ipmp_group "$interface_list" warn_vni "$interface_list" warn_forwarding "$interface_list" warn_static_routes setup_chk "exclusiveonly" warn_iptun "$interface_list" setup_chk "sharedonly" warn_cgtp "$interface_list" setup_chk "datalink" warn_vlan "$interface_list" warn_aggregation "$interface_list" warn_ibiface "$interface_list" setup_chk "netdevalloc" warn_ppp if (( opt_fast_mode == 0 )) ; then setup_chk "driverconf" warn_driverconf "$interface_list" fi fi } function warn_nfs { setup_chk "nfs" typeset i # NFS server works on S11 (( g_source_release >= 11 )) && return # NFS server will eventually work in for s10c zone # (( g_source_release == 10 && g_target_release == 11 )) && return # Check live system shares [[ ! -f /usr/sbin/share ]] && return for i in $(share -F nfs 2>/dev/null | nawk '{print $2}') do warn_item_compact "$i" done } # lofi does not work on S10 targets function warn_lofi { typeset dev typeset file typeset dummy setup_chk "lofi" # lofi works on s11 and s10c (( g_target_release >= 11 )) && return # Check for lofi utility [[ ! -f /usr/sbin/lofiadm ]] && return lofiadm | tail +2 | while read dev file dummy ; do warn_item $dev $file done } function warn_ramdisk { typeset dev typeset dummy setup_chk "ramdisk" [[ ! -f /usr/sbin/ramdiskadm ]] && return ramdiskadm | tail +2 | while read dev dummy ; do warn_item $dev done } function warn_smb { typeset shares typeset i setup_chk "smb" (( g_source_release < 11 )) && return [[ ! -f /usr/sbin/share ]] && return for i in $(share -F smb 2>/dev/null | tail +2 | nawk '{print $2}') do warn_item_compact "$i" done } function warn_vfstab { typeset dev typeset mnt setup_chk "vfstab" nawk '{ if (substr($1, 0, 1) == "#" || length($1) == 0) next if ($1 == "fd" || $1 == "/proc" || $1 == "swap" || $1 == "ctfs" || $1 == "objfs" || $1 == "sharefs" || $1 == "/devices" || $3 == "/" || $4 == "nfs" || $4 == "lofs" || $4 == "swap") next print $0, $1 }' /etc/vfstab | \ while read dev mnt do warn_item "$dev" "$mnt" done } # # Warn if iscsi client function warn_iscsi_initiator { typeset targets typeset i typeset is_init_online setup_chk "iscsi-initiator" (( g_source_release == 8 || g_source_release == 9 )) && return # Check if iscsi initiator service is online is_init_online=$(svcs -H svc:/network/iscsi/initiator:default \ 2> /dev/null | awk '{ print $1 }') if [[ $is_init_online == "online" ]]; then [[ ! -f /usr/sbin/iscsiadm ]] && return targets=$(iscsiadm list target | grep '^Target:' | awk '{ print $2 }') for i in $targets ; do warn_item $i done fi } # # Warn if iscsi server # function warn_iscsi_target { typeset targets typeset i typeset is_tgt_online setup_chk "iscsi-target" (( g_source_release == 8 || g_source_release == 9 )) && return # Get the iscsi target service status if (( g_source_release == 10 )) ; then is_tgt_online=$(svcs -H svc:/system/iscsitgt:default \ 2> /dev/null | awk '{ print $1 }') else is_tgt_online=$(svcs -H svc:/network/iscsi/target:default \ 2> /dev/null | awk '{ print $1 }') fi # Check if the service is online if [[ $is_tgt_online == "online" ]] ; then if (( g_source_release == 10 )) ; then [[ ! -f /usr/sbin/iscsitadm ]] && return targets=$(iscsitadm list target 2>/dev/null | grep 'iSCSI Name:' | awk '{ print $2 }') else [[ ! -f /usr/sbin/itadm ]] && return targets=$(itadm list-target 2>/dev/null | tail +2 | awk '{ print $1 }') fi for i in $targets ; do warn_item $i done fi } # # warn fcoe client or server # function warn_fcoe { typeset type typeset mac typeset wwn # must be on of "fcoe-initiator" or "fcoe-target" setup_chk $1 if [[ $1 == "fcoe-initiator" ]] ; then type="Initiator" else type="Target" fi (( g_source_release < 11 )) && return [[ ! -f /usr/sbin/fcadm ]] && return fcadm list-fcoe-ports 2>/dev/null | nawk -v m=$type ' { if ( $1 == "HBA" && $2 == "Port" ) { name=$4; getline; t=$3; getline; mac=$3; if ( t == m ) { print "MAC=" mac "|WWN=" name; } } }' | while IFS='|' read mac wwn ; do warn_item $mac $wwn done } # # Warn for npiv in use # function warn_npiv { typeset phys typeset virt setup_chk "npiv" (( g_source_release < 11 )) && return [[ ! -f usr/sbin/fcinfo ]] && return fcinfo hba-port 2>/dev/null | nawk ' { if ( $1 == "HBA" && $2 == "Port" ) { phys=$4; npiv=0; } else if ( $1 == "NPIV" && $2 == "Port" ) { npiv=1; } else if ( $1 == "Port" && npiv == 1 ) { print "Physical=" phys "|Virtual=" $3; } }' | while IFS='|' read phys virt ; do print PHYS $phys warn_item $phys $virt done } # # Warn for fc target configured # function warn_fc_target { typeset list typeset i setup_chk "fc-target" (( g_source_release < 11 )) && return [[ ! -f /usr/sbin/fcinfo ]] && return list=$(fcinfo hba-port -t 2>/dev/null | nawk ' { if ( $1 == "HBA" && $2 == "Port" ) { print $4 } }') for i in $list ; do warn_item $i done } function warn_fc_initiator { typeset wwn setup_chk "fc-initiator" (( g_source_release < 10 )) && return [[ ! -f /usr/sbin/fcinfo ]] && return fcinfo hba-port -i 2>/dev/null | nawk ' { if ( $1 == "HBA" && $2 == "Port" ) { wwn=$4; } if ( $1 == "State:" && $2 == "online") { print wwn; } }' | while read wwn ; do warn_item $wwn done } function warn_comstar { typeset list typeset i (( g_source_release < 11 )) && return setup_chk "scsi" [[ ! -f /usr/sbin/sbdadm ]] && return list=$(sbdadm list-lu | grep '^[0-9]' | awk '{ print $3 }') for i in $list ; do warn_item $i done } # Check if a particular service is enabled. If a colon exists in the # name, then we check only that specific service instance. If no # colon exists, check all instances of that service. function check_svc { typeset svc=$1 typeset service typeset svc_state if [[ $svc != *:* ]]; then svc="$svc:*" fi svcs -Ho fmri,state "$svc" 2>/dev/null | while read service svc_state; do [ "$svc_state" == "disabled" ] && continue warn_item "$service" done } function warn_svcs { typeset SVCS typeset i # svcs that can't work at all if (( g_source_release == 8 || g_source_release == 9 )); then # Not yet supporting s8/s9 return elif (( g_source_release == 10 )); then SVCS="\ ldoms/ldmd\ system/virtualbox/vboxservice\ application/virtualbox/zoneaccess\ network/ipmievd \ network/iscsi/initiator \ network/nfs/server \ system/iscsitgt\ system/pools\ system/pools/dynamic\ " else SVCS="\ ldoms/ldmd\ system/virtualbox/vboxservice\ application/virtualbox/zoneaccess\ network/ipmievd \ network/iscsi/target \ network/smb/server\ network/tnd\ system/iscsi/target\ system/labeld\ system/pools\ system/pools/dynamic\ system/stmf\ system/wusbd " # Remove when s10c can be an nfs server if (( g_source_release == 10 && g_target_release == 11 )) ; then SVCS="$SVCS\ network/nfs/server " fi fi setup_chk "svcnotallowed" for i in $SVCS do check_svc $i done } function warn_svcs_priv { typeset SVCS_NTP typeset SVCS_DHCP typeset SVCS_EXLCUSIVE typeset svc typeset priv # ntp requires extra privileges SVCS_NTP="\ network/ntp \ network/ntp4" # dhcp requires extra privileges SVCS_DHCP="\ network/dhcp-server" # svcs that require an exclusive-ip zone SVCS_EXCLUSIVE="\ network/ipfilter \ network/ipsec/ike \ network/ipsec/ipsecalgs \ network/ipsec/manual-key \ network/ipsec/policy \ network/ipv4-forwarding \ network/ipv6-forwarding \ network/rarp \ network/routing/bgp \ network/routing/legacy-routing \ network/routing/ndp \ network/routing/ospf \ network/routing/ospf6 \ network/routing/rdisc \ network/routing/rip \ network/routing/ripng \ network/routing/route \ network/routing-setup \ network/routing/zebra " # Future: check services on s8/s9 with ps? (( g_source_release == 8 || g_source_release == 9 )) && return setup_chk "ntp-client" for svc in $SVCS_NTP ; do check_svc $svc done # svcs that require an exclusive IP stack if (( g_target_release < 11 )) ; then setup_chk "dhcp-server" for svc in $SVCS_DHCP ; do check_svc $svc done setup_chk "svcexclip" for svc in $SVCS_EXCLUSIVE do check_svc $svc done fi } # # Look for packages which we know can't be used in a zone. # function warn_pkgs { typeset PKGS="\ VRTSvxvm\ " typeset i setup_chk "pkg" for i in $PKGS do [[ -d /var/sadm/pkg/$i ]] && warn_item "$i" done (( g_source_release == 8 || g_source_release == 9 )) && return } function warn_zones { typeset zoneid typeset zonename typeset zonestate typeset dummy setup_chk "zones" (( g_source_release < 10 )) && return [[ ! -f /usr/sbin/zoneadm ]] && return zoneadm list -p | grep -v '^0:global:' | while IFS=: read zoneid zonename zonestate dummy ; do warn_item "$zonename" "$zonestate" done } function warn_etcsystem { typeset line setup_chk "etcsystem" nawk -v targ="$g_target_release" ' BEGIN { FS="[ \t=]*" code["exclude:"]="noalternate" code["include:"]="noalternate" code["forceload:"]="noalternate" code["rootdev:"]="noalternate" code["rootfs:"]="noalternate" code["moddir:"]="noalternate" code["rlim_fd_cur"] = "alternate" code["rlim_fd_max"] = "alternate" code["semsys:seminfo_semmsl"] = "alternate" code["semsys:seminfo_semopm"] = "alternate" code["semsys:seminfo_semmni"] = "alternate" code["semsys:seminfo_semmns"] = "obsolete" code["semsys:seminfo_semmnu"] = "obsolete" code["semsys:seminfo_semume"] = "obsolete" code["semsys:seminfo_semvmx"] = "obsolete" code["semsys:seminfo_semaem"] = "obsolete" code["shmsys:shminfo_shmmin"] = "obsolete" code["shmsys:shminfo_shmseg"] = "obsolete" code["msgsys:msginfo_msgmax"] = "obsolete" code["symsys:shminfo_shmmni"] = "alternate" code["symsys:shminfo_shmmni"] = "alternate" code["symsys:shminfo_shmmax"] = "alternate" code["msgsys:msginfo_msgmnb"] = "alternate" code["msgsys:msginfo_msgtql"] = "alternate" code["msgsys:msginfo_msgmni"] = "alternate" if (targ == 10) { code["c2audit:audit_load"] = "noalternate" } else if (targ >= 11) { code["c2audit:audit_load"] = "replaced" type["c2audit:audit_load"] = "utility" tune["c2audit:audit_load"] = "auditconfig(1m)" } type["rlim_fd_cur"] = "rctl" type["rlim_fd_max"] = "rctl" type["semsys:seminfo_semmsl"] = "rctl" type["semsys:seminfo_semopm"] = "rctl" type["semsys:seminfo_semmni"] = "rctl" type["symsys:shminfo_shmmni"] = "rctl" type["symsys:shminfo_shmmni"] = "rctl" type["symsys:shminfo_shmmax"] = "rctl" type["msgsys:msginfo_msgmnb"] = "rctl" type["msgsys:msginfo_msgtql"] = "rctl" type["msgsys:msginfo_msgmni"] = "rctl" tune["rlim_fd_cur"] = "process.max-file-descriptor" tune["rlim_fd_max"] = "process.max-file-descriptor" tune["semsys:seminfo_semmsl"] = "process.max-sem-nsems" tune["semsys:seminfo_semopm"] = "process.max-sem-ops" tune["semsys:seminfo_semmni"] = "project.max-sem-ids" tune["shmsys:shminfo_shmmni"] = "project.max-shm-ids" tune["shmsys:shminfo_shmmni"] = "project.max-shm-memory" tune["shmsys:shminfo_shmmax"] = "project.max-shm-memory" tune["msgsys:msginfo_msgmnb"] = "process.max-msg-qbytes" tune["msgsys:msginfo_msgtql"] = "process.max-msg-messages" tune["msgsys:msginfo_msgmni"] = "project.max-msg-ids" } { if (substr($1, 0, 1) == "*" || length($1) == 0) next if (substr($1, 0, 1) == "#" || length($1) == 0) next print $0 cmd=$1 if ( cmd == "set" ) { cmd=$2 } if (cmd in code) { outcode=code[cmd]; } else { outcode="noinfo" } if (cmd in type) { outtype=type[cmd]; } else { outtype="" } if (cmd in tune) { outtune=tune[cmd]; } else { outtune="" } print outcode, outtype, outtune }' /etc/system | \ while read line do typeset tunecode="" typeset tunetype="" typeset tunedescription="" read tunecode tunetype tunedescription if (( opt_parse_mode == 0 )) ; then case $tunecode in "noinfo") tunecode="$w_tune_noinfo";; "obsolete") tunecode="$w_tune_obsolete";; "replaced") tunecode="$w_tune_replaced";; "alternate") tunecode="$w_tune_alternate";; "noalternate") tunecode="$w_tune_noalternate";; esac fi warn_item "$line" "$tunecode" "$tunetype" "$tunedescription" # add a line return for tunables with alternates. (( opt_parse_mode == 0 )) && [[ -n $tunedescription ]] && print done } function warn_unsupported { setup_chk "unsupported" warn_mobile_ip } function warn_svm { setup_chk "svm" [ ! -d /etc/lvm -o ! -f /etc/lvm/mddb.cf ] && return nawk '{ if (substr($1, 0, 1) == "#" || length($1) == 0) next exit 1 }' /etc/lvm/mddb.cf (( $? != 0 )) && warn_item_compact "SVM" } # XXX need any guidance for separate /var configurations ?? function warn_var { true } # Warn about non-root zpools function warn_zpools { typeset zpool typeset rpool typeset grep setup_chk "zpool" (( g_source_release < 10 )) && return [[ ! -f /usr/sbin/zpool ]] && return rpool="$(df -h / | nawk '$NF == "/" { sub("/.*", "", $1); print $1 }')" if [[ -z "$rpool" ]] ; then grep="cat" else grep="grep -v $rpool" fi # Don't warn about root pool if there is one zpool list -H | awk '{ print $1}' | $grep | while read zpool ; do warn_item $zpool done } function warn_resource_pools { typeset pool setup_chk "resourcepool" [[ ! -f /usr/sbin/pooladm ]] && return pooladm 2>/dev/null | nawk ' { if ( $1 == "pool" && $2 != "pool_default" ) { print $2 } }' | while read pool ; do warn_item $pool done } # Warn about processor sets. function warn_psets { typeset cpus typeset d1 typeset d2 typeset d3 typeset d4 setup_chk "pset" (( g_source_release < 10 )) && return [[ ! -f /usr/sbin/psrset ]] && return psrset | while read d1 d2 d3 id d4 cpus ; do [[ -z $cpus ]] && cpus="none" warn_item ${id%:} $cpus done } # Warn if default scheduler set function warn_sched { typeset sched setup_chk "sched" sched=$(dispadmin -d 2>/dev/null | awk '{ print $1 }') if [[ -n "$sched" ]] ; then warn_item $sched fi } function warn_patches { typeset req_patch typeset patches typeset patch typeset -i found setup_chk "patch" # We only need to check for patches if we're going into a solaris10 # branded zone. if (( g_source_release != 10 || g_target_release != 11 )) ; then return fi # Putting S10 in a solaris10 branded zone requires a minimum patch # level. # # Make sure we have the minimal KU patch we support. These are the # KUs for S10u9. # if [[ $(uname -p) == "i386" ]]; then req_patches="142910-17 119255-75 119535-24 140915-02" else req_patches="142909-17 119254-75 119534-24 140914-02" fi # # Check the core kernel pkg for the required KU patch. # if [[ ! -f /var/sadm/pkg/SUNWcakr/pkginfo ]]; then warn_issue "$w_patch" "$req_patch" return fi patches=$(nawk -F= '{if ($1 == "PATCHLIST") print $2}' \ /var/sadm/pkg/SUNWcakr/pkginfo) for req_patch in $req_patches ; do (( found = 0 )) for patch in $patches ; do if [[ $patch == $req_patch ]] ; then (( found = 1 )) break fi done if (( found == 0 )) ; then warn_issue "$w_patch" "$req_patch" fi done } # Identify ndd tunable settings in the boot scripts. function warn_ndd { typeset file typeset line typeset driver typeset parameter typeset lastskipped="" typeset bootfiles="/etc/rc*.d/S* /lib/svc/method/*" typeset ul_drivers="/dev/arp /dev/ip /dev/ip6 /dev/iptun" ul_drivers="$ul_drivers /dev/tcp /dev/udp /dev/sctp" setup_chk "ndd" # Scan bootfiles for ndd references. # Suppress trailing backslashes which can mess up read command. grep 'ndd -set' $bootfiles 2> /dev/null | \ sed -e 's/\\$//' | \ while IFS=': ' read file line; do # Skip warning for this parameter if the boot file was # not changed since installation. if [[ "$lastskipped" == "$file" ]]; then continue fi if pkg_check $file; then lastskipped="$file" continue fi # Extract driver name and parameter from ndd line set -- $line while [[ -n "$2" && "$1" != "*ndd" && $2 != "-set" ]]; do shift done driver="$3" parameter="$4" # ndd commands for IP and Transport layer drivers are # supported in exclusive-IP zones. Skip the warning # for these drivers when the destination is S11. if (( g_target_release >= 11 )) && \ [[ " $ul_drivers " == *\ $driver\ * ]]; then continue fi warn_item "$file" "$driver" "$parameter" done } function basic_checks { setup_mode "basic" (( opt_parse_mode == 0 )) && printf -- "$basic_header\n" # critical problems warn_etcsystem warn_unsupported warn_be warn_nfs warn_smb warn_pkgs warn_sched warn_iscsi_initiator warn_iscsi_target warn_fcoe "fcoe-initiator" warn_fcoe "fcoe-target" warn_npiv warn_fc_target warn_fc_initiator warn_comstar warn_lofi warn_ramdisk warn_svcs warn_zones # potential configuration issues warn_svcs_priv warn_svm warn_vfstab warn_resource_pools warn_psets warn_zpools warn_patches warn_net (( opt_fast_mode == 0 )) && warn_ndd if (( opt_parse_mode == 0 )) ; then # Add a blank line after last message (( g_check_fired > 0 )) && print printf -- "$basic_footer\n\n" $g_check_fired fi } # # The main body of the script starts here. # trap trap_cleanup 1 2 15 # These global variables are set by command line options typeset -i opt_debug_mode=0 typeset -i opt_version_mode=0 typeset -i opt_parse_mode=0 typeset -i opt_basic_mode=0 typeset -i opt_config_mode=0 typeset -i opt_version_mode=0 typeset -i opt_static_mode=0 typeset -i opt_dynamic_mode=0 typeset -i opt_execnames=0 typeset -i opt_fast_mode=0 typeset -i opt_xml_mode=0 typeset -i opt_recovery_mode=0 # These global variables are set by arguments to command line options typeset -u arg_target_release="" # Arg of -T typeset arg_dynamic_time="" # Arg of -r typeset arg_static_file_in="" # File passed to -S typeset arg_execname_file_in="" # File passed to -E # These global varables are used by the implementation typeset -i g_source_release # Solaris release of source host typeset -i g_target_release # Solaris release of target host typeset g_target_ip_type # exclusive or shared ip target zone typeset g_arch # uname -p typeset -i g_interrupted=0 # Set by SIGINT handler # Globals use by network interface inspection functions typeset g_mac_address # Mac of interface typeset g_mac_addr_type # Mac assignment type typeset g_ip_addr_list # List of ip adresses on interrace typeset g_ip_dynamic # true if ip address assignment is dynamic typeset g_static_file_list # array of files specified by -s typeset g_execname_list # array of execnames specified by -e typeset -i g_static_file_count=0 typeset -i g_execname_count=0 typeset g_hname="" typeset g_dynamic_seconds typeset -i g_check_count=0 # number of checks done for current mode typeset -i g_check_fired=0 # number of checks that fired for current mode typeset -i g_total_fired=0 # number of check fired total typeset -i g_dtrace_pid=0 # pid of dtrace script to kill on SIGINT g_arch=$(uname -p) g_source_release=$(uname -r | nawk -F. '{print $2}') # some locals typeset rels typeset dyn_time typeset dyn_units typeset cmd_opts=":DVT:bchr:xs:S:e:E:Pf" # The /usr/sbin/zonep2vchk can be copied to 5.10 system and needs to run # properly, which means that the zonep2vchk script needs to run on ksh88 # (default ksh in 5.10). The ksh88 and ksh93 are both POSIX compliant, but # not completely compatible. Therefore, ksh93 specific commands/options # should not be used when zonep2vchk is run on 5.10. # # The -A option to typeset command is not supported in ksh88. We use it # only for 5.11 onward. # # -R -X -Z options which utilizes exclude_pools will only be allowed on 5.11 # onward since there is no consumer (ie archiveadm) in 5.10. If -X is used # on something before Solaris 11, it ends up with the generic invalid option # error. if (( g_source_release >= 11 )) ; then typeset -A exclude_pools # additional options for 5.11 used by archiveadm(1M) cmd_opts="${cmd_opts}RXZ:" fi while getopts "$cmd_opts" opt do case "$opt" in V) opt_version_mode=1;; T) arg_target_release="$OPTARG";; b) opt_basic_mode=1;; c) opt_config_mode=1;; D) opt_debug_mode=1;; f) opt_fast_mode=1;; h) print "$m_usage" exit 0;; r) opt_dynamic_mode=1 arg_dynamic_time="$OPTARG" ;; x) opt_dynamic_mode=1 arg_dynamic_time="inf" ;; s) opt_static_mode=1 echo "$OPTARG" | tr ',' '\n' | while read file ; do (( g_static_file_count = \ g_static_file_count + 1 )) g_static_file_list[$g_static_file_count]="$file" done ;; S) opt_static_mode=1 arg_static_file_in="$OPTARG" if [[ -n $arg_static_file_in && ! -r $arg_static_file_in ]] ; then fatal "$e_file_in" "$arg_static_file_in" fi ;; e) opt_execnames=1 echo "$OPTARG" | tr ',' '\n' | while read file ; do (( g_execname_count = \ g_execname_count + 1 )) g_execname_list[$g_execname_count]="$file" done ;; E) opt_execnames=1 arg_execname_file_in="$OPTARG" if [[ -n $arg_execname_file_in && ! -r $arg_execname_file_in ]] ; then fatal "$e_file_in" "$arg_execname_file_in" fi cat "$OPTARG" | while read file ; do (( g_execname_count = \ g_execname_count + 1 )) g_execname_list[$g_execname_count]="$file" done ;; P) opt_parse_mode=1;; # -R, -X, and -Z are for archiveadm(1M)'s private use. R) opt_recovery_mode=1;; X) opt_xml_mode=1 opt_config_mode=1 ;; Z) for pool in ${OPTARG//,/ }; do exclude_pools["$pool"]=1 done ;; :) printf "$e_opt_arg\n" "$OPTARG" >&2 print "$m_usage" >&2 exit 2;; \?) printf "$e_bad_opt\n" "$OPTARG" >&2 print "$m_usage" >&2 exit 2;; *) print "$m_usage" >&2 exit 2;; esac done shift OPTIND-1 if (( opt_version_mode == 1 )) ; then printf "$c_version\n" $VERSION exit 0 fi # -c is exclusive with the other checking options if (( opt_config_mode == 1 )) ; then (( opt_basic_mode == 1 || opt_static_mode == 1 || \ opt_dynamic_mode == 1 )) && \ fatal "$e_incompat_options" "$m_usage" fi if (( g_source_release >= 11 )) ; then # -X, -R, and -Z are for private use by archiveadm(1M). If -R or -Z # is used, -X must also be used. if (( opt_recovery_mode && opt_xml_mode == 0 )); then fatal "$e_bad_opt" R fi if [[ -n "${!exclude_pools[*]}" ]] && (( opt_xml_mode == 0 )); then fatal "$e_incompat_options" "$m_usage" fi fi # Minimum Solaris 10 if (( g_source_release < 10 )) ; then fatal "$e_unsupported" fi # Must be global zone if [[ $(zonename) != "global" ]]; then fatal "$e_nonglobal_zone" fi # Set default target release if not specified with -T if [[ -z $arg_target_release ]] ; then if (( g_source_release == 8 || g_source_release == 9 )); then arg_target_release="S10" g_target_release=10 elif (( g_source_release >= 10 )) ; then arg_target_release="S$g_source_release" g_target_release=$g_source_release fi else if [[ $arg_target_release == "S10" ]] ; then g_target_release=10 elif [[ $arg_target_release == "S11" ]] ; then g_target_release=11 elif [[ $arg_target_release == "S$g_source_release" ]] ; then # For future versions of solaris. They must # be run on themselves, unless we build # additional brands. g_target_release=$g_source_release else rels=$(printf "$e_s10_or_s11") fatal "$e_release" "$arg_target_release" "$rels" fi # Verify target release supports current release if (( g_source_release == 8 || g_source_release == 9 )); then # Solaris 8 and 9 can only be hosted by Solaris 10 if (( g_target_release != 10 )) ; then fatal "$e_release" "$arg_target_release" "S10" fi elif (( g_source_release == 10 )) ; then # Solaris 10 can be run on Solaris 10 or 11 if (( g_target_release != 10 && g_target_release != 11 )) ; then rels=$(printf "$e_s10_or_s11") fatal "$e_release" "$arg_target_release" $rels fi else # Solaris 11 or greater can be run only itself if (( g_target_release != g_source_release )) ; then fatal "$e_release" "$arg_target_release" \ "S$g_source_release" fi fi fi # We assume a shared-IP target zone for Solaris 10 target systems. # Otherwise we assume an exclusive-IP target zone. if (( g_target_release >= 11 )) ; then g_target_ip_type="exclusive" else g_target_ip_type="shared" fi # System must not be running Trusted Extensions. if (( g_source_release >= 10 )) && [[ -x /bin/plabel ]] && /bin/plabel > /dev/null 2>&1; then fatal "$e_trusted_extensions" fi # Validate generic commands we need. [[ ! -x /usr/bin/nawk ]] && fatal "$e_no_cmd" "nawk(1)" # # Must be root # typeset -i euid euid=$(ps -o uid= -p $$) (( euid != 0 )) && fatal "$e_needroot" # # Validate things we need to perform static analysis, which uses elfdump. # if (( opt_static_mode == 1 )) ; then [[ ! -x /usr/bin/elfdump && ! -x /usr/ccs/bin/elfdump ]] && fatal "$e_no_cmd" "elfdump(1)" [[ ! -x /usr/bin/od ]] && fatal "$e_no_cmd" "od(1)" fi # # Validate things we need to perform dynamic analysis, which uses DTrace. # if (( opt_dynamic_mode == 1 )) ; then # DTrace is not available on S8/S9. (( g_source_release == 8 || g_source_release == 9 )) && fatal "$e_nodyn" [[ ! -x /usr/bin/ppriv ]] && fatal "$e_no_cmd" "ppriv(1)" [[ ! -x /usr/sbin/dtrace ]] && fatal "$e_no_cmd" "dtrace(1M)" if [[ $arg_dynamic_time == "inf" ]] ; then dyn_time="0" dyn_units="s" else # validate value and units for the time DTrace should run dyn_time=${arg_dynamic_time%%[hms]} [[ $dyn_time == +([[:digit:]]) ]] || fatal "$e_badtime" "$arg_dynamic_time" dyn_units=${arg_dynamic_time##+([[:digit:]])} [[ $dyn_time == $arg_dynamic_time ]] && fatal "$e_badtime" "$arg_dynamic_time" [[ $dyn_units != "h" && $dyn_units != "m" && $dyn_units != "s" ]] && fatal "$e_badtime" "$arg_dynamic_time" fi fi g_hname=$(hostname) g_hname=${g_hname%%.*} if (( opt_config_mode == 1 )); then pconfig exit 0 fi # # print header # nodename=$(uname -n) if [[ -z $nodename ]] ; then nodename="" fi solaris_version=$(head -1 /etc/release) # strip whitespace solaris_version=$(echo $solaris_version) if [[ -z $solaris_version ]] ; then solaris_version="" fi kernel_version=$(uname -rv) if [[ -z $kernel_version ]] ; then kernel_version="" fi kernel_platform=$(uname -im) if [[ -z $kernel_platform ]] ; then kernel_platform="" fi target_version="Solaris $g_target_release" if (( g_source_release == 10 && g_target_release == 11 )) ; then target_brand="solaris10 $b_s10_container" target_brand_parse="solaris10" elif (( g_source_release == 10 )) ; then target_brand="native $b_default" target_brand_parse="native" else target_brand="solaris $b_default" target_brand_parse="solaris" fi if (( opt_parse_mode == 0 )) ; then # Print human readable header printf -- "$run_header\n" "$VERSION" "$nodename" "$solaris_version" \ "$kernel_version" "$kernel_platform" "$target_version" \ "$target_brand" "$g_target_ip_type" print else print "header:version:$VERSION" print "header:source:$nodename:$solaris_version:$kernel_version:$kernel_platform" print "header:target:$target_version:$target_brand_parse:$g_target_ip_type" fi # If no options, default to basic mode. (( opt_basic_mode == 0 && opt_static_mode == 0 && opt_dynamic_mode == 0 )) && \ opt_basic_mode=1 (( opt_basic_mode == 1 )) && basic_checks # # Perform static binary file checks. # if (( opt_static_mode == 1 )) ; then if (( g_static_file_count > 0 )) ; then set -- "${g_static_file_list[@]}" else set -- fi static_check_files "$arg_static_file_in" $@ fi # # Perform dynamic runtime analysis on the system. # if (( opt_dynamic_mode == 1 )) ; then tmpfile=$(mktemp -t) (( $? == 1 )) && fatal "$e_no_tmpfile" tmpout=$(mktemp -t) (( $? == 1 )) && fatal "$e_no_tmpfile" # convert time to seconds for how long DTrace should run if [[ $dyn_units == "h" ]]; then # hours dyn_time=$(($dyn_time * 3600)) elif [[ $dyn_units == "m" ]] ; then # minutes dyn_time=$(($dyn_time * 60)) else # seconds dyn_time=$dyn_time fi g_dynamic_seconds=$dyn_time gen_dyn_script > $tmpfile setup_mode "dynamic" if (( opt_parse_mode == 0)) ; then if [[ $arg_dynamic_time == "inf" ]] ; then printf -- "$dyn_int_header\n" else printf -- "$dyn_header\n" "$arg_dynamic_time" fi fi # run script chmod +x $tmpfile if (( opt_debug_mode == 1 )); then $tmpfile > $tmpout & g_dtrace_pid=$! else $tmpfile > $tmpout 2>/dev/null & g_dtrace_pid=$! fi wait if (( opt_debug_mode == 1 )); then echo "DTrace script: $tmpfile" else rm -f $tmpfile fi g_dtrace_pid=0 if (( opt_debug_mode == 1 )); then echo "DTraace output: $tmpout" fi typeset category typeset issue typeset prog typeset priv typeset dev setup_chk "privna" grep '^incompatible|privnotallowed|' $tmpout | while IFS='|' read category issue prog priv ; do warn_item "$prog" "$priv" done setup_chk "privex" grep '^configuration|privexclip|' $tmpout | while IFS='|' read category issue prog priv ; do warn_item "$prog" "$priv" done setup_chk "privopt" grep '^configuration|privoptional|' $tmpout | while IFS='|' read category issue prog priv ; do warn_item "$prog" "$priv" done setup_chk "devna" grep '^incompatible|devnotallowed|' $tmpout | while IFS='|' read category issue prog dev ; do warn_item "$prog" "$dev" done setup_chk "devex" grep '^configuration|devexclip|' $tmpout | while IFS='|' read category issue prog dev ; do warn_item "$prog" "$dev" done setup_chk "devopt" grep '^configuration|devoptional|' $tmpout | while IFS='|' read category issue prog dev ; do warn_item "$prog" "$dev" done if (( opt_debug_mode == 0 )); then rm -rf $tmpout fi if (( opt_parse_mode == 0)) ; then # Add a blank line after last message (( g_check_fired > 0 )) && print printf -- "$dyn_footer\n\n" $g_check_fired fi fi # Final tally of issues setup_mode "final" # Print issue totals if ((opt_basic_mode || opt_static_mode || opt_dynamic_mode)) ; then if (( opt_parse_mode == 0 )) ; then printf -- "$total_header\n" $g_total_fired else print "footer:issues:$g_total_fired" fi (( g_total_fired > 0 )) && exit 3 fi exit 0