#!/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