summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/Adm/sun/Makefile29
-rw-r--r--usr/src/cmd/Adm/sun/issue.in14
-rw-r--r--usr/src/cmd/Makefile30
-rw-r--r--usr/src/cmd/Makefile.check4
-rw-r--r--usr/src/cmd/adbgen/common/adbsub.c16
-rw-r--r--usr/src/cmd/auditd/auditd.xml6
-rw-r--r--usr/src/cmd/auditrecord/Makefile8
-rw-r--r--usr/src/cmd/bhyve/Makefile32
-rw-r--r--usr/src/cmd/bhyve/acpi.c8
-rw-r--r--usr/src/cmd/bhyve/bhyverun.c29
-rw-r--r--usr/src/cmd/bhyve/rfb.c7
-rw-r--r--usr/src/cmd/bhyve/test/Makefile.com1
-rw-r--r--usr/src/cmd/bhyve/test/tst/mevent/lists.delete.c2
-rw-r--r--usr/src/cmd/bhyve/test/tst/mevent/testlib.c3
-rw-r--r--usr/src/cmd/bhyve/test/tst/mevent/testlib.h11
-rw-r--r--usr/src/cmd/bhyve/zhyve.c167
-rw-r--r--usr/src/cmd/cmd-crypto/etc/pkcs11.conf2
-rw-r--r--usr/src/cmd/cmd-inet/etc/services702
-rw-r--r--usr/src/cmd/cmd-inet/etc/sock2path.d/system%2Fkernel4
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile4
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c37
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h25
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c76
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_path.c84
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c38
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c36
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c22
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/wpad/Makefile3
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/Makefile3
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/arp.c7
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ndp.c9
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/route.c90
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c32
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile6
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c12
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c13
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c12
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c557
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vxlan.c68
-rw-r--r--usr/src/cmd/column/Makefile34
-rw-r--r--usr/src/cmd/column/THIRDPARTYLICENSE26
-rw-r--r--usr/src/cmd/column/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/cmd/column/column.c329
-rw-r--r--usr/src/cmd/connstat/connstat_tcp.c5
-rw-r--r--usr/src/cmd/coreadm/coreadm.c6
-rw-r--r--usr/src/cmd/coreadm/coreadm.xml8
-rw-r--r--usr/src/cmd/cron/Makefile53
-rw-r--r--usr/src/cmd/cron/cron.c154
-rw-r--r--usr/src/cmd/cron/cron.h4
-rw-r--r--usr/src/cmd/cron/crontab.c40
-rw-r--r--usr/src/cmd/cron/crontab.root18
-rw-r--r--usr/src/cmd/cron/svc-cron42
-rw-r--r--usr/src/cmd/devfsadm/devlink.tab.sh5
-rw-r--r--usr/src/cmd/devfsadm/i386/Makefile3
-rw-r--r--usr/src/cmd/devfsadm/i386/lx_link_i386.c81
-rw-r--r--usr/src/cmd/devfsadm/misc_link.c47
-rw-r--r--usr/src/cmd/dispadmin/Makefile32
-rw-r--r--usr/src/cmd/dispadmin/dispadmin.conf1
-rw-r--r--usr/src/cmd/dladm/Makefile3
-rw-r--r--usr/src/cmd/dladm/dladm.c991
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_db.c122
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_door.c21
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_impl.h17
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_main.c64
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_util.c94
-rw-r--r--usr/src/cmd/dlstat/dlstat.c69
-rw-r--r--usr/src/cmd/dtrace/demo/Makefile10
-rw-r--r--usr/src/cmd/dtrace/test/README9
-rw-r--r--usr/src/cmd/dtrace/test/cmd/jdtrace/Makefile2
-rw-r--r--usr/src/cmd/dtrace/test/cmd/scripts/dtest.pl2
-rw-r--r--usr/src/cmd/dtrace/test/tst/Makefile.com2
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/Makefile8
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/java_api/Makefile2
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/llquantize/tst.range.d4
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/mdb/tst.postmort.ksh69
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.c7
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.ksh68
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/ustack/unpriv_helper.d4
-rw-r--r--usr/src/cmd/dumpadm/Makefile8
-rw-r--r--usr/src/cmd/dumpadm/dconf.c39
-rw-r--r--usr/src/cmd/dumpadm/dconf.h2
-rw-r--r--usr/src/cmd/dumpadm/dumpadm.conf11
-rw-r--r--usr/src/cmd/dumpadm/main.c14
-rw-r--r--usr/src/cmd/dumpadm/svc-dumpadm14
-rw-r--r--usr/src/cmd/flowadm/flowadm.c50
-rw-r--r--usr/src/cmd/flowstat/flowstat.c20
-rw-r--r--usr/src/cmd/fm/fmdump/common/nvlrender.c2
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h31
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c55
-rw-r--r--usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c20
-rw-r--r--usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c1
-rw-r--r--usr/src/cmd/fs.d/Makefile4
-rw-r--r--usr/src/cmd/fs.d/hyprlofs/Makefile42
-rw-r--r--usr/src/cmd/fs.d/hyprlofs/hlcfg/Makefile30
-rw-r--r--usr/src/cmd/fs.d/hyprlofs/hlcfg/hlcfg.c244
-rw-r--r--usr/src/cmd/fs.d/hyprlofs/mount/Makefile31
-rw-r--r--usr/src/cmd/fs.d/hyprlofs/mount/mount.c148
-rw-r--r--usr/src/cmd/fs.d/lxproc/Makefile32
-rw-r--r--usr/src/cmd/fs.d/lxproc/mount.c140
-rw-r--r--usr/src/cmd/fs.d/mount.c11
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/nfs_sec.c8
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/smfcfg.c20
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/smfcfg.h2
-rw-r--r--usr/src/cmd/fs.d/nfs/lockd/lockd.c15
-rw-r--r--usr/src/cmd/fs.d/nfs/mount/Makefile13
-rw-r--r--usr/src/cmd/fs.d/nfs/mount/mount.c2
-rw-r--r--usr/src/cmd/fs.d/nfs/svc/nfs-server4
-rw-r--r--usr/src/cmd/fs.d/nfs/umount/umount.c2
-rw-r--r--usr/src/cmd/halt/halt.c19
-rw-r--r--usr/src/cmd/ibd_upgrade/ibd_delete_link.c2
-rw-r--r--usr/src/cmd/init/init.c63
-rw-r--r--usr/src/cmd/init/init.dfl3
-rw-r--r--usr/src/cmd/initpkg/mountall.sh5
-rw-r--r--usr/src/cmd/initpkg/shutdown.sh2
-rw-r--r--usr/src/cmd/initpkg/umountall.sh4
-rw-r--r--usr/src/cmd/ipf/etc/Makefile27
-rw-r--r--usr/src/cmd/ipf/etc/smartos_version1
-rw-r--r--usr/src/cmd/ipf/lib/common/printfr.c18
-rw-r--r--usr/src/cmd/ipf/svc/ipfilter20
-rw-r--r--usr/src/cmd/ipf/svc/ipfilter.xml7
-rw-r--r--usr/src/cmd/ipf/tools/Makefile.tools23
-rw-r--r--usr/src/cmd/ipf/tools/ipf_y.y17
-rw-r--r--usr/src/cmd/ipf/tools/ipfstat.c4
-rw-r--r--usr/src/cmd/ipf/tools/ipmon_y.y5
-rw-r--r--usr/src/cmd/ipf/tools/ipnat_y.y4
-rw-r--r--usr/src/cmd/ipf/tools/ippool_y.y4
-rw-r--r--usr/src/cmd/ipf/tools/lexer.c37
-rw-r--r--usr/src/cmd/ipf/tools/lexer.h5
-rw-r--r--usr/src/cmd/iscsid/iscsi-initiator20
-rw-r--r--usr/src/cmd/iscsid/iscsi-initiator.xml17
-rw-r--r--usr/src/cmd/ksh/Makefile.com2
-rw-r--r--usr/src/cmd/localedef/Makefile10
-rw-r--r--usr/src/cmd/localedef/UTF-8.x114
-rw-r--r--usr/src/cmd/lofiadm/main.c27
-rw-r--r--usr/src/cmd/logadm/Makefile2
-rw-r--r--usr/src/cmd/logadm/conf.c5
-rw-r--r--usr/src/cmd/logadm/glob.c6
-rw-r--r--usr/src/cmd/logadm/logadm.conf11
-rw-r--r--usr/src/cmd/logadm/main.c24
-rw-r--r--usr/src/cmd/login/login.dfl17
-rw-r--r--usr/src/cmd/machid/Makefile80
-rw-r--r--usr/src/cmd/machid/machid.c137
-rw-r--r--usr/src/cmd/man/Makefile.com23
-rw-r--r--usr/src/cmd/mdb/Makefile.common1
-rw-r--r--usr/src/cmd/mdb/Makefile.module8
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_cmds.c45
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_ctf.c58
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_main.c11
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_modapi.h19
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_print.c98
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_tab.c24
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/Makefile.files1
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/ctxop.c3
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/genunix.c105
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/refhash.c61
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/refhash.h35
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/zone.c46
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/zone.h1
-rw-r--r--usr/src/cmd/mdb/common/modules/ipc/ipc.c5
-rw-r--r--usr/src/cmd/mdb/common/modules/libc/libc.c28
-rw-r--r--usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c67
-rw-r--r--usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c2
-rw-r--r--usr/src/cmd/mdb/common/modules/random/random.c16
-rw-r--r--usr/src/cmd/mdb/common/modules/xhci/xhci.c893
-rw-r--r--usr/src/cmd/mdb/intel/amd64/libpython/Makefile1
-rw-r--r--usr/src/cmd/mdb/intel/amd64/libumem/Makefile1
-rw-r--r--usr/src/cmd/mdb/intel/amd64/xhci/Makefile27
-rw-r--r--usr/src/cmd/mdb/intel/ia32/libumem/Makefile1
-rw-r--r--usr/src/cmd/mdb/intel/ia32/xhci/Makefile25
-rw-r--r--usr/src/cmd/mdb/sparc/v7/libumem/Makefile1
-rw-r--r--usr/src/cmd/mdb/sparc/v9/libumem/Makefile1
-rw-r--r--usr/src/cmd/netfiles/Makefile4
-rw-r--r--usr/src/cmd/netfiles/nsswitch.conf4
-rw-r--r--usr/src/cmd/netfiles/resolv.conf0
-rw-r--r--usr/src/cmd/nicstat/Makefile31
-rw-r--r--usr/src/cmd/nicstat/nicstat.pl424
-rw-r--r--usr/src/cmd/nsadmin/Makefile93
-rwxr-xr-xusr/src/cmd/nsadmin/bash/bash_completion9417
-rw-r--r--usr/src/cmd/nsadmin/bash/bash_completion.d/dladm34
-rw-r--r--usr/src/cmd/nsadmin/bash/bash_completion.d/machines19
-rw-r--r--usr/src/cmd/nsadmin/bash/bash_completion.d/vms62
-rw-r--r--usr/src/cmd/nsadmin/bash/bash_completion.d/zone_alias42
-rw-r--r--usr/src/cmd/nsadmin/bash/bash_completion.d/zones50
-rw-r--r--usr/src/cmd/nsadmin/bashrc.sh5
-rw-r--r--usr/src/cmd/nsadmin/dot-bash_profile.sh12
-rw-r--r--usr/src/cmd/nsadmin/dot-bashrc.sh57
-rw-r--r--usr/src/cmd/nsadmin/dot-profile.sh25
-rw-r--r--usr/src/cmd/nsadmin/etc-profile.sh18
-rw-r--r--usr/src/cmd/nsadmin/etc-skel-bashrc.sh7
-rw-r--r--usr/src/cmd/nsadmin/system55
-rw-r--r--usr/src/cmd/nsadmin/zshrc (renamed from usr/src/cmd/ssh/etc/Makefile)43
-rw-r--r--usr/src/cmd/nscd/Makefile1
-rw-r--r--usr/src/cmd/passwd/Makefile2
-rw-r--r--usr/src/cmd/pgrep/Makefile9
-rw-r--r--usr/src/cmd/pgrep/idtab.c7
-rw-r--r--usr/src/cmd/pgrep/pgrep.c112
-rw-r--r--usr/src/cmd/pgrep/psexp.c14
-rw-r--r--usr/src/cmd/pgrep/psexp.h15
-rw-r--r--usr/src/cmd/prstat/prstat.c40
-rw-r--r--usr/src/cmd/prstat/prstat.h1
-rw-r--r--usr/src/cmd/prtconf/prtconf.c5
-rw-r--r--usr/src/cmd/ps/ps.c201
-rw-r--r--usr/src/cmd/ps/ucbps.c219
-rw-r--r--usr/src/cmd/ptools/Makefile.bld37
-rw-r--r--usr/src/cmd/ptools/common/ptools_common.c50
-rw-r--r--usr/src/cmd/ptools/common/ptools_common.h36
-rw-r--r--usr/src/cmd/ptools/pargs/pargs.c3
-rw-r--r--usr/src/cmd/ptools/pfiles/pfiles.c1
-rw-r--r--usr/src/cmd/ptools/pflags/pflags.c5
-rw-r--r--usr/src/cmd/ptools/pmap/pmap.c10
-rw-r--r--usr/src/cmd/ptools/pmap/pmap_common.c5
-rw-r--r--usr/src/cmd/ptools/preap/preap.c8
-rw-r--r--usr/src/cmd/ptools/psig/psig.c9
-rw-r--r--usr/src/cmd/ptools/ptime/ptime.c7
-rw-r--r--usr/src/cmd/ptools/pwait/pwait.c29
-rw-r--r--usr/src/cmd/ptools/pwdx/pwdx.c7
-rw-r--r--usr/src/cmd/rcap/common/utils.c75
-rw-r--r--usr/src/cmd/rcap/common/utils.h2
-rw-r--r--usr/src/cmd/rcap/rcapadm/rcapadm.c16
-rw-r--r--usr/src/cmd/rcap/rcapd/Makefile4
-rw-r--r--usr/src/cmd/rcap/rcapd/rcapd_collection_zone.c141
-rw-r--r--usr/src/cmd/rcap/rcapd/rcapd_scanner.c3
-rw-r--r--usr/src/cmd/rcap/rcapstat/Makefile12
-rw-r--r--usr/src/cmd/rcap/rcapstat/rcapstat.c7
-rw-r--r--usr/src/cmd/savecore/Makefile.com13
-rw-r--r--usr/src/cmd/savecore/savecore.c172
-rw-r--r--usr/src/cmd/sed/main.c27
-rw-r--r--usr/src/cmd/sendmail/src/Makefile3
-rw-r--r--usr/src/cmd/sgs/elfdump/Makefile.targ2
-rw-r--r--usr/src/cmd/sgs/elfdump/amd64/Makefile2
-rw-r--r--usr/src/cmd/sgs/elfdump/i386/Makefile2
-rw-r--r--usr/src/cmd/sgs/include/conv.h2
-rw-r--r--usr/src/cmd/sgs/lex/common/main.c45
-rw-r--r--usr/src/cmd/sgs/lex/common/once.h12
-rw-r--r--usr/src/cmd/sgs/libconv/common/corenote.c13
-rw-r--r--usr/src/cmd/sgs/libconv/common/corenote.msg5
-rw-r--r--usr/src/cmd/sgs/libconv/common/phdr.c46
-rw-r--r--usr/src/cmd/sgs/libconv/common/phdr.msg30
-rw-r--r--usr/src/cmd/sgs/librtld_db/common/librtld_db.msg6
-rw-r--r--usr/src/cmd/sgs/librtld_db/common/rd_elf.c28
-rw-r--r--usr/src/cmd/sgs/rtld/common/_rtld.h4
-rw-r--r--usr/src/cmd/sgs/rtld/common/analyze.c63
-rw-r--r--usr/src/cmd/sgs/rtld/common/globals.c3
-rw-r--r--usr/src/cmd/sgs/rtld/common/rtld.msg7
-rw-r--r--usr/src/cmd/sgs/rtld/common/setup.c10
-rw-r--r--usr/src/cmd/sgs/rtld/common/util.c16
-rw-r--r--usr/src/cmd/sgs/yacc/common/dextern.h19
-rw-r--r--usr/src/cmd/sgs/yacc/common/y1.c36
-rw-r--r--usr/src/cmd/sgs/yacc/common/y2.c7
-rw-r--r--usr/src/cmd/smbios/Makefile4
-rw-r--r--usr/src/cmd/smbios/smbios.c26
-rw-r--r--usr/src/cmd/ssh/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/cmd/ssh/doc/LICENCE194
-rw-r--r--usr/src/cmd/ssh/etc/ssh.xml177
-rw-r--r--usr/src/cmd/ssh/etc/ssh_config31
-rw-r--r--usr/src/cmd/ssh/etc/sshd127
-rw-r--r--usr/src/cmd/ssh/etc/sshd_config145
-rw-r--r--usr/src/cmd/stat/Makefile11
-rw-r--r--usr/src/cmd/stat/arcstat/Makefile1
-rw-r--r--[-rwxr-xr-x]usr/src/cmd/stat/arcstat/arcstat.pl0
-rw-r--r--usr/src/cmd/stat/vfsstat/Makefile (renamed from usr/src/cmd/ssh/Makefile)37
-rw-r--r--usr/src/cmd/stat/vfsstat/vfsstat.pl227
-rw-r--r--usr/src/cmd/stat/ziostat/Makefile41
-rwxr-xr-xusr/src/cmd/stat/ziostat/ziostat.pl204
-rw-r--r--usr/src/cmd/svc/configd/backend.c20
-rw-r--r--usr/src/cmd/svc/configd/rc_node.c3
-rw-r--r--usr/src/cmd/svc/milestone/Makefile19
-rw-r--r--usr/src/cmd/svc/milestone/console-login40
-rwxr-xr-xusr/src/cmd/svc/milestone/fs-joyent312
-rw-r--r--usr/src/cmd/svc/milestone/fs-root98
-rw-r--r--usr/src/cmd/svc/milestone/fs-usr162
-rw-r--r--usr/src/cmd/svc/milestone/identity-node150
-rw-r--r--usr/src/cmd/svc/milestone/joyent-fs.xml93
-rw-r--r--usr/src/cmd/svc/milestone/make-console-login-xml41
-rw-r--r--usr/src/cmd/svc/milestone/manifest-import31
-rwxr-xr-xusr/src/cmd/svc/milestone/mdata-execute53
-rwxr-xr-xusr/src/cmd/svc/milestone/mdata-fetch477
-rw-r--r--usr/src/cmd/svc/milestone/mdata.xml39
-rw-r--r--usr/src/cmd/svc/milestone/minimal-fs.xml4
-rw-r--r--usr/src/cmd/svc/milestone/net-early-admin237
-rw-r--r--usr/src/cmd/svc/milestone/net-physical1244
-rw-r--r--usr/src/cmd/svc/milestone/net-routing-setup35
-rw-r--r--usr/src/cmd/svc/milestone/network-early-admin.xml73
-rw-r--r--usr/src/cmd/svc/milestone/network-location.xml8
-rw-r--r--usr/src/cmd/svc/milestone/network-physical.xml102
-rw-r--r--usr/src/cmd/svc/milestone/network-routing-setup.xml14
-rw-r--r--usr/src/cmd/svc/milestone/network.xml8
-rw-r--r--usr/src/cmd/svc/milestone/single-user.xml2
-rwxr-xr-xusr/src/cmd/svc/milestone/smartdc-config211
-rw-r--r--usr/src/cmd/svc/milestone/smartdc-config.xml145
-rwxr-xr-xusr/src/cmd/svc/milestone/smartdc-init246
-rw-r--r--usr/src/cmd/svc/milestone/smartdc-init.xml124
-rwxr-xr-xusr/src/cmd/svc/milestone/smartdc-ur79
-rw-r--r--usr/src/cmd/svc/milestone/smartdc-ur.xml62
-rwxr-xr-xusr/src/cmd/svc/milestone/sysidtool-net5
-rwxr-xr-xusr/src/cmd/svc/milestone/sysidtool-system5
-rw-r--r--usr/src/cmd/svc/profile/Makefile6
-rw-r--r--usr/src/cmd/svc/profile/generic.xml397
-rw-r--r--usr/src/cmd/svc/shell/smf_include.sh1
-rw-r--r--usr/src/cmd/svc/startd/graph.c27
-rw-r--r--usr/src/cmd/svc/startd/method.c75
-rw-r--r--usr/src/cmd/svc/startd/startd.h4
-rw-r--r--usr/src/cmd/svc/svcadm/Makefile7
-rw-r--r--usr/src/cmd/svc/svccfg/Makefile1
-rw-r--r--usr/src/cmd/svc/svcs/Makefile2
-rw-r--r--usr/src/cmd/svc/svcs/explain.c4
-rw-r--r--usr/src/cmd/svc/svcs/svcs.c84
-rw-r--r--usr/src/cmd/syslogd/syslog.conf4
-rw-r--r--usr/src/cmd/syslogd/system-log102
-rw-r--r--usr/src/cmd/tail/Makefile5
-rw-r--r--usr/src/cmd/truss/print.c11
-rw-r--r--usr/src/cmd/truss/systable.c8
-rw-r--r--usr/src/cmd/varpd/Makefile75
-rw-r--r--usr/src/cmd/varpd/varpd.c526
-rw-r--r--usr/src/cmd/varpd/varpd.xml67
-rw-r--r--usr/src/cmd/vi/port/Makefile3
-rw-r--r--usr/src/cmd/vi/port/ex_cmdsub.c2
-rw-r--r--usr/src/cmd/vndadm/Makefile67
-rw-r--r--usr/src/cmd/vndadm/test/Makefile19
-rw-r--r--usr/src/cmd/vndadm/test/Makefile.com43
-rw-r--r--usr/src/cmd/vndadm/test/Makefile.subdirs29
-rw-r--r--usr/src/cmd/vndadm/test/Makefile.targ59
-rw-r--r--usr/src/cmd/vndadm/test/scripts/Makefile28
-rwxr-xr-xusr/src/cmd/vndadm/test/scripts/vndtest.ksh298
-rw-r--r--usr/src/cmd/vndadm/test/tst/Makefile18
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/Makefile34
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/cmd.common.ksh33
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh30
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh.out2
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/create.sdev.ksh25
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/create.setbuf.ksh34
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/ecreate.destroy.ksh25
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadprop.ksh24
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadvalue.ksh24
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbuftoobig.ksh24
-rw-r--r--usr/src/cmd/vndadm/test/tst/cmd/ecreate.setrdonlyprop.ksh24
-rw-r--r--usr/src/cmd/vndadm/test/tst/dld/Makefile27
-rw-r--r--usr/src/cmd/vndadm/test/tst/dld/create.reuse.ksh31
-rw-r--r--usr/src/cmd/vndadm/test/tst/dld/dld.common.ksh29
-rw-r--r--usr/src/cmd/vndadm/test/tst/dld/ecreate.ipfirst.ksh27
-rw-r--r--usr/src/cmd/vndadm/test/tst/dld/ecreate.vndfirst.ksh27
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/Makefile49
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.attach.c63
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.attachnolink.c67
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.badlinkname.c119
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.doublelink.c82
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.gioctlattach.c69
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.link.c76
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.linkexists.c90
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.ngioctlfault.c96
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv1.c69
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv2.c69
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv3.c70
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv4.c75
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv5.c77
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.olink.c77
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.olinknopriv.c83
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/create.rmenolink.c69
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.attachrdonly.c63
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.badioctl.c79
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.basicopenctl.c76
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlfault.c78
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlnattach.c100
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.iocsize.ksh54
-rw-r--r--usr/src/cmd/vndadm/test/tst/ioctl/tst.openctlbadflags.c88
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/Makefile44
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.badlink.c39
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.badpropid.c76
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.badpropsize.c63
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.badzone.c43
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.basic.c49
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.enomem.c91
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.frameioeagain.c80
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.open.c56
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.propiter.c79
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/create.proprdonly.c63
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/err.badclose.c33
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/tst.badopen.c49
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/tst.strerror.c30
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/tst.strerror.exe.out37
-rw-r--r--usr/src/cmd/vndadm/test/tst/lib/tst.strsyserror.c50
-rw-r--r--usr/src/cmd/vndadm/vndadm.c872
-rw-r--r--usr/src/cmd/vndstat/Makefile33
-rw-r--r--usr/src/cmd/vndstat/vndstat.c542
-rw-r--r--usr/src/cmd/zfs/zfs_main.c262
-rw-r--r--usr/src/cmd/zlogin/zlogin.c594
-rw-r--r--usr/src/cmd/zoneadm/Makefile11
-rw-r--r--usr/src/cmd/zoneadm/svc-resource-mgmt14
-rw-r--r--usr/src/cmd/zoneadm/svc-zones139
-rw-r--r--usr/src/cmd/zoneadm/zfs.c16
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c490
-rw-r--r--usr/src/cmd/zoneadm/zones.xml23
-rw-r--r--usr/src/cmd/zoneadmd/Makefile44
-rw-r--r--usr/src/cmd/zoneadmd/Makefile.com72
-rw-r--r--usr/src/cmd/zoneadmd/amd64/Makefile31
-rw-r--r--usr/src/cmd/zoneadmd/i386/Makefile30
-rw-r--r--usr/src/cmd/zoneadmd/log.c1027
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c704
-rw-r--r--usr/src/cmd/zoneadmd/zcons.c186
-rw-r--r--usr/src/cmd/zoneadmd/zfd.c1237
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.c979
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.h44
-rw-r--r--usr/src/cmd/zonecfg/Makefile4
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.c918
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.h17
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_grammar.y91
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_lex.l31
-rw-r--r--usr/src/cmd/zonename/Makefile10
-rw-r--r--usr/src/cmd/zonestat/zonestatd/zonestatd.c11
-rw-r--r--usr/src/cmd/zpool/zpool_main.c3
412 files changed, 34607 insertions, 4415 deletions
diff --git a/usr/src/cmd/Adm/sun/Makefile b/usr/src/cmd/Adm/sun/Makefile
index 9c280f54ec..636dc875e6 100644
--- a/usr/src/cmd/Adm/sun/Makefile
+++ b/usr/src/cmd/Adm/sun/Makefile
@@ -21,9 +21,11 @@
#
# Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2019 Joyent, Inc.
#
-ETCFILES= ioctl.syscon passwd shadow motd
+ETCGENFILES=motd issue
+ETCFILES= ioctl.syscon passwd shadow $(ETCGENFILES)
FTPDFILES= ftpusers
KVMFILES= README
SMBFILES= smbpasswd
@@ -45,35 +47,28 @@ $(ROOTVARSMB)/smbpasswd := FILEMODE = 0400
.KEEP_STATE:
-$(ROOTETCFTPUSERSLINK): $(ROOTETCFTPDFILES)
- $(RM) $@; $(SYMLINK) ftpd/ftpusers $@
-
all: $(ETCFILES) $(KVMFILES) $(SMBFILES) $(FTPDFILES)
install: all $(ROOTETCFILES) $(ROOTETCFTPDFILES) $(ROOTUSRKVMFILES) $(ROOTVARSMBFILES) $(ROOTETCFTPUSERSLINK)
clean:
- $(RM) $(ROOTETCFTPUSERSLINK)
+ $(RM) $(ROOTETCFTPUSERSLINK) $(ETCGENFILES) $(SMBFILES)
-lint:
+clobber: clean
-clobber:
+$(ROOTETCFTPUSERSLINK): $(ROOTETCFTPDFILES)
+ $(RM) $@; $(SYMLINK) ftpd/ftpusers $@
-motd: FRC
+motd: $(ROOT)/buildstamp
@-$(ECHO) "rebuilding motd"
- @$(RELEASE_BUILD)-$(ECHO) "The illumos Project\t$(VERSION)\t$(RELEASE_DATE)" > motd
- @$(NOT_RELEASE_BUILD)-$(ECHO) "The illumos Project\t$(VERSION)\t`date +'%h. %d, %Y'`" > motd
+ @$(ECHO) "SmartOS (build: $$(cat $(ROOT)/buildstamp))" >$@
+
+issue: issue.in $(ROOT)/buildstamp
+ sed "s+build: 00000000T000000Z+$$(cat $(ROOT)/buildstamp)+" issue.in >$@
@$(NOT_RELEASE_BUILD)-$(ECHO) $(DEV_CM) | sed -e "s/@(#)//" >> motd
@-$(CAT) release_info >> motd
smbpasswd:
$(TOUCH) smbpasswd
-clean:
-
-lint:
-
-clobber:
- $(RM) motd smbpasswd
-
FRC:
diff --git a/usr/src/cmd/Adm/sun/issue.in b/usr/src/cmd/Adm/sun/issue.in
new file mode 100644
index 0000000000..d9957b7a0d
--- /dev/null
+++ b/usr/src/cmd/Adm/sun/issue.in
@@ -0,0 +1,14 @@
+
+
+ *--+--*--*
+ |\ |\ |\ |\ J O Y E N T
+ | \| \| \| \ ##### #### # ##### ### # # TM
+ +--*--+--*--* # # # # # # # ## #
+ |\ |\ |\ |\ | # #### # # # # # # #
+ | \| \| \| \| # # # # # # # # ##
+ *--+--+--+--+ # # # # # ### # #
+ \ |\ |\ |\ |
+ \| \| \| \| SmartOS
+ *--+--*--* build: 00000000T000000Z
+
+
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index fd13f07290..6d6276c70d 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -34,8 +34,8 @@
include ../Makefile.master
#
-# Note that the commands 'lp', and 'perl' are first in
-# the list, violating alphabetical order. This is because they are very
+# Note that if the 'lp' command were built, it would be first in
+# the list, violating alphabetical order. This is because it is very
# long-running and should be given the most wall-clock time for a
# parallel build.
#
@@ -56,7 +56,6 @@ FIRST_SUBDIRS= \
COMMON_SUBDIRS= \
allocate \
availdevs \
- lp \
perl \
Adm \
abi \
@@ -98,6 +97,7 @@ COMMON_SUBDIRS= \
cmd-crypto \
cmd-inet \
col \
+ column \
compress \
connstat \
consadm \
@@ -198,7 +198,6 @@ COMMON_SUBDIRS= \
growfs \
grpck \
gss \
- hal \
halt \
head \
hostid \
@@ -235,7 +234,6 @@ COMMON_SUBDIRS= \
kvmstat \
last \
lastcomm \
- latencytop \
ldap \
ldapcachemgr \
lgrpinfo \
@@ -258,6 +256,7 @@ COMMON_SUBDIRS= \
ls \
luxadm \
mach \
+ machid \
mail \
mailwrapper \
mailx \
@@ -292,6 +291,7 @@ COMMON_SUBDIRS= \
news \
newtask \
nice \
+ nicstat \
nl \
nlsadmin \
nohup \
@@ -317,7 +317,6 @@ COMMON_SUBDIRS= \
picl \
plimit \
policykit \
- pools \
power \
powertop \
ppgsz \
@@ -325,7 +324,6 @@ COMMON_SUBDIRS= \
plockstat \
pr \
prctl \
- print \
printf \
priocntl \
profiles \
@@ -343,7 +341,6 @@ COMMON_SUBDIRS= \
pwck \
pwconv \
pwd \
- pyzfs \
raidctl \
raidz_test \
ramdiskadm \
@@ -395,7 +392,6 @@ COMMON_SUBDIRS= \
srchtxt \
srptadm \
srptsvc \
- ssh \
stat \
stmfadm \
stmfproxy \
@@ -447,8 +443,11 @@ COMMON_SUBDIRS= \
utmpd \
uuidgen \
valtools \
+ varpd \
vgrind \
vi \
+ vndadm \
+ vndstat \
volcheck \
volrmmount \
vrrpadm \
@@ -518,11 +517,14 @@ sparc_SUBDIRS= \
vntsd
#
-# Commands that are messaged. Note that 'lp' comes first
-# (see previous comment about 'lp'.)
+# Commands that are messaged. Note that 'lp' comes first (see previous comment
+# about 'lp'.)
+#
+# We purposefully leave out auditrecord's messages from illumos-joyent: it
+# attempts to use Perl modules constructed as part of the build alongside the
+# native Perl.
#
MSGSUBDIRS= \
- lp \
abi \
acctadm \
allocate \
@@ -531,7 +533,6 @@ MSGSUBDIRS= \
audit \
auditconfig \
auditd \
- auditrecord \
auditset \
auths \
autopush \
@@ -659,11 +660,9 @@ MSGSUBDIRS= \
pg \
pgrep \
picl \
- pools \
power \
pr \
praudit \
- print \
profiles \
projadd \
projects \
@@ -674,7 +673,6 @@ MSGSUBDIRS= \
ptools \
pwconv \
pwd \
- pyzfs \
raidctl \
ramdiskadm \
rcap \
diff --git a/usr/src/cmd/Makefile.check b/usr/src/cmd/Makefile.check
index 91507c9ad9..ac1ff29c88 100644
--- a/usr/src/cmd/Makefile.check
+++ b/usr/src/cmd/Makefile.check
@@ -118,16 +118,12 @@ MANIFEST_SUBDIRS= \
krb5/krb5kdc \
krb5/kwarn \
krb5/slave \
- lp/cmd/lpsched \
picl/picld \
pools/poold \
- print/bsd-sysv-commands \
- print/ppdmgr \
rcap/rcapd \
rpcsvc/rpc.bootparamd \
sendmail/lib \
smbsrv/smbd \
- ssh/etc \
svc/milestone \
tsol/labeld \
tsol/tnctl \
diff --git a/usr/src/cmd/adbgen/common/adbsub.c b/usr/src/cmd/adbgen/common/adbsub.c
index d9b7a37273..773a215ae8 100644
--- a/usr/src/cmd/adbgen/common/adbsub.c
+++ b/usr/src/cmd/adbgen/common/adbsub.c
@@ -19,7 +19,6 @@
*
* CDDL HEADER END
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 1983-1998 by Sun Microsystems, Inc.
@@ -27,6 +26,10 @@
*/
/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
* Subroutines to be called by adbgen2.c, the C program generated
* by adbgen1.c.
*/
@@ -155,9 +158,8 @@ do_fmt(char *acp)
case 'S':
case 'i':
if (warnings) {
- fprintf(stderr,
- "Unknown format size \"%s\", assuming zero\n",
- acp);
+ fprintf(stderr, "Unknown format size \"%s\", "
+ "assuming zero\n", acp);
warns++;
}
width = 0;
@@ -167,7 +169,7 @@ do_fmt(char *acp)
exit(1);
}
for (i = 0; i < rcount; i++) {
- putchar(*cp);
+ (void) putchar(*cp);
}
cp++;
sum += width * rcount;
@@ -186,8 +188,8 @@ format(char *name, size_t size, char *fmt)
fs = do_fmt(fmt);
if (fs != size && warnings) {
fprintf(stderr,
- "warning: \"%s\" size is %ld, \"%s\" width is %d\n",
- name, size, fmt, fs);
+ "warning: \"%s\" size is %ld, \"%s\" width is %d\n",
+ name, size, fmt, fs);
warns++;
}
last_off += fs;
diff --git a/usr/src/cmd/auditd/auditd.xml b/usr/src/cmd/auditd/auditd.xml
index 88632647f5..ac0600c9e1 100644
--- a/usr/src/cmd/auditd/auditd.xml
+++ b/usr/src/cmd/auditd/auditd.xml
@@ -142,7 +142,7 @@
-->
<property_group name='preselection' type='application'>
<propval name='flags' type='astring'
- value='lo' />
+ value='lo,ex' />
<propval name='naflags' type='astring'
value='lo' />
<propval name='read_authorization' type='astring'
@@ -188,7 +188,7 @@
<propval name='arge' type='boolean'
value='false' />
<propval name='argv' type='boolean'
- value='false' />
+ value='true' />
<propval name='cnt' type='boolean'
value='true' />
<propval name='group' type='boolean'
@@ -196,7 +196,7 @@
<propval name='path' type='boolean'
value='false' />
<propval name='perzone' type='boolean'
- value='false' />
+ value='true' />
<propval name='public' type='boolean'
value='false' />
<propval name='seq' type='boolean'
diff --git a/usr/src/cmd/auditrecord/Makefile b/usr/src/cmd/auditrecord/Makefile
index 4f4670dfc9..fdf5213b3f 100644
--- a/usr/src/cmd/auditrecord/Makefile
+++ b/usr/src/cmd/auditrecord/Makefile
@@ -22,13 +22,15 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2018, Joyent, Inc.
+#
include $(SRC)/cmd/Makefile.cmd
ATTR = audit_record_attr
ROOTAUDITDIR = $(ROOT)/usr/lib/audit
-SECURITYFILES = $(ATTR:%=$(ROOTAUDITDIR)/%)
+SECURITYFILES = $(ATTR:%=$(ROOTAUDITDIR)/%)
$(SECURITYFILES) := FILEMODE = $(LIBFILEMODE)
PROG = auditrecord
@@ -41,7 +43,7 @@ ADTXMLFILE = $(LIBBSMDIR)/common/adt.xml
.KEEP_STATE:
-all: $(PROG) $(ATTR)
+all: $(PROG) $(ATTR)
install: all $(ROOTUSRSBINPROG) install_data
@@ -59,7 +61,7 @@ clean:
$(RM) $(ATTR) $(STRIPTEXT) $(AGETTEXT)
$(ATTR): $(STRIPTEXT) $(ATTRPROC) $(ADTXMLFILE) $(ATTR).txt
- ./$(STRIPTEXT) < $(ATTR).txt > $(ATTR)
+ $(PERL) ./$(STRIPTEXT) < $(ATTR).txt > $(ATTR)
$(PERL) -I $(LIBBSMDIR) ./$(ATTRPROC) $(ADTXMLFILE) >> $(ATTR)
$(ROOTUSRSBINPROG): $(PROG)
diff --git a/usr/src/cmd/bhyve/Makefile b/usr/src/cmd/bhyve/Makefile
index 7126fdda17..4dc737c768 100644
--- a/usr/src/cmd/bhyve/Makefile
+++ b/usr/src/cmd/bhyve/Makefile
@@ -11,7 +11,7 @@
#
# Copyright 2014 Pluribus Networks Inc.
-# Copyright 2019 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
# Copyright 2020 Oxide Computer Company
#
@@ -103,13 +103,17 @@ SRCS = acpi.c \
OBJS = $(SRCS:.c=.o)
-CLOBBERFILES = $(ROOTUSRSBINPROG)
+CLOBBERFILES = $(ROOTUSRSBINPROG) $(ZHYVE)
+
+ZHYVE_DIR = $(ROOT)/usr/lib/brand/bhyve
+ZHYVE_PROG = zhyve
+ZHYVE = $(ZHYVE_DIR)/$(ZHYVE_PROG)
MEVENT_TEST_PROG = mevent_test
MEVENT_TEST_SRCS = mevent.c mevent_test.c
MEVENT_TEST_OBJS = $(MEVENT_TEST_SRCS:.c=.o)
-CLEANFILES = $(PROG) $(MEVENT_TEST_PROG) $(MEVENT_TEST_OBJS)
+CLEANFILES = $(PROG) $(ZHYVE_PROG) $(MEVENT_TEST_PROG) $(MEVENT_TEST_OBJS)
CFLAGS += $(CCVERBOSE) -_gcc=-Wimplicit-function-declaration -_gcc=-Wno-parentheses
CPPFLAGS = -I$(COMPAT)/bhyve -I$(CONTRIB)/bhyve \
@@ -118,14 +122,13 @@ CPPFLAGS = -I$(COMPAT)/bhyve -I$(CONTRIB)/bhyve \
-I$(CONTRIB)/bhyve/dev/mii \
-I$(SRC)/uts/common/io/e1000api \
$(CPPFLAGS.master) \
+ -I$(ROOT)/usr/platform/i86pc/include \
-I$(SRC)/uts/i86pc/io/vmm \
-I$(SRC)/uts/common \
-I$(SRC)/uts/i86pc \
+ -I$(SRC)/lib/libdladm/common \
-DWITHOUT_CAPSICUM
-# Disable the crypto code until it is wired up
-CPPFLAGS += -DNO_OPENSSL
-
pci_nvme.o := CERRWARN += -_gcc=-Wno-pointer-sign
pci_nvme.o := SMOFF += kmalloc_wrong_size
@@ -135,12 +138,14 @@ SMOFF += all_func_returns,leaks,no_if_block
CSTD= $(CSTD_GNU99)
C99MODE= -xc99=%all
-$(PROG) := LDLIBS += -lsocket -lnsl -ldlpi -ldladm -lmd -luuid -lvmmapi -lz
+$(PROG) := LDLIBS += -lsocket -lnsl -ldlpi -ldladm -lmd -lsunw_crypto -luuid \
+ -lvmmapi -lz
+$(ZHYVE_PROG) := LDLIBS += -lnvpair
$(MEVENT_TEST_PROG) := LDLIBS += -lsocket
.KEEP_STATE:
-all: $(PROG) $(MEVENT_TEST_PROG) $(SUBDIRS)
+all: $(PROG) $(MEVENT_TEST_PROG) $(ZHYVE_PROG) $(SUBDIRS)
$(PROG): $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
@@ -149,7 +154,7 @@ $(PROG): $(OBJS)
$(MEVENT_TEST_PROG): $(MEVENT_TEST_OBJS)
$(LINK.c) -o $@ $(MEVENT_TEST_OBJS) $(LDFLAGS) $(LDLIBS)
-install: all $(ROOTUSRSBINPROG) $(SUBDIRS)
+install: all $(ZHYVE) $(ROOTUSRSBINPROG) $(SUBDIRS)
clean: $(SUBDIRS)
$(RM) $(OBJS) $(CLEANFILES)
@@ -161,3 +166,12 @@ $(SUBDIRS): FRC
@cd $@; pwd; $(MAKE) $(TARGET)
FRC:
+
+include ../Makefile.targ
+
+$(ZHYVE_DIR)/%: %
+ $(INS.file)
+
+%.o: $(SRC)/uts/i86pc/io/vmm/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/cmd/bhyve/acpi.c b/usr/src/cmd/bhyve/acpi.c
index 76ddf5f5f6..580bb900dd 100644
--- a/usr/src/cmd/bhyve/acpi.c
+++ b/usr/src/cmd/bhyve/acpi.c
@@ -272,15 +272,7 @@ basl_fwrite_madt(FILE *fp)
EFPRINTF(fp, "[0001]\t\tLocal Apic ID : %02x\n", i);
EFPRINTF(fp, "[0004]\t\tFlags (decoded below) : 00000001\n");
EFPRINTF(fp, "\t\t\tProcessor Enabled : 1\n");
-#ifdef __FreeBSD__
EFPRINTF(fp, "\t\t\tRuntime Online Capable : 0\n");
-#else
- /*
- * Until iasl is updated to support the "Runtime Online
- * Capable" entry, it must be omitted. This should be
- * re-checked when illumos receives an acpica update.
- */
-#endif /* __FreeBSD__ */
EFPRINTF(fp, "\n");
}
diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c
index 8b7166ce5e..c4ebef1b31 100644
--- a/usr/src/cmd/bhyve/bhyverun.c
+++ b/usr/src/cmd/bhyve/bhyverun.c
@@ -85,6 +85,10 @@ __FBSDID("$FreeBSD$");
#endif
#include <vmmapi.h>
+#ifndef __FreeBSD__
+#include <sys/stat.h>
+#endif
+
#include "bhyverun.h"
#include "acpi.h"
#include "atkbdc.h"
@@ -1222,6 +1226,28 @@ do_open(const char *vmname)
return (ctx);
}
+#ifndef __FreeBSD__
+
+#define FILE_PROVISIONING "/var/svc/provisioning"
+#define FILE_PROVISION_SUCCESS "/var/svc/provision_success"
+
+static void
+mark_provisioned(void)
+{
+ struct stat stbuf;
+
+ if (lstat(FILE_PROVISIONING, &stbuf) != 0)
+ return;
+
+ if (rename(FILE_PROVISIONING, FILE_PROVISION_SUCCESS) != 0) {
+ (void) fprintf(stderr, "Cannot rename %s to %s: %s\n",
+ FILE_PROVISIONING, FILE_PROVISION_SUCCESS,
+ strerror(errno));
+ }
+}
+
+#endif
+
int
main(int argc, char *argv[])
{
@@ -1525,7 +1551,10 @@ main(int argc, char *argv[])
fbsdrun_addcpu(ctx, BSP, BSP, rip);
#else
fbsdrun_addcpu(ctx, BSP, BSP, rip, suspend);
+
+ mark_provisioned();
#endif
+
/*
* Head off to the main event dispatch loop
*/
diff --git a/usr/src/cmd/bhyve/rfb.c b/usr/src/cmd/bhyve/rfb.c
index a3d80197a8..624c7dc665 100644
--- a/usr/src/cmd/bhyve/rfb.c
+++ b/usr/src/cmd/bhyve/rfb.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
* Copyright (c) 2015 Leon Dang
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -807,7 +807,7 @@ rfb_handle(struct rfb_softc *rc, int cfd)
* The client then sends the resulting 16-bytes response.
*/
#ifndef NO_OPENSSL
- strncpy(keystr, rc->password, PASSWD_LENGTH);
+ strncpy((char *)keystr, rc->password, PASSWD_LENGTH);
/* VNC clients encrypts the challenge with all the bit fields
* in each byte of the password mirrored.
@@ -842,7 +842,8 @@ rfb_handle(struct rfb_softc *rc, int cfd)
&ks, DES_ENCRYPT);
if (memcmp(crypt_expected, buf, AUTH_LENGTH) != 0) {
- message = "Auth Failed: Invalid Password.";
+ message =
+ (unsigned char *)"Auth Failed: Invalid Password.";
sres = htonl(1);
} else
sres = 0;
diff --git a/usr/src/cmd/bhyve/test/Makefile.com b/usr/src/cmd/bhyve/test/Makefile.com
index a2e5bce08f..aeba956e12 100644
--- a/usr/src/cmd/bhyve/test/Makefile.com
+++ b/usr/src/cmd/bhyve/test/Makefile.com
@@ -32,6 +32,7 @@ CPPFLAGS = -I$(SRC)/cmd/bhyve \
-I$(CONTRIB)/bhyve/dev/usb/controller \
-I$(CONTRIB)/bhyve/dev/mii \
$(CPPFLAGS.master) \
+ -I$(ROOT)/usr/platform/i86pc/include \
-I$(SRC)/uts/i86pc/io/vmm \
-I$(SRC)/uts/common \
-I$(SRC)/uts/i86pc \
diff --git a/usr/src/cmd/bhyve/test/tst/mevent/lists.delete.c b/usr/src/cmd/bhyve/test/tst/mevent/lists.delete.c
index c5ed91a790..d09ac133a3 100644
--- a/usr/src/cmd/bhyve/test/tst/mevent/lists.delete.c
+++ b/usr/src/cmd/bhyve/test/tst/mevent/lists.delete.c
@@ -163,7 +163,7 @@ main(int argc, const char *argv[])
*/
flush_and_wait(flush_pipe[1]);
count2 = get_count();
- if (count1 - 1 != count2) {
+ if (count1 - 1 != count2 ) {
FAIL(("mevent_delete() did not decrease count by 1: "
"was %d, now %d", count1, count2));
}
diff --git a/usr/src/cmd/bhyve/test/tst/mevent/testlib.c b/usr/src/cmd/bhyve/test/tst/mevent/testlib.c
index 67261b9a31..af756d1509 100644
--- a/usr/src/cmd/bhyve/test/tst/mevent/testlib.c
+++ b/usr/src/cmd/bhyve/test/tst/mevent/testlib.c
@@ -25,8 +25,7 @@ const char *testlib_prog;
boolean_t testlib_verbose;
static void
-timed_out(int signo)
-{
+timed_out(int signo) {
ASSERT_INT_EQ(("timeout signal"), signo, SIGALRM);
FAIL(("Timed out"));
diff --git a/usr/src/cmd/bhyve/test/tst/mevent/testlib.h b/usr/src/cmd/bhyve/test/tst/mevent/testlib.h
index 7e5ca2e9c9..80949f3cc7 100644
--- a/usr/src/cmd/bhyve/test/tst/mevent/testlib.h
+++ b/usr/src/cmd/bhyve/test/tst/mevent/testlib.h
@@ -13,9 +13,6 @@
* Copyright 2018 Joyent, Inc.
*/
-#ifndef _TESTLIB_H_
-#define _TESTLIB_H_
-
#include <assert.h>
#include <errno.h>
#include <signal.h>
@@ -31,7 +28,7 @@
#define EXIT_PASS 0
#define EXIT_FAIL 1
-#define VERBOSE(msg) \
+#define VERBOSE(msg) \
if (testlib_verbose) { \
(void) printf("VERBOSE %s: %s:%d %s: ", testlib_prog, \
__FILE__, __LINE__, __func__); \
@@ -39,7 +36,7 @@
(void) printf("\n"); \
}
-#define FAIL_PROLOGUE() \
+#define FAIL_PROLOGUE() \
(void) printf("FAIL %s: %s:%d: ", testlib_prog, __FILE__, __LINE__)
#define FAIL(msg) \
@@ -50,7 +47,7 @@
exit(EXIT_FAIL); \
}
-#define FAIL_ERRNO(msg) FAIL((msg ": %s", strerror(errno)))
+#define FAIL_ERRNO(msg) FAIL((msg ": %s", strerror(errno)))
#define PASS() \
{ \
@@ -89,5 +86,3 @@ extern boolean_t testlib_verbose;
extern void start_test(const char *, uint32_t);
extern void start_event_thread(void);
extern void test_mevent_count_lists(int *, int *, int *);
-
-#endif /* _TESTLIB_H_ */
diff --git a/usr/src/cmd/bhyve/zhyve.c b/usr/src/cmd/bhyve/zhyve.c
new file mode 100644
index 0000000000..d3e764b14d
--- /dev/null
+++ b/usr/src/cmd/bhyve/zhyve.c
@@ -0,0 +1,167 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+/*
+ * This small 'zhyve' stub is init for the zone: we therefore need to pick up
+ * our command-line arguments placed in ZHYVE_CMD_FILE by the boot stub, do a
+ * little administration, and exec the real bhyve binary.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/corectl.h>
+
+#define ZHYVE_CMD_FILE "/var/run/bhyve/zhyve.cmd"
+
+/*
+ * Do a read of the specified size or return an error. Returns 0 on success
+ * and -1 on error. Sets errno to EINVAL if EOF is encountered. For other
+ * errors, see read(2).
+ */
+static int
+full_read(int fd, char *buf, size_t len)
+{
+ ssize_t nread = 0;
+ size_t totread = 0;
+
+ while (totread < len) {
+ nread = read(fd, buf + totread, len - totread);
+ if (nread == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (nread < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ return (-1);
+ }
+ totread += nread;
+ }
+ assert(totread == len);
+
+ return (0);
+}
+
+/*
+ * Reads the command line options from the packed nvlist in the file referenced
+ * by path. On success, 0 is returned and the members of *argv reference memory
+ * allocated from an nvlist. On failure, -1 is returned.
+ */
+
+static int
+parse_options_file(const char *path, uint_t *argcp, char ***argvp)
+{
+ int fd = -1;
+ struct stat stbuf;
+ char *buf = NULL;
+ nvlist_t *nvl = NULL;
+ int ret;
+
+ if ((fd = open(path, O_RDONLY)) < 0 ||
+ fstat(fd, &stbuf) != 0 ||
+ (buf = malloc(stbuf.st_size)) == NULL ||
+ full_read(fd, buf, stbuf.st_size) != 0 ||
+ nvlist_unpack(buf, stbuf.st_size, &nvl, 0) != 0 ||
+ nvlist_lookup_string_array(nvl, "bhyve_args", argvp, argcp) != 0) {
+ nvlist_free(nvl);
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+
+ free(buf);
+ (void) close(fd);
+
+ (void) printf("Configuration from %s:\n", path);
+ nvlist_print(stdout, nvl);
+
+ return (ret);
+}
+
+/*
+ * Setup to suppress core dumps within the zone.
+ */
+static void
+config_core_dumps()
+{
+ (void) core_set_options(0x0);
+}
+
+int
+main(int argc, char **argv)
+{
+ char **tmpargs;
+ uint_t zargc;
+ char **zargv;
+ int fd;
+
+ config_core_dumps();
+
+ fd = open("/dev/null", O_WRONLY);
+ assert(fd >= 0);
+ if (fd != STDIN_FILENO) {
+ (void) dup2(fd, STDIN_FILENO);
+ (void) close(fd);
+ }
+
+ fd = open("/dev/zfd/1", O_WRONLY);
+ assert(fd >= 0);
+ if (fd != STDOUT_FILENO) {
+ (void) dup2(fd, STDOUT_FILENO);
+ (void) close(fd);
+ }
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ fd = open("/dev/zfd/2", O_WRONLY);
+ assert(fd >= 0);
+ if (fd != STDERR_FILENO) {
+ (void) dup2(fd, STDERR_FILENO);
+ (void) close(fd);
+ }
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ if (parse_options_file(ZHYVE_CMD_FILE, &zargc, &zargv) != 0) {
+ (void) fprintf(stderr, "%s: failed to parse %s: %s\n",
+ argv[0], ZHYVE_CMD_FILE, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+
+ /*
+ * Annoyingly, we need a NULL at the end.
+ */
+
+ if ((tmpargs = malloc(sizeof (*zargv) * (zargc + 1))) == NULL) {
+ perror("malloc failed");
+ return (EXIT_FAILURE);
+ }
+
+ memcpy(tmpargs, zargv, sizeof (*zargv) * zargc);
+ tmpargs[zargc] = NULL;
+
+ (void) execv("/usr/sbin/bhyve", tmpargs);
+
+ perror("execv failed");
+ return (EXIT_FAILURE);
+}
diff --git a/usr/src/cmd/cmd-crypto/etc/pkcs11.conf b/usr/src/cmd/cmd-crypto/etc/pkcs11.conf
index 2b8971a85e..835e61f777 100644
--- a/usr/src/cmd/cmd-crypto/etc/pkcs11.conf
+++ b/usr/src/cmd/cmd-crypto/etc/pkcs11.conf
@@ -20,6 +20,7 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2011 Joyent, Inc. All rights reserved.
#
# /etc/crypto/pkcs11.conf
#
@@ -39,5 +40,4 @@
metaslot:metaslot_status=enabled;metaslot_auto_key_migrate=enabled;metaslot_token=Sun Software PKCS#11 softtoken;metaslot_slot=Sun Crypto Softtoken
/usr/lib/security/$ISA/pkcs11_kernel.so
/usr/lib/security/$ISA/pkcs11_softtoken.so
-/usr/lib/security/$ISA/pkcs11_tpm.so
# End SUNWcsr
diff --git a/usr/src/cmd/cmd-inet/etc/services b/usr/src/cmd/cmd-inet/etc/services
index 37514ac0a7..1029745480 100644
--- a/usr/src/cmd/cmd-inet/etc/services
+++ b/usr/src/cmd/cmd-inet/etc/services
@@ -1,6 +1,6 @@
-#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2019 Joyent, Inc.
#
# CDDL HEADER START
#
@@ -22,9 +22,18 @@
# CDDL HEADER END
#
# Network services, Internet style
-# Look at http://www.iana.org/assignments/port-numbers for more
#
-tcpmux 1/tcp
+# Note that it is presently the policy of IANA to assign a single well-known
+# port number for both TCP and UDP; hence, officially ports have two entries
+# even if the protocol doesn't support UDP operations.
+#
+# Updated from http://www.iana.org/assignments/port-numbers and other
+# sources like http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services .
+# New ports will be added on request if they have been officially assigned
+# by IANA and used in the real-world or are needed by a debian package.
+# If you need a huge list of used numbers please install the nmap package.
+
+tcpmux 1/tcp # TCP port service multiplexer
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
@@ -33,207 +42,614 @@ systat 11/tcp users
daytime 13/tcp
daytime 13/udp
netstat 15/tcp
-qotd 17/tcp # Quote of the Day
+qotd 17/tcp quote
+msp 18/tcp # message send protocol
+msp 18/udp
chargen 19/tcp ttytst source
chargen 19/udp ttytst source
ftp-data 20/tcp
ftp 21/tcp
ftp 21/sctp
-ssh 22/tcp # Secure Shell
+fsp 21/udp fspd
+ssh 22/tcp # SSH Remote Login Protocol
ssh 22/sctp
+ssh 22/udp
telnet 23/tcp
smtp 25/tcp mail
time 37/tcp timserver
time 37/udp timserver
rlp 39/tcp # Resource Location Protocol
-rlp 39/udp # Resource Location Protocol
-name 42/udp nameserver
-whois 43/tcp nicname # usually to sri-nic
-tacacs 49/tcp
+rlp 39/udp resource # resource location
+nameserver 42/tcp name # IEN 116
+nameserver 42/udp name
+whois 43/tcp nicname
+tacacs 49/tcp # Login Host Protocol (TACACS)
tacacs 49/udp
+re-mail-ck 50/tcp # Remote Mail Checking Protocol
+re-mail-ck 50/udp
+domain 53/tcp # name-domain server
domain 53/udp
-domain 53/tcp
-tacacs-ds 65/tcp
+mtp 57/tcp # deprecated
+tacacs-ds 65/tcp # TACACS-Database Service
tacacs-ds 65/udp
-bootps 67/udp # BOOTP/DHCP server
-bootpc 68/udp # BOOTP/DHCP client
-http 80/tcp www www-http
-http 80/udp www www-http
-http 80/sctp
-kerberos 88/udp kdc # Kerberos V5 KDC
-kerberos 88/tcp kdc # Kerberos V5 KDC
-hostnames 101/tcp hostname # usually to sri-nic
-pop2 109/tcp pop-2 # Post Office Protocol - V2
-pop3 110/tcp # Post Office Protocol - Version 3
-sunrpc 111/udp rpcbind
-sunrpc 111/tcp rpcbind
+bootps 67/tcp # BOOTP server
+bootps 67/udp
+bootpc 68/tcp # BOOTP client
+bootpc 68/udp
+tftp 69/udp
+gopher 70/tcp # Internet Gopher
+gopher 70/udp
+rje 77/tcp netrjs
+finger 79/tcp
+www 80/tcp http # WorldWideWeb HTTP
+www 80/sctp http
+www 80/udp # HyperText Transfer Protocol
+link 87/tcp ttylink
+kerberos 88/tcp kerberos5 krb5 kerberos-sec # Kerberos v5
+kerberos 88/udp kerberos5 krb5 kerberos-sec # Kerberos v5
+supdup 95/tcp
+hostnames 101/tcp hostname # usually from sri-nic
+iso-tsap 102/tcp tsap # part of ISODE
+x400 103/tcp # ISO Mail
+acr-nema 104/tcp dicom # Digital Imag. & Comm. 300
+acr-nema 104/udp dicom # Digital Imag. & Comm. 300
+csnet-ns 105/tcp cso-ns # also used by CSO name server
+csnet-ns 105/udp cso-ns
+rtelnet 107/tcp # Remote Telnet
+rtelnet 107/udp
+pop2 109/tcp postoffice pop-2 # POP version 2
+pop2 109/udp pop-2
+pop3 110/tcp pop-3 # POP version 3
+pop3 110/udp pop-3
+sunrpc 111/tcp portmapper # RPC 4.0 portmapper
+sunrpc 111/udp portmapper
+auth 113/tcp authentication tap ident
sftp 115/tcp
-imap 143/tcp imap2 # Internet Mail Access Protocol v2
+uucp-path 117/tcp
+nntp 119/tcp readnews untp # USENET News Transfer Protocol
+ntp 123/tcp
+ntp 123/udp # Network Time Protocol
+pwdgen 129/tcp # PWDGEN service
+pwdgen 129/udp # PWDGEN service
+loc-srv 135/tcp epmap # Location Service
+loc-srv 135/udp epmap
+netbios-ns 137/tcp # NETBIOS Name Service
+netbios-ns 137/udp
+netbios-dgm 138/tcp # NETBIOS Datagram Service
+netbios-dgm 138/udp
+netbios-ssn 139/tcp # NETBIOS session service
+netbios-ssn 139/udp
+imap2 143/tcp imap # Interim Mail Access P 2 and 4
+imap2 143/udp imap
+snmp 161/tcp # Simple Net Mgmt Protocol
+snmp 161/udp # Simple Net Mgmt Protocol
+snmp-trap 162/tcp snmptrap # Traps for SNMP
+snmp-trap 162/udp snmptrap # Traps for SNMP
+cmip-man 163/tcp # ISO mgmt over IP (CMOT)
+cmip-man 163/udp
+cmip-agent 164/tcp
+cmip-agent 164/udp
+mailq 174/tcp # Mailer transport queue for Zmailer
+mailq 174/udp # Mailer transport queue for Zmailer
+xdmcp 177/tcp # X Display Mgr. Control Proto
+xdmcp 177/udp
+nextstep 178/tcp NeXTStep NextStep # NeXTStep window
+nextstep 178/udp NeXTStep NextStep # server
bgp 179/tcp # Border Gateway Protocol
-bgp 179/udp
bgp 179/sctp
-irc 194/tcp
+bgp 179/udp
+prospero 191/tcp # Cliff Neuman's Prospero
+prospero 191/udp
+irc 194/tcp # Internet Relay Chat
irc 194/udp
-smux 199/tcp
+smux 199/tcp # SNMP Unix Multiplexer
smux 199/udp
-imap3 220/tcp
-imap3 220/udp
-clearcase 371/tcp
-clearcase 371/udp
-ldap 389/tcp # Lightweight Directory Access Protocol
-ldap 389/udp # Lightweight Directory Access Protocol
-https 443/tcp
+at-rtmp 201/tcp # AppleTalk routing
+at-rtmp 201/udp
+at-nbp 202/tcp # AppleTalk name binding
+at-nbp 202/udp
+at-echo 204/tcp # AppleTalk echo
+at-echo 204/udp
+at-zis 206/tcp # AppleTalk zone information
+at-zis 206/udp
+qmtp 209/tcp # Quick Mail Transfer Protocol
+qmtp 209/udp # Quick Mail Transfer Protocol
+z3950 210/tcp wais # NISO Z39.50 database
+z3950 210/udp wais
+ipx 213/tcp # IPX
+ipx 213/udp
+imap3 220/tcp # Interactive Mail Access
+imap3 220/udp # Protocol v3
+pawserv 345/tcp # Perf Analysis Workbench
+pawserv 345/udp
+zserv 346/tcp # Zebra server
+zserv 346/udp
+fatserv 347/tcp # Fatmen Server
+fatserv 347/udp
+rpc2portmap 369/tcp
+rpc2portmap 369/udp # Coda portmapper
+codaauth2 370/tcp
+codaauth2 370/udp # Coda authentication server
+clearcase 371/tcp Clearcase
+clearcase 371/udp Clearcase
+ulistserv 372/tcp # UNIX Listserv
+ulistserv 372/udp
+ldap 389/tcp # Lightweight Directory Access Protocol
+ldap 389/udp
+imsp 406/tcp # Interactive Mail Support Protocol
+imsp 406/udp
+slp 427/tcp slp # Service Location Protocol, V2
+slp 427/udp slp # Service Location Protocol, V2
+mobile-ip 434/udp mobile-ip # Mobile-IP
+cvc_hostd 442/tcp # Network Console
+https 443/tcp # http protocol over TLS/SSL
https 443/udp
https 443/sctp
+snpp 444/tcp # Simple Network Paging Protocol
+snpp 444/udp
+microsoft-ds 445/tcp # Microsoft Naked CIFS
+microsoft-ds 445/udp
kpasswd 464/tcp
kpasswd 464/udp
+saft 487/tcp # Simple Asynchronous File Transfer
+saft 487/udp
+isakmp 500/tcp # IPsec - Internet Security Association
+isakmp 500/udp # and Key Management Protocol
dhcpv6-client 546/udp dhcpv6c # DHCPv6 Client (RFC 3315)
dhcpv6-client 546/tcp
dhcpv6-server 547/udp dhcpv6s # DHCPv6 Server (RFC 3315)
dhcpv6-server 547/tcp
-rtsp 554/tcp
-rtsp 554/udp
-nntps 563/tcp snntp
-nntps 563/udp snntp
-submission 587/tcp # Mail Message Submission
-submission 587/udp # see RFC 2476
-ipp 631/tcp
+rtsp 554/tcp # Real Time Stream Control Protocol
+rtsp 554/udp # Real Time Stream Control Protocol
+nqs 607/tcp # Network Queuing system
+nqs 607/udp
+npmp-local 610/tcp dqs313_qmaster # npmp-local / DQS
+npmp-local 610/udp dqs313_qmaster
+npmp-gui 611/tcp dqs313_execd # npmp-gui / DQS
+npmp-gui 611/udp dqs313_execd
+hmmp-ind 612/tcp dqs313_intercell # HMMP Indication / DQS
+hmmp-ind 612/udp dqs313_intercell
+qmqp 628/tcp
+qmqp 628/udp
+ipp 631/tcp # Internet Printing Protocol
ipp 631/udp
-ldaps 636/tcp # LDAP protocol over TLS/SSL (was sldap)
-ldaps 636/udp # LDAP protocol over TLS/SSL (was sldap)
-silc 706/tcp
-silc 706/udp
-iscsi 860/tcp
-iscsi 860/udp
-rsync 873/tcp
-rsync 873/udp
-ftps-data 989/tcp
-ftps-data 989/udp
-ftps 990/tcp
-ftps 990/udp
-imaps 993/tcp
-imaps 993/udp
-pop3s 995/tcp
-pop3s 995/udp
-socks 1080/tcp
-socks 1080/udp
-openvpn 1194/tcp
-openvpn 1194/udp
-icap 1344/tcp # Internet Content Adaptation Protocol
-wins 1512/tcp
-wins 1512/udp
-radius 1812/tcp
-radius 1812/udp
-radius-acct 1813/tcp
-radius-acct 1813/udp
-cvspserver 2401/tcp
-icpv2 3130/tcp
-icpv2 3130/udp
-iscsi-target 3260/tcp
-iscsi-target 3260/udp
-mysql 3306/tcp
-mysql 3306/udp
-nut 3493/tcp # Network UPS Tools
-svn 3690/tcp
-svn 3690/udp
-epmd 4369/tcp # Erlang Port Mapper Daemon
-epmd 4369/udp
-sip 5060/tcp
-sip 5060/udp
-sip-tls 5061/tcp
-sip-tls 5061/udp
-xmpp-client 5222/tcp
-xmpp-server 5269/tcp
-postgresql 5432/tcp postgres
-postgresql 5432/udp postgres
-http-alt 8080/tcp webcache # HTTP Alternate, webcache
-http-alt 8080/udp
-memcache 11211/tcp
-memcache 11211/udp
-#
-# Host specific functions
-#
-tftp 69/udp
-rje 77/tcp
-finger 79/tcp
-link 87/tcp ttylink
-supdup 95/tcp
-iso-tsap 102/tcp
-x400 103/tcp # ISO Mail
-x400-snd 104/tcp
-csnet-ns 105/tcp
-uucp-path 117/tcp
-nntp 119/tcp usenet # Network News Transfer
-ntp 123/tcp # Network Time Protocol
-ntp 123/udp # Network Time Protocol
-netbios-ns 137/tcp # NETBIOS Name Service
-netbios-ns 137/udp # NETBIOS Name Service
-netbios-dgm 138/tcp # NETBIOS Datagram Service
-netbios-dgm 138/udp # NETBIOS Datagram Service
-netbios-ssn 139/tcp # NETBIOS Session Service
-netbios-ssn 139/udp # NETBIOS Session Service
-NeWS 144/tcp news # Window System
-snmpd 161/udp snmp # Net-SNMP snmp daemon
-slp 427/tcp slp # Service Location Protocol, V2
-slp 427/udp slp # Service Location Protocol, V2
-mobile-ip 434/udp mobile-ip # Mobile-IP
-cvc_hostd 442/tcp # Network Console
-microsoft-ds 445/tcp # Microsoft Directory Services
-microsoft-ds 445/udp # Microsoft Directory Services
-ike 500/udp ike # Internet Key Exchange
uuidgen 697/tcp # UUID Generator
uuidgen 697/udp # UUID Generator
#
# UNIX specific services
#
-# these are NOT officially assigned
-#
rdc 121/tcp # SNDR server daemon
exec 512/tcp
-login 513/tcp
-shell 514/tcp cmd # no passwords used
-printer 515/tcp spooler # line printer spooler
-courier 530/tcp rpc # experimental
-uucp 540/tcp uucpd # uucp daemon
biff 512/udp comsat
+login 513/tcp
who 513/udp whod
+shell 514/tcp cmd # no passwords used
syslog 514/udp
+printer 515/tcp spooler # line printer spooler
talk 517/udp
-route 520/udp router routed
+ntalk 518/udp
+route 520/udp router routed # RIP
ripng 521/udp
-klogin 543/tcp # Kerberos authenticated rlogin
-kshell 544/tcp cmd # Kerberos authenticated remote shell
+timed 525/udp timeserver
+tempo 526/tcp newdate
+courier 530/tcp rpc
+conference 531/tcp chat
+netnews 532/tcp readnews
+netwall 533/udp # for emergency broadcasts
+gdomap 538/tcp # GNUstep distributed objects
+gdomap 538/udp
+uucp 540/tcp uucpd # uucp daemon
+klogin 543/tcp # Kerberized `rlogin' (v5)
+kshell 544/tcp krcmd # Kerberized `rsh' (v5)
+afpovertcp 548/tcp # AFP over TCP
+afpovertcp 548/udp
new-rwho 550/udp new-who # experimental
+remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem
rmonitor 560/udp rmonitord # experimental
monitor 561/udp # experimental
+nntps 563/tcp snntp # NNTP over SSL
+nntps 563/udp snntp
+submission 587/tcp # Submission [RFC4409]
+submission 587/udp
pcserver 600/tcp # ECD Integrated PC board srvr
+ldaps 636/tcp # LDAP over SSL
+ldaps 636/udp
+tinc 655/tcp # tinc control port
+tinc 655/udp
sun-dr 665/tcp # Remote Dynamic Reconfiguration
-kerberos-adm 749/tcp # Kerberos V5 Administration
+silc 706/tcp
+silc 706/udp
+kerberos-adm 749/tcp # Kerberos `kadmin' (v5)
kerberos-adm 749/udp # Kerberos V5 Administration
kerberos-iv 750/udp # Kerberos V4 key server
krb5_prop 754/tcp # Kerberos V5 KDC propogation
-swat 901/tcp # Samba Web Adm.Tool
+#
+webster 765/tcp # Network dictionary
+webster 765/udp
+iscsi 860/tcp
+iscsi 860/udp
+rsync 873/tcp
+rsync 873/udp
+ftps-data 989/tcp # FTP over SSL (data)
+ftps 990/tcp
+telnets 992/tcp # Telnet over SSL
+telnets 992/udp
+imaps 993/tcp # IMAP over SSL
+imaps 993/udp
+ircs 994/tcp # IRC over SSL
+ircs 994/udp
+pop3s 995/tcp # POP-3 over SSL
+pop3s 995/udp
ufsd 1008/tcp ufsd # UFS-aware server
ufsd 1008/udp ufsd
+portolan 1296/tcp # Portolan
+svp-underlay 1339/tcp # SDC VXLAN underlay invalidation
cvc 1495/tcp # Network Console
+#
+# From ``Assigned Numbers'':
+#
+#> The Registered Ports are not controlled by the IANA and on most systems
+#> can be used by ordinary user processes or programs executed by ordinary
+#> users.
+#
+#> Ports are used in the TCP [45,106] to name the ends of logical
+#> connections which carry long term conversations. For the purpose of
+#> providing services to unknown callers, a service contact port is
+#> defined. This list specifies the port used by the server process as its
+#> contact port. While the IANA can not control uses of these ports it
+#> does register or list uses of these ports as a convienence to the
+#> community.
+#
+socks 1080/tcp # socks proxy server
+socks 1080/udp
+proofd 1093/tcp
+proofd 1093/udp
+rootd 1094/tcp
+rootd 1094/udp
+openvpn 1194/tcp
+openvpn 1194/udp
+rmiregistry 1099/tcp # Java RMI Registry
+rmiregistry 1099/udp
+kazaa 1214/tcp
+kazaa 1214/udp
+nessus 1241/tcp # Nessus vulnerability
+nessus 1241/udp # assessment scanner
+icap 1344/tcp # Internet Content Adaptation Protocol
+lotusnote 1352/tcp lotusnotes # Lotus Note
+lotusnote 1352/udp lotusnotes
+ms-sql-s 1433/tcp # Microsoft SQL Server
+ms-sql-s 1433/udp
+ms-sql-m 1434/tcp # Microsoft SQL Monitor
+ms-sql-m 1434/udp
+wins 1512/tcp
+wins 1512/udp
ingreslock 1524/tcp
+ingreslock 1524/udp
+prospero-np 1525/tcp # Prospero non-privileged
+prospero-np 1525/udp
+datametrics 1645/tcp old-radius
+datametrics 1645/udp old-radius
+sa-msg-port 1646/tcp old-radacct
+sa-msg-port 1646/udp old-radacct
+kermit 1649/tcp
+kermit 1649/udp
+l2f 1701/tcp l2tp
+l2f 1701/udp l2tp
www-ldap-gw 1760/tcp # HTTP to LDAP gateway
www-ldap-gw 1760/udp # HTTP to LDAP gateway
-listen 2766/tcp # System V listener port
-nfsd 2049/udp nfs # NFS server daemon (clts)
-nfsd 2049/tcp nfs # NFS server daemon (cots)
+radius 1812/tcp
+radius 1812/udp
+radius-acct 1813/tcp radacct # Radius Accounting
+radius-acct 1813/udp radacct
+msnp 1863/tcp # MSN Messenger
+msnp 1863/udp
+unix-status 1957/tcp # remstats unix-status server
+log-server 1958/tcp # remstats log server
+remoteping 1959/tcp # remstats remoteping server
+cisco-sccp 2000/tcp sieve # Cisco SCCP
+cisco-sccp 2000/udp
+search 2010/tcp ndtp
+pipe_server 2010/tcp
+nfs 2049/tcp # Network File System
+nfs 2049/udp # Network File System
nfsd 2049/sctp nfs
-eklogin 2105/tcp # Kerberos encrypted rlogin
+gnunet 2086/tcp
+gnunet 2086/udp
+rtcm-sc104 2101/tcp # RTCM SC-104 IANA 1/29/99
+rtcm-sc104 2101/udp
+gsigatekeeper 2119/tcp
+gsigatekeeper 2119/udp
+gris 2135/tcp # Grid Resource Information Server
+gris 2135/udp # Grid Resource Information Server
+cvspserver 2401/tcp # CVS client/server operations
+cvspserver 2401/udp
+venus 2430/tcp # codacon port
+venus 2430/udp # Venus callback/wbc interface
+venus-se 2431/tcp # tcp side effects
+venus-se 2431/udp # udp sftp side effect
+codasrv 2432/tcp # not used
+codasrv 2432/udp # server port
+codasrv-se 2433/tcp # tcp side effects
+codasrv-se 2433/udp # udp sftp side effect
+mon 2583/tcp # MON traps
+mon 2583/udp
+dict 2628/tcp # Dictionary server
+dict 2628/udp
+listen 2766/tcp # System V listener port
+gsiftp 2811/tcp
+gsiftp 2811/udp
+gpsd 2947/tcp
+gpsd 2947/udp
+gds_db 3050/tcp # InterBase server
+gds_db 3050/udp
+icpv2 3130/tcp icp # Internet Cache Protocol
+icpv2 3130/udp icp
+iscsi-target 3260/tcp
+iscsi-target 3260/udp
+mysql 3306/tcp
+mysql 3306/udp
+nut 3493/tcp # Network UPS Tools
+nut 3493/udp
+distcc 3632/tcp # distributed compiler
+distcc 3632/udp
+daap 3689/tcp # Digital Audio Access Protocol
+daap 3689/udp
+svn 3690/tcp subversion # Subversion protocol
+svn 3690/udp subversion
+suucp 4031/tcp # UUCP over SSL
+suucp 4031/udp # UUCP over SSL
lockd 4045/udp # NFS lock daemon/manager
lockd 4045/tcp
+sysrqd 4094/tcp # sysrq daemon
+sysrqd 4094/udp # sysrq daemon
+remctl 4373/tcp # Remote Authenticated Command Service
+remctl 4373/udp # Remote Authenticated Command Service
+epmd 4369/tcp # Erlang Port Mapper Daemon
+epmd 4369/udp
ipsec-nat-t 4500/udp # IPsec NAT-Traversal
+iax 4569/tcp # Inter-Asterisk eXchange
+iax 4569/udp
+radmin-port 4899/tcp # RAdmin Port
+radmin-port 4899/udp
+rfe 5002/udp # Radio Free Ethernet
+rfe 5002/tcp
+mmcc 5050/tcp # multimedia conference control tool (Yahoo IM)
+mmcc 5050/udp
+sip 5060/tcp # Session Initiation Protocol
+sip 5060/udp
+sip-tls 5061/tcp
+sip-tls 5061/udp
+aol 5190/tcp # AIM
+aol 5190/udp
+xmpp-client 5222/tcp jabber-client # Jabber Client Connection
+xmpp-client 5222/udp jabber-client
+xmpp-server 5269/tcp jabber-server # Jabber Server Connection
+xmpp-server 5269/udp jabber-server
+cfengine 5308/tcp
+cfengine 5308/udp
+mdns 5353/tcp # Multicast DNS
mdns 5353/udp # Multicast DNS
-mdns 5353/tcp
+postgresql 5432/tcp postgres # PostgreSQL Database
+postgresql 5432/udp postgres
+freeciv 5556/tcp rptp # Freeciv gameplay
+freeciv 5556/udp
+amqp 5672/tcp
+amqp 5672/udp
+amqp 5672/sctp
+ggz 5688/tcp # GGZ Gaming Zone
+ggz 5688/udp # GGZ Gaming Zone
vnc-server 5900/tcp # VNC Server
+x11 6000/tcp x11-0 # X Window System
+x11 6000/udp x11-0
+x11-1 6001/tcp
+x11-1 6001/udp
+x11-2 6002/tcp
+x11-2 6002/udp
+x11-3 6003/tcp
+x11-3 6003/udp
+x11-4 6004/tcp
+x11-4 6004/udp
+x11-5 6005/tcp
+x11-5 6005/udp
+x11-6 6006/tcp
+x11-6 6006/udp
+x11-7 6007/tcp
+x11-7 6007/udp
dtspc 6112/tcp # CDE subprocess control
+gnutella-svc 6346/tcp # gnutella
+gnutella-svc 6346/udp
+gnutella-rtr 6347/tcp # gnutella
+gnutella-rtr 6347/udp
+sge_qmaster 6444/tcp # Grid Engine Qmaster Service
+sge_qmaster 6444/udp # Grid Engine Qmaster Service
+sge_execd 6445/tcp # Grid Engine Execution Service
+sge_execd 6445/udp # Grid Engine Execution Service
servicetag 6481/udp
servicetag 6481/tcp
-fs 7100/tcp # Font server
+afs3-fileserver 7000/tcp bbs # file server itself
+afs3-fileserver 7000/udp bbs
+afs3-callback 7001/tcp # callbacks to cache managers
+afs3-callback 7001/udp
+afs3-prserver 7002/tcp # users & groups database
+afs3-prserver 7002/udp
+afs3-vlserver 7003/tcp # volume location database
+afs3-vlserver 7003/udp
+afs3-kaserver 7004/tcp # AFS/Kerberos authentication
+afs3-kaserver 7004/udp
+afs3-volser 7005/tcp # volume managment server
+afs3-volser 7005/udp
+afs3-errors 7006/tcp # error interpretation service
+afs3-errors 7006/udp
+afs3-bos 7007/tcp # basic overseer process
+afs3-bos 7007/udp
+afs3-update 7008/tcp # server-to-server updater
+afs3-update 7008/udp
+afs3-rmtsys 7009/tcp # remote cache manager service
+afs3-rmtsys 7009/udp
+font-service 7100/tcp xfs # X Font Service
+font-service 7100/udp xfs
+http-alt 8080/tcp webcache # WWW caching service
+http-alt 8080/udp # WWW caching service
+bacula-dir 9101/tcp # Bacula Director
+bacula-dir 9101/udp
+bacula-fd 9102/tcp # Bacula File Daemon
+bacula-fd 9102/udp
+bacula-sd 9103/tcp # Bacula Storage Daemon
+bacula-sd 9103/udp
+xmms2 9667/tcp # Cross-platform Music Multiplexing System
+xmms2 9667/udp # Cross-platform Music Multiplexing System
+amanda 10080/tcp # amanda backup services
+amanda 10080/udp
+memcache 11211/tcp
+memcache 11211/udp
+hkp 11371/tcp # OpenPGP HTTP Keyserver
+hkp 11371/udp # OpenPGP HTTP Keyserver
+bprd 13720/tcp # VERITAS NetBackup
+bprd 13720/udp
+bpdbm 13721/tcp # VERITAS NetBackup
+bpdbm 13721/udp
+bpjava-msvc 13722/tcp # BP Java MSVC Protocol
+bpjava-msvc 13722/udp
+vnetd 13724/tcp # Veritas Network Utility
+vnetd 13724/udp
+bpcd 13782/tcp # VERITAS NetBackup
+bpcd 13782/udp
+vopied 13783/tcp # VERITAS NetBackup
+vopied 13783/udp
solaris-audit 16162/tcp # Secure remote audit logging
-wnn6 22273/tcp # Wnn6 jserver
-wnn6 22273/udp # Wnn6 jserver
+wnn6 22273/tcp # wnn6
+wnn6 22273/udp
+
+#
+# Datagram Delivery Protocol services
+#
+rtmp 1/ddp # Routing Table Maintenance Protocol
+nbp 2/ddp # Name Binding Protocol
+echo 4/ddp # AppleTalk Echo Protocol
+zip 6/ddp # Zone Information Protocol
+
+#=========================================================================
+# The remaining port numbers are not as allocated by IANA.
+#=========================================================================
+
+# Kerberos (Project Athena/MIT) services
+# Note that these are for Kerberos v4, and are unofficial. Sites running
+# v4 should uncomment these and comment out the v5 entries above.
+#
+kerberos4 750/udp kerberos-iv kdc # Kerberos (server)
+kerberos4 750/tcp kerberos-iv kdc
+kerberos_master 751/udp # Kerberos authentication
+kerberos_master 751/tcp
+passwd_server 752/udp # Kerberos passwd server
+krb_prop 754/tcp krb5_prop hprop # Kerberos slave propagation
+krbupdate 760/tcp kreg # Kerberos registration
+swat 901/tcp # swat
+kpop 1109/tcp # Pop with Kerberos
+knetd 2053/tcp # Kerberos de-multiplexor
+zephyr-srv 2102/udp # Zephyr server
+zephyr-clt 2103/udp # Zephyr serv-hm connection
+zephyr-hm 2104/udp # Zephyr hostmanager
+eklogin 2105/tcp # Kerberos encrypted rlogin
+# Hmmm. Are we using Kv4 or Kv5 now? Worrying.
+# The following is probably Kerberos v5 --- ajt@debian.org (11/02/2000)
+kx 2111/tcp # X over Kerberos
+iprop 2121/tcp # incremental propagation
+#
+# Unofficial but necessary (for NetBSD) services
+#
+supfilesrv 871/tcp # SUP server
+supfiledbg 1127/tcp # SUP debugging
+
+#
+# Services added for the Debian GNU/Linux distribution
+#
+linuxconf 98/tcp # LinuxConf
+poppassd 106/tcp # Eudora
+poppassd 106/udp
+ssmtp 465/tcp smtps # SMTP over SSL
+moira_db 775/tcp # Moira database
+moira_update 777/tcp # Moira update protocol
+moira_ureg 779/udp # Moira user registration
+spamd 783/tcp # spamassassin daemon
+omirr 808/tcp omirrd # online mirror
+omirr 808/udp omirrd
+customs 1001/tcp # pmake customs server
+customs 1001/udp
+skkserv 1178/tcp # skk jisho server port
+predict 1210/udp # predict -- satellite tracking
+rmtcfg 1236/tcp # Gracilis Packeten remote config server
+wipld 1300/tcp # Wipl network monitor
+xtel 1313/tcp # french minitel
+xtelw 1314/tcp # french minitel
+support 1529/tcp # GNATS
+cfinger 2003/tcp # GNU Finger
+frox 2121/tcp # frox: caching ftp proxy
+ninstall 2150/tcp # ninstall service
+ninstall 2150/udp
+zebrasrv 2600/tcp # zebra service
+zebra 2601/tcp # zebra vty
+ripd 2602/tcp # ripd vty (zebra)
+ripngd 2603/tcp # ripngd vty (zebra)
+ospfd 2604/tcp # ospfd vty (zebra)
+bgpd 2605/tcp # bgpd vty (zebra)
+ospf6d 2606/tcp # ospf6d vty (zebra)
+ospfapi 2607/tcp # OSPF-API
+isisd 2608/tcp # ISISd vty (zebra)
+afbackup 2988/tcp # Afbackup system
+afbackup 2988/udp
+afmbackup 2989/tcp # Afmbackup system
+afmbackup 2989/udp
+xtell 4224/tcp # xtell server
+fax 4557/tcp # FAX transmission service (old)
+hylafax 4559/tcp # HylaFAX client-server protocol (new)
+distmp3 4600/tcp # distmp3host daemon
+munin 4949/tcp lrrd # Munin
+enbd-cstatd 5051/tcp # ENBD client statd
+enbd-sstatd 5052/tcp # ENBD server statd
+pcrd 5151/tcp # PCR-1000 Daemon
+noclog 5354/tcp # noclogd with TCP (nocol)
+noclog 5354/udp # noclogd with UDP (nocol)
+hostmon 5355/tcp # hostmon uses TCP (nocol)
+hostmon 5355/udp # hostmon uses UDP (nocol)
+rplay 5555/udp # RPlay audio service
+nsca 5667/tcp # Nagios Agent - NSCA
+mrtd 5674/tcp # MRT Routing Daemon
+bgpsim 5675/tcp # MRT Routing Simulator
+canna 5680/tcp # cannaserver
+sane-port 6566/tcp sane saned # SANE network scanner daemon
+ircd 6667/tcp # Internet Relay Chat
+zope-ftp 8021/tcp # zope management by ftp
+tproxy 8081/tcp # Transparent Proxy
+omniorb 8088/tcp # OmniORB
+omniorb 8088/udp
+clc-build-daemon 8990/tcp # Common lisp build daemon
+xinetd 9098/tcp
+mandelspawn 9359/udp mandelbrot # network mandelbrot
+git 9418/tcp # Git Version Control System
+zope 9673/tcp # zope server
+webmin 10000/tcp
+kamanda 10081/tcp # amanda backup services (Kerberos)
+kamanda 10081/udp
+amandaidx 10082/tcp # amanda backup services
+amidxtape 10083/tcp # amanda backup services
+smsqp 11201/tcp # Alamin SMS gateway
+smsqp 11201/udp
+xpilot 15345/tcp # XPilot Contact Port
+xpilot 15345/udp
+sgi-cmsd 17001/udp # Cluster membership services daemon
+sgi-crsd 17002/udp
+sgi-gcd 17003/udp # SGI Group membership daemon
+sgi-cad 17004/tcp # Cluster Admin daemon
+isdnlog 20011/tcp # isdn logging system
+isdnlog 20011/udp
+vboxd 20012/tcp # voice box system
+vboxd 20012/udp
+binkp 24554/tcp # binkp fidonet protocol
+asp 27374/tcp # Address Search Protocol
+asp 27374/udp
+csync2 30865/tcp # cluster synchronization tool
+dircproxy 57000/tcp # Detachable IRC Proxy
+tfido 60177/tcp # fidonet EMSI over telnet
+fido 60179/tcp # fidonet EMSI over TCP
+
+# Local services
diff --git a/usr/src/cmd/cmd-inet/etc/sock2path.d/system%2Fkernel b/usr/src/cmd/cmd-inet/etc/sock2path.d/system%2Fkernel
index c62e339953..49151907eb 100644
--- a/usr/src/cmd/cmd-inet/etc/sock2path.d/system%2Fkernel
+++ b/usr/src/cmd/cmd-inet/etc/sock2path.d/system%2Fkernel
@@ -18,6 +18,7 @@
# CDDL HEADER END
#
# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, Joyent, Inc. All rights reserved.
#
# socket configuration information
#
@@ -52,3 +53,6 @@
29 4 1 /dev/spdsock
31 1 0 trill
+
+ 33 1 0 lx_netlink
+ 33 4 0 lx_netlink
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
index f9ae4eacdc..499d0b89b0 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
@@ -19,13 +19,15 @@
# CDDL HEADER END
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
# Needed for ROOTFS_LIBDIR definition
include ../../../../lib/Makefile.lib
PROG= ipmgmtd
-OBJS= ipmgmt_main.o ipmgmt_door.o ipmgmt_persist.o ipmgmt_util.o
+OBJS= ipmgmt_main.o ipmgmt_door.o ipmgmt_persist.o ipmgmt_util.o \
+ ipmgmt_path.o
SRCS= $(OBJS:.o=.c)
SVCMETHOD= net-ipmgmt
MANIFEST= network-ipmgmt.xml
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
index c83c7627ad..bb4ffcbf0e 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014, Joyent, Inc. All rights reserved.
* Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*/
@@ -113,7 +114,9 @@ ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
goto fail;
}
- /* check for solaris.network.interface.config authorization */
+ /*
+ * if not root, check for solaris.network.interface.config authorization
+ */
if (infop->idi_set) {
uid_t uid;
struct passwd pwd;
@@ -125,24 +128,32 @@ ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
goto fail;
}
uid = ucred_getruid(cred);
+ ucred_free(cred);
if ((int)uid < 0) {
err = errno;
ipmgmt_log(LOG_ERR, "Could not get user id.");
goto fail;
}
- if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) ==
- NULL) {
- err = errno;
- ipmgmt_log(LOG_ERR, "Could not get password entry.");
- goto fail;
- }
- if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
- pwd.pw_name) != 1) {
- err = EPERM;
- ipmgmt_log(LOG_ERR, "Not authorized for operation.");
- goto fail;
+
+ /*
+ * Branded zones may have different auth, but root always
+ * allowed.
+ */
+ if (uid != 0) {
+ if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
+ err = errno;
+ ipmgmt_log(LOG_ERR,
+ "Could not get password entry.");
+ goto fail;
+ }
+ if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
+ pwd.pw_name) != 1) {
+ err = EPERM;
+ ipmgmt_log(LOG_ERR,
+ "Not authorized for operation.");
+ goto fail;
+ }
}
- ucred_free(cred);
}
/* individual handlers take care of calling door_return */
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
index e95e5c7e00..f4d6d30645 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
* Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
@@ -144,8 +145,6 @@ extern ipmgmt_aobjmap_list_t aobjmap;
#define ADDROBJ_LOOKUPADD 0x00000004
#define ADDROBJ_SETLIFNUM 0x00000008
-/* Permanent data store for ipadm */
-#define IPADM_DB_FILE "/etc/ipadm/ipadm.conf"
#define IPADM_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/*
@@ -155,20 +154,12 @@ extern ipmgmt_aobjmap_list_t aobjmap;
*/
#define IPADM_DB_VERSION 1
-/*
- * A temporary file created in SMF volatile filesystem. This file captures the
- * in-memory copy of list `aobjmap' on disk. This is done to recover from
- * daemon reboot (using svcadm) or crashes.
- */
-#define IPADM_TMPFS_DIR "/etc/svc/volatile/ipadm"
-#define ADDROBJ_MAPPING_DB_FILE IPADM_TMPFS_DIR"/aobjmap.conf"
-
-/*
- * A temporary copy of the ipadm configuration file might need
- * to be created if write requests are encountered during boottime
- * and the root filesystem is mounted read-only.
- */
-#define IPADM_VOL_DB_FILE IPADM_TMPFS_DIR"/ipadm.conf"
+typedef enum ipadm_path {
+ IPADM_PATH_TMPFS_DIR = 1,
+ IPADM_PATH_ADDROBJ_MAP_DB,
+ IPADM_PATH_DB,
+ IPADM_PATH_VOL_DB
+} ipadm_path_t;
/* SCF resources required to interact with svc.configd */
typedef struct scf_resources {
@@ -198,6 +189,8 @@ extern void ipmgmt_release_scf_resources(scf_resources_t *);
extern boolean_t ipmgmt_needs_upgrade(scf_resources_t *);
extern void ipmgmt_update_dbver(scf_resources_t *);
+extern void ipmgmt_path(ipadm_path_t, char *, size_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
index 5cdc0f5697..994d1b0125 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
/*
@@ -105,6 +106,7 @@ ipmgmt_db_init()
int fd, err, scferr;
scf_resources_t res;
boolean_t upgrade = B_TRUE;
+ char aobjpath[MAXPATHLEN];
/*
* Check to see if we need to upgrade the data-store. We need to
@@ -134,11 +136,11 @@ ipmgmt_db_init()
ipmgmt_release_scf_resources(&res);
/* creates the address object data store, if it doesn't exist */
- if ((fd = open(ADDROBJ_MAPPING_DB_FILE, O_CREAT|O_RDONLY,
- IPADM_FILE_MODE)) == -1) {
+ ipmgmt_path(IPADM_PATH_ADDROBJ_MAP_DB, aobjpath, sizeof (aobjpath));
+ if ((fd = open(aobjpath, O_CREAT|O_RDONLY, IPADM_FILE_MODE)) == -1) {
err = errno;
- ipmgmt_log(LOG_ERR, "could not open %s: %s",
- ADDROBJ_MAPPING_DB_FILE, strerror(err));
+ ipmgmt_log(LOG_ERR, "could not open %s: %s", aobjpath,
+ strerror(err));
return (err);
}
(void) close(fd);
@@ -152,8 +154,8 @@ ipmgmt_db_init()
* representation of the mapping. That is, build `aobjmap' structure
* from address object data store.
*/
- if ((err = ipadm_rw_db(ipmgmt_aobjmap_init, NULL,
- ADDROBJ_MAPPING_DB_FILE, 0, IPADM_DB_READ)) != 0) {
+ if ((err = ipadm_rw_db(ipmgmt_aobjmap_init, NULL, aobjpath, 0,
+ IPADM_DB_READ)) != 0) {
/* if there was nothing to initialize, it's fine */
if (err != ENOENT)
return (err);
@@ -165,17 +167,42 @@ ipmgmt_db_init()
return (err);
}
+static const char *
+ipmgmt_door_path()
+{
+ static char door[MAXPATHLEN];
+ static boolean_t init_done = B_FALSE;
+
+ if (!init_done) {
+ const char *zroot = zone_get_nroot();
+
+ /*
+ * If this is a branded zone, make sure we use the "/native"
+ * prefix for the door path:
+ */
+ (void) snprintf(door, sizeof (door), "%s%s", zroot != NULL ?
+ zroot : "", IPMGMT_DOOR);
+
+ init_done = B_TRUE;
+ }
+
+ return (door);
+}
+
static int
ipmgmt_door_init()
{
int fd;
int err;
+ const char *door = ipmgmt_door_path();
- /* create the door file for ipmgmtd */
- if ((fd = open(IPMGMT_DOOR, O_CREAT|O_RDONLY, IPADM_FILE_MODE)) == -1) {
+ /*
+ * Create the door file for ipmgmtd.
+ */
+ if ((fd = open(door, O_CREAT | O_RDONLY, IPADM_FILE_MODE)) == -1) {
err = errno;
- ipmgmt_log(LOG_ERR, "could not open %s: %s",
- IPMGMT_DOOR, strerror(err));
+ ipmgmt_log(LOG_ERR, "could not open %s: %s", door,
+ strerror(err));
return (err);
}
(void) close(fd);
@@ -186,15 +213,16 @@ ipmgmt_door_init()
ipmgmt_log(LOG_ERR, "failed to create door: %s", strerror(err));
return (err);
}
+
/*
* fdetach first in case a previous daemon instance exited
* ungracefully.
*/
- (void) fdetach(IPMGMT_DOOR);
- if (fattach(ipmgmt_door_fd, IPMGMT_DOOR) != 0) {
+ (void) fdetach(door);
+ if (fattach(ipmgmt_door_fd, door) != 0) {
err = errno;
- ipmgmt_log(LOG_ERR, "failed to attach door to %s: %s",
- IPMGMT_DOOR, strerror(err));
+ ipmgmt_log(LOG_ERR, "failed to attach door to %s: %s", door,
+ strerror(err));
goto fail;
}
return (0);
@@ -207,13 +235,15 @@ fail:
static void
ipmgmt_door_fini()
{
+ const char *door = ipmgmt_door_path();
+
if (ipmgmt_door_fd == -1)
return;
- (void) fdetach(IPMGMT_DOOR);
+ (void) fdetach(door);
if (door_revoke(ipmgmt_door_fd) == -1) {
ipmgmt_log(LOG_ERR, "failed to revoke access to door %s: %s",
- IPMGMT_DOOR, strerror(errno));
+ door, strerror(errno));
}
}
@@ -350,10 +380,14 @@ ipmgmt_init_privileges()
{
struct stat statbuf;
int err;
+ char tmpfsdir[MAXPATHLEN];
- /* create the IPADM_TMPFS_DIR directory */
- if (stat(IPADM_TMPFS_DIR, &statbuf) < 0) {
- if (mkdir(IPADM_TMPFS_DIR, (mode_t)0755) < 0) {
+ /*
+ * Create the volatile storage directory:
+ */
+ ipmgmt_path(IPADM_PATH_TMPFS_DIR, tmpfsdir, sizeof (tmpfsdir));
+ if (stat(tmpfsdir, &statbuf) < 0) {
+ if (mkdir(tmpfsdir, (mode_t)0755) < 0) {
err = errno;
goto fail;
}
@@ -364,8 +398,8 @@ ipmgmt_init_privileges()
}
}
- if ((chmod(IPADM_TMPFS_DIR, 0755) < 0) ||
- (chown(IPADM_TMPFS_DIR, UID_NETADM, GID_NETADM) < 0)) {
+ if ((chmod(tmpfsdir, 0755) < 0) ||
+ (chown(tmpfsdir, UID_NETADM, GID_NETADM) < 0)) {
err = errno;
goto fail;
}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_path.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_path.c
new file mode 100644
index 0000000000..0219ac1522
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_path.c
@@ -0,0 +1,84 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Lookup functions for various file paths used by ipmgmtd. This mechanism
+ * primarily exists to account for a native root prefix when run within a
+ * branded zone (e.g. "/native").
+ */
+
+#include <stdio.h>
+#include <zone.h>
+#include "ipmgmt_impl.h"
+
+#define IPADM_PERM_DIR "/etc/ipadm"
+#define IPADM_TMPFS_DIR "/etc/svc/volatile/ipadm"
+
+typedef struct ipadm_path_ent {
+ ipadm_path_t ipe_id;
+ const char *ipe_path;
+} ipadm_path_ent_t;
+
+static ipadm_path_ent_t ipadm_paths[] = {
+ /*
+ * A temporary directory created in the SMF volatile filesystem.
+ */
+ { IPADM_PATH_TMPFS_DIR, IPADM_TMPFS_DIR },
+
+ /*
+ * This file captures the in-memory copy of list `aobjmap' on disk.
+ * This allows the system to recover in the event that the daemon
+ * crashes or is restarted.
+ */
+ { IPADM_PATH_ADDROBJ_MAP_DB, IPADM_TMPFS_DIR "/aobjmap.conf" },
+
+ /*
+ * The permanent data store for ipadm.
+ */
+ { IPADM_PATH_DB, IPADM_PERM_DIR "/ipadm.conf" },
+
+ /*
+ * A temporary copy of the ipadm configuration created, if needed, to
+ * service write requests early in boot. This file is merged with the
+ * permanent data store once it is available for writes.
+ */
+ { IPADM_PATH_VOL_DB, IPADM_TMPFS_DIR "/ipadm.conf" },
+
+ { 0, NULL }
+};
+
+/*
+ * Load one of the paths used by ipadm into the provided string buffer.
+ * Prepends the native system prefix (e.g. "/native") if one is in effect,
+ * such as when running within a branded zone.
+ */
+void
+ipmgmt_path(ipadm_path_t ip, char *buf, size_t bufsz)
+{
+ int i;
+
+ for (i = 0; ipadm_paths[i].ipe_path != NULL; i++) {
+ if (ipadm_paths[i].ipe_id == ip) {
+ const char *zroot = zone_get_nroot();
+
+ (void) snprintf(buf, bufsz, "%s%s", zroot != NULL ?
+ zroot : "", ipadm_paths[i].ipe_path);
+
+ return;
+ }
+ }
+
+ abort();
+}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
index c1995611e9..a185068005 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
@@ -386,13 +386,18 @@ static void *
ipmgmt_db_restore_thread(void *arg)
{
int err;
+ char confpath[MAXPATHLEN];
+ char tmpconfpath[MAXPATHLEN];
+
+ ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
+ ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
for (;;) {
(void) sleep(5);
(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
if (!ipmgmt_rdonly_root)
break;
- err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
+ err = ipmgmt_cpfile(tmpconfpath, confpath, B_FALSE);
if (err == 0) {
ipmgmt_rdonly_root = B_FALSE;
break;
@@ -424,6 +429,11 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
mode_t mode;
pthread_t tid;
pthread_attr_t attr;
+ char confpath[MAXPATHLEN];
+ char tmpconfpath[MAXPATHLEN];
+
+ ipmgmt_path(IPADM_PATH_DB, confpath, sizeof (confpath));
+ ipmgmt_path(IPADM_PATH_VOL_DB, tmpconfpath, sizeof (tmpconfpath));
writeop = (db_op != IPADM_DB_READ);
if (writeop) {
@@ -436,11 +446,10 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
/*
* Did a previous write attempt fail? If so, don't even try to
- * read/write to IPADM_DB_FILE.
+ * read/write to the permanent configuration file.
*/
if (!ipmgmt_rdonly_root) {
- err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
- mode, db_op);
+ err = ipadm_rw_db(db_walk_func, db_warg, confpath, mode, db_op);
if (err != EROFS)
goto done;
}
@@ -448,11 +457,11 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
/*
* If we haven't already copied the file to the volatile
* file system, do so. This should only happen on a failed
- * writeop(i.e., we have acquired the write lock above).
+ * writeop (i.e., we have acquired the write lock above).
*/
- if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
+ if (access(tmpconfpath, F_OK) != 0) {
assert(writeop);
- err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
+ err = ipmgmt_cpfile(confpath, tmpconfpath, B_TRUE);
if (err != 0)
goto done;
(void) pthread_attr_init(&attr);
@@ -463,7 +472,7 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
NULL);
(void) pthread_attr_destroy(&attr);
if (err != 0) {
- (void) unlink(IPADM_VOL_DB_FILE);
+ (void) unlink(tmpconfpath);
goto done;
}
ipmgmt_rdonly_root = B_TRUE;
@@ -472,7 +481,7 @@ ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
/*
* Read/write from the volatile copy.
*/
- err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
+ err = ipadm_rw_db(db_walk_func, db_warg, tmpconfpath,
mode, db_op);
done:
(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
@@ -1254,6 +1263,9 @@ ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
int err;
ipadm_dbwrite_cbarg_t cb;
nvlist_t *nvl = NULL;
+ char aobjpath[MAXPATHLEN];
+
+ ipmgmt_path(IPADM_PATH_ADDROBJ_MAP_DB, aobjpath, sizeof (aobjpath));
if (op == IPADM_DB_WRITE) {
if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
@@ -1264,14 +1276,14 @@ ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
else
cb.dbw_flags = 0;
- err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
- ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
+ err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb, aobjpath,
+ IPADM_FILE_MODE, IPADM_DB_WRITE);
nvlist_free(nvl);
} else {
assert(op == IPADM_DB_DELETE);
- err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
- ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
+ err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep, aobjpath,
+ IPADM_FILE_MODE, IPADM_DB_DELETE);
}
return (err);
}
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c
index 133254be4a..e6a88304a7 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <sys/stat.h>
#include <libnvpair.h>
+#include <zone.h>
#include "common.h"
#include "defaults.h"
@@ -67,6 +68,32 @@ static struct dhcp_default defaults[] = {
{ "ADOPT_DOMAINNAME", "0", 0, 0 },
};
+
+/*
+ * df_find_defaults(): builds the path to the default configuration file
+ *
+ * input: void
+ * output: void
+ */
+
+static const char *
+df_find_defaults(void)
+{
+ static char agent_defaults_path[MAXPATHLEN] = { 0 };
+ const char *zroot = NULL;
+
+ if (agent_defaults_path[0] != '\0') {
+ return agent_defaults_path;
+ }
+
+ zroot = zone_get_nroot();
+
+ (void) snprintf(agent_defaults_path, MAXPATHLEN, "%s%s",
+ zroot != NULL ? zroot : "", DHCP_AGENT_DEFAULTS);
+
+ return agent_defaults_path;
+}
+
/*
* df_build_cache(): builds the defaults nvlist cache
*
@@ -77,6 +104,7 @@ static struct dhcp_default defaults[] = {
static nvlist_t *
df_build_cache(void)
{
+ const char *agent_defaults_path = df_find_defaults();
char entry[1024];
int i;
char *param, *pastv6, *value, *end;
@@ -84,7 +112,7 @@ df_build_cache(void)
nvlist_t *nvlist;
struct dhcp_default *defp;
- if ((fp = fopen(DHCP_AGENT_DEFAULTS, "r")) == NULL)
+ if ((fp = fopen(agent_defaults_path, "r")) == NULL)
return (NULL);
if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
@@ -164,6 +192,7 @@ df_build_cache(void)
const char *
df_get_string(const char *if_name, boolean_t isv6, uint_t param)
{
+ const char *agent_defaults_path = df_find_defaults();
char *value;
char paramstr[256];
char name[256];
@@ -175,10 +204,11 @@ df_get_string(const char *if_name, boolean_t isv6, uint_t param)
if (param >= (sizeof (defaults) / sizeof (*defaults)))
return (NULL);
- if (stat(DHCP_AGENT_DEFAULTS, &statbuf) != 0) {
+
+ if (stat(agent_defaults_path, &statbuf) != 0) {
if (!df_unavail_msg) {
dhcpmsg(MSG_WARNING, "cannot access %s; using "
- "built-in defaults", DHCP_AGENT_DEFAULTS);
+ "built-in defaults", agent_defaults_path);
df_unavail_msg = B_TRUE;
}
return (defaults[param].df_default);
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
index 6b5a08a51a..7517f2c094 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
* Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
*
* REQUESTING state of the client state machine.
@@ -39,6 +40,7 @@
#include <dhcp_hostconf.h>
#include <dhcpagent_util.h>
#include <dhcpmsg.h>
+#include <strings.h>
#include "states.h"
#include "util.h"
@@ -645,8 +647,24 @@ accept_v4_acknak(dhcp_smach_t *dsmp, PKT_LIST *plp)
stop_pkt_retransmission(dsmp);
if (*plp->opts[CD_DHCP_TYPE]->value == NAK) {
- dhcpmsg(MSG_WARNING, "accept_v4_acknak: NAK on interface %s",
- dsmp->dsm_name);
+ char saddr[18];
+
+ saddr[0] = '\0';
+ if (plp->opts[CD_SERVER_ID] != NULL &&
+ plp->opts[CD_SERVER_ID]->len == sizeof (struct in_addr)) {
+ struct in_addr t_server;
+
+ bcopy(plp->opts[CD_SERVER_ID]->value, &t_server,
+ plp->opts[CD_SERVER_ID]->len);
+ (void) strlcpy(saddr, inet_ntoa(t_server),
+ sizeof (saddr));
+ }
+
+ dhcpmsg(MSG_WARNING, "accept_v4_acknak: NAK on interface %s "
+ "from %s %s",
+ dsmp->dsm_name,
+ inet_ntoa(plp->pktfrom.v4.sin_addr), saddr);
+
dsmp->dsm_bad_offers++;
free_pkt_entry(plp);
dhcp_restart(dsmp);
diff --git a/usr/src/cmd/cmd-inet/usr.lib/wpad/Makefile b/usr/src/cmd/cmd-inet/usr.lib/wpad/Makefile
index 7d72bad58f..0efa270e8b 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpad/Makefile
@@ -34,8 +34,7 @@ include ../../../Makefile.cmd
ROOTMANIFESTDIR = $(ROOTSVCNETWORK)
LDLIBS += -ldladm -ldlpi
-NATIVE_LIBS += libcrypto.so
-all install := LDLIBS += -lcrypto
+all install := LDLIBS += -lsunw_crypto
SMOFF += all_func_returns
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
index 97476c95d9..98971bf5b0 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
@@ -166,6 +166,7 @@ route := CPPFLAGS += -DNDEBUG
ndd := LDLIBS += -ldladm -lipadm
$(RELEASE_BUILD)ndd := CERRWARN += -_gcc=-Wno-unused
in.comsat := LDFLAGS += $(MAPFILE.NGB:%=-M%)
+route := LDLIBS += -lzonecfg -lcontract
.KEEP_STATE:
@@ -268,7 +269,7 @@ lint: $(LINTSUBDIRS)
in.telnetd.c $(LDLIBS) -lbsm -lpam -lsocket -lnsl
$(LINT.c) if_mpadm.c $(LDLIBS) -lsocket -lnsl -lipmp -linetutil
$(LINT.c) ipaddrsel.c $(LDLIBS) -lsocket -lnsl
- $(LINT.c) route.c $(LDLIBS) -lsocket -lnsl -ltsnet
+ $(LINT.c) route.c $(LDLIBS) -lsocket -lnsl -ltsnet -lcontract -lzonecfg
$(LINT.c) syncinit.c $(LDLIBS) -ldlpi
$(LINT.c) syncloop.c $(LDLIBS) -ldlpi
$(LINT.c) syncstat.c $(LDLIBS) -ldlpi
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/arp.c b/usr/src/cmd/cmd-inet/usr.sbin/arp.c
index 19ab13fd47..aa9adac6ce 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/arp.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/arp.c
@@ -58,6 +58,7 @@
#include <arpa/inet.h>
#include <net/if_types.h>
#include <net/if_dl.h>
+#include <zone.h>
static int file(char *);
static int set(int, char *[]);
@@ -118,7 +119,11 @@ main(int argc, char *argv[])
* is to let netstat, which prints it as part of
* the MIB statistics, do it.
*/
- (void) execl("/usr/bin/netstat", "netstat",
+ char netstat_path[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+ (void) snprintf(netstat_path, sizeof (netstat_path), "%s%s", zroot != NULL ?
+ zroot : "", "/usr/bin/netstat");
+ (void) execl(netstat_path, "netstat",
(n_flag ? "-np" : "-p"),
"-f", "inet", (char *)0);
(void) fprintf(stderr, "failed to exec netstat: %s\n",
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ndp.c b/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
index 23b940c686..2fc19775ad 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ndp.c
@@ -40,6 +40,7 @@
#include <inet/ip.h>
#include <net/if_dl.h>
#include <net/route.h>
+#include <zone.h>
typedef struct sockaddr_in6 sin6_t;
@@ -95,7 +96,6 @@ static int ndp_set_nce(char *, char *, char *[], int);
static int ndp_set_file(char *);
static char *ndp_iface = NULL;
-static char *netstat_path = "/usr/bin/netstat";
static pid_t ndp_pid;
static boolean_t ndp_noresolve = B_FALSE; /* Don't lookup addresses */
static boolean_t ndp_run = B_TRUE;
@@ -103,6 +103,7 @@ static boolean_t ndp_run = B_TRUE;
#define MAX_ATTEMPTS 5
#define MAX_OPTS 5
#define WORDSEPS " \t\r\n"
+#define NETSTAT_PATH "/usr/bin/netstat"
/*
* Macros borrowed from route(1M) for working with PF_ROUTE messages
@@ -767,6 +768,12 @@ ndp_get(int fd, struct lifreq *lifrp, void *unused)
static void
ndp_get_all(void)
{
+ char netstat_path[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+
+ (void) snprintf(netstat_path, sizeof (netstat_path), "%s%s", zroot != NULL ?
+ zroot : "", NETSTAT_PATH);
+
(void) execl(netstat_path, "netstat",
(ndp_noresolve ? "-np" : "-p"),
"-f", "inet6", (char *)0);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/route.c b/usr/src/cmd/cmd-inet/usr.sbin/route.c
index a2fd0d2d17..29ccf97bb1 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/route.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/route.c
@@ -6,6 +6,7 @@
/* All Rights Reserved */
/* Copyright (c) 1990 Mentat Inc. */
+/* Copyright 2018, Joyent, Inc. */
/*
*
@@ -79,6 +80,13 @@
#include <assert.h>
#include <strings.h>
+#include <libcontract.h>
+#include <sys/ctfs.h>
+#include <sys/contract/process.h>
+#include <sys/wait.h>
+#include <libzonecfg.h>
+#include <zone.h>
+
#include <libtsnet.h>
#include <tsol/label.h>
@@ -292,6 +300,7 @@ static void syntax_error(char *err, ...);
static void usage(char *cp);
static void write_to_rtfile(FILE *fp, int argc, char **argv);
static void pmsg_secattr(const char *, size_t, const char *);
+static void do_zone(char *);
static pid_t pid;
static int s;
@@ -308,6 +317,7 @@ static char perm_file_sfx[] = "/etc/inet/static_routes";
static char *perm_file;
static char temp_file_sfx[] = "/etc/inet/static_routes.tmp";
static char *temp_file;
+static char *zonename;
static struct in6_addr in6_host_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/*
@@ -354,7 +364,7 @@ usage(char *cp)
cp);
}
(void) fprintf(stderr, gettext("usage: route [ -fnpqv ] "
- "[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n"));
+ "[-z <zone> ] [ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n"));
exit(1);
/* NOTREACHED */
}
@@ -418,7 +428,7 @@ main(int argc, char **argv)
if (argc < 2)
usage(NULL);
- while ((ch = getopt(argc, argv, "R:nqdtvfp")) != EOF) {
+ while ((ch = getopt(argc, argv, "R:nqdtvfpz:")) != EOF) {
switch (ch) {
case 'n':
nflag = B_TRUE;
@@ -444,6 +454,9 @@ main(int argc, char **argv)
case 'R':
root_dir = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
case '?':
default:
usage(NULL);
@@ -453,6 +466,8 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
+ do_zone(zonename);
+
pid = getpid();
if (tflag)
s = open("/dev/null", O_WRONLY);
@@ -3252,3 +3267,74 @@ pmsg_secattr(const char *sptr, size_t msglen, const char *labelstr)
sizeof (buf)));
}
}
+
+static void
+do_zone(char *name)
+{
+ zoneid_t zoneid;
+ zone_state_t st;
+ int fd, status, rc = 0;
+ pid_t pid;
+
+ if (name == NULL)
+ return;
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ (void) fprintf(stderr,
+ "route: -z can only be specified from the global zone\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(name, GLOBAL_ZONENAME) == 0)
+ return;
+
+ if (zone_get_state(name, &st) != Z_OK)
+ quit("unable to get zone state", errno);
+
+ if (st != ZONE_STATE_RUNNING) {
+ (void) fprintf(stderr, "route: zone must be running\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((zoneid = getzoneidbyname(name)) == -1)
+ quit("cannot determine zone id", errno);
+
+ if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) == -1)
+ quit("cannot open ctfs template", errno);
+
+ /*
+ * zone_enter() does not allow contracts to straddle zones, so we must
+ * create a new, though largely unused contract. Once we fork, the
+ * child is the only member of the new contract, so it can perform a
+ * zone_enter().
+ */
+ rc |= ct_tmpl_set_critical(fd, 0);
+ rc |= ct_tmpl_set_informative(fd, 0);
+ rc |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
+ rc |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
+ if (rc || ct_tmpl_activate(fd)) {
+ (void) close(fd);
+ quit("could not create contract", errno);
+ }
+
+ switch (pid = fork1()) {
+ case 0:
+ (void) ct_tmpl_clear(fd);
+ (void) close(fd);
+ if (zone_enter(zoneid) == -1)
+ quit("could not enter zone", errno);
+ return;
+
+ case -1:
+ quit("fork1 failed", errno);
+
+ default:
+ (void) ct_tmpl_clear(fd);
+ (void) close(fd);
+ if (waitpid(pid, &status, 0) < 0)
+ quit("waitpid failed", errno);
+
+ exit(WEXITSTATUS(status));
+ }
+
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c
index 71a2fc9853..be826baba2 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c
@@ -21,10 +21,9 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2012 Joyent, Inc. All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -46,6 +45,7 @@
#include <libscf.h>
#include <libscf_priv.h>
#include <libuutil.h>
+#include <ifaddrs.h>
/*
* This program moves routing management under SMF. We do this by giving
@@ -2335,8 +2335,8 @@ out:
/*
*
- * Return the number of IPv6 addresses configured. This answers the
- * generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
+ * Return the number of non-loopback IPv6 addresses configured. This answers
+ * the generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
* is configured, and we also only enable IPv6 routing daemons if IPv6 is
* enabled.
*/
@@ -2344,28 +2344,24 @@ static int
ra_numv6intfs(void)
{
static int num = -1;
- int ipsock;
- struct lifnum lifn;
+ int cnt;
+ struct ifaddrs *ifp_head, *ifp;
if (num != -1)
return (num);
- if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
- (void) fprintf(stderr,
- gettext("%1$s: unable to open %2$s: %3$s\n"),
- myname, IP_DEV_NAME, strerror(errno));
+ if (getifaddrs(&ifp_head) < 0)
return (0);
- }
- lifn.lifn_family = AF_INET6;
- lifn.lifn_flags = 0;
- if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
- (void) close(ipsock);
- return (0);
+ cnt = 0;
+ for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
+ if (!(ifp->ifa_flags & IFF_LOOPBACK) &&
+ (ifp->ifa_flags & IFF_IPV6))
+ cnt++;
}
- (void) close(ipsock);
- return (num = lifn.lifn_count);
+ freeifaddrs(ifp_head);
+ return (num = cnt);
}
/*
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
index 4709cfe59e..4e3dd8259a 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/Makefile
@@ -40,16 +40,18 @@ OBJS= nfs4_xdr.o snoop.o snoop_aarp.o snoop_adsp.o snoop_aecho.o \
snoop_pppoe.o snoop_rip.o snoop_rip6.o snoop_rpc.o snoop_rpcprint.o \
snoop_rpcsec.o snoop_rport.o snoop_rquota.o snoop_rstat.o snoop_rtmp.o \
snoop_sctp.o snoop_slp.o snoop_smb.o snoop_socks.o snoop_solarnet.o \
- snoop_tcp.o snoop_tftp.o snoop_trill.o snoop_udp.o snoop_zip.o
+ snoop_svp.o snoop_tcp.o snoop_tftp.o snoop_trill.o snoop_udp.o \
+ snoop_vxlan.o snoop_zip.o
SRCS= $(OBJS:.o=.c)
HDRS= snoop.h snoop_mip.h at.h snoop_ospf.h snoop_ospf6.h
include ../../../Makefile.cmd
+include ../../../Makefile.ctf
CPPFLAGS += -I. -I$(SRC)/common/net/dhcp \
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-LDLIBS += -ldhcputil -ldlpi -lsocket -lnsl -ltsol
+LDLIBS += -ldhcputil -ldlpi -lsocket -lnsl -ltsol -luuid
LDFLAGS += $(MAPFILE.NGB:%=-M%)
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-implicit-function-declaration
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
index 538cc295db..6abda78efc 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
@@ -121,6 +121,7 @@ main(int argc, char **argv)
char *output_area;
int nbytes;
char *datalink = NULL;
+ char *zonename = NULL;
dlpi_handle_t dh;
names[0] = '\0';
@@ -227,7 +228,7 @@ main(int argc, char **argv)
}
(void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
- while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz"))
+ while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz:Z"))
!= EOF) {
switch (c) {
case 'a':
@@ -348,8 +349,11 @@ main(int argc, char **argv)
case 'U':
Uflg = B_TRUE;
break;
-#ifdef DEBUG
case 'z':
+ zonename = optarg;
+ break;
+#ifdef DEBUG
+ case 'Z':
zflg = B_TRUE;
break;
#endif /* DEBUG */
@@ -371,7 +375,7 @@ main(int argc, char **argv)
* requested was chosen, but that's too hard.
*/
if (!icapfile) {
- use_kern_pf = open_datalink(&dh, datalink);
+ use_kern_pf = open_datalink(&dh, datalink, zonename);
} else {
use_kern_pf = B_FALSE;
cap_open_read(icapfile);
@@ -812,6 +816,8 @@ usage(void)
(void) fprintf(stderr,
"\t[ -r ] # Do not resolve address to name\n");
(void) fprintf(stderr,
+ "\t[ -z zone ] # Open links from named zone\n");
+ (void) fprintf(stderr,
"\n\t[ filter expression ]\n");
(void) fprintf(stderr, "\nExample:\n");
(void) fprintf(stderr, "\tsnoop -o saved host fred\n\n");
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
index 1d1d921f65..81add827e6 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
@@ -24,6 +24,7 @@
* Use is subject to license terms.
*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Joyent, Inc.
*/
#ifndef _SNOOP_H
@@ -195,7 +196,7 @@ extern void cap_open_read(const char *);
extern void cap_open_write(const char *);
extern void cap_read(int, int, int, void (*)(), int);
extern void cap_close(void);
-extern boolean_t open_datalink(dlpi_handle_t *, const char *);
+extern boolean_t open_datalink(dlpi_handle_t *, const char *, const char *);
extern void init_datalink(dlpi_handle_t, ulong_t, ulong_t, struct timeval *,
struct Pf_ext_packetfilt *);
extern void net_read(dlpi_handle_t, size_t, int, void (*)(), int);
@@ -273,6 +274,8 @@ extern int interpret_socks_reply(int, char *, int);
extern int interpret_trill(int, struct ether_header **, char *, int *);
extern int interpret_isis(int, char *, int, boolean_t);
extern int interpret_bpdu(int, char *, int);
+extern int interpret_vxlan(int, char *, int);
+extern int interpret_svp(int, char *, int);
extern void init_ldap(void);
extern boolean_t arp_for_ether(char *, struct ether_addr *);
extern char *ether_ouiname(uint32_t);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
index ab6bc292ac..8fbf3fc15f 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
@@ -29,6 +29,7 @@
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/signal.h>
@@ -114,7 +115,7 @@ select_datalink(const char *linkname, void *arg)
* about the datalink useful for building the proper packet filters.
*/
boolean_t
-open_datalink(dlpi_handle_t *dhp, const char *linkname)
+open_datalink(dlpi_handle_t *dhp, const char *linkname, const char *zonename)
{
int retval;
int flags = DLPI_PASSIVE | DLPI_RAW;
@@ -122,6 +123,9 @@ open_datalink(dlpi_handle_t *dhp, const char *linkname)
dlpi_info_t dlinfo;
if (linkname == NULL) {
+ if (zonename != NULL)
+ pr_err("a datalink must be specified with a zone name");
+
/*
* Select a datalink to use by default. Prefer datalinks that
* are plumbed by IP.
@@ -145,7 +149,8 @@ open_datalink(dlpi_handle_t *dhp, const char *linkname)
flags |= DLPI_DEVIPNET;
if (Iflg || strcmp(linkname, "lo0") == 0)
flags |= DLPI_IPNETINFO;
- if ((retval = dlpi_open(linkname, dhp, flags)) != DLPI_SUCCESS) {
+ if ((retval = dlpi_open_zone(linkname, zonename, dhp,
+ flags)) != DLPI_SUCCESS) {
pr_err("cannot open \"%s\": %s", linkname,
dlpi_strerror(retval));
}
@@ -614,6 +619,10 @@ cap_open_read(const char *name)
if (fstat(capfile_in, &st) < 0)
pr_err("couldn't stat %s: %m", name);
+ if (st.st_size > INT_MAX)
+ pr_err("input file size (%llu bytes) exceeds maximum "
+ "supported size (%d bytes)",
+ (unsigned long long)st.st_size, INT_MAX);
cap_len = st.st_size;
cap_buffp = mmap(0, cap_len, PROT_READ, MAP_PRIVATE, capfile_in, 0);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c
index 332069508c..f084365faf 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
*/
#include <stdio.h>
@@ -54,8 +55,9 @@
static headerlen_fn_t ether_header_len, fddi_header_len, tr_header_len,
ib_header_len, ipnet_header_len, ipv4_header_len, ipv6_header_len;
-static interpreter_fn_t interpret_ether, interpret_fddi, interpret_tr,
+static interpreter_fn_t interpret_fddi, interpret_tr,
interpret_ib, interpret_ipnet, interpret_iptun;
+interpreter_fn_t interpret_ether;
static void addr_copy_swap(struct ether_addr *, struct ether_addr *);
static int tr_machdr_len(char *, int *, int *);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
index 7be45437d5..77e9d97766 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c
@@ -21,6 +21,7 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018, Joyent, Inc.
*/
#include <stdio.h>
@@ -76,6 +77,7 @@ static const struct porttable pt_udp[] = {
{ 560, "RMONITOR" },
{ 561, "MONITOR" },
{ IPPORT_SOCKS, "SOCKS" },
+ { IPPORT_VXLAN, "VXLAN" },
{ 0, NULL }
};
@@ -128,6 +130,7 @@ static struct porttable pt_tcp[] = {
{ 540, "UUCP" },
{ 600, "PCSERVER" },
{ IPPORT_SOCKS, "SOCKS" },
+ { 1296, "SVP" },
{ 1524, "INGRESLOCK" },
{ 2904, "M2UA" },
{ 2905, "M3UA" },
@@ -425,6 +428,15 @@ interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
(void) interpret_socks_reply(flags, data,
dlen);
return (1);
+ case IPPORT_VXLAN:
+ (void) interpret_vxlan(flags, data, dlen);
+ return (1);
+ case 1296:
+ if (proto == IPPROTO_TCP) {
+ (void) interpret_svp(flags, data, dlen);
+ return (1);
+ }
+ break;
}
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c
new file mode 100644
index 0000000000..a0768c2234
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_svp.c
@@ -0,0 +1,557 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Decode SVP (SmartDC VxLAN Protocol) packets
+ */
+
+#include <inttypes.h>
+#include <sys/crc32.h>
+#include <uuid/uuid.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <libvarpd_svp_prot.h>
+#include "snoop.h"
+
+/*
+ * String size large enough for an IPv6 address + / + a 3 digit (or less)
+ * prefix length
+ */
+#define ADDRSTR_LEN (INET6_ADDRSTRLEN + 4)
+
+/*
+ * Large enough for all currently known status strings as well as a
+ * 16-bit hex value.
+ */
+#define STATUSSTR_LEN 32
+
+/*
+ * Large enough for all currently known op strings, as well as a
+ * 16-bit hex value.
+ */
+#define OPSTR_LEN 32
+
+/*
+ * Large enough for VL3 types and bulk types, as well as a 32-bit
+ * hex value.
+ */
+#define TYPESTR_LEN 32
+
+static uint32_t svp_crc32_tab[] = { CRC32_TABLE };
+
+#define STR(_x, _buf, _len) \
+ case _x: \
+ (void) strlcpy(_buf, #_x, _len); \
+ break
+
+static void
+svp_op_str(uint16_t op, char *buf, size_t buflen)
+{
+ switch (op) {
+ STR(SVP_R_UNKNOWN, buf, buflen);
+ STR(SVP_R_PING, buf, buflen);
+ STR(SVP_R_PONG, buf, buflen);
+ STR(SVP_R_VL2_REQ, buf, buflen);
+ STR(SVP_R_VL2_ACK, buf, buflen);
+ STR(SVP_R_VL3_REQ, buf, buflen);
+ STR(SVP_R_VL3_ACK, buf, buflen);
+ STR(SVP_R_BULK_REQ, buf, buflen);
+ STR(SVP_R_BULK_ACK, buf, buflen);
+ STR(SVP_R_LOG_REQ, buf, buflen);
+ STR(SVP_R_LOG_ACK, buf, buflen);
+ STR(SVP_R_LOG_RM, buf, buflen);
+ STR(SVP_R_LOG_RM_ACK, buf, buflen);
+ STR(SVP_R_SHOOTDOWN, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%hx", op);
+ }
+}
+
+static void
+svp_status_str(uint16_t status, char *buf, size_t buflen)
+{
+ switch (status) {
+ STR(SVP_S_OK, buf, buflen);
+ STR(SVP_S_FATAL, buf, buflen);
+ STR(SVP_S_NOTFOUND, buf, buflen);
+ STR(SVP_S_BADL3TYPE, buf, buflen);
+ STR(SVP_S_BADBULK, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%hx", status);
+ }
+}
+
+static void
+svp_vl3_type_str(uint32_t type, char *buf, size_t buflen)
+{
+ switch (type) {
+ STR(SVP_VL3_IP, buf, buflen);
+ STR(SVP_VL3_IPV6, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%x", type);
+ }
+}
+
+static void
+svp_bulk_type_str(uint32_t type, char *buf, size_t buflen)
+{
+ switch (type) {
+ STR(SVP_BULK_VL2, buf, buflen);
+ STR(SVP_BULK_VL3, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%x", type);
+ }
+}
+
+static void
+svp_log_type_str(uint32_t type, char *buf, size_t buflen)
+{
+ switch (type) {
+ STR(SVP_LOG_VL2, buf, buflen);
+ STR(SVP_LOG_VL3, buf, buflen);
+ default:
+ (void) snprintf(buf, buflen, "0x%x", type);
+ }
+}
+#undef STR
+
+static void
+svp_addr_str(void *addrp, uint8_t *prefixp, char *buf, size_t buflen)
+{
+ struct in_addr v4;
+ int af = AF_INET6;
+
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addrp)) {
+ af = AF_INET;
+ IN6_V4MAPPED_TO_INADDR((struct in6_addr *)addrp, &v4);
+ addrp = &v4;
+ }
+
+ if (inet_ntop(af, addrp, buf, buflen) == NULL) {
+ uint8_t *p = addrp;
+ size_t i;
+
+ (void) strlcpy(buf, "0x", buflen);
+ for (i = 0; i < 16; i++) {
+ (void) snprintf(buf + 2 + i * 2,
+ sizeof (buf) - 2 - i * 2, "%02hhx", p[i]);
+ }
+ }
+
+ if (prefixp != NULL && *prefixp != 128) {
+ char buf2[5]; /* / + 3 digits + NUL */
+
+ if (af == AF_INET)
+ *prefixp -= 96;
+
+ (void) snprintf(buf2, sizeof (buf2), "/%hhu", *prefixp);
+ (void) strlcat(buf, buf2, buflen);
+ }
+}
+
+static boolean_t
+svp_check_crc(char *data, int len)
+{
+ svp_req_t *req = (svp_req_t *)data;
+ uint32_t save_crc = req->svp_crc32;
+ uint32_t crc = -1U;
+
+ req->svp_crc32 = 0;
+ CRC32(crc, (uint8_t *)data, len, -1U, svp_crc32_tab);
+ crc = ~crc;
+ req->svp_crc32 = save_crc;
+
+ return (ntohl(save_crc) == crc ? B_TRUE : B_FALSE);
+}
+
+static void
+do_svp_vl2_req(void *data, int len)
+{
+ svp_vl2_req_t *vl2 = data;
+
+ show_printf("MAC = %s", ether_ntoa((struct ether_addr *)vl2->sl2r_mac));
+ show_printf("Virtual network id = %u", ntohl(vl2->sl2r_vnetid));
+}
+
+static void
+do_svp_vl2_ack(void *data, int len)
+{
+ svp_vl2_ack_t *vl2a = data;
+ char status[STATUSSTR_LEN];
+ char addr[ADDRSTR_LEN];
+
+ svp_status_str(ntohs(vl2a->sl2a_status), status, sizeof (status));
+ svp_addr_str(vl2a->sl2a_addr, NULL, addr, sizeof (addr));
+
+ show_printf("Status = %s", status);
+ show_printf("UL3 Address = %s", addr);
+ show_printf("UL3 Port = %hu", ntohs(vl2a->sl2a_port));
+}
+
+static void
+do_svp_vl3_req(void *data, int len)
+{
+ svp_vl3_req_t *req = data;
+ char type[TYPESTR_LEN];
+ char addr[ADDRSTR_LEN];
+
+ svp_vl3_type_str(ntohl(req->sl3r_type), type, sizeof (type));
+ svp_addr_str(req->sl3r_ip, NULL, addr, sizeof (addr));
+
+ show_printf("Virtual network id = %u", ntohl(req->sl3r_vnetid));
+ show_printf("Type = %s", type);
+ show_printf("VL3 Address = %s", addr);
+}
+
+static void
+do_svp_vl3_ack(void *data, int len)
+{
+ svp_vl3_ack_t *vl3a = data;
+ char status[STATUSSTR_LEN];
+ char addr[ADDRSTR_LEN];
+
+ svp_status_str(ntohl(vl3a->sl3a_status), status, sizeof (status));
+ svp_addr_str(vl3a->sl3a_uip, NULL, addr, sizeof (addr));
+
+ show_printf("Status = %s", status);
+ show_printf("MAC = %s",
+ ether_ntoa((struct ether_addr *)vl3a->sl3a_mac));
+ show_printf("UL3 Address = %s", addr);
+ show_printf("UL3 Port = %hu", ntohs(vl3a->sl3a_uport));
+}
+
+static void
+do_svp_bulk_req(void *data, int len)
+{
+ svp_bulk_req_t *req = data;
+ char type[TYPESTR_LEN];
+
+ if (len < sizeof (svp_bulk_req_t)) {
+ show_printf("SVP_R_BULK_REQ runt");
+ return;
+ }
+
+ svp_bulk_type_str(ntohl(req->svbr_type), type, sizeof (type));
+ show_printf("Type = %s", type);
+}
+
+static void
+do_svp_bulk_ack(void *data, int len)
+{
+ svp_bulk_ack_t *ack = data;
+ char status[STATUSSTR_LEN];
+ char type[TYPESTR_LEN];
+
+ svp_status_str(ntohl(ack->svba_status), status, sizeof (status));
+ svp_bulk_type_str(ntohl(ack->svba_type), type, sizeof (type));
+
+ show_printf("Status = %s", status);
+ show_printf("Type = %s", type);
+
+ /*
+ * Currently the data format is undefined (see libvarp_svp_prot.h),
+ * so there is nothing else we can display.
+ */
+}
+
+static void
+do_svp_log_req(void *data, int len)
+{
+ svp_log_req_t *svlr = data;
+ char addr[ADDRSTR_LEN];
+
+ svp_addr_str(svlr->svlr_ip, NULL, addr, sizeof (addr));
+
+ show_printf("Count = %u", ntohl(svlr->svlr_count));
+ show_printf("Address = %s", addr);
+}
+
+static void
+do_svp_log_ack(void *data, int len)
+{
+ svp_log_ack_t *ack = data;
+ union {
+ svp_log_vl2_t *vl2;
+ svp_log_vl3_t *vl3;
+ uint32_t *vtype;
+ void *vd;
+ } u;
+ size_t total = 0, rlen = 0;
+ uint8_t prefixlen;
+ boolean_t is_host;
+ char status[STATUSSTR_LEN];
+ char typestr[TYPESTR_LEN];
+ char uuid[UUID_PRINTABLE_STRING_LENGTH];
+ char addr[ADDRSTR_LEN];
+
+ u.vd = (ack + 1);
+
+ svp_status_str(ntohl(ack->svla_status), status, sizeof (status));
+
+ show_printf("Status = %s", status);
+ len -= sizeof (*ack);
+
+ while (len > 0) {
+ uint32_t type;
+
+ if (len < sizeof (uint32_t)) {
+ show_printf(" Trailing runt");
+ break;
+ }
+
+ type = ntohl(*u.vtype);
+ svp_log_type_str(type, typestr, sizeof (typestr));
+
+ switch (type) {
+ case SVP_LOG_VL2:
+ rlen = sizeof (svp_log_vl2_t);
+ break;
+ case SVP_LOG_VL3:
+ rlen = sizeof (svp_log_vl3_t);
+ break;
+ default:
+ /*
+ * If we don't know the type of log record we have,
+ * we cannot determine the size of the record, so we
+ * cannot continue past this.
+ */
+ show_printf("Log %-4zu: Log type = %s", ++total,
+ typestr);
+ return;
+ }
+
+ if (len < rlen) {
+ show_printf("Log %-4zu %s runt", ++total, typestr);
+ return;
+ }
+
+ /* These are the same in SVP_LOG_VL2 and SVP_LOG_VL3 records */
+ show_printf("Log %-4zu Log type = %s", ++total, typestr);
+
+ uuid_parse(uuid, u.vl2->svl2_id);
+ show_printf("%8s UUID = %s", "", uuid);
+
+ switch (type) {
+ case SVP_LOG_VL2:
+ show_printf("%8s MAC = %s", "",
+ ether_ntoa((struct ether_addr *)u.vl2->svl2_mac));
+ show_printf("%8s Vnet = %u", "",
+ ntohl(u.vl2->svl2_vnetid));
+ u.vl2++;
+ break;
+ case SVP_LOG_VL3:
+ svp_addr_str(u.vl3->svl3_ip, NULL, addr, sizeof (addr));
+
+ show_printf("%8s VLAN = %hu", "",
+ ntohs(u.vl3->svl3_vlan));
+ show_printf("%8s Address = %s", "", addr);
+ show_printf("%8s Vnet = %u", "",
+ ntohl(u.vl3->svl3_vnetid));
+ u.vl3++;
+ break;
+ }
+
+ len -= rlen;
+ show_space();
+ }
+ show_printf("Total log records = %zu", total);
+}
+
+static void
+do_svp_lrm_req(void *data, int len)
+{
+ /*
+ * Sized large enough to hold the expected size message
+ * (formatted below) if there's a length mismatch.
+ */
+ char mismatch_str[64] = { 0 };
+ svp_lrm_req_t *req = data;
+ size_t expected_sz = sizeof (*req);
+ size_t i, n;
+
+ n = ntohl(req->svrr_count);
+
+ /* IDs are 16-byte UUIDs */
+ expected_sz += n * UUID_LEN;
+ if (len != expected_sz) {
+ (void) snprintf(mismatch_str, sizeof (mismatch_str),
+ " (expected %zu bytes, actual size is %d bytes)",
+ expected_sz, len);
+ }
+ show_printf("ID Count = %u%s", n, mismatch_str);
+ if (len != expected_sz)
+ return;
+
+ for (i = 0; i < n; i++) {
+ char uuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ uuid_parse(uuid, &req->svrr_ids[UUID_LEN * i]);
+ show_printf("%-4s %s", (i == 0) ? "IDs:" : "", uuid);
+ }
+}
+
+static void
+do_svp_lrm_ack(void *data, int len)
+{
+ svp_lrm_ack_t *ack = data;
+ char status[STATUSSTR_LEN];
+
+ svp_status_str(ntohl(ack->svra_status), status, sizeof (status));
+ show_printf("Status = %s", status);
+}
+
+static void
+do_svp_shootdown(void *data, int len)
+{
+ svp_shootdown_t *sd = data;
+
+ show_printf("Vnet = %u", ntohl(sd->svsd_vnetid));
+ show_printf("MAC Address = %s",
+ ether_ntoa((struct ether_addr *)sd->svsd_mac));
+}
+
+static struct svp_len_tbl {
+ uint16_t slt_op;
+ size_t slt_len;
+} svp_len_tbl[] = {
+ { SVP_R_UNKNOWN, 0 },
+ { SVP_R_PING, 0 },
+ { SVP_R_PONG, 0 },
+ { SVP_R_VL2_REQ, sizeof (svp_vl2_req_t) },
+ { SVP_R_VL2_ACK, sizeof (svp_vl2_ack_t) },
+ { SVP_R_VL3_REQ, sizeof (svp_vl3_req_t) },
+ { SVP_R_VL3_ACK, sizeof (svp_vl3_ack_t) },
+ { SVP_R_BULK_REQ, sizeof (svp_bulk_req_t) },
+ { SVP_R_BULK_ACK, sizeof (svp_bulk_ack_t) },
+ { SVP_R_LOG_REQ, sizeof (svp_log_req_t) },
+ { SVP_R_LOG_ACK, 0 },
+ { SVP_R_LOG_RM, sizeof (svp_lrm_req_t) },
+ { SVP_R_LOG_RM_ACK, sizeof (svp_lrm_ack_t) },
+ { SVP_R_SHOOTDOWN, sizeof (svp_shootdown_t) },
+};
+
+static boolean_t
+svp_check_runt(uint16_t op, int len)
+{
+ if (op > SVP_R_SHOOTDOWN)
+ return (B_FALSE);
+
+ if (len < svp_len_tbl[op].slt_len) {
+ char opstr[OPSTR_LEN];
+
+ svp_op_str(op, opstr, sizeof (opstr));
+ show_printf("%s Runt", opstr);
+ show_space();
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+int
+interpret_svp(int flags, char *data, int fraglen)
+{
+ svp_req_t *req = (svp_req_t *)data;
+ char opstr[OPSTR_LEN];
+ uint16_t op;
+ boolean_t crc_ok;
+
+ if (fraglen < sizeof (svp_req_t)) {
+ if (flags & F_SUM)
+ (void) snprintf(get_sum_line(), MAXLINE,
+ "SVP RUNT");
+ if (flags & F_DTAIL)
+ show_header("SVP RUNT: ", "Short packet", fraglen);
+
+ return (fraglen);
+ }
+
+ op = ntohs(req->svp_op);
+ svp_op_str(op, opstr, sizeof (opstr));
+
+ crc_ok = svp_check_crc(data, fraglen);
+
+ if (flags & F_SUM) {
+ (void) snprintf(get_sum_line(), MAXLINE,
+ "SVP V=%hu OP=%s ID=%u%s", ntohs(req->svp_ver), opstr,
+ ntohl(req->svp_id), crc_ok ? "" : " (BAD CRC)");
+ }
+
+ if (flags & F_DTAIL) {
+ show_header("SVP: ", "SVP Header", sizeof (svp_req_t));
+ show_space();
+ show_printf("Version = %hu", ntohs(req->svp_ver));
+ show_printf("Op = %s", opstr);
+ show_printf("Packet length = %u bytes%s", ntohl(req->svp_size),
+ (ntohl(req->svp_size) == fraglen - sizeof (*req)) ?
+ "" : " (mismatch)");
+ show_printf("Id = %u", ntohl(req->svp_id));
+ show_printf("CRC = %x%s", ntohl(req->svp_crc32),
+ crc_ok ? "" : " (bad)");
+ show_space();
+
+ req++;
+ fraglen -= sizeof (*req);
+
+ /*
+ * Since we cannot know the length of an unknown op,
+ * svp_check_runt() returns B_TRUE for both truncated packets
+ * and unknown packets -- we have nothing meaningful besides
+ * the header we could print anyway.
+ */
+ if (svp_check_runt(op, fraglen))
+ return (fraglen);
+
+ switch (op) {
+ case SVP_R_VL2_REQ:
+ do_svp_vl2_req(req, fraglen);
+ break;
+ case SVP_R_VL2_ACK:
+ do_svp_vl2_ack(req, fraglen);
+ break;
+ case SVP_R_VL3_REQ:
+ do_svp_vl3_req(req, fraglen);
+ break;
+ case SVP_R_VL3_ACK:
+ do_svp_vl3_ack(req, fraglen);
+ break;
+ case SVP_R_BULK_REQ:
+ do_svp_bulk_req(req, fraglen);
+ break;
+ case SVP_R_BULK_ACK:
+ do_svp_bulk_ack(req, fraglen);
+ break;
+ case SVP_R_LOG_REQ:
+ do_svp_log_req(req, fraglen);
+ break;
+ case SVP_R_LOG_ACK:
+ do_svp_log_ack(req, fraglen);
+ break;
+ case SVP_R_LOG_RM:
+ do_svp_lrm_req(req, fraglen);
+ break;
+ case SVP_R_LOG_RM_ACK:
+ do_svp_lrm_ack(req, fraglen);
+ break;
+ case SVP_R_SHOOTDOWN:
+ do_svp_shootdown(req, fraglen);
+ break;
+ }
+
+ show_space();
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vxlan.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vxlan.c
new file mode 100644
index 0000000000..36025ca8f3
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vxlan.c
@@ -0,0 +1,68 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Decode VXLAN encapsulated packets.
+ */
+
+#include <sys/vxlan.h>
+#include "snoop.h"
+
+int
+interpret_vxlan(int flags, char *data, int fraglen)
+{
+ vxlan_hdr_t *vxlan = (vxlan_hdr_t *)data;
+ uint32_t id, vxf;
+
+ if (fraglen < sizeof (vxlan_hdr_t)) {
+ if (flags & F_SUM)
+ (void) snprintf(get_sum_line(), MAXLINE,
+ "VXLAN RUNT");
+ if (flags & F_DTAIL)
+ show_header("VXLAN RUNT: ", "Short packet", fraglen);
+
+ return (fraglen);
+ }
+
+ id = ntohl(vxlan->vxlan_id) >> VXLAN_ID_SHIFT;
+ vxf = ntohl(vxlan->vxlan_flags);
+
+ if (flags & F_SUM) {
+ (void) snprintf(get_sum_line(), MAXLINE,
+ "VXLAN VNI=%d", id);
+ }
+
+ if (flags & F_DTAIL) {
+ show_header("VXLAN: ", "VXLAN Header", sizeof (vxlan_hdr_t));
+ show_space();
+ (void) snprintf(get_line(0, 0), get_line_remain(),
+ "Flags = 0x%08x", vxf);
+ (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
+ getflag(vxf >> 24, VXLAN_F_VDI >> 24, "vni present",
+ "vni missing"));
+ (void) snprintf(get_line(0, 0), get_line_remain(),
+ "VXLAN network id (VNI) = %d", id);
+ show_space();
+ }
+
+ if (flags & (F_DTAIL | F_ALLSUM)) {
+ fraglen -= sizeof (vxlan_hdr_t);
+ data += sizeof (vxlan_hdr_t);
+
+ return (interpret_ether(flags, data, fraglen, fraglen));
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/column/Makefile b/usr/src/cmd/column/Makefile
new file mode 100644
index 0000000000..b9b395b384
--- /dev/null
+++ b/usr/src/cmd/column/Makefile
@@ -0,0 +1,34 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+PROG=column
+OBJS=column.o
+
+include ../Makefile.cmd
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_PROG
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/column/THIRDPARTYLICENSE b/usr/src/cmd/column/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..a80f56cb43
--- /dev/null
+++ b/usr/src/cmd/column/THIRDPARTYLICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 1989, 1993, 1994
+ The Regents of the University of California. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+4. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+ *
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/usr/src/cmd/column/THIRDPARTYLICENSE.descrip b/usr/src/cmd/column/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..42051a2982
--- /dev/null
+++ b/usr/src/cmd/column/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+PORTIONS OF COLUMN COMMAND FUNCTIONALITY
diff --git a/usr/src/cmd/column/column.c b/usr/src/cmd/column/column.c
new file mode 100644
index 0000000000..5c76cb8751
--- /dev/null
+++ b/usr/src/cmd/column/column.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Portions Copyright 2018 Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/termios.h>
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define TAB 8
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
+
+static void c_columnate(void);
+static void input(FILE *);
+static void maketbl(void);
+static void print(void);
+static void r_columnate(void);
+static void usage(void);
+static int width(const wchar_t *);
+
+static int termwidth = 80; /* default terminal width */
+
+static int entries; /* number of records */
+static int eval; /* exit value */
+static int maxlength; /* longest record */
+static wchar_t **list; /* array of pointers to records */
+static const wchar_t *separator = L"\t "; /* field separator for table option */
+
+int
+main(int argc, char **argv)
+{
+ struct winsize win;
+ FILE *fp;
+ int ch, tflag, xflag;
+ char *p;
+ const char *src;
+ wchar_t *newsep;
+ size_t seplen;
+
+ (void) setlocale(LC_ALL, "");
+
+ if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
+ if ((p = getenv("COLUMNS")))
+ termwidth = atoi(p);
+ } else
+ termwidth = win.ws_col;
+
+ tflag = xflag = 0;
+ while ((ch = getopt(argc, argv, "c:s:tx")) != -1)
+ switch (ch) {
+ case 'c':
+ termwidth = atoi(optarg);
+ break;
+ case 's':
+ src = optarg;
+ seplen = mbsrtowcs(NULL, &src, 0, NULL);
+ if (seplen == (size_t)-1)
+ err(1, "bad separator");
+ newsep = malloc((seplen + 1) * sizeof (wchar_t));
+ if (newsep == NULL)
+ err(1, NULL);
+ (void) mbsrtowcs(newsep, &src, seplen + 1, NULL);
+ separator = newsep;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!*argv)
+ input(stdin);
+ else for (; *argv; ++argv)
+ if ((fp = fopen(*argv, "rF"))) {
+ input(fp);
+ (void) fclose(fp);
+ } else {
+ warn("%s", *argv);
+ eval = 1;
+ }
+
+ if (!entries)
+ exit(eval);
+
+ maxlength = roundup(maxlength + 1, TAB);
+ if (tflag)
+ maketbl();
+ else if (maxlength >= termwidth)
+ print();
+ else if (xflag)
+ c_columnate();
+ else
+ r_columnate();
+ exit(eval);
+
+ /*NOTREACHED*/
+ return (eval);
+}
+
+static void
+c_columnate(void)
+{
+ int chcnt, col, cnt, endcol, numcols;
+ wchar_t **lp;
+
+ numcols = termwidth / maxlength;
+ endcol = maxlength;
+ for (chcnt = col = 0, lp = list; ; ++lp) {
+ (void) wprintf(L"%ls", *lp);
+ chcnt += width(*lp);
+ if (!--entries)
+ break;
+ if (++col == numcols) {
+ chcnt = col = 0;
+ endcol = maxlength;
+ (void) putwchar('\n');
+ } else {
+ while ((cnt = roundup(chcnt + 1, TAB)) <= endcol) {
+ (void) putwchar('\t');
+ chcnt = cnt;
+ }
+ endcol += maxlength;
+ }
+ }
+ if (chcnt)
+ (void) putwchar('\n');
+}
+
+static void
+r_columnate(void)
+{
+ int base, chcnt, cnt, col, endcol, numcols, numrows, row;
+
+ numcols = termwidth / maxlength;
+ numrows = entries / numcols;
+ if (entries % numcols)
+ ++numrows;
+
+ for (row = 0; row < numrows; ++row) {
+ endcol = maxlength;
+ for (base = row, chcnt = col = 0; col < numcols; ++col) {
+ (void) wprintf(L"%ls", list[base]);
+ chcnt += width(list[base]);
+ if ((base += numrows) >= entries)
+ break;
+ while ((cnt = roundup(chcnt + 1, TAB)) <= endcol) {
+ (void) putwchar('\t');
+ chcnt = cnt;
+ }
+ endcol += maxlength;
+ }
+ (void) putwchar('\n');
+ }
+}
+
+static void
+print(void)
+{
+ int cnt;
+ wchar_t **lp;
+
+ for (cnt = entries, lp = list; cnt--; ++lp)
+ (void) wprintf(L"%ls\n", *lp);
+}
+
+typedef struct _tbl {
+ wchar_t **list;
+ int cols, *len;
+} TBL;
+#define DEFCOLS 25
+
+static void
+maketbl(void)
+{
+ TBL *t;
+ int coloff, cnt;
+ wchar_t *p, **lp;
+ int *lens, maxcols;
+ TBL *tbl;
+ wchar_t **cols;
+ wchar_t *last;
+
+ if ((t = tbl = calloc(entries, sizeof (TBL))) == NULL)
+ err(1, (char *)NULL);
+ if ((cols = calloc((maxcols = DEFCOLS), sizeof (*cols))) == NULL)
+ err(1, (char *)NULL);
+ if ((lens = calloc(maxcols, sizeof (int))) == NULL)
+ err(1, (char *)NULL);
+ for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
+ for (coloff = 0, p = *lp;
+ (cols[coloff] = wcstok(p, separator, &last));
+ p = NULL)
+ if (++coloff == maxcols) {
+ if (!(cols = realloc(cols, ((uint_t)maxcols +
+ DEFCOLS) * sizeof (char *))) ||
+ !(lens = realloc(lens,
+ ((uint_t)maxcols + DEFCOLS) *
+ sizeof (int))))
+ err(1, NULL);
+ (void) memset((char *)lens + maxcols *
+ sizeof (int), 0, DEFCOLS * sizeof (int));
+ maxcols += DEFCOLS;
+ }
+ if ((t->list = calloc(coloff, sizeof (*t->list))) == NULL)
+ err(1, (char *)NULL);
+ if ((t->len = calloc(coloff, sizeof (int))) == NULL)
+ err(1, (char *)NULL);
+ for (t->cols = coloff; --coloff >= 0; ) {
+ t->list[coloff] = cols[coloff];
+ t->len[coloff] = width(cols[coloff]);
+ if (t->len[coloff] > lens[coloff])
+ lens[coloff] = t->len[coloff];
+ }
+ }
+ for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) {
+ for (coloff = 0; coloff < t->cols - 1; ++coloff)
+ (void) wprintf(L"%ls%*ls", t->list[coloff],
+ lens[coloff] - t->len[coloff] + 2, L" ");
+ (void) wprintf(L"%ls\n", t->list[coloff]);
+ }
+}
+
+#define DEFNUM 1000
+#define MAXLINELEN (LINE_MAX + 1)
+
+static void
+input(FILE *fp)
+{
+ static int maxentry;
+ int len;
+ wchar_t *p, buf[MAXLINELEN];
+
+ if (!list)
+ if ((list = calloc((maxentry = DEFNUM), sizeof (*list))) ==
+ NULL)
+ err(1, (char *)NULL);
+ while (fgetws(buf, MAXLINELEN, fp)) {
+ for (p = buf; *p && iswspace(*p); ++p)
+ ;
+ if (!*p)
+ continue;
+ if (!(p = wcschr(p, L'\n'))) {
+ warnx("line too long");
+ eval = 1;
+ continue;
+ }
+ *p = L'\0';
+ len = width(buf);
+ if (maxlength < len)
+ maxlength = len;
+ if (entries == maxentry) {
+ maxentry += DEFNUM;
+ if (!(list = realloc(list,
+ (uint_t)maxentry * sizeof (*list))))
+ err(1, NULL);
+ }
+ list[entries] = malloc((wcslen(buf) + 1) * sizeof (wchar_t));
+ if (list[entries] == NULL)
+ err(1, NULL);
+ (void) wcscpy(list[entries], buf);
+ entries++;
+ }
+}
+
+/* Like wcswidth(), but ignores non-printing characters. */
+static int
+width(const wchar_t *wcs)
+{
+ int w, cw;
+
+ for (w = 0; *wcs != L'\0'; wcs++)
+ if ((cw = wcwidth(*wcs)) > 0)
+ w += cw;
+ return (w);
+}
+
+static void
+usage(void)
+{
+
+ (void) fprintf(stderr,
+ "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");
+ exit(1);
+}
diff --git a/usr/src/cmd/connstat/connstat_tcp.c b/usr/src/cmd/connstat/connstat_tcp.c
index 4cd20c9b09..bcf2c2ef5b 100644
--- a/usr/src/cmd/connstat/connstat_tcp.c
+++ b/usr/src/cmd/connstat/connstat_tcp.c
@@ -14,6 +14,7 @@
*/
/*
* Copyright (c) 2015, 2016 by Delphix. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <stdio.h>
@@ -77,6 +78,7 @@ typedef struct tcp_fields_buf_s {
uint64_t t_rtt_sum;
int t_state;
uint64_t t_rtt;
+ uint64_t t_rttvar;
} tcp_fields_buf_t;
static boolean_t print_tcp_state(ofmt_arg_t *, char *, uint_t);
@@ -126,6 +128,8 @@ static ofmt_field_t tcp_fields[] = {
offsetof(tcp_fields_buf_t, t_rtt_sum), print_uint64 },
{ "RTTC", 11,
offsetof(tcp_fields_buf_t, t_rtt_cnt), print_uint32 },
+ { "RTTVAR", 8,
+ offsetof(tcp_fields_buf_t, t_rttvar), print_uint64 },
{ "STATE", 12,
offsetof(tcp_fields_buf_t, t_state), print_tcp_state },
{ NULL, 0, 0, NULL}
@@ -189,6 +193,7 @@ tcp_ci2buf(struct tcpConnEntryInfo_s *ci)
fields_buf.t_rtt = (ci->ce_out_data_segs == 0 ? 0 : ci->ce_rtt_sa);
fields_buf.t_rtt_sum = ci->ce_rtt_sum;
fields_buf.t_rtt_cnt = ci->ce_rtt_cnt;
+ fields_buf.t_rttvar = ci->ce_rtt_sd;
fields_buf.t_state = ci->ce_state;
}
diff --git a/usr/src/cmd/coreadm/coreadm.c b/usr/src/cmd/coreadm/coreadm.c
index ca7edc179e..23916a7c06 100644
--- a/usr/src/cmd/coreadm/coreadm.c
+++ b/usr/src/cmd/coreadm/coreadm.c
@@ -244,6 +244,12 @@ main(int argc, char **argv)
command);
usage();
}
+ if (glob_pattern != NULL && glob_pattern[0] != '/') {
+ (void) fprintf(stderr, gettext(
+ "%s: The -g option must specify an absolute path\n"),
+ command);
+ usage();
+ }
if ((proc_pattern != NULL || proc_content != CC_CONTENT_INVALID) &&
npids == 0) {
(void) sprintf(curpid, "%u", (uint_t)getppid());
diff --git a/usr/src/cmd/coreadm/coreadm.xml b/usr/src/cmd/coreadm/coreadm.xml
index 46a4cda17a..c6198f885a 100644
--- a/usr/src/cmd/coreadm/coreadm.xml
+++ b/usr/src/cmd/coreadm/coreadm.xml
@@ -92,17 +92,17 @@
value='solaris.smf.value.coreadm' />
<propval name='global_pattern'
- type='astring' value='' />
+ type='astring' value='/%Z/cores/core.%f.%p' />
<propval name='global_content'
type='astring' value='default' />
<propval name='init_pattern'
- type='astring' value='core' />
+ type='astring' value='/%Z/cores/core.%f.%p' />
<propval name='init_content'
type='astring' value='default' />
<propval name='global_enabled'
- type='boolean' value='false' />
- <propval name='process_enabled'
type='boolean' value='true' />
+ <propval name='process_enabled'
+ type='boolean' value='false' />
<propval name='global_setid_enabled'
type='boolean' value='false' />
<propval name='process_setid_enabled'
diff --git a/usr/src/cmd/cron/Makefile b/usr/src/cmd/cron/Makefile
index 8e9a95060d..3e1eebe136 100644
--- a/usr/src/cmd/cron/Makefile
+++ b/usr/src/cmd/cron/Makefile
@@ -28,6 +28,7 @@
DEFAULTFILES = cron.dfl
include ../Makefile.cmd
+include ../Makefile.ctf
MANIFEST = cron.xml
@@ -48,6 +49,7 @@ ROOTVAR = $(ROOT)/var
ROOTSPCRON = $(ROOTVAR)/spool/cron
ROOTCROND = $(ROOTETC)/cron.d
+ROOTCRONDCRONTABS = $(ROOTCROND)/crontabs
ROOTCRONTABS = $(ROOTSPCRON)/crontabs
ROOTATJOBS = $(ROOTSPCRON)/atjobs
ROOTLIBCRON = $(ROOTLIB)/cron
@@ -67,9 +69,6 @@ POFILES1= at.po crontab.po funcs.po batch.po
POFILES= $(POFILES1) atrm.po
$(POFILES1) := XGETFLAGS= -a -x $(PROG1).xcl
-ROOTDIRS = $(ROOTSPCRON) $(ROOTCROND) \
- $(ROOTCRONTABS) $(ROOTATJOBS)
-
ROOTPROG = $(PROG1:%=$(ROOTUSRSBIN)/%) $(PROG2:%=$(ROOTBIN)/%) \
$(SCRIPT:%=$(ROOTBIN)/%) \
$(XPG6PROG:%=$(ROOTXPG6BIN)/%) \
@@ -103,21 +102,21 @@ XPG4ATOBJS= $(ATOBJS:%=objs.xpg4/%) $(XPG4OBJS:%=objs.xpg4/%)
XPG6COMMONOBJS= $(COMMONOBJS:%=objs.xpg6/%)
XPG6CTOBJS= $(CRONTABOBJS:%=objs.xpg6/%)
-cron := POBJS = $(CRONOBJS) $(COMMONOBJ2)
-at := POBJS = $(ATOBJS) $(COMMONOBJS)
-at.xpg4 := POBJS = $(XPG4ATOBJS) $(XPG4COMMONOBJS)
-atrm := POBJS = $(ATRMOBJS) $(COMMONOBJS)
-atq := POBJS = $(ATQOBJS) $(COMMONOBJS)
-crontab := POBJS = $(CRONTABOBJS) $(COMMONOBJS)
-crontab.xpg4 := POBJS = $(XPG4CTOBJS) $(XPG4COMMONOBJS)
-crontab.xpg6 := POBJS = $(XPG6CTOBJS) $(XPG6COMMONOBJS)
-parsetest := POBJS = $(PARSETESTOBJS)
+cron := OBJS = $(CRONOBJS) $(COMMONOBJ2)
+at := OBJS = $(ATOBJS) $(COMMONOBJS)
+at.xpg4 := OBJS = $(XPG4ATOBJS) $(XPG4COMMONOBJS)
+atrm := OBJS = $(ATRMOBJS) $(COMMONOBJS)
+atq := OBJS = $(ATQOBJS) $(COMMONOBJS)
+crontab := OBJS = $(CRONTABOBJS) $(COMMONOBJS)
+crontab.xpg4 := OBJS = $(XPG4CTOBJS) $(XPG4COMMONOBJS)
+crontab.xpg6 := OBJS = $(XPG6CTOBJS) $(XPG6COMMONOBJS)
+parsetest := OBJS = $(PARSETESTOBJS)
CFLAGS += $(CCVERBOSE)
NOBJS= $(CRONOBJS) $(ATOBJS) $(ATRMOBJS1) $(ATQOBJS) $(CRONTABOBJS1) \
$(COMMONOBJS)
-OBJS = $(NOBJS) $(XPG4COMMONOBJS) $(XPG4ATOBJS) $(XPG4CTOBJS) \
+COBJS = $(NOBJS) $(XPG4COMMONOBJS) $(XPG4ATOBJS) $(XPG4CTOBJS) \
$(XPG6COMMONOBJS) $(XPG6CTOBJS) $(GETRESPOBJ)
SRCS = $(NOBJS:%.o=%.c) $(GETRESPSRC)
@@ -160,34 +159,37 @@ all : $(PROG) $(XPG4) $(XPG6) $(SCRIPT) $(XPG4SCRIPT) $(FILES) \
$(PARSETEST)
install : all $(ROOTPROG) $(ROOTETCDEFAULTFILES) $(ROOTSYMLINK) \
- $(ROOTMANIFEST) $(ROOTMETHOD)
+ $(ROOTMANIFEST) $(ROOTMETHOD) $(ROOTCRONDCRONTABS)/root
-$(PROG) $(PARSETEST): $$(POBJS)
- $(LINK.c) $(POBJS) -o $@ $(LDLIBS)
+$(PROG) $(PARSETEST): $$(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
$(POST_PROCESS)
-$(XPG4) : objs.xpg4 $$(POBJS)
- $(LINK.c) $(POBJS) -o $@ $(LDLIBS)
+$(XPG4) : objs.xpg4 $$(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
$(POST_PROCESS)
-$(XPG6) : objs.xpg6 $$(POBJS)
- $(LINK.c) $(POBJS) -o $@ $(LDLIBS)
+$(XPG6) : objs.xpg6 $$(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
$(POST_PROCESS)
objs.xpg6/%.o: %.c
$(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
objs.xpg6:
-@mkdir -p $@
objs.xpg4/%.o: %.c
$(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
objs.xpg4:
-@mkdir -p $@
objs.xpg4/values-xpg4.o: ../../lib/crt/common/values-xpg4.c
$(COMPILE.c) -o $@ ../../lib/crt/common/values-xpg4.c
+ $(POST_PROCESS_O)
%.o: $(SRC)/common/util/%.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
@@ -211,20 +213,21 @@ att2.c : att2.l att2.ed att1.c
ed - lex.yy.c < att2.ed
$(MV) lex.yy.c att2.c
-# Don't re-install directories installed by Targetdirs
-#$(ROOTDIRS):
-# $(INS.dir)
-
$(ROOTSYMLINK) :
$(RM) $@; $(SYMLINK) $(SYMLNKDEST) $@
+$(ROOTCRONDCRONTABS)/root: crontab.root
+ $(RM) $@; \
+ $(INS) -s -m $(FILEMODE) -f $(@D) crontab.root; \
+ $(MV) $(@D)/crontab.root $@
+
check: $(CHKMANIFEST)
$(POFILE): $(POFILES)
$(RM) $@; cat $(POFILES) > $@
clean :
- $(RM) $(OBJS) att1.h att1.c att2.c
+ $(RM) $(COBJS) att1.h att1.c att2.c
strip :
$(STRIP) $(PROG) $(XPG4) $(XPG6)
diff --git a/usr/src/cmd/cron/cron.c b/usr/src/cmd/cron/cron.c
index faefcbebd0..8b549c3f0d 100644
--- a/usr/src/cmd/cron/cron.c
+++ b/usr/src/cmd/cron/cron.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*
* Copyright 2013 Joshua M. Clulow <josh@sysmgr.org>
- *
+ * Copyright 2013 Joyent, Inc. All rights reserved.
* Copyright (c) 2014 Gary Mills
* Copyright (c) 2016 by Delphix. All rights reserved.
* Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
@@ -311,7 +311,8 @@ static struct usr *find_usr(char *);
static int ex(struct event *e);
static void read_dirs(int);
static void mail(char *, char *, int);
-static void readcron(struct usr *, time_t);
+static void readcron(char *, struct usr *, time_t);
+static void readcronfile(FILE *, struct usr *, time_t);
static int next_ge(int, char *);
static void free_if_unused(struct usr *);
static void del_atjob(char *, char *);
@@ -416,7 +417,7 @@ extern void el_delete(void);
static int valid_entry(char *, int);
static struct usr *create_ulist(char *, int);
-static void init_cronevent(char *, int);
+static void init_cronevent(char *, char *);
static void init_atevent(char *, time_t, int, int);
static void update_atevent(struct usr *, char *, time_t, int);
@@ -755,6 +756,18 @@ read_dirs(int first)
time_t tim;
+ if (chdir(SYSCRONDIR) != -1) {
+ cwd = CRON;
+ if ((dir = opendir(".")) != NULL) {
+ while ((dp = readdir(dir)) != NULL) {
+ if (!valid_entry(dp->d_name, CRONEVENT))
+ continue;
+ init_cronevent(SYSCRONDIR, dp->d_name);
+ }
+ (void) closedir(dir);
+ }
+ }
+
if (chdir(CRONDIR) == -1)
crabort(BADCD, REMOVE_FIFO|CONSOLE_MSG);
cwd = CRON;
@@ -763,7 +776,7 @@ read_dirs(int first)
while ((dp = readdir(dir)) != NULL) {
if (!valid_entry(dp->d_name, CRONEVENT))
continue;
- init_cronevent(dp->d_name, first);
+ init_cronevent(CRONDIR, dp->d_name);
}
(void) closedir(dir);
@@ -849,23 +862,18 @@ create_ulist(char *name, int type)
}
void
-init_cronevent(char *name, int first)
+init_cronevent(char *basedir, char *name)
{
struct usr *u;
- if (first) {
+ if ((u = find_usr(name)) == NULL) {
u = create_ulist(name, CRONEVENT);
- readcron(u, 0);
+ readcron(basedir, u, 0);
} else {
- if ((u = find_usr(name)) == NULL) {
- u = create_ulist(name, CRONEVENT);
- readcron(u, 0);
- } else {
- u->ctexists = TRUE;
- rm_ctevents(u);
- el_remove(u->ctid, 0);
- readcron(u, 0);
- }
+ u->ctexists = TRUE;
+ rm_ctevents(u);
+ el_remove(u->ctid, 0);
+ readcron(basedir, u, 0);
}
}
@@ -946,7 +954,7 @@ mod_ctab(char *name, time_t reftime)
(void) strcpy(u->home, pw->pw_dir);
u->uid = pw->pw_uid;
u->gid = pw->pw_gid;
- readcron(u, reftime);
+ readcron(CRONDIR, u, reftime);
} else {
u->uid = pw->pw_uid;
u->gid = pw->pw_gid;
@@ -969,7 +977,7 @@ mod_ctab(char *name, time_t reftime)
/* user didnt have a crontab last time */
u->ctid = ecid++;
u->ctevents = NULL;
- readcron(u, reftime);
+ readcron(CRONDIR, u, reftime);
return;
}
#ifdef DEBUG
@@ -978,7 +986,7 @@ mod_ctab(char *name, time_t reftime)
#endif
rm_ctevents(u);
el_remove(u->ctid, 0);
- readcron(u, reftime);
+ readcron(CRONDIR, u, reftime);
}
}
@@ -1112,8 +1120,94 @@ update_atevent(struct usr *u, char *name, time_t tim, int jobtype)
static char line[CTLINESIZE]; /* holds a line from a crontab file */
static int cursor; /* cursor for the above line */
+static int
+copyfile(char *name, FILE *dp)
+{
+ FILE *tf;
+
+ if ((tf = fopen(name, "r")) == NULL) {
+ (void) fclose(dp);
+ return (1);
+ }
+
+ while (fgets(line, CTLINESIZE, tf) != NULL) {
+ if (fputs(line, dp) == EOF) {
+ (void) fclose(tf);
+ (void) fclose(dp);
+ return (1);
+ }
+ }
+ (void) fclose(tf);
+
+ return (0);
+}
+
+static void
+readcron(char *basedir, struct usr *u, time_t reftime)
+{
+ char *altpath;
+ struct stat sb;
+ FILE *cf; /* cf will be a user's crontab file */
+ char altnamebuf[PATH_MAX];
+ char namebuf[PATH_MAX];
+
+ if (strcmp(basedir, SYSCRONDIR) == 0)
+ altpath = CRONDIR;
+ else
+ altpath = SYSCRONDIR;
+
+ if (snprintf(altnamebuf, sizeof (altnamebuf), "%s/%s", altpath,
+ u->name) >= sizeof (altnamebuf))
+ return;
+
+ if (snprintf(namebuf, sizeof (namebuf), "%s/%s", basedir, u->name) >=
+ sizeof (namebuf))
+ return;
+
+ if (stat(altnamebuf, &sb) != -1) {
+ /*
+ * There is a secondary crontab for this user. We need to
+ * merge the two crontabs into a temporary file for loading.
+ */
+ int fd;
+ char tmpfile[PATH_MAX];
+
+ (void) strlcpy(tmpfile, "/tmp/cronXXXXXX", sizeof (tmpfile));
+ if ((fd = mkstemp(tmpfile)) == -1)
+ return;
+
+ unlink(tmpfile);
+ if ((cf = fdopen(fd, "w+")) == NULL) {
+ close(fd);
+ return;
+ }
+
+ if (copyfile(namebuf, cf) != 0)
+ return;
+
+ if (copyfile(altnamebuf, cf) != 0)
+ return;
+
+ (void) fflush(cf);
+ rewind(cf);
+
+ } else {
+ /*
+ * Only one crontab, open it directly.
+ */
+ if ((cf = fopen(namebuf, "r")) == NULL) {
+ mail(u->name, NOREAD, ERR_UNIXERR);
+ return;
+ }
+ }
+
+ readcronfile(cf, u, reftime);
+
+ (void) fclose(cf);
+}
+
static void
-readcron(struct usr *u, time_t reftime)
+readcronfile(FILE *cf, struct usr *u, time_t reftime)
{
/*
* readcron reads in a crontab file for a user (u). The list of
@@ -1121,12 +1215,9 @@ readcron(struct usr *u, time_t reftime)
* this list. Each event is also entered into the main event
* list.
*/
- FILE *cf; /* cf will be a user's crontab file */
struct event *e;
int start;
unsigned int i;
- char namebuf[PATH_MAX];
- char *pname;
struct shared *tz = NULL;
struct shared *home = NULL;
struct shared *shell = NULL;
@@ -1134,19 +1225,6 @@ readcron(struct usr *u, time_t reftime)
/* read the crontab file */
cte_init(); /* Init error handling */
- if (cwd != CRON) {
- if (snprintf(namebuf, sizeof (namebuf), "%s/%s",
- CRONDIR, u->name) >= sizeof (namebuf)) {
- return;
- }
- pname = namebuf;
- } else {
- pname = u->name;
- }
- if ((cf = fopen(pname, "r")) == NULL) {
- mail(u->name, NOREAD, ERR_UNIXERR);
- return;
- }
while (fgets(line, CTLINESIZE, cf) != NULL) {
char *tmp;
/* process a line of a crontab file */
@@ -1282,7 +1360,6 @@ again:
#endif
}
cte_sendmail(u->name); /* mail errors if any to user */
- (void) fclose(cf);
rel_shared(tz);
rel_shared(shell);
rel_shared(home);
@@ -2384,6 +2461,9 @@ ex(struct event *e)
} else {
r = audit_cron_session(e->u->name, CRONDIR,
e->u->uid, e->u->gid, NULL);
+ if (r != 0)
+ r = audit_cron_session(e->u->name, SYSCRONDIR,
+ e->u->uid, e->u->gid, NULL);
}
if (r != 0) {
msg("cron audit problem. job failed (%s) for user %s",
diff --git a/usr/src/cmd/cron/cron.h b/usr/src/cmd/cron/cron.h
index e071209673..0620572f8c 100644
--- a/usr/src/cmd/cron/cron.h
+++ b/usr/src/cmd/cron/cron.h
@@ -75,6 +75,10 @@ struct message {
char logname[LLEN];
};
+/* anything below here can be changed */
+
+#define SYSCRONDIR "/etc/cron.d/crontabs"
+
/*
* Errors from the crontab field parser.
*/
diff --git a/usr/src/cmd/cron/crontab.c b/usr/src/cmd/cron/crontab.c
index 06010aec83..18716bc8c2 100644
--- a/usr/src/cmd/cron/crontab.c
+++ b/usr/src/cmd/cron/crontab.c
@@ -73,8 +73,8 @@
#define BADUSAGE \
"usage:\n" \
"\tcrontab [-u username] [file]\n" \
- "\tcrontab [-u username] { -e | -l | -r }\n" \
- "\tcrontab { -e | -l | -r } [username]"
+ "\tcrontab [-u username] { -e | -g | -l | -r }\n" \
+ "\tcrontab { -e | -g | -l | -r } [username]"
#define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)."
#define NOTALLOWED "you are not authorized to use cron. Sorry."
#define NOTROOT \
@@ -122,6 +122,7 @@ main(int argc, char **argv)
int c, r;
int rflag = 0;
int lflag = 0;
+ int gflag = 0;
int eflag = 0;
int errflg = 0;
char *pp;
@@ -154,11 +155,14 @@ main(int argc, char **argv)
exit(1);
}
- while ((c = getopt(argc, argv, "elru:")) != EOF) {
+ while ((c = getopt(argc, argv, "eglru:")) != EOF) {
switch (c) {
case 'e':
eflag++;
break;
+ case 'g':
+ gflag++;
+ break;
case 'l':
lflag++;
break;
@@ -180,6 +184,9 @@ main(int argc, char **argv)
if (eflag + lflag + rflag > 1)
errflg++;
+ if (gflag && !lflag)
+ errflg++;
+
if ((eflag || lflag || rflag) && argc > 0) {
if (user != NULL)
errflg++;
@@ -253,12 +260,27 @@ main(int argc, char **argv)
exit(0);
}
if (lflag) {
- if ((fp = fopen(cf, "r")) == NULL)
- crabort(BADOPEN);
- while (fgets(line, CTLINESIZE, fp) != NULL)
- fputs(line, stdout);
- fclose(fp);
- exit(0);
+ char sysconf[PATH_MAX];
+
+ if (gflag) {
+ if (snprintf(sysconf, sizeof (sysconf), "%s/%s",
+ SYSCRONDIR, login) < sizeof (sysconf) &&
+ (fp = fopen(sysconf, "r")) != NULL) {
+ while (fgets(line, CTLINESIZE, fp) != NULL)
+ fputs(line, stdout);
+ fclose(fp);
+ exit(0);
+ } else {
+ crabort(BADOPEN);
+ }
+ } else {
+ if ((fp = fopen(cf, "r")) == NULL)
+ crabort(BADOPEN);
+ while (fgets(line, CTLINESIZE, fp) != NULL)
+ fputs(line, stdout);
+ fclose(fp);
+ exit(0);
+ }
}
if (eflag) {
if ((fp = fopen(cf, "r")) == NULL) {
diff --git a/usr/src/cmd/cron/crontab.root b/usr/src/cmd/cron/crontab.root
new file mode 100644
index 0000000000..4153ad2d6a
--- /dev/null
+++ b/usr/src/cmd/cron/crontab.root
@@ -0,0 +1,18 @@
+## Rotate and trim the audit logs nightly.
+0 0 * * * /smartdc/bin/sdc-lastcomm -R 30
+## Run logadm hourly so that the minimum rotate interval is 1h
+0 * * * * /usr/sbin/logadm
+## Rotate vm.log files for any KVM VMs
+0 * * * * SDC_LOG_ROLL_BACKWARD=1 /usr/vm/sbin/rotate-kvm-logs.sh >> /var/log/rotate-kvm-logs.log 2>&1
+## Headnode should phone home nightly.
+0 1 * * * [ -x /opt/smartdc/bin/sdc-phonehome ] && /opt/smartdc/bin/sdc-phonehome
+## Delete saved core dumps over 7 days old
+15 0 * * * find /zones/*/cores -type f -mtime +7 -exec rm -f "{}" \;
+## Delete archived zone data over 7 days old
+30 0 * * * find /zones/archive/ -mount -maxdepth 1 -mindepth 1 -type d -mtime +7 -exec rm -rf "{}" \;
+## Delete logs to be uploaded over 7 days old if they aren't being consumed
+45 0 * * * [ -d /var/log/sdc/upload/ ] && find /var/log/sdc/upload/ -mount -maxdepth 1 -mindepth 1 -type f -mtime +7 -exec rm -f "{}" \;
+
+# NOTE: all entries above are in root's system-defined crontab; see the
+# crontab(1) man page.
+
diff --git a/usr/src/cmd/cron/svc-cron b/usr/src/cmd/cron/svc-cron
index 4def6071b8..55033608ee 100644
--- a/usr/src/cmd/cron/svc-cron
+++ b/usr/src/cmd/cron/svc-cron
@@ -22,8 +22,7 @@
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-#
-# ident "%Z%%M% %I% %E% SMI"
+# Copyright 2012 Joyent, Inc. All rights reserved.
#
# Start method script for the cron service.
#
@@ -37,6 +36,45 @@ if [ -p /etc/cron.d/FIFO ]; then
fi
fi
+if smf_is_globalzone && [ -n "$(bootparams | grep '^headnode=true')" ]; then
+ #
+ # Randomize root's crontab so all HN's are not in sync.
+ #
+ utc_offset=`nawk -F= '{if ($1 == "utc_offset") print $2}' \
+ /usbkey/config.inc/generic`
+ [ -z "$utc_offset" ] && utc_offset=0
+
+ n=$(date +%S)
+ hr=$(($n % 5))
+ hr=$(($hr + $utc_offset))
+
+ n=$(date +%M)
+ mn=$(($n % 15))
+
+ nawk -v hr=$hr -v mn=$mn '{
+ if (substr($1, 1, 1) == "#") {
+ print $0
+ next
+ }
+ if (substr($2, 1, 1) == "*") {
+ print $0
+ next
+ }
+ if (length($0) == 0) {
+ print $0
+ next
+ }
+
+ printf("%d %d %s %s %s %s", mn, hr, $3, $4, $5, $6)
+ for (i = 7; i <= NF; i++)
+ printf(" %s", $i)
+ printf("\n")
+ mn += 10
+ }' /etc/cron.d/crontabs/root >/etc/cron.d/crontabs/root.$$
+ cp /etc/cron.d/crontabs/root.$$ /etc/cron.d/crontabs/root
+ rm -f /etc/cron.d/crontabs/root.$$
+fi
+
if [ -x /usr/sbin/cron ]; then
/usr/bin/rm -f /etc/cron.d/FIFO
/usr/sbin/cron &
diff --git a/usr/src/cmd/devfsadm/devlink.tab.sh b/usr/src/cmd/devfsadm/devlink.tab.sh
index 6724fcb573..0267efeb9f 100644
--- a/usr/src/cmd/devfsadm/devlink.tab.sh
+++ b/usr/src/cmd/devfsadm/devlink.tab.sh
@@ -22,8 +22,7 @@
#
# Copyright (c) 1998, 2000 by Sun Microsystems, Inc.
# All rights reserved.
-#
-#ident "%Z%%M% %I% %E% SMI"
+# Copyright (c) 2012 Joyent, Inc. All rights reserved.
#
# This is the script that generates the devlink.tab file. It is
# architecture-aware, and dumps different stuff for x86 and sparc.
@@ -34,8 +33,6 @@
#
cat <<EOM
-#ident "%Z%%M% %I% %E% SMI"
-#
# Copyright (c) 1998 by Sun Microsystems, Inc.
#
#
diff --git a/usr/src/cmd/devfsadm/i386/Makefile b/usr/src/cmd/devfsadm/i386/Makefile
index 1f14c93dad..75f2da3436 100644
--- a/usr/src/cmd/devfsadm/i386/Makefile
+++ b/usr/src/cmd/devfsadm/i386/Makefile
@@ -24,8 +24,11 @@
LINK_OBJS_i386 = \
misc_link_i386.o \
+ lx_link_i386.o \
xen_link.o
+lx_link_i386.o lx_link_i386.po lx_link_i386.ln := CPPFLAGS += -I$(UTSBASE)/common/brand/lx
+
xen_link.o xen_link.ln xen_link.po := CPPFLAGS += -I$(UTSBASE)/i86xpv
include ../Makefile.com
diff --git a/usr/src/cmd/devfsadm/i386/lx_link_i386.c b/usr/src/cmd/devfsadm/i386/lx_link_i386.c
new file mode 100644
index 0000000000..b99a8361a0
--- /dev/null
+++ b/usr/src/cmd/devfsadm/i386/lx_link_i386.c
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <devfsadm.h>
+#include <strings.h>
+#include <stdio.h>
+#include <sys/lx_ptm.h>
+#include <sys/lx_autofs.h>
+
+static int lx_ptm(di_minor_t minor, di_node_t node);
+static int lx_autofs(di_minor_t minor, di_node_t node);
+static int lx_systrace(di_minor_t minor, di_node_t node);
+
+static devfsadm_create_t lx_create_cbt[] = {
+ { "pseudo", "ddi_pseudo", LX_PTM_DRV,
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, lx_ptm },
+ { "pseudo", "ddi_pseudo", LX_AUTOFS_NAME,
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, lx_autofs },
+ { "pseudo", "ddi_pseudo", "lx_systrace",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, lx_systrace },
+};
+
+DEVFSADM_CREATE_INIT_V0(lx_create_cbt);
+
+static int
+lx_ptm(di_minor_t minor, di_node_t node)
+{
+ char *mname = di_minor_name(minor);
+
+ if (strcmp(LX_PTM_MINOR_NODE, mname) == 0)
+ (void) devfsadm_mklink("brand/lx/ptmx", node, minor, 0);
+
+ return (DEVFSADM_CONTINUE);
+}
+
+static int
+lx_autofs(di_minor_t minor, di_node_t node)
+{
+ char *mname = di_minor_name(minor);
+
+ if (strcmp(LX_AUTOFS_MINORNAME, mname) == 0)
+ (void) devfsadm_mklink("brand/lx/autofs", node, minor, 0);
+
+ return (DEVFSADM_CONTINUE);
+}
+
+static int
+lx_systrace(di_minor_t minor, di_node_t node)
+{
+ char *mname = di_minor_name(minor);
+ char path[MAXPATHLEN];
+
+ (void) snprintf(path, sizeof (path), "dtrace/provider/%s", mname);
+ (void) devfsadm_mklink(path, node, minor, 0);
+
+ return (DEVFSADM_CONTINUE);
+}
diff --git a/usr/src/cmd/devfsadm/misc_link.c b/usr/src/cmd/devfsadm/misc_link.c
index 5f241df296..49be9e9b2d 100644
--- a/usr/src/cmd/devfsadm/misc_link.c
+++ b/usr/src/cmd/devfsadm/misc_link.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <regex.h>
@@ -32,6 +32,7 @@
#include <limits.h>
#include <sys/zone.h>
#include <sys/zcons.h>
+#include <sys/zfd.h>
#include <sys/cpuid_drv.h>
static int display(di_minor_t minor, di_node_t node);
@@ -53,6 +54,7 @@ static int av_create(di_minor_t minor, di_node_t node);
static int tsalarm_create(di_minor_t minor, di_node_t node);
static int ntwdt_create(di_minor_t minor, di_node_t node);
static int zcons_create(di_minor_t minor, di_node_t node);
+static int zfd_create(di_minor_t minor, di_node_t node);
static int cpuid(di_minor_t minor, di_node_t node);
static int glvc(di_minor_t minor, di_node_t node);
static int ses_callback(di_minor_t minor, di_node_t node);
@@ -114,12 +116,15 @@ static devfsadm_create_t misc_cbt[] = {
"(^nca$)|(^rds$)|(^sdp$)|(^ipnet$)|(^dlpistub$)|(^bpf$)",
TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name
},
+ { "pseudo", "ddi_pseudo", "inotify",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
+ },
{ "pseudo", "ddi_pseudo", "ipd",
TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
},
{ "pseudo", "ddi_pseudo",
"(^ipf$)|(^ipnat$)|(^ipstate$)|(^ipauth$)|"
- "(^ipsync$)|(^ipscan$)|(^iplookup$)",
+ "(^ipsync$)|(^ipscan$)|(^iplookup$)|(^ipfev$)",
TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name,
},
{ "pseudo", "ddi_pseudo", "dld",
@@ -180,6 +185,9 @@ static devfsadm_create_t misc_cbt[] = {
{ "pseudo", "ddi_pseudo", "zcons",
TYPE_EXACT | DRV_EXACT, ILEVEL_0, zcons_create,
},
+ { "pseudo", "ddi_pseudo", "zfd",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, zfd_create,
+ },
{ "pseudo", "ddi_pseudo", CPUID_DRIVER_NAME,
TYPE_EXACT | DRV_EXACT, ILEVEL_0, cpuid,
},
@@ -204,6 +212,9 @@ static devfsadm_create_t misc_cbt[] = {
{ "pseudo", "ddi_pseudo", "tpm",
TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
},
+ { "pseudo", "ddi_pseudo", "overlay",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
+ }
};
DEVFSADM_CREATE_INIT_V0(misc_cbt);
@@ -228,6 +239,9 @@ static devfsadm_remove_t misc_remove_cbt[] = {
ZCONS_SLAVE_NAME ")$",
RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
},
+ { "pseudo", "^zfd/" ZONENAME_REGEXP "/(master|slave)/[0-9]+$",
+ RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
+ },
{ "pseudo", "^" CPUID_SELF_NAME "$", RM_ALWAYS | RM_PRE | RM_HOT,
ILEVEL_0, devfsadm_rm_all
},
@@ -675,6 +689,35 @@ zcons_create(di_minor_t minor, di_node_t node)
return (DEVFSADM_CONTINUE);
}
+static int
+zfd_create(di_minor_t minor, di_node_t node)
+{
+ char *minor_str;
+ char *zonename;
+ int *id;
+ char path[MAXPATHLEN];
+
+ minor_str = di_minor_name(minor);
+
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zfd_zname",
+ &zonename) == -1)
+ return (DEVFSADM_CONTINUE);
+
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "zfd_id", &id) == -1)
+ return (DEVFSADM_CONTINUE);
+
+ if (strncmp(minor_str, "slave", 5) == 0) {
+ (void) snprintf(path, sizeof (path), "zfd/%s/slave/%d",
+ zonename, id[0]);
+ } else {
+ (void) snprintf(path, sizeof (path), "zfd/%s/master/%d",
+ zonename, id[0]);
+ }
+ (void) devfsadm_mklink(path, node, minor, 0);
+
+ return (DEVFSADM_CONTINUE);
+}
+
/*
* /dev/cpu/self/cpuid -> /devices/pseudo/cpuid@0:self
*/
diff --git a/usr/src/cmd/dispadmin/Makefile b/usr/src/cmd/dispadmin/Makefile
index 131b8567f3..93e4ab653d 100644
--- a/usr/src/cmd/dispadmin/Makefile
+++ b/usr/src/cmd/dispadmin/Makefile
@@ -22,12 +22,14 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# cmd/dispadmin/Makefile
+# Copyright 2019 Joyent, Inc.
#
PROG= dispadmin
MANIFEST= scheduler.xml
SVCMETHOD= svc-scheduler
+ETCFILES= dispadmin.conf
+
SDC= SDC$(PROG)
RT= RT$(PROG)
TS= TS$(PROG)
@@ -36,6 +38,8 @@ FSS= FSS$(PROG)
FX= FX$(PROG)
PROGS= $(PROG) $(RT) $(TS) $(IA) $(FSS) $(FX) $(SDC)
+ROOTETCFILES= $(ETCFILES:%=$(ROOTETC)/%)
+
include ../Makefile.cmd
CFLAGS += $(CCVERBOSE)
@@ -59,6 +63,8 @@ ROOTSDC= $(SDC:%=$(ROOTDIR)/SDC/%)
ROOTTS= $(TS:%=$(ROOTDIR)/TS/%)
ROOTMANIFESTDIR= $(ROOTSVCSYSTEM)
+$(ROOTETCFILES) := FILEMODE = 644
+
# this would be simpler if we renamed rtdispadmin.c and tsdispadmin.c
OBJECTS= $(PROG).o rt$(PROG).o ts$(PROG).o ia$(PROG).o \
fss$(PROG).o fx$(PROG).o sdc$(PROG).o subr.o
@@ -83,20 +89,15 @@ $(ROOTDIR)/TS/% : %
$(INS.file)
.KEEP_STATE:
-
-all: $(PROGS)
+
+all: $(PROGS)
$(PROGS): $$(OBJ) subr.o
$(LINK.c) -o $@ $(OBJ) subr.o $(LDLIBS)
$(POST_PROCESS)
-llib-lsubr.ln: subr.c
- $(LINT.c) -y -o subr subr.c
-
-lint := LDLIBS += -L. -lsubr
-
install: all $(ROOTPROG) $(ROOTRT) $(ROOTTS) $(ROOTIA) $(ROOTFSS) $(ROOTFX) \
- $(ROOTSDC) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+ $(ROOTSDC) $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTETCFILES)
# Don't re-install directories already installed by Targetdirs
#$(ROOTDIRS):
@@ -105,15 +106,6 @@ install: all $(ROOTPROG) $(ROOTRT) $(ROOTTS) $(ROOTIA) $(ROOTFSS) $(ROOTFX) \
check: $(CHKMANIFEST)
clean:
- $(RM) $(OBJECTS) $(PROGS) llib-lsubr.ln
-
-lint: llib-lsubr.ln
- $(LINT.c) dispadmin.c $(LDLIBS)
- $(LINT.c) fssdispadmin.c $(LDLIBS)
- $(LINT.c) fxdispadmin.c $(LDLIBS)
- $(LINT.c) iadispadmin.c $(LDLIBS)
- $(LINT.c) rtdispadmin.c $(LDLIBS)
- $(LINT.c) sdcdispadmin.c $(LDLIBS)
- $(LINT.c) tsdispadmin.c $(LDLIBS)
-
+ $(RM) $(OBJECTS) $(PROGS)
+
include ../Makefile.targ
diff --git a/usr/src/cmd/dispadmin/dispadmin.conf b/usr/src/cmd/dispadmin/dispadmin.conf
new file mode 100644
index 0000000000..7970647c62
--- /dev/null
+++ b/usr/src/cmd/dispadmin/dispadmin.conf
@@ -0,0 +1 @@
+DEFAULT_SCHEDULER=FSS
diff --git a/usr/src/cmd/dladm/Makefile b/usr/src/cmd/dladm/Makefile
index 57328597dd..8c93d1008a 100644
--- a/usr/src/cmd/dladm/Makefile
+++ b/usr/src/cmd/dladm/Makefile
@@ -20,6 +20,7 @@
#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2018 Joyent, Inc.
#
# Copyright (c) 2018, Joyent, Inc.
@@ -38,7 +39,7 @@ XGETFLAGS += -a -x $(PROG).xcl
LDLIBS += -L$(ROOT)/lib -lsocket
LDLIBS += -ldladm -ldlpi -lkstat -lsecdb -lbsm -lofmt -linetutil -ldevinfo
-LDLIBS += $(ZLAZYLOAD) -lrstp $(ZNOLAZYLOAD)
+LDLIBS += $(ZLAZYLOAD) -lrstp $(ZNOLAZYLOAD) -lnsl -lumem -lcustr
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-unused-label
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c
index 969bcaddba..c59926be94 100644
--- a/usr/src/cmd/dladm/dladm.c
+++ b/usr/src/cmd/dladm/dladm.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2020 Peter Tribble.
*/
@@ -62,6 +63,7 @@
#include <libdliptun.h>
#include <libdlsim.h>
#include <libdlbridge.h>
+#include <libdloverlay.h>
#include <libinetutil.h>
#include <libvrrpadm.h>
#include <bsm/adt.h>
@@ -77,6 +79,7 @@
#include <stddef.h>
#include <stp_in.h>
#include <ofmt.h>
+#include <libcustr.h>
#define MAXPORT 256
#define MAXVNIC 256
@@ -157,6 +160,7 @@ typedef struct show_vnic_state {
dladm_status_t vs_status;
uint32_t vs_flags;
ofmt_handle_t vs_ofmt;
+ char *vs_zonename;
} show_vnic_state_t;
typedef struct show_part_state {
@@ -187,6 +191,11 @@ typedef struct show_usage_state_s {
ofmt_handle_t us_ofmt;
} show_usage_state_t;
+typedef struct show_overlay_request_s {
+ boolean_t sor_failed;
+ ofmt_handle_t sor_ofmt;
+} show_overlay_request_t;
+
/*
* callback functions for printing output and error diagnostics.
*/
@@ -195,6 +204,7 @@ static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
+static ofmt_cb_t print_overlay_cb, print_overlay_fma_cb, print_overlay_targ_cb;
typedef void cmdfunc_t(int, char **, const char *);
@@ -221,6 +231,8 @@ static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge;
static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge;
static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun;
static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun;
+static cmdfunc_t do_create_overlay, do_delete_overlay, do_modify_overlay;
+static cmdfunc_t do_show_overlay;
static void do_up_vnic_common(int, char **, const char *, boolean_t);
@@ -256,8 +268,11 @@ static void die(const char *, ...);
static void die_optdup(int);
static void die_opterr(int, int, const char *);
static void die_dlerr(dladm_status_t, const char *, ...);
+static void die_dlerrlist(dladm_status_t, dladm_errlist_t *,
+ const char *, ...);
static void warn(const char *, ...);
static void warn_dlerr(dladm_status_t, const char *, ...);
+static void warn_dlerrlist(dladm_errlist_t *);
typedef struct cmd {
char *c_name;
@@ -267,7 +282,7 @@ typedef struct cmd {
static cmd_t cmds[] = {
{ "rename-link", do_rename_link,
- " rename-link <oldlink> <newlink>" },
+ " rename-link [-z zonename] <oldlink> <newlink>" },
{ "show-link", do_show_link,
" show-link [-pP] [-o <field>,..] [-s [-i <interval>]] "
"[<link>]\n" },
@@ -302,12 +317,13 @@ static cmd_t cmds[] = {
{ "show-wifi", do_show_wifi,
" show-wifi [-p] [-o <field>,...] [<link>]\n" },
{ "set-linkprop", do_set_linkprop,
- " set-linkprop [-t] -p <prop>=<value>[,...] <name>" },
+ " set-linkprop [-t] [-z zonename] -p <prop>=<value>[,...] "
+ "<name>" },
{ "reset-linkprop", do_reset_linkprop,
- " reset-linkprop [-t] [-p <prop>,...] <name>" },
+ " reset-linkprop [-t] [-z zonename] [-p <prop>,...] <name>"},
{ "show-linkprop", do_show_linkprop,
- " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] "
- "<name>\n" },
+ " show-linkprop [-cP] [-o <field>,...] [-z zonename] "
+ "[-p <prop>,...] <name>\n" },
{ "show-ether", do_show_ether,
" show-ether [-px][-o <field>,...] <link>\n" },
{ "create-secobj", do_create_secobj,
@@ -349,10 +365,10 @@ static cmd_t cmds[] = {
"\t\t {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n"
"\t\t [-p <prop>=<value>[,...]] <vnic-link>" },
{ "delete-vnic", do_delete_vnic,
- " delete-vnic [-t] <vnic-link>" },
+ " delete-vnic [-t] [-z zonename] <vnic-link>" },
{ "show-vnic", do_show_vnic,
- " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] "
- "[<link>]\n" },
+ " show-vnic [-pP] [-l <link>] [-z zonename] "
+ "[-s [-i <interval>]] [<link>]\n" },
{ "up-vnic", do_up_vnic, NULL },
{ "create-part", do_create_part,
" create-part [-t] [-f] -l <link> [-P <pkey>]\n"
@@ -403,6 +419,17 @@ static cmd_t cmds[] = {
" <bridge>\n"
" show-bridge -t [-p] [-o <field>,...] [-s [-i <interval>]]"
" <bridge>\n" },
+ { "create-overlay", do_create_overlay,
+ " create-overlay [-t] -e <encap> -s <search> -v <vnetid>\n"
+ "\t\t [ -p <prop>=<value>[,...]] <overlay>" },
+ { "delete-overlay", do_delete_overlay,
+ " delete-overlay <overlay>" },
+ { "modify-overlay", do_modify_overlay,
+ " modify-overlay -d mac | -f | -s mac=ip:port "
+ "<overlay>" },
+ { "show-overlay", do_show_overlay,
+ " show-overlay [-f | -t] [[-p] -o <field>,...] "
+ "[<overlay>]\n" },
{ "show-usage", do_show_usage,
" show-usage [-a] [-d | -F <format>] "
"[-s <DD/MM/YYYY,HH:MM:SS>]\n"
@@ -961,6 +988,7 @@ typedef struct show_linkprop_state {
char ls_link[MAXLINKNAMELEN];
char *ls_line;
char **ls_propvals;
+ char *ls_zonename;
dladm_arg_list_t *ls_proplist;
boolean_t ls_parsable;
boolean_t ls_persist;
@@ -1013,21 +1041,24 @@ typedef struct vnic_fields_buf_s
char vnic_macaddr[18];
char vnic_macaddrtype[19];
char vnic_vid[6];
+ char vnic_zone[ZONENAME_MAX];
} vnic_fields_buf_t;
static const ofmt_field_t vnic_fields[] = {
{ "LINK", 13,
offsetof(vnic_fields_buf_t, vnic_link), print_default_cb},
-{ "OVER", 13,
+{ "OVER", 11,
offsetof(vnic_fields_buf_t, vnic_over), print_default_cb},
-{ "SPEED", 7,
+{ "SPEED", 6,
offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb},
{ "MACADDRESS", 18,
offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb},
-{ "MACADDRTYPE", 20,
+{ "MACADDRTYPE", 12,
offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb},
-{ "VID", 7,
+{ "VID", 5,
offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb},
+{ "ZONE", 20,
+ offsetof(vnic_fields_buf_t, vnic_zone), print_default_cb},
{ NULL, 0, 0, NULL}}
;
@@ -1427,6 +1458,82 @@ static ofmt_field_t bridge_trill_fields[] = {
offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb },
{ NULL, 0, 0, NULL}};
+static const struct option overlay_create_lopts[] = {
+ { "encap", required_argument, NULL, 'e' },
+ { "prop", required_argument, NULL, 'p' },
+ { "search", required_argument, NULL, 's' },
+ { "temporary", no_argument, NULL, 't' },
+ { "vnetid", required_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+};
+
+static const struct option overlay_modify_lopts[] = {
+ { "delete-entry", required_argument, NULL, 'd' },
+ { "flush-table", no_argument, NULL, 'f' },
+ { "set-entry", required_argument, NULL, 's' },
+ { NULL, 0, NULL, 0 }
+};
+
+static const struct option overlay_show_lopts[] = {
+ { "fma", no_argument, NULL, 'f' },
+ { "target", no_argument, NULL, 't' },
+ { "parsable", no_argument, NULL, 'p' },
+ { "parseable", no_argument, NULL, 'p' },
+ { "output", required_argument, NULL, 'o' },
+ { NULL, 0, NULL, 0 }
+};
+
+/*
+ * Structures for dladm show-overlay
+ */
+typedef enum {
+ OVERLAY_LINK,
+ OVERLAY_PROPERTY,
+ OVERLAY_PERM,
+ OVERLAY_REQ,
+ OVERLAY_VALUE,
+ OVERLAY_DEFAULT,
+ OVERLAY_POSSIBLE
+} overlay_field_index_t;
+
+static const ofmt_field_t overlay_fields[] = {
+/* name, field width, index */
+{ "LINK", 19, OVERLAY_LINK, print_overlay_cb },
+{ "PROPERTY", 19, OVERLAY_PROPERTY, print_overlay_cb },
+{ "PERM", 5, OVERLAY_PERM, print_overlay_cb },
+{ "REQ", 4, OVERLAY_REQ, print_overlay_cb },
+{ "VALUE", 11, OVERLAY_VALUE, print_overlay_cb },
+{ "DEFAULT", 10, OVERLAY_DEFAULT, print_overlay_cb },
+{ "POSSIBLE", 10, OVERLAY_POSSIBLE, print_overlay_cb },
+{ NULL, 0, 0, NULL }
+};
+
+typedef enum {
+ OVERLAY_FMA_LINK,
+ OVERLAY_FMA_STATUS,
+ OVERLAY_FMA_DETAILS
+} overlay_fma_field_index_t;
+
+static const ofmt_field_t overlay_fma_fields[] = {
+{ "LINK", 20, OVERLAY_FMA_LINK, print_overlay_fma_cb },
+{ "STATUS", 8, OVERLAY_FMA_STATUS, print_overlay_fma_cb },
+{ "DETAILS", 52, OVERLAY_FMA_DETAILS, print_overlay_fma_cb },
+{ NULL, 0, 0, NULL }
+};
+
+typedef enum {
+ OVERLAY_TARG_LINK,
+ OVERLAY_TARG_TARGET,
+ OVERLAY_TARG_DEST
+} overlay_targ_field_index_t;
+
+static const ofmt_field_t overlay_targ_fields[] = {
+{ "LINK", 20, OVERLAY_TARG_LINK, print_overlay_targ_cb },
+{ "TARGET", 18, OVERLAY_TARG_TARGET, print_overlay_targ_cb },
+{ "DESTINATION", 42, OVERLAY_TARG_DEST, print_overlay_targ_cb },
+{ NULL, 0, 0, NULL }
+};
+
static char *progname;
static sig_atomic_t signalled;
@@ -1436,6 +1543,12 @@ static sig_atomic_t signalled;
*/
static dladm_handle_t handle = NULL;
+/*
+ * Global error list that all routines can use. It's initialized by the main
+ * code.
+ */
+static dladm_errlist_t errlist;
+
#define DLADM_ETHERSTUB_NAME "etherstub"
#define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID)
@@ -1486,6 +1599,8 @@ main(int argc, char *argv[])
"could not open /dev/dld");
}
+ dladm_errlist_init(&errlist);
+
cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
dladm_close(handle);
@@ -2497,13 +2612,17 @@ do_rename_link(int argc, char *argv[], const char *use)
char *link1, *link2;
char *altroot = NULL;
dladm_status_t status;
+ char *zonename = NULL;
opterr = 0;
- while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
+ while ((option = getopt_long(argc, argv, ":R:z:", lopts, NULL)) != -1) {
switch (option) {
case 'R':
altroot = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, use);
break;
@@ -2519,7 +2638,7 @@ do_rename_link(int argc, char *argv[], const char *use)
link1 = argv[optind++];
link2 = argv[optind];
- if ((status = dladm_rename_link(handle, link1, link2)) !=
+ if ((status = dladm_rename_link(handle, zonename, link1, link2)) !=
DLADM_STATUS_OK)
die_dlerr(status, "rename operation failed");
}
@@ -3408,11 +3527,12 @@ do_show_link(int argc, char *argv[], const char *use)
ofmt_handle_t ofmt;
ofmt_status_t oferr;
uint_t ofmtflags = 0;
+ char *zonename = NULL;
bzero(&state, sizeof (state));
opterr = 0;
- while ((option = getopt_long(argc, argv, ":pPsi:o:",
+ while ((option = getopt_long(argc, argv, ":pPsi:o:z:",
show_lopts, NULL)) != -1) {
switch (option) {
case 'p':
@@ -3445,6 +3565,9 @@ do_show_link(int argc, char *argv[], const char *use)
if (!dladm_str2interval(optarg, &interval))
die("invalid interval value '%s'", optarg);
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, use);
break;
@@ -3464,8 +3587,8 @@ do_show_link(int argc, char *argv[], const char *use)
if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >=
MAXLINKNAMELEN)
die("link name too long");
- if ((status = dladm_name2info(handle, linkname, &linkid, &f,
- NULL, NULL)) != DLADM_STATUS_OK) {
+ if ((status = dladm_zname2info(handle, zonename, linkname,
+ &linkid, &f, NULL, NULL)) != DLADM_STATUS_OK) {
die_dlerr(status, "link %s is not valid", linkname);
}
@@ -4734,6 +4857,12 @@ do_create_vnic(int argc, char *argv[], const char *use)
if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
die("-f option can only be used with -v");
+ /*
+ * If creating a transient VNIC for a zone, mark it in the kernel.
+ */
+ if (strstr(propstr, "zone=") != NULL && !(flags & DLADM_OPT_PERSIST))
+ flags |= DLADM_OPT_TRANSIENT;
+
if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
usage();
@@ -4778,7 +4907,7 @@ do_create_vnic(int argc, char *argv[], const char *use)
status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af,
- &linkid, proplist, flags);
+ &linkid, proplist, &errlist, flags);
switch (status) {
case DLADM_STATUS_OK:
break;
@@ -4789,7 +4918,8 @@ do_create_vnic(int argc, char *argv[], const char *use)
break;
default:
- die_dlerr(status, "vnic creation over %s failed", devname);
+ die_dlerrlist(status, &errlist, "vnic creation over %s failed",
+ devname);
}
dladm_free_props(proplist);
@@ -4825,9 +4955,10 @@ do_delete_vnic_common(int argc, char *argv[], const char *use,
datalink_id_t linkid;
char *altroot = NULL;
dladm_status_t status;
+ char *zonename = NULL;
opterr = 0;
- while ((option = getopt_long(argc, argv, ":R:t", lopts,
+ while ((option = getopt_long(argc, argv, ":R:tz:", lopts,
NULL)) != -1) {
switch (option) {
case 't':
@@ -4836,6 +4967,9 @@ do_delete_vnic_common(int argc, char *argv[], const char *use,
case 'R':
altroot = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, use);
}
@@ -4848,8 +4982,8 @@ do_delete_vnic_common(int argc, char *argv[], const char *use,
if (altroot != NULL)
altroot_cmd(altroot, argc, argv);
- status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
- NULL);
+ status = dladm_zname2info(handle, zonename, argv[optind], &linkid, NULL,
+ NULL, NULL);
if (status != DLADM_STATUS_OK)
die("invalid link name '%s'", argv[optind]);
@@ -4981,6 +5115,9 @@ print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
char vnic_name[MAXLINKNAMELEN];
char mstr[MAXMACADDRLEN * 3];
vnic_fields_buf_t vbuf;
+ uint_t valcnt = 1;
+ char zonename[DLADM_PROP_VAL_MAX + 1];
+ char *valptr[1];
if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
DLADM_STATUS_OK)
@@ -5010,6 +5147,18 @@ print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
(void) sprintf(devname, "?");
+
+ zonename[0] = '\0';
+ if (!is_etherstub) {
+ valptr[0] = zonename;
+ (void) dladm_get_linkprop(handle, linkid,
+ DLADM_PROP_VAL_CURRENT, "zone", (char **)valptr, &valcnt);
+ }
+
+ if (state->vs_zonename != NULL &&
+ strcmp(state->vs_zonename, zonename) != 0)
+ return (DLADM_STATUS_OK);
+
state->vs_found = B_TRUE;
if (state->vs_stats) {
/* print vnic statistics */
@@ -5085,6 +5234,13 @@ print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
(void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
"%d", vnic->va_vid);
+
+ if (zonename[0] != '\0')
+ (void) snprintf(vbuf.vnic_zone,
+ sizeof (vbuf.vnic_zone), "%s", zonename);
+ else
+ (void) strlcpy(vbuf.vnic_zone, "--",
+ sizeof (vbuf.vnic_zone));
}
ofmt_print(state->vs_ofmt, &vbuf);
@@ -5123,10 +5279,11 @@ do_show_vnic_common(int argc, char *argv[], const char *use,
ofmt_handle_t ofmt;
ofmt_status_t oferr;
uint_t ofmtflags = 0;
+ char *zonename = NULL;
bzero(&state, sizeof (state));
opterr = 0;
- while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
+ while ((option = getopt_long(argc, argv, ":pPl:si:o:z:", lopts,
NULL)) != -1) {
switch (option) {
case 'p':
@@ -5165,6 +5322,9 @@ do_show_vnic_common(int argc, char *argv[], const char *use,
o_arg = B_TRUE;
fields_str = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, use);
}
@@ -5175,8 +5335,8 @@ do_show_vnic_common(int argc, char *argv[], const char *use,
/* get vnic ID (optional last argument) */
if (optind == (argc - 1)) {
- status = dladm_name2info(handle, argv[optind], &linkid, NULL,
- NULL, NULL);
+ status = dladm_zname2info(handle, zonename, argv[optind],
+ &linkid, NULL, NULL, NULL);
if (status != DLADM_STATUS_OK) {
die_dlerr(status, "invalid vnic name '%s'",
argv[optind]);
@@ -5187,8 +5347,8 @@ do_show_vnic_common(int argc, char *argv[], const char *use,
}
if (l_arg) {
- status = dladm_name2info(handle, state.vs_link, &dev_linkid,
- NULL, NULL, NULL);
+ status = dladm_zname2info(handle, zonename, state.vs_link,
+ &dev_linkid, NULL, NULL, NULL);
if (status != DLADM_STATUS_OK) {
die_dlerr(status, "invalid link name '%s'",
state.vs_link);
@@ -5200,6 +5360,7 @@ do_show_vnic_common(int argc, char *argv[], const char *use,
state.vs_etherstub = etherstub;
state.vs_found = B_FALSE;
state.vs_flags = flags;
+ state.vs_zonename = zonename;
if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
if (etherstub)
@@ -5288,7 +5449,7 @@ do_create_etherstub(int argc, char *argv[], const char *use)
status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0,
- VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags);
+ VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, &errlist, flags);
if (status != DLADM_STATUS_OK)
die_dlerr(status, "etherstub creation failed");
}
@@ -6688,6 +6849,7 @@ do_show_linkprop(int argc, char **argv, const char *use)
ofmt_handle_t ofmt;
ofmt_status_t oferr;
uint_t ofmtflags = 0;
+ char *zonename = NULL;
bzero(propstr, DLADM_STRSIZE);
opterr = 0;
@@ -6698,7 +6860,7 @@ do_show_linkprop(int argc, char **argv, const char *use)
state.ls_header = B_TRUE;
state.ls_retstatus = DLADM_STATUS_OK;
- while ((option = getopt_long(argc, argv, ":p:cPo:",
+ while ((option = getopt_long(argc, argv, ":p:cPo:z:",
prop_longopts, NULL)) != -1) {
switch (option) {
case 'p':
@@ -6717,6 +6879,9 @@ do_show_linkprop(int argc, char **argv, const char *use)
case 'o':
fields_str = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, use);
break;
@@ -6724,8 +6889,8 @@ do_show_linkprop(int argc, char **argv, const char *use)
}
if (optind == (argc - 1)) {
- if ((status = dladm_name2info(handle, argv[optind], &linkid,
- NULL, NULL, NULL)) != DLADM_STATUS_OK) {
+ if ((status = dladm_zname2info(handle, zonename, argv[optind],
+ &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) {
die_dlerr(status, "link %s is not valid", argv[optind]);
}
} else if (optind != argc) {
@@ -6736,6 +6901,7 @@ do_show_linkprop(int argc, char **argv, const char *use)
!= DLADM_STATUS_OK)
die("invalid link properties specified");
state.ls_proplist = proplist;
+ state.ls_zonename = zonename;
state.ls_status = DLADM_STATUS_OK;
if (state.ls_parsable)
@@ -6780,6 +6946,17 @@ show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
return (DLADM_WALK_CONTINUE);
}
+ if (statep->ls_zonename != NULL) {
+ datalink_id_t tlinkid;
+
+ if (dladm_zname2info(hdl, statep->ls_zonename, statep->ls_link,
+ &tlinkid, NULL, NULL, NULL) != DLADM_STATUS_OK ||
+ linkid != tlinkid) {
+ statep->ls_status = DLADM_STATUS_NOTFOUND;
+ return (DLADM_WALK_CONTINUE);
+ }
+ }
+
if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) ||
(!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) {
statep->ls_status = DLADM_STATUS_BADARG;
@@ -6862,11 +7039,12 @@ set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
dladm_status_t status = DLADM_STATUS_OK;
char propstr[DLADM_STRSIZE];
dladm_arg_list_t *proplist = NULL;
+ char *zonename = NULL;
opterr = 0;
bzero(propstr, DLADM_STRSIZE);
- while ((option = getopt_long(argc, argv, ":p:R:t",
+ while ((option = getopt_long(argc, argv, ":p:R:tz:",
prop_longopts, NULL)) != -1) {
switch (option) {
case 'p':
@@ -6881,6 +7059,9 @@ set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
case 'R':
altroot = optarg;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, use);
@@ -6903,8 +7084,8 @@ set_linkprop(int argc, char **argv, boolean_t reset, const char *use)
altroot_cmd(altroot, argc, argv);
}
- status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
- NULL);
+ status = dladm_zname2info(handle, zonename, argv[optind], &linkid,
+ NULL, NULL, NULL);
if (status != DLADM_STATUS_OK)
die_dlerr(status, "link %s is not valid", argv[optind]);
@@ -8927,6 +9108,21 @@ warn_dlerr(dladm_status_t err, const char *format, ...)
(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
}
+static void
+warn_dlerrlist(dladm_errlist_t *errlist)
+{
+ if (errlist != NULL && errlist->el_count > 0) {
+ int i;
+ for (i = 0; i < errlist->el_count; i++) {
+ (void) fprintf(stderr, gettext("%s: warning: "),
+ progname);
+
+ (void) fprintf(stderr, "%s\n",
+ gettext(errlist->el_errs[i]));
+ }
+ }
+}
+
/*
* Also closes the dladm handle if it is not NULL.
*/
@@ -8952,6 +9148,34 @@ die_dlerr(dladm_status_t err, const char *format, ...)
exit(EXIT_FAILURE);
}
+/*
+ * Like die_dlerr, but uses the errlist for additional information.
+ */
+/* PRINTFLIKE3 */
+static void
+die_dlerrlist(dladm_status_t err, dladm_errlist_t *errlist,
+ const char *format, ...)
+{
+ va_list alist;
+ char errmsg[DLADM_STRSIZE];
+
+ warn_dlerrlist(errlist);
+ format = gettext(format);
+ (void) fprintf(stderr, "%s: ", progname);
+
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
+
+ /* close dladm handle if it was opened */
+ if (handle != NULL)
+ dladm_close(handle);
+
+ exit(EXIT_FAILURE);
+
+}
+
/* PRINTFLIKE1 */
static void
die(const char *format, ...)
@@ -9659,3 +9883,702 @@ do_up_part(int argc, char *argv[], const char *use)
(void) dladm_part_up(handle, partid, 0);
}
+
+static void
+do_create_overlay(int argc, char *argv[], const char *use)
+{
+ int opt;
+ char *encap = NULL, *endp, *search = NULL;
+ char name[MAXLINKNAMELEN];
+ dladm_status_t status;
+ uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
+ uint64_t vid;
+ boolean_t havevid = B_FALSE;
+ char propstr[DLADM_STRSIZE];
+ dladm_arg_list_t *proplist = NULL;
+
+ bzero(propstr, sizeof (propstr));
+ while ((opt = getopt_long(argc, argv, ":te:v:p:s:",
+ overlay_create_lopts, NULL)) != -1) {
+ switch (opt) {
+ case 'e':
+ encap = optarg;
+ break;
+ case 's':
+ search = optarg;
+ break;
+ case 't':
+ flags &= ~DLADM_OPT_PERSIST;
+ break;
+ case 'p':
+ (void) strlcat(propstr, optarg, DLADM_STRSIZE);
+ if (strlcat(propstr, ",", DLADM_STRSIZE) >=
+ DLADM_STRSIZE)
+ die("property list too long '%s'", propstr);
+ break;
+ case 'v':
+ vid = strtoul(optarg, &endp, 10);
+ if (*endp != '\0' || (vid == 0 && errno == EINVAL))
+ die("couldn't parse virtual networkd id: %s",
+ optarg);
+ if (vid == ULONG_MAX && errno == ERANGE)
+ die("virtual networkd id too large: %s",
+ optarg);
+ havevid = B_TRUE;
+ break;
+ default:
+ die_opterr(optopt, opt, use);
+ }
+ }
+
+ if (havevid == B_FALSE)
+ die("missing required virtual network id");
+
+ if (encap == NULL)
+ die("missing required encapsulation plugin");
+
+ if (search == NULL)
+ die("missing required search plugin");
+
+ if (optind != (argc - 1))
+ die("missing device name");
+
+ if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
+ die("link name too long '%s'", argv[optind]);
+
+ if (!dladm_valid_linkname(name))
+ die("invalid link name '%s'", argv[optind]);
+
+ if (strlen(encap) + 1 > MAXLINKNAMELEN)
+ die("encapsulation plugin name too long '%s'", encap);
+
+ if (strlen(search) + 1 > MAXLINKNAMELEN)
+ die("search plugin name too long '%s'", encap);
+
+ if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
+ != DLADM_STATUS_OK)
+ die("invalid overlay property");
+
+ status = dladm_overlay_create(handle, name, encap, search, vid,
+ proplist, &errlist, flags);
+ dladm_free_props(proplist);
+ if (status != DLADM_STATUS_OK) {
+ die_dlerrlist(status, &errlist, "overlay creation failed");
+ }
+}
+
+/* ARGSUSED */
+static void
+do_delete_overlay(int argc, char *argv[], const char *use)
+{
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
+
+ if (argc != 2) {
+ usage();
+ }
+
+ status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to delete %s", argv[1]);
+
+ status = dladm_overlay_delete(handle, linkid);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to delete %s", argv[1]);
+}
+
+typedef struct showoverlay_state {
+ ofmt_handle_t sho_ofmt;
+ const char *sho_linkname;
+ dladm_overlay_propinfo_handle_t sho_info;
+ uint8_t sho_value[DLADM_OVERLAY_PROP_SIZEMAX];
+ uint32_t sho_size;
+} showoverlay_state_t;
+
+typedef struct showoverlay_fma_state {
+ ofmt_handle_t shof_ofmt;
+ const char *shof_linkname;
+ dladm_overlay_status_t *shof_status;
+} showoverlay_fma_state_t;
+
+typedef struct showoverlay_targ_state {
+ ofmt_handle_t shot_ofmt;
+ const char *shot_linkname;
+ const struct ether_addr *shot_key;
+ const dladm_overlay_point_t *shot_point;
+} showoverlay_targ_state_t;
+
+static void
+print_overlay_value(char *outbuf, uint_t bufsize, uint_t type, const void *pbuf,
+ const size_t psize)
+{
+ const struct in6_addr *ipv6;
+ struct in_addr ip;
+
+ switch (type) {
+ case OVERLAY_PROP_T_INT:
+ if (psize != 1 && psize != 2 && psize != 4 && psize != 8) {
+ (void) snprintf(outbuf, bufsize, "?");
+ break;
+ }
+ if (psize == 1)
+ (void) snprintf(outbuf, bufsize, "%d", *(int8_t *)pbuf);
+ if (psize == 2)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(int16_t *)pbuf);
+ if (psize == 4)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(int32_t *)pbuf);
+ if (psize == 8)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(int64_t *)pbuf);
+ break;
+ case OVERLAY_PROP_T_UINT:
+ if (psize != 1 && psize != 2 && psize != 4 && psize != 8) {
+ (void) snprintf(outbuf, bufsize, "?");
+ break;
+ }
+ if (psize == 1)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint8_t *)pbuf);
+ if (psize == 2)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint16_t *)pbuf);
+ if (psize == 4)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint32_t *)pbuf);
+ if (psize == 8)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint64_t *)pbuf);
+ break;
+ case OVERLAY_PROP_T_IP:
+ if (psize != sizeof (struct in6_addr)) {
+ warn("malformed overlay IP property: %d bytes\n",
+ psize);
+ (void) snprintf(outbuf, bufsize, "--");
+ break;
+ }
+
+ ipv6 = pbuf;
+ if (IN6_IS_ADDR_V4MAPPED(ipv6)) {
+ IN6_V4MAPPED_TO_INADDR(ipv6, &ip);
+ if (inet_ntop(AF_INET, &ip, outbuf, bufsize) == NULL) {
+ warn("malformed overlay IP property\n");
+ (void) snprintf(outbuf, bufsize, "--");
+ break;
+ }
+ } else {
+ if (inet_ntop(AF_INET6, ipv6, outbuf, bufsize) ==
+ NULL) {
+ warn("malformed overlay IP property\n");
+ (void) snprintf(outbuf, bufsize, "--");
+ break;
+ }
+ }
+
+ break;
+ case OVERLAY_PROP_T_STRING:
+ (void) snprintf(outbuf, bufsize, "%s", pbuf);
+ break;
+ default:
+ abort();
+ }
+
+ return;
+
+}
+
+static boolean_t
+print_overlay_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+ dladm_status_t status;
+ showoverlay_state_t *sp = ofarg->ofmt_cbarg;
+ dladm_overlay_propinfo_handle_t infop = sp->sho_info;
+ const char *pname;
+ uint_t type, prot;
+ const void *def;
+ uint32_t defsize;
+ const mac_propval_range_t *rangep;
+
+ if ((status = dladm_overlay_prop_info(infop, &pname, &type, &prot, &def,
+ &defsize, &rangep)) != DLADM_STATUS_OK) {
+ warn_dlerr(status, "failed to get get property info");
+ return (B_TRUE);
+ }
+
+ switch (ofarg->ofmt_id) {
+ case OVERLAY_LINK:
+ (void) snprintf(buf, bufsize, "%s", sp->sho_linkname);
+ break;
+ case OVERLAY_PROPERTY:
+ (void) snprintf(buf, bufsize, "%s", pname);
+ break;
+ case OVERLAY_PERM:
+ if ((prot & OVERLAY_PROP_PERM_RW) == OVERLAY_PROP_PERM_RW) {
+ (void) snprintf(buf, bufsize, "%s", "rw");
+ } else if ((prot & OVERLAY_PROP_PERM_RW) ==
+ OVERLAY_PROP_PERM_READ) {
+ (void) snprintf(buf, bufsize, "%s", "r-");
+ } else {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ }
+ break;
+ case OVERLAY_REQ:
+ (void) snprintf(buf, bufsize, "%s",
+ prot & OVERLAY_PROP_PERM_REQ ? "y" : "-");
+ break;
+ case OVERLAY_VALUE:
+ if (sp->sho_size == 0) {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ } else {
+ print_overlay_value(buf, bufsize, type, sp->sho_value,
+ sp->sho_size);
+ }
+ break;
+ case OVERLAY_DEFAULT:
+ if (defsize == 0) {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ } else {
+ print_overlay_value(buf, bufsize, type, def, defsize);
+ }
+ break;
+ case OVERLAY_POSSIBLE: {
+ int i;
+ char **vals, *ptr, *lim;
+ if (rangep->mpr_count == 0) {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ break;
+ }
+
+ vals = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
+ rangep->mpr_count);
+ if (vals == NULL)
+ die("insufficient memory");
+ for (i = 0; i < rangep->mpr_count; i++) {
+ vals[i] = (char *)vals + sizeof (char *) *
+ rangep->mpr_count + i * DLADM_MAX_PROP_VALCNT;
+ }
+
+ if (dladm_range2strs(rangep, vals) != 0) {
+ free(vals);
+ (void) snprintf(buf, bufsize, "%s", "?");
+ break;
+ }
+
+ ptr = buf;
+ lim = buf + bufsize;
+ for (i = 0; i < rangep->mpr_count; i++) {
+ ptr += snprintf(ptr, lim - ptr, "%s,", vals[i]);
+ if (ptr >= lim)
+ break;
+ }
+ if (rangep->mpr_count > 0)
+ buf[strlen(buf) - 1] = '\0';
+ free(vals);
+ break;
+ }
+ default:
+ abort();
+ }
+ return (B_TRUE);
+}
+
+static int
+dladm_overlay_show_one(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_propinfo_handle_t phdl, void *arg)
+{
+ showoverlay_state_t *sp = arg;
+ sp->sho_info = phdl;
+
+ sp->sho_size = sizeof (sp->sho_value);
+ if (dladm_overlay_get_prop(handle, linkid, phdl, &sp->sho_value,
+ &sp->sho_size) != DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ ofmt_print(sp->sho_ofmt, sp);
+ return (DLADM_WALK_CONTINUE);
+}
+
+static int
+show_one_overlay(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
+{
+ char buf[MAXLINKNAMELEN];
+ dladm_status_t info_status;
+ showoverlay_state_t state;
+ datalink_class_t class;
+ show_overlay_request_t *req = arg;
+
+ if ((info_status = dladm_datalink_id2info(hdl, linkid, NULL, &class,
+ NULL, buf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
+ warn_dlerr(info_status, "failed to get info for "
+ "datalink id %u", linkid);
+ req->sor_failed = B_TRUE;
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if (class != DATALINK_CLASS_OVERLAY) {
+ warn("%s is not an overlay", buf);
+ req->sor_failed = B_TRUE;
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ state.sho_linkname = buf;
+ state.sho_ofmt = req->sor_ofmt;
+
+ dladm_errlist_reset(&errlist);
+ (void) dladm_overlay_walk_prop(handle, linkid, dladm_overlay_show_one,
+ &state, &errlist);
+ warn_dlerrlist(&errlist);
+ if (errlist.el_count) {
+ req->sor_failed = B_TRUE;
+ }
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+static boolean_t
+print_overlay_targ_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+ char keybuf[ETHERADDRSTRL];
+ const showoverlay_targ_state_t *shot = ofarg->ofmt_cbarg;
+ const dladm_overlay_point_t *point = shot->shot_point;
+ char macbuf[ETHERADDRSTRL];
+ char ipbuf[INET6_ADDRSTRLEN];
+ custr_t *cus;
+
+ switch (ofarg->ofmt_id) {
+ case OVERLAY_TARG_LINK:
+ (void) snprintf(buf, bufsize, shot->shot_linkname);
+ break;
+ case OVERLAY_TARG_TARGET:
+ if ((point->dop_flags & DLADM_OVERLAY_F_DEFAULT) != 0) {
+ (void) snprintf(buf, bufsize, "*:*:*:*:*:*");
+ } else {
+ if (ether_ntoa_r(shot->shot_key, keybuf) == NULL) {
+ warn("encountered malformed mac address key\n");
+ return (B_FALSE);
+ }
+ (void) snprintf(buf, bufsize, "%s", keybuf);
+ }
+ break;
+ case OVERLAY_TARG_DEST:
+ if (custr_alloc_buf(&cus, buf, bufsize) != 0) {
+ die("ran out of memory for printing the overlay "
+ "target destination");
+ }
+
+ if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET) {
+ if (ether_ntoa_r(&point->dop_mac, macbuf) == NULL) {
+ warn("encountered malformed mac address target "
+ "for key %s\n", keybuf);
+ return (B_FALSE);
+ }
+ (void) custr_append(cus, macbuf);
+ }
+
+ if (point->dop_dest & OVERLAY_PLUGIN_D_IP) {
+ if (IN6_IS_ADDR_V4MAPPED(&point->dop_ip)) {
+ struct in_addr v4;
+ IN6_V4MAPPED_TO_INADDR(&point->dop_ip, &v4);
+ if (inet_ntop(AF_INET, &v4, ipbuf,
+ sizeof (ipbuf)) == NULL)
+ abort();
+ } else if (inet_ntop(AF_INET6, &point->dop_ip, ipbuf,
+ sizeof (ipbuf)) == NULL) {
+ /*
+ * The only failrues we should get are
+ * EAFNOSUPPORT and ENOSPC because of buffer
+ * exhaustion. In either of these cases, that
+ * means something has gone horribly wrong.
+ */
+ abort();
+ }
+ if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET)
+ (void) custr_appendc(cus, ',');
+ (void) custr_append(cus, ipbuf);
+ }
+
+ if (point->dop_dest & OVERLAY_PLUGIN_D_PORT) {
+ if (point->dop_dest & OVERLAY_PLUGIN_D_IP)
+ (void) custr_appendc(cus, ':');
+ else if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET)
+ (void) custr_appendc(cus, ',');
+ (void) custr_append_printf(cus, "%u", point->dop_port);
+ }
+
+ custr_free(cus);
+
+ break;
+ }
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static int
+show_one_overlay_table_entry(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key, const dladm_overlay_point_t *point, void *arg)
+{
+ showoverlay_targ_state_t *shot = arg;
+
+ shot->shot_key = key;
+ shot->shot_point = point;
+ ofmt_print(shot->shot_ofmt, shot);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+/* ARGSUSED */
+static int
+show_one_overlay_table(dladm_handle_t handle, datalink_id_t linkid, void *arg)
+{
+ char linkbuf[MAXLINKNAMELEN];
+ dladm_status_t info_status;
+ showoverlay_targ_state_t shot;
+ datalink_class_t class;
+ show_overlay_request_t *req = arg;
+
+ if ((info_status = dladm_datalink_id2info(handle, linkid, NULL, &class,
+ NULL, linkbuf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
+ warn_dlerr(info_status, "failed to get info for "
+ "datalink id %u", linkid);
+ req->sor_failed = B_TRUE;
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ if (class != DATALINK_CLASS_OVERLAY) {
+ warn("%s is not an overlay", linkbuf);
+ req->sor_failed = B_TRUE;
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ shot.shot_ofmt = req->sor_ofmt;
+ shot.shot_linkname = linkbuf;
+
+ (void) dladm_overlay_walk_cache(handle, linkid,
+ show_one_overlay_table_entry, &shot);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+static boolean_t
+print_overlay_fma_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+ showoverlay_fma_state_t *shof = ofarg->ofmt_cbarg;
+ dladm_overlay_status_t *st = shof->shof_status;
+
+ switch (ofarg->ofmt_id) {
+ case OVERLAY_FMA_LINK:
+ (void) snprintf(buf, bufsize, "%s", shof->shof_linkname);
+ break;
+ case OVERLAY_FMA_STATUS:
+ (void) snprintf(buf, bufsize, st->dos_degraded == B_TRUE ?
+ "DEGRADED": "ONLINE");
+ break;
+ case OVERLAY_FMA_DETAILS:
+ (void) snprintf(buf, bufsize, "%s", st->dos_degraded == B_TRUE ?
+ st->dos_fmamsg : "-");
+ break;
+ default:
+ abort();
+ }
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static void
+show_one_overlay_fma_cb(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_status_t *stat, void *arg)
+{
+ showoverlay_fma_state_t *shof = arg;
+ shof->shof_status = stat;
+ ofmt_print(shof->shof_ofmt, shof);
+}
+
+
+static int
+show_one_overlay_fma(dladm_handle_t handle, datalink_id_t linkid, void *arg)
+{
+ dladm_status_t status;
+ char linkbuf[MAXLINKNAMELEN];
+ datalink_class_t class;
+ showoverlay_fma_state_t shof;
+ show_overlay_request_t *req = arg;
+
+ if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, linkbuf,
+ MAXLINKNAMELEN) != DLADM_STATUS_OK ||
+ class != DATALINK_CLASS_OVERLAY) {
+ die("datalink %s is not an overlay device\n", linkbuf);
+ }
+
+ shof.shof_ofmt = req->sor_ofmt;
+ shof.shof_linkname = linkbuf;
+
+ status = dladm_overlay_status(handle, linkid,
+ show_one_overlay_fma_cb, &shof);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to obtain device status for %s",
+ linkbuf);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+static void
+do_show_overlay(int argc, char *argv[], const char *use)
+{
+ int i, opt;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
+ int (*funcp)(dladm_handle_t, datalink_id_t, void *);
+ char *fields_str = NULL;
+ const ofmt_field_t *fieldsp;
+ ofmt_status_t oferr;
+ boolean_t parse;
+ show_overlay_request_t req;
+ uint_t ofmtflags;
+ int err;
+
+ funcp = show_one_overlay;
+ fieldsp = overlay_fields;
+ parse = B_FALSE;
+ req.sor_failed = B_FALSE;
+ ofmtflags = OFMT_WRAP;
+ while ((opt = getopt_long(argc, argv, ":o:pft", overlay_show_lopts,
+ NULL)) != -1) {
+ switch (opt) {
+ case 'f':
+ funcp = show_one_overlay_fma;
+ fieldsp = overlay_fma_fields;
+ break;
+ case 'o':
+ fields_str = optarg;
+ break;
+ case 'p':
+ parse = B_TRUE;
+ ofmtflags = OFMT_PARSABLE;
+ break;
+ case 't':
+ funcp = show_one_overlay_table;
+ fieldsp = overlay_targ_fields;
+ break;
+ default:
+ die_opterr(optopt, opt, use);
+ }
+ }
+
+ if (fields_str != NULL && strcasecmp(fields_str, "all") == 0)
+ fields_str = NULL;
+
+ oferr = ofmt_open(fields_str, fieldsp, ofmtflags, 0, &req.sor_ofmt);
+ ofmt_check(oferr, parse, req.sor_ofmt, die, warn);
+
+ err = 0;
+ if (argc > optind) {
+ for (i = optind; i < argc; i++) {
+ status = dladm_name2info(handle, argv[i], &linkid,
+ NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK) {
+ warn_dlerr(status, "failed to find %s",
+ argv[i]);
+ err = 1;
+ continue;
+ }
+ (void) funcp(handle, linkid, &req);
+ }
+ } else {
+ (void) dladm_walk_datalink_id(funcp, handle, &req,
+ DATALINK_CLASS_OVERLAY, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_ACTIVE);
+ }
+ if (req.sor_failed) {
+ err = 1;
+ }
+ ofmt_close(req.sor_ofmt);
+
+ exit(err);
+}
+
+static void
+do_modify_overlay(int argc, char *argv[], const char *use)
+{
+ int opt, ocnt = 0;
+ boolean_t flush, set, delete;
+ struct ether_addr e;
+ char *dest;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
+
+ flush = set = delete = B_FALSE;
+ while ((opt = getopt_long(argc, argv, ":fd:s:", overlay_modify_lopts,
+ NULL)) != -1) {
+ switch (opt) {
+ case 'd':
+ if (delete == B_TRUE)
+ die_optdup('d');
+ delete = B_TRUE;
+ ocnt++;
+ if (ether_aton_r(optarg, &e) == NULL)
+ die("invalid mac address: %s\n", optarg);
+ break;
+ case 'f':
+ if (flush == B_TRUE)
+ die_optdup('f');
+ flush = B_TRUE;
+ ocnt++;
+ break;
+ case 's':
+ if (set == B_TRUE)
+ die_optdup('s');
+ set = B_TRUE;
+ ocnt++;
+ dest = strchr(optarg, '=');
+ *dest = '\0';
+ dest++;
+ if (dest == NULL)
+ die("malformed value, expected mac=dest, "
+ "got: %s\n", optarg);
+ if (ether_aton_r(optarg, &e) == NULL)
+ die("invalid mac address: %s\n", optarg);
+ break;
+ default:
+ die_opterr(optopt, opt, use);
+ }
+ }
+
+ if (ocnt == 0)
+ die("need to specify one of -d, -f, or -s");
+ if (ocnt > 1)
+ die("only one of -d, -f, or -s may be used");
+
+ if (argv[optind] == NULL)
+ die("missing required overlay device\n");
+ if (argc > optind + 1)
+ die("only one overlay device may be specified\n");
+
+ status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
+ NULL);
+ if (status != DLADM_STATUS_OK) {
+ die_dlerr(status, "failed to find overlay %s", argv[optind]);
+ }
+
+ if (flush == B_TRUE) {
+ status = dladm_overlay_cache_flush(handle, linkid);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to flush target cache for "
+ "overlay %s", argv[optind]);
+ }
+
+ if (delete == B_TRUE) {
+ status = dladm_overlay_cache_delete(handle, linkid, &e);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to flush target %s from "
+ "overlay target cache %s", optarg, argv[optind]);
+ }
+
+ if (set == B_TRUE) {
+ status = dladm_overlay_cache_set(handle, linkid, &e, dest);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to set target %s for overlay "
+ "target cache %s", optarg, argv[optind]);
+ }
+
+}
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_db.c b/usr/src/cmd/dlmgmtd/dlmgmt_db.c
index 99307dbc03..6ccd9d97b8 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_db.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_db.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
#include <assert.h>
@@ -43,6 +44,7 @@
#include <libcontract.h>
#include <libcontract_priv.h>
#include <sys/contract/process.h>
+#include <zone.h>
#include "dlmgmt_impl.h"
typedef enum dlmgmt_db_op {
@@ -552,6 +554,10 @@ dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp,
linkp->ll_zoneid, flags, &err)) == NULL)
return (err);
+ /* If transient op and onloan, use the global zone cache file. */
+ if (flags == DLMGMT_ACTIVE && linkp->ll_onloan)
+ req->ls_zoneid = GLOBAL_ZONEID;
+
/*
* If the return error is EINPROGRESS, this request is handled
* asynchronously; return success.
@@ -714,11 +720,13 @@ parse_linkprops(char *buf, dlmgmt_link_t *linkp)
char attr_name[MAXLINKATTRLEN];
size_t attr_buf_len = 0;
void *attr_buf = NULL;
+ boolean_t rename;
curr = buf;
len = strlen(buf);
attr_name[0] = '\0';
for (i = 0; i < len; i++) {
+ rename = B_FALSE;
char c = buf[i];
boolean_t match = (c == '=' ||
(c == ',' && !found_type) || c == ';');
@@ -768,6 +776,21 @@ parse_linkprops(char *buf, dlmgmt_link_t *linkp)
goto parse_fail;
linkp->ll_media =
(uint32_t)*(int64_t *)attr_buf;
+ } else if (strcmp(attr_name, "zone") == 0) {
+ if (read_str(curr, &attr_buf) == 0)
+ goto parse_fail;
+ linkp->ll_zoneid = getzoneidbyname(attr_buf);
+ if (linkp->ll_zoneid == -1) {
+ if (errno == EFAULT)
+ abort();
+ /*
+ * If we can't find the zone, assign the
+ * link to the GZ and mark it for being
+ * renamed.
+ */
+ linkp->ll_zoneid = 0;
+ rename = B_TRUE;
+ }
} else {
attr_buf_len = translators[type].read_func(curr,
&attr_buf);
@@ -811,6 +834,16 @@ parse_linkprops(char *buf, dlmgmt_link_t *linkp)
(void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
}
+
+ /*
+ * The zone that this link belongs to has died, we are
+ * reparenting it to the GZ and renaming it to avoid name
+ * collisions.
+ */
+ if (rename == B_TRUE) {
+ (void) snprintf(linkp->ll_link, MAXLINKNAMELEN,
+ "SUNWorphan%u", (uint16_t)(gethrtime() / 1000));
+ }
curr = buf + i + 1;
}
@@ -1222,12 +1255,19 @@ generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link);
if (!persist) {
+ char zname[ZONENAME_MAX];
/*
- * We store the linkid in the active database so that dlmgmtd
- * can recover in the event that it is restarted.
+ * We store the linkid and the zone name in the active database
+ * so that dlmgmtd can recover in the event that it is
+ * restarted.
*/
u64 = linkp->ll_linkid;
ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64);
+
+ if (getzonenamebyid(linkp->ll_zoneid, zname,
+ sizeof (zname)) != -1) {
+ ptr += write_str(ptr, BUFLEN(lim, ptr), "zone", zname);
+ }
}
u64 = linkp->ll_class;
ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
@@ -1382,38 +1422,88 @@ dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func)
}
/*
+ * Attempt to mitigate one of the deadlocks in the dlmgmtd architecture.
+ *
+ * dlmgmt_db_init() calls dlmgmt_process_db_req() which eventually gets to
+ * dlmgmt_zfop() which tries to fork, enter the zone and read the file.
+ * Because of the upcall architecture of dlmgmtd this can lead to deadlock
+ * with the following scenario:
+ * a) the thread preparing to fork will have acquired the malloc locks
+ * then attempt to suspend every thread in preparation to fork.
+ * b) all of the upcalls will be blocked in door_ucred() trying to malloc()
+ * and get the credentials of their caller.
+ * c) we can't suspend the in-kernel thread making the upcall.
+ *
+ * Thus, we cannot serve door requests because we're blocked in malloc()
+ * which fork() owns, but fork() is in turn blocked on the in-kernel thread
+ * making the door upcall. This is a fundamental architectural problem with
+ * any server handling upcalls and also trying to fork().
+ *
+ * To minimize the chance of this deadlock occuring, we check ahead of time to
+ * see if the file we want to read actually exists in the zone (which it almost
+ * never does), so we don't need fork in that case (i.e. rarely to never).
+ */
+static boolean_t
+zone_file_exists(char *zoneroot, char *filename)
+{
+ struct stat sb;
+ char fname[MAXPATHLEN];
+
+ (void) snprintf(fname, sizeof (fname), "%s/%s", zoneroot, filename);
+
+ if (stat(fname, &sb) == -1)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
* Initialize the datalink <link name, linkid> mapping and the link's
* attributes list based on the configuration file /etc/dladm/datalink.conf
* and the active configuration cache file
* /etc/svc/volatile/dladm/datalink-management:default.cache.
*/
int
-dlmgmt_db_init(zoneid_t zoneid)
+dlmgmt_db_init(zoneid_t zoneid, char *zoneroot)
{
dlmgmt_db_req_t *req;
int err;
boolean_t boot = B_FALSE;
+ char tdir[MAXPATHLEN];
+ char *path = cachefile;
if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL,
DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL)
return (err);
- if ((err = dlmgmt_process_db_req(req)) != 0) {
- /*
- * If we get back ENOENT, that means that the active
- * configuration file doesn't exist yet, and is not an error.
- * We'll create it down below after we've loaded the
- * persistent configuration.
- */
- if (err != ENOENT)
- goto done;
+ /* Handle running in a non-native branded zone (i.e. has /native) */
+ if (zone_file_exists(zoneroot, "/native" DLMGMT_TMPFS_DIR)) {
+ (void) snprintf(tdir, sizeof (tdir), "/native%s", cachefile);
+ path = tdir;
+ }
+
+ if (zone_file_exists(zoneroot, path)) {
+ if ((err = dlmgmt_process_db_req(req)) != 0) {
+ /*
+ * If we get back ENOENT, that means that the active
+ * configuration file doesn't exist yet, and is not an
+ * error. We'll create it down below after we've
+ * loaded the persistent configuration.
+ */
+ if (err != ENOENT)
+ goto done;
+ boot = B_TRUE;
+ }
+ } else {
boot = B_TRUE;
}
- req->ls_flags = DLMGMT_PERSIST;
- err = dlmgmt_process_db_req(req);
- if (err != 0 && err != ENOENT)
- goto done;
+ if (zone_file_exists(zoneroot, DLMGMT_PERSISTENT_DB_PATH)) {
+ req->ls_flags = DLMGMT_PERSIST;
+ err = dlmgmt_process_db_req(req);
+ if (err != 0 && err != ENOENT)
+ goto done;
+ }
err = 0;
if (rewrite_needed) {
/*
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_door.c b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
index 11e4329669..60fa361caa 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_door.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -58,6 +59,7 @@
#include <libsysevent.h>
#include <libdlmgmt.h>
#include <librcm.h>
+#include <unistd.h>
#include "dlmgmt_impl.h"
typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
@@ -423,8 +425,11 @@ dlmgmt_getname(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
retvalp->lr_flags = linkp->ll_flags;
retvalp->lr_class = linkp->ll_class;
retvalp->lr_media = linkp->ll_media;
+ retvalp->lr_flags |= (linkp->ll_trans == B_TRUE) ?
+ DLMGMT_TRANSIENT : 0;
}
+
dlmgmt_table_unlock();
retvalp->lr_err = err;
}
@@ -439,6 +444,10 @@ dlmgmt_getlinkid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
dlmgmt_link_t *linkp;
int err = 0;
+ /* Enable the global zone to lookup links it has given away. */
+ if (zoneid == GLOBAL_ZONEID && getlinkid->ld_zoneid != -1)
+ zoneid = getlinkid->ld_zoneid;
+
/*
* Hold the reader lock to access the link
*/
@@ -648,6 +657,7 @@ dlmgmt_remapid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
goto done;
+
if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
err = EEXIST;
goto done;
@@ -1232,8 +1242,7 @@ dlmgmt_setzoneid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
* Before we remove the link from its current zone, make sure that
* there isn't a link with the same name in the destination zone.
*/
- if (zoneid != GLOBAL_ZONEID &&
- link_by_name(linkp->ll_link, newzoneid) != NULL) {
+ if (link_by_name(linkp->ll_link, newzoneid) != NULL) {
err = EEXIST;
goto done;
}
@@ -1245,9 +1254,10 @@ dlmgmt_setzoneid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
"zone %d: %s", linkid, oldzoneid, strerror(err));
goto done;
}
- avl_remove(&dlmgmt_loan_avl, linkp);
+
linkp->ll_onloan = B_FALSE;
}
+
if (newzoneid != GLOBAL_ZONEID) {
if (zone_add_datalink(newzoneid, linkid) != 0) {
err = errno;
@@ -1256,7 +1266,6 @@ dlmgmt_setzoneid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
(void) zone_add_datalink(oldzoneid, linkid);
goto done;
}
- avl_add(&dlmgmt_loan_avl, linkp);
linkp->ll_onloan = B_TRUE;
}
@@ -1309,6 +1318,10 @@ dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
int err = 0;
dlmgmt_door_zonehalt_t *zonehalt = argp;
dlmgmt_zonehalt_retval_t *retvalp = retp;
+ static char my_pid[10];
+
+ if (my_pid[0] == '\0')
+ (void) snprintf(my_pid, sizeof (my_pid), "%d\n", getpid());
if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
if (zoneid != GLOBAL_ZONEID) {
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_impl.h b/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
index cdfd0d8a4d..c65a0438d6 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_impl.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
*/
/*
@@ -60,13 +61,24 @@ typedef struct dlmgmt_link_s {
datalink_class_t ll_class;
uint32_t ll_media;
datalink_id_t ll_linkid;
+
+ /*
+ * The zone that owns the link. If this is set to the id of
+ * an NGZ and ll_onloan is set then the link was created and
+ * is owned by the GZ but is currently being loaned out to an
+ * NGZ. E.g., when the GZ admin creates a VNIC for exclusive
+ * use by an NGZ. If ll_onloan is set then ll_zoneid cannot be 0.
+ *
+ * If ll_zoneid is set to the id of an NGZ but ll_onloan is
+ * not set then the link was created and is owned by the NGZ.
+ */
zoneid_t ll_zoneid;
boolean_t ll_onloan;
avl_node_t ll_name_node;
avl_node_t ll_id_node;
- avl_node_t ll_loan_node;
uint32_t ll_flags;
uint32_t ll_gen; /* generation number */
+ boolean_t ll_trans; /* transient link */
} dlmgmt_link_t;
/*
@@ -91,7 +103,6 @@ extern dladm_handle_t dld_handle;
extern datalink_id_t dlmgmt_nextlinkid;
extern avl_tree_t dlmgmt_name_avl;
extern avl_tree_t dlmgmt_id_avl;
-extern avl_tree_t dlmgmt_loan_avl;
extern avl_tree_t dlmgmt_dlconf_avl;
boolean_t linkattr_equal(dlmgmt_linkattr_t **, const char *, void *,
@@ -138,7 +149,7 @@ void dlmgmt_handler(void *, char *, size_t, door_desc_t *, uint_t);
void dlmgmt_log(int, const char *, ...);
int dlmgmt_write_db_entry(const char *, dlmgmt_link_t *, uint32_t);
int dlmgmt_delete_db_entry(dlmgmt_link_t *, uint32_t);
-int dlmgmt_db_init(zoneid_t);
+int dlmgmt_db_init(zoneid_t, char *);
void dlmgmt_db_fini(zoneid_t);
#ifdef __cplusplus
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_main.c b/usr/src/cmd/dlmgmtd/dlmgmt_main.c
index c02610bb5f..60466fd773 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_main.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_main.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
/*
@@ -125,15 +126,24 @@ dlmgmt_door_fini(void)
dlmgmt_door_fd = -1;
}
-int
+static int
dlmgmt_door_attach(zoneid_t zoneid, char *rootdir)
{
int fd;
int err = 0;
char doorpath[MAXPATHLEN];
+ struct stat statbuf;
- (void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir,
- DLMGMT_DOOR);
+ /* Handle running in a non-native branded zone (i.e. has /native) */
+ (void) snprintf(doorpath, sizeof (doorpath), "%s/native%s",
+ rootdir, DLMGMT_TMPFS_DIR);
+ if (stat(doorpath, &statbuf) == 0) {
+ (void) snprintf(doorpath, sizeof (doorpath), "%s/native%s",
+ rootdir, DLMGMT_DOOR);
+ } else {
+ (void) snprintf(doorpath, sizeof (doorpath), "%s%s",
+ rootdir, DLMGMT_DOOR);
+ }
/*
* Create the door file for dlmgmtd.
@@ -192,8 +202,16 @@ dlmgmt_zone_init(zoneid_t zoneid)
(void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir,
DLMGMT_TMPFS_DIR);
if (stat(tmpfsdir, &statbuf) < 0) {
- if (mkdir(tmpfsdir, (mode_t)0755) < 0)
- return (errno);
+ if (mkdir(tmpfsdir, (mode_t)0755) < 0) {
+ /*
+ * Handle running in a non-native branded zone
+ * (i.e. has /native)
+ */
+ (void) snprintf(tmpfsdir, sizeof (tmpfsdir),
+ "%s/native%s", rootdir, DLMGMT_TMPFS_DIR);
+ if (mkdir(tmpfsdir, (mode_t)0755) < 0)
+ return (errno);
+ }
} else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
return (ENOTDIR);
}
@@ -203,7 +221,7 @@ dlmgmt_zone_init(zoneid_t zoneid)
return (EPERM);
}
- if ((err = dlmgmt_db_init(zoneid)) != 0)
+ if ((err = dlmgmt_db_init(zoneid, rootdir)) != 0)
return (err);
return (dlmgmt_door_attach(zoneid, rootdir));
}
@@ -214,7 +232,7 @@ dlmgmt_zone_init(zoneid_t zoneid)
static int
dlmgmt_allzones_init(void)
{
- int err, i;
+ int i;
zoneid_t *zids = NULL;
uint_t nzids, nzids_saved;
@@ -235,11 +253,37 @@ again:
}
for (i = 0; i < nzids; i++) {
- if ((err = dlmgmt_zone_init(zids[i])) != 0)
- break;
+ int res;
+ zone_status_t status;
+
+ /*
+ * Skip over zones that have gone away or are going down
+ * since we got the list. Process all zones in the list,
+ * logging errors for any that failed.
+ */
+ if (zone_getattr(zids[i], ZONE_ATTR_STATUS, &status,
+ sizeof (status)) < 0)
+ continue;
+ switch (status) {
+ case ZONE_IS_SHUTTING_DOWN:
+ case ZONE_IS_EMPTY:
+ case ZONE_IS_DOWN:
+ case ZONE_IS_DYING:
+ case ZONE_IS_DEAD:
+ /* FALLTHRU */
+ continue;
+ default:
+ break;
+ }
+ if ((res = dlmgmt_zone_init(zids[i])) != 0) {
+ (void) fprintf(stderr, "zone (%ld) init error %s",
+ zids[i], strerror(res));
+ dlmgmt_log(LOG_ERR, "zone (%d) init error %s",
+ zids[i], strerror(res));
+ }
}
free(zids);
- return (err);
+ return (0);
}
static int
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_util.c b/usr/src/cmd/dlmgmtd/dlmgmt_util.c
index afcfbed37b..c8ba0009a0 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_util.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_util.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
*/
/*
@@ -45,13 +46,10 @@
/*
* There are three datalink AVL tables. The dlmgmt_name_avl tree contains all
* datalinks and is keyed by zoneid and link name. The dlmgmt_id_avl also
- * contains all datalinks, and it is keyed by link ID. The dlmgmt_loan_avl is
- * keyed by link name, and contains the set of global-zone links that are
- * currently on loan to non-global zones.
+ * contains all datalinks, and it is keyed by link ID.
*/
avl_tree_t dlmgmt_name_avl;
avl_tree_t dlmgmt_id_avl;
-avl_tree_t dlmgmt_loan_avl;
avl_tree_t dlmgmt_dlconf_avl;
@@ -162,8 +160,6 @@ dlmgmt_linktable_init(void)
offsetof(dlmgmt_link_t, ll_name_node));
avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
offsetof(dlmgmt_link_t, ll_id_node));
- avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
- offsetof(dlmgmt_link_t, ll_loan_node));
avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id,
sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node));
dlmgmt_nextlinkid = 1;
@@ -181,7 +177,6 @@ dlmgmt_linktable_fini(void)
avl_destroy(&dlmgmt_dlconf_avl);
avl_destroy(&dlmgmt_name_avl);
- avl_destroy(&dlmgmt_loan_avl);
avl_destroy(&dlmgmt_id_avl);
}
@@ -359,9 +354,9 @@ link_destroy(dlmgmt_link_t *linkp)
}
/*
- * Set the DLMGMT_ACTIVE flag on the link to note that it is active. When a
- * link becomes active and it belongs to a non-global zone, it is also added
- * to that zone.
+ * Set the DLMGMT_ACTIVE flag on the link to note that it is active.
+ * When a link is active and is owned by an NGZ then it is added to
+ * that zone's datalink list.
*/
int
link_activate(dlmgmt_link_t *linkp)
@@ -369,27 +364,75 @@ link_activate(dlmgmt_link_t *linkp)
int err = 0;
zoneid_t zoneid = ALL_ZONES;
+ /*
+ * If zone_check_datalink() returns 0 it means we found the
+ * link in one of the NGZ's datalink lists. Otherwise the link
+ * is under the GZ.
+ */
if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
/*
- * This link was already added to a non-global zone. This can
- * happen if dlmgmtd is restarted.
+ * This is a bit subtle. If the following expression
+ * is true then the link was found in one of the NGZ's
+ * datalink lists but the link structure has it under
+ * the GZ. This means that the link is supposed to be
+ * loaned out to an NGZ but the dlmgmtd state is out
+ * of sync -- possibly due to the process restarting.
+ * In this case we need to sync the dlmgmtd state by
+ * marking it as on-loan to the NGZ it's currently
+ * under.
*/
if (zoneid != linkp->ll_zoneid) {
+ assert(linkp->ll_zoneid == 0);
+ assert(linkp->ll_onloan == B_FALSE);
+
+ /*
+ * If dlmgmtd already has a link with this
+ * name under the NGZ then we have a problem.
+ */
if (link_by_name(linkp->ll_link, zoneid) != NULL) {
err = EEXIST;
goto done;
}
+ /*
+ * Remove the current linkp entry from the
+ * list because it's under the wrong zoneid.
+ * We don't have to update the dlmgmt_id_avl
+ * because it compares entries by ll_linkid
+ * only.
+ */
if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
avl_remove(&dlmgmt_name_avl, linkp);
+ /*
+ * Update the link to reflect the fact that
+ * it's on-loan to an NGZ and re-add it to the
+ * list.
+ */
linkp->ll_zoneid = zoneid;
avl_add(&dlmgmt_name_avl, linkp);
- avl_add(&dlmgmt_loan_avl, linkp);
linkp->ll_onloan = B_TRUE;
+
+ /*
+ * When a VNIC is not persistent and loaned to
+ * a zone it is considered transient. This is
+ * the same logic found in do_create_vnic()
+ * and is needed here in the event of a
+ * dlmgmtd restart.
+ */
+ if (linkp->ll_class == DATALINK_CLASS_VNIC &&
+ !(linkp->ll_flags & DLMGMT_PERSIST))
+ linkp->ll_trans = B_TRUE;
}
} else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
+ /*
+ * In this case the link was not found under any NGZs
+ * but according to its ll_zoneid member it is owned
+ * by an NGZ. Add the datalink to the appropriate zone
+ * datalink list.
+ */
err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
+ assert(linkp->ll_onloan == B_FALSE);
}
done:
if (err == 0)
@@ -430,10 +473,6 @@ link_by_name(const char *name, zoneid_t zoneid)
(void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
link.ll_zoneid = zoneid;
linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
- if (linkp == NULL && zoneid == GLOBAL_ZONEID) {
- /* The link could be on loan to a non-global zone? */
- linkp = avl_find(&dlmgmt_loan_avl, &link, NULL);
- }
return (linkp);
}
@@ -449,6 +488,10 @@ dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
return (EINVAL);
if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
return (ENOSPC);
+ if (flags & ~(DLMGMT_ACTIVE | DLMGMT_PERSIST | DLMGMT_TRANSIENT) ||
+ ((flags & DLMGMT_PERSIST) && (flags & DLMGMT_TRANSIENT)) ||
+ flags == 0)
+ return (EINVAL);
if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
err = ENOMEM;
@@ -462,6 +505,15 @@ dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
linkp->ll_zoneid = zoneid;
linkp->ll_gen = 0;
+ /*
+ * While DLMGMT_TRANSIENT starts off as a flag it is converted
+ * into a link field since it is really a substate of
+ * DLMGMT_ACTIVE -- it should not survive as a flag beyond
+ * this point.
+ */
+ linkp->ll_trans = (flags & DLMGMT_TRANSIENT) ? B_TRUE : B_FALSE;
+ flags &= ~DLMGMT_TRANSIENT;
+
if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
err = EEXIST;
@@ -490,6 +542,12 @@ done:
int
dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
{
+ /*
+ * After dlmgmt_create_common() the link flags should only
+ * ever include ACTIVE or PERSIST.
+ */
+ assert((linkp->ll_flags & ~(DLMGMT_ACTIVE | DLMGMT_PERSIST)) == 0);
+
if ((linkp->ll_flags & flags) == 0) {
/*
* The link does not exist in the specified space.
@@ -511,8 +569,6 @@ dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) {
(void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid);
- if (linkp->ll_onloan)
- avl_remove(&dlmgmt_loan_avl, linkp);
}
if (linkp->ll_flags == 0) {
diff --git a/usr/src/cmd/dlstat/dlstat.c b/usr/src/cmd/dlstat/dlstat.c
index 915c2196d1..d11e623206 100644
--- a/usr/src/cmd/dlstat/dlstat.c
+++ b/usr/src/cmd/dlstat/dlstat.c
@@ -70,7 +70,7 @@ typedef struct link_chain_s {
struct link_chain_s *lc_next;
} link_chain_t;
-typedef void * (*stats2str_t)(const char *, void *,
+typedef void * (*stats2str_t)(const char *, const char *, void *,
char, boolean_t);
typedef struct show_state {
@@ -147,6 +147,7 @@ typedef struct total_fields_buf_s {
char t_rbytes[MAXSTATLEN];
char t_opackets[MAXSTATLEN];
char t_obytes[MAXSTATLEN];
+ char t_zone[ZONENAME_MAX];
} total_fields_buf_t;
static ofmt_field_t total_s_fields[] = {
@@ -160,6 +161,8 @@ static ofmt_field_t total_s_fields[] = {
offsetof(total_fields_buf_t, t_opackets), print_default_cb},
{ "OBYTES", 8,
offsetof(total_fields_buf_t, t_obytes), print_default_cb},
+{ "ZONE", 20,
+ offsetof(total_fields_buf_t, t_zone), print_default_cb},
{ NULL, 0, 0, NULL}};
/*
@@ -963,8 +966,8 @@ cleanup_removed_links(show_state_t *state)
}
void *
-print_total_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_total_stats(const char *linkname, const char *zonename, void *statentry,
+ char unit, boolean_t parsable)
{
total_stat_entry_t *sentry = statentry;
total_stat_t *link_stats = &sentry->tse_stats;
@@ -976,6 +979,7 @@ print_total_stats(const char *linkname, void *statentry, char unit,
(void) snprintf(buf->t_linkname, sizeof (buf->t_linkname), "%s",
linkname);
+ (void) snprintf(buf->t_zone, sizeof (buf->t_zone), "%s", zonename);
map_to_units(buf->t_ipackets, sizeof (buf->t_ipackets),
link_stats->ts_ipackets, unit, parsable);
@@ -994,8 +998,8 @@ done:
}
void *
-print_rx_generic_ring_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_rx_generic_ring_stats(const char *linkname, const char *zonename,
+ void *statentry, char unit, boolean_t parsable)
{
ring_stat_entry_t *sentry = statentry;
ring_stat_t *link_stats = &sentry->re_stats;
@@ -1028,8 +1032,8 @@ done:
}
void *
-print_tx_generic_ring_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_tx_generic_ring_stats(const char *linkname, const char *zonename,
+ void *statentry, char unit, boolean_t parsable)
{
ring_stat_entry_t *sentry = statentry;
ring_stat_t *link_stats = &sentry->re_stats;
@@ -1062,8 +1066,8 @@ done:
}
void *
-print_rx_ring_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_rx_ring_stats(const char *linkname, const char *zonename, void *statentry,
+ char unit, boolean_t parsable)
{
ring_stat_entry_t *sentry = statentry;
ring_stat_t *link_stats = &sentry->re_stats;
@@ -1096,8 +1100,8 @@ done:
}
void *
-print_tx_ring_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_tx_ring_stats(const char *linkname, const char *zonename, void *statentry,
+ char unit, boolean_t parsable)
{
ring_stat_entry_t *sentry = statentry;
ring_stat_t *link_stats = &sentry->re_stats;
@@ -1130,8 +1134,8 @@ done:
}
void *
-print_rx_generic_lane_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_rx_generic_lane_stats(const char *linkname, const char *zonename,
+ void *statentry, char unit, boolean_t parsable)
{
rx_lane_stat_entry_t *sentry = statentry;
rx_lane_stat_t *link_stats = &sentry->rle_stats;
@@ -1178,8 +1182,8 @@ done:
}
void *
-print_tx_generic_lane_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_tx_generic_lane_stats(const char *linkname, const char *zonename,
+ void *statentry, char unit, boolean_t parsable)
{
tx_lane_stat_entry_t *sentry = statentry;
tx_lane_stat_t *link_stats = &sentry->tle_stats;
@@ -1223,8 +1227,8 @@ done:
}
void *
-print_rx_lane_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_rx_lane_stats(const char *linkname, const char *zonename, void *statentry,
+ char unit, boolean_t parsable)
{
rx_lane_stat_entry_t *sentry = statentry;
rx_lane_stat_t *link_stats = &sentry->rle_stats;
@@ -1289,8 +1293,8 @@ done:
}
void *
-print_tx_lane_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_tx_lane_stats(const char *linkname, const char *zonename, void *statentry,
+ char unit, boolean_t parsable)
{
tx_lane_stat_entry_t *sentry = statentry;
tx_lane_stat_t *link_stats = &sentry->tle_stats;
@@ -1344,8 +1348,8 @@ done:
}
void *
-print_fanout_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_fanout_stats(const char *linkname, const char *zonename, void *statentry,
+ char unit, boolean_t parsable)
{
fanout_stat_entry_t *sentry = statentry;
fanout_stat_t *link_stats = &sentry->fe_stats;
@@ -1398,8 +1402,8 @@ done:
}
void *
-print_aggr_port_stats(const char *linkname, void *statentry, char unit,
- boolean_t parsable)
+print_aggr_port_stats(const char *linkname, const char *zonename,
+ void *statentry, char unit, boolean_t parsable)
{
aggr_port_stat_entry_t *sentry = statentry;
aggr_port_stat_t *link_stats = &sentry->ape_stats;
@@ -1476,7 +1480,8 @@ done:
void
walk_dlstat_stats(show_state_t *state, const char *linkname,
- dladm_stat_type_t stattype, dladm_stat_chain_t *diff_stat)
+ const char *zonename, dladm_stat_type_t stattype,
+ dladm_stat_chain_t *diff_stat)
{
dladm_stat_chain_t *curr;
@@ -1486,7 +1491,8 @@ walk_dlstat_stats(show_state_t *state, const char *linkname,
/* Format the raw numbers for printing */
fields_buf = state->ls_stats2str[stattype](linkname,
- curr->dc_statentry, state->ls_unit, state->ls_parsable);
+ zonename, curr->dc_statentry, state->ls_unit,
+ state->ls_parsable);
/* Print the stats */
if (fields_buf != NULL)
ofmt_print(state->ls_ofmt, fields_buf);
@@ -1501,12 +1507,20 @@ show_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
int i;
dladm_stat_chain_t *diff_stat;
char linkname[DLPI_LINKNAME_MAX];
+ char zonename[DLADM_PROP_VAL_MAX + 1];
+ char *valptr[1];
+ uint_t valcnt = 1;
if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
goto done;
}
+ valptr[0] = zonename;
+ if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, "zone",
+ (char **)valptr, &valcnt) != 0)
+ zonename[0] = '\0';
+
for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
if (state->ls_stattype[i]) {
/*
@@ -1514,7 +1528,8 @@ show_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
* Stats are returned as chain of raw numbers
*/
diff_stat = query_link_stats(handle, linkid, arg, i);
- walk_dlstat_stats(state, linkname, i, diff_stat);
+ walk_dlstat_stats(state, linkname, zonename, i,
+ diff_stat);
dladm_link_stat_free(diff_stat);
}
}
@@ -1634,7 +1649,7 @@ do_show(int argc, char *argv[], const char *use)
char *o_fields_str = NULL;
char *total_stat_fields =
- "link,ipkts,rbytes,opkts,obytes";
+ "link,ipkts,rbytes,opkts,obytes,zone";
char *rx_total_stat_fields =
"link,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
char *tx_total_stat_fields =
diff --git a/usr/src/cmd/dtrace/demo/Makefile b/usr/src/cmd/dtrace/demo/Makefile
index a75a418a96..cfb35083ee 100644
--- a/usr/src/cmd/dtrace/demo/Makefile
+++ b/usr/src/cmd/dtrace/demo/Makefile
@@ -21,6 +21,8 @@
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
#
+# Copyright (c) 2018, Joyent, Inc.
+#
include ../../Makefile.cmd
@@ -157,11 +159,11 @@ $(ROOTDEMODIR):
$(ROOTDEMODIR)/%: %
$(INS.file)
-$(HTMLFILES): $(DFILES) $(MKDEMO)
- ./$(MKDEMO) $@
+$(HTMLFILES): $(DFILES) $(MKDEMO)
+ $(PERL) ./$(MKDEMO) $@
-$(DFILES): $(MKDEMO)
- ./$(MKDEMO) $@
+$(DFILES): $(MKDEMO)
+ $(PERL) ./$(MKDEMO) $@
$(ROOTDEMOFILES): $(ROOTDEMODIR)
diff --git a/usr/src/cmd/dtrace/test/README b/usr/src/cmd/dtrace/test/README
index 51ab650fd7..094f70e7da 100644
--- a/usr/src/cmd/dtrace/test/README
+++ b/usr/src/cmd/dtrace/test/README
@@ -20,13 +20,10 @@ CDDL HEADER END
Copyright 2006 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
-
-ident "%Z%%M% %I% %E% SMI"
+Copyright 2017 Joyent, Inc.
DTrace Testing Suite
The SUNWdtrt package delivers a set of test programs and D source
-files into the directory /opt/SUNWdtrt. For more information see
-the following web site:
-
- http://www.opensolaris.org/os/community/dtrace/dtest
+files into the directory /opt/SUNWdtrt. To run the tests:
+ /opt/SUNWdtrt/bin/dtest
diff --git a/usr/src/cmd/dtrace/test/cmd/jdtrace/Makefile b/usr/src/cmd/dtrace/test/cmd/jdtrace/Makefile
index 66479e77bc..ee93b7a258 100644
--- a/usr/src/cmd/dtrace/test/cmd/jdtrace/Makefile
+++ b/usr/src/cmd/dtrace/test/cmd/jdtrace/Makefile
@@ -75,7 +75,7 @@ $(PROG): $(SRCS)
$(POST_PROCESS) ; $(STRIP_STABS)
JFLAGS= -g -cp $(CLASSPATH) -d $(CLASSDIR)
-JFLAGS += -source 1.5 -target 1.6 -Xlint:all,-options
+JFLAGS += -source 1.5 -target 1.6 -Xlint:all,-options,-path
COMPILE.java=$(JAVAC) $(JFLAGS)
JAVASRC= JDTrace.java Getopt.java
diff --git a/usr/src/cmd/dtrace/test/cmd/scripts/dtest.pl b/usr/src/cmd/dtrace/test/cmd/scripts/dtest.pl
index d6f1c8c277..e7f9189822 100644
--- a/usr/src/cmd/dtrace/test/cmd/scripts/dtest.pl
+++ b/usr/src/cmd/dtrace/test/cmd/scripts/dtest.pl
@@ -566,7 +566,7 @@ $defdir = -d $dt_tst ? $dt_tst : '.';
$bindir = -d $dt_bin ? $dt_bin : '.';
if (!$opt_F) {
- my @dependencies = ("gcc", "make", "java", "perl");
+ my @dependencies = ("gcc", "cc", "make", "java", "perl", "printenv");
for my $dep (@dependencies) {
if (!inpath($dep)) {
diff --git a/usr/src/cmd/dtrace/test/tst/Makefile.com b/usr/src/cmd/dtrace/test/tst/Makefile.com
index 0d8fb3316c..b7100f4af5 100644
--- a/usr/src/cmd/dtrace/test/tst/Makefile.com
+++ b/usr/src/cmd/dtrace/test/tst/Makefile.com
@@ -113,6 +113,6 @@ scripts: FRC
@cd ../cmd/scripts; pwd; $(MAKE) install
dstyle: FRC
- @if [ -n "$(DSRCS)" ]; then $(DSTYLE) $(DSRCS); fi
+ @if [ -n "$(DSRCS)" ]; then $(PERL) $(DSTYLE) $(DSRCS); fi
FRC:
diff --git a/usr/src/cmd/dtrace/test/tst/common/Makefile b/usr/src/cmd/dtrace/test/tst/common/Makefile
index a29d774069..9ec706565a 100644
--- a/usr/src/cmd/dtrace/test/tst/common/Makefile
+++ b/usr/src/cmd/dtrace/test/tst/common/Makefile
@@ -149,6 +149,14 @@ usdt/tst.forker.o: usdt/forker.h
usdt/forker.h: usdt/forker.d
$(DTRACE) -h -s usdt/forker.d -o usdt/forker.h
+ustack/tst.unpriv.exe: ustack/tst.unpriv.o ustack/unpriv_helper.o
+ $(LINK.c) -o ustack/tst.unpriv.exe \
+ ustack/tst.unpriv.o ustack/unpriv_helper.o $(LDLIBS)
+ $(POST_PROCESS) ; $(STRIP_STABS)
+
+ustack/unpriv_helper.o: ustack/unpriv_helper.d
+ $(COMPILE.d) -o ustack/unpriv_helper.o -s ustack/unpriv_helper.d
+
usdt/tst.lazyprobe.exe: usdt/tst.lazyprobe.o usdt/lazyprobe.o
$(LINK.c) -o usdt/tst.lazyprobe.exe \
usdt/tst.lazyprobe.o usdt/lazyprobe.o $(LDLIBS)
diff --git a/usr/src/cmd/dtrace/test/tst/common/java_api/Makefile b/usr/src/cmd/dtrace/test/tst/common/java_api/Makefile
index 43daede8e8..04e6cca7b4 100644
--- a/usr/src/cmd/dtrace/test/tst/common/java_api/Makefile
+++ b/usr/src/cmd/dtrace/test/tst/common/java_api/Makefile
@@ -60,7 +60,7 @@ lint:
install: all $(PROTO_TEST_JAR)
JFLAGS= -g -cp $(CLASSPATH) -d $(CLASSDIR)
-JFLAGS += -source 1.5 -target 1.6 -Xlint:all,-options,-rawtypes
+JFLAGS += -source 1.5 -target 1.6 -Xlint:all,-options,-rawtypes,-path
COMPILE.java=$(JAVAC) $(JFLAGS)
$(TEST_JAR): $(SRCDIR)/*.java
diff --git a/usr/src/cmd/dtrace/test/tst/common/llquantize/tst.range.d b/usr/src/cmd/dtrace/test/tst/common/llquantize/tst.range.d
index e2882b3f8e..a9138d2f54 100644
--- a/usr/src/cmd/dtrace/test/tst/common/llquantize/tst.range.d
+++ b/usr/src/cmd/dtrace/test/tst/common/llquantize/tst.range.d
@@ -19,10 +19,6 @@
* CDDL HEADER END
*/
-/*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
- */
-
#pragma D option quiet
BEGIN
diff --git a/usr/src/cmd/dtrace/test/tst/common/mdb/tst.postmort.ksh b/usr/src/cmd/dtrace/test/tst/common/mdb/tst.postmort.ksh
new file mode 100644
index 0000000000..c5921b8d28
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/mdb/tst.postmort.ksh
@@ -0,0 +1,69 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+DIR=/var/tmp/dtest.$$
+
+mkdir $DIR
+cd $DIR
+
+expected=`od -t u8 -N 8 /dev/urandom | head -1 | cut -d ' ' -f2`
+
+$dtrace -x bufpolicy=ring -x bufsize=10k -qs /dev/stdin > /dev/null 2>&1 <<EOF &
+ tick-1ms
+ /i < 10000/
+ {
+ printf("%d: expected is $expected!\n", i++);
+ }
+
+ tick-1ms
+ /i >= 10000/
+ {
+ exit(0);
+ }
+EOF
+
+background=$!
+
+#
+# Give some time for the enabling to get there...
+#
+sleep 2
+
+echo "::walk dtrace_state | ::dtrace" | mdb -k | tee test.out
+grep "expected is $expected" test.out 2> /dev/null 1>&2
+status=$?
+
+kill $background
+
+cd /
+/usr/bin/rm -rf $DIR
+
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.c b/usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.c
new file mode 100644
index 0000000000..43ba244444
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.c
@@ -0,0 +1,7 @@
+int
+main(int argc, char *argv[])
+{
+ for (;;)
+ ;
+ return (0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.ksh b/usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.ksh
new file mode 100644
index 0000000000..26c430bff7
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/ustack/tst.unpriv.ksh
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+ppriv -s A=basic,dtrace_user,dtrace_proc $$
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+file=out.$$
+dtrace=$1
+
+rm -f $file
+
+dir=`/bin/dirname $tst`
+
+$dtrace -o $file -c $dir/tst.unpriv.exe -ws /dev/stdin <<EOF
+ profile-1234hz
+ /pid == \$target/
+ {
+ @[ustack(20, 8192)] = count();
+ }
+
+ tick-1s
+ {
+ secs++;
+ }
+
+ tick-1s
+ /secs > 10/
+ {
+ trace("test timed out");
+ exit(1);
+ }
+
+ profile-1234hz
+ /pid == \$target && secs > 5/
+ {
+ raise(SIGINT);
+ exit(0);
+ }
+EOF
+
+status=$?
+exit $status
diff --git a/usr/src/cmd/dtrace/test/tst/common/ustack/unpriv_helper.d b/usr/src/cmd/dtrace/test/tst/common/ustack/unpriv_helper.d
new file mode 100644
index 0000000000..eb7b0e9e9d
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/ustack/unpriv_helper.d
@@ -0,0 +1,4 @@
+dtrace:helper:ustack:
+{
+ this->otherstr = "doogle";
+}
diff --git a/usr/src/cmd/dumpadm/Makefile b/usr/src/cmd/dumpadm/Makefile
index e1303c5d0e..c6b80188fa 100644
--- a/usr/src/cmd/dumpadm/Makefile
+++ b/usr/src/cmd/dumpadm/Makefile
@@ -26,12 +26,12 @@
PROG = dumpadm
MANIFEST = dumpadm.xml
SVCMETHOD= svc-dumpadm
+ETCFILES= dumpadm.conf
OBJS = main.o dconf.o minfree.o utils.o swap.o
SRCS = $(OBJS:.o=.c)
-
-lint := LINTFLAGS = -mx
+ROOTETCFILES= $(ETCFILES:%=$(ROOTETC)/%)
include ../Makefile.cmd
@@ -52,13 +52,11 @@ $(PROG): $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
$(POST_PROCESS)
-install: all $(ROOTUSRSBINPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+install: all $(ROOTUSRSBINPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTETCFILES)
check: $(CHKMANIFEST)
clean:
$(RM) $(OBJS)
-lint: lint_SRCS
-
include ../Makefile.targ
diff --git a/usr/src/cmd/dumpadm/dconf.c b/usr/src/cmd/dumpadm/dconf.c
index dc5355ba48..6e549afaa7 100644
--- a/usr/src/cmd/dumpadm/dconf.c
+++ b/usr/src/cmd/dumpadm/dconf.c
@@ -28,6 +28,7 @@
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/dumpadm.h>
+#include <sys/dumphdr.h>
#include <sys/utsname.h>
#include <unistd.h>
@@ -539,6 +540,42 @@ dconf_get_dumpsize(dumpconf_t *dcp)
return (0);
}
+int
+dconf_set_crypt(dumpconf_t *dcp, const char *keyfile)
+{
+ int fd;
+ uint8_t key[DUMP_CRYPT_KEYLEN];
+
+ if ((fd = open(keyfile, O_RDONLY)) == -1) {
+ warn(gettext("failed to open %s"), keyfile);
+ return (-1);
+ }
+
+ if (read(fd, key, sizeof (key)) != sizeof (key)) {
+ warn(gettext("failed to read %d byte key from %s"),
+ DUMP_CRYPT_KEYLEN, keyfile);
+ (void) close(fd);
+ return (-1);
+ }
+
+ (void) close(fd);
+
+ if (ioctl(dcp->dc_dump_fd, DIOCSCRYPTKEY, key) == -1) {
+ warn(gettext("failed to set encryption key"));
+ return (-1);
+ }
+
+ /*
+ * Reload our config flags as they may have changed.
+ */
+ if ((dcp->dc_cflags = ioctl(dcp->dc_dump_fd, DIOCGETCONF, 0)) == -1) {
+ warn(gettext("failed to get kernel dump settings"));
+ return (-1);
+ }
+
+ return (0);
+}
+
void
dconf_print(dumpconf_t *dcp, FILE *fp)
{
@@ -580,6 +617,8 @@ dconf_print(dumpconf_t *dcp, FILE *fp)
(void) fprintf(fp, gettext(" Save compressed: %s\n"),
(dcp->dc_csave == DC_UNCOMPRESSED) ? gettext("off") :
gettext("on"));
+ (void) fprintf(fp, gettext(" Dump encrypted: %s\n"),
+ (dcp->dc_cflags & DUMP_ENCRYPT) ? gettext("yes") : gettext("no"));
}
int
diff --git a/usr/src/cmd/dumpadm/dconf.h b/usr/src/cmd/dumpadm/dconf.h
index 74920f0def..e2f609cee7 100644
--- a/usr/src/cmd/dumpadm/dconf.h
+++ b/usr/src/cmd/dumpadm/dconf.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _DCONF_H
@@ -73,6 +74,7 @@ extern int dconf_update(dumpconf_t *, int);
extern void dconf_print(dumpconf_t *, FILE *);
extern int dconf_write_uuid(dumpconf_t *);
extern int dconf_get_dumpsize(dumpconf_t *);
+extern int dconf_set_crypt(dumpconf_t *, const char *);
extern int dconf_str2device(dumpconf_t *, char *);
extern int dconf_str2savdir(dumpconf_t *, char *);
diff --git a/usr/src/cmd/dumpadm/dumpadm.conf b/usr/src/cmd/dumpadm/dumpadm.conf
new file mode 100644
index 0000000000..804e1da11a
--- /dev/null
+++ b/usr/src/cmd/dumpadm/dumpadm.conf
@@ -0,0 +1,11 @@
+#
+# dumpadm.conf
+#
+# Configuration parameters for system crash dump.
+# Do NOT edit this file by hand -- use dumpadm(1m) instead.
+#
+DUMPADM_DEVICE=/dev/zvol/dsk/zones/dump
+DUMPADM_SAVDIR=/var/crash/volatile
+DUMPADM_CONTENT=kernel
+DUMPADM_ENABLE=no
+DUMPADM_CSAVE=on
diff --git a/usr/src/cmd/dumpadm/main.c b/usr/src/cmd/dumpadm/main.c
index 07a7dd5207..dccafbba33 100644
--- a/usr/src/cmd/dumpadm/main.c
+++ b/usr/src/cmd/dumpadm/main.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/stat.h>
@@ -36,10 +37,10 @@
static const char USAGE[] = "\
Usage: %s [-enuy] [-c kernel | curproc | all ]\n\
- [-d dump-device | swap | none ] [-m min {k|m|%%} ] [-s savecore-dir]\n\
- [-r root-dir] [-z on|off]\n";
+ [-d dump-device | swap | none ] [-k key-file] [-m min {k|m|%%} ]\n\
+ [-s savecore-dir] [-r root-dir] [-z on|off]\n";
-static const char OPTS[] = "einuyc:d:m:s:r:z:";
+static const char OPTS[] = "einuyc:d:m:s:r:z:k:";
static const char PATH_DEVICE[] = "/dev/dump";
static const char PATH_CONFIG[] = "/etc/dumpadm.conf";
@@ -57,6 +58,7 @@ main(int argc, char *argv[])
int dcmode = DC_CURRENT; /* kernel settings override unless -u */
int modified = 0; /* have we modified the dump config? */
char *minfstr = NULL; /* string value of -m argument */
+ char *keyfile = NULL; /* key file for -k argument */
dumpconf_t dc; /* current configuration */
int chrooted = 0;
int douuid = 0;
@@ -136,6 +138,9 @@ main(int argc, char *argv[])
}
douuid++;
break;
+ case 'k':
+ keyfile = optarg;
+ break;
case 'm':
minfstr = optarg;
@@ -191,6 +196,9 @@ main(int argc, char *argv[])
return (E_ERROR);
}
+ if (keyfile != NULL && dconf_set_crypt(&dc, keyfile) == -1)
+ return (E_ERROR);
+
if (dcmode == DC_OVERRIDE) {
/*
* In override mode, we try to force an update. If this
diff --git a/usr/src/cmd/dumpadm/svc-dumpadm b/usr/src/cmd/dumpadm/svc-dumpadm
index 316e075754..488ba8d54d 100644
--- a/usr/src/cmd/dumpadm/svc-dumpadm
+++ b/usr/src/cmd/dumpadm/svc-dumpadm
@@ -21,6 +21,7 @@
#
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2020 Joyent, Inc.
#
. /lib/svc/share/smf_include.sh
@@ -100,7 +101,7 @@ fi
# how to modify the dump settings.
#
if [ -x /usr/sbin/dumpadm ]; then
- /usr/sbin/dumpadm -u || $SMF_EXIT_ERR_CONFIG
+ /usr/sbin/dumpadm -u || exit $SMF_EXIT_ERR_CONFIG
else
echo "WARNING: /usr/sbin/dumpadm is missing or not executable" >& 2
exit $SMF_EXIT_ERR_CONFIG
@@ -113,6 +114,11 @@ else
exit $SMF_EXIT_ERR_CONFIG
fi
+if [[ -f $DUMPADM_SAVDIR/keyfile ]]; then
+ /usr/sbin/dumpadm -k $DUMPADM_SAVDIR/keyfile || \
+ exit $SMT_EXIT_ERR_CONFIG
+fi
+
#
# If the savecore executable is absent then we're done
#
@@ -147,11 +153,15 @@ if [ "x$DUMPADM_ENABLE" != xno ]; then
mksavedir && /usr/bin/savecore $DUMPADM_SAVDIR &
fi
else
+ keyarg=""
+ [[ -f "$DUMPADM_SAVDIR/keyfile" ]] && \
+ keyarg="-k $DUMPADM_SAVDIR/keyfile"
+
#
# The dump device couldn't have been dedicated before we
# ran dumpadm, so we must execute savecore again.
#
- mksavedir && /usr/bin/savecore $DUMPADM_SAVDIR &
+ mksavedir && /usr/bin/savecore $keyarg $DUMPADM_SAVDIR &
fi
else
#
diff --git a/usr/src/cmd/flowadm/flowadm.c b/usr/src/cmd/flowadm/flowadm.c
index 058c1e03d8..a1f1c7387e 100644
--- a/usr/src/cmd/flowadm/flowadm.c
+++ b/usr/src/cmd/flowadm/flowadm.c
@@ -236,9 +236,9 @@ usage(void)
(void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
" <args>...\n"
" add-flow [-t] -l <link> -a <attr>=<value>[,...]\n"
- "\t\t [-p <prop>=<value>,...] <flow>\n"
- " remove-flow [-t] {-l <link> | <flow>}\n"
- " show-flow [-p] [-l <link>] "
+ "\t\t [-p <prop>=<value>,...] [-z zonename] <flow>\n"
+ " remove-flow [-t] [-z zonename] {-l <link> | <flow>}\n"
+ " show-flow [-p] [-l <link>] [-z zonename] "
"[<flow>]\n\n"
" set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n"
" reset-flowprop [-t] [-p <prop>,...] <flow>\n"
@@ -336,11 +336,12 @@ do_add_flow(int argc, char *argv[])
dladm_arg_list_t *proplist = NULL;
dladm_arg_list_t *attrlist = NULL;
dladm_status_t status;
+ char *zonename = NULL;
bzero(propstr, DLADM_STRSIZE);
bzero(attrstr, DLADM_STRSIZE);
- while ((option = getopt_long(argc, argv, "tR:l:a:p:",
+ while ((option = getopt_long(argc, argv, "tR:l:a:p:z:",
prop_longopts, NULL)) != -1) {
switch (option) {
case 't':
@@ -354,9 +355,6 @@ do_add_flow(int argc, char *argv[])
MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
die("link name too long");
}
- if (dladm_name2info(handle, devname, &linkid, NULL,
- NULL, NULL) != DLADM_STATUS_OK)
- die("invalid link '%s'", devname);
l_arg = B_TRUE;
break;
case 'a':
@@ -371,6 +369,9 @@ do_add_flow(int argc, char *argv[])
DLADM_STRSIZE)
die("property list too long '%s'", propstr);
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option);
}
@@ -379,6 +380,10 @@ do_add_flow(int argc, char *argv[])
die("link is required");
}
+ if (dladm_zname2info(handle, zonename, devname, &linkid, NULL,
+ NULL, NULL) != DLADM_STATUS_OK)
+ die("invalid link '%s'", devname);
+
opterr = 0;
index = optind;
@@ -417,11 +422,12 @@ do_remove_flow(int argc, char *argv[])
boolean_t l_arg = B_FALSE;
remove_flow_state_t state;
dladm_status_t status;
+ char *zonename = NULL;
bzero(&state, sizeof (state));
opterr = 0;
- while ((option = getopt_long(argc, argv, ":tR:l:",
+ while ((option = getopt_long(argc, argv, ":tR:l:z:",
longopts, NULL)) != -1) {
switch (option) {
case 't':
@@ -435,12 +441,11 @@ do_remove_flow(int argc, char *argv[])
MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
die("link name too long");
}
- if (dladm_name2info(handle, linkname, &linkid, NULL,
- NULL, NULL) != DLADM_STATUS_OK) {
- die("invalid link '%s'", linkname);
- }
l_arg = B_TRUE;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option);
break;
@@ -461,6 +466,12 @@ do_remove_flow(int argc, char *argv[])
/* if link is specified then flow name should not be there */
if (optind == argc-1)
usage();
+
+ if (dladm_zname2info(handle, zonename, linkname, &linkid, NULL,
+ NULL, NULL) != DLADM_STATUS_OK) {
+ die("invalid link '%s'", linkname);
+ }
+
/* walk the link to find flows and remove them */
state.fs_tempop = t_arg;
state.fs_altroot = altroot;
@@ -600,11 +611,12 @@ do_show_flow(int argc, char *argv[])
ofmt_handle_t ofmt;
ofmt_status_t oferr;
uint_t ofmtflags = 0;
+ char *zonename = NULL;
bzero(&state, sizeof (state));
opterr = 0;
- while ((option = getopt_long(argc, argv, ":pPl:o:",
+ while ((option = getopt_long(argc, argv, ":pPl:o:z:",
longopts, NULL)) != -1) {
switch (option) {
case 'p':
@@ -625,17 +637,23 @@ do_show_flow(int argc, char *argv[])
if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
>= MAXLINKNAMELEN)
die("link name too long\n");
- if (dladm_name2info(handle, linkname, &linkid, NULL,
- NULL, NULL) != DLADM_STATUS_OK)
- die("invalid link '%s'", linkname);
l_arg = B_TRUE;
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option);
break;
}
}
+ if (l_arg) {
+ if (dladm_zname2info(handle, zonename, linkname, &linkid, NULL,
+ NULL, NULL) != DLADM_STATUS_OK)
+ die("invalid link '%s'", linkname);
+ }
+
/* get flow name (optional last argument */
if (optind == (argc-1)) {
if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
diff --git a/usr/src/cmd/flowstat/flowstat.c b/usr/src/cmd/flowstat/flowstat.c
index 23e973c8a2..a0e2b85f32 100644
--- a/usr/src/cmd/flowstat/flowstat.c
+++ b/usr/src/cmd/flowstat/flowstat.c
@@ -201,9 +201,9 @@ static char *progname;
static dladm_handle_t handle = NULL;
const char *usage_ermsg = "flowstat [-r | -t] [-i interval] "
- "[-l link] [flow]\n"
+ "[-l link] [-z zonename] [flow]\n"
" flowstat [-A] [-i interval] [-p] [ -o field[,...]]\n"
- " [-u R|K|M|G|T|P] [-l link] [flow]\n"
+ " [-u R|K|M|G|T|P] [-l link] [-z zonename] [flow]\n"
" flowstat -h [-a] [-d] [-F format]"
" [-s <DD/MM/YYYY,HH:MM:SS>]\n"
" [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> "
@@ -566,6 +566,7 @@ main(int argc, char *argv[])
show_flow_state_t state;
char *fields_str = NULL;
char *o_fields_str = NULL;
+ char *zonename = NULL;
char *total_stat_fields =
"flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs";
@@ -592,10 +593,11 @@ main(int argc, char *argv[])
if ((status = dladm_open(&handle)) != DLADM_STATUS_OK)
die_dlerr(status, "could not open /dev/dld");
+ linkname[0] = '\0';
bzero(&state, sizeof (state));
opterr = 0;
- while ((option = getopt_long(argc, argv, ":rtApi:o:u:l:h",
+ while ((option = getopt_long(argc, argv, ":rtApi:o:u:l:hz:",
NULL, NULL)) != -1) {
switch (option) {
case 'r':
@@ -647,9 +649,6 @@ main(int argc, char *argv[])
if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
>= MAXLINKNAMELEN)
die("link name too long\n");
- if (dladm_name2info(handle, linkname, &linkid, NULL,
- NULL, NULL) != DLADM_STATUS_OK)
- die("invalid link '%s'", linkname);
break;
case 'h':
if (r_arg || t_arg || p_arg || o_arg || u_arg ||
@@ -660,6 +659,9 @@ main(int argc, char *argv[])
do_show_history(argc, argv);
return (0);
break;
+ case 'z':
+ zonename = optarg;
+ break;
default:
die_opterr(optopt, option, usage_ermsg);
break;
@@ -683,6 +685,12 @@ main(int argc, char *argv[])
die("the option -A is not compatible with "
"-r, -t, -p, -o, -u, -i");
+ if (linkname[0] != '\0') {
+ if (dladm_zname2info(handle, zonename, linkname, &linkid, NULL,
+ NULL, NULL) != DLADM_STATUS_OK)
+ die("invalid link '%s'", linkname);
+ }
+
/* get flow name (optional last argument) */
if (optind == (argc-1)) {
if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
diff --git a/usr/src/cmd/fm/fmdump/common/nvlrender.c b/usr/src/cmd/fm/fmdump/common/nvlrender.c
index 2c2f5ca662..99f027a77d 100644
--- a/usr/src/cmd/fm/fmdump/common/nvlrender.c
+++ b/usr/src/cmd/fm/fmdump/common/nvlrender.c
@@ -83,7 +83,7 @@ fmdump_render_nvlist(nvlist_prtctl_t pctl, void *private, nvlist_t *nvl,
int
fmdump_print_json(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
{
- if (nvlist_print_json(fp, rp->rec_nvl) != 0 || fprintf(fp, "\n") < 0 ||
+ if (nvlist_print_json(fp, rp->rec_nvl) < 0 || fprintf(fp, "\n") < 0 ||
fflush(fp) != 0)
return (-1);
diff --git a/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h
index f33ea9ecd6..96e1a956af 100644
--- a/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _FABRIC_XLATE_H
@@ -31,6 +32,7 @@
#include <sys/types.h>
#include <sys/pcie.h>
#include <sys/fm/io/pci.h>
+#include <limits.h>
#ifdef __cplusplus
extern "C" {
@@ -45,6 +47,17 @@ extern "C" {
#define PF_ADDR_PIO (1 << 1)
#define PF_ADDR_CFG (1 << 2)
+
+/*
+ * The fabric ereport preparation functions (fab_prep_*) in fab_erpt_tbl_t
+ * structures may return an error if the ereport could not be set up properly.
+ * Typically, these errors are errnos. It is possible that based on incoming
+ * ereport payload data, we might not want to generate an ereport at all: In
+ * this case, the preparation functions may instead return PF_EREPORT_IGNORE,
+ * which is set at a high value so as not to collide with the errnos.
+ */
+#define PF_EREPORT_IGNORE INT_MAX
+
extern fmd_xprt_t *fab_fmd_xprt; /* FMD transport layer handle */
extern char fab_buf[];
@@ -121,8 +134,21 @@ typedef struct fab_data {
uint16_t pcie_rp_ctl; /* root complex control register */
uint32_t pcie_rp_err_status; /* pcie root complex error status reg */
uint32_t pcie_rp_err_cmd; /* pcie root complex error cmd reg */
- uint16_t pcie_rp_ce_src_id; /* pcie root complex ce sourpe id */
- uint16_t pcie_rp_ue_src_id; /* pcie root complex ue sourpe id */
+ uint16_t pcie_rp_ce_src_id; /* pcie root complex ce source id */
+ uint16_t pcie_rp_ue_src_id; /* pcie root complex ue source id */
+
+ /*
+ * The slot register values refer to the registers of the component's
+ * parent slot, not the component itself.
+ *
+ * You should only use the register values -- i.e.,
+ * pcie_slot_{cap,control,status} -- if pcie_slot_data_valid is set to
+ * true.
+ */
+ boolean_t pcie_slot_data_valid; /* true if slot data is valid */
+ uint32_t pcie_slot_cap; /* pcie slot capabilities */
+ uint16_t pcie_slot_control; /* pcie slot control */
+ uint16_t pcie_slot_status; /* pcie slot status */
/* Flags */
boolean_t pcie_rp_send_all; /* need to send ereports on all rps */
@@ -131,7 +157,6 @@ typedef struct fab_data {
typedef struct fab_erpt_tbl {
const char *err_class; /* Final Ereport Class */
uint32_t reg_bit; /* Error Bit Mask */
- /* Pointer to function that prepares the ereport body */
const char *tgt_class; /* Target Ereport Class */
} fab_erpt_tbl_t;
diff --git a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c
index 69ecf1aa8d..14ae738863 100644
--- a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_fabric.c
@@ -22,10 +22,13 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2019 Joyent, Inc.
*/
#include <stddef.h>
#include <strings.h>
#include <sys/fm/util.h>
+#include <sys/pcie.h>
#include "fabric-xlate.h"
@@ -271,6 +274,24 @@ fab_pci_fabric_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data)
FAB_LOOKUP(32, "pcie_adv_rp_command", &data->pcie_rp_err_cmd);
FAB_LOOKUP(16, "pcie_adv_rp_ce_src_id", &data->pcie_rp_ce_src_id);
FAB_LOOKUP(16, "pcie_adv_rp_ue_src_id", &data->pcie_rp_ue_src_id);
+
+ /*
+ * PCIe Parent Slot Registers
+ *
+ * These are only passed in the ereport if the parent PCIe component
+ * supports the registers and the registers have valid data. As such, we
+ * look up one slot register value first: If that value is present in
+ * the input ereport data, then we know the others should be there as
+ * well. We also set the pcie_slot_data_valid flag to ensure we know
+ * the slot register data is safe to use in the module.
+ */
+ data->pcie_slot_data_valid = B_FALSE;
+ if (nvlist_lookup_uint32(nvl, "pcie_slot_cap", &data->pcie_slot_cap) ==
+ 0) {
+ FAB_LOOKUP(16, "pcie_slot_control", &data->pcie_slot_control);
+ FAB_LOOKUP(16, "pcie_slot_status", &data->pcie_slot_status);
+ data->pcie_slot_data_valid = B_TRUE;
+ }
}
static int
@@ -358,6 +379,38 @@ fab_prep_pcie_ue_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
PCIE_AER_CTL_FST_ERR_PTR_MASK);
int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
+ if (data->pcie_slot_data_valid) {
+ (void) nvlist_add_uint32(erpt, "pcie_slot_cap",
+ data->pcie_slot_cap);
+ (void) nvlist_add_uint16(erpt, "pcie_slot_control",
+ data->pcie_slot_control);
+ (void) nvlist_add_uint16(erpt, "pcie_slot_status",
+ data->pcie_slot_status);
+
+ /*
+ * It is possible to see uncorrectable errors for a slot that
+ * are related to the slot's child device being physically
+ * removed from the slot. As such, in the case that the slot
+ * reports that it is empty, we do not want to generate an
+ * ereport for all errors. Generating an ereport here will cause
+ * the eft module to fault the device and io-retire to
+ * subsequently retire the device. Retiring the device makes
+ * little sense given that the device is physically gone; more
+ * confusingly, if plugged back into the slot, it would be
+ * marked retired already.
+ *
+ * The only error ignored for this case is Completion Timeout.
+ * It is possible more errors should be ignored, and if they
+ * are seen in the field it might be worth broadening the set
+ * of ignored errors.
+ */
+ if (tbl->reg_bit == PCIE_AER_UCE_TO &&
+ ((data->pcie_slot_status &
+ PCIE_SLOTSTS_PRESENCE_DETECTED) == 0x0)) {
+ return (PF_EREPORT_IGNORE);
+ }
+ }
+
/* Generate an ereport for this error bit. */
(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
PCIEX_ERROR_SUBCLASS, class);
@@ -776,7 +829,7 @@ fab_xlate_pcie_erpts(fmd_hdl_t *hdl, fab_data_t *data)
fmd_hdl_debug(hdl, "Sending Ereports Now");
- /* Go through the error logs and send the relavant reports */
+ /* Go through the error logs and send the relevant reports */
for (tbl = fab_master_err_tbl; tbl->erpt_tbl; tbl++) {
fab_send_erpt(hdl, data, tbl);
}
diff --git a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c
index 8593144b28..94678dbd47 100644
--- a/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c
+++ b/usr/src/cmd/fm/modules/common/fabric-xlate/fx_subr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <strings.h>
#include <fm/topo_hc.h>
@@ -185,6 +186,7 @@ fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
fab_erpt_tbl_t *erpt_tbl, *entry;
nvlist_t *erpt;
uint32_t reg;
+ int err;
erpt_tbl = tbl->erpt_tbl;
if (tbl->reg_size == 16) {
@@ -200,7 +202,9 @@ fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
goto done;
- if (tbl->fab_prep(hdl, data, erpt, entry) != 0) {
+
+ err = tbl->fab_prep(hdl, data, erpt, entry);
+ if (err != 0 && err != PF_EREPORT_IGNORE) {
fmd_hdl_debug(hdl, "Prepping ereport failed: "
"class = %s\n", entry->err_class);
nvlist_free(erpt);
@@ -394,7 +398,7 @@ fab_find_rppath_by_devbdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
xmlNodePtr devNode;
- char *retval, *temp;
+ char *retval, *temp;
char query[500];
int i, size, bus, dev, fn;
char *hcpath;
@@ -577,7 +581,7 @@ fail:
char *
fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf)
{
- char *retval;
+ char *retval;
char query[500];
int bus, dev, fn;
char rcpath[255];
@@ -705,7 +709,7 @@ found:
propgroup:
/* Retrive the "dev" propval and return */
for (devNode = devNode->children; devNode; devNode = devNode->next) {
- char *tprop;
+ char *tprop;
tprop = GET_PROP(devNode, "name");
if (STRCMP(devNode->name, "propval") &&
@@ -866,8 +870,8 @@ fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl)
char *
fab_get_rpdev(fmd_hdl_t *hdl)
{
- char *retval;
- char query[500];
+ char *retval;
+ char query[500];
(void) snprintf(query, sizeof (query), "//propval["
"@name='extended-capabilities' and contains(@value, '%s')]"
@@ -888,8 +892,8 @@ fab_send_erpt_all_rps(fmd_hdl_t *hdl, nvlist_t *erpt)
{
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
- char *rppath, *hbpath;
- char query[600];
+ char *rppath, *hbpath;
+ char query[600];
nvlist_t *detector, *nvl;
uint_t i, size;
size_t len;
diff --git a/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c b/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c
index fa46bc51b3..20f5820cf1 100644
--- a/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c
+++ b/usr/src/cmd/fm/modules/common/zfs-retire/zfs_retire.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/*
* Copyright 2019 Joyent, Inc.
diff --git a/usr/src/cmd/fs.d/Makefile b/usr/src/cmd/fs.d/Makefile
index 2ce08652b7..1b1939e1f7 100644
--- a/usr/src/cmd/fs.d/Makefile
+++ b/usr/src/cmd/fs.d/Makefile
@@ -40,8 +40,8 @@ DEFAULTFILES= fs.dfl
include ../Makefile.cmd
-SUBDIR1= bootfs lofs zfs
-SUBDIR2= dev fd pcfs nfs hsfs proc ctfs udfs ufs tmpfs \
+SUBDIR1= bootfs hyprlofs lofs zfs
+SUBDIR2= dev fd pcfs nfs hsfs lxproc proc ctfs udfs ufs tmpfs \
autofs mntfs objfs sharefs smbclnt reparsed
SUBDIRS= $(SUBDIR1) $(SUBDIR2)
I18NDIRS= $(SUBDIR2)
diff --git a/usr/src/cmd/fs.d/hyprlofs/Makefile b/usr/src/cmd/fs.d/hyprlofs/Makefile
new file mode 100644
index 0000000000..1a3aaf18d3
--- /dev/null
+++ b/usr/src/cmd/fs.d/hyprlofs/Makefile
@@ -0,0 +1,42 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2012, Joyent, Inc. All rights reserved
+#
+
+SUBDIRS= hlcfg mount
+
+all:= TARGET= all
+install:= TARGET= install
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+lint:= TARGET= lint
+
+.KEEP_STATE:
+
+.PARALLEL: $(SUBDIRS)
+
+all install clean clobber lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/fs.d/hyprlofs/hlcfg/Makefile b/usr/src/cmd/fs.d/hyprlofs/hlcfg/Makefile
new file mode 100644
index 0000000000..d2ae22e9fd
--- /dev/null
+++ b/usr/src/cmd/fs.d/hyprlofs/hlcfg/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2012, Joyent, Inc. All rights reserved.
+#
+
+FSTYPE= hyprlofs
+LIBPROG= hlcfg
+
+include ../../Makefile.fstype
+include ../../Makefile.mount
+include ../../Makefile.mount.targ
diff --git a/usr/src/cmd/fs.d/hyprlofs/hlcfg/hlcfg.c b/usr/src/cmd/fs.d/hyprlofs/hlcfg/hlcfg.c
new file mode 100644
index 0000000000..16e8e32b1c
--- /dev/null
+++ b/usr/src/cmd/fs.d/hyprlofs/hlcfg/hlcfg.c
@@ -0,0 +1,244 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * This is a simple test program to exercise the hyprlofs ioctls. This is
+ * not designed as a full featured CLI and only does minimal error checking
+ * and reporting.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <strings.h>
+#include <sys/errno.h>
+#include <sys/fs/hyprlofs.h>
+
+extern int errno;
+
+char *usage = "usage: <fs path> add [<file name> <alias>]+\n"
+ " <fs path> addl [<file name>]+\n"
+ " <fs path> rm [<alias>]+\n"
+ " <fs path> clear"
+ " <fs path> get";
+
+typedef enum {
+ CMD_ADD,
+ CMD_RM,
+ CMD_CLR,
+ CMD_ADDL,
+ CMD_GET
+} cmd_t;
+
+static int
+get_entries(int fd)
+{
+ int err;
+ int i;
+ hyprlofs_curr_entries_t e;
+ hyprlofs_curr_entry_t *ep;
+
+ e.hce_cnt = 0;
+ e.hce_entries = NULL;
+
+ err = ioctl(fd, HYPRLOFS_GET_ENTRIES, &e);
+ if (err != 0 && errno != E2BIG) {
+ perror("ioctl");
+ return (1);
+ }
+
+ if (err == 0) {
+ (void) printf("success, but no entries\n");
+ return (0);
+ }
+
+ /*
+ * E2BIG is what we expect when there are existing mappings
+ * since the current cnt is still returned in that case.
+ */
+ (void) printf("cnt: %d\n", e.hce_cnt);
+
+ /* alloc array and call again, then print array */
+ if ((ep = (hyprlofs_curr_entry_t *)
+ malloc(sizeof (hyprlofs_curr_entry_t) * e.hce_cnt)) == NULL) {
+ (void) fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ e.hce_entries = ep;
+ errno = 0;
+ if (ioctl(fd, HYPRLOFS_GET_ENTRIES, &e) != 0) {
+ /*
+ * Not handling an increase here. We would need to free and
+ * start over to do that, but ok for a test program.
+ */
+ perror("ioctl");
+ free(ep);
+ return (1);
+ }
+ for (i = 0; i < e.hce_cnt; i++)
+ (void) printf("%s %s\n", ep[i].hce_path, ep[i].hce_name);
+
+ free(ep);
+ return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ int i, ap;
+ cmd_t cmd;
+ int cnt = 0;
+ int fd;
+ int rv = 0;
+ hyprlofs_entry_t *e = NULL;
+ hyprlofs_entries_t ents;
+
+ if (argc < 3) {
+ (void) fprintf(stderr, "%s\n", usage);
+ exit(1);
+ }
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ perror("can't open hyprlofs mount");
+ exit(1);
+ }
+
+ if (strcmp(argv[2], "add") == 0) {
+ cmd = CMD_ADD;
+ } else if (strcmp(argv[2], "rm") == 0) {
+ cmd = CMD_RM;
+ } else if (strcmp(argv[2], "clear") == 0) {
+ cmd = CMD_CLR;
+ } else if (strcmp(argv[2], "addl") == 0) {
+ cmd = CMD_ADDL;
+ } else if (strcmp(argv[2], "get") == 0) {
+ cmd = CMD_GET;
+ } else {
+ (void) fprintf(stderr, "%s\n", usage);
+ exit(1);
+ }
+
+ /* Count up the number of parameters. The arg format varies w/ cmd */
+ switch (cmd) {
+ case CMD_ADD:
+ for (i = 3; i < argc; i++) {
+ /* argv[i] is the file path */
+
+ /* The next arg is the alias */
+ if (++i >= argc) {
+ (void) fprintf(stderr, "missing alias for %s\n",
+ argv[i - 1]);
+ exit(1);
+ }
+
+ cnt++;
+ }
+ break;
+ case CMD_ADDL:
+ cnt = argc - 3;
+ break;
+ case CMD_RM:
+ cnt = argc - 3;
+ break;
+ case CMD_CLR: /*FALLTHRU*/
+ case CMD_GET:
+ if (argc > 3) {
+ (void) fprintf(stderr, "%s\n", usage);
+ exit(1);
+ }
+ break;
+ }
+
+ if (cnt > 0) {
+ if ((e = (hyprlofs_entry_t *)malloc(sizeof (hyprlofs_entry_t) *
+ cnt)) == NULL) {
+ (void) fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * Format up the args.
+ * We only setup the path member for the add cmd.
+ * We won't run this loop for the clear cmd.
+ * The addl command is special since we use basename to get the alias.
+ */
+ for (i = 0, ap = 3; i < cnt; i++, ap++) {
+ if (cmd == CMD_ADDL) {
+ e[i].hle_path = argv[ap];
+ e[i].hle_plen = strlen(e[i].hle_path);
+
+ e[i].hle_name = basename(argv[ap]);
+ e[i].hle_nlen = strlen(e[i].hle_name);
+
+ continue;
+ }
+
+ if (cmd == CMD_ADD) {
+ e[i].hle_path = argv[ap++];
+ e[i].hle_plen = strlen(e[i].hle_path);
+ }
+
+ e[i].hle_name = argv[ap];
+ e[i].hle_nlen = strlen(e[i].hle_name);
+ }
+
+ ents.hle_entries = e;
+ ents.hle_len = cnt;
+
+ switch (cmd) {
+ case CMD_ADD: /*FALLTHRU*/
+ case CMD_ADDL:
+ if (ioctl(fd, HYPRLOFS_ADD_ENTRIES, &ents) < 0) {
+ perror("ioctl");
+ rv = 1;
+ }
+ break;
+ case CMD_RM:
+ if (ioctl(fd, HYPRLOFS_RM_ENTRIES, &ents) < 0) {
+ perror("ioctl");
+ rv = 1;
+ }
+ break;
+ case CMD_CLR:
+ if (ioctl(fd, HYPRLOFS_RM_ALL) < 0) {
+ perror("ioctl");
+ rv = 1;
+ }
+ break;
+ case CMD_GET:
+ rv = get_entries(fd);
+ break;
+ }
+
+ (void) close(fd);
+ if (cnt > 0)
+ free(e);
+ return (rv);
+}
diff --git a/usr/src/cmd/fs.d/hyprlofs/mount/Makefile b/usr/src/cmd/fs.d/hyprlofs/mount/Makefile
new file mode 100644
index 0000000000..a0b63d211c
--- /dev/null
+++ b/usr/src/cmd/fs.d/hyprlofs/mount/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2012 Joyent, Inc. All rights reserved.
+#
+
+FSTYPE= hyprlofs
+LIBPROG= mount
+
+include ../../Makefile.fstype
+include ../../Makefile.mount
+include ../../Makefile.mount.targ
diff --git a/usr/src/cmd/fs.d/hyprlofs/mount/mount.c b/usr/src/cmd/fs.d/hyprlofs/mount/mount.c
new file mode 100644
index 0000000000..a95c9ca3c2
--- /dev/null
+++ b/usr/src/cmd/fs.d/hyprlofs/mount/mount.c
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2012 Joyent, Inc. All rights reserved.
+ */
+
+#define HLFS
+#define MNTTYPE_HYFS "hyprlofs"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <errno.h>
+#include <sys/fstyp.h>
+#include <sys/fsid.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/mount.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <fslib.h>
+
+#define RET_OK 0
+/*
+ * /sbin/mount and the fs-local method understand this exit code to
+ * mean that all the mount failures were related to hyprlofs mounts. Since
+ * this program only attempts to mount hyfs file systems, when it fails
+ * it returns this exit status.
+ */
+#define RET_ERR 111
+
+static void usage(void);
+
+static char optbuf[MAX_MNTOPT_STR] = { '\0', };
+static int optsize = 0;
+
+static char fstype[] = MNTTYPE_HYFS;
+
+/*
+ * usage: mount [-Ormq] [-o options] special mountp
+ *
+ * This mount program is exec'ed by /usr/sbin/mount if '-F hyprlofs' is
+ * specified.
+ */
+int
+main(int argc, char *argv[])
+{
+ int c;
+ char *special; /* Entity being mounted */
+ char *mountp; /* Entity being mounted on */
+ char *savedoptbuf;
+ char *myname;
+ char typename[64];
+ int flags = 0;
+ int errflag = 0;
+ int qflg = 0;
+
+ myname = strrchr(argv[0], '/');
+ myname = myname ? myname+1 : argv[0];
+ (void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname);
+ argv[0] = typename;
+
+ while ((c = getopt(argc, argv, "o:rmOq")) != EOF) {
+ switch (c) {
+ case '?':
+ errflag++;
+ break;
+
+ case 'o':
+ if (strlcpy(optbuf, optarg, sizeof (optbuf)) >=
+ sizeof (optbuf)) {
+ (void) fprintf(stderr,
+ gettext("%s: Invalid argument: %s\n"),
+ myname, optarg);
+ return (2);
+ }
+ optsize = strlen(optbuf);
+ break;
+ case 'O':
+ flags |= MS_OVERLAY;
+ break;
+ case 'r':
+ flags |= MS_RDONLY;
+ break;
+
+ case 'm':
+ flags |= MS_NOMNTTAB;
+ break;
+
+ case 'q':
+ qflg = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ if ((argc - optind != 2) || errflag) {
+ usage();
+ }
+ special = argv[argc - 2];
+ mountp = argv[argc - 1];
+
+ if ((savedoptbuf = strdup(optbuf)) == NULL) {
+ (void) fprintf(stderr, gettext("%s: out of memory\n"),
+ myname);
+ exit(2);
+ }
+ if (mount(special, mountp, flags | MS_OPTIONSTR, fstype, NULL, 0,
+ optbuf, MAX_MNTOPT_STR)) {
+ (void) fprintf(stderr, "mount: ");
+ perror(special);
+ exit(RET_ERR);
+ }
+ if (optsize && !qflg)
+ cmp_requested_to_actual_options(savedoptbuf, optbuf,
+ special, mountp);
+ return (0);
+}
+
+void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: mount [-Ormq] [-o options] special mountpoint\n");
+ exit(RET_ERR);
+}
diff --git a/usr/src/cmd/fs.d/lxproc/Makefile b/usr/src/cmd/fs.d/lxproc/Makefile
new file mode 100644
index 0000000000..77075ef1dd
--- /dev/null
+++ b/usr/src/cmd/fs.d/lxproc/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+FSTYPE= lxproc
+LIBPROG= mount
+
+include ../Makefile.fstype
+include ../Makefile.mount
+include ../Makefile.mount.targ
diff --git a/usr/src/cmd/fs.d/lxproc/mount.c b/usr/src/cmd/fs.d/lxproc/mount.c
new file mode 100644
index 0000000000..5a000997bd
--- /dev/null
+++ b/usr/src/cmd/fs.d/lxproc/mount.c
@@ -0,0 +1,140 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2012 Joyent, Inc. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <errno.h>
+#include <sys/fstyp.h>
+#include <sys/fsid.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/mount.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <fslib.h>
+
+#define RET_OK 0
+#define RET_ERR 33
+
+static void usage(void);
+
+static char optbuf[MAX_MNTOPT_STR] = { '\0', };
+static int optsize = 0;
+
+static char fstype[] = "lxproc";
+
+/*
+ * usage: mount [-Ormq] [-o options] special mountp
+ *
+ * This mount program is exec'ed by /usr/sbin/mount if '-F lxproc' is
+ * specified.
+ */
+int
+main(int argc, char *argv[])
+{
+ int c;
+ char *special; /* Entity being mounted */
+ char *mountp; /* Entity being mounted on */
+ char *savedoptbuf;
+ char *myname;
+ char typename[64];
+ int flags = 0;
+ int errflag = 0;
+ int qflg = 0;
+
+ myname = strrchr(argv[0], '/');
+ myname = myname ? myname+1 : argv[0];
+ (void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname);
+ argv[0] = typename;
+
+ while ((c = getopt(argc, argv, "o:rmOq")) != EOF) {
+ switch (c) {
+ case '?':
+ errflag++;
+ break;
+
+ case 'o':
+ if (strlcpy(optbuf, optarg, sizeof (optbuf)) >=
+ sizeof (optbuf)) {
+ (void) fprintf(stderr,
+ gettext("%s: Invalid argument: %s\n"),
+ myname, optarg);
+ return (2);
+ }
+ optsize = strlen(optbuf);
+ break;
+ case 'O':
+ flags |= MS_OVERLAY;
+ break;
+ case 'r':
+ flags |= MS_RDONLY;
+ break;
+
+ case 'm':
+ flags |= MS_NOMNTTAB;
+ break;
+
+ case 'q':
+ qflg = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ if ((argc - optind != 2) || errflag) {
+ usage();
+ }
+ special = argv[argc - 2];
+ mountp = argv[argc - 1];
+
+ if ((savedoptbuf = strdup(optbuf)) == NULL) {
+ (void) fprintf(stderr, gettext("%s: out of memory\n"),
+ myname);
+ exit(2);
+ }
+ if (mount(special, mountp, flags | MS_OPTIONSTR, fstype, NULL, 0,
+ optbuf, MAX_MNTOPT_STR)) {
+ (void) fprintf(stderr, "mount: ");
+ perror(special);
+ exit(RET_ERR);
+ }
+ if (optsize && !qflg)
+ cmp_requested_to_actual_options(savedoptbuf, optbuf,
+ special, mountp);
+ return (0);
+}
+
+void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: mount [-Ormq] [-o options] special mountpoint\n");
+ exit(RET_ERR);
+}
diff --git a/usr/src/cmd/fs.d/mount.c b/usr/src/cmd/fs.d/mount.c
index 8c8d7034fe..19be4b28c1 100644
--- a/usr/src/cmd/fs.d/mount.c
+++ b/usr/src/cmd/fs.d/mount.c
@@ -18,6 +18,12 @@
*
* CDDL HEADER END
*/
+
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ */
+
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
@@ -52,6 +58,7 @@
#include <stropts.h>
#include <sys/conf.h>
#include <locale.h>
+#include <zone.h>
#include <priv.h>
#include "fslib.h"
@@ -799,6 +806,7 @@ mnterror(int flag)
void
doexec(char *fstype, char *newargv[])
{
+ const char *zroot = zone_get_nroot();
char full_path[PATH_MAX];
char alter_path[PATH_MAX];
char *vfs_path = VFS_PATH;
@@ -806,7 +814,8 @@ doexec(char *fstype, char *newargv[])
int i;
/* build the full pathname of the fstype dependent command. */
- sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname);
+ (void) snprintf(full_path, sizeof (full_path), "%s/%s/%s/%s",
+ (zroot != NULL ? zroot : ""), vfs_path, fstype, myname);
sprintf(alter_path, "%s/%s/%s", alt_path, fstype, myname);
newargv[1] = myname;
diff --git a/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c b/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
index 06dc44a12c..af83923825 100644
--- a/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
+++ b/usr/src/cmd/fs.d/nfs/lib/nfs_sec.c
@@ -45,6 +45,7 @@
#include <stdlib.h>
#include <syslog.h>
#include <synch.h>
+#include <zone.h>
#include <rpc/rpc.h>
#include <nfs/nfs_sec.h>
#include <rpc/rpcsec_gss.h>
@@ -707,12 +708,17 @@ get_seconfig(int whichway, char *name, int num,
{
char line[BUFSIZ]; /* holds each line of NFSSEC_CONF */
FILE *fp; /* file stream for NFSSEC_CONF */
+ char nfssec_conf[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
if ((whichway == GETBYNAME) && (name == NULL))
return (SC_NOTFOUND);
+ (void) snprintf(nfssec_conf, sizeof (nfssec_conf), "%s%s", zroot != NULL ?
+ zroot : "", NFSSEC_CONF);
+
(void) mutex_lock(&matching_lock);
- if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) {
+ if ((fp = fopen(nfssec_conf, "r")) == NULL) {
(void) mutex_unlock(&matching_lock);
return (SC_OPENFAIL);
}
diff --git a/usr/src/cmd/fs.d/nfs/lib/smfcfg.c b/usr/src/cmd/fs.d/nfs/lib/smfcfg.c
index 892f0cd052..4f9399143c 100644
--- a/usr/src/cmd/fs.d/nfs/lib/smfcfg.c
+++ b/usr/src/cmd/fs.d/nfs/lib/smfcfg.c
@@ -22,6 +22,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -344,8 +345,23 @@ fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
} else {
ret = scf_error();
}
- if ((ret != 0) && scf_error() != SCF_ERROR_NONE)
- fprintf(stdout, gettext("%s\n"), scf_strerror(ret));
+ if ((ret != 0) && scf_error() != SCF_ERROR_NONE) {
+ /*
+ * This is a workaround for the NFS service manifests not
+ * containing the proper properties in local zones.
+ *
+ * When in a local zone and the property doesn't exist on an NFS
+ * service (most likely nfs/server or nfs/client), don't print
+ * the error. The caller will still see the correct error code,
+ * but a user creating a delegated dataset or mounting an NFS
+ * share won't see this spurious error.
+ */
+ if (getzoneid() == GLOBAL_ZONEID ||
+ scf_error() != SCF_ERROR_NOT_FOUND) {
+ fprintf(stdout, gettext("%s\n"), scf_strerror(ret));
+ }
+ }
+
out:
fs_smf_fini(phandle);
return (ret);
diff --git a/usr/src/cmd/fs.d/nfs/lib/smfcfg.h b/usr/src/cmd/fs.d/nfs/lib/smfcfg.h
index c06327d801..f0b70907aa 100644
--- a/usr/src/cmd/fs.d/nfs/lib/smfcfg.h
+++ b/usr/src/cmd/fs.d/nfs/lib/smfcfg.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#ifndef _SMFCFG_H
@@ -42,6 +43,7 @@
#include <locale.h>
#include <errno.h>
#include <sys/types.h>
+#include <zone.h>
#ifdef __cplusplus
extern "C" {
diff --git a/usr/src/cmd/fs.d/nfs/lockd/lockd.c b/usr/src/cmd/fs.d/nfs/lockd/lockd.c
index 3541ee13d0..6ea338b01a 100644
--- a/usr/src/cmd/fs.d/nfs/lockd/lockd.c
+++ b/usr/src/cmd/fs.d/nfs/lockd/lockd.c
@@ -23,6 +23,7 @@
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -88,7 +89,7 @@
struct lm_svc_args lmargs = {
.version = LM_SVC_CUR_VERS,
/* fd, n_fmly, n_proto, n_rdev (below) */
- .debug = 0,
+ .n_v4_only = 0,
.timout = 5 * 60,
.grace = 90,
.retransmittimeout = 5
@@ -137,6 +138,8 @@ int (*Mysvc)(int, struct netbuf, struct netconfig *) = nlmsvc;
/* used by cots_listen_event() */
int max_conns_allowed = -1; /* used by cots_listen_event() */
+int debug = 0;
+
int
main(int ac, char *av[])
{
@@ -238,7 +241,7 @@ main(int ac, char *av[])
break;
case 'd': /* debug */
- lmargs.debug = atoi(optarg);
+ debug = atoi(optarg);
break;
case 'g': /* grace_period */
@@ -288,12 +291,12 @@ main(int ac, char *av[])
if (optind != ac)
usage();
- if (lmargs.debug) {
+ if (debug != 0) {
printf("%s: debug= %d, conn_idle_timout= %d,"
" grace_period= %d, listen_backlog= %d,"
" max_connections= %d, max_servers= %d,"
" retrans_timeout= %d\n",
- MyName, lmargs.debug, lmargs.timout,
+ MyName, debug, lmargs.timout,
lmargs.grace, listen_backlog,
max_conns_allowed, max_servers,
lmargs.retransmittimeout);
@@ -309,7 +312,7 @@ main(int ac, char *av[])
}
/* Daemonize, if not debug. */
- if (lmargs.debug == 0)
+ if (debug == 0)
pipe_fd = daemonize_init();
openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
@@ -405,7 +408,7 @@ main(int ac, char *av[])
/*
* lockd is up and running as far as we are concerned.
*/
- if (lmargs.debug == 0)
+ if (debug == 0)
daemonize_fini(pipe_fd);
/*
diff --git a/usr/src/cmd/fs.d/nfs/mount/Makefile b/usr/src/cmd/fs.d/nfs/mount/Makefile
index a53b876974..cb6c77044b 100644
--- a/usr/src/cmd/fs.d/nfs/mount/Makefile
+++ b/usr/src/cmd/fs.d/nfs/mount/Makefile
@@ -25,13 +25,6 @@
FSTYPE= nfs
LIBPROG= mount
-ROOTFS_PROG= $(LIBPROG)
-
-# duplicate ROOTLIBFSTYPE value needed for installation rule
-# we must define this before including Makefile.fstype
-ROOTLIBFSTYPE = $(ROOT)/usr/lib/fs/$(FSTYPE)
-$(ROOTLIBFSTYPE)/%: $(ROOTLIBFSTYPE) %
- $(RM) $@; $(SYMLINK) ../../../../etc/fs/$(FSTYPE)/$(LIBPROG) $@
include ../../Makefile.fstype
@@ -69,7 +62,7 @@ CLOBBERFILES += $(LIBPROG)
.KEEP_STATE:
-all: $(ROOTFS_PROG)
+all: $(LIBPROG)
$(LIBPROG): webnfs.h $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
@@ -118,7 +111,9 @@ $(POFILE): $(SRCS) webnfs.h
sed "/^domain/d" messages.po > $@
$(RM) $(POFILE).i messages.po
-install: $(ROOTETCPROG)
+install: all $(FSTYPEPROG)
+ $(RM) $(ROOTETCPROG)
+ $(SYMLINK) ../../../usr/lib/fs/$(FSTYPE)/$(LIBPROG) $(ROOTETCPROG)
lint: webnfs.h webnfs_xdr.c webnfs_client.c lint_SRCS
diff --git a/usr/src/cmd/fs.d/nfs/mount/mount.c b/usr/src/cmd/fs.d/nfs/mount/mount.c
index efb1f998f3..e1206e186a 100644
--- a/usr/src/cmd/fs.d/nfs/mount/mount.c
+++ b/usr/src/cmd/fs.d/nfs/mount/mount.c
@@ -2104,7 +2104,7 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
}
while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers,
- vers_min, vers_to_try, "datagram_v")) == NULL) {
+ vers_min, vers_to_try, NULL)) == NULL) {
if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
pr_err(gettext("%s: %s\n"), fshost,
clnt_spcreateerror(""));
diff --git a/usr/src/cmd/fs.d/nfs/svc/nfs-server b/usr/src/cmd/fs.d/nfs/svc/nfs-server
index bf8e73be98..d982829758 100644
--- a/usr/src/cmd/fs.d/nfs/svc/nfs-server
+++ b/usr/src/cmd/fs.d/nfs/svc/nfs-server
@@ -53,13 +53,13 @@ configure_ipfilter()
#
# Nothing to do if:
+ # - service's policy is 'use_global'
# - ipfilter isn't online
# - global policy is 'custom'
- # - service's policy is 'use_global'
#
+ [ "`get_policy $SMF_FMRI`" = "use_global" ] && return 0
service_check_state $IPF_FMRI $SMF_ONLINE || return 0
[ "`get_global_def_policy`" = "custom" ] && return 0
- [ "`get_policy $SMF_FMRI`" = "use_global" ] && return 0
svcadm restart $IPF_FMRI
}
diff --git a/usr/src/cmd/fs.d/nfs/umount/umount.c b/usr/src/cmd/fs.d/nfs/umount/umount.c
index aabdc8a592..66d280bcdb 100644
--- a/usr/src/cmd/fs.d/nfs/umount/umount.c
+++ b/usr/src/cmd/fs.d/nfs/umount/umount.c
@@ -297,7 +297,7 @@ retry:
*/
timep = (quick ? &create_timeout : NULL);
cl = clnt_create_timed(list[i].host, MOUNTPROG, vers,
- "datagram_n", timep);
+ NULL, timep);
/*
* Do not print any error messages in case of forced
* unmount.
diff --git a/usr/src/cmd/halt/halt.c b/usr/src/cmd/halt/halt.c
index 893539611b..ca0ed8e77f 100644
--- a/usr/src/cmd/halt/halt.c
+++ b/usr/src/cmd/halt/halt.c
@@ -21,6 +21,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
@@ -1250,6 +1251,17 @@ do_archives_update(int do_fast_reboot)
pid_t pid;
char *cmd_argv[MAXARGS];
+#if defined(__i386)
+ {
+ /*
+ * bootadm will complain and exit if not a grub root, so
+ * just skip running it.
+ */
+ struct stat sb;
+ if (stat("/boot/grub/stage2", &sb) == -1)
+ return;
+ }
+#endif /* __i386 */
cmd_argv[i++] = "/sbin/bootadm";
cmd_argv[i++] = "-ea";
@@ -1314,7 +1326,7 @@ main(int argc, char *argv[])
optstring = "dlnqfp";
usage = gettext("usage: %s [ -dlnq(p|f) ] [ boot args ]\n");
#endif
- cmd = A_SHUTDOWN;
+ cmd = A_REBOOT;
fcn = AD_BOOT;
} else {
(void) fprintf(stderr,
@@ -1512,7 +1524,8 @@ main(int argc, char *argv[])
* check_zone_haltedness later on.
*/
if (zoneid == GLOBAL_ZONEID && cmd != A_DUMP) {
- need_check_zones = halt_zones();
+ if (!qflag)
+ need_check_zones = halt_zones();
}
#if defined(__x86)
@@ -1604,7 +1617,7 @@ main(int argc, char *argv[])
(void) signal(SIGINT, SIG_IGN);
- if (!qflag && !nosync) {
+ if (!nosync) {
struct utmpx wtmpx;
bzero(&wtmpx, sizeof (struct utmpx));
diff --git a/usr/src/cmd/ibd_upgrade/ibd_delete_link.c b/usr/src/cmd/ibd_upgrade/ibd_delete_link.c
index b9d10a56cd..f63630207d 100644
--- a/usr/src/cmd/ibd_upgrade/ibd_delete_link.c
+++ b/usr/src/cmd/ibd_upgrade/ibd_delete_link.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#include <stdio.h>
@@ -86,6 +87,7 @@ ibd_delete_link(dladm_handle_t dlh, char *link)
getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
+ getlinkid.ld_zoneid = -1;
if ((status = ibd_dladm_door_call(dlh, &getlinkid, sizeof (getlinkid),
&retval, sizeof (retval))) != DLADM_STATUS_OK) {
diff --git a/usr/src/cmd/init/init.c b/usr/src/cmd/init/init.c
index 460fd42036..86f717d54a 100644
--- a/usr/src/cmd/init/init.c
+++ b/usr/src/cmd/init/init.c
@@ -24,6 +24,7 @@
* Copyright (c) 2013 Gary Mills
*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2020 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -146,6 +147,8 @@
#define UT_USER_SZ 32 /* Size of a utmpx ut_user field */
#define UT_LINE_SZ 32 /* Size of a utmpx ut_line field */
+#define CHECK_SVC SCF_INSTANCE_FS_MINIMAL
+
/*
* SLEEPTIME The number of seconds "init" sleeps between wakeups if
* nothing else requires this "init" wakeup.
@@ -550,6 +553,8 @@ static time_t init_boot_time; /* Substitute for kernel boot time. */
#define NSTARTD_FAILURE_TIMES 3 /* trigger after 3 failures */
#define STARTD_FAILURE_RATE_NS 5000000000LL /* 1 failure/5 seconds */
+#define STARTD_THROTTLE_RETRY 60 /* space failure retry after 60 secs */
+#define ROOT_MIN_FREE 524288 /* 512KB min. space needed in root */
static hrtime_t startd_failure_time[NSTARTD_FAILURE_TIMES];
static uint_t startd_failure_index;
@@ -695,9 +700,7 @@ main(int argc, char *argv[])
console(B_FALSE,
"\n\n%s Release %s Version %s %s-bit\r\n",
un.sysname, un.release, un.version, bits);
- console(B_FALSE,
- "Copyright (c) 1983, 2010, Oracle and/or its affiliates."
- " All rights reserved.\r\n");
+ console(B_FALSE, "Copyright 2010-2020 Joyent, Inc.\r\n");
#else
bootbanner_print(init_bootbanner_print, 0);
#endif
@@ -3519,6 +3522,28 @@ bail:
}
/*
+ * Attempt to confirm that svc.startd is ready to accept a user-initiated
+ * run-level change. startd is not ready until it has started its
+ * _scf_notify_wait thread to watch for events from svc.configd. This is
+ * inherently racy. To workaround this, we check the status of a file that
+ * startd will create once it has started the _scf_notify_wait thread.
+ * If we don't see this file after one minute, then charge ahead.
+ */
+static void
+verify_startd_ready()
+{
+ struct stat64 buf;
+ int i;
+
+ for (i = 0; i < 60; i++) {
+ if (stat64("/etc/svc/volatile/startd.ready", &buf) == 0)
+ return;
+ sleep(1);
+ }
+ console(B_TRUE, "verify startd timeout\n");
+}
+
+/*
* Function to handle requests from users to main init running as process 1.
*/
static void
@@ -3606,6 +3631,12 @@ userinit(int argc, char **argv)
(void) audit_put_record(ADT_SUCCESS, ADT_SUCCESS, argv[1]);
/*
+ * Before we tell init to start a run-level change, we need to be
+ * sure svc.startd is ready to accept that.
+ */
+ verify_startd_ready();
+
+ /*
* Signal init; init will take care of telling svc.startd.
*/
if (kill(init_pid, init_signal) == FAILURE) {
@@ -4315,9 +4346,7 @@ contract_event(struct pollfd *poll)
if (ret == 0) {
if (cookie == STARTD_COOKIE &&
do_restart_startd) {
- if (smf_debug)
- console(B_TRUE, "Restarting "
- "svc.startd.\n");
+ console(B_TRUE, "Restarting svc.startd.\n");
/*
* Account for the failure. If the failure rate
@@ -4448,6 +4477,28 @@ startd_run(const char *cline, int tmpl, ctid_t old_ctid)
if (pid == 0) {
/* child */
+ struct statvfs64 sbuf;
+
+ /*
+ * svc.configd needs some space (a few hundred KB) in / for its
+ * database. One common cause for startd failure is when
+ * configd dies because / is full. We don't want to go into the
+ * fast restart loop (startd_failure_rate_critical) and enter
+ * maintenance so we check for this case and slow down the
+ * failure rate so as to keep retrying in the hope space will
+ * free up.
+ */
+ if (statvfs64("/", &sbuf) != -1 &&
+ (sbuf.f_bsize * sbuf.f_bfree) < ROOT_MIN_FREE) {
+ syslog(LOG_ERR, "Insufficent space (%ld) in / to "
+ "start svc.startd.\n",
+ (long)(sbuf.f_bsize * sbuf.f_bfree));
+ console(B_TRUE, "Insufficent space (%ld) in / to "
+ "start svc.startd.\n",
+ (long)(sbuf.f_bsize * sbuf.f_bfree));
+ sleep(STARTD_THROTTLE_RETRY);
+ exit(1);
+ }
/* See the comment in efork() */
for (i = SIGHUP; i <= SIGRTMAX; ++i) {
diff --git a/usr/src/cmd/init/init.dfl b/usr/src/cmd/init/init.dfl
index 371b48becc..150f720b1c 100644
--- a/usr/src/cmd/init/init.dfl
+++ b/usr/src/cmd/init/init.dfl
@@ -29,5 +29,6 @@
# TZ, LANG, CMASK, or any of the LC_* environment variables. value may
# be enclosed in double quotes (") or single quotes (').
#
-TZ=PST8PDT
+TZ=UTC
CMASK=022
+LANG=en_US.UTF-8
diff --git a/usr/src/cmd/initpkg/mountall.sh b/usr/src/cmd/initpkg/mountall.sh
index fa59a20a41..2302c7592c 100644
--- a/usr/src/cmd/initpkg/mountall.sh
+++ b/usr/src/cmd/initpkg/mountall.sh
@@ -29,6 +29,8 @@
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
# All Rights Reserved
#
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+#
usage () {
if [ -n "$1" ]; then
@@ -149,6 +151,9 @@ isremote() {
# Get list of remote FS types (just once)
RemoteFSTypes=`while read t junk; do echo $t; done < /etc/dfs/fstypes`
+# Ensure nfs/smbfs are remote FS types even if not delivered from fstypes
+isremote "nfs" || set -A RemoteFSTypes "nfs"
+isremote "smbfs" || set -A RemoteFSTypes "smbfs"
#
# Process command line args
diff --git a/usr/src/cmd/initpkg/shutdown.sh b/usr/src/cmd/initpkg/shutdown.sh
index a90213cd81..e93de5568c 100644
--- a/usr/src/cmd/initpkg/shutdown.sh
+++ b/usr/src/cmd/initpkg/shutdown.sh
@@ -43,7 +43,7 @@ usage() {
}
notify() {
- /usr/sbin/wall -a <<-!
+ /usr/sbin/wall -Za <<-!
$*
!
# We used to do rwall here if showmounts had any output, but
diff --git a/usr/src/cmd/initpkg/umountall.sh b/usr/src/cmd/initpkg/umountall.sh
index c9a94fd8f1..4a45e19e18 100644
--- a/usr/src/cmd/initpkg/umountall.sh
+++ b/usr/src/cmd/initpkg/umountall.sh
@@ -25,6 +25,7 @@
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
# All Rights Reserved
#
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
usage () {
@@ -98,6 +99,9 @@ isremote() {
# Get list of remote FS types (just once)
RemoteFSTypes=`while read t junk; do echo $t; done < /etc/dfs/fstypes`
+# Ensure nfs/smbfs are remote FS types even if not delivered from fstypes
+isremote "nfs" || set -A RemoteFSTypes "nfs"
+isremote "smbfs" || set -A RemoteFSTypes "smbfs"
#
# Process command line args
diff --git a/usr/src/cmd/ipf/etc/Makefile b/usr/src/cmd/ipf/etc/Makefile
index 3e06187ae9..a5eb399f56 100644
--- a/usr/src/cmd/ipf/etc/Makefile
+++ b/usr/src/cmd/ipf/etc/Makefile
@@ -22,42 +22,31 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#cmd/ipf/etc/Makefile
+# Copyright 2019 Joyent, Inc.
#
-IPFCONF= ipf.conf
-IPFPROG= $(IPFCONF)
+IPFFILES = ipf.conf smartos_version
include ../../Makefile.cmd
-
ETCIPF= $(ROOTETC)/ipf
-DIRS= $(ETCIPF)
-
-ETCIPFPROG= $(IPFPROG:%=$(ETCIPF)/%)
+ROOTETCIPFFILES = $(IPFFILES:%=$(ETCIPF)/%)
-$(ETCIPFPROG):= FILEMODE= 0644
+$(ETCIPF)/ipf.conf := FILEMODE= 0644
+$(ETCIPF)/smartos_version := FILEMODE= 0444
.KEEP_STATE:
-all: $(IPFPROG) $(DIRS) $(ETCIPFPROG)
-
-install: all $(DIRS)
+all:
-$(PFILAP):
- $(SH) $@.sh
+install: all $(ROOTETCIPFFILES)
-$(ETCIPF)/% : % $(ETCIPF)
+$(ETCIPF)/% : %
$(INS.file)
-$(DIRS):
- $(INS.dir)
-
clean:
clobber:
-lint:
-
.PARALLEL:
diff --git a/usr/src/cmd/ipf/etc/smartos_version b/usr/src/cmd/ipf/etc/smartos_version
new file mode 100644
index 0000000000..0cfbf08886
--- /dev/null
+++ b/usr/src/cmd/ipf/etc/smartos_version
@@ -0,0 +1 @@
+2
diff --git a/usr/src/cmd/ipf/lib/common/printfr.c b/usr/src/cmd/ipf/lib/common/printfr.c
index 063eb87c07..b096c46e0e 100644
--- a/usr/src/cmd/ipf/lib/common/printfr.c
+++ b/usr/src/cmd/ipf/lib/common/printfr.c
@@ -7,9 +7,10 @@
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+#include <uuid/uuid.h>
#include "ipf.h"
@@ -386,7 +387,8 @@ ioctlfunc_t iocfunc;
printf(" head %s", fp->fr_grhead);
if (*fp->fr_group != '\0')
printf(" group %s", fp->fr_group);
- if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) {
+ if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag ||
+ (fp->fr_flags & FR_CFWLOG) || !uuid_is_null(fp->fr_uuid)) {
char *s = "";
printf(" set-tag(");
@@ -397,6 +399,18 @@ ioctlfunc_t iocfunc;
if (*fp->fr_nattag.ipt_tag) {
printf("%snat=%-.*s", s, IPFTAG_LEN,
fp->fr_nattag.ipt_tag);
+ s = ", ";
+ }
+ if (fp->fr_flags & FR_CFWLOG) {
+ printf("cfwlog");
+ s = ", ";
+ }
+
+ if (!uuid_is_null(fp->fr_uuid)) {
+ char uuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ uuid_unparse(fp->fr_uuid, uuid);
+ printf("%suuid=%s", s, uuid);
}
printf(")");
}
diff --git a/usr/src/cmd/ipf/svc/ipfilter b/usr/src/cmd/ipf/svc/ipfilter
index 48e3e2e915..bb25316b44 100644
--- a/usr/src/cmd/ipf/svc/ipfilter
+++ b/usr/src/cmd/ipf/svc/ipfilter
@@ -23,9 +23,12 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
#
+set -o xtrace
+
. /lib/svc/share/smf_include.sh
. /lib/svc/share/ipf_include.sh
@@ -152,8 +155,25 @@ upgrade_config()
svcadm refresh $SMF_FMRI >/dev/null 2>&1
}
+symlink_persistent_file()
+{
+ persist_file=/var/fw/$1
+ etc_file=$ETC_IPF_DIR/$1
+
+ [ ! -e $persist_file ] && return 0
+ [ -L $etc_file ] && return 0
+
+ [ -e $etc_file ] && mv $etc_file{,.orig}
+
+ ln -s $persist_file $etc_file
+}
+
+
configure_firewall()
{
+ symlink_persistent_file ipnat.conf
+ symlink_persistent_file ipf.conf
+ symlink_persistent_file ipf6.conf
create_global_rules || exit $SMF_EXIT_ERR_CONFIG
create_global_ovr_rules || exit $SMF_EXIT_ERR_CONFIG
create_services_rules || exit $SMF_EXIT_ERR_CONFIG
diff --git a/usr/src/cmd/ipf/svc/ipfilter.xml b/usr/src/cmd/ipf/svc/ipfilter.xml
index 5f088f5344..8b6506795f 100644
--- a/usr/src/cmd/ipf/svc/ipfilter.xml
+++ b/usr/src/cmd/ipf/svc/ipfilter.xml
@@ -4,6 +4,7 @@
Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
+
CDDL HEADER START
The contents of this file are subject to the terms of the
@@ -97,13 +98,13 @@
type='method'
name='refresh'
exec='/lib/svc/method/ipfilter reload'
- timeout_seconds='120' >
+ timeout_seconds='1200' >
</exec_method>
- <instance name='default' enabled='false'>
+ <instance name='default' enabled='true'>
<property_group name='firewall_config_default'
type='com.sun,fw_configuration'>
- <propval name='policy' type='astring' value='none' />
+ <propval name='policy' type='astring' value='custom' />
<propval name='block_policy' type='astring'
value='none' />
<propval name='custom_policy_file' type='astring'
diff --git a/usr/src/cmd/ipf/tools/Makefile.tools b/usr/src/cmd/ipf/tools/Makefile.tools
index 7c1e151762..a89fc63f97 100644
--- a/usr/src/cmd/ipf/tools/Makefile.tools
+++ b/usr/src/cmd/ipf/tools/Makefile.tools
@@ -23,8 +23,7 @@
# Use is subject to license terms.
#
# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
-#
-# Copyright (c) 2012, Joyent Inc. All rights reserved.
+# Copyright 2020 Joyent, Inc.
#
PROG= ipf ipfs ipmon ipnat ippool ipfstat
@@ -36,7 +35,7 @@ IPFSTAT_OBJS= ipfstat.o ipfzone.o
IPMON_OBJS= ipmon.o ipfzone.o ipmon_y.o ipmon_l.o
IPNAT_OBJS= ipnat.o ipfzone.o ipnat_y.o ipnat_l.o
IPPOOL_OBJS= ippool.o ipfzone.o ippool_y.o ippool_l.o
-IPFTEST_OBJS= ipftest.o ipfzone.o \
+IPFTEST_OBJS= cfw.o ipftest.o ipfzone.o \
ip_fil.o ip_state.o ip_compat.o \
ip_frag.o ip_nat.o ip_nat6.o fil.o \
ip_htable.o ip_lookup.o \
@@ -65,12 +64,12 @@ CPPFLAGS += -I. -DIPFILTER_LOOKUP -DIPFILTER_LOG
ipfstat.o := CPPFLAGS += -DSTATETOP
ipfstat := LDLIBS += -lcurses
-ipf := LDLIBS += -lsocket -lnsl
-ipftest := LDLIBS += -lsocket -lnsl -lmd
-ipfstat := LDLIBS += -lsocket -lnsl -lkvm -lelf
-ipmon := LDLIBS += -lsocket -lnsl
-ipnat := LDLIBS += -lsocket -lnsl -lkvm -lelf
-ippool := LDLIBS += -lsocket -lnsl -lkvm -lelf
+ipf := LDLIBS += -lsocket -lnsl -luuid
+ipftest := LDLIBS += -lsocket -lnsl -lmd -luuid
+ipfstat := LDLIBS += -lsocket -lnsl -lkvm -lelf -luuid
+ipmon := LDLIBS += -lsocket -lnsl -luuid
+ipnat := LDLIBS += -lsocket -lnsl -lkvm -lelf -luuid
+ippool := LDLIBS += -lsocket -lnsl -lkvm -lelf -luuid
CLEANFILES += $(OBJS)
CLOBBERFILES += $(IPFPROG)
@@ -244,17 +243,15 @@ ippool_l.o: ../ippool_l.c $(COMMONIPF)/netinet/ip_pool.h ../ippool_l.h
CLEANFILES += ../ippool_l.c ../ippool_l.h
ipftest: $(IPFTEST_OBJS) $(LIBIPF) $(MAPFILE.NGB)
- $(LINK.c) $(ZIGNORE) -o ipftest $(IPFTEST_OBJS) $(LDLIBS)
+ $(LINK.c) $(ZIGNORE) -o ipftest $(IPFTEST_OBJS) $(LDLIBS)
$(POST_PROCESS)
clean:
-$(RM) $(CLEANFILES)
-lint: lint_SRCS
-
#
# NOTE: all rules must use relative paths otherwise absolute paths will be
-# embedded into the binaries making them false positives and
+# embedded into the binaries making them false positives and
# reported by wsdiff
#
diff --git a/usr/src/cmd/ipf/tools/ipf_y.y b/usr/src/cmd/ipf/tools/ipf_y.y
index 7689d676c7..c8909b4e92 100644
--- a/usr/src/cmd/ipf/tools/ipf_y.y
+++ b/usr/src/cmd/ipf/tools/ipf_y.y
@@ -6,6 +6,7 @@
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
*/
#include "ipf.h"
@@ -16,6 +17,7 @@
# define _NET_BPF_H_
# include <pcap.h>
#endif
+#include <uuid/uuid.h>
#include "netinet/ip_pool.h"
#include "netinet/ip_htable.h"
#include "netinet/ipl.h"
@@ -98,6 +100,7 @@ static int set_ipv6_addr = 0;
union i6addr m;
} ipp;
union i6addr ip6;
+ uuid_t uuid;
};
%type <port> portnum
@@ -117,6 +120,7 @@ static int set_ipv6_addr = 0;
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
%token YY_RANGE_OUT YY_RANGE_IN
%token <ip6> YY_IPV6
+%token <uuid> YY_UUID
%token IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL
%token IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST
@@ -127,6 +131,7 @@ static int set_ipv6_addr = 0;
%token IPFY_HEAD IPFY_GROUP
%token IPFY_AUTH IPFY_PREAUTH
%token IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK
+%token IPFY_UUID IPFY_CFWLOG
%token IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP
%token IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH
%token IPFY_PPS
@@ -518,6 +523,8 @@ taginlist:
taginspec:
logtag
|nattag
+ |uuidtag
+ |cfwtag
;
nattag: IPFY_NAT '=' YY_STR { DOALL(strncpy(fr->fr_nattag.ipt_tag,\
@@ -530,6 +537,12 @@ nattag: IPFY_NAT '=' YY_STR { DOALL(strncpy(fr->fr_nattag.ipt_tag,\
logtag: IPFY_LOG '=' YY_NUMBER { DOALL(fr->fr_logtag = $3;) }
;
+cfwtag: IPFY_CFWLOG { DOALL(fr->fr_flags |= FR_CFWLOG;) }
+ ;
+
+uuidtag: IPFY_UUID '=' YY_UUID { DOALL(uuid_copy(fr->fr_uuid, $3);) }
+ ;
+
settagout:
| IPFY_SETTAG '(' tagoutlist ')'
;
@@ -542,6 +555,8 @@ tagoutlist:
tagoutspec:
logtag
| nattag
+ | uuidtag
+ | cfwtag
;
matchtagin:
@@ -1566,6 +1581,7 @@ static struct wordtab ipfwords[96] = {
{ "bpf-v6", IPFY_BPFV6 },
#endif
{ "call", IPFY_CALL },
+ { "cfwlog", IPFY_CFWLOG },
{ "code", IPFY_ICMPCODE },
{ "count", IPFY_COUNT },
{ "dup-to", IPFY_DUPTO },
@@ -1641,6 +1657,7 @@ static struct wordtab ipfwords[96] = {
{ "to", IPFY_TO },
{ "ttl", IPFY_TTL },
{ "udp", IPFY_UDP },
+ { "uuid", IPFY_UUID },
{ "v6hdrs", IPF6_V6HDRS },
{ "with", IPFY_WITH },
{ NULL, 0 }
diff --git a/usr/src/cmd/ipf/tools/ipfstat.c b/usr/src/cmd/ipf/tools/ipfstat.c
index d72f6ba97a..caa9ff7468 100644
--- a/usr/src/cmd/ipf/tools/ipfstat.c
+++ b/usr/src/cmd/ipf/tools/ipfstat.c
@@ -165,6 +165,10 @@ static int sort_dstip __P((const void *, const void *));
static int sort_dstpt __P((const void *, const void *));
#endif
+#if SOLARIS
+#include "ipfzone.h"
+#endif
+
static void usage(name)
char *name;
diff --git a/usr/src/cmd/ipf/tools/ipmon_y.y b/usr/src/cmd/ipf/tools/ipmon_y.y
index e6dda81c35..b4fce4015d 100644
--- a/usr/src/cmd/ipf/tools/ipmon_y.y
+++ b/usr/src/cmd/ipf/tools/ipmon_y.y
@@ -1,11 +1,14 @@
/*
* Copyright (C) 1993-2005 by Darren Reed.
* See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2019 Joyent, Inc.
*/
%{
#include "ipf.h"
#include <syslog.h>
+#include <uuid/uuid.h>
#undef OPT_NAT
#undef OPT_VERBOSE
#include "ipmon_l.h"
@@ -42,11 +45,13 @@ static ipmon_action_t *alist = NULL;
struct in_addr addr;
struct opt *opt;
union i6addr ip6;
+ uuid_t uuid;
}
%token <num> YY_NUMBER YY_HEX
%token <str> YY_STR
%token <ip6> YY_IPV6
+%token <uuid> YY_UUID
%token YY_COMMENT
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
%token YY_RANGE_OUT YY_RANGE_IN
diff --git a/usr/src/cmd/ipf/tools/ipnat_y.y b/usr/src/cmd/ipf/tools/ipnat_y.y
index d929bf413a..2c913afea2 100644
--- a/usr/src/cmd/ipf/tools/ipnat_y.y
+++ b/usr/src/cmd/ipf/tools/ipnat_y.y
@@ -6,6 +6,7 @@
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -39,6 +40,7 @@
#include <sys/time.h>
#include <syslog.h>
#include <net/if.h>
+#include <uuid/uuid.h>
#if __FreeBSD_version >= 300000
# include <net/if_var.h>
#endif
@@ -89,6 +91,7 @@ static void setnatproto __P((int));
int v;
} ipp;
union i6addr ip6;
+ uuid_t uuid;
};
%token <num> YY_NUMBER YY_HEX
@@ -97,6 +100,7 @@ static void setnatproto __P((int));
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
%token YY_RANGE_OUT YY_RANGE_IN
%token <ip6> YY_IPV6
+%token <uuid> YY_UUID
%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
diff --git a/usr/src/cmd/ipf/tools/ippool_y.y b/usr/src/cmd/ipf/tools/ippool_y.y
index cca5052bd4..5aadd22206 100644
--- a/usr/src/cmd/ipf/tools/ippool_y.y
+++ b/usr/src/cmd/ipf/tools/ippool_y.y
@@ -6,6 +6,7 @@
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -34,6 +35,7 @@
#include <netdb.h>
#include <ctype.h>
#include <unistd.h>
+#include <uuid/uuid.h>
#include "ipf.h"
#include "netinet/ip_lookup.h"
@@ -66,6 +68,7 @@ static int set_ipv6_addr = 0;
iphtent_t *ipe;
ip_pool_node_t *ipp;
union i6addr ip6;
+ uuid_t uuid;
}
%token <num> YY_NUMBER YY_HEX
@@ -74,6 +77,7 @@ static int set_ipv6_addr = 0;
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
%token YY_RANGE_OUT YY_RANGE_IN
%token <ip6> YY_IPV6
+%token <uuid> YY_UUID
%token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT
%token IPT_TABLE IPT_GROUPMAP IPT_HASH
diff --git a/usr/src/cmd/ipf/tools/lexer.c b/usr/src/cmd/ipf/tools/lexer.c
index 3db3a0888b..b4ee8b3f77 100644
--- a/usr/src/cmd/ipf/tools/lexer.c
+++ b/usr/src/cmd/ipf/tools/lexer.c
@@ -5,6 +5,7 @@
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
*/
#include <ctype.h>
@@ -14,6 +15,7 @@
#endif
#include <sys/ioctl.h>
#include <syslog.h>
+#include <uuid/uuid.h>
#ifdef TEST_LEXER
# define NO_YACC
union {
@@ -21,6 +23,7 @@ union {
char *str;
struct in_addr ipa;
i6addr_t ip6;
+ uuid_t uuid;
} yylval;
#endif
#include "lexer.h"
@@ -455,6 +458,40 @@ nextchar:
}
#endif
+ /*
+ * UUID: e.g., "2426e38c-9f63-c0b8-cfd5-9aaeaf992d42" or its uppercase
+ * variant.
+ */
+ if (isbuilding == 0 && (ishex(c) || c == '-')) {
+ char uuidbuf[UUID_PRINTABLE_STRING_LENGTH], *s, oc;
+ int start;
+
+ start = yypos;
+ s = uuidbuf;
+ oc = c;
+
+ /*
+ * Don't worry about exact position of hexdigits and hyphens
+ * because uuid_parse() will provide the sanity check.
+ */
+ do {
+ *s++ = c;
+ c = yygetc(1);
+ } while ((ishex(c) || c == '-') &&
+ (s - uuidbuf < sizeof (uuidbuf)));
+ yyunputc(c);
+ *s = '\0';
+
+ if (uuid_parse(uuidbuf, yylval.uuid) == 0) {
+ rval = YY_UUID;
+ yyexpectaddr = 0;
+ goto done;
+ }
+ yypos = start;
+ c = oc;
+ }
+
+
if (c == ':') {
if (isbuilding == 1) {
yyunputc(c);
diff --git a/usr/src/cmd/ipf/tools/lexer.h b/usr/src/cmd/ipf/tools/lexer.h
index a296cb0bc3..448b3e6ffd 100644
--- a/usr/src/cmd/ipf/tools/lexer.h
+++ b/usr/src/cmd/ipf/tools/lexer.h
@@ -1,4 +1,6 @@
-
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
typedef struct wordtab {
char *w_word;
int w_value;
@@ -16,6 +18,7 @@ typedef struct wordtab {
#define YY_IPV6 1008
#define YY_STR 1009
#define YY_IPADDR 1010
+#define YY_UUID 1011
#endif
#define YYBUFSIZ 8192
diff --git a/usr/src/cmd/iscsid/iscsi-initiator b/usr/src/cmd/iscsid/iscsi-initiator
index 48b97f0f35..39d983ffff 100644
--- a/usr/src/cmd/iscsid/iscsi-initiator
+++ b/usr/src/cmd/iscsid/iscsi-initiator
@@ -22,6 +22,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2020 Joyent, Inc.
#
#
@@ -170,6 +171,25 @@ mount_iscsi() {
}
umount_iscsi () {
+ # In case any non-system zpools reside on iscsi drives, export
+ # all of them now so that the system won't hang later in the shutdown
+ # sequence when those zpools need to be unmounted.
+ SYS_POOL=`svcprop -p config/zpool svc:/system/smartdc/init:default \
+ 2>/dev/null`
+ SYS_POOL=${SYS_POOL:-zones}
+
+ zpools=$(zpool list -Ho name)
+ for pool in $zpools; do
+ if [ "$pool" == $SYS_POOL ]; then
+ continue
+ fi
+ zpool export $pool
+ got=$?
+ if [ $got -ne 0 ]; then
+ echo "Exporting zpool $pool failed ($got)"
+ fi
+ done
+
#
# Generate iscsi mountp list from /etc/vfstab
exec < /etc/vfstab
diff --git a/usr/src/cmd/iscsid/iscsi-initiator.xml b/usr/src/cmd/iscsid/iscsi-initiator.xml
index 42e0f21384..5f74945ac6 100644
--- a/usr/src/cmd/iscsid/iscsi-initiator.xml
+++ b/usr/src/cmd/iscsid/iscsi-initiator.xml
@@ -23,6 +23,7 @@
CDDL HEADER END
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright 2020 Joyent, Inc.
Service manifests for the iSCSI Initiator
-->
@@ -98,6 +99,20 @@ potential to specialize all the properties/methods.
<service_fmri value='svc:/network/loopback' />
</dependency>
+ <!--
+ We declare a dependency on the optional iscsi-target svc so that it
+ will not shutdown before the initiator svc. In this way we can use
+ targets on the same machine and not see a failure or hang when we're
+ exporting any zpools that might be using local targets.
+ -->
+ <dependency
+ name='iscsi-target'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/network/iscsi/target' />
+ </dependency>
+
<dependent
name='iscsi-initiator_multi-user'
grouping='optional_all'
@@ -136,7 +151,7 @@ potential to specialize all the properties/methods.
<method_credential
user='root'
group='root'
- privileges='basic,sys_devices,sys_mount'
+ privileges='basic,sys_config,sys_devices,sys_mount'
/>
</method_context>
</exec_method>
diff --git a/usr/src/cmd/ksh/Makefile.com b/usr/src/cmd/ksh/Makefile.com
index 9f6b431e1f..b1aef300da 100644
--- a/usr/src/cmd/ksh/Makefile.com
+++ b/usr/src/cmd/ksh/Makefile.com
@@ -37,11 +37,13 @@ LIBSHELLBASE=../../../lib/libshell
LIBSHELLSRC=$(LIBSHELLBASE)/common/sh
SRCS= $(OBJECTS:%.o=$(LIBSHELLSRC)/%.c)
+OBJS= $(OBJECTS)
LDLIBS += -lshell
# Set common AST build flags (e.g., needed to support the math stuff).
include ../../../Makefile.ast
+include ../../Makefile.ctf
# 1. Make sure that the -D/-U defines in CFLAGS below are in sync
# with usr/src/lib/libshell/Makefile.com
diff --git a/usr/src/cmd/localedef/Makefile b/usr/src/cmd/localedef/Makefile
index 358f63de01..8a8e5dc2e0 100644
--- a/usr/src/cmd/localedef/Makefile
+++ b/usr/src/cmd/localedef/Makefile
@@ -13,7 +13,7 @@
# Copyright 2017 Nexenta Systems, Inc.
# Copyright 2011 EveryCity Ltd. All rights reserved.
# Copyright 2013 DEY Storage Systems, Inc.
-# Copyright 2016 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
# Copyright 2017 RackTop Systems.
#
@@ -23,6 +23,10 @@ include $(SRC)/cmd/localedef/Makefile.common
LDLIBS += -lavl -lgen
+I18NEXTFILE = $(ROOTI18NEXT)/UTF-8.x
+
+$(I18NEXTFILE) := FILEMODE = 0444
+
.KEEP_STATE:
all: $(PROG)
@@ -43,9 +47,7 @@ $(POFILE): $(PIFILES)
$(SED) -e '/domain/d' messages.po > $@
$(RM) $(PIFILES) messages.po
-install: all $(ROOTPROG)
-
-lint: lint_SRCS
+install: all $(ROOTPROG) $(I18NEXTFILE)
clean:
$(RM) $(CLEANFILES)
diff --git a/usr/src/cmd/localedef/UTF-8.x b/usr/src/cmd/localedef/UTF-8.x
new file mode 100644
index 0000000000..b7ab359bd4
--- /dev/null
+++ b/usr/src/cmd/localedef/UTF-8.x
@@ -0,0 +1,114 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1996-1997, 2000-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Method file for Solaris Unicode locales.
+#
+#
+#ident "@(#)UTF-8.x 1.4 03/08/19 SMI"
+#
+
+METHODS
+
+#
+# Encoding definitions to use UTF-8 (MB) and UTF-32 (WC):
+file_code utf8
+process_code ucs4
+
+#
+# We use the following methods from the libc:
+iswctype@native "__iswctype_std" "libc" "/usr/lib/" "libc.so.1"
+towctrans@native "__towctrans_std"
+towlower@native "__towlower_std"
+towupper@native "__towupper_std"
+trwctype "__trwctype_std"
+wctrans "__wctrans_std"
+wctype "__wctype_std"
+
+mbsinit "__mbsinit_gen"
+mbrlen "__mbrlen_gen"
+
+strcoll "__strcoll_std"
+strxfrm "__strxfrm_std"
+wcscoll "__wcscoll_bc"
+wcscoll@native "__wcscoll_std"
+wcsxfrm "__wcsxfrm_bc"
+wcsxfrm@native "__wcsxfrm_std"
+
+fnmatch "__fnmatch_std"
+regcomp "__regcomp_std"
+regexec "__regexec_std"
+regerror "__regerror_std"
+regfree "__regfree_std"
+
+strfmon "__strfmon_std"
+
+strftime "__strftime_std"
+strptime "__strptime_std"
+wcsftime "__wcsftime_std"
+
+getdate "__getdate_std"
+
+#
+# The methods designated at below are all Unicode locale-specific methods
+# coming from the methods_unicode.so.3 shared object:
+eucpctowc "__u32_to_dense_u32_utf8" "localelib" "/usr/lib/locale/common" "methods_unicode.so.3"
+wctoeucpc "__dense_u32_to_u32_utf8"
+
+iswctype "__iswctype_bc_utf8"
+towctrans "__towctrans_bc_utf8"
+towlower "__towlower_bc_utf8"
+towupper "__towupper_bc_utf8"
+
+mbftowc "__mbftowc_dense_utf8"
+mbftowc@native "__mbftowc_dense_native_utf8"
+fgetwc "__fgetwc_dense_utf8"
+fgetwc@native "__fgetwc_dense_native_utf8"
+mblen "__mblen_dense_utf8"
+mbstowcs "__mbstowcs_dense_utf8"
+mbstowcs@native "__mbstowcs_dense_native_utf8"
+mbtowc "__mbtowc_dense_utf8"
+mbtowc@native "__mbtowc_dense_native_utf8"
+wcstombs "__wcstombs_dense_utf8"
+wcstombs@native "__wcstombs_dense_native_utf8"
+wcswidth "__wcswidth_dense_utf8"
+wcswidth@native "__wcswidth_dense_utf8"
+wctomb "__wctomb_dense_utf8"
+wctomb@native "__wctomb_dense_native_utf8"
+wcwidth "__wcwidth_dense_utf8"
+wcwidth@native "__wcwidth_dense_utf8"
+
+btowc "__btowc_dense_utf8"
+btowc@native "__btowc_dense_utf8"
+wctob "__wctob_dense_utf8"
+wctob@native "__wctob_dense_utf8"
+mbrtowc "__mbrtowc_dense_utf8"
+mbrtowc@native "__mbrtowc_dense_native_utf8"
+wcrtomb "__wcrtomb_dense_utf8"
+wcrtomb@native "__wcrtomb_dense_native_utf8"
+mbsrtowcs "__mbsrtowcs_dense_utf8"
+mbsrtowcs@native "__mbsrtowcs_dense_native_utf8"
+wcsrtombs "__wcsrtombs_dense_utf8"
+wcsrtombs@native "__wcsrtombs_dense_native_utf8"
+
+END METHODS
diff --git a/usr/src/cmd/lofiadm/main.c b/usr/src/cmd/lofiadm/main.c
index 4a4ee348c0..6ed5b49050 100644
--- a/usr/src/cmd/lofiadm/main.c
+++ b/usr/src/cmd/lofiadm/main.c
@@ -412,7 +412,8 @@ out:
* DO NOT use this function if the filename is actually the device name.
*/
static int
-lofi_map_file(int lfd, struct lofi_ioctl *li, const char *filename)
+lofi_map_file(int lfd, struct lofi_ioctl *li, const char *filename,
+ boolean_t no_devlink_flag)
{
int minor;
@@ -425,7 +426,8 @@ lofi_map_file(int lfd, struct lofi_ioctl *li, const char *filename)
"unsupported"));
die(gettext("could not map file %s"), filename);
}
- wait_until_dev_complete(li);
+ if (!no_devlink_flag)
+ wait_until_dev_complete(li);
return (minor);
}
@@ -436,7 +438,7 @@ lofi_map_file(int lfd, struct lofi_ioctl *li, const char *filename)
static void
add_mapping(int lfd, const char *devicename, const char *filename,
mech_alias_t *cipher, const char *rkey, size_t rksz, boolean_t rdonly,
- boolean_t label)
+ boolean_t label, boolean_t no_devlink_flag)
{
struct lofi_ioctl li;
@@ -475,7 +477,7 @@ add_mapping(int lfd, const char *devicename, const char *filename,
char path[MAXPATHLEN];
/* pick one via the driver */
- minor = lofi_map_file(lfd, &li, filename);
+ minor = lofi_map_file(lfd, &li, filename, no_devlink_flag);
if (minor > 0) {
make_blkdevname(&li, path, sizeof (path));
@@ -500,7 +502,8 @@ add_mapping(int lfd, const char *devicename, const char *filename,
die(gettext("could not map file %s to %s"), filename,
devicename);
}
- wait_until_dev_complete(&li);
+ if (!no_devlink_flag)
+ wait_until_dev_complete(&li);
}
/*
@@ -1393,7 +1396,7 @@ lofi_uncompress(int lfd, const char *filename)
if (statbuf.st_size == 0)
return;
- minor = lofi_map_file(lfd, &li, filename);
+ minor = lofi_map_file(lfd, &li, filename, B_FALSE);
(void) snprintf(devicename, sizeof (devicename), "/dev/%s/%d",
LOFI_BLOCK_NAME, minor);
@@ -1935,6 +1938,7 @@ main(int argc, char *argv[])
boolean_t ephflag = B_FALSE;
boolean_t compressflag = B_FALSE;
boolean_t uncompressflag = B_FALSE;
+ boolean_t no_devlink_flag = B_FALSE;
/* the next two work together for -c, -k, -T, -e options only */
boolean_t need_crypto = B_FALSE; /* if any -c, -k, -T, -e */
boolean_t cipher_only = B_TRUE; /* if -c only */
@@ -1950,7 +1954,7 @@ main(int argc, char *argv[])
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
- while ((c = getopt(argc, argv, "a:c:Cd:efk:lrs:T:U")) != EOF) {
+ while ((c = getopt(argc, argv, "a:c:Cd:efk:lrs:T:UX")) != EOF) {
switch (c) {
case 'a':
addflag = B_TRUE;
@@ -2031,6 +2035,13 @@ main(int argc, char *argv[])
case 'U':
uncompressflag = B_TRUE;
break;
+ case 'X':
+ /*
+ * Private flag to skip the wait for the /dev links to
+ * be created.
+ */
+ no_devlink_flag = B_TRUE;
+ break;
case '?':
default:
errflag = B_TRUE;
@@ -2163,7 +2174,7 @@ main(int argc, char *argv[])
*/
if (addflag)
add_mapping(lfd, devicename, filename, cipher, rkey, rksz,
- rdflag, labelflag);
+ rdflag, labelflag, no_devlink_flag);
else if (compressflag)
lofi_compress(&lfd, filename, compress_index, segsize);
else if (uncompressflag)
diff --git a/usr/src/cmd/logadm/Makefile b/usr/src/cmd/logadm/Makefile
index b9ee0560ea..7b959c0dba 100644
--- a/usr/src/cmd/logadm/Makefile
+++ b/usr/src/cmd/logadm/Makefile
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2019 Joyent, Inc.
#
PROG= logadm
@@ -36,6 +37,7 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64
CERRWARN += -_gcc=-Wno-parentheses
CERRWARN += -_gcc=-Wno-clobbered
CERRWARN += $(CNOWARN_UNINIT)
+CERRWARN += -_gcc=-Wno-unused-label
XGETFLAGS += -a -x logadm.xcl
$(ROOTETC)/$(CONFIGFILE):= FILEMODE= 644
diff --git a/usr/src/cmd/logadm/conf.c b/usr/src/cmd/logadm/conf.c
index 25bcc4f63d..93837fbebf 100644
--- a/usr/src/cmd/logadm/conf.c
+++ b/usr/src/cmd/logadm/conf.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
* Copyright 2018 Sebastian Wiedenroth
*/
@@ -279,8 +279,6 @@ conf_scan(const char *fname, char *buf, int buflen, int timescan)
if (SETJMP) {
err(EF_FILE, "cannot process invalid entry %s",
entry);
- ret = 0;
- LOCAL_ERR_BREAK;
}
if (timescan) {
@@ -529,7 +527,6 @@ conf_close(struct opts *opts)
(void) unlink(tuname);
err(EF_JMP, "unsafe to update configuration file "
"or timestamps");
- return;
}
/* rename updated files into place */
diff --git a/usr/src/cmd/logadm/glob.c b/usr/src/cmd/logadm/glob.c
index 338a1c6b9f..0978c876e9 100644
--- a/usr/src/cmd/logadm/glob.c
+++ b/usr/src/cmd/logadm/glob.c
@@ -22,6 +22,8 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
+ * Copyright 2019 Joyent, Inc.
+ *
* logadm/glob.c -- globbing routines
*
* these routines support two kinds of globs. first, the
@@ -62,8 +64,6 @@
* braces, and don't support the more powerful reglobs required by logadm.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <libintl.h>
#include <stdlib.h>
@@ -100,8 +100,6 @@ glob_debrace(struct fn *fnp)
while (sp != NULL && (left = strchr(sp, '{')) != NULL)
if ((right = strchr(left, '}')) == NULL) {
err(EF_FILE|EF_JMP, "Missing }");
- fn_list_free(ret);
- return (NULL);
} else {
/* stuff before "left" is finished */
fn_list_appendrange(ret, sp, left);
diff --git a/usr/src/cmd/logadm/logadm.conf b/usr/src/cmd/logadm/logadm.conf
index 7b19473a19..39eea57578 100644
--- a/usr/src/cmd/logadm/logadm.conf
+++ b/usr/src/cmd/logadm/logadm.conf
@@ -19,6 +19,7 @@
# CDDL HEADER END
#
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, Joyent, Inc.
#
# logadm.conf
#
@@ -35,12 +36,18 @@
# logadm typically runs early every morning via an entry in
# root's crontab (see crontab(1)).
#
-/var/log/syslog -C 8 -a 'kill -HUP `cat /var/run/syslog.pid`'
-/var/adm/messages -C 4 -a 'kill -HUP `cat /var/run/syslog.pid`'
+/var/log/syslog -C 8 -a 'kill -HUP `cat /var/run/*syslog*.pid`'
+/var/adm/messages -C 4 -a 'kill -HUP `cat /var/run/*syslog*.pid`'
/var/cron/log -c -s 512k -t /var/cron/olog
/var/lp/logs/lpsched -C 2 -N -t '$file.$N'
/var/fm/fmd/errlog -N -s 2m -M '/usr/sbin/fmadm -q rotate errlog && mv /var/fm/fmd/errlog.0- $nfile'
/var/fm/fmd/fltlog -N -A 6m -s 10m -M '/usr/sbin/fmadm -q rotate fltlog && mv /var/fm/fmd/fltlog.0- $nfile'
+vm_logs /var/log/vm/vmadm.log -b '/usr/vm/sbin/rotate-logs.sh -m /var/log/vm/logs/ /var/log/vm/vmadm.log' -t '/var/log/vm/vmadm_$nodename_%FT%H:%M:%S.log' -C 168 -S 1g -p 1h
+fw_logs /var/log/fw/fwadm.log -b '/usr/vm/sbin/rotate-logs.sh -i /var/log/fw/logs/ /var/log/fw/fwadm.log' -t '/var/log/fw/fwadm_$nodename_%FT%H:%M:%S.log' -C 168 -S 1g -p 1h
+vmadmd_logs /var/svc/log/*vmadmd*.log -C 168 -S 1g -c -p 1h -t '/var/log/vm/vmadmd_$nodename_%FT%H:%M:%S.log'
+vminfod_logs /var/svc/log/*vminfod*.log -C 168 -S 1g -c -p 1h -t '/var/log/vm/vminfod_$nodename_%FT%H:%M:%S.log'
+/var/log/*.log -C 2 -s 5m -c
+/var/log/*.debug -C 2 -s 5m -c
smf_logs /var/svc/log/*.log -C 8 -s 1m -c
#
# The entry below is used by turnacct(1M)
diff --git a/usr/src/cmd/logadm/main.c b/usr/src/cmd/logadm/main.c
index 624397d41f..15f71be166 100644
--- a/usr/src/cmd/logadm/main.c
+++ b/usr/src/cmd/logadm/main.c
@@ -603,17 +603,14 @@ rotatelog(struct fn *fnp, struct opts *opts)
if (opts_count(opts, "N"))
return (1);
err(EF_WARN|EF_SYS, "%s", fname);
- return (B_FALSE);
}
if ((stbuf.st_mode & S_IFMT) == S_IFLNK) {
err(EF_WARN, "%s is a symlink", fname);
- return (B_FALSE);
}
if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
err(EF_WARN, "%s is not a regular file", fname);
- return (B_FALSE);
}
/* even if size condition is not met, this entry is "done" */
@@ -1074,7 +1071,6 @@ docmd(struct opts *opts, const char *msg, const char *cmd,
(arg2) ? arg2 : "",
(arg3) ? " " : "",
(arg3) ? arg3 : "");
- first = B_FALSE;
}
err_fromfd(pfd.fd);
}
@@ -1084,7 +1080,6 @@ docmd(struct opts *opts, const char *msg, const char *cmd,
}
if (waitpid(pid, &wstat, 0) < 0) {
err(EF_SYS, "waitpid");
- return;
}
if (!first) {
@@ -1149,20 +1144,15 @@ docopytruncate(struct opts *opts, const char *file, const char *file_copy)
/* open log file to be rotated and remember its chmod mask */
if ((fi = open(file, O_RDWR)) < 0) {
err(EF_SYS, "cannot open file %s", file);
- return;
}
if (fstat(fi, &s) < 0) {
err(EF_SYS, "cannot access: %s", file);
- (void) close(fi);
- return;
}
/* create new file for copy destination with correct attributes */
if ((fo = open(file_copy, O_CREAT|O_TRUNC|O_WRONLY, s.st_mode)) < 0) {
err(EF_SYS, "cannot create file: %s", file_copy);
- (void) close(fi);
- return;
}
(void) fchown(fo, s.st_uid, s.st_gid);
@@ -1188,10 +1178,6 @@ docopytruncate(struct opts *opts, const char *file, const char *file_copy)
do {
if (fstat(fi, &s) < 0) {
err(EF_SYS, "cannot stat: %s", file);
- (void) close(fi);
- (void) close(fo);
- (void) remove(file_copy);
- return;
}
if ((rem = s.st_size - written) < thresh) {
@@ -1231,10 +1217,6 @@ docopytruncate(struct opts *opts, const char *file, const char *file_copy)
}
err(EF_SYS, "cannot write into file %s", file_copy);
- (void) close(fi);
- (void) close(fo);
- (void) remove(file_copy);
- return;
}
} while (len >= 0);
@@ -1249,12 +1231,6 @@ docopytruncate(struct opts *opts, const char *file, const char *file_copy)
while ((len = read(fi, buf, sizeof (buf))) > 0)
if (write(fo, buf, len) != len) {
err(EF_SYS, "cannot write into file %s", file_copy);
- (void) lockf(fi, F_ULOCK, 0);
- (void) fchmod(fi, s.st_mode);
- (void) close(fi);
- (void) close(fo);
- (void) remove(file_copy);
- return;
}
(void) ftruncate(fi, 0);
diff --git a/usr/src/cmd/login/login.dfl b/usr/src/cmd/login/login.dfl
index 13ecd51113..4515dfcc6a 100644
--- a/usr/src/cmd/login/login.dfl
+++ b/usr/src/cmd/login/login.dfl
@@ -36,7 +36,7 @@
# any of the currently enabled /dev/vt/# virtual terminal devices.
# Comment this line out to allow remote login by root.
#
-CONSOLE=/dev/console
+#CONSOLE=/dev/console
# PASSREQ determines if login requires a password.
#
@@ -47,19 +47,16 @@ PASSREQ=YES
ALTSHELL=YES
# PATH sets the initial shell PATH variable
-# sample with GNU tools in front of the path
-# PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin
-# sample with XPG4 tools in front of the path
-# PATH=/usr/xpg4/bin:/usr/bin:/usr/sbin:/sbin
-PATH=/usr/bin:/usr/sbin:/sbin:/usr/gnu/bin
+#
+#PATH=/usr/bin:
# SUPATH sets the initial shell PATH variable for root
#
-SUPATH=/usr/sbin:/sbin:/usr/bin
+#SUPATH=/usr/sbin:/usr/bin
# TIMEOUT sets the number of seconds (between 0 and 900) to wait before
# abandoning a login session.
-#
+#
#TIMEOUT=300
# UMASK sets the initial shell file creation mode mask. See umask(1).
@@ -80,9 +77,9 @@ SYSLOG=YES
#SLEEPTIME=4
# DISABLETIME If present, and greater than zero, the number of seconds
-# login will wait after RETRIES failed attempts or the PAM framework returns
+# login will wait after RETRIES failed attempts or the PAM framework returns
# PAM_ABORT. Default is 20. Minimum is 0. No maximum is imposed.
-#
+#
#DISABLETIME=20
# RETRIES determines the number of failed logins that will be
diff --git a/usr/src/cmd/machid/Makefile b/usr/src/cmd/machid/Makefile
new file mode 100644
index 0000000000..6a3c7138dc
--- /dev/null
+++ b/usr/src/cmd/machid/Makefile
@@ -0,0 +1,80 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+PROG= machid
+
+include ../Makefile.cmd
+
+#
+# List of all links present on all architectures and machines.
+#
+# Note that this function is obsolesent and we don't generally
+# add to this list (see psarc/1992/171).
+#
+FIRSTLINK = i286
+LINKS = i386 i486 i860 i86pc iAPX286 \
+ m68k mc68000 mc68010 mc68020 mc68030 mc68040 \
+ sparc sun sun2 sun3 sun3x sun4 sun4c sun4m sun4d sun4e \
+ u370 u3b u3b15 u3b2 u3b5 vax pdp11
+
+ROOTFIRSTLINK = $(ROOTBIN)/$(FIRSTLINK)
+ROOTLINKS = $(LINKS:%=$(ROOTBIN)/%)
+
+#
+# Install the program as the first machine in the list.
+#
+INSTALLIT= $(INS.link)
+$(ROOTFIRSTLINK):= INSTALLIT = $(INS.rename)
+$(ROOTLINKS):= INSLINKTARGET = $(ROOTFIRSTLINK)
+
+$(ROOTLINKS): $(ROOTFIRSTLINK)
+
+#
+# Link installation rules
+#
+$(ROOTBIN)/%: $(PROG)
+ $(INSTALLIT)
+
+$(ROOTFIRSTLINK): $(ROOTBIN)
+
+$(ROOTBIN):
+ $(INS.dir)
+
+CFLAGS += $(CCVERBOSE)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTLINKS)
+
+clean:
+
+lint: lint_PROG
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/machid/machid.c b/usr/src/cmd/machid/machid.c
new file mode 100644
index 0000000000..c3d57b91f9
--- /dev/null
+++ b/usr/src/cmd/machid/machid.c
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1993-1994, by Sun Microsystems, Inc.
+ */
+
+/*
+ * This program replicates the function of the links from a machine name
+ * (such as sun4c) through /usr/kvm to true or false as appropriate. It
+ * knows the correct special cases.
+ *
+ * IMPORTANT NOTE:
+ *
+ * Do not modify this program to know about additional special cases or
+ * reflect new platforms or instruction set architectures. This is a
+ * deprecated interface and strictly for backwards compatibility. This
+ * is psarc/1992/171. Note the following excerpt from the opinion:
+ *
+ * It is most important to note that the manual page states in
+ * the NOTES section: "The machid family of commands is
+ * obsolete. Use uname -p and uname -m instead."
+ *
+ * The intent of Kernel Architecture Project team is to provide
+ * only enough functionality to mimic the existing definitions
+ * on the SPARC and Intel x86 versions of Solaris 2.x. No new
+ * identifiers will ever be added to the documented and
+ * undocumented identifiers listed above.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/systeminfo.h>
+
+static char static_buf[SYS_NMLN];
+static char *progname;
+
+static void get_info_item(int command, char **buf, long *count);
+
+/* ARGSUSED */
+int
+main(int argc, char *argv[], char *envp[])
+{
+ char *buf = &static_buf[0];
+ long buflen = SYS_NMLN;
+
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ /*
+ * First possible match is on the processor type.
+ *
+ * Special case for architectures: i386 matches i486 and visa versa.
+ */
+ get_info_item(SI_ARCHITECTURE, &buf, &buflen);
+ if (strcmp(buf, progname) == 0)
+ return (0);
+ if ((strcmp(buf, "i386") == 0 && strcmp(progname, "i486") == 0) ||
+ (strcmp(buf, "i486") == 0 && strcmp(progname, "i386") == 0))
+ return (0);
+
+ /*
+ * Next possible match is the machine, or more exactly, the value
+ * which would be returned by uname(2) in the machine field or uname(1)
+ * with the -m option. For historical reasons this is really is
+ * often a class of platforms which are identical to userland processes
+ * such as sun4c, sun4m, etc.
+ */
+ get_info_item(SI_MACHINE, &buf, &buflen);
+ if (strcmp(buf, progname) == 0)
+ return (0);
+
+ /*
+ * Finally, match the vendor. We hardwire in one historical match.
+ */
+ get_info_item(SI_HW_PROVIDER, &buf, &buflen);
+ if (strcmp(buf, progname) == 0)
+ return (0);
+ if (strcasecmp(buf, "Sun_Microsystems") == 0 &&
+ strcmp("sun", progname) == 0)
+ return (0);
+
+ return (255);
+}
+
+/*
+ * get_info_item is a wrapper around the sysinfo system call. It makes sure
+ * the buffer is large enough, returning a larger buffer if needed. On
+ * unrecoverable error, it exits. An error message doesn't help and makes
+ * this tiny program link stdio and maybe deal with internationalization,
+ * so the best thing is to die silently. Note that the larger buffer is
+ * retained for later use. Reality is that the buffer will always be big
+ * enough, but this is coded to the spec rather than implementation.
+ */
+static void
+get_info_item(int command, char **buf, long *count)
+{
+ long error;
+
+ error = sysinfo(command, *buf, *count);
+ if (error > *count) {
+ *count = error;
+ if (*buf != static_buf) {
+ free(*buf);
+ }
+ *buf = (char *) malloc(*count);
+ error = sysinfo(command, *buf, *count);
+ }
+
+ if (error == -1)
+ exit(-1);
+}
diff --git a/usr/src/cmd/man/Makefile.com b/usr/src/cmd/man/Makefile.com
new file mode 100644
index 0000000000..8f1b3adf7d
--- /dev/null
+++ b/usr/src/cmd/man/Makefile.com
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+PROG= man
+LINKS= apropos whatis catman
+LIBLINKS = makewhatis
+OBJS= makewhatis.o man.o stringlist.o
+SRCS= $(OBJS:%.o=%.c)
+
+
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common
index ff81215380..4fc3f3d317 100644
--- a/usr/src/cmd/mdb/Makefile.common
+++ b/usr/src/cmd/mdb/Makefile.common
@@ -103,6 +103,7 @@ COMMON_MODULES_KVM = \
stmf_sbd \
ufs \
usba \
+ xhci \
zfs
CLOSED_COMMON_MODULES_KVM = \
diff --git a/usr/src/cmd/mdb/Makefile.module b/usr/src/cmd/mdb/Makefile.module
index b61ed79ad4..ee89bd5a18 100644
--- a/usr/src/cmd/mdb/Makefile.module
+++ b/usr/src/cmd/mdb/Makefile.module
@@ -104,7 +104,7 @@ LINTFILES_raw = $(LINTOBJS)
LINTFILES = $(LINTFILES_$(MDBTGT))
#
-# Python specific flags. To try and make life easier for folks how are
+# Python specific flags. To try and make life easier for folks who are
# building with an LFS python, we attempt to use -isystem when it's
# available.
#
@@ -112,6 +112,12 @@ PYCPPFLAGS = -_gcc=-isystem -_gcc=$(ADJUNCT_PROTO)/usr/include/python$(PYTHON_V
PYCPPFLAGS += -_cc=-I$(ADJUNCT_PROTO)/usr/include/python$(PYTHON_VERSION)
PYLNFLAGS = -I$(ADJUNCT_PROTO)/usr/include/python$(PYTHON_VERSION)
+#
+# At this time, we do not have python27 in the adjunct proto area, only
+# python26. As such, we explicitly override the python version dmod here.
+#
+PYTHON_VERSION = 2.6
+
kvm_TGTFLAGS = -D_KERNEL
proc_TGTFLAGS = -D_USER
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
index 10c622443a..9943773424 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
@@ -26,7 +26,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2019 Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
* Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
* Copyright (c) 2015, 2017 by Delphix. All rights reserved.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
@@ -2165,6 +2165,46 @@ cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_OK);
}
+static void
+dis_help(void)
+{
+ static const char dis_desc[] =
+"Disassembles instructions starting at the final argument or the current\n"
+"value of dot. If the address is the start of a function, the entire\n"
+"function is disassembled, or else a window of instructions before and after\n"
+"the disassembled address are displayed.\n"
+"\n";
+
+ static const char dis_opts[] =
+" -a Print instruction addresses as numeric values instead of \n"
+" symbolic values.\n"
+" -b Print instruction addresses as both numeric and symbolic "
+"values.\n"
+" -f Read instructions from the target's object file instead of the \n"
+" target's virtual address space.\n"
+" -n instr Display 'instr' instructions before and after the given "
+"address.\n"
+" -w Force window behavior, even at the start of a function.\n"
+"\n";
+
+ static const char dis_examples[] =
+" ::dis\n"
+" clock::dis\n"
+" ::dis gethrtime\n"
+" set_freemem+0x16::dis -n 4\n"
+"\n";
+
+ mdb_printf("%s", dis_desc);
+ (void) mdb_dec_indent(2);
+ mdb_printf("%<b>OPTIONS%</b>\n");
+ (void) mdb_inc_indent(2);
+ mdb_printf("%s", dis_opts);
+ (void) mdb_dec_indent(2);
+ mdb_printf("%<b>EXAMPLES%</b>\n");
+ (void) mdb_inc_indent(2);
+ (void) mdb_printf("%s", dis_examples);
+}
+
/*ARGSUSED*/
static int
walk_step(uintptr_t addr, const void *data, void *private)
@@ -3105,7 +3145,8 @@ const mdb_dcmd_t mdb_dcmd_builtins[] = {
{ "dcmds", "[[-n] pattern]",
"list available debugger commands", cmd_dcmds, cmd_dcmds_help },
{ "delete", "?[id|all]", "delete traced software events", cmd_delete },
- { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis },
+ { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis,
+ dis_help },
{ "disasms", NULL, "list available disassemblers", cmd_disasms },
{ "dismode", "[mode]", "get/set disassembly mode", cmd_dismode },
{ "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods },
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
index 90cedaea4e..9cc7c6f1a0 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
@@ -838,6 +838,7 @@ static int
member_info_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
{
mbr_info_t *mbrp = data;
+ int kind, ret;
if (strcmp(name, mbrp->mbr_member) == 0) {
if (mbrp->mbr_offp != NULL)
@@ -848,7 +849,46 @@ member_info_cb(const char *name, mdb_ctf_id_t id, ulong_t off, void *data)
return (1);
}
- return (0);
+ /*
+ * C11 as well as earlier GNU extensions allow an embedded struct
+ * or union to be unnamed as long as there are no unambiguous member
+ * names. If we encounter a SOU member with a 0-length name,
+ * recurse into it and see if any of them match.
+ */
+ if (strlen(name) != 0)
+ return (0);
+
+ kind = mdb_ctf_type_kind(id);
+ if (kind == CTF_ERR)
+ return (-1);
+ if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+ return (0);
+
+ /*
+ * Search the unnamed SOU for mbrp->mbr_member, possibly recursing if
+ * it also contains unnamed members. If the desired member is found.
+ * *mbrp->mbr_offp will contain the offset of the member relative to
+ * this unnamed SOU (if the offset was requested) -- i.e.
+ * we effectively have *mbrp->mbr_offp == offsetof("", member). We want
+ * unnamed SOUs to act as members of the enclosing SOUs, so we need to
+ * return the offset as relative to the outer SOU. Since 'off' is
+ * the offset of the unnamed SOU relative to the enclosing SOU (i.e.
+ * off == offsetof(outer, "")), we add the two together to produce the
+ * desired offset. This can recurse as necessary -- the compiler
+ * prevents any ambiguities from occurring (or else it wouldn't be
+ * able to compile the code), and the result will be relative to
+ * the start of the SOU given in the mdb_ctf_member_info() call.
+ */
+ ret = mdb_ctf_member_iter(id, member_info_cb, mbrp);
+ if (ret == -1)
+ return (-1);
+ if (ret == 0)
+ return (0);
+
+ if (mbrp->mbr_offp != NULL)
+ *(mbrp->mbr_offp) += off;
+
+ return (1);
}
int
@@ -856,10 +896,21 @@ mdb_ctf_member_info(mdb_ctf_id_t id, const char *member, ulong_t *offp,
mdb_ctf_id_t *typep)
{
mbr_info_t mbr;
+ /*
+ * We want the resulting offset (if requested -- offp != NULL) to
+ * be relative to the start of _this_ SOU. If we have to search any
+ * embedded unnamed SOUs, instead of merely assigning the resulting
+ * offset value to mbr_offp, we will have to add the offsets of
+ * any nested SOUs along the way (see comments in member_info_cb()).
+ * Therefore, initialize off to 0 here so we do not need to worry about
+ * recursion depth in member_info_cb (otherwise we would need to set
+ * mbr_offp when depth = 1, and add when depth > 1).
+ */
+ ulong_t off = 0;
int rc;
mbr.mbr_member = member;
- mbr.mbr_offp = offp;
+ mbr.mbr_offp = &off;
mbr.mbr_typep = typep;
rc = mdb_ctf_member_iter(id, member_info_cb, &mbr);
@@ -872,6 +923,9 @@ mdb_ctf_member_info(mdb_ctf_id_t id, const char *member, ulong_t *offp,
if (rc == 0)
return (set_errno(EMDB_CTFNOMEMB));
+ if (offp != NULL)
+ *offp = off;
+
return (0);
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_main.c b/usr/src/cmd/mdb/common/mdb/mdb_main.c
index 8747464328..e1c2ce5fa4 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_main.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_main.c
@@ -51,6 +51,7 @@
#include <libctf.h>
#include <errno.h>
#include <kvm.h>
+#include <zone.h>
#include <mdb/mdb_lex.h>
#include <mdb/mdb_debug.h>
@@ -818,9 +819,15 @@ main(int argc, char *argv[], char *envp[])
if (strchr(pidarg, '/') != NULL)
(void) mdb_iob_snprintf(object, MAXPATHLEN,
"%s/object/a.out", pidarg);
- else
+ else {
+ const char *root;
+
(void) mdb_iob_snprintf(object, MAXPATHLEN,
- "/proc/%s/object/a.out", pidarg);
+ "%s/proc/%s/object/a.out",
+ (root = zone_get_nroot()) != NULL ? root : "",
+ pidarg);
+ }
+
tgt_argv[tgt_argc++] = object;
tgt_argv[tgt_argc++] = pidarg;
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_modapi.h b/usr/src/cmd/mdb/common/mdb/mdb_modapi.h
index d85bba5e2a..0d6ea3821c 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_modapi.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_modapi.h
@@ -80,11 +80,6 @@ extern "C" {
#define DCMD_HDRSPEC(fl) (((fl) & DCMD_LOOPFIRST) || !((fl) & DCMD_LOOP))
/*
- * Debugger tab command function flags
- */
-#define DCMD_TAB_SPACE 0x01 /* Tab cb invoked with trailing space */
-
-/*
* Debugger command function return values:
*/
#define DCMD_OK 0 /* Dcmd completed successfully */
@@ -113,10 +108,18 @@ typedef struct mdb_arg {
} a_un;
} mdb_arg_t;
+#if (MDB_API_VERSION >= 4)
+/*
+ * Debugger tab command function flags
+ */
+#define DCMD_TAB_SPACE 0x01 /* Tab cb invoked with trailing space */
+
typedef struct mdb_tab_cookie mdb_tab_cookie_t;
-typedef int mdb_dcmd_f(uintptr_t, uint_t, int, const mdb_arg_t *);
typedef int mdb_dcmd_tab_f(mdb_tab_cookie_t *, uint_t, int,
const mdb_arg_t *);
+#endif /* MDB_API_VERSION >= 4 */
+
+typedef int mdb_dcmd_f(uintptr_t, uint_t, int, const mdb_arg_t *);
typedef struct mdb_dcmd {
const char *dc_name; /* Command name */
@@ -124,7 +127,9 @@ typedef struct mdb_dcmd {
const char *dc_descr; /* Description */
mdb_dcmd_f *dc_funcp; /* Command function */
void (*dc_help)(void); /* Command help function (or NULL) */
+#if (MDB_API_VERSION >= 4)
mdb_dcmd_tab_f *dc_tabp; /* Tab completion function */
+#endif
} mdb_dcmd_t;
#define WALK_ERR -1 /* Walk fatal error (terminate walk) */
@@ -346,6 +351,7 @@ typedef void (*mdb_callback_f)(void *);
extern void *mdb_callback_add(int, mdb_callback_f, void *);
extern void mdb_callback_remove(void *);
+#if (MDB_API_VERSION >= 4)
#define MDB_TABC_ALL_TYPES 0x1 /* Include array types in type output */
#define MDB_TABC_MEMBERS 0x2 /* Tab comp. types with members */
#define MDB_TABC_NOPOINT 0x4 /* Tab comp. everything but pointers */
@@ -370,6 +376,7 @@ extern int mdb_tab_typename(int *, const mdb_arg_t **, char *buf, size_t len);
*/
extern int mdb_tab_complete_mt(mdb_tab_cookie_t *, uint_t, int,
const mdb_arg_t *);
+#endif /* MDB_API_VERSION >= 4 */
extern size_t strlcat(char *, const char *, size_t);
extern char *strcat(char *, const char *);
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_print.c b/usr/src/cmd/mdb/common/mdb/mdb_print.c
index 62338f78a2..bd23ef681f 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_print.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_print.c
@@ -1699,6 +1699,52 @@ elt_print(const char *name, mdb_ctf_id_t id, mdb_ctf_id_t base,
mdb_printf("%s%s", pap->pa_prefix,
(depth == 0) ? "" : pap->pa_suffix);
mdb_printf("%s", name);
+
+ /*
+ * When no name is present (i.e. an unnamed struct or union),
+ * display '(anon)' instead only when no prefix is present.
+ * When printing out a struct or union (sou), prefixes are
+ * only present (i.e. !NULL or non-empty) when printing
+ * individual members of that sou, e.g.
+ * `::print struct foo f_member`. When printing an entire sou,
+ * the prefix will be NULL or empty. We end up with:
+ *
+ * > ::print struct foo
+ * {
+ * ...
+ * f_member = 0xabcd
+ * (anon) = {
+ * anon_member = 0x1234
+ * ....
+ * }
+ * ...
+ * }
+ *
+ * and
+ *
+ * > ::print struct foo anon_member
+ * anon_member = 0x1234
+ *
+ * instead of:
+ *
+ * > ::print struct foo
+ * {
+ * ...
+ * f_member = 0xabcd
+ * = {
+ * anon_member = 0x1234
+ * }
+ * ...
+ * }
+ *
+ * and
+ *
+ * > ::print struct foo anon_member
+ * anon_member(anon) = 0x1234
+ */
+ if (depth > 0 && strlen(name) == 0 &&
+ (pap->pa_prefix == NULL || strlen(pap->pa_prefix) == 0))
+ mdb_printf("(anon)");
}
if ((pap->pa_flags & PA_SHOWTYPE) && kind == CTF_K_INTEGER) {
@@ -1717,8 +1763,9 @@ elt_print(const char *name, mdb_ctf_id_t id, mdb_ctf_id_t base,
}
if (depth != 0 ||
- ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL))
+ ((pap->pa_flags & PA_SHOWNAME) && pap->pa_prefix != NULL)) {
mdb_printf("%s ", pap->pa_flags & PA_SHOWVAL ? " =" : "");
+ }
if (depth == 0 && pap->pa_prefix != NULL)
name = pap->pa_prefix;
@@ -2124,10 +2171,10 @@ cmd_print_tab_common(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
/*
* This is the reason that tab completion was created. We're going to go
- * along and walk the delimiters until we find something a member that
- * we don't recognize, at which point we'll try and tab complete it.
- * Note that ::print takes multiple args, so this is going to operate on
- * whatever the last arg that we have is.
+ * along and walk the delimiters until we find something in a member
+ * that we don't recognize, at which point we'll try and tab complete
+ * it. Note that ::print takes multiple args, so this is going to
+ * operate on whatever the last arg that we have is.
*/
if (mdb_ctf_lookup_by_name(tn, &id) != 0)
return (1);
@@ -2137,11 +2184,11 @@ cmd_print_tab_common(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
delim = parse_delimiter(&start);
/*
- * If we hit the case where we actually have no delimiters, than we need
+ * If we hit the case where we actually have no delimiters, then we need
* to make sure that we properly set up the fields the loops would.
*/
if (delim == MEMBER_DELIM_DONE)
- (void) mdb_snprintf(member, sizeof (member), "%s", start);
+ (void) mdb_snprintf(member, sizeof (member), start);
while (delim != MEMBER_DELIM_DONE) {
switch (delim) {
@@ -2198,7 +2245,7 @@ cmd_print_tab_common(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
/*
* We are going to try to resolve this name as a member. There
- * are a few two different questions that we need to answer. The
+ * are a two different questions that we need to answer. The
* first is do we recognize this member. The second is are we at
* the end of the string. If we encounter a member that we don't
* recognize before the end, then we have to error out and can't
@@ -2228,6 +2275,7 @@ cmd_print_tab_common(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
* already have in rid.
*/
return (mdb_tab_complete_member_by_id(mcp, rid, member));
+
}
int
@@ -2437,8 +2485,10 @@ cmd_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
kind = mdb_ctf_type_kind(rid);
if (last_deref && IS_SOU(kind)) {
char *end;
+ size_t len = strlen(member);
(void) mdb_snprintf(buf, sizeof (buf),
- "%s", member);
+ "%s", (len == 0) ?
+ "<anon>" : member);
end = strrchr(buf, '[');
*end = '\0';
pa.pa_suffix = "->";
@@ -2557,8 +2607,7 @@ print_help(void)
}
static int
-printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt,
- boolean_t sign)
+printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt, int sign)
{
ssize_t size;
mdb_ctf_id_t base;
@@ -2576,7 +2625,7 @@ printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt,
} u;
if (mdb_ctf_type_resolve(id, &base) == -1) {
- mdb_warn("could not resolve type");
+ mdb_warn("could not resolve type\n");
return (DCMD_ABORT);
}
@@ -2814,7 +2863,6 @@ printf_string(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt)
if (size != 1) {
mdb_warn("string format specifier requires "
"an array of characters\n");
- return (DCMD_ABORT);
}
bzero(buf, sizeof (buf));
@@ -2948,7 +2996,7 @@ cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
if (argc == 0 || argv[0].a_type != MDB_TYPE_STRING) {
mdb_warn("expected a format string\n");
- return (DCMD_USAGE);
+ return (DCMD_ABORT);
}
/*
@@ -2957,12 +3005,6 @@ cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
* subset of mdb_printf() format strings that we allow.
*/
fmt = argv[0].a_un.a_str;
- /*
- * 'dest' must be large enough to hold a copy of the format string,
- * plus a NUL and up to 2 additional characters for each conversion
- * in the format string. This gives us a bloat factor of 5/2 ~= 3.
- * e.g. "%d" (strlen of 2) --> "%lld\0" (need 5 bytes)
- */
dest = mdb_zalloc(strlen(fmt) * 3, UM_SLEEP | UM_GC);
fmts = mdb_zalloc(strlen(fmt) * sizeof (char *), UM_SLEEP | UM_GC);
funcs = mdb_zalloc(strlen(fmt) * sizeof (void *), UM_SLEEP | UM_GC);
@@ -3146,22 +3188,22 @@ static char _mdb_printf_help[] =
"\n"
" %% Prints the '%' symbol.\n"
" %a Prints the member in symbolic form.\n"
-" %d Prints the member as a decimal integer. If the member is a signed\n"
+" %d Prints the member as a decimal integer. If the member is a signed\n"
" integer type, the output will be signed.\n"
" %H Prints the member as a human-readable size.\n"
" %I Prints the member as an IPv4 address (must be 32-bit integer type).\n"
" %N Prints the member as an IPv6 address (must be of type in6_addr_t).\n"
" %o Prints the member as an unsigned octal integer.\n"
" %p Prints the member as a pointer, in hexadecimal.\n"
-" %q Prints the member in signed octal. Honk if you ever use this!\n"
-" %r Prints the member as an unsigned value in the current output radix.\n"
-" %R Prints the member as a signed value in the current output radix.\n"
+" %q Prints the member in signed octal. Honk if you ever use this!\n"
+" %r Prints the member as an unsigned value in the current output radix. \n"
+" %R Prints the member as a signed value in the current output radix. \n"
" %s Prints the member as a string (requires a pointer or an array of\n"
" characters).\n"
" %u Prints the member as an unsigned decimal integer.\n"
" %x Prints the member in hexadecimal.\n"
" %X Prints the member in hexadecimal, using the characters A-F as the\n"
-" digits for the values 10-15.\n"
+" digits for the values 10-15. \n"
" %Y Prints the member as a time_t as the string "
"'year month day HH:MM:SS'.\n"
"\n"
@@ -3174,13 +3216,13 @@ static char _mdb_printf_help[] =
"\n"
"The following flag specifers are recognized by ::printf:\n"
"\n"
-" %- Left-justify the output within the specified field width. If the\n"
+" %- Left-justify the output within the specified field width. If the\n"
" width of the output is less than the specified field width, the\n"
-" output will be padded with blanks on the right-hand side. Without\n"
+" output will be padded with blanks on the right-hand side. Without\n"
" %-, values are right-justified by default.\n"
"\n"
" %0 Zero-fill the output field if the output is right-justified and the\n"
-" width of the output is less than the specified field width. Without\n"
+" width of the output is less than the specified field width. Without\n"
" %0, right-justified values are prepended with blanks in order to\n"
" fill the field.\n"
"\n"
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_tab.c b/usr/src/cmd/mdb/common/mdb/mdb_tab.c
index 8addc11a46..cd6995f887 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_tab.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_tab.c
@@ -388,11 +388,6 @@ mdb_tab_size(mdb_tab_cookie_t *mcp)
return (mdb_nv_size(&mcp->mtc_nv));
}
-/*
- * Determine whether the specified name is a valid tab completion for
- * the given command. If the name is a valid tab completion then
- * it will be saved in the mdb_tab_cookie_t.
- */
void
mdb_tab_insert(mdb_tab_cookie_t *mcp, const char *name)
{
@@ -501,31 +496,18 @@ tab_complete_type(mdb_ctf_id_t id, void *arg)
mdb_tab_cookie_t *mcp = arg;
uint_t flags = (uint_t)(uintptr_t)mcp->mtc_cba;
- /*
- * CTF data includes types that mdb commands don't understand. Before
- * we resolve the actual type prune any entry that is a type we
- * don't care about.
- */
- switch (mdb_ctf_type_kind(id)) {
- case CTF_K_CONST:
- case CTF_K_RESTRICT:
- case CTF_K_VOLATILE:
- return (0);
- }
-
if (mdb_ctf_type_resolve(id, &rid) != 0)
return (1);
rkind = mdb_ctf_type_kind(rid);
-
- if ((flags & MDB_TABC_MEMBERS) && rkind != CTF_K_STRUCT &&
+ if (flags & MDB_TABC_MEMBERS && rkind != CTF_K_STRUCT &&
rkind != CTF_K_UNION)
return (0);
- if ((flags & MDB_TABC_NOPOINT) && rkind == CTF_K_POINTER)
+ if (flags & MDB_TABC_NOPOINT && rkind == CTF_K_POINTER)
return (0);
- if ((flags & MDB_TABC_NOARRAY) && rkind == CTF_K_ARRAY)
+ if (flags & MDB_TABC_NOARRAY && rkind == CTF_K_ARRAY)
return (0);
(void) mdb_ctf_type_name(id, buf, sizeof (buf));
diff --git a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
index 9170118470..d371cf70fe 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
+++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
@@ -72,6 +72,7 @@ GENUNIX_SRCS = \
pci.c \
pg.c \
rctl.c \
+ refhash.c \
refstr.c \
sobj.c \
streams.c \
diff --git a/usr/src/cmd/mdb/common/modules/genunix/ctxop.c b/usr/src/cmd/mdb/common/modules/genunix/ctxop.c
index d78432b743..c8a59ce9ac 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/ctxop.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/ctxop.c
@@ -27,8 +27,9 @@
* Copyright 2018 Joyent, Inc.
*/
-#include <mdb/mdb_modapi.h>
+#include <sys/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
+#include <sys/thread.h>
#include "ctxop.h"
struct ctxop_walk_state {
diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c
index f8d2de5f12..32370ba7e1 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c
@@ -99,6 +99,7 @@
#include "pci.h"
#include "pg.h"
#include "rctl.h"
+#include "refhash.h"
#include "sobj.h"
#include "streams.h"
#include "sysevent.h"
@@ -116,10 +117,6 @@
*/
#define NINTR 16
-#define KILOS 10
-#define MEGS 20
-#define GIGS 30
-
#ifndef STACK_BIAS
#define STACK_BIAS 0
#endif
@@ -2136,24 +2133,24 @@ typedef struct datafmt {
} datafmt_t;
static datafmt_t kmemfmt[] = {
- { "cache ", "name ",
- "-------------------------", "%-25s " },
- { " buf", " size", "------", "%6u " },
- { " buf", "in use", "------", "%6u " },
- { " buf", " total", "------", "%6u " },
- { " memory", " in use", "----------", "%10lu%c " },
- { " alloc", " succeed", "---------", "%9u " },
- { "alloc", " fail", "-----", "%5u " },
+ { "cache ", "name ",
+ "------------------------------", "%-30s " },
+ { " buf", " size", "-----", "%5H " },
+ { " buf", " in use", "---------", "%9u " },
+ { " buf", " total", "---------", "%9u " },
+ { "memory", "in use", "------", "%6lH " },
+ { " alloc", " succeed", "----------", "%10u " },
+ { "alloc", " fail", "-----", "%5u" },
{ NULL, NULL, NULL, NULL }
};
static datafmt_t vmemfmt[] = {
- { "vmem ", "name ",
- "-------------------------", "%-*s " },
- { " memory", " in use", "----------", "%9llu%c " },
- { " memory", " total", "-----------", "%10llu%c " },
- { " memory", " import", "----------", "%9llu%c " },
- { " alloc", " succeed", "---------", "%9llu " },
+ { "vmem ", "name ",
+ "------------------------------", "%-*s " },
+ { " memory", " in use", "---------", "%9llH " },
+ { " memory", " total", "----------", "%10llH " },
+ { " memory", " import", "---------", "%9llH " },
+ { " alloc", " succeed", "----------", "%10llu " },
{ "alloc", " fail", "-----", "%5llu " },
{ NULL, NULL, NULL, NULL }
};
@@ -2205,15 +2202,9 @@ typedef struct kmastat_vmem {
int kv_fail;
} kmastat_vmem_t;
-typedef struct kmastat_args {
- kmastat_vmem_t **ka_kvpp;
- uint_t ka_shift;
-} kmastat_args_t;
-
static int
-kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_args_t *kap)
+kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_vmem_t **kvpp)
{
- kmastat_vmem_t **kvpp = kap->ka_kvpp;
kmastat_vmem_t *kv;
datafmt_t *dfp = kmemfmt;
int magsize;
@@ -2254,9 +2245,7 @@ out:
mdb_printf((dfp++)->fmt, cp->cache_bufsize);
mdb_printf((dfp++)->fmt, total - avail);
mdb_printf((dfp++)->fmt, total);
- mdb_printf((dfp++)->fmt, meminuse >> kap->ka_shift,
- kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' :
- kap->ka_shift == KILOS ? 'K' : 'B');
+ mdb_printf((dfp++)->fmt, meminuse);
mdb_printf((dfp++)->fmt, alloc);
mdb_printf((dfp++)->fmt, cp->cache_alloc_fail);
mdb_printf("\n");
@@ -2265,9 +2254,8 @@ out:
}
static int
-kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap)
+kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_vmem_t *kv)
{
- kmastat_vmem_t *kv = *kap->ka_kvpp;
size_t len;
while (kv != NULL && kv->kv_addr != addr)
@@ -2276,20 +2264,18 @@ kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap)
if (kv == NULL || kv->kv_alloc == 0)
return (WALK_NEXT);
- len = MIN(17, strlen(v->vm_name));
+ len = MIN(22, strlen(v->vm_name));
- mdb_printf("Total [%s]%*s %6s %6s %6s %10lu%c %9u %5u\n", v->vm_name,
- 17 - len, "", "", "", "",
- kv->kv_meminuse >> kap->ka_shift,
- kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' :
- kap->ka_shift == KILOS ? 'K' : 'B', kv->kv_alloc, kv->kv_fail);
+ mdb_printf("Total [%s]%*s %5s %9s %9s %6lH %10u %5u\n", v->vm_name,
+ 22 - len, "", "", "", "",
+ kv->kv_meminuse, kv->kv_alloc, kv->kv_fail);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
-kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp)
+kmastat_vmem(uintptr_t addr, const vmem_t *v, const void *ignored)
{
datafmt_t *dfp = vmemfmt;
const vmem_kstat_t *vkp = &v->vm_kstat;
@@ -2307,16 +2293,10 @@ kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp)
}
mdb_printf("%*s", ident, "");
- mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name);
- mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64 >> *shiftp,
- *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
- *shiftp == KILOS ? 'K' : 'B');
- mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64 >> *shiftp,
- *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
- *shiftp == KILOS ? 'K' : 'B');
- mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64 >> *shiftp,
- *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
- *shiftp == KILOS ? 'K' : 'B');
+ mdb_printf((dfp++)->fmt, 30 - ident, v->vm_name);
+ mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64);
+ mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64);
+ mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64);
mdb_printf((dfp++)->fmt, vkp->vk_alloc.value.ui64);
mdb_printf((dfp++)->fmt, vkp->vk_fail.value.ui64);
@@ -2331,44 +2311,35 @@ kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
kmastat_vmem_t *kv = NULL;
datafmt_t *dfp;
- kmastat_args_t ka;
-
- ka.ka_shift = 0;
- if (mdb_getopts(argc, argv,
- 'k', MDB_OPT_SETBITS, KILOS, &ka.ka_shift,
- 'm', MDB_OPT_SETBITS, MEGS, &ka.ka_shift,
- 'g', MDB_OPT_SETBITS, GIGS, &ka.ka_shift, NULL) != argc)
- return (DCMD_USAGE);
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->hdr1);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->hdr1);
mdb_printf("\n");
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->hdr2);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->hdr2);
mdb_printf("\n");
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->dashes);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes);
mdb_printf("\n");
- ka.ka_kvpp = &kv;
- if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &ka) == -1) {
+ if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &kv) == -1) {
mdb_warn("can't walk 'kmem_cache'");
return (DCMD_ERR);
}
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->dashes);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes);
mdb_printf("\n");
- if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, &ka) == -1) {
+ if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, kv) == -1) {
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->dashes);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes);
mdb_printf("\n");
mdb_printf("\n");
@@ -2385,7 +2356,7 @@ kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_printf("%s ", dfp->dashes);
mdb_printf("\n");
- if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, &ka.ka_shift) == -1) {
+ if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, NULL) == -1) {
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
@@ -4494,6 +4465,8 @@ static const mdb_dcmd_t dcmds[] = {
/* from zone.c */
{ "zid2zone", ":", "find the zone_t with the given zone id",
zid2zone },
+ { "zdid2zone", ":", "find the zone_t with the given zone debug id",
+ zdid2zone },
{ "zone", "?[-r [-v]]", "display kernel zone(s)", zoneprt },
{ "zsd", ":[-v] [zsd_key]", "display zone-specific-data entries for "
"selected zones", zsd },
@@ -4823,6 +4796,10 @@ static const mdb_walker_t walkers[] = {
{ "rctl_val", "given a rctl_t, walk all rctl_val entries associated",
rctl_val_walk_init, rctl_val_walk_step },
+ /* from refhash.c */
+ { REFHASH_WALK_NAME, REFHASH_WALK_DESC,
+ refhash_walk_init, refhash_walk_step, NULL },
+
/* from sobj.c */
{ "blocked", "walk threads blocked on a given sobj",
blocked_walk_init, blocked_walk_step, NULL },
diff --git a/usr/src/cmd/mdb/common/modules/genunix/refhash.c b/usr/src/cmd/mdb/common/modules/genunix/refhash.c
new file mode 100644
index 0000000000..4b4c92dc14
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/genunix/refhash.c
@@ -0,0 +1,61 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018, Joyent, Inc.
+ */
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_ctf.h>
+
+#include <inttypes.h>
+#include <sys/refhash.h>
+
+typedef struct refhash_walk_data {
+ size_t rwd_offset;
+} refhash_walk_data_t;
+
+int
+refhash_walk_init(mdb_walk_state_t *wsp)
+{
+ refhash_t refh = { 0 };
+ refhash_walk_data_t *rwd;
+ int offset;
+
+ /* mdb_ctf_offsetof_by_name() will print any errors */
+ if ((offset = mdb_ctf_offsetof_by_name("refhash_t", "rh_objs")) == -1)
+ return (WALK_ERR);
+
+ if (mdb_vread(&refh, sizeof (refhash_t), wsp->walk_addr) == -1) {
+ mdb_warn("failed to read refhash_t at %#lx", wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ rwd = wsp->walk_data = mdb_zalloc(sizeof (*rwd), UM_SLEEP | UM_GC);
+ rwd->rwd_offset = refh.rh_link_off;
+
+ wsp->walk_addr += offset;
+ if (mdb_layered_walk("list", wsp) == -1) {
+ mdb_warn("can't walk refhash_t");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+int
+refhash_walk_step(mdb_walk_state_t *wsp)
+{
+ refhash_walk_data_t *rwd = wsp->walk_data;
+ uintptr_t addr = wsp->walk_addr - rwd->rwd_offset;
+
+ return (wsp->walk_callback(addr, wsp->walk_layer, wsp->walk_cbdata));
+}
diff --git a/usr/src/cmd/mdb/common/modules/genunix/refhash.h b/usr/src/cmd/mdb/common/modules/genunix/refhash.h
new file mode 100644
index 0000000000..1e91ced8d5
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/genunix/refhash.h
@@ -0,0 +1,35 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018, Joyent, Inc.
+ */
+
+#ifndef _REFHASH_H
+#define _REFHASH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define REFHASH_WALK_NAME "refhash"
+#define REFHASH_WALK_DESC "walk a refhash"
+
+struct mdb_walk_state;
+
+extern int refhash_walk_init(struct mdb_walk_state *);
+extern int refhash_walk_step(struct mdb_walk_state *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REFHASH_H */
diff --git a/usr/src/cmd/mdb/common/modules/genunix/zone.c b/usr/src/cmd/mdb/common/modules/genunix/zone.c
index 49cd3e7b6e..57545d94a3 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/zone.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/zone.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
*/
#include <mdb/mdb_param.h>
@@ -34,9 +34,9 @@
#define ZONE_NAMELEN 20
#ifdef _LP64
-#define ZONE_PATHLEN 32
+#define ZONE_PATHLEN 25
#else
-#define ZONE_PATHLEN 40
+#define ZONE_PATHLEN 33
#endif
/*
@@ -52,7 +52,8 @@ char *zone_status_names[] = {
"empty", /* ZONE_IS_EMPTY */
"down", /* ZONE_IS_DOWN */
"dying", /* ZONE_IS_DYING */
- "dead" /* ZONE_IS_DEAD */
+ "dead", /* ZONE_IS_DEAD */
+ "free" /* ZONE_IS_FREE */
};
static int
@@ -80,6 +81,31 @@ zid2zone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_OK);
}
+static int
+zdid_lookup_cb(uintptr_t addr, const zone_t *zone, void *arg)
+{
+ zoneid_t zdid = *(uintptr_t *)arg;
+ if (zone->zone_did == zdid)
+ mdb_printf("%p\n", addr);
+
+ return (WALK_NEXT);
+}
+
+/*ARGSUSED*/
+int
+zdid2zone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ if (!(flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ if (mdb_walk("zone", (mdb_walk_cb_t)zdid_lookup_cb, &addr) == -1) {
+ mdb_warn("failed to walk zone");
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
int
zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
@@ -122,10 +148,10 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
*/
if (DCMD_HDRSPEC(flags)) {
if (ropt_given == FALSE)
- mdb_printf("%<u>%?s %6s %-13s %-20s %-s%</u>\n",
+ mdb_printf("%<u>%?s %4s %-13s %-19s %-s%</u>\n",
"ADDR", "ID", "STATUS", "NAME", "PATH");
else
- mdb_printf("%<u>%?s %6s %10s %10s %-20s%</u>\n",
+ mdb_printf("%<u>%?s %6s %10s %10s %-19s%</u>\n",
"ADDR", "ID", "REFS", "CREFS", "NAME");
}
@@ -164,7 +190,7 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
statusp = zone_status_names[zn.zone_status];
else
statusp = "???";
- mdb_printf("%0?p %6d %-13s %-20s %s\n", addr, zn.zone_id,
+ mdb_printf("%0?p %4d %-13s %-19s %s\n", addr, zn.zone_id,
statusp, name, path);
} else {
/*
@@ -172,7 +198,7 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
* Display the zone's subsystem-specific reference counts if
* the user specified the '-v' option.
*/
- mdb_printf("%0?p %6d %10u %10u %-20s\n", addr, zn.zone_id,
+ mdb_printf("%0?p %6d %10u %10u %-19s\n", addr, zn.zone_id,
zn.zone_ref, zn.zone_cred_ref, name);
if (vopt_given == TRUE) {
GElf_Sym subsys_names_sym;
@@ -410,7 +436,7 @@ zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
* Prepare to output the specified zone's ZSD information.
*/
if (DCMD_HDRSPEC(flags))
- mdb_printf("%<u>%-20s %?s %?s %8s%</u>\n", "ZONE", "KEY",
+ mdb_printf("%<u>%-19s %?s %?s %8s%</u>\n", "ZONE", "KEY",
"VALUE", "FLAGS");
len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zone.zone_name);
if (len > 0) {
@@ -419,7 +445,7 @@ zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
} else {
(void) strcpy(name, "??");
}
- mdb_printf("%-20s ", name);
+ mdb_printf("%-19s ", name);
/*
* Display the requested ZSD entries.
diff --git a/usr/src/cmd/mdb/common/modules/genunix/zone.h b/usr/src/cmd/mdb/common/modules/genunix/zone.h
index 0881f9bbae..94a383e41c 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/zone.h
+++ b/usr/src/cmd/mdb/common/modules/genunix/zone.h
@@ -34,6 +34,7 @@ extern "C" {
#endif
extern int zid2zone(uintptr_t, uint_t, int argc, const mdb_arg_t *);
+extern int zdid2zone(uintptr_t, uint_t, int argc, const mdb_arg_t *);
extern int zoneprt(uintptr_t, uint_t, int argc, const mdb_arg_t *);
extern int zone_walk_init(mdb_walk_state_t *);
diff --git a/usr/src/cmd/mdb/common/modules/ipc/ipc.c b/usr/src/cmd/mdb/common/modules/ipc/ipc.c
index bc87716015..04db8f7fcf 100644
--- a/usr/src/cmd/mdb/common/modules/ipc/ipc.c
+++ b/usr/src/cmd/mdb/common/modules/ipc/ipc.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
#include <mdb/mdb_modapi.h>
@@ -228,7 +229,9 @@ shm_print(kshmid_t *shmid, uintptr_t addr)
printtime_nice("ctime: ", shmid->shm_ctime);
mdb_printf("sptinfo: %-?p sptseg: %-?p\n",
shmid->shm_sptinfo, shmid->shm_sptseg);
- mdb_printf("sptprot: <%lb>\n", shmid->shm_sptprot, prot_flag_bits);
+ mdb_printf("opts: rmpend: %d prot: <%b>\n",
+ ((shmid->shm_opts & SHM_RM_PENDING) != 0),
+ (shmid->shm_opts & SHM_PROT_MASK), prot_flag_bits);
}
diff --git a/usr/src/cmd/mdb/common/modules/libc/libc.c b/usr/src/cmd/mdb/common/modules/libc/libc.c
index 69f4beda74..8ee6af407e 100644
--- a/usr/src/cmd/mdb/common/modules/libc/libc.c
+++ b/usr/src/cmd/mdb/common/modules/libc/libc.c
@@ -138,6 +138,8 @@ d_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack));
mdb_printf(" mcontext = 0x%p\n",
addr + OFFSETOF(ucontext_t, uc_mcontext));
+ mdb_printf(" brand = 0x%p 0x%p 0x%p\n",
+ uc.uc_brand_data[0], uc.uc_brand_data[1], uc.uc_brand_data[2]);
return (DCMD_OK);
}
@@ -849,14 +851,19 @@ d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
prt_addr(uberdata.all_lwps, 1),
prt_addr(uberdata.all_zombies, 0));
- HD("nthreads nzombies ndaemons pid sigacthandler");
- mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n",
+ HD("nthreads nzombies ndaemons pid");
+ mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d\n",
OFFSET(nthreads),
uberdata.nthreads,
uberdata.nzombies,
uberdata.ndaemons,
- (int)uberdata.pid,
- prt_addr((void *)uberdata.sigacthandler, 0));
+ (int)uberdata.pid);
+
+ HD("sigacthandler setctxt");
+ mdb_printf(OFFSTR "%s %s\n",
+ OFFSET(sigacthandler),
+ prt_addr((void *)uberdata.sigacthandler, 1),
+ prt_addr((void *)uberdata.setctxt, 1));
HD("lwp_stacks lwp_laststack nfreestack stk_cache");
mdb_printf(OFFSTR "%s %s %-10d %d\n",
@@ -879,12 +886,17 @@ d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
prt_addr(uberdata.ulwp_replace_last, 1),
prt_addr(uberdata.atforklist, 0));
- HD("robustlocks robustlist progname");
- mdb_printf(OFFSTR "%s %s %s\n",
+ HD("robustlocks robustlist");
+ mdb_printf(OFFSTR "%s %s\n",
OFFSET(robustlocks),
prt_addr(uberdata.robustlocks, 1),
- prt_addr(uberdata.robustlist, 1),
- prt_addr(uberdata.progname, 0));
+ prt_addr(uberdata.robustlist, 1));
+
+ HD("progname ub_broot");
+ mdb_printf(OFFSTR "%s %s\n",
+ OFFSET(progname),
+ prt_addr(uberdata.progname, 1),
+ prt_addr(uberdata.ub_broot, 1));
HD("tdb_bootstrap tdb_sync_addr_hash tdb_'count tdb_'fail");
mdb_printf(OFFSTR "%s %s %-10d %d\n",
diff --git a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
index 85f3839c96..68b2e9d362 100644
--- a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
+++ b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
@@ -60,6 +60,12 @@
#define MDB_PATH_NELEM 256 /* Maximum path components */
+/*
+ * Due to mdb_param.h shenanigans, there's no simple way to include string.h
+ * here...
+ */
+extern char *strtok(char *restrict, const char *restrict);
+
typedef struct mdb_path {
size_t mdp_nelem; /* Number of components */
uint_t mdp_complete; /* Path completely resolved? */
@@ -1811,18 +1817,73 @@ mdb_get_lbolt(void)
return ((ts/nsec) - lbi.lbi_debug_time);
}
+#define startswith(a, b) (strncmp((a), (b), strlen(b)) == 0)
+
+/*
+ * Dig out the branch and revision of the illumos-joyent repo, if we were
+ * provided with it. This is a rather fragile JSON parser, in that it requires
+ * JSON formatted exactly as per the boot_archive.gitstatus file that
+ * "buildversion" is built from.
+ */
void
mdb_print_buildversion(void)
{
+ boolean_t in_joyent = B_FALSE;
GElf_Sym sym;
- if (mdb_lookup_by_name("buildversion", &sym) != 0)
- return;
+ if (mdb_lookup_by_name("buildversion", &sym) != 0) {
+ /* Older kernels used this name. */
+ if (mdb_lookup_by_name("gitstatus_start", &sym) != 0)
+ return;
+ }
char *str = mdb_zalloc(4096, UM_SLEEP | UM_GC);
if (mdb_readstr(str, 4096, sym.st_value) < 1)
return;
- mdb_printf("build version: %s\n", str);
+ /*
+ * Each line is of the form
+ *
+ * "repo": "smartos-live",
+ */
+ for (char *line = strtok(str, "\n"); line != NULL;
+ line = strtok(NULL, "\n")) {
+ /* skip whitespace and first " */
+ line += strspn(line, " \t\"");
+
+ if (startswith(line, "repo")) {
+ line += sizeof ("repo") - 1;
+ line += strspn(line, " \t\":");
+
+ if (startswith(line, "illumos-joyent"))
+ in_joyent = B_TRUE;
+ else if (in_joyent)
+ return;
+ continue;
+ }
+
+ if (!in_joyent)
+ continue;
+
+ if (startswith(line, "branch")) {
+ char *trail = strrchr(line, '"');
+ if (trail != NULL)
+ *trail = '\0';
+ line += sizeof ("branch") - 1;
+ line += strspn(line, " \t\":");
+ mdb_printf("git branch: %s\n", line);
+ continue;
+ }
+
+ if (startswith(line, "rev")) {
+ char *trail = strrchr(line, '"');
+ if (trail != NULL)
+ *trail = '\0';
+ line += sizeof ("rev") - 1;
+ line += strspn(line, " \t\":");
+ mdb_printf("git rev: %s\n", line);
+ continue;
+ }
+ }
}
diff --git a/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c b/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c
index ecb2aba4cc..1a63798c93 100644
--- a/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c
+++ b/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c
@@ -34,6 +34,7 @@
#include <sys/sunmdi.h>
#include <sys/list.h>
#include <sys/scsi/scsi.h>
+#include <sys/refhash.h>
#pragma pack(1)
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
@@ -47,7 +48,6 @@
#pragma pack()
#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
struct {
int value;
diff --git a/usr/src/cmd/mdb/common/modules/random/random.c b/usr/src/cmd/mdb/common/modules/random/random.c
index a1b41f0eb8..2da56dae32 100644
--- a/usr/src/cmd/mdb/common/modules/random/random.c
+++ b/usr/src/cmd/mdb/common/modules/random/random.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
#include <sys/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
@@ -39,10 +41,9 @@ rnd_get_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
rnd_stats_t rnd_stats, rnd_stats_cpu;
uint32_t random_max_ncpus;
- size_t rndmag_t_size;
+ size_t rndmag_pad_t_size;
ulong_t rndmag_t_offset;
uintptr_t rndmag;
- mdb_ctf_id_t rndmag_id;
int i;
if ((flags & DCMD_ADDRSPEC) || argc != 0)
@@ -53,23 +54,20 @@ rnd_get_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_ERR);
}
- if ((mdb_ctf_lookup_by_name("rndmag_t", &rndmag_id) != 0) ||
- (mdb_ctf_offsetof(rndmag_id, "rm_stats", &rndmag_t_offset) != 0) ||
+ if (((rndmag_t_offset = mdb_ctf_offsetof_by_name("rndmag_t", "rm_stats")) == -1) ||
(mdb_readvar(&random_max_ncpus, "random_max_ncpus") == -1) ||
(mdb_readvar(&rndmag, "rndmag") == -1) ||
- ((rndmag_t_size = mdb_ctf_type_size(rndmag_id)) == 0)) {
+ ((rndmag_pad_t_size = mdb_ctf_sizeof_by_name("rndmag_pad_t")) == -1)) {
/* Can't find per-cpu stats. Don't add them in. */
random_max_ncpus = 0;
}
- rndmag_t_offset /= 8;
-
/*
* Read and aggregate per-cpu stats if we have them.
*/
for (i = 0; i < random_max_ncpus; i++) {
mdb_vread(&rnd_stats_cpu, sizeof (rnd_stats_cpu),
- rndmag + rndmag_t_offset + i * rndmag_t_size);
+ rndmag + rndmag_t_offset + i * rndmag_pad_t_size);
rnd_stats.rs_rndOut += rnd_stats_cpu.rs_rndOut;
rnd_stats.rs_rndcOut += rnd_stats_cpu.rs_rndcOut;
diff --git a/usr/src/cmd/mdb/common/modules/xhci/xhci.c b/usr/src/cmd/mdb/common/modules/xhci/xhci.c
new file mode 100644
index 0000000000..1a1882e738
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/xhci/xhci.c
@@ -0,0 +1,893 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <sys/mdb_modapi.h>
+#include <sys/usb/hcd/xhci/xhci.h>
+
+#define XHCI_MDB_TRB_INDENT 4
+
+static const char *xhci_mdb_epctx_eptypes[] = {
+ "Not Valid",
+ "ISOCH OUT",
+ "BULK OUT",
+ "INTR OUT",
+ "CONTROL",
+ "ISOCH IN",
+ "BULK IN",
+ "INTR IN"
+};
+
+static const char *xhci_mdb_epctx_states[] = {
+ "Disabled",
+ "Running",
+ "Halted",
+ "Stopped",
+ "Error",
+ "<Unknown>",
+ "<Unknown>",
+ "<Unknown>"
+};
+
+static const mdb_bitmask_t xhci_mdb_trb_flags[] = {
+ { "C", XHCI_TRB_CYCLE, XHCI_TRB_CYCLE },
+ { "ENT", XHCI_TRB_ENT, XHCI_TRB_ENT },
+ { "ISP", XHCI_TRB_ISP, XHCI_TRB_ISP },
+ { "NS", XHCI_TRB_NOSNOOP, XHCI_TRB_NOSNOOP },
+ { "CH", XHCI_TRB_CHAIN, XHCI_TRB_CHAIN },
+ { "IOC", XHCI_TRB_IOC, XHCI_TRB_IOC },
+ { "IDT", XHCI_TRB_IDT, XHCI_TRB_IDT },
+ { "BEI", XHCI_TRB_BEI, XHCI_TRB_BEI },
+ { NULL, 0, 0 }
+};
+
+typedef struct xhci_mdb_walk_endpoint {
+ xhci_device_t xmwe_device;
+ uint_t xmwe_ep;
+} xhci_mdb_walk_endpoint_t;
+
+static const char *
+xhci_mdb_trb_code_to_str(int code)
+{
+ switch (code) {
+ case XHCI_CODE_INVALID:
+ return ("Invalid");
+ case XHCI_CODE_SUCCESS:
+ return ("Success");
+ case XHCI_CODE_DATA_BUF:
+ return ("Data Overrun or Underrun");
+ case XHCI_CODE_BABBLE:
+ return ("Babble");
+ case XHCI_CODE_TXERR:
+ return ("Transaction Error");
+ case XHCI_CODE_TRB:
+ return ("Invalid TRB");
+ case XHCI_CODE_STALL:
+ return ("Stall");
+ case XHCI_CODE_RESOURCE:
+ return ("No Resources Available");
+ case XHCI_CODE_BANDWIDTH:
+ return ("No Bandwidth Available");
+ case XHCI_CODE_NO_SLOTS:
+ return ("No Slots Available");
+ case XHCI_CODE_STREAM_TYPE:
+ return ("Stream Context Type Detected");
+ case XHCI_CODE_SLOT_NOT_ON:
+ return ("Slot disabled");
+ case XHCI_CODE_ENDP_NOT_ON:
+ return ("Endpoint disabled");
+ case XHCI_CODE_SHORT_XFER:
+ return ("Short Transfer");
+ case XHCI_CODE_RING_UNDERRUN:
+ return ("Isoch. Ring Underrun");
+ case XHCI_CODE_RING_OVERRUN:
+ return ("Isoch. Ring Overrun");
+ case XHCI_CODE_VF_RING_FULL:
+ return ("VF Ring Full");
+ case XHCI_CODE_PARAMETER:
+ return ("Invalid Context Paramenter");
+ case XHCI_CODE_BW_OVERRUN:
+ return ("Bandwidth Overrun");
+ case XHCI_CODE_CONTEXT_STATE:
+ return ("Illegal Context Transition");
+ case XHCI_CODE_NO_PING_RESP:
+ return ("Failed to Complete Periodic Transfer");
+ case XHCI_CODE_EV_RING_FULL:
+ return ("Event Ring Full");
+ case XHCI_CODE_INCOMPAT_DEV:
+ return ("Incompatible Device");
+ case XHCI_CODE_MISSED_SRV:
+ return ("Missed Isoch. Service Window");
+ case XHCI_CODE_CMD_RING_STOP:
+ return ("Command Ring Stop");
+ case XHCI_CODE_CMD_ABORTED:
+ return ("Command Aborted");
+ case XHCI_CODE_XFER_STOPPED:
+ return ("Transfer Stopped");
+ case XHCI_CODE_XFER_STOPINV:
+ return ("Invalid Transfer Length");
+ case XHCI_CODE_XFER_STOPSHORT:
+ return ("Stopped before End of Transfer Descriptor");
+ case XHCI_CODE_MELAT:
+ return ("Max Exit Latency too large");
+ case XHCI_CODE_RESERVED:
+ return ("Reserved");
+ case XHCI_CODE_ISOC_OVERRUN:
+ return ("Isochronus Overrun");
+ case XHCI_CODE_EVENT_LOST:
+ return ("Event Lost");
+ case XHCI_CODE_UNDEFINED:
+ return ("Undefined Fatal Error");
+ case XHCI_CODE_INVALID_SID:
+ return ("Invalid Stream ID");
+ case XHCI_CODE_SEC_BW:
+ return ("Secondary Bandwith Allocation Failure");
+ case XHCI_CODE_SPLITERR:
+ return ("USB2 SPlit Transaction Error");
+ default:
+ break;
+ }
+
+ if (code >= 192 && code <= 223)
+ return ("Vendor Defined Error");
+ if (code >= 224 && code <= 255)
+ return ("Vendor Defined Info");
+
+ return ("Reserved");
+}
+
+static const char *
+xhci_mdb_trb_type_to_str(int code)
+{
+ /*
+ * The macros for the types are all already shifted over based on their
+ * place in the TRB, so shift there again ourselves.
+ */
+ switch (code << 10) {
+ case XHCI_TRB_TYPE_NORMAL:
+ return ("Normal");
+ case XHCI_TRB_TYPE_SETUP:
+ return ("Setup");
+ case XHCI_TRB_TYPE_DATA:
+ return ("Data");
+ case XHCI_TRB_TYPE_STATUS:
+ return ("Status");
+ case XHCI_TRB_TYPE_LINK:
+ return ("Link");
+ case XHCI_TRB_TYPE_EVENT:
+ return ("Event");
+ case XHCI_TRB_TYPE_NOOP:
+ return ("No-Op");
+ case XHCI_CMD_ENABLE_SLOT:
+ return ("Enable Slot");
+ case XHCI_CMD_DISABLE_SLOT:
+ return ("Disable Slot");
+ case XHCI_CMD_ADDRESS_DEVICE:
+ return ("Address Device");
+ case XHCI_CMD_CONFIG_EP:
+ return ("Configure Endpoint");
+ case XHCI_CMD_EVAL_CTX:
+ return ("Evaluate Context");
+ case XHCI_CMD_RESET_EP:
+ return ("Reset Endpoint");
+ case XHCI_CMD_STOP_EP:
+ return ("Stop Endpoint");
+ case XHCI_CMD_SET_TR_DEQ:
+ return ("Set Transfer Ring Dequeue Pointer");
+ case XHCI_CMD_RESET_DEV:
+ return ("Reset Device");
+ case XHCI_CMD_FEVENT:
+ return ("Force Event");
+ case XHCI_CMD_NEG_BW:
+ return ("Negotiate Bandwidth");
+ case XHCI_CMD_SET_LT:
+ return ("Set Latency Tolerance");
+ case XHCI_CMD_GET_BW:
+ return ("Get Bandwidth");
+ case XHCI_CMD_FHEADER:
+ return ("Force Header");
+ case XHCI_CMD_NOOP:
+ return ("No-Op Command");
+ case XHCI_EVT_XFER:
+ return ("Transfer Event");
+ case XHCI_EVT_CMD_COMPLETE:
+ return ("Command Completion Event");
+ case XHCI_EVT_PORT_CHANGE:
+ return ("Port Status Change Event");
+ case XHCI_EVT_BW_REQUEST:
+ return ("Bandwidth Request Event");
+ case XHCI_EVT_DOORBELL:
+ return ("Doorbell Event");
+ case XHCI_EVT_HOST_CTRL:
+ return ("Host Controller Event");
+ case XHCI_EVT_DEVICE_NOTIFY:
+ return ("Device Notification Event");
+ case XHCI_EVT_MFINDEX_WRAP:
+ return ("MFINDEX Wrap Event");
+ default:
+ break;
+ }
+
+ if (code >= 43 && code <= 63)
+ return ("Vendor Defiend");
+ return ("Reserved");
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_epctx(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ uint32_t info, info2, txinfo;
+ xhci_endpoint_context_t epctx;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("::xhci_epctx requires an address\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&epctx, sizeof (epctx), addr) != sizeof (epctx)) {
+ mdb_warn("failed to read xhci_endpoint_context_t at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ info = LE_32(epctx.xec_info);
+ info2 = LE_32(epctx.xec_info2);
+ txinfo = LE_32(epctx.xec_txinfo);
+
+ mdb_printf("Endpoint State: %s (%d)\n",
+ xhci_mdb_epctx_states[XHCI_EPCTX_STATE(info)],
+ XHCI_EPCTX_STATE(info));
+
+ mdb_printf("Mult: %d\n", XHCI_EPCTX_GET_MULT(info));
+ mdb_printf("Max Streams: %d\n", XHCI_EPCTX_GET_MAXP_STREAMS(info));
+ mdb_printf("LSA: %d\n", XHCI_EPCTX_GET_LSA(info));
+ mdb_printf("Interval: %d\n", XHCI_EPCTX_GET_IVAL(info));
+ mdb_printf("Max ESIT Hi: %d\n", XHCI_EPCTX_GET_MAX_ESIT_HI(info));
+
+ mdb_printf("CErr: %d\n", XHCI_EPCTX_GET_CERR(info2));
+ mdb_printf("EP Type: %s (%d)\n",
+ xhci_mdb_epctx_eptypes[XHCI_EPCTX_GET_EPTYPE(info2)],
+ XHCI_EPCTX_GET_EPTYPE(info2));
+ mdb_printf("Host Initiate Disable: %d\n", XHCI_EPCTX_GET_HID(info2));
+ mdb_printf("Max Burst: %d\n", XHCI_EPCTX_GET_MAXB(info2));
+ mdb_printf("Max Packet Size: %d\n", XHCI_EPCTX_GET_MPS(info2));
+
+ mdb_printf("Ring DCS: %d\n", LE_64(epctx.xec_dequeue) & 0x1);
+ mdb_printf("Ring PA: 0x%lx\n", LE_64(epctx.xec_dequeue) & ~0xf);
+
+ mdb_printf("Average TRB Length: %d\n", XHCI_EPCTX_AVG_TRB_LEN(txinfo));
+ mdb_printf("Max ESIT: %d\n", XHCI_EPCTX_GET_MAX_ESIT_PAYLOAD(txinfo));
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_slotctx(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ uint32_t info, info2, tt, state;
+ xhci_slot_context_t sctx;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("::xhci_slotctx requires an address\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&sctx, sizeof (sctx), addr) != sizeof (sctx)) {
+ mdb_warn("failed to read xhci_slot_context_t at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ info = LE_32(sctx.xsc_info);
+ info2 = LE_32(sctx.xsc_info2);
+ tt = LE_32(sctx.xsc_tt);
+ state = LE_32(sctx.xsc_state);
+
+ mdb_printf("Route: 0x%x\n", XHCI_SCTX_GET_ROUTE(info));
+
+ mdb_printf("Slot Speed: ");
+ switch (XHCI_SCTX_GET_SPEED(info)) {
+ case XHCI_SPEED_FULL:
+ mdb_printf("Full");
+ break;
+ case XHCI_SPEED_LOW:
+ mdb_printf("Low");
+ break;
+ case XHCI_SPEED_HIGH:
+ mdb_printf("High");
+ break;
+ case XHCI_SPEED_SUPER:
+ mdb_printf("Super");
+ break;
+ default:
+ mdb_printf("Unknown");
+ break;
+ }
+ mdb_printf(" (%d)\n", XHCI_SCTX_GET_SPEED(info));
+
+
+ mdb_printf("MTT: %d\n", XHCI_SCTX_GET_MTT(info));
+ mdb_printf("HUB: %d\n", XHCI_SCTX_GET_HUB(info));
+ mdb_printf("DCI: %d\n", XHCI_SCTX_GET_DCI(info));
+
+ mdb_printf("Max Exit Latency: %d\n", XHCI_SCTX_GET_MAX_EL(info2));
+ mdb_printf("Root Hub Port: %d\n", XHCI_SCTX_GET_RHPORT(info2));
+ mdb_printf("Hub Number of Ports: %d\n", XHCI_SCTX_GET_NPORTS(info2));
+
+ mdb_printf("TT Hub Slot id: %d\n", XHCI_SCTX_GET_TT_HUB_SID(tt));
+ mdb_printf("TT Port Number: %d\n", XHCI_SCTX_GET_TT_PORT_NUM(tt));
+ mdb_printf("TT Think Time: %d\n", XHCI_SCTX_GET_TT_THINK_TIME(tt));
+ mdb_printf("IRQ Target: %d\n", XHCI_SCTX_GET_IRQ_TARGET(tt));
+
+ mdb_printf("Device Address: 0x%x\n", XHCI_SCTX_GET_DEV_ADDR(state));
+ mdb_printf("Slot State: ");
+ switch (XHCI_SCTX_GET_SLOT_STATE(state)) {
+ case XHCI_SLOT_DIS_ENAB:
+ mdb_printf("Disabled/Enabled");
+ break;
+ case XHCI_SLOT_DEFAULT:
+ mdb_printf("Default");
+ break;
+ case XHCI_SLOT_ADDRESSED:
+ mdb_printf("Addressed");
+ break;
+ case XHCI_SLOT_CONFIGURED:
+ mdb_printf("Configured");
+ break;
+ default:
+ mdb_printf("Unknown");
+ break;
+ }
+ mdb_printf(" (%d)\n", XHCI_SCTX_GET_SLOT_STATE(state));
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_print_transfer_event(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("Transfer Length (Remain): %d\n", XHCI_TRB_REMAIN(status));
+ mdb_printf("Completion Code: %s (%d)\n",
+ xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
+ XHCI_TRB_GET_CODE(status));
+
+ mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags));
+ mdb_printf("Event Data: %d\n", XHCI_TRB_GET_ED(flags));
+ mdb_printf("Endpoint ID: %d\n", XHCI_TRB_GET_EP(flags));
+ mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_print_command_event(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("Command Param: 0x%x\n", XHCI_TRB_REMAIN(status));
+ mdb_printf("Completion Code: %s (%d)\n",
+ xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
+ XHCI_TRB_GET_CODE(status));
+
+ mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags));
+ /* Skip VF ID as we don't support VFs */
+ mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_psc(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("Port: %d\n", XHCI_TRB_PORTID(pa));
+ mdb_printf("Completion Code: %s (%d)\n",
+ xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
+ XHCI_TRB_GET_CODE(status));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_print_normal_trb(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("TRB Length: %d bytes\n", XHCI_TRB_LEN(status));
+ mdb_printf("TRB TD Size: %d packets\n", XHCI_TRB_GET_TDREM(status));
+ mdb_printf("TRB Interrupt: %d\n", XHCI_TRB_GET_INTR(status));
+ mdb_printf("TRB Flags: %b (0x%x)\n", flags, xhci_mdb_trb_flags,
+ XHCI_TRB_GET_FLAGS(flags));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_trb(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ xhci_trb_t trb;
+ uint64_t pa;
+ uint32_t status, trbflags, type;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("::xhci_trb expects an address\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&trb, sizeof (trb), addr) != sizeof (trb)) {
+ mdb_warn("failed to read xhci_trb_t at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+ pa = LE_64(trb.trb_addr);
+ status = LE_32(trb.trb_status);
+ trbflags = LE_32(trb.trb_flags);
+
+ type = XHCI_TRB_GET_TYPE(trbflags);
+
+ if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
+ mdb_printf("\n");
+
+ mdb_set_dot(addr + sizeof (xhci_trb_t));
+ mdb_printf("%s TRB (%d)\n", xhci_mdb_trb_type_to_str(type), type);
+ mdb_inc_indent(XHCI_MDB_TRB_INDENT);
+
+ switch (XHCI_RING_TYPE_SHIFT(type)) {
+ case XHCI_EVT_XFER:
+ return (xhci_mdb_print_transfer_event(pa, status, trbflags));
+ case XHCI_EVT_CMD_COMPLETE:
+ return (xhci_mdb_print_command_event(pa, status, trbflags));
+ case XHCI_EVT_PORT_CHANGE:
+ return (xhci_mdb_print_psc(pa, status, trbflags));
+ case XHCI_TRB_TYPE_NORMAL:
+ return (xhci_mdb_print_normal_trb(pa, status, trbflags));
+ }
+
+ /*
+ * Just print generic information if we don't have a specific printer
+ * for that TRB type.
+ */
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("TRB Status: 0x%x\n", status);
+ mdb_printf("TRB Flags: 0x%x\n", trbflags);
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_walk_xhci_init(mdb_walk_state_t *wsp)
+{
+ GElf_Sym sym;
+ uintptr_t addr;
+
+ if (wsp->walk_addr != 0) {
+ mdb_warn("::walk xhci only supports global walks\n");
+ return (WALK_ERR);
+ }
+
+ if (mdb_lookup_by_obj("xhci", "xhci_soft_state", &sym) != 0) {
+ mdb_warn("failed to find xhci_soft_state symbol");
+ return (WALK_ERR);
+ }
+
+ if (mdb_vread(&addr, sizeof (addr), sym.st_value) != sizeof (addr)) {
+ mdb_warn("failed to read xhci_soft_state at %p", addr);
+ return (WALK_ERR);
+ }
+
+ wsp->walk_addr = addr;
+ if (mdb_layered_walk("softstate", wsp) != 0) {
+ mdb_warn("failed to walk softstate");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_walk_xhci_step(mdb_walk_state_t *wsp)
+{
+ xhci_t xhci;
+
+ if (mdb_vread(&xhci, sizeof (xhci), wsp->walk_addr) != sizeof (xhci)) {
+ mdb_warn("failed to read xhci_t at %p", wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ return (wsp->walk_callback(wsp->walk_addr, &xhci, wsp->walk_cbdata));
+}
+
+static int
+xhci_mdb_walk_xhci_device_init(mdb_walk_state_t *wsp)
+{
+ uintptr_t addr;
+
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk xhci_device requires an xhci_t\n");
+ return (WALK_ERR);
+ }
+
+ addr = wsp->walk_addr;
+ addr += offsetof(xhci_t, xhci_usba);
+ addr += offsetof(xhci_usba_t, xa_devices);
+ wsp->walk_addr = (uintptr_t)addr;
+ if (mdb_layered_walk("list", wsp) != 0) {
+ mdb_warn("failed to walk list");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_walk_xhci_device_step(mdb_walk_state_t *wsp)
+{
+ xhci_device_t xd;
+
+ if (mdb_vread(&xd, sizeof (xd), wsp->walk_addr) != sizeof (xd)) {
+ mdb_warn("failed to read xhci_device_t at %p", wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ return (wsp->walk_callback(wsp->walk_addr, &xd, wsp->walk_cbdata));
+}
+
+static int
+xhci_mdb_walk_xhci_endpoint_init(mdb_walk_state_t *wsp)
+{
+ xhci_mdb_walk_endpoint_t *xm;
+ xhci_device_t *xd;
+
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk xhci_endpoint requires an xhci_device_t\n");
+ return (WALK_ERR);
+ }
+
+ xm = mdb_alloc(sizeof (xhci_mdb_walk_endpoint_t), UM_SLEEP | UM_GC);
+ xm->xmwe_ep = 0;
+ xd = &xm->xmwe_device;
+ if (mdb_vread(xd, sizeof (*xd), wsp->walk_addr) != sizeof (*xd)) {
+ mdb_warn("failed to read xhci_endpoint_t at %p",
+ wsp->walk_addr);
+ return (WALK_ERR);
+ }
+ wsp->walk_data = xm;
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_walk_xhci_endpoint_step(mdb_walk_state_t *wsp)
+{
+ int ret;
+ uintptr_t addr;
+ xhci_mdb_walk_endpoint_t *xm = wsp->walk_data;
+
+ if (xm->xmwe_ep >= XHCI_NUM_ENDPOINTS)
+ return (WALK_DONE);
+
+ addr = (uintptr_t)xm->xmwe_device.xd_endpoints[xm->xmwe_ep];
+ if (addr != (uintptr_t)NULL) {
+ xhci_endpoint_t xe;
+
+ if (mdb_vread(&xe, sizeof (xe), addr) != sizeof (xe)) {
+ mdb_warn("failed to read xhci_endpoint_t at %p",
+ xm->xmwe_device.xd_endpoints[xm->xmwe_ep]);
+ return (WALK_ERR);
+ }
+
+ ret = wsp->walk_callback(addr, &xe, wsp->walk_cbdata);
+ } else {
+ ret = WALK_NEXT;
+ }
+ xm->xmwe_ep++;
+
+ return (ret);
+}
+
+typedef struct xhci_mdb_find {
+ int xmf_slot;
+ int xmf_ep;
+ uintptr_t xmf_addr;
+} xhci_mdb_find_t;
+
+static int
+xhci_mdb_find_endpoint_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const xhci_endpoint_t *xep = data;
+ xhci_mdb_find_t *xmf = arg;
+
+ /*
+ * The endpoints that are presented here are off by one from the actual
+ * endpoint ID in the xhci_endpoint_t, as we're really displaying the
+ * index into the device input context.
+ */
+ if (xep->xep_num + 1 == xmf->xmf_ep) {
+ xmf->xmf_addr = addr;
+ return (WALK_DONE);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_find_device_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const xhci_device_t *xd = data;
+ xhci_mdb_find_t *xmf = arg;
+
+ if (xd->xd_slot == xmf->xmf_slot) {
+ if (xmf->xmf_ep == -1) {
+ xmf->xmf_addr = addr;
+ return (WALK_DONE);
+ }
+
+ if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_find_endpoint_cb,
+ xmf, addr) == -1) {
+ mdb_warn("failed to walk xhci_endpoint at %p", addr);
+ return (WALK_ERR);
+ }
+
+ return (WALK_DONE);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_find(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ uintptr_t ep, slot;
+ boolean_t ep_set, slot_set;
+ xhci_mdb_find_t xmf;
+
+ if ((flags & DCMD_ADDRSPEC) == 0)
+ return (DCMD_USAGE);
+
+ ep_set = slot_set = B_FALSE;
+ if (mdb_getopts(argc, argv, 'e', MDB_OPT_UINTPTR_SET, &ep_set, &ep,
+ 's', MDB_OPT_UINTPTR_SET, &slot_set, &slot, NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (!slot_set) {
+ mdb_warn("-s is required\n");
+ return (DCMD_USAGE);
+ }
+
+ xmf.xmf_slot = (int)slot;
+ if (ep_set)
+ xmf.xmf_ep = (int)ep;
+ else
+ xmf.xmf_ep = -1;
+ xmf.xmf_addr = 0;
+
+ if (mdb_pwalk("xhci`xhci_device", xhci_mdb_find_device_cb,
+ &xmf, addr) == -1) {
+ mdb_warn("failed to walk xhci_device at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ if (xmf.xmf_addr == 0) {
+ if (ep_set) {
+ mdb_warn("failed to find xhci_endpoint_t for slot %d "
+ "and endpoint %d\n", slot, ep);
+ } else {
+ mdb_warn("failed to find xhci_device_t for slot %d\n",
+ slot);
+ }
+ return (DCMD_ERR);
+ }
+
+ mdb_printf("%p\n", xmf.xmf_addr);
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_endpoint_count(uintptr_t addr, const void *ep, void *arg)
+{
+ int *countp = arg;
+
+ *countp += 1;
+ return (WALK_NEXT);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_endpoint_summary(uintptr_t addr, const void *ep, void *arg)
+{
+ const xhci_device_t *xd = arg;
+ const xhci_endpoint_t *xep = ep;
+ const char *type;
+ const char *state;
+ xhci_endpoint_context_t epctx;
+ int eptype;
+
+ if (mdb_vread(&epctx, sizeof (epctx),
+ (uintptr_t)xd->xd_endout[xep->xep_num]) != sizeof (epctx)) {
+ mdb_warn("failed to read endpoint context at %p",
+ xd->xd_endout[xep->xep_num]);
+ return (WALK_ERR);
+ }
+
+ eptype = XHCI_EPCTX_GET_EPTYPE(LE_32(epctx.xec_info2));
+ type = xhci_mdb_epctx_eptypes[eptype];
+ state = xhci_mdb_epctx_states[XHCI_EPCTX_STATE(LE_32(epctx.xec_info))];
+
+ mdb_printf("%-4d %-10s %-10s 0x%-04x 0x%-04x\n", xep->xep_num, type,
+ state, xep->xep_ring.xr_head, xep->xep_ring.xr_tail);
+
+ return (WALK_NEXT);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_device(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ int count;
+ xhci_device_t xd;
+ usba_device_t ud;
+ char product[256], mfg[256];
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ return (mdb_eval("::walk xhci`xhci | ::walk xhci`xhci_device | "
+ "::xhci_device"));
+ }
+
+ if (mdb_vread(&xd, sizeof (xd), addr) != sizeof (xd)) {
+ mdb_warn("failed to read xhci_device_t at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+ if (mdb_vread(&ud, sizeof (ud), (uintptr_t)xd.xd_usbdev) !=
+ sizeof (ud)) {
+ mdb_warn("failed to read usba_device_t at %p\n", xd.xd_usbdev);
+ return (DCMD_ERR);
+ }
+
+ if (ud.usb_mfg_str == NULL || mdb_readstr(mfg, sizeof (mfg),
+ (uintptr_t)ud.usb_mfg_str) <= 0) {
+ (void) strlcpy(mfg, "Unknown Manufacturer", sizeof (mfg));
+ }
+
+ if (ud.usb_product_str == NULL || mdb_readstr(product, sizeof (product),
+ (uintptr_t)ud.usb_product_str) <= 0) {
+ (void) strlcpy(product, "Unknown Product", sizeof (product));
+ }
+
+ mdb_printf("%<b>%s - %s%</b>\n", mfg, product);
+
+ count = 0;
+ if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_endpoint_count, &count,
+ addr) == -1) {
+ mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+ mdb_printf("Port %02d | Slot %02d | # Endpoints %02d\n", xd.xd_port,
+ xd.xd_slot, count);
+ mdb_printf("%<u>%-4s %-10s %-10s %-6s %-6s%</u>\n", "EP", "Type",
+ "State", "Head", "Tail");
+
+ if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_print_endpoint_summary,
+ &xd, addr) == -1) {
+ mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+
+ mdb_printf("\n");
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_find_trb(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ xhci_ring_t xr;
+ uint64_t base, max, target;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("missing required xhci_ring_t\n");
+ return (DCMD_USAGE);
+ }
+
+ if (argc == 0) {
+ mdb_warn("missing required PA of ring\n");
+ return (DCMD_USAGE);
+ }
+
+ if (argc > 1) {
+ mdb_warn("too many arguments\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&xr, sizeof (xr), addr) != sizeof (xr)) {
+ mdb_warn("failed to read xhci_ring_t at %p", addr);
+ return (DCMD_USAGE);
+ }
+
+ if (argv[0].a_type == MDB_TYPE_IMMEDIATE) {
+ target = argv[0].a_un.a_val;
+ } else if (argv[0].a_type == MDB_TYPE_STRING) {
+ target = mdb_strtoull(argv[0].a_un.a_str);
+ } else {
+ mdb_warn("argument is an unknown supported type: %d\n",
+ argv[0].a_type);
+ return (DCMD_USAGE);
+ }
+ target = roundup(target, sizeof (xhci_trb_t));
+
+ base = xr.xr_dma.xdb_cookies[0].dmac_laddress;
+ max = base + xr.xr_ntrb * sizeof (xhci_trb_t);
+
+ if (target < base || target > max) {
+ mdb_warn("target address %p is outside the range of PAs for "
+ "TRBs in the ring [%p, %p)", target, base, max);
+ return (DCMD_ERR);
+ }
+ target -= base;
+ mdb_printf("0x%" PRIx64 "\n", target + (uintptr_t)xr.xr_trb);
+
+ return (DCMD_OK);
+}
+
+static const mdb_dcmd_t xhci_dcmds[] = {
+ { "xhci_epctx", ":", "print endpoint context",
+ xhci_mdb_print_epctx, NULL },
+ { "xhci_slotctx", ":", "print slot context",
+ xhci_mdb_print_slotctx, NULL },
+ { "xhci_trb", ":", "print TRB",
+ xhci_mdb_print_trb, NULL },
+ { "xhci_find", ": -s slot [-e endpiont]",
+ "find given xhci slot or endpoint",
+ xhci_mdb_find, NULL },
+ { "xhci_device", ":", "device summary",
+ xhci_mdb_print_device, NULL },
+ { "xhci_find_trb", ": pa", "find trb with PA in ring",
+ xhci_mdb_find_trb, NULL },
+ { NULL }
+};
+
+static const mdb_walker_t xhci_walkers[] = {
+ { "xhci", "walk list of xhci_t structures",
+ xhci_mdb_walk_xhci_init, xhci_mdb_walk_xhci_step, NULL },
+ { "xhci_device", "walk list of xhci_device_t structures",
+ xhci_mdb_walk_xhci_device_init, xhci_mdb_walk_xhci_device_step,
+ NULL },
+ { "xhci_endpoint", "walk list of xhci_endpoint_t structures",
+ xhci_mdb_walk_xhci_endpoint_init, xhci_mdb_walk_xhci_endpoint_step,
+ NULL },
+ { NULL }
+};
+
+static const mdb_modinfo_t xhci_modinfo = {
+ MDB_API_VERSION, xhci_dcmds, xhci_walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+ return (&xhci_modinfo);
+}
diff --git a/usr/src/cmd/mdb/intel/amd64/libpython/Makefile b/usr/src/cmd/mdb/intel/amd64/libpython/Makefile
index f454b29658..d78b5e0fc2 100644
--- a/usr/src/cmd/mdb/intel/amd64/libpython/Makefile
+++ b/usr/src/cmd/mdb/intel/amd64/libpython/Makefile
@@ -42,7 +42,6 @@ include ../../../Makefile.module
%.ln := CPPFLAGS += $(PYLNFLAGS)
LINTFLAGS += -erroff=E_MACRO_REDEFINED
-
dmod/$(MODULE) := LDLIBS += -lproc
%.o: $(MODSRCS_DIR)/%.c
diff --git a/usr/src/cmd/mdb/intel/amd64/libumem/Makefile b/usr/src/cmd/mdb/intel/amd64/libumem/Makefile
index c13578207d..5a9b46141d 100644
--- a/usr/src/cmd/mdb/intel/amd64/libumem/Makefile
+++ b/usr/src/cmd/mdb/intel/amd64/libumem/Makefile
@@ -22,6 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2012 Joyent, Inc. All rights reserved.
MODULE = libumem.so
MDBTGT = proc
diff --git a/usr/src/cmd/mdb/intel/amd64/xhci/Makefile b/usr/src/cmd/mdb/intel/amd64/xhci/Makefile
new file mode 100644
index 0000000000..0de7a701a7
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/xhci/Makefile
@@ -0,0 +1,27 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+
+MODULE = xhci.so
+MDBTGT = kvm
+
+MODSRCS = xhci.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
diff --git a/usr/src/cmd/mdb/intel/ia32/libumem/Makefile b/usr/src/cmd/mdb/intel/ia32/libumem/Makefile
index 51f0985cf2..ca4d07a66a 100644
--- a/usr/src/cmd/mdb/intel/ia32/libumem/Makefile
+++ b/usr/src/cmd/mdb/intel/ia32/libumem/Makefile
@@ -22,6 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2012 Joyent, Inc. All rights reserved.
MODULE = libumem.so
MDBTGT = proc
diff --git a/usr/src/cmd/mdb/intel/ia32/xhci/Makefile b/usr/src/cmd/mdb/intel/ia32/xhci/Makefile
new file mode 100644
index 0000000000..6fb72a3b2d
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/xhci/Makefile
@@ -0,0 +1,25 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+MODULE = xhci.so
+MDBTGT = kvm
+
+MODSRCS = xhci.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
diff --git a/usr/src/cmd/mdb/sparc/v7/libumem/Makefile b/usr/src/cmd/mdb/sparc/v7/libumem/Makefile
index c9ca51f625..7475d38815 100644
--- a/usr/src/cmd/mdb/sparc/v7/libumem/Makefile
+++ b/usr/src/cmd/mdb/sparc/v7/libumem/Makefile
@@ -22,6 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2012 Joyent, Inc. All rights reserved.
MODULE = libumem.so
MDBTGT = proc
diff --git a/usr/src/cmd/mdb/sparc/v9/libumem/Makefile b/usr/src/cmd/mdb/sparc/v9/libumem/Makefile
index dbb51cd96f..cada3a7d9c 100644
--- a/usr/src/cmd/mdb/sparc/v9/libumem/Makefile
+++ b/usr/src/cmd/mdb/sparc/v9/libumem/Makefile
@@ -22,6 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2012 Joyent, Inc. All rights reserved.
MODULE = libumem.so
MDBTGT = proc
diff --git a/usr/src/cmd/netfiles/Makefile b/usr/src/cmd/netfiles/Makefile
index 0ae84c2276..aa6886311d 100644
--- a/usr/src/cmd/netfiles/Makefile
+++ b/usr/src/cmd/netfiles/Makefile
@@ -21,6 +21,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
TXTS= nsswitch.conf netconfig hosts services
DEFAULTFILES= nss.dfl
@@ -29,7 +31,7 @@ include ../Makefile.cmd
FILES= hosts services
ETCFILES= netconfig nsswitch.conf nsswitch.files nsswitch.nis \
- nsswitch.dns nsswitch.ldap nsswitch.ad
+ nsswitch.dns nsswitch.ldap nsswitch.ad resolv.conf
ROOTNET= $(ROOTETC)/net
TICLTS= $(ROOTNET)/ticlts
diff --git a/usr/src/cmd/netfiles/nsswitch.conf b/usr/src/cmd/netfiles/nsswitch.conf
index 58ec600c9a..166e5e0ca3 100644
--- a/usr/src/cmd/netfiles/nsswitch.conf
+++ b/usr/src/cmd/netfiles/nsswitch.conf
@@ -29,8 +29,8 @@
passwd: files
group: files
-hosts: files
-ipnodes: files
+hosts: files dns mdns
+ipnodes: files dns mdns
networks: files
protocols: files
rpc: files
diff --git a/usr/src/cmd/netfiles/resolv.conf b/usr/src/cmd/netfiles/resolv.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/usr/src/cmd/netfiles/resolv.conf
diff --git a/usr/src/cmd/nicstat/Makefile b/usr/src/cmd/nicstat/Makefile
new file mode 100644
index 0000000000..935011119a
--- /dev/null
+++ b/usr/src/cmd/nicstat/Makefile
@@ -0,0 +1,31 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2013 Joyent, Inc. All rights reserved.
+#
+
+PROG = nicstat
+
+include ../Makefile.cmd
+
+all: $(PROG)
+
+install: all .WAIT $(ROOTPROG)
+
+clean:
+
+$(ROOTBINPROG): $(PROG)
+ $(INS.file)
+
+lint:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/nicstat/nicstat.pl b/usr/src/cmd/nicstat/nicstat.pl
new file mode 100644
index 0000000000..fae4c797df
--- /dev/null
+++ b/usr/src/cmd/nicstat/nicstat.pl
@@ -0,0 +1,424 @@
+#!/usr/perl5/bin/perl -w
+#
+# nicstat - print network traffic, Kbyte/s read and written.
+# Solaris 8+, Perl (Sun::Solaris::Kstat).
+#
+# "netstat -i" only gives a packet count, this program gives Kbytes.
+#
+# 04-Apr-2011, ver 1.00J
+#
+# USAGE: nicstat [-hsz] [-i int[,int...]] | [interval [count]]
+#
+# -h # help
+# -s # print summary output
+# -z # skip zero lines
+# -i int[,int...] # print these instances only
+# eg,
+# nicstat # print summary since boot
+# nicstat 1 # print continually, every 1 second
+# nicstat 1 5 # print 5 times, every 1 second
+# nicstat -i hme0 # only examine hme0
+#
+# This prints out the KB/s transferred for all the network cards (NICs),
+# including packet counts and average sizes. The first line is the summary
+# data since boot.
+#
+# FIELDS:
+# Int Interface
+# rKB/s read Kbytes/s
+# wKB/s write Kbytes/s
+# rPk/s read Packets/s
+# wPk/s write Packets/s
+# rAvs read Average size, bytes
+# wAvs write Average size, bytes
+# %Util %Utilisation (r or w/ifspeed)
+# Sat Saturation (defer, nocanput, norecvbuf, noxmtbuf)
+#
+# NOTES:
+#
+# - Some unusual network cards may not provide all the details to Kstat,
+# (or provide different symbols). Check for newer versions of this program,
+# and the @Network array in the code below.
+# - Utilisation is based on bytes transferred divided by speed of the interface
+# (if the speed is known). It should be impossible to reach 100% as there
+# are overheads due to bus negotiation and timing.
+# - Loopback interfaces may only provide packet counts (if anything), and so
+# bytes and %util will always be zero. Newer versions of Solaris (newer than
+# Solaris 10 6/06) may provide loopback byte stats.
+# - Saturation is determined by counting read and write errors caused by the
+# interface running at saturation. This approach is not ideal, and the value
+# reported is often lower than it should be (eg, 0.0). Reading the rKB/s and
+# wKB/s fields may be more useful.
+#
+# SEE ALSO:
+# nicstat.c # the C version, also on my website
+# kstat -n hme0 [interval [count]] # or qfe0, ...
+# netstat -iI hme0 [interval [count]]
+# se netstat.se [interval] # SE Toolkit
+# se nx.se [interval] # SE Toolkit
+#
+# COPYRIGHT: Copyright (c) 2013 Brendan Gregg.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at docs/cddl1.txt or
+# http://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at docs/cddl1.txt.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2015 Joyent, Inc. All rights reserved.
+#
+# Author: Brendan Gregg [Sydney, Australia]
+#
+# 18-Jul-2004 Brendan Gregg Created this.
+# 07-Jan-2005 " " added saturation value.
+# 07-Jan-2005 " " added summary style (from Peter Tribble).
+# 23-Jan-2006 " " Tweaked style.
+# 11-Aug-2006 " " Improved output neatness.
+# 30-Sep-2006 " " Added loopback, tweaked output.
+# 04-Apr-2011 brendan@joyent.com Updated for smartmachines.
+
+use strict;
+use Getopt::Std;
+use Sun::Solaris::Kstat;
+my $Kstat = Sun::Solaris::Kstat->new();
+
+
+#
+# Process command line args
+#
+usage() if defined $ARGV[0] and $ARGV[0] eq "--help";
+getopts('hi:sz') or usage();
+usage() if defined $main::opt_h;
+my $STYLE = defined $main::opt_s ? $main::opt_s : 0;
+my $SKIPZERO = defined $main::opt_z ? $main::opt_z : 0;
+
+# process [interval [count]],
+my ($interval, $loop_max);
+if (defined $ARGV[0]) {
+ $interval = $ARGV[0];
+ $loop_max = defined $ARGV[1] ? $ARGV[1] : 2**32;
+ usage() if $interval == 0;
+}
+else {
+ $interval = 1;
+ $loop_max = 1;
+}
+
+# check for -i,
+my %NetworkOnly; # network interfaces to print
+my $NETWORKONLY = 0; # match on network interfaces
+if (defined $main::opt_i) {
+ foreach my $net (split /,/, $main::opt_i) {
+ $NetworkOnly{$net} = 1;
+ }
+ $NETWORKONLY = 1;
+}
+
+# globals,
+my $loop = 0; # current loop number
+my $PAGESIZE = 20; # max lines per header
+my $line = $PAGESIZE; # counter for lines printed
+my %NetworkNames; # Kstat network interfaces
+my %NetworkData; # network interface data
+my %NetworkDataOld; # network interface data
+$main::opt_h = 0;
+$| = 1; # autoflush
+
+# kstat "link" module includes:
+my @Network = qw(dmfe bge be bnx ce eri eth external ge hme igb ige internal ixgbe le net ppp qfe rtls);
+my %Network;
+$Network{$_} = 1 foreach (@Network);
+my $ZONENAME = `/usr/bin/zonename`;
+chomp $ZONENAME;
+
+### Determine network interfaces
+unless (find_nets()) {
+ if ($NETWORKONLY) {
+ print STDERR "ERROR1: $main::opt_i matched no network interfaces.\n";
+ }
+ else {
+ print STDERR "ERROR1: No network interfaces found!\n";
+ }
+ exit 1;
+}
+
+
+#
+# Main
+#
+while (1) {
+
+ ### Print Header
+ if ($line >= $PAGESIZE) {
+ if ($STYLE == 0) {
+ printf "%8s %12s %7s %7s %7s %7s %7s %7s %6s %5s\n",
+ "Time", "Int", "rKB/s", "wKB/s", "rPk/s", "wPk/s", "rAvs",
+ "wAvs", "%Util", "Sat";
+ }
+ elsif ($STYLE == 1) {
+ printf "%8s %12s %14s %14s\n", "Time", "Int", "rKB/s", "wKB/s";
+ }
+
+ $line = 0;
+ }
+
+ ### Get new data
+ my (@NetworkData) = fetch_net_data();
+
+ foreach my $network_data (@NetworkData) {
+
+ ### Extract values
+ my ($int, $rbytes, $wbytes, $rpackets, $wpackets, $speed, $sat, $time)
+ = split /:/, $network_data;
+
+ ### Retrieve old values
+ my ($old_rbytes, $old_wbytes, $old_rpackets, $old_wpackets, $old_sat,
+ $old_time);
+ if (defined $NetworkDataOld{$int}) {
+ ($old_rbytes, $old_wbytes, $old_rpackets, $old_wpackets,
+ $old_sat, $old_time) = split /:/, $NetworkDataOld{$int};
+ }
+ else {
+ $old_rbytes = $old_wbytes = $old_rpackets = $old_wpackets
+ = $old_sat = $old_time = 0;
+ }
+
+ #
+ # Calculate statistics
+ #
+
+ # delta time
+ my $tdiff = $time - $old_time;
+
+ # per second values
+ my $rbps = ($rbytes - $old_rbytes) / $tdiff;
+ my $wbps = ($wbytes - $old_wbytes) / $tdiff;
+ my $rkps = $rbps / 1024;
+ my $wkps = $wbps / 1024;
+ my $rpps = ($rpackets - $old_rpackets) / $tdiff;
+ my $wpps = ($wpackets - $old_wpackets) / $tdiff;
+ my $ravs = $rpps > 0 ? $rbps / $rpps : 0;
+ my $wavs = $wpps > 0 ? $wbps / $wpps : 0;
+
+ # skip zero lines if asked
+ next if $SKIPZERO and ($rbps + $wbps) == 0;
+
+ # % utilisation
+ my $util;
+ if ($speed > 0) {
+ # the following has a mysterious "800", it is 100
+ # for the % conversion, and 8 for bytes2bits.
+ my $rutil = $rbps * 800 / $speed;
+ my $wutil = $wbps * 800 / $speed;
+ $util = $rutil > $wutil ? $rutil : $wutil;
+ $util = 100 if $util > 100;
+ }
+ else {
+ $util = 0;
+ }
+
+ # saturation per sec
+ my $sats = ($sat - $old_sat) / $tdiff;
+
+ #
+ # Print statistics
+ #
+ if ($rbps ne "") {
+ my @Time = localtime();
+
+ if ($STYLE == 0) {
+ printf "%02d:%02d:%02d %12s ",
+ $Time[2], $Time[1], $Time[0], $int;
+ print_neat($rkps);
+ print_neat($wkps);
+ print_neat($rpps);
+ print_neat($wpps);
+ print_neat($ravs);
+ print_neat($wavs);
+ printf "%6.2f %5.2f\n", $util, $sats;
+ }
+ elsif ($STYLE == 1) {
+ printf "%02d:%02d:%02d %12s %14.3f %14.3f\n",
+ $Time[2], $Time[1], $Time[0], $int, $rkps, $wkps;
+ }
+
+ $line++;
+
+ # for multiple interfaces, always print the header
+ $line += $PAGESIZE if @NetworkData > 1;
+ }
+
+ ### Store old values
+ $NetworkDataOld{$int}
+ = "$rbytes:$wbytes:$rpackets:$wpackets:$sat:$time";
+ }
+
+ ### Check for end
+ last if ++$loop == $loop_max;
+
+ ### Interval
+ sleep $interval;
+}
+
+
+# find_nets - walk Kstat to discover network interfaces.
+#
+# This walks %Kstat and populates a %NetworkNames with discovered
+# network interfaces.
+#
+sub find_nets {
+ my $found = 0;
+
+ ### Loop over all Kstat modules
+ foreach my $module (keys %$Kstat) {
+ my $Modules = $Kstat->{$module};
+
+ foreach my $instance (keys %$Modules) {
+ my $Instances = $Modules->{$instance};
+
+ foreach my $name (keys %$Instances) {
+
+ ### Skip interface if asked
+ if ($NETWORKONLY) {
+ next unless $NetworkOnly{$name};
+ }
+
+ my $Names = $Instances->{$name};
+
+ # Check this is a network device.
+ # Matching on ifspeed has been more reliable than "class"
+ # we also match loopback and "link" interfaces.
+ if (defined $$Names{ifspeed} || $module eq "lo"
+ || $module eq "link") {
+ next if $name eq "mac";
+ if ($module eq "link") {
+ my $nname = $name;
+ $nname =~ s/\d+$//;
+ next unless defined $Network{$nname}
+ or $ZONENAME eq $nname
+ or $ZONENAME eq "global";
+ }
+ ### Save network interface
+ $NetworkNames{$name} = $Names;
+ $found++;
+ }
+ }
+ }
+ }
+
+ return $found;
+}
+
+# fetch - fetch Kstat data for the network interfaces.
+#
+# This uses the interfaces in %NetworkNames and returns useful Kstat data.
+# The Kstat values used are rbytes64, obytes64, ipackets64, opackets64
+# (or the 32 bit versions if the 64 bit values are not there).
+#
+sub fetch_net_data {
+ my ($rbytes, $wbytes, $rpackets, $wpackets, $speed, $time);
+ my @NetworkData = ();
+
+ $Kstat->update();
+
+ ### Loop over previously found network interfaces
+ foreach my $name (sort keys %NetworkNames) {
+ my $Names = $NetworkNames{$name};
+
+ if (defined $$Names{opackets}) {
+
+ ### Fetch write bytes
+ if (defined $$Names{obytes64}) {
+ $rbytes = $$Names{rbytes64};
+ $wbytes = $$Names{obytes64};
+ }
+ elsif (defined $$Names{obytes}) {
+ $rbytes = $$Names{rbytes};
+ $wbytes = $$Names{obytes};
+ } else {
+ $rbytes = $wbytes = 0;
+ }
+
+ ### Fetch read bytes
+ if (defined $$Names{opackets64}) {
+ $rpackets = $$Names{ipackets64};
+ $wpackets = $$Names{opackets64};
+ }
+ else {
+ $rpackets = $$Names{ipackets};
+ $wpackets = $$Names{opackets};
+ }
+
+ ### Fetch interface speed
+ if (defined $$Names{ifspeed}) {
+ $speed = $$Names{ifspeed};
+ }
+ else {
+ # if we can't fetch the speed, print the
+ # %Util as 0.0 . To do this we,
+ $speed = 2 ** 48;
+ }
+
+ ### Determine saturation value
+ my $sat = 0;
+ if (defined $$Names{nocanput} or defined $$Names{norcvbuf}) {
+ $sat += defined $$Names{defer} ? $$Names{defer} : 0;
+ $sat += defined $$Names{nocanput} ? $$Names{nocanput} : 0;
+ $sat += defined $$Names{norcvbuf} ? $$Names{norcvbuf} : 0;
+ $sat += defined $$Names{noxmtbuf} ? $$Names{noxmtbuf} : 0;
+ }
+
+ ### use the last snaptime value,
+ $time = $$Names{snaptime};
+
+ ### store data
+ push @NetworkData, "$name:$rbytes:$wbytes:" .
+ "$rpackets:$wpackets:$speed:$sat:$time";
+ }
+ }
+
+ return @NetworkData;
+}
+
+# print_neat - print a float with decimal places if appropriate.
+#
+# This specifically keeps the width to 7 characters, if possible, plus
+# a trailing space.
+#
+sub print_neat {
+ my $num = shift;
+ if ($num >= 100000) {
+ printf "%7d ", $num;
+ } elsif ($num >= 100) {
+ printf "%7.1f ", $num;
+ } else {
+ printf "%7.2f ", $num;
+ }
+}
+
+# usage - print usage and exit.
+#
+sub usage {
+ print STDERR <<END;
+USAGE: nicstat [-hsz] [-i int[,int...]] | [interval [count]]
+ eg, nicstat # print summary since boot
+ nicstat 1 # print continually every 1 second
+ nicstat 1 5 # print 5 times, every 1 second
+ nicstat -s # summary output
+ nicstat -i hme0 # print hme0 only
+END
+ exit 1;
+}
diff --git a/usr/src/cmd/nsadmin/Makefile b/usr/src/cmd/nsadmin/Makefile
index 533351bd86..45bdcc6701 100644
--- a/usr/src/cmd/nsadmin/Makefile
+++ b/usr/src/cmd/nsadmin/Makefile
@@ -25,64 +25,85 @@
# Copyright 2019 Joyent, Inc.
#
-PROG= profile .login ksh.kshrc system
-PROGSKEL= .profile .kshrc
-PROGROOT= .profile .bashrc
+ETCFILES = profile .login ksh.kshrc system zshrc
+ETCSKELFILES = .profile .kshrc .bashrc
+ETCBASHFILES = bash_completion
+ETCBASHCOMPLETIONDFILES = dladm zones zone_alias
+ROOTFILES = .profile .bashrc .bash_profile
include ../Makefile.cmd
-ROOTROOT= $(ROOT)/root
+ROOTETCFILES = $(ETCFILES:%=$(ROOTETC)/%)
ROOTETCSKEL= $(ROOTETC)/skel
-ROOTETCSKELPROG= $(PROGSKEL:%=$(ROOTETCSKEL)/%)
+ROOTETCSKELFILES = $(ETCSKELFILES:%=$(ROOTETCSKEL)/%)
ROOTETCVERSIONS= $(ROOTETC)/versions
-ROOTETCVERSIONSPROG= $(ROOTETCVERSIONS)/build
-ROOTROOTPROG= $(PROGROOT:%=$(ROOTROOT)/%)
+ROOTETCVERSIONSFILES = $(ROOTETCVERSIONS)/build
+ETCBASHDIR = $(ROOTETC)/bash
+ROOTETCBASHFILES = $(ETCBASHFILES:%=$(ETCBASHDIR)/%)
+ETCBASHCOMPLETIONDDIR = $(ETCBASHDIR)/bash_completion.d
+ROOTETCBASHCOMPLETIONDFILES = \
+ $(ETCBASHCOMPLETIONDFILES:%=$(ETCBASHCOMPLETIONDDIR)/%)
+ROOTROOT= $(ROOT)/root
+ROOTROOTFILES = $(ROOTFILES:%=$(ROOTROOT)/%)
+
+FILES = $(ROOTETCFILES) $(ROOTETCSKELFILES) \
+ $(ROOTETCBASHFILES) $(ROOTETCBASHCOMPLETIONDFILES) \
+ $(ROOTROOTFILES) $(ROOTETCVERSIONSFILES)
+
FILEMODE= 0644
-CLOBBERFILES = profile .bashrc .profile .login .kshrc
+.KEEP_STATE:
+
+all:
+
+# Use $^ instead of $< - it's broken without %
+INS.file = $(RM) $@; $(INS) -s -m $(FILEMODE) -f $(@D) $^
+INS.rename = $(INS.file); $(MV) $(@D)/$(^F) $@
+
+$(ROOTROOT) \
+$(ROOTETCVERSIONS) \
+$(ETCBASHDIR) \
+$(ROOTETCBASHCOMPLETIONDDIR) \
+$(ROOTETCSKEL):
+ $(INS.dir)
-.login: login.csh
- $(RM) .login
- $(CP) login.csh .login
+$(ROOTETC)/profile: etc-profile.sh
+ $(INS.rename)
-profile: etc-profile.sh
- $(RM) profile
- $(CP) etc-profile.sh $@
+$(ROOTETC)/.login: login.csh
+ $(INS.rename)
-.profile: dot-profile.sh
- $(RM) .profile
- $(CP) dot-profile.sh $@
+# skel file and root's default
+$(ROOTROOT)/.kshrc $(ROOTETCSKEL)/.kshrc: dot-kshrc.sh
+ $(INS.rename)
-.kshrc: dot-kshrc.sh
- $(RM) .kshrc
- $(CP) dot-kshrc.sh $@
+# skel file and root's default
+$(ROOTROOT)/.profile $(ROOTETCSKEL)/.profile: dot-profile.sh
+ $(INS.rename)
-.bashrc: bashrc.sh
- $(RM) .bashrc
- $(CP) bashrc.sh $@
+$(ROOTETCSKEL)/.bashrc: etc-skel-bashrc.sh
+ $(INS.rename)
-.KEEP_STATE:
+$(ROOTROOT)/.bash_profile: dot-bash_profile.sh
+ $(INS.rename)
-all: $(PROG) $(PROGSKEL)
+$(ROOTROOT)/.bashrc: dot-bashrc.sh
+ $(INS.rename)
-$(ROOTROOT)/% \
-$(ROOTETCSKEL)/%: %
+$(ROOTETCBASHDIR)/%: %
$(INS.file)
-$(ROOTROOT) \
-$(ROOTETCVERSIONS) \
-$(ROOTETCSKEL):
- $(INS.dir)
+$(ROOTETCBASHCOMPLETIONDDIR)/%: %
+ $(INS.file)
-$(ROOTETCVERSIONSPROG): $(ROOTETCVERSIONS) FRC
+$(ROOTETCVERSIONSFILES): $(ROOTETCVERSIONS) FRC
if [[ -n "$$BUILDVERSION_EXEC" ]]; then \
- $$BUILDVERSION_EXEC >$(ROOTETCVERSIONSPROG) ; \
+ $$BUILDVERSION_EXEC >$(ROOTETCVERSIONSFILES) ; \
else \
- touch $(ROOTETCVERSIONSPROG) ; \
+ touch $(ROOTETCVERSIONSFILES) ; \
fi
-install: all $(ROOTETCSKEL) $(ROOTETCPROG) \
- $(ROOTETCSKELPROG) $(ROOTROOTPROG) $(ROOTETCVERSIONSPROG)
+install: all $(FILES)
clean:
diff --git a/usr/src/cmd/nsadmin/bash/bash_completion b/usr/src/cmd/nsadmin/bash/bash_completion
new file mode 100755
index 0000000000..71f3e9e63f
--- /dev/null
+++ b/usr/src/cmd/nsadmin/bash/bash_completion
@@ -0,0 +1,9417 @@
+#
+# This file contains an example set of shell completions that can be used with
+# bash(1). These completions allow a user to complete filenames, commands
+# name, command line options, and command line arguments using the [tab] key.
+# The completions defined here are specific to the GNU command set, as a result
+# they will provide the choice of GNU command line options in response to the
+# [tab] key. For the completed options to match the command implementation,
+# you may have to have /usr/gnu/bin at the head of your PATH.
+#
+# These completions are not included in the default bash(1) environment. To
+# include them in the default environment, it is recommended that this file be
+# copied to /etc/bash/bash_completion and be sourced from either a system wide
+# bashrc in /etc/bash/bashrc or individual bashrcs in ~/.bashrc via
+# [ -f /etc/bash/bash_completion ] && . /etc/bash/bash_completion
+#
+
+# bash_completion - programmable completion functions for bash 3.x
+# (backwards compatible with bash 2.05b)
+#
+# $Id: bash_completion,v 1.872 2006/03/01 16:20:18 ianmacd Exp $
+#
+# Copyright (C) Ian Macdonald <ian@caliban.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The latest version of this software can be obtained here:
+#
+# http://www.caliban.org/bash/index.shtml#completion
+#
+# RELEASE: 20060301
+
+if [[ $- == *v* ]]; then
+ BASH_COMPLETION_ORIGINAL_V_VALUE="-v"
+else
+ BASH_COMPLETION_ORIGINAL_V_VALUE="+v"
+fi
+
+if [[ -n $BASH_COMPLETION_DEBUG ]]; then
+ set -v
+else
+ set +v
+fi
+
+# Alter the following to reflect the location of this file.
+#
+[ -n "$BASH_COMPLETION" ] || BASH_COMPLETION=/etc/bash/bash_completion
+[ -n "$BASH_COMPLETION_DIR" ] || BASH_COMPLETION_DIR=/etc/bash/bash_completion.d
+readonly BASH_COMPLETION BASH_COMPLETION_DIR
+
+# Set a couple of useful vars
+#
+UNAME=$( uname -s )
+# strip OS type and version under Cygwin (e.g. CYGWIN_NT-5.1 => Cygwin)
+UNAME=${UNAME/CYGWIN_*/Cygwin}
+RELEASE=$( uname -r )
+
+# features supported by bash 2.05 and higher
+if [ ${BASH_VERSINFO[0]} -eq 2 ] && [[ ${BASH_VERSINFO[1]} > 04 ]] ||
+ [ ${BASH_VERSINFO[0]} -gt 2 ]; then
+ declare -r bash205=$BASH_VERSION 2>/dev/null || :
+ default="-o default"
+ dirnames="-o dirnames"
+ filenames="-o filenames"
+fi
+# features supported by bash 2.05b and higher
+if [ ${BASH_VERSINFO[0]} -eq 2 ] && [[ ${BASH_VERSINFO[1]} = "05b" ]] ||
+ [ ${BASH_VERSINFO[0]} -gt 2 ]; then
+ declare -r bash205b=$BASH_VERSION 2>/dev/null || :
+ nospace="-o nospace"
+fi
+# features supported by bash 3.0 and higher
+if [ ${BASH_VERSINFO[0]} -gt 2 ]; then
+ declare -r bash3=$BASH_VERSION 2>/dev/null || :
+ bashdefault="-o bashdefault"
+ plusdirs="-o plusdirs"
+fi
+
+# Turn on extended globbing and programmable completion
+shopt -s extglob progcomp
+
+# A lot of the following one-liners were taken directly from the
+# completion examples provided with the bash 2.04 source distribution
+
+# Make directory commands see only directories
+complete -d pushd
+
+# The following section lists completions that are redefined later
+# Do NOT break these over multiple lines.
+#
+# START exclude -- do NOT remove this line
+complete -f -X '!*.?(t)bz?(2)' bunzip2 bzcat bzcmp bzdiff bzegrep bzfgrep bzgrep
+complete -f -X '!*.@(zip|ZIP|jar|JAR|exe|EXE|pk3|war|wsz|ear|zargo|xpi|sxw|ott)' unzip zipinfo
+complete -f -X '*.Z' compress znew
+complete -f -X '!*.@(Z|gz|tgz|Gz|dz)' gunzip zcmp zdiff zcat zegrep zfgrep zgrep zless zmore
+complete -f -X '!*.Z' uncompress
+complete -f -X '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX)' ee display
+complete -f -X '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|GIF|JPG|JP?(E)G|TIF?(F)|PNG|P[BGP]M|BMP|X[BP]M|RLE|RGB|PCX|FITS|PM)' xv qiv
+complete -f -X '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview
+complete -f -X '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi
+complete -f -X '!*.@(dvi|DVI)?(.@(gz|bz2))' kdvi
+complete -f -X '!*.@(dvi|DVI)' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx
+complete -f -X '!*.@(pdf|PDF)' acroread gpdf xpdf
+complete -f -X '!*.@(?(e)ps|?(E)PS|pdf|PDF)' kpdf
+complete -f -X '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ)|cb(r|z)|CB(R|Z)|djv?(u)|DJV?(U)||dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX)' evince
+complete -f -X '!*.@(?(e)ps|?(E)PS)' ps2pdf
+complete -f -X '!*.texi*' makeinfo texi2html
+complete -f -X '!*.@(?(la)tex|?(LA)TEX|texi|TEXI|dtx|DTX|ins|INS)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi
+complete -f -X '!*.@(mp3|MP3)' mpg123 mpg321 madplay
+complete -f -X '!*.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp3|MP3|m4v|M4V|ogg|OGG|ogm|OGM|mp4|MP4|wav|WAV|asx|ASX|mng|MNG|srt)' xine aaxine fbxine kaffeine
+complete -f -X '!*.@(avi|asf|wmv)' aviplay
+complete -f -X '!*.@(rm?(j)|ra?(m)|smi?(l))' realplay
+complete -f -X '!*.@(mpg|mpeg|avi|mov|qt)' xanim
+complete -f -X '!*.@(ogg|OGG|m3u|flac|spx)' ogg123
+complete -f -X '!*.@(mp3|MP3|ogg|OGG|pls|m3u)' gqmpeg freeamp
+complete -f -X '!*.fig' xfig
+complete -f -X '!*.@(mid?(i)|MID?(I))' playmidi
+complete -f -X '!*.@(mid?(i)|MID?(I)|rmi|RMI|rcp|RCP|[gr]36|[GR]36|g18|G18|mod|MOD|xm|XM|it|IT|x3m|X3M)' timidity
+complete -f -X '*.@(o|so|so.!(conf)|a|rpm|gif|GIF|jp?(e)g|JP?(E)G|mp3|MP3|mp?(e)g|MPG|avi|AVI|asf|ASF|ogg|OGG|class|CLASS)' vi vim gvim rvim view rview rgvim rgview gview
+complete -f -X '*.@(o|so|so.!(conf)|a|rpm|gif|GIF|jp?(e)g|JP?(E)G|mp3|MP3|mp?(e)g|MPG|avi|AVI|asf|ASF|ogg|OGG|class|CLASS)' emacs
+complete -f -X '!*.@(exe|EXE|com|COM|scr|SCR|exe.so)' wine
+complete -f -X '!*.@(zip|ZIP|z|Z|gz|GZ|tgz|TGZ)' bzme
+complete -f -X '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx opera galeon curl dillo elinks amaya
+complete -f -X '!*.@(sxw|stw|sxg|sgl|doc|dot|rtf|txt|htm|html|odt|ott|odm)' oowriter
+complete -f -X '!*.@(sxi|sti|pps|ppt|pot|odp|otp)' ooimpress
+complete -f -X '!*.@(sxc|stc|xls|xlw|xlt|csv|ods|ots)' oocalc
+complete -f -X '!*.@(sxd|std|sda|sdd|odg|otg)' oodraw
+complete -f -X '!*.@(sxm|smf|mml|odf)' oomath
+complete -f -X '!*.odb' oobase
+complete -f -X '!*.rpm' rpm2cpio
+# FINISH exclude -- do not remove this line
+
+# start of section containing compspecs that can be handled within bash
+
+# user commands see only users
+complete -u su usermod userdel passwd chage write chfn groups slay w sux
+
+# group commands see only groups
+[ -n "$bash205" ] && complete -g groupmod groupdel newgrp 2>/dev/null
+
+# bg completes with stopped jobs
+complete -A stopped -P '%' bg
+
+# other job commands
+complete -j -P '%' fg jobs disown
+
+# readonly and unset complete with shell variables
+complete -v readonly unset
+
+# set completes with set options
+complete -A setopt set
+
+# shopt completes with shopt options
+complete -A shopt shopt
+
+# helptopics
+complete -A helptopic help
+
+# unalias completes with aliases
+complete -a unalias
+
+# bind completes with readline bindings (make this more intelligent)
+complete -A binding bind
+
+# type and which complete on commands
+complete -c command type which
+
+# builtin completes on builtins
+complete -b builtin
+
+# start of section containing completion functions called by other functions
+
+# This function checks whether we have a given program on the system.
+# No need for bulky functions in memory if we don't.
+#
+have()
+{
+ unset -v have
+ PATH=/usr/gnu/bin:$PATH:/sbin:/usr/sbin type $1 &>/dev/null &&
+ have="yes"
+}
+
+# use GNU sed if we have it, since its extensions are still used in our code
+#
+[ $UNAME != Linux ] && have gsed && alias sed=gsed
+
+# This function checks whether a given readline variable
+# is `on'.
+#
+_rl_enabled()
+{
+ [[ "$( bind -v )" = *$1+([[:space:]])on* ]]
+}
+
+# This function shell-quotes the argument
+quote()
+{
+ echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
+}
+
+# This function quotes the argument in a way so that readline dequoting
+# results in the original argument
+quote_readline()
+{
+ local t="${1//\\/\\\\}"
+ echo \'${t//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
+}
+
+# This function shell-dequotes the argument
+dequote()
+{
+ eval echo "$1"
+}
+
+
+# Get the word to complete
+# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases
+# where the user is completing in the middle of a word.
+# (For example, if the line is "ls foobar",
+# and the cursor is here --------> ^
+# it will complete just "foo", not "foobar", which is what the user wants.)
+_get_cword()
+{
+ if [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then
+ echo "${COMP_WORDS[COMP_CWORD]}"
+ else
+ local i
+ local cur="$COMP_LINE"
+ local index="$COMP_POINT"
+ for (( i = 0; i <= COMP_CWORD; ++i )); do
+ while [[ "${#cur}" -ge ${#COMP_WORDS[i]} ]] && [[ "${cur:0:${#COMP_WORDS[i]}}" != "${COMP_WORDS[i]}" ]]; do
+ cur="${cur:1}"
+ index="$(( index - 1 ))"
+ done
+ if [[ "$i" -lt "$COMP_CWORD" ]]; then
+ local old_size="${#cur}"
+ cur="${cur#${COMP_WORDS[i]}}"
+ local new_size="${#cur}"
+ index="$(( index - old_size + new_size ))"
+ fi
+ done
+
+ if [[ "${COMP_WORDS[COMP_CWORD]:0:${#cur}}" != "$cur" ]]; then
+ # We messed up! At least return the whole word so things keep working
+ echo "${COMP_WORDS[COMP_CWORD]}"
+ else
+ echo "${cur:0:$index}"
+ fi
+ fi
+}
+
+
+# This function performs file and directory completion. It's better than
+# simply using 'compgen -f', because it honours spaces in filenames.
+# If passed -d, it completes only on directories. If passed anything else,
+# it's assumed to be a file glob to complete on.
+#
+_filedir()
+{
+ local IFS=$'\t\n' xspec
+
+ _expand || return 0
+
+ local toks=( ) tmp
+ while read -r tmp; do
+ [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp
+ done < <( compgen -d -- "$(quote_readline "$cur")" )
+
+ if [[ "$1" != -d ]]; then
+ xspec=${1:+"!*.$1"}
+ while read -r tmp; do
+ [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp
+ done < <( compgen -f -X "$xspec" -- "$(quote_readline "$cur")" )
+ fi
+
+ COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" )
+}
+
+# This function completes on signal names
+#
+_signals()
+{
+ local i
+
+ # standard signal completion is rather braindead, so we need
+ # to hack around to get what we want here, which is to
+ # complete on a dash, followed by the signal name minus
+ # the SIG prefix
+ COMPREPLY=( $( compgen -A signal SIG${cur#-} ))
+ for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
+ COMPREPLY[i]=-${COMPREPLY[i]#SIG}
+ done
+}
+
+# This function completes on configured network interfaces
+#
+_configured_interfaces()
+{
+ if [ -f /etc/debian_version ]; then
+ # Debian system
+ COMPREPLY=( $( sed -ne 's|^iface \([^ ]\+\).*$|\1|p' \
+ /etc/network/interfaces ) )
+ elif [ -f /etc/SuSE-release ]; then
+ # SuSE system
+ COMPREPLY=( $( command ls \
+ /etc/sysconfig/network/ifcfg-* | \
+ sed -ne 's|.*ifcfg-\('$cur'.*\)|\1|p' ) )
+ elif [ -f /etc/pld-release ]; then
+ # PLD Linux
+ COMPREPLY=( $( command ls -B \
+ /etc/sysconfig/interfaces | \
+ sed -ne 's|.*ifcfg-\('$cur'.*\)|\1|p' ) )
+ else
+ # Assume Red Hat
+ COMPREPLY=( $( command ls \
+ /etc/sysconfig/network-scripts/ifcfg-* | \
+ sed -ne 's|.*ifcfg-\('$cur'.*\)|\1|p' ) )
+ fi
+}
+
+# This function completes on all available network interfaces
+# -a: restrict to active interfaces only
+# -w: restrict to wireless interfaces only
+#
+_available_interfaces()
+{
+ local cmd
+
+ if [ "${1:-}" = -w ]; then
+ cmd="iwconfig"
+ elif [ "${1:-}" = -a ]; then
+ cmd="ifconfig"
+ else
+ cmd="ifconfig -a"
+ fi
+
+ COMPREPLY=( $( eval $cmd 2>/dev/null | \
+ sed -ne 's|^\('$cur'[^[:space:][:punct:]]\{1,\}\).*$|\1|p') )
+}
+
+# This function expands tildes in pathnames
+#
+_expand()
+{
+ # FIXME: Why was this here?
+ # [ "$cur" != "${cur%\\}" ] && cur="$cur\\"
+
+ # expand ~username type directory specifications
+ if [[ "$cur" == \~*/* ]]; then
+ eval cur=$cur
+ elif [[ "$cur" == \~* ]]; then
+ cur=${cur#\~}
+ COMPREPLY=( $( compgen -P '~' -u $cur ) )
+ return ${#COMPREPLY[@]}
+ fi
+}
+
+# This function completes on process IDs.
+# AIX and Solaris ps prefers X/Open syntax.
+[ $UNAME = SunOS -o $UNAME = AIX ] &&
+_pids()
+{
+ COMPREPLY=( $( compgen -W '$( command ps -efo pid | sed 1d )' -- $cur ))
+} ||
+_pids()
+{
+ COMPREPLY=( $( compgen -W '$( command ps axo pid | sed 1d )' -- $cur ) )
+}
+
+# This function completes on process group IDs.
+# AIX and SunOS prefer X/Open, all else should be BSD.
+[ $UNAME = SunOS -o $UNAME = AIX ] &&
+_pgids()
+{
+ COMPREPLY=( $( compgen -W '$( command ps -efo pgid | sed 1d )' -- $cur ))
+} ||
+_pgids()
+{
+ COMPREPLY=( $( compgen -W '$( command ps axo pgid | sed 1d )' -- $cur ))
+}
+
+# This function completes on user IDs
+#
+_uids()
+{
+ if type getent &>/dev/null; then
+ COMPREPLY=( $( getent passwd | \
+ awk -F: '{if ($3 ~ /^'$cur'/) print $3}' ) )
+ elif type perl &>/dev/null; then
+ COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"' )' -- $cur ) )
+ else
+ # make do with /etc/passwd
+ COMPREPLY=( $( awk 'BEGIN {FS=":"} {if ($3 ~ /^'$cur'/) print $3}'\
+ /etc/passwd ) )
+ fi
+}
+
+# This function completes on group IDs
+#
+_gids()
+{
+ if type getent &>/dev/null; then
+ COMPREPLY=( $( getent group | \
+ awk -F: '{if ($3 ~ /^'$cur'/) print $3}' ) )
+ elif type perl &>/dev/null; then
+ COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($gid) = (getgrent)[2]) { print $gid . "\n" }'"'"' )' -- $cur ) )
+ else
+ # make do with /etc/group
+ COMPREPLY=( $( awk 'BEGIN {FS=":"} {if ($3 ~ /^'$cur'/) print $3}'\
+ /etc/group ) )
+ fi
+}
+
+# This function completes on services
+#
+_services()
+{
+ local sysvdir famdir
+ [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d || sysvdir=/etc/init.d
+ famdir=/etc/xinetd.d
+ COMPREPLY=( $( builtin echo $sysvdir/!(*.rpmsave|*.rpmorig|*~|functions)) )
+
+ if [ -d $famdir ]; then
+ COMPREPLY=( "${COMPREPLY[@]}" $( builtin echo $famdir/!(*.rpmsave|*.rpmorig|*~)) )
+ fi
+
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]#@($sysvdir|$famdir)/}' -- $cur ) )
+}
+
+# This function complete on modules
+#
+_modules()
+{
+ local modpath
+ modpath=/lib/modules/$1
+ COMPREPLY=( $( command ls -R $modpath | \
+ sed -ne 's/^\('$cur'.*\)\.k\?o\(\|.gz\)$/\1/p') )
+}
+
+# this function complete on user:group format
+#
+_usergroup()
+{
+ local IFS=$'\n'
+ cur=${cur//\\\\ / }
+ if [[ $cur = *@(\\:|.)* ]] && [ -n "$bash205" ]; then
+ user=${cur%%*([^:.])}
+ COMPREPLY=( $(compgen -P ${user/\\\\} -g -- ${cur##*[.:]}) )
+ elif [[ $cur = *:* ]] && [ -n "$bash205" ]; then
+ COMPREPLY=( $( compgen -g -- ${cur##*[.:]} ) )
+ else
+ COMPREPLY=( $( compgen -S : -u -- $cur ) )
+ fi
+}
+
+# this function count the number of mandatory args
+#
+_count_args()
+{
+ args=1
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" != -* ]]; then
+ args=$(($args+1))
+ fi
+ done
+}
+
+# start of section containing completion functions for bash built-ins
+
+# bash alias completion
+#
+_alias()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=${COMP_WORDS[$COMP_CWORD]}
+
+ case "$COMP_LINE" in
+ *[^=])
+ COMPREPLY=( $( compgen -A alias -S '=' -- $cur ) )
+ ;;
+ *=)
+ COMPREPLY=( "$( alias ${cur%=} 2>/dev/null | \
+ sed -e 's|^alias '$cur'\(.*\)$|\1|' )" )
+ ;;
+ esac
+}
+complete -F _alias $nospace alias
+
+# bash export completion
+#
+_export()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=${COMP_WORDS[$COMP_CWORD]}
+
+ case "$COMP_LINE" in
+ *=\$*)
+ COMPREPLY=( $( compgen -v -P '$' -- ${cur#*=\$} ) )
+ ;;
+ *[^=])
+ COMPREPLY=( $( compgen -v -S '=' -- $cur ) )
+ ;;
+ *=)
+ COMPREPLY=( "$( eval echo -n \"$`echo ${cur%=}`\" |
+ ( echo -n \'
+ sed -e 's/'\''/'\''\\\'\'''\''/g'
+ echo -n \' ) )" )
+ ;;
+ esac
+}
+complete -F _export $default $nospace export
+
+# bash shell function completion
+#
+_function()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ $1 == @(declare|typeset) ]]; then
+ if [ "$prev" = -f ]; then
+ COMPREPLY=( $( compgen -A function -- $cur ) )
+ elif [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a -f -F -i -r -x -p' -- \
+ $cur ) )
+ fi
+ elif [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -A function -- $cur ) )
+ else
+ COMPREPLY=( "() $( type -- ${COMP_WORDS[1]} | sed -e 1,2d )" )
+ fi
+}
+complete -F _function function declare typeset
+
+# bash complete completion
+#
+_complete()
+{
+ local cur prev options
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ -o)
+ options="default dirnames filenames"
+ [ -n "$bash205b" ] && options="$options nospace"
+ [ -n "$bash3" ] && options="$options bashdefault plusdirs"
+ COMPREPLY=( $( compgen -W "$options" -- $cur ) )
+ return 0
+ ;;
+
+ -A)
+ COMPREPLY=( $( compgen -W 'alias arrayvar binding \
+ builtin command directory disabled enabled \
+ export file function group helptopic hostname \
+ job keyword running service setopt shopt \
+ signal stopped user variable' -- $cur ) )
+ return 0
+ ;;
+
+ -C)
+ COMPREPLY=( $( compgen -A command -- $cur ) )
+ return 0
+ ;;
+ -F)
+ COMPREPLY=( $( compgen -A function -- $cur ) )
+ return 0
+ ;;
+ -@(p|r))
+ COMPREPLY=( $( complete -p | sed -e 's|.* ||' | \
+ grep "^$cur" ) )
+ return 0
+ ;;
+
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # relevant options completion
+ options="-a -b -c -d -e -f -g -j -k -s -v -u -A -G -W -P -S -X -F -C"
+ [ -n "$bash205" ] && options="$options -o"
+ COMPREPLY=( $( compgen -W "$options" -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -A command -- $cur ) )
+ fi
+}
+complete -F _complete complete
+
+# start of section containing completion functions for external programs
+
+# a little help for FreeBSD ports users
+[ $UNAME = FreeBSD ] && complete -W 'index search fetch fetch-list \
+ extract patch configure build install reinstall \
+ deinstall clean clean-depends kernel buildworld' make
+
+# This completes on a list of all available service scripts for the
+# 'service' command and/or the SysV init.d directory, followed by
+# that script's available commands
+#
+{ have service || [ -d /etc/init.d/ ]; } &&
+_service()
+{
+ local cur sysvdir
+
+ COMPREPLY=()
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ cur=`_get_cword`
+
+ # don't complete for things like killall, ssh and mysql if it's
+ # the standalone command, rather than the init script
+ [[ ${COMP_WORDS[0]} != @(*init.d/!(functions|~)|service) ]] && return 0
+
+ # don't complete past 2nd token
+ [ $COMP_CWORD -gt 2 ] && return 0
+
+ [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \
+ || sysvdir=/etc/init.d
+
+ if [[ $COMP_CWORD -eq 1 ]] && [[ $prev == "service" ]]; then
+ _services
+ else
+ COMPREPLY=( $( compgen -W '`sed -ne "y/|/ /; \
+ s/^.*Usage.*{\(.*\)}.*$/\1/p" \
+ $sysvdir/${prev##*/} 2>/dev/null`' -- $cur ) )
+ fi
+
+ return 0
+} &&
+complete -F _service service
+[ -d /etc/init.d/ ] && complete -F _service $default \
+ $(for i in /etc/init.d/*; do echo ${i##*/}; done)
+
+# chown(1) completion
+#
+_chown()
+{
+ local cur
+ cur=`_get_cword`
+
+ # options completion
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c -h -f -R -v --changes \
+ --dereference --no-dereference --from= --silent --quiet \
+ --reference= --recursive --verbose --help --version' -- $cur ) )
+ else
+ _count_args
+
+ case $args in
+ 1)
+ _usergroup
+ ;;
+ *)
+ _filedir
+ ;;
+ esac
+ fi
+}
+complete -F _chown $filenames chown
+
+# chgrp(1) completion
+#
+_chgrp()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ cur=${cur//\\\\/}
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # options completion
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c -h -f -R -v --changes \
+ --dereference --no-dereference --silent --quiet \
+ --reference= --recursive --verbose --help --version' -- $cur ) )
+ return 0
+ fi
+
+ # first parameter on line or first since an option?
+ if [ $COMP_CWORD -eq 1 ] && [[ "$cur" != -* ]] || \
+ [[ "$prev" == -* ]] && [ -n "$bash205" ]; then
+ local IFS=$'\n'
+ COMPREPLY=( $( compgen -g $cur 2>/dev/null ) )
+ else
+ _filedir || return 0
+ fi
+
+ return 0
+}
+complete -F _chgrp $filenames chgrp
+
+# umount(8) completion. This relies on the mount point being the third
+# space-delimited field in the output of mount(8)
+#
+_umount()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ OLDIFS="$IFS"
+ IFS="\n"
+ COMPREPLY=( $( compgen -W '$( mount | cut -d" " -f 3 )' -- $cur ) )
+ IFS="$OLDIFS"
+
+ return 0
+}
+complete -F _umount $dirnames umount
+
+# mount(8) completion. This will pull a list of possible mounts out of
+# /etc/{,v}fstab, unless the word being completed contains a ':', which
+# would indicate the specification of an NFS server. In that case, we
+# query the server for a list of all available exports and complete on
+# that instead.
+#
+_mount()
+{ local cur i sm host
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ [[ "$cur" == \\ ]] && cur="/"
+
+ for i in {,/usr}/{,s}bin/showmount; do [ -x $i ] && sm=$i && break; done
+
+ if [ -n "$sm" ] && [[ "$cur" == *:* ]]; then
+ COMPREPLY=( $( $sm -e ${cur%%:*} | sed 1d | \
+ grep ^${cur#*:} | awk '{print $1}' ) )
+ elif [[ "$cur" == //* ]]; then
+ host=${cur#//}
+ host=${host%%/*}
+ if [ -n "$host" ]; then
+ COMPREPLY=( $( compgen -W "$( echo $( smbclient -d 0 -NL $host 2>/dev/null|
+ sed -ne '/^['"$'\t '"']*Sharename/,/^$/p' |
+ sed -ne '3,$s|^[^A-Za-z]*\([^'"$'\t '"']*\).*$|//'$host'/\1|p' ) )" -- "$cur" ) )
+ fi
+ elif [ -r /etc/vfstab ]; then
+ # Solaris
+ COMPREPLY=( $( awk '! /^[ \t]*#/ {if ($3 ~ /\//) print $3}' \
+ /etc/vfstab | grep "^$cur" ) )
+ elif [ ! -e /etc/fstab ]; then
+ # probably Cygwin
+ COMPREPLY=( $( mount | awk '! /^[ \t]*#/ {if ($3 ~ /\//) print $3}' \
+ | grep "^$cur" ) )
+ else
+ # probably Linux
+ COMPREPLY=( $( awk '! /^[ \t]*#/ {if ($2 ~ /\//) print $2}' \
+ /etc/fstab | grep "^$cur" ) )
+ fi
+
+ return 0
+}
+complete -F _mount $default $filenames mount
+
+# Linux rmmod(8) completion. This completes on a list of all currently
+# installed kernel modules.
+#
+have rmmod && {
+_rmmod()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( /sbin/lsmod | \
+ awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}' 2>/dev/null ))
+ return 0
+}
+complete -F _rmmod rmmod
+
+# Linux insmod(8), modprobe(8) and modinfo(8) completion. This completes on a
+# list of all available modules for the version of the kernel currently
+# running.
+#
+_insmod()
+{
+ local cur prev modpath
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # behave like lsmod for modprobe -r
+ if [ $1 = "modprobe" ] &&
+ [ "${COMP_WORDS[1]}" = "-r" ]; then
+ COMPREPLY=( $( /sbin/lsmod | \
+ awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}' ) )
+ return 0
+ fi
+
+ # do filename completion if we're giving a path to a module
+ if [[ "$cur" == */* ]]; then
+ _filedir '@(?(k)o?(.gz))'
+ return 0
+ fi
+
+ if [ $COMP_CWORD -gt 1 ] &&
+ [[ "${COMP_WORDS[COMP_CWORD-1]}" != -* ]]; then
+ # do module parameter completion
+ COMPREPLY=( $( /sbin/modinfo -p ${COMP_WORDS[1]} 2>/dev/null | \
+ awk '{if ($1 ~ /^parm:/ && $2 ~ /^'$cur'/) { print $2 } \
+ else if ($1 !~ /:/ && $1 ~ /^'$cur'/) { print $1 }}' ) )
+ else
+ _modules $(uname -r)
+ fi
+
+ return 0
+}
+complete -F _insmod $filenames insmod modprobe modinfo
+}
+
+# man(1) completion
+#
+[ $UNAME = GNU -o $UNAME = Linux -o $UNAME = Darwin \
+ -o $UNAME = FreeBSD -o $UNAME = SunOS -o $UNAME = Cygwin \
+ -o $UNAME = OpenBSD ] &&
+_man()
+{
+ local cur prev sect manpath UNAME
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ _expand || return 0
+
+ # default completion if parameter contains /
+ if [[ "$cur" == */* ]]; then
+ _filedir
+ return 0
+ fi
+
+ UNAME=$( uname -s )
+ # strip OS type and version under Cygwin
+ UNAME=${UNAME/CYGWIN_*/Cygwin}
+ if [ $UNAME = GNU -o $UNAME = Linux -o $UNAME = FreeBSD \
+ -o $UNAME = Cygwin ]; then
+ manpath=$( manpath 2>/dev/null || command man --path )
+ else
+ manpath=$MANPATH
+ fi
+
+ if [ -z "$manpath" ]; then
+ COMPREPLY=( $( compgen -c -- $cur ) )
+ return 0
+ fi
+
+ # determine manual section to search
+ [[ "$prev" == [0-9ln] ]] && sect=$prev || sect='*'
+
+ manpath=$manpath:
+ if [ -n "$cur" ]; then
+ manpath="${manpath//://*man$sect/$cur* } ${manpath//://*cat$sect/$cur* }"
+ else
+ manpath="${manpath//://*man$sect/ } ${manpath//://*cat$sect/ }"
+ fi
+
+ # redirect stderr for when path doesn't exist
+ COMPREPLY=( $( eval command ls "$manpath" 2>/dev/null ) )
+ # weed out directory path names and paths to man pages
+ COMPREPLY=( ${COMPREPLY[@]##*/?(:)} )
+ # strip suffix from man pages
+ COMPREPLY=( ${COMPREPLY[@]%.@(gz|bz2)} )
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]%.*}' -- "${cur//\\\\/}" ) )
+
+ [[ "$prev" != [0-9ln] ]] && _filedir '[0-9ln]'
+
+ return 0
+}
+[ $UNAME = GNU -o $UNAME = Linux -o $UNAME = Darwin \
+ -o $UNAME = FreeBSD -o $UNAME = SunOS -o $UNAME = Cygwin \
+ -o $UNAME = OpenBSD ] && \
+complete -F _man $filenames man apropos whatis
+
+# renice(8) completion
+#
+_renice()
+{
+ local command cur curopt i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ command=$1
+
+ i=0
+ # walk back through command line and find last option
+ while [ $i -le $COMP_CWORD -a ${#COMPREPLY[@]} -eq 0 ]; do
+ curopt=${COMP_WORDS[COMP_CWORD-$i]}
+ case "$curopt" in
+ -u)
+ COMPREPLY=( $( compgen -u -- $cur ) )
+ ;;
+ -g)
+ _pgids
+ ;;
+ -p|$command)
+ _pids
+ ;;
+ esac
+ i=$(( ++i ))
+ done
+}
+complete -F _renice renice
+
+# kill(1) completion
+#
+_kill()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
+ # return list of available signals
+ _signals
+ else
+ # return list of available PIDs
+ _pids
+ fi
+}
+complete -F _kill kill
+
+# Linux and FreeBSD killall(1) completion.
+#
+[ $UNAME = Linux -o $UNAME = FreeBSD ] &&
+_killall()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
+ _signals
+ else
+ COMPREPLY=( $( compgen -W '$( command ps axo command | \
+ sed -ne "1d; s/^\[\?\([^-][^] ]*\).*$/\1/p" | \
+ sed -e "s/.*\///" )' -- $cur ) )
+ fi
+
+ return 0
+}
+[ $UNAME = Linux -o $UNAME = FreeBSD ] && complete -F _killall killall pkill
+
+# Linux and FreeBSD pgrep(1) completion.
+#
+[ $UNAME = Linux -o $UNAME = FreeBSD ] &&
+_pgrep()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( compgen -W '$( command ps axo command | \
+ sed -ne "1d; s/^\[\?\([^-][^] ]*\).*$/\1/p" | \
+ sed -e "s/.*\///" )' -- $cur ) )
+
+ return 0
+}
+[ $UNAME = Linux -o $UNAME = FreeBSD ] && complete -F _pgrep pgrep
+# Linux pidof(8) completion.
+[ $UNAME = Linux ] && complete -F _pgrep pidof
+
+# GNU find(1) completion. This makes heavy use of ksh style extended
+# globs and contains Linux specific code for completing the parameter
+# to the -fstype option.
+#
+_find()
+{
+ local cur prev i exprfound onlyonce
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(max|min)depth)
+ COMPREPLY=( $( compgen -W '0 1 2 3 4 5 6 7 8 9' -- $cur ) )
+ return 0
+ ;;
+ -?(a|c)newer|-fls|-fprint?(0|f)|-?(i)?(l)name|-?(i)wholename)
+ _filedir
+ return 0
+ ;;
+ -fstype)
+ # this is highly non-portable
+ [ -e /proc/filesystems ] &&
+ COMPREPLY=( $( cut -d$'\t' -f 2 /proc/filesystems | \
+ grep "^$cur" ) )
+ return 0
+ ;;
+ -gid)
+ _gids
+ return 0
+ ;;
+ -group)
+ if [ -n "$bash205" ]; then
+ COMPREPLY=( $( compgen -g -- $cur 2>/dev/null) )
+ fi
+ return 0
+ ;;
+ -?(x)type)
+ COMPREPLY=( $( compgen -W 'b c d p f l s' -- $cur ) )
+ return 0
+ ;;
+ -uid)
+ _uids
+ return 0
+ ;;
+ -user)
+ COMPREPLY=( $( compgen -u -- $cur ) )
+ return 0
+ ;;
+ -exec|-ok)
+ COMP_WORDS=(COMP_WORDS[0] $cur)
+ COMP_CWORD=1
+ _command
+ return 0
+ ;;
+ -[acm]min|-[acm]time|-?(i)?(l)name|-inum|-?(i)path|-?(i)regex| \
+ -links|-perm|-size|-used|-printf)
+ # do nothing, just wait for a parameter to be given
+ return 0
+ ;;
+ esac
+
+ _expand || return 0
+
+ # set exprfound to 1 if there is already an expression present
+ for i in ${COMP_WORDS[@]}; do
+ [[ "$i" = [-\(\),\!]* ]] && exprfound=1 && break
+ done
+
+ # handle case where first parameter is not a dash option
+ if [ "$exprfound" != 1 ] && [[ "$cur" != [-\(\),\!]* ]]; then
+ _filedir -d
+ return 0
+ fi
+
+ # complete using basic options
+ COMPREPLY=( $( compgen -W '-daystart -depth -follow -help -maxdepth \
+ -mindepth -mount -noleaf -version -xdev -amin -anewer \
+ -atime -cmin -cnewer -ctime -empty -false -fstype \
+ -gid -group -ilname -iname -inum -ipath -iregex \
+ -wholename \
+ -links -lname -mmin -mtime -name -newer -nouser \
+ -nogroup -perm -regex -size -true -type -uid -used \
+ -user -xtype -exec -fls -fprint -fprint0 -fprintf -ok \
+ -print -print0 -printf -prune -ls' -- $cur ) )
+
+ # this removes any options from the list of completions that have
+ # already been specified somewhere on the command line, as long as
+ # these options can only be used once (in a word, "options", in
+ # opposition to "tests" and "actions", as in the find(1) manpage).
+ onlyonce=' -daystart -depth -follow -help -maxdepth -mindepth -mount \
+ -noleaf -version -xdev '
+ COMPREPLY=( $( echo "${COMP_WORDS[@]}" | \
+ (while read -d ' ' i; do
+ [ "$i" == "" ] ||
+ [ "${onlyonce/ ${i%% *} / }" == "$onlyonce" ] &&
+ continue
+ # flatten array with spaces on either side,
+ # otherwise we cannot grep on word boundaries of
+ # first and last word
+ COMPREPLY=" ${COMPREPLY[@]} "
+ # remove word from list of completions
+ COMPREPLY=( ${COMPREPLY/ ${i%% *} / } )
+ done
+ echo "${COMPREPLY[@]}")
+ ) )
+
+ _filedir
+
+ return 0
+}
+complete -F _find $filenames find
+
+# Linux iwconfig(8) completion
+#
+[ $UNAME = Linux ] && have iwconfig &&
+_iwconfig()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ mode)
+ COMPREPLY=( $( compgen -W 'managed ad-hoc master \
+ repeater secondary monitor' -- $cur ) )
+ return 0
+ ;;
+ essid)
+ COMPREPLY=( $( compgen -W 'on off any' -- $cur ) )
+ if [ -n "${COMP_IWLIST_SCAN:-}" ]; then
+ COMPREPLY=( "${COMPREPLY[@]}" \
+ $( iwlist ${COMP_WORDS[1]} scan | \
+ awk -F '"' '/ESSID/ {print $2}' | \
+ grep "^$cur" ))
+ fi
+ return 0
+ ;;
+ nwid)
+ COMPREPLY=( $( compgen -W 'on off' -- $cur ) )
+ return 0
+ ;;
+ channel)
+ COMPREPLY=( $( iwlist ${COMP_WORDS[1]} channel | \
+ awk '/^[[:space:]]*Channel/ {print $2}' | \
+ grep "^$cur" ) )
+ return 0
+ ;;
+
+ freq)
+ COMPREPLY=( $( iwlist ${COMP_WORDS[1]} channel | \
+ awk '/^[[:space:]]*Channel/ {print $4"G"}' | \
+ grep "^$cur" ) )
+ return 0
+ ;;
+ ap)
+ COMPREPLY=( $( compgen -W 'on off any' -- $cur ) )
+ if [ -n "${COMP_IWLIST_SCAN:-}" ]; then
+ COMPREPLY=( "${COMPREPLY[@]}" \
+ $( iwlist ${COMP_WORDS[1]} scan | \
+ awk -F ': ' '/Address/ {print $2}' | \
+ grep "^$cur" ) )
+ fi
+ return 0
+ ;;
+ rate)
+ COMPREPLY=( $( compgen -W 'auto fixed' -- $cur ) )
+ COMPREPLY=( "${COMPREPLY[@]}" \
+ $( iwlist ${COMP_WORDS[1]} rate | \
+ awk '/^[[:space:]]*[0-9]/ {print $1"M"}' | \
+ grep "^$cur" ) )
+ return 0
+ ;;
+ rts)
+ COMPREPLY=( $( compgen -W 'auto fixed off' -- $cur ) )
+ return 0
+ ;;
+ frag)
+ COMPREPLY=( $( compgen -W 'auto fixed off' -- $cur ) )
+ return 0
+ ;;
+ key)
+ COMPREPLY=( $( compgen -W 'off on open restricted' -- $cur ) )
+ return 0
+ ;;
+ enc)
+ COMPREPLY=( $( compgen -W 'off on open restricted' -- $cur ) )
+ return 0
+ ;;
+ power)
+ COMPREPLY=( $( compgen -W 'period timeout off on' -- $cur ) )
+ return 0
+ ;;
+ txpower)
+ COMPREPLY=( $( compgen -W 'off on auto' -- $cur ) )
+ return 0
+ ;;
+ retry)
+ COMPREPLY=( $( compgen -W 'limit lifetime' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--help --version' -- $cur ) )
+ else
+ _available_interfaces -w
+ fi
+ else
+ COMPREPLY=( $( compgen -W 'essid nwid mode freq channel sens mode \
+ ap nick rate rts frag enc key power txpower commit' -- $cur ) )
+ fi
+
+} &&
+complete -F _iwconfig iwconfig
+
+# Linux iwlist(8) completion
+#
+[ $UNAME = Linux ] && have iwlist &&
+_iwlist()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--help --version' -- $cur ) )
+ else
+ _available_interfaces -w
+ fi
+ else
+ COMPREPLY=( $( compgen -W 'scan scanning freq frequency \
+ channel rate bit bitrate key enc encryption power \
+ txpower retry ap accesspoint peers event' -- $cur ) )
+ fi
+} &&
+complete -F _iwlist iwlist
+
+# Linux iwspy(8) completion
+#
+[ $UNAME = Linux ] && have iwspy &&
+_iwspy()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--help --version' -- $cur ) )
+ else
+ _available_interfaces -w
+ fi
+ else
+ COMPREPLY=( $( compgen -W 'setthr getthr off' -- $cur ) )
+ fi
+} &&
+complete -F _iwspy iwspy
+
+# Linux iwpriv(8) completion
+#
+[ $UNAME = Linux ] && have iwpriv &&
+_iwpriv()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ roam)
+ COMPREPLY=( $( compgen -W 'on off' -- $cur ) )
+ return 0
+ ;;
+ port)
+ COMPREPLY=( $( compgen -W 'ad-hoc managed' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--help --version' -- $cur ) )
+ else
+ _available_interfaces -w
+ fi
+ else
+ COMPREPLY=( $( compgen -W '--all roam port' -- $cur ) )
+ fi
+} &&
+complete -F _iwpriv iwpriv
+
+# RedHat & Debian GNU/Linux if{up,down} completion
+#
+[ $UNAME = Linux ] && { have ifup || have ifdown; } &&
+_ifupdown()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ _configured_interfaces
+ COMPREPLY=( $(compgen -W '${COMPREPLY[@]}' -- "$cur") )
+ fi
+
+ return 0
+} &&
+complete -F _ifupdown ifup ifdown
+[ $UNAME = Linux ] && have ifstatus && complete -F _ifupdown ifstatus
+
+# Linux ipsec(8) completion (for FreeS/WAN)
+#
+[ $UNAME = Linux ] && have ipsec &&
+_ipsec()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W 'auto barf eroute klipsdebug look \
+ manual pluto ranbits rsasigkey \
+ setup showdefaults showhostkey spi \
+ spigrp tncfg whack' -- $cur ) )
+ return 0
+ fi
+
+ case ${COMP_WORDS[1]} in
+ auto)
+ COMPREPLY=( $( compgen -W '--asynchronous --up --add --delete \
+ --replace --down --route --unroute \
+ --ready --status --rereadsecrets' \
+ -- $cur ) )
+ ;;
+ manual)
+ COMPREPLY=( $( compgen -W '--up --down --route --unroute \
+ --union' -- $cur ) )
+ ;;
+ ranbits)
+ COMPREPLY=( $( compgen -W '--quick --continuous --bytes' \
+ -- $cur ) )
+ ;;
+ setup)
+ COMPREPLY=( $( compgen -W '--start --stop --restart' -- $cur ) )
+ ;;
+
+ *)
+ ;;
+ esac
+
+ return 0
+} &&
+complete -F _ipsec ipsec
+
+# Postfix completion.
+#
+have postfix && {
+# postfix(1)
+#
+_postfix()
+{
+ local cur prev
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ $cur == '-' ]]; then
+ COMPREPLY=(-c -D -v)
+ return 0
+ fi
+ if [[ $prev == '-c' ]]; then
+ _filedir -d
+ return 0
+ fi
+ if [[ $prev == '-D' ]]; then
+ COMPREPLY=( $( compgen -W 'start' -- "`get_cword`" ) )
+ return 0
+ fi
+ COMPREPLY=( $( compgen -W 'start stop reload abort flush check' -- \
+ "`get_cword`" ) )
+}
+complete -F _postfix postfix
+
+# postalias(1) and postmap(1)
+#
+_postmap()
+{
+ local cur prev len idx
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ $cur == '-' ]]; then
+ COMPREPLY=(-N -f -i -n -o -p -r -v -w -c -d -q)
+ return 0
+ fi
+ if [[ $prev == '-c' ]]; then
+ _filedir -d
+ return 0
+ fi
+ if [[ $prev == -[dq] ]]; then
+ return 0
+ fi
+
+ if [[ "$cur" == *:* ]]; then
+ COMPREPLY=( $( compgen -f -- ${cur#*:} ) )
+ else
+ len=${#cur}
+ idx=0
+ for pval in $( /usr/sbin/postconf -m ); do
+ if [[ "$cur" == "${pval:0:$len}" ]]; then
+ COMPREPLY[$idx]="$pval:"
+ idx=$(($idx+1))
+ fi
+ done
+ if [[ $idx -eq 0 ]]; then
+ COMPREPLY=( $( compgen -f -- "$cur" ) )
+ fi
+ fi
+ return 0
+}
+complete -F _postmap postmap postalias
+
+# postcat(1)
+#
+_postcat()
+{
+ local cur prev pval len idx qfile
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ $cur == '-' ]]; then
+ COMPREPLY=(-c -q -v)
+ return 0
+ fi
+ if [[ $prev == '-c' ]]; then
+ _filedir -d
+ return 0
+ fi
+
+ qfile=0
+ for idx in "${COMP_WORDS[@]}"; do
+ [[ "$idx" = -q ]] && qfile=1 && break
+ done
+ if [[ $qfile == 1 ]]; then
+ len=${#cur}
+ idx=0
+ for pval in $( mailq | \
+ sed -e '1d; $d; /^[^0-9A-Z]\|^$/d; s/[* !].*$//' ); do
+ if [[ "$cur" == "${pval:0:$len}" ]]; then
+ COMPREPLY[$idx]=$pval
+ idx=$(($idx+1))
+ fi
+ done
+ return 0
+ else
+ _filedir
+ return 0
+ fi
+}
+complete -F _postcat postcat
+
+# postconf(1)
+#
+_postconf()
+{
+ local cur prev pval len idx eqext
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ if [[ $cur == '-' ]]; then
+ COMPREPLY=(-c -d -e -h -m -l -n -v)
+ return 0
+ fi
+ if [[ $prev == '-c' ]]; then
+ _filedir -d
+ return 0
+ fi
+ if [[ $prev == '-e' ]]; then
+ cur=${cur#[\"\']}
+ eqext='='
+ fi
+ len=${#cur}
+ idx=0
+ for pval in $( /usr/sbin/postconf | cut -d ' ' -f 1 ); do
+ if [[ "$cur" == "${pval:0:$len}" ]]; then
+ COMPREPLY[$idx]="$pval$eqext"
+ idx=$(($idx+1))
+ fi
+ done
+ return 0
+}
+complete -F _postconf postconf
+
+# postsuper(1)
+#
+_postsuper()
+{
+ local cur prev pval len idx
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ $cur == '-' ]]; then
+ COMPREPLY=(-c -d -h -H -p -r -s -v)
+ return 0
+ fi
+ case $prev in
+ -[dr])
+ len=${#cur}
+ idx=0
+ for pval in $( echo ALL; mailq | \
+ sed -e '1d; $d; /^[^0-9A-Z]\|^$/d; s/[* !].*$//' ); do
+ if [[ "$cur" == "${pval:0:$len}" ]]; then
+ COMPREPLY[$idx]=$pval
+ idx=$(($idx+1))
+ fi
+ done
+ return 0
+ ;;
+ -h)
+ len=${#cur}
+ idx=0
+ for pval in $( echo ALL; mailq | \
+ sed -e '1d; $d; /^[^0-9A-Z]\|^$/d; s/[* ].*$//; /!$/d' ); do
+ if [[ "$cur" == "${pval:0:$len}" ]]; then
+ COMPREPLY[$idx]=$pval
+ idx=$(($idx+1))
+ fi
+ done
+ return 0
+ ;;
+ -H)
+ len=${#cur}
+ idx=0
+ for pval in $( echo ALL; mailq | \
+ sed -e '1d; $d; /^[^0-9A-Z]\|^$/d; /^[0-9A-Z]*[* ]/d; s/!.*$//' ); do
+ if [[ "$cur" == "${pval:0:$len}" ]]; then
+ COMPREPLY[$idx]=$pval
+ idx=$(($idx+1))
+ fi
+ done
+ return 0
+ ;;
+ esac
+ COMPREPLY=( $( compgen -W 'hold incoming active deferred' -- $cur ) )
+ return 0
+}
+complete -F _postsuper postsuper
+}
+
+# cvs(1) completion
+#
+have cvs && {
+set_prefix()
+{
+ [ -z ${prefix:-} ] || prefix=${cur%/*}/
+ [ -r ${prefix:-}CVS/Entries ] || prefix=""
+}
+
+get_entries()
+{
+ local IFS=$'\n'
+ [ -r ${prefix:-}CVS/Entries ] && \
+ entries=$(cut -d/ -f2 -s ${prefix:-}CVS/Entries)
+}
+
+get_modules()
+{
+ if [ -n "$prefix" ]; then
+ COMPREPLY=( $( command ls -d ${cvsroot}/${prefix}/!(CVSROOT) ) )
+ else
+ COMPREPLY=( $( command ls -d ${cvsroot}/!(CVSROOT) ) )
+ fi
+}
+
+_cvs()
+{
+ local cur count mode i cvsroot cvsroots pwd
+ local -a flags miss files entries changed newremoved
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ count=0
+ for i in "${COMP_WORDS[@]}"; do
+ [ $count -eq $COMP_CWORD ] && break
+ # Last parameter was the CVSROOT, now go back to mode selection
+ if [ "${COMP_WORDS[((count))]}" == "$cvsroot" -a "$mode" == "cvsroot" ]; then
+ mode=""
+ fi
+ if [ -z "$mode" ]; then
+ case $i in
+ -d)
+ mode=cvsroot
+ cvsroot=${COMP_WORDS[((count+1))]}
+ ;;
+ @(ad?(d)|new))
+ mode=add
+ ;;
+ @(adm?(in)|rcs))
+ mode=admin
+ ;;
+ ann?(notate))
+ mode=annotate
+ ;;
+ @(checkout|co|get))
+ mode=checkout
+ ;;
+ @(com?(mit)|ci))
+ mode=commit
+ ;;
+ di?(f?(f)))
+ mode=diff
+ ;;
+ ex?(p?(ort)))
+ mode=export
+ ;;
+ ?(un)edit)
+ mode=$i
+ ;;
+ hi?(s?(tory)))
+ mode=history
+ ;;
+ im?(p?(ort)))
+ mode=import
+ ;;
+ re?(l?(ease)))
+ mode=release
+ ;;
+ ?(r)log)
+ mode=log
+ ;;
+ @(rdiff|patch))
+ mode=rdiff
+ ;;
+ @(remove|rm|delete))
+ mode=remove
+ ;;
+ @(rtag|rfreeze))
+ mode=rtag
+ ;;
+ st?(at?(us)))
+ mode=status
+ ;;
+ @(tag|freeze))
+ mode=tag
+ ;;
+ up?(d?(ate)))
+ mode=update
+ ;;
+ *)
+ ;;
+ esac
+ elif [[ "$i" = -* ]]; then
+ flags=( "${flags[@]}" $i )
+ fi
+ count=$((++count))
+ done
+
+ case "$mode" in
+ add)
+ if [[ "$cur" != -* ]]; then
+ set_prefix
+ if [ $COMP_CWORD -gt 1 -a -r ${prefix:-}CVS/Entries ]; then
+ get_entries
+ [ -z "$cur" ] && \
+ files=$( command ls -Ad !(CVS) ) || \
+ files=$( command ls -d ${cur}* 2>/dev/null )
+ for i in "${entries[@]}"; do
+ files=( ${files[@]/#$i//} )
+ done
+ COMPREPLY=( $( compgen -W '${files[@]}' -- \
+ $cur ) )
+ fi
+ else
+ COMPREPLY=( $( compgen -W '-k -m' -- $cur ) )
+ fi
+ ;;
+ admin)
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $( compgen -W '-i -a -A -e -b -c -k -l -u \
+ -L -U -m -M -n -N -o -q -I \
+ -s -t -t- -T -V -x -z' -- \
+ $cur ) )
+ fi
+ ;;
+ annotate)
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $( compgen -W '-D -F -f -l -R -r' -- $cur ) )
+ else
+ get_entries
+ COMPREPLY=( $( compgen -W '${entries[@]}' -- $cur ) )
+ fi
+ ;;
+ checkout)
+ if [[ "$cur" != -* ]]; then
+ [ -z "$cvsroot" ] && cvsroot=$CVSROOT
+ COMPREPLY=( $( cvs -d "$cvsroot" co -c 2> /dev/null | \
+ awk '{print $1}' ) )
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W '-A -N -P -R -c -f -l -n -p \
+ -s -r -D -d -k -j' -- $cur ) )
+ fi
+ ;;
+ commit)
+ set_prefix
+
+ if [[ "$cur" != -* ]] && [ -r ${prefix:-}CVS/Entries ]; then
+ # if $COMP_CVS_REMOTE is not null, 'cvs commit' will
+ # complete on remotely checked-out files (requires
+ # passwordless access to the remote repository
+ if [ -n "${COMP_CVS_REMOTE:-}" ]; then
+ # this is the least computationally intensive
+ # way found so far, but other changes
+ # (something other than changed/removed/new)
+ # may be missing
+ changed=( $( cvs -q diff --brief 2>&1 | \
+ sed -ne 's/^Files [^ ]* and \([^ ]*\) differ$/\1/p' ) )
+ newremoved=( $( cvs -q diff --brief 2>&1 | \
+ sed -ne 's/^cvs diff: \([^ ]*\) .*, no comparison available$/\1/p' ) )
+ COMPREPLY=( $( compgen -W '${changed[@]:-} \
+ ${newremoved[@]:-}' -- $cur ) )
+ else
+ _filedir
+ fi
+ else
+ COMPREPLY=( $( compgen -W '-n -R -l -f -F -m -r' -- \
+ $cur ) )
+ fi
+ ;;
+ cvsroot)
+ if [ -r ~/.cvspass ]; then
+ # Ugly escaping because of bash treating ':' specially
+ cvsroots=$( sed 's/^[^ ]* //; s/:/\\:/g' ~/.cvspass )
+ COMPREPLY=( $( compgen -W '$cvsroots' -- $cur ) )
+ fi
+ ;;
+ export)
+ if [[ "$cur" != -* ]]; then
+ [ -z "$cvsroot" ] && cvsroot=$CVSROOT
+ COMPREPLY=( $( cvs -d "$cvsroot" co -c | awk '{print $1}' ) )
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W '-N -f -l -R -n \
+ -r -D -d -k' -- $cur ) )
+ fi
+ ;;
+ diff)
+ if [[ "$cur" == -* ]]; then
+ _longopt diff
+ else
+ get_entries
+ COMPREPLY=( $( compgen -W '${entries[@]:-}' -- $cur ) )
+ fi
+ ;;
+ remove)
+ if [[ "$cur" != -* ]]; then
+ set_prefix
+ if [ $COMP_CWORD -gt 1 -a -r ${prefix:-}CVS/Entries ]; then
+ get_entries
+ # find out what files are missing
+ for i in "${entries[@]}"; do
+ [ ! -r "$i" ] && miss=( "${miss[@]}" $i )
+ done
+ COMPREPLY=( $(compgen -W '${miss[@]:-}' -- $cur) )
+ fi
+ else
+ COMPREPLY=( $( compgen -W '-f -l -R' -- $cur ) )
+ fi
+ ;;
+ import)
+ if [[ "$cur" != -* ]]; then
+ # starts with same algorithm as checkout
+ [ -z "$cvsroot" ] && cvsroot=$CVSROOT
+ prefix=${cur%/*}
+ if [ -r ${cvsroot}/${prefix} ]; then
+ get_modules
+ COMPREPLY=( ${COMPREPLY[@]#$cvsroot} )
+ COMPREPLY=( ${COMPREPLY[@]#\/} )
+ fi
+ pwd=$( pwd )
+ pwd=${pwd##*/}
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]} $pwd' -- \
+ $cur ) )
+ else
+ COMPREPLY=( $( compgen -W '-d -k -I -b -m -W' -- $cur ))
+ fi
+ ;;
+ update)
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $( compgen -W '-A -P -C -d -f -l -R -p \
+ -k -r -D -j -I -W' -- \
+ $cur ) )
+ fi
+ ;;
+ "")
+ COMPREPLY=( $( compgen -W 'add admin annotate checkout ci co \
+ commit diff delete edit export \
+ freeze get history import log new \
+ patch rcs rdiff release remove \
+ rfreeze rlog rm rtag stat status \
+ tag unedit up update -H -Q -q -b \
+ -d -e -f -l -n -t -r -v -w -x -z \
+ --help --version' -- $cur ) )
+ ;;
+ *)
+ ;;
+ esac
+
+ return 0
+}
+complete -F _cvs $default cvs
+}
+
+have rpm && {
+# helper functions for rpm completion
+#
+_rpm_installed_packages()
+{
+ local ver nodig nosig
+
+ if [ -r /var/log/rpmpkgs -a \
+ /var/log/rpmpkgs -nt /var/lib/rpm/Packages ]; then
+ # using RHL 7.2 or later - this is quicker than querying the DB
+ COMPREPLY=( $( sed -ne \
+ 's|^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9a-z.@]\+.*\.rpm$|\1|p' \
+ /var/log/rpmpkgs ) )
+ else
+ nodig=""
+ nosig=""
+ ver=$(rpm --version)
+ ver=${ver##* }
+
+ if [[ "$ver" > "4.0.4" ]]; then
+ nodig="--nodigest"
+ fi
+ if [[ "$ver" > "4.0.99" ]]; then
+ nosig="--nosignature"
+ fi
+
+ COMPREPLY=( $( rpm -qa $nodig $nosig | sed -ne \
+ 's|^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9a-z.@]\+$|\1|p' ) )
+ fi
+}
+
+_rpm_groups()
+{
+ local IFS=$'\t'
+ # remove trailing backslash, or grep will complain
+ cur=${cur%"\\"}
+ COMPREPLY=( $( rpm -qa $nodig $nosig --queryformat '%{group}\n' | \
+ grep "^$cur" ) )
+ # backslash escape spaces and translate newlines to tabs
+ COMPREPLY=( $( echo "${COMPREPLY[@]}" | sed 's/ /\\ /g' | tr '\n' '\t' ) )
+}
+
+# rpm(8) completion
+#
+_rpm()
+{
+ local cur prev ver nodig nosig
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ nodig=""
+ nosig=""
+ ver=$(rpm --version); ver=${ver##* }
+
+ if [[ "$ver" > "4.0.4" ]]; then
+ nodig="--nodigest"
+ fi
+ if [[ "$ver" > "4.0.99" ]]; then
+ nosig="--nosignature"
+ fi
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ # first parameter on line
+ case "$cur" in
+ -b*)
+ COMPREPLY=( $( compgen -W '-ba -bb -bc -bi -bl -bp -bs'\
+ -- $cur ) )
+ ;;
+ -t*)
+ COMPREPLY=( $( compgen -W '-ta -tb -tc -ti -tl -tp -ts'\
+ -- $cur ) )
+ ;;
+ --*)
+ COMPREPLY=( $( compgen -W '--help --version --initdb \
+ --checksig --recompile --rebuild --resign --addsign \
+ --rebuilddb --showrc --setperms --setugids --tarbuild \
+ --eval --install --upgrade --query --freshen --erase \
+ --verify --querytags --rmsource --rmspec --clean \
+ --import' -- $cur ) )
+ ;;
+ *)
+ COMPREPLY=( $( compgen -W '-b -e -F -i -q -t -U -V' \
+ -- $cur ) )
+ ;;
+ esac
+
+ return 0
+ fi
+
+ case "$prev" in
+ --@(@(db|exclude)path|prefix|relocate|root))
+ _filedir -d
+ return 0
+ ;;
+ --eval)
+ # get a list of macros
+ COMPREPLY=( $( sed -ne 's|^\(%'${cur#\%}'[^ '$'\t'']*\).*$|\1|p' \
+ /usr/lib/rpm/macros ) )
+ return 0
+ ;;
+ --pipe)
+ COMPREPLY=( $( compgen -c -- $cur ) )
+ return 0
+ ;;
+ --rcfile)
+ _filedir
+ return 0
+ ;;
+ --specfile)
+ # complete on .spec files
+ _filedir spec
+ return 0
+ ;;
+ --whatprovides)
+ if [[ "$cur" == */* ]]; then
+ _filedir
+ else
+ # complete on capabilities
+ COMPREPLY=( $( rpm -qa $nodig $nosig --queryformat \
+ '%{providename}\n' | grep "^$cur" ) )
+ fi
+ return 0
+ ;;
+ --whatrequires)
+ # complete on capabilities
+ COMPREPLY=( $( rpm -qa $nodig $nosig --queryformat \
+ '%{requirename}\n' | grep "^$cur" ) )
+ return 0
+ ;;
+ esac
+
+ case "${COMP_WORDS[1]}" in
+ -@([iFU]*|-install|-freshen|-upgrade))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--percent --force --test \
+ --replacepkgs --replacefiles --root --excludedocs \
+ --includedocs --noscripts --rcfile --ignorearch \
+ --dbpath --prefix --ignoreos --nodeps --allfiles \
+ --ftpproxy --ftpport --justdb --httpproxy --httpport \
+ --noorder --relocate --badreloc --notriggers \
+ --excludepath --ignoresize --oldpackage --define \
+ --eval --pipe --queryformat --repackage --nosuggests \
+ --nodigest --nosignature' -- $cur ) )
+ else
+ _filedir 'rpm'
+ fi
+ ;;
+ -@(e|-erase))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--allmatches --noscripts \
+ --notriggers --nodeps --test --repackage' -- $cur ) )
+ else
+ _rpm_installed_packages
+ fi
+ ;;
+ -@(q*|-query))
+ # check whether we're doing file completion
+ if [ "${COMP_LINE#* -*([^ -])f}" != "$COMP_LINE" ]; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--scripts --root \
+ --rcfile --requires --ftpport --ftpproxy \
+ --httpproxy --httpport --provides --triggers \
+ --dump --changelog --dbpath \
+ --last --filesbypkg \
+ --info --list --state \
+ --docfiles --configfiles --queryformat \
+ --conflicts --obsoletes \
+ --nodigest --nosignature \
+ --triggerscripts' -- $cur ) )
+ else
+ _filedir
+ fi
+ elif [ "${COMP_LINE#* -*([^ -])g}" != "$COMP_LINE" ]; then
+ _rpm_groups
+ elif [ "${COMP_LINE#* -*([^ -])p}" != "$COMP_LINE" ]; then
+ # uninstalled package completion
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--scripts --root \
+ --rcfile --whatprovides --whatrequires \
+ --requires --triggeredby --ftpport --ftpproxy \
+ --httpproxy --httpport --provides --triggers \
+ --dump --changelog --dbpath --filesbypkg \
+ --define --eval --pipe --showrc --info --list \
+ --state --docfiles --configfiles --queryformat\
+ --conflicts --obsoletes --nodigest \
+ --nosignature' -- $cur ) )
+ else
+ _filedir 'rpm'
+ fi
+ else
+ # installed package completion
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--scripts --root \
+ --rcfile --whatprovides --whatrequires \
+ --requires --triggeredby --ftpport --ftpproxy \
+ --httpproxy --httpport --provides --triggers \
+ --dump --changelog --dbpath --specfile \
+ --querybynumber --last --filesbypkg --define \
+ --eval --pipe --showrc --info --list --state \
+ --docfiles --configfiles --queryformat \
+ --conflicts --obsoletes --pkgid --hdrid \
+ --fileid --tid --nodigest --nosignature \
+ --triggerscripts' -- $cur ) )
+ elif [ "${COMP_LINE#* -*([^ -])a}" == "$COMP_LINE" ]; then
+ _rpm_installed_packages
+ fi
+ fi
+ ;;
+ -@(K*|-checksig))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--nopgp --nogpg --nomd5 \
+ --nodigest --nosignature' -- $cur ) )
+ else
+ _filedir 'rpm'
+ fi
+ ;;
+ -@([Vy]*|-verify))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--root --rcfile --dbpath \
+ --nodeps --nogroup --nolinkto --nomode --nomtime \
+ --nordev --nouser --nofiles --noscripts --nomd5 \
+ --querytags --specfile --whatrequires --whatprovides \
+ --nodigest --nosignature' -- $cur ) )
+ # check whether we're doing file completion
+ elif [ "${COMP_LINE#* -*([^ -])f}" != "$COMP_LINE" ]; then
+ _filedir
+ elif [ "${COMP_LINE#* -*([^ -])g}" != "$COMP_LINE" ]; then
+ _rpm_groups
+ elif [ "${COMP_LINE#* -*([^ -])p}" != "$COMP_LINE" ]; then
+ _filedir 'rpm'
+ else
+ _rpm_installed_packages
+ fi
+ ;;
+ -[bt]*)
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--short-circuit --timecheck \
+ --clean --rmsource --rmspec --test --sign --buildroot \
+ --target -- buildarch --buildos --nobuild --nodeps \
+ --nodirtokens' -- $cur ) )
+ elif [[ ${COMP_WORDS[1]} == -b* ]]; then
+ _filedir 'spec'
+ else
+ _filedir '@(tgz|tar.@(gz|bz2))'
+ fi
+ ;;
+ --re@(build|compile))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--nodeps --rmsource \
+ --rmspec --sign --nodirtokens --target' -- $cur ) )
+ else
+ _filedir '?(no)src.rpm'
+ fi
+ ;;
+ --tarbuild)
+ _filedir '@(tgz|tar.@(gz|bz2))'
+ ;;
+ --@(re|add)sign)
+ _filedir 'rpm'
+ ;;
+ --set@(perms|gids))
+ _rpm_installed_packages
+ ;;
+ --@(clean|rms@(ource|pec)))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--clean --rmsource \
+ --rmspec' -- $cur ) )
+ else
+ _filedir 'spec'
+ fi
+ ;;
+ --@(import|dbpath|root))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--import --dbpath --root' \
+ -- $cur ) )
+ else
+ _filedir
+ fi
+ ;;
+ esac
+
+ return 0
+}
+complete -F _rpm $filenames rpm rpmbuild
+}
+
+# Debian apt-get(8) completion.
+#
+have apt-get &&
+_apt_get()
+{
+ local cur prev special i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[i]} == @(install|remove|purge|source|build-dep) ]]; then
+ special=${COMP_WORDS[i]}
+ fi
+ done
+
+ if [ -n "$special" ]; then
+ case $special in
+ remove|purge)
+ if [ -f /etc/debian_version ]; then
+ # Debian system
+ COMPREPLY=( $( _comp_dpkg_installed_packages \
+ $cur ) )
+ else
+ # assume RPM based
+ _rpm_installed_packages
+ fi
+ return 0
+ ;;
+ *)
+ COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) )
+ return 0
+ ;;
+
+ esac
+ fi
+
+ case "$prev" in
+ -@(c|-config-file))
+ _filedir
+ return 0
+ ;;
+
+ -@(t|-target-release|-default-release))
+ COMPREPLY=( $( apt-cache policy | \
+ grep "release.o=Debian,a=$cur" | \
+ sed -e "s/.*a=\(\w*\).*/\1/" | uniq 2> /dev/null) )
+ return 0
+ ;;
+
+ esac
+
+ if [[ "$cur" == -* ]]; then
+
+ COMPREPLY=( $( compgen -W '-d -f -h -v -m -q -s -y \
+ -u -t -b -c -o --download-only --fix-broken \
+ --help --version --ignore-missing \
+ --fix-missing --no-download --quiet --simulate \
+ --just-print --dry-run --recon --no-act --yes \
+ --assume-yes --show-upgraded --only-source \
+ --compile --build --ignore-hold \
+ --target-release --no-upgrade --force-yes \
+ --print-uris --purge --reinstall \
+ --list-cleanup --default-release \
+ --trivial-only --no-remove --diff-only \
+ --tar-only --config-file --option --auto-remove' -- $cur ) )
+ else
+
+ COMPREPLY=( $( compgen -W 'update upgrade dselect-upgrade \
+ dist-upgrade install remove purge source \
+ build-dep check clean autoclean autoremove' \
+ -- $cur ) )
+
+ fi
+
+
+ return 0
+} &&
+complete -F _apt_get $filenames apt-get
+
+# Debian apt-cache(8) completion.
+#
+have apt-cache &&
+_apt_cache()
+{
+ local cur prev special i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+
+ if [ "$cur" != show ]; then
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[i]} == @(add|depends|dotty|policy|rdepends|madison|show?(pkg|src|)) ]]; then
+ special=${COMP_WORDS[i]}
+ fi
+ done
+ fi
+
+
+ if [ -n "$special" ]; then
+ case $special in
+ add)
+ _filedir
+ return 0
+ ;;
+
+ *)
+ COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) )
+ return 0
+ ;;
+
+ esac
+ fi
+
+
+ case "$prev" in
+ -@(c|p|s|-config-file|-@(pkg|src)-cache))
+ _filedir
+ return 0
+ ;;
+ search)
+ if [[ "$cur" != -* ]]; then
+ return 0
+ fi
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+
+ COMPREPLY=( $( compgen -W '-h -v -p -s -q -i -f -a -g -c \
+ -o --help --version --pkg-cache --src-cache \
+ --quiet --important --full --all-versions \
+ --no-all-versions --generate --no-generate \
+ --names-only --all-names --recurse \
+ --config-file --option' -- $cur ) )
+ else
+
+ COMPREPLY=( $( compgen -W 'add gencaches show showpkg showsrc \
+ stats dump dumpavail unmet search search \
+ depends rdepends pkgnames dotty xvcg \
+ policy madison' -- $cur ) )
+
+ fi
+
+
+ return 0
+} &&
+complete -F _apt_cache $filenames apt-cache
+
+
+# Debian aptitude(1) completion
+#
+have aptitude && {
+have grep-status && {
+_comp_dpkg_hold_packages()
+{
+ grep-status -P -e "^$1" -a -FStatus 'hold' -n -s Package
+}
+} || {
+_comp_dpkg_hold_packages()
+{
+ grep -B 2 'hold' /var/lib/dpkg/status | grep "Package: $1" \
+ | cut -d\ -f2
+}
+}
+
+_aptitude()
+{
+ local cur dashoptions prev special i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+
+ dashoptions='-S -u -i -h --help --version -s --simulate -d \
+ --download-only -P --prompt -y --assume-yes -F \
+ --display-format -O --sort -w --width -f -r -g \
+ --with-recommends --with-suggests -R -G \
+ --without-recommends --without-suggests -t \
+ --target-release -V --show-versions -D --show-deps\
+ -Z -v --verbose --purge-unused'
+
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[i]} == @(install|reinstall|hold|unhold|markauto|unmarkauto|dist-upgrade|full-upgrade|download|show|forbid-version|purge|remove|changelog|why|why-not|keep|keep-all) ]]; then
+ special=${COMP_WORDS[i]}
+ fi
+ #exclude some mutually exclusive options
+ [[ ${COMP_WORDS[i]} == '-u' ]] && dashoptions=${dashoptions/-i}
+ [[ ${COMP_WORDS[i]} == '-i' ]] && dashoptions=${dashoptions/-u}
+ done
+
+ if [[ -n "$special" ]]; then
+ case $special in
+ @(install|hold|markauto|unmarkauto|dist-upgrade|full-upgrade|download|show|changelog|why|why-not))
+ COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) )
+ return 0
+ ;;
+ @(purge|remove|reinstall|forbid-version))
+ COMPREPLY=( $( _comp_dpkg_installed_packages $cur ) )
+ return 0
+ ;;
+ unhold)
+ COMPREPLY=( $( _comp_dpkg_hold_packages $cur ) )
+ return 0
+ ;;
+
+ esac
+ fi
+
+ case $prev in
+ # don't complete anything if these options are found
+ @(autoclean|clean|forget-new|search|upgrade|safe-upgrade|update|keep-all))
+ return 0
+ ;;
+
+ -S)
+ _filedir
+ return 0
+ ;;
+
+ -@(t|-target-release|-default-release))
+ COMPREPLY=( $( apt-cache policy | \
+ grep "release.o=Debian,a=$cur" | \
+ sed -e "s/.*a=\(\w*\).*/\1/" | uniq 2> /dev/null ) )
+ return 0
+ ;;
+
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W "$dashoptions" -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W 'update upgrade safe-upgrade forget-new clean \
+ autoclean install reinstall remove \
+ hold unhold purge markauto unmarkauto why why-not \
+ dist-upgrade full-upgrade download search show \
+ forbid-version changelog keep-all' -- $cur ) )
+ fi
+
+
+ return 0
+}
+complete -F _aptitude $default aptitude
+}
+
+# Debian apt-build(1) completion.
+#
+have apt-build &&
+_apt_build()
+{
+ local cur prev special i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[i]} == @(install|remove|source|info|clean) ]]; then
+ special=${COMP_WORDS[i]}
+ fi
+ done
+
+ if [ -n "$special" ]; then
+ case $special in
+ @(install|source|info))
+ COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) )
+ return 0
+ ;;
+ remove)
+ COMPREPLY=( $( _comp_dpkg_installed_packages \
+ $cur ) )
+ return 0
+ ;;
+ *)
+ return 0
+ ;;
+ esac
+ fi
+
+ case "$prev" in
+
+ --@(patch|build-dir|repository-dir))
+ _filedir
+ return 0
+ ;;
+
+ -@(h|-help))
+ return 0
+ ;;
+
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--help --show-upgraded -u --build-dir \
+ --repository-dir --build-only \
+ --build-command --reinstall --rebuild \
+ --remove-builddep --no-wrapper --purge \
+ --patch --patch-strip -p --yes -y \
+ --version -v --no-source' -- $cur ) )
+
+ else
+ COMPREPLY=( $( compgen -W 'update upgrade install remove \
+ source dist-upgrade world clean info \
+ clean-build update-repository ' -- $cur ) )
+ fi
+
+
+ return 0
+} &&
+complete -F _apt_build $filenames apt-build
+
+# chsh(1) completion
+#
+_chsh()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [ "$prev" = "-s" ]; then
+ if [ -f /etc/debian_version ]; then
+ COMPREPLY=( $( </etc/shells ) )
+ else
+ COMPREPLY=( $( chsh -l | grep "^$cur" ) )
+ fi
+ else
+ COMPREPLY=( $( compgen -u -- $cur ) )
+ fi
+
+ return 0
+}
+complete -F _chsh chsh
+
+# chkconfig(8) completion
+#
+have chkconfig &&
+_chkconfig()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ @([1-6]|--@(list|add|del)))
+ _services
+ return 0
+ ;;
+ --level)
+ COMPREPLY=( $( compgen -W '1 2 3 4 5 6' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--list --add --del --level' -- $cur ) )
+ else
+ if [ $COMP_CWORD -eq 2 -o $COMP_CWORD -eq 4 ]; then
+ COMPREPLY=( $( compgen -W 'on off reset' -- $cur ) )
+ else
+ _services
+ fi
+ fi
+} &&
+complete -F _chkconfig chkconfig
+
+# This function provides simple user@host completion
+#
+_user_at_host() {
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ $cur == *@* ]]; then
+ _known_hosts
+ else
+ COMPREPLY=( $( compgen -u -- "$cur" ) )
+ fi
+
+ return 0
+}
+shopt -u hostcomplete && complete -F _user_at_host $nospace talk ytalk finger
+
+# This function performs host completion based on ssh's known_hosts files,
+# defaulting to standard host completion if they don't exist.
+#
+_known_hosts()
+{
+ local cur curd ocur user suffix aliases global_kh user_kh hosts i host
+ local -a kh khd config
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ ocur=$cur
+
+ [ "$1" = -a ] || [ "$2" = -a ] && aliases='yes'
+ [ "$1" = -c ] || [ "$2" = -c ] && suffix=':'
+ [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@}
+ kh=()
+
+ # ssh config files
+ [ -r /etc/ssh/ssh_config ] &&
+ config=( "${config[@]}" "/etc/ssh/ssh_config" )
+ [ -r "${HOME}/.ssh/config" ] &&
+ config=( "${config[@]}" "${HOME}/.ssh/config" )
+ [ -r "${HOME}/.ssh2/config" ] &&
+ config=( "${config[@]}" "${HOME}/.ssh2/config" )
+
+ if [ ${#config[@]} -gt 0 ]; then
+ # expand path (if present) to global known hosts file
+ global_kh=$( eval echo $( sed -ne 's/^[ \t]*[Gg][Ll][Oo][Bb][Aa][Ll][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/\1/p' "${config[@]}" ) )
+ # expand path (if present) to user known hosts file
+ user_kh=$( eval echo $( sed -ne 's/^[ \t]*[Uu][Ss][Ee][Rr][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/\1/p' "${config[@]}" ) )
+ fi
+
+ # Global known_hosts files
+ [ -r "$global_kh" ] &&
+ kh=( "${kh[@]}" "$global_kh" )
+ [ -r /etc/ssh/ssh_known_hosts ] &&
+ kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts )
+ [ -r /etc/ssh/ssh_known_hosts2 ] &&
+ kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts2 )
+ [ -r /etc/known_hosts ] &&
+ kh=( "${kh[@]}" /etc/known_hosts )
+ [ -r /etc/known_hosts2 ] &&
+ kh=( "${kh[@]}" /etc/known_hosts2 )
+ [ -d /etc/ssh2/knownhosts ] &&
+ khd=( "${khd[@]}" /etc/ssh2/knownhosts/*pub )
+
+ # User known_hosts files
+ [ -r "$user_kh" ] &&
+ kh=( "${kh[@]}" "$user_kh" )
+ [ -r ~/.ssh/known_hosts ] &&
+ kh=( "${kh[@]}" ~/.ssh/known_hosts )
+ [ -r ~/.ssh/known_hosts2 ] &&
+ kh=( "${kh[@]}" ~/.ssh/known_hosts2 )
+ [ -d ~/.ssh2/hostkeys ] &&
+ khd=( "${khd[@]}" ~/.ssh2/hostkeys/*pub )
+
+ # If we have known_hosts files to use
+ if [ ${#kh[@]} -gt 0 -o ${#khd[@]} -gt 0 ]; then
+ # Escape slashes and dots in paths for awk
+ cur=${cur//\//\\\/}
+ cur=${cur//\./\\\.}
+ curd=$cur
+
+ if [[ "$cur" == [0-9]*.* ]]; then
+ # Digits followed by a dot - just search for that
+ cur="^$cur.*"
+ elif [[ "$cur" == [0-9]* ]]; then
+ # Digits followed by no dot - search for digits followed
+ # by a dot
+ cur="^$cur.*\."
+ elif [ -z "$cur" ]; then
+ # A blank - search for a dot or an alpha character
+ cur="[a-z.]"
+ else
+ cur="^$cur"
+ fi
+
+ if [ ${#kh[@]} -gt 0 ]; then
+
+ # FS needs to look for a comma separated list
+ COMPREPLY=( $( awk 'BEGIN {FS=","}
+ /^[^|]/ {for (i=1; i<=2; ++i) { \
+ gsub(" .*$", "", $i); \
+ if ($i ~ /'$cur'/) {print $i} \
+ }}' "${kh[@]}" 2>/dev/null ) )
+ fi
+ if [ ${#khd[@]} -gt 0 ]; then
+ # Needs to look for files called
+ # .../.ssh2/key_22_<hostname>.pub
+ # dont fork any processes, because in a cluster environment,
+ # there can be hundreds of hostkeys
+ for i in "${khd[@]}" ; do
+ if [[ "$i" == *key_22_$curd*.pub ]] && [ -r "$i" ] ; then
+ host=${i/#*key_22_/}
+ host=${host/%.pub/}
+ COMPREPLY=( "${COMPREPLY[@]}" $host )
+ fi
+ done
+ fi
+
+ # append any available aliases from config files
+ if [ ${#config[@]} -gt 0 ] && [ -n "$aliases" ]; then
+ local host_aliases=$( sed -ne 's/^[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?['"$'\t '"']\+\([^*?]*\)$/\2/p' "${config[@]}" )
+ hosts=$( compgen -W "$host_aliases" -- $ocur )
+ COMPREPLY=( "${COMPREPLY[@]}" $hosts )
+ fi
+
+ # Now add results of normal hostname completion
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -A hostname -- $ocur ) )
+
+ # apply suffix
+ for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
+ COMPREPLY[i]=$user${COMPREPLY[i]}$suffix
+ done
+ else
+ # Just do normal hostname completion
+ COMPREPLY=( $( compgen -A hostname -S "$suffix" -- $cur ) )
+ fi
+
+ return 0
+}
+complete -F _known_hosts traceroute traceroute6 tracepath tracepath6 \
+ ping ping6 fping fping6 telnet host nslookup rsh rlogin ftp dig ssh-installkeys mtr
+
+# ssh(1) completion
+#
+have ssh && {
+_ssh()
+{
+ local cur prev
+ local -a config
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -*c)
+ COMPREPLY=( $( compgen -W 'blowfish 3des 3des-cbc blowfish-cbc \
+ arcfour cast128-cbc' -- $cur ) )
+ ;;
+ -*i)
+ _filedir
+ ;;
+ -*l)
+ COMPREPLY=( $( compgen -u -- $cur ) )
+ ;;
+ *)
+ _known_hosts -a
+
+ [ $COMP_CWORD -eq 1 ] || \
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -c -- $cur ) )
+ esac
+
+ return 0
+}
+shopt -u hostcomplete && complete -F _ssh ssh slogin sftp xhost autossh
+
+# scp(1) completion
+#
+_scp()
+{
+ local cur userhost path
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _expand || return 0
+
+ if [[ "$cur" == *:* ]]; then
+ local IFS=$'\t\n'
+ # remove backslash escape from :
+ cur=${cur/\\:/:}
+ userhost=${cur%%?(\\):*}
+ path=${cur#*:}
+ # unescape spaces
+ path=${path//\\\\\\\\ / }
+ if [ -z "$path" ]; then
+ # default to home dir of specified user on remote host
+ path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null)
+ fi
+ # escape spaces; remove executables, aliases, pipes and sockets;
+ # add space at end of file names
+ COMPREPLY=( $( ssh -o 'Batchmode yes' $userhost \
+ command ls -aF1d "$path*" 2>/dev/null | \
+ sed -e "s/[][(){}<>\",:;^&!$&=?\`|\\ ']/\\\\\\\\\\\\&/g" \
+ -e 's/[*@|=]$//g' -e 's/[^\/]$/& /g' ) )
+ return 0
+ fi
+
+ [[ "$cur" == */* ]] || _known_hosts -c -a
+ local IFS=$'\t\n'
+ COMPREPLY=( "${COMPREPLY[@]}" $( command ls -aF1d $cur* \
+ 2>/dev/null | sed \
+ -e "s/[][(){}<>\",:;^&!$&=?\`|\\ ']/\\\\&/g" \
+ -e 's/[*@|=]$//g' -e 's/[^\/]$/& /g' ) )
+ return 0
+}
+complete -F _scp $nospace scp
+}
+
+# rsync(1) completion
+#
+have rsync &&
+_rsync()
+{
+ local cur prev shell i userhost path
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ _expand || return 0
+
+ case "$prev" in
+ --@(config|password-file|include-from|exclude-from))
+ _filedir
+ return 0
+ ;;
+ -@(T|-temp-dir|-compare-dest))
+ _filedir -d
+ return 0
+ ;;
+ -@(e|-rsh))
+ COMPREPLY=( $( compgen -W 'rsh ssh' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ case "$cur" in
+ -*)
+ COMPREPLY=( $( compgen -W '-v -q -c -a -r -R -b -u -l -L -H \
+ -p -o -g -D -t -S -n -W -x -B -e -C -I -T -P \
+ -z -h -4 -6 --verbose --quiet --checksum \
+ --archive --recursive --relative --backup \
+ --backup-dir --suffix= --update --links \
+ --copy-links --copy-unsafe-links --safe-links \
+ --hard-links --perms --owner --group --devices\
+ --times --sparse --dry-run --whole-file \
+ --no-whole-file --one-file-system \
+ --block-size= --rsh= --rsync-path= \
+ --cvs-exclude --existing --ignore-existing \
+ --delete --delete-excluded --delete-after \
+ --ignore-errors --max-delete= --partial \
+ --force --numeric-ids --timeout= \
+ --ignore-times --size-only --modify-window= \
+ --temp-dir= --compare-dest= --compress \
+ --exclude= --exclude-from= --include= \
+ --include-from= --version --daemon --no-detach\
+ --address= --config= --port= --blocking-io \
+ --no-blocking-io --stats --progress \
+ --log-format= --password-file= --bwlimit= \
+ --write-batch= --read-batch= --help' -- $cur ))
+ ;;
+ *:*)
+ # find which remote shell is used
+ shell=rsh
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == -@(e|-rsh) ]]; then
+ shell=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+ if [[ "$shell" == ssh ]]; then
+ # remove backslash escape from :
+ cur=${cur/\\:/:}
+ userhost=${cur%%?(\\):*}
+ path=${cur#*:}
+ # unescape spaces
+ path=${path//\\\\\\\\ / }
+ if [ -z "$path" ]; then
+ # default to home dir of specified
+ # user on remote host
+ path=$(ssh -o 'Batchmode yes' \
+ $userhost pwd 2>/dev/null)
+ fi
+ # escape spaces; remove executables, aliases, pipes
+ # and sockets; add space at end of file names
+ COMPREPLY=( $( ssh -o 'Batchmode yes' $userhost \
+ command ls -aF1d "$path*" 2>/dev/null | \
+ sed -e 's/ /\\\\\\\ /g' -e 's/[*@|=]$//g' \
+ -e 's/[^\/]$/& /g' ) )
+ fi
+ ;;
+ *)
+ _known_hosts -c -a
+ _filedir
+ ;;
+ esac
+
+ return 0
+} &&
+complete -F _rsync $nospace $filenames rsync
+
+# Linux route(8) completion
+#
+[ $UNAME = Linux ] &&
+_route()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [ "$prev" = dev ]; then
+ COMPREPLY=( $( ifconfig -a | sed -ne 's|^\('$cur'[^ ]*\).*$|\1|p' ))
+ return 0
+ fi
+
+ COMPREPLY=( $( compgen -W 'add del -host -net netmask metric mss \
+ window irtt reject mod dyn reinstate dev \
+ default gw' -- $cur ) )
+
+ COMPREPLY=( $( echo " ${COMP_WORDS[@]}" | \
+ (while read -d ' ' i; do
+ [ "$i" == "" ] && continue
+ # flatten array with spaces on either side,
+ # otherwise we cannot grep on word
+ # boundaries of first and last word
+ COMPREPLY=" ${COMPREPLY[@]} "
+ # remove word from list of completions
+ COMPREPLY=( ${COMPREPLY/ $i / } )
+ done
+ echo "${COMPREPLY[@]}")
+ ) )
+ return 0
+}
+[ $UNAME = Linux ] && complete -F _route route
+
+# GNU make(1) completion
+#
+have make || have gmake || have gnumake || have pmake &&
+_make()
+{
+ local file makef makef_dir="." makef_inc cur prev i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # --name value style option
+ case $prev in
+ -@(f|o|W))
+ _filedir
+ return 0
+ ;;
+ -@(I|C))
+ _filedir -d
+ return 0
+ ;;
+ esac
+
+ # --name=value style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case "$prev" in
+ --@(file|makefile))
+ _filedir
+ return 0
+ ;;
+ --@(directory|include-dir))
+ _filedir -d
+ return 0
+ ;;
+ esac
+ fi
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-b -m -B -C -d -e -f -h -i -I\
+ -j -l -k -n -o -p -q -r -R - s -S -t -v -w -W \
+ --always-make --directory= --debug \
+ --environment-overrides --file= --makefile= --help \
+ --ignore-errors --include-dir= --jobs --load-average \
+ --max-load --keep-going --just-print --dry-run \
+ --recon --old-file= --assume-old= --print-data-base \
+ --question --no-builtin-rules --no-builtin-variables \
+ --silent --quiet --no-keep-goind --stop --touch \
+ --version --print-directory --no-print-directory \
+ --what-if= --new-file= --assume-new= \
+ --warn-undefined-variables' -- $cur ) )
+ else
+ # before we check for makefiles, see if a path was specified
+ # with -C
+ for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
+ if [[ ${COMP_WORDS[i]} == -C ]]; then
+ # eval for tilde expansion
+ eval makef_dir=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+
+ # make reads `GNUmakefile', then `makefile', then `Makefile'
+ if [ -f ${makef_dir}/GNUmakefile ]; then
+ makef=${makef_dir}/GNUmakefile
+ elif [ -f ${makef_dir}/makefile ]; then
+ makef=${makef_dir}/makefile
+ elif [ -f ${makef_dir}/Makefile ]; then
+ makef=${makef_dir}/Makefile
+ else
+ makef=${makef_dir}/*.mk # local convention
+ fi
+
+ # before we scan for targets, see if a Makefile name was
+ # specified with -f
+ for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
+ if [[ ${COMP_WORDS[i]} == -f ]]; then
+ # eval for tilde expansion
+ eval makef=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+
+ [ ! -f $makef ] && return 0
+
+ # deal with included Makefiles
+ makef_inc=$( grep -E '^-?include' $makef | sed -e "s,^.* ,"$makef_dir"/," )
+
+ for file in $makef_inc; do
+ [ -f $file ] && makef="$makef $file"
+ done
+
+ COMPREPLY=( $( awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ \
+ {split($1,A,/ /);for(i in A)print A[i]}' \
+ $makef 2>/dev/null | command grep "^$cur" ))
+ fi
+} &&
+complete -f -F _make $filenames make gmake gnumake pmake
+
+# GNU tar(1) completion
+#
+_tar()
+{
+ local cur ext regex tar untar
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W 'c t x u r d A' -- $cur ) )
+ return 0
+ fi
+
+ case "${COMP_WORDS[1]}" in
+ ?(-)[cr]*f)
+ _filedir
+ return 0
+ ;;
+ +([^IZzjy])f)
+ ext='t@(ar?(.@(Z|gz|bz?(2)))|gz|bz?(2))'
+ regex='t\(ar\(\.\(Z\|gz\|bz2\?\)\)\?\|gz\|bz2\?\)'
+ ;;
+ *[Zz]*f)
+ ext='t?(ar.)@(gz|Z)'
+ regex='t\(ar\.\)\?\(gz\|Z\)'
+ ;;
+ *[Ijy]*f)
+ ext='t?(ar.)bz?(2)'
+ regex='t\(ar\.\)\?bz2\?'
+ ;;
+ *)
+ _filedir
+ return 0
+ ;;
+
+ esac
+
+ if [[ "$COMP_LINE" == *$ext' ' ]]; then
+ # complete on files in tar file
+ #
+ # get name of tar file from command line
+ tar=$( echo "$COMP_LINE" | \
+ sed -e 's/^.* \([^ ]*'$regex'\) .*$/\1/' )
+ # devise how to untar and list it
+ untar=t${COMP_WORDS[1]//[^Izjyf]/}
+
+ COMPREPLY=( $( compgen -W "$( echo $( tar $untar $tar \
+ 2>/dev/null ) )" -- "$cur" ) )
+ return 0
+ fi
+
+ # file completion on relevant files
+ _filedir "$ext"
+
+ return 0
+}
+[ -n "${COMP_TAR_INTERNAL_PATHS:-}" ] && complete -F _tar $dirnames tar ||
+ complete -F _tar $filenames tar
+
+# jar(1) completion
+#
+have jar &&
+_jar()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD = 1 ]; then
+ COMPREPLY=( $( compgen -W 'c t x u' -- $cur ) )
+ return 0
+ fi
+
+ case "${COMP_WORDS[1]}" in
+ *c*f)
+ _filedir
+ ;;
+ *f)
+ _filedir '?(e|j|w)ar'
+ ;;
+ *)
+ _filedir
+ ;;
+ esac
+} &&
+complete -F _jar $filenames jar
+
+# Linux iptables(8) completion
+#
+have iptables &&
+_iptables()
+{
+ local cur prev table chain
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ chain='s/^Chain \([^ ]\+\).*$/\1/p'
+
+ if [[ $COMP_LINE == *-t\ *filter* ]]; then
+ table="-t filter"
+ elif [[ $COMP_LINE == *-t\ *nat* ]]; then
+ table="-t nat"
+ elif [[ $COMP_LINE == *-t\ *mangle* ]]; then
+ table="-t mangle"
+ fi
+
+ case "$prev" in
+ -*[AIDRPFXLZ])
+ COMPREPLY=( $( compgen -W '`iptables $table -nL | \
+ sed -ne "s/^Chain \([^ ]\+\).*$/\1/p"`' -- $cur ) )
+ ;;
+ -*t)
+ COMPREPLY=( $( compgen -W 'nat filter mangle' -- $cur ) )
+ ;;
+ -j)
+ if [ "$table" = "-t filter" -o "$table" = "" ]; then
+ COMPREPLY=( $( compgen -W 'ACCEPT DROP LOG ULOG REJECT \
+ `iptables $table -nL | sed -ne "$chain" \
+ -e "s/INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING//"`' -- \
+ $cur ) )
+ elif [ "$table" = "-t nat" ]; then
+ COMPREPLY=( $( compgen -W 'ACCEPT DROP LOG ULOG REJECT \
+ MIRROR SNAT DNAT MASQUERADE `iptables $table -nL | \
+ sed -ne "$chain" -e "s/OUTPUT|PREROUTING|POSTROUTING//"`' \
+ -- $cur ) )
+ elif [ "$table" = "-t mangle" ]; then
+ COMPREPLY=( $( compgen -W 'ACCEPT DROP LOG ULOG REJECT \
+ MARK TOS `iptables $table -nL | sed -ne "$chain" \
+ -e "s/INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING//"`' -- \
+ $cur ) )
+ fi
+ ;;
+ *)
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-i -o -s -d -p -f -m --append \
+ --delete --insert --replace --list --flush --zero --new \
+ --delete-chain --policy --rename-chain --proto --source \
+ --destination --in-interface --jump --match --numeric \
+ --out-interface --table --verbose --line-numbers --exact \
+ --fragment --modprobe= --set-counters --version' -- "$cur") )
+ fi
+ ;;
+ esac
+
+} &&
+complete -F _iptables iptables
+
+# tcpdump(8) completion
+#
+have tcpdump &&
+_tcpdump()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(r|w|F))
+ _filedir
+ return 0
+ ;;
+ -i)
+ _available_interfaces -a
+ return 0
+ ;;
+ esac
+
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a -d -e -f -l -n -N -O -p \
+ -q -R -S -t -u -v -x -C -F -i -m -r -s -T -w \
+ -E' -- $cur ) )
+ fi
+
+} &&
+complete -F _tcpdump tcpdump
+
+# autorpm(8) completion
+#
+have autorpm &&
+_autorpm()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( compgen -W '--notty --debug --help --version \
+ auto add fullinfo info help install list \
+ remove set' -- $cur ) )
+
+} &&
+complete -F _autorpm autorpm
+
+# This meta-cd function observes the CDPATH variable, so that cd additionally
+# completes on directories under those specified in CDPATH.
+#
+_cd()
+{
+ local IFS=$'\t\n' cur=`_get_cword` i j k
+
+ # try to allow variable completion
+ if [[ "$cur" == ?(\\)\$* ]]; then
+ COMPREPLY=( $( compgen -v -P '$' -- "${cur#?(\\)$}" ) )
+ return 0
+ fi
+
+ # Use standard dir completion if no CDPATH or parameter starts with /,
+ # ./ or ../
+ if [ -z "${CDPATH:-}" ] || [[ "$cur" == ?(.)?(.)/* ]]; then
+ _filedir -d
+ return 0
+ fi
+
+ local -r mark_dirs=$(_rl_enabled mark-directories && echo y)
+ local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y)
+
+ # we have a CDPATH, so loop on its contents
+ for i in ${CDPATH//:/$'\t'}; do
+ # create an array of matched subdirs
+ k="${#COMPREPLY[@]}"
+ for j in $( compgen -d $i/$cur ); do
+ if [[ ( $mark_symdirs && -h $j || $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then
+ j="${j}/"
+ fi
+ COMPREPLY[k++]=${j#$i/}
+ done
+ done
+
+ _filedir -d
+
+ if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
+ i=${COMPREPLY[0]}
+ if [ "$i" == "$cur" ] && [[ $i != "*/" ]]; then
+ COMPREPLY[0]="${i}/"
+ fi
+ fi
+
+ return 0
+}
+if shopt -q cdable_vars; then
+ complete -v -F _cd $nospace $filenames cd
+else
+ complete -F _cd $nospace $filenames cd
+fi
+
+_remove_comp_word()
+{
+ if [[ COMP_CWORD -eq 0 ]]; then
+ return
+ elif [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
+ local old_cw0="${COMP_WORDS[0]}"
+ local new_cw0="${COMP_WORDS[1]}"
+ local old_length="${#COMP_LINE}"
+ COMP_LINE=${COMP_LINE#${old_cw0}}
+ local head=${COMP_LINE:0:${#new_cw0}}
+ local i=1
+ while [[ $head != $new_cw0 ]]; do
+ COMP_LINE=${COMP_LINE:1}
+ head=${COMP_LINE:0:${#new_cw0}}
+ if (( ++i > 10 )); then
+ break
+ fi
+ done
+ local new_length="${#COMP_LINE}"
+ COMP_POINT=$(( COMP_POINT + new_length - old_length))
+
+ COMP_CWORD=$(( COMP_CWORD - 1 ))
+ for (( i=0; i < ${#COMP_WORDS[@]} - 1; ++i )); do
+ COMP_WORDS[i]="${COMP_WORDS[i+1]}"
+ done
+ unset COMP_WORDS[${#COMP_WORDS[@]}-1]
+ else
+ return
+ fi
+}
+
+# A meta-command completion function for commands like sudo(8), which need to
+# first complete on a command, then complete according to that command's own
+# completion definition - currently not quite foolproof (e.g. mount and umount
+# don't work properly), but still quite useful.
+#
+_command()
+{
+ local cur func cline cspec noglob cmd done i \
+ _COMMAND_FUNC _COMMAND_FUNC_ARGS
+
+ _remove_comp_word
+ COMPREPLY=()
+ cur=`_get_cword`
+ # If the the first arguments following our meta-command-invoker are
+ # switches, get rid of them. Most definitely not foolproof.
+ done=
+ while [ -z $done ] ; do
+ cmd=${COMP_WORDS[0]}
+ if [[ "$cmd" == -* ]] && [ $COMP_CWORD -ge 1 ]; then
+ _remove_comp_word
+ elif [[ "$cmd" == -* ]] && [[ $COMP_CWORD -eq 0 ]]; then
+ return
+ else
+ done=1
+ fi
+ done
+
+ if [ $COMP_CWORD -eq 0 ]; then
+ COMPREPLY=( $( compgen -c -- $cur ) )
+ elif complete -p $cmd &>/dev/null; then
+ cspec=$( complete -p $cmd )
+ if [ "${cspec#* -F }" != "$cspec" ]; then
+ # COMP_CWORD and COMP_WORDS() are not read-only,
+ # so we can set them before handing off to regular
+ # completion routine
+
+ # get function name
+ func=${cspec#*-F }
+ func=${func%% *}
+
+ if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
+ $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}"
+ else
+ $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
+ fi
+
+ # remove any \: generated by a command that doesn't
+ # default to filenames or dirnames (e.g. sudo chown)
+ # FIXME: I'm pretty sure this does not work!
+ if [ "${cspec#*-o }" != "$cspec" ]; then
+ cspec=${cspec#*-o }
+ cspec=${cspec%% *}
+ if [[ "$cspec" != @(dir|file)names ]]; then
+ COMPREPLY=("${COMPREPLY[@]//\\\\:/:}")
+ fi
+ fi
+ elif [ -n "$cspec" ]; then
+ cspec=${cspec#complete};
+ cspec=${cspec%%$cmd};
+ COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) );
+ fi
+ fi
+
+ [ ${#COMPREPLY[@]} -eq 0 ] && _filedir
+}
+complete -F _command $filenames nohup exec nice eval strace time ltrace then \
+ else do vsound command xargs
+
+_root_command()
+{
+ PATH=/usr/gnu/bin:$PATH:/sbin:/usr/sbin _command $1 $2 $3
+}
+complete -F _root_command $filenames sudo fakeroot really
+
+# ant(1) completion
+#
+have ant && {
+_ant()
+{
+ local cur prev buildfile i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -buildfile|-f)
+ _filedir 'xml'
+ return 0
+ ;;
+ -logfile)
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # relevant options completion
+ COMPREPLY=( $( compgen -W '-help -projecthelp -version -quiet \
+ -verbose -debug -emacs -logfile -logger \
+ -listener -buildfile -f -D -find' -- $cur ) )
+ else
+ # available targets completion
+ # find which buildfile to use
+ buildfile=build.xml
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == -buildfile ]]; then
+ buildfile=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+ [ ! -f $buildfile ] && return 0
+
+ # parse buildfile for targets
+ COMPREPLY=( $( awk -F'"' '/<target name="/ {print $2}' \
+ $buildfile | grep "^$cur" )
+ $( awk -F"'" "/<target name='/ "'{print $2}' \
+ $buildfile | grep "^$cur" )
+ $( awk -F'"' '/<target [^n]/ {if ($1 ~ /name=/) { print $2 } else if ($3 ~ /name=/) {print $4} else if ($5 ~ /name=/) {print $6}}' \
+ $buildfile | grep "^$cur" ) )
+ fi
+}
+have complete-ant-cmd.pl && \
+ complete -C complete-ant-cmd.pl -F _ant $filenames ant || \
+ complete -F _ant $filenames ant
+}
+
+have nslookup &&
+_nslookup()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=${COMP_WORDS[COMP_CWORD]#-}
+
+ COMPREPLY=( $( compgen -P '-' -W 'all class= debug d2 domain= \
+ srchlist= defname search port= querytype= \
+ type= recurse retry root timeout vc \
+ ignoretc' -- $cur ) )
+} &&
+complete -F _nslookup nslookup
+
+# mysqladmin(1) completion
+#
+have mysqladmin &&
+_mysqladmin()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -u)
+ COMPREPLY=( $( compgen -u -- $cur ) )
+ return 0
+ ;;
+ *)
+ ;;
+ esac
+
+ COMPREPLY=( $( compgen -W '-# -f -? -C -h -p -P -i -r -E -s -S -t -u \
+ -v -V -w' -- $cur ) )
+
+ COMPREPLY=( "${COMPREPLY[@]}" \
+ $( compgen -W 'create drop extended-status flush-hosts \
+ flush-logs flush-status flush-tables \
+ flush-threads flush-privileges kill \
+ password ping processlist reload refresh \
+ shutdown status variables version' \
+ -- $cur ) )
+} &&
+complete -F _mysqladmin mysqladmin
+
+# gzip(1) completion
+#
+have gzip &&
+_gzip()
+{
+ local cur prev xspec IFS=$'\t\n'
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c -d -f \
+ -h -l -L -n -N -q -r -S -t -v -V \
+ -1 -2 -3 -4 -5 -6 -7 -8 -9 \
+ --stdout --decompress --force --help --list \
+ --license --no-name --name --quiet --recursive \
+ --suffix --test --verbose --version --fast \
+ --best' -- $cur ) )
+ return 0
+ fi
+
+ xspec="*.?(t)gz"
+ if [[ "$prev" == --* ]]; then
+ [[ "$prev" == --decompress || \
+ "$prev" == --list || \
+ "$prev" == --test ]] && xspec="!"$xspec
+ [[ "$prev" == --force ]] && xspec=
+ elif [[ "$prev" == -* ]]; then
+ [[ "$prev" == -*[dlt]* ]] && xspec="!"$xspec
+ [[ "$prev" == -*f* ]] && xspec=
+ elif [ "$prev" = '>' ]; then
+ xspec=
+ elif [ "$prev" = '<' ]; then
+ xspec=
+ fi
+
+ _expand || return 0
+
+ COMPREPLY=( $( compgen -f -X "$xspec" -- $cur ) \
+ $( compgen -d -- $cur ) )
+} &&
+complete -F _gzip $filenames gzip
+
+# bzip2(1) completion
+#
+have bzip2 &&
+_bzip2()
+{
+ local cur prev xspec IFS=$'\t\n'
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c -d -f -h -k -L -q -s \
+ -t -v -V -z -1 -2 -3 -4 -5 -6 -7 -8 -9 \
+ --help --decompress --compress --keep --force \
+ --test --stdout --quiet --verbose --license \
+ --version --small --fast --best' -- $cur ) )
+ return 0
+ fi
+
+ xspec="*.bz2"
+ if [[ "$prev" == --* ]]; then
+ [[ "$prev" == --decompress || \
+ "$prev" == --list || \
+ "$prev" == --test ]] && xspec="!"$xspec
+ [[ "$prev" == --compress ]] && xspec=
+ elif [[ "$prev" == -* ]]; then
+ [[ "$prev" == -*[dt]* ]] && xspec="!"$xspec
+ [[ "$prev" == -*z* ]] && xspec=
+ fi
+
+ _expand || return 0
+
+ COMPREPLY=( $( compgen -f -X "$xspec" -- $cur ) \
+ $( compgen -d -- $cur ) )
+} &&
+complete -F _bzip2 $filenames bzip2
+
+# openssl(1) completion
+#
+have openssl && {
+_openssl_sections()
+{
+ local config
+
+ config=/etc/ssl/openssl.cnf
+ [ ! -f $config ] && config=/usr/share/ssl/openssl.cnf
+ for (( i=2; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == -config ]]; then
+ config=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+ [ ! -f $config ] && return 0
+
+ COMPREPLY=( $( awk '/\[.*\]/ {print $2} ' $config | grep "^$cur" ) )
+}
+
+_openssl()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W 'asn1parse ca ciphers crl crl2pkcs7 \
+ dgst dh dhparam dsa dsaparam enc errstr gendh gendsa \
+ genrsa nseq passwd pkcs12 pkcs7 pkcs8 rand req rsa \
+ rsautl s_client s_server s_time sess_id smime speed \
+ spkac verify version x509 md2 md4 md5 mdc2 rmd160 sha \
+ sha1 base64 bf bf-cbc bf-cfb bf-ecb bf-ofb cast \
+ cast-cbc cast5-cbc cast5-cfb cast5-ecb cast5-ofb des \
+ des-cbc des-cfb des-ecb des-ede des-ede-cbc \
+ des-ede-cfb des-ede-ofb des-ede3 des-ede3-cbc \
+ des-ede3-cfb des-ede3-ofb des-ofb des3 desx rc2 \
+ rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb \
+ rc4 rc4-40' -- $cur ) )
+ else
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ case ${COMP_WORDS[1]} in
+ asn1parse)
+ case $prev in
+ -inform)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out|oid))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -in -out -noout -offset \
+ -length -i -oid -strparse' -- $cur ) )
+ fi
+ ;;
+ ca)
+ case $prev in
+ -@(config|revoke|cert|in|out|spkac|ss_cert))
+ _filedir
+ return 0
+ ;;
+ -outdir)
+ _filedir -d
+ return 0
+ ;;
+ -@(name|crlexts|extensions))
+ _openssl_sections
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-verbose -config -name \
+ -gencrl -revoke -crldays -crlhours -crlexts \
+ -startdate -enddate -days -md -policy -keyfile \
+ -key -passin -cert -in -out -notext -outdir \
+ -infiles -spkac -ss_cert -preserveDN -batch \
+ -msie_hack -extensions' -- $cur ) )
+ fi
+ ;;
+ ciphers)
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-v -ssl2 -ssl3 -tls1' -- $cur ) )
+ fi
+ ;;
+ crl)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out|CAfile))
+ _filedir
+ return 0
+ ;;
+ -CAPath)
+ _filedir -d
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -text -in -out -noout \
+ -hash -issuer -lastupdate -nextupdate -CAfile -CApath' -- $cur ) )
+ fi
+ ;;
+ crl2pkcs7)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -out -print_certs' -- $cur ) )
+ fi
+ ;;
+ dgst)
+ case $prev in
+ -@(out|sign|verify|prvrify|signature))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-md5 -md4 -md2 -sha1 -sha -mdc2 -ripemd160 -dss1 \
+ -c -d -hex -binary -out -sign -verify -prverify -signature' -- $cur ) )
+ else
+ _filedir
+ fi
+ ;;
+ dsa)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -passin -out -passout -des -des3 -idea -text -noout \
+ -modulus -pubin -pubout' -- $cur ) )
+ fi
+ ;;
+ dsaparam)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out|rand))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -out -noout \
+ -text -C -rand -genkey' -- $cur ) )
+ fi
+ ;;
+ enc)
+ case $prev in
+ -@(in|out|kfile))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-ciphername -in -out -pass \
+ -e -d -a -A -k -kfile -S -K -iv -p -P -bufsize -debug' -- $cur ) )
+ fi
+ ;;
+ dhparam)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out|rand))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -out -dsaparam -noout \
+ -text -C -2 -5 -rand' -- $cur ) )
+ fi
+ ;;
+ gendsa)
+ case $prev in
+ -@(out|rand))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-out -des -des3 -idea -rand' -- $cur ) )
+ else
+ _filedir
+ fi
+ ;;
+ genrsa)
+ case $prev in
+ -@(out|rand))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-out -passout -des -des3 -idea -f4 -3 -rand' -- $cur ) )
+ fi
+ ;;
+ pkcs7)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -out -print_certs -text -noout' -- $cur ) )
+ fi
+ ;;
+ rand)
+ case $prev in
+ -@(out|rand))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-out -rand -base64' -- $cur ) )
+ fi
+ ;;
+ req)
+ case "$prev" in
+ -@(in|out|key)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+
+ -@(in|out|rand|key|keyout|config))
+ _filedir
+ return 0
+ ;;
+ -extensions)
+ _openssl_sections
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in \
+ -passin -out -passout -text -noout -verify \
+ -modulus -new -rand -newkey -newkey -nodes \
+ -key -keyform -keyout -md5 -sha1 -md2 -mdc2 \
+ -config -x509 -days -asn1-kludge -newhdr \
+ -extensions -reqexts section' -- $cur ) )
+ fi
+ ;;
+ rsa)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER NET PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -passin -out -passout \
+ -sgckey -des -des3 -idea -text -noout -modulus -check -pubin \
+ -pubout -engine' -- $cur ) )
+ fi
+ ;;
+ rsautl)
+ case $prev in
+ -@(in|out|inkey))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-in -out -inkey -pubin -certin -sign -verify \
+ -encrypt -decrypt -pkcs -ssl -raw -hexdump -asn1parse' -- $cur ) )
+ fi
+ ;;
+ s_client)
+ case $prev in
+ -connect)
+ _known_hosts
+ return 0
+ ;;
+ -@(cert|key|CAfile|rand))
+ _filedir
+ return 0
+ ;;
+ -CApath)
+ _filedir -d
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-connect -verify -cert -key -CApath -CAfile \
+ -reconnect -pause -showcerts -debug -msg -nbio_test -state -nbio \
+ -crlf -ign_eof -quiet -ssl2 -ssl3 -tls1 -no_ssl2 -no_ssl3 -no_tls1 \
+ -bugs -cipher -starttls -engine -rand' -- $cur ) )
+ fi
+ ;;
+ s_server)
+ case $prev in
+ -@(cert|key|dcert|dkey|dhparam|CAfile|rand))
+ _filedir
+ return 0
+ ;;
+ -CApath)
+ _filedir -d
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-accept -context -verify -Verify -cert -key \
+ -dcert -dkey -dhparam -nbio -nbio_test -crlf -debug -msg -state -CApath \
+ -CAfile -nocert -cipher -quiet -no_tmp_rsa -ssl2 -ssl3 -tls1 -no_ssl2 \
+ -no_ssl3 -no_tls1 -no_dhe -bugs -hack -www -WWW -HTTP -engine -id_prefix \
+ -rand' -- $cur ) )
+ fi
+ ;;
+ s_time)
+ case $prev in
+ -connect)
+ _known_hosts
+ return 0
+ ;;
+ -@(cert|key|CAfile))
+ _filedir
+ return 0
+ ;;
+ -CApath)
+ _filedir -d
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-connect -www -cert -key -CApath -CAfile -reuse \
+ -new -verify -nbio -time -ssl2 -ssl3 -bugs -cipher' -- $cur ) )
+ fi
+ ;;
+
+ sess_id)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out))
+ _filedir
+ return 0
+ ;;
+ esac
+
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform -in -out -text -noout \
+ -context ID' -- $cur ) )
+ fi
+ ;;
+ smime)
+ case $prev in
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'SMIME DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -@(in|out|certfile|signer|recip|inkey|content|rand))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-encrypt -decrypt -sign -verify -pk7out -des -des3 \
+ -rc2-40 -rc2-64 -rc2-128 -aes128 -aes192 -aes256 -in -certfile -signer \
+ -recip -inform -passin -inkey -out -outform -content -to -from -subject \
+ -text -rand' -- $cur ) )
+ else
+ _filedir
+ fi
+ ;;
+ speed)
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-engine' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W 'md2 mdc2 md5 hmac sha1 rmd160 idea-cbc \
+ rc2-cbc rc5-cbc bf-cbc des-cbc des-ede3 rc4 rsa512 rsa1024 rsa2048 \
+ rsa4096 dsa512 dsa1024 dsa2048 idea rc2 des rsa blowfish' -- $cur ) )
+ fi
+ ;;
+ verify)
+ case $prev in
+ -@(CAfile|untrusted))
+ _filedir
+ return 0
+ ;;
+ -CApath)
+ _filedir -d
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-CApath -CAfile -purpose -untrusted -help -issuer_checks \
+ -verbose -certificates' -- $cur ) )
+ else
+ _filedir
+ fi
+ ;;
+ x509)
+ case "$prev" in
+ -@(in|out|CA|CAkey|CAserial|extfile))
+ _filedir
+ return 0
+ ;;
+ -@(in|out)form)
+ COMPREPLY=( $( compgen -W 'DER PEM NET' -- $cur ) )
+ return 0
+ ;;
+ -@(key|CA|CAkey)form)
+ COMPREPLY=( $( compgen -W 'DER PEM' -- $cur ) )
+ return 0
+ ;;
+ -extensions)
+ _openssl_sections
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-inform -outform \
+ -keyform -CAform -CAkeyform -in -out \
+ -serial -hash -subject -issuer -nameopt \
+ -email -startdate -enddate -purpose \
+ -dates -modulus -fingerprint -alias \
+ -noout -trustout -clrtrust -clrreject \
+ -addtrust -addreject -setalias -days \
+ -set_serial -signkey -x509toreq -req \
+ -CA -CAkey -CAcreateserial -CAserial \
+ -text -C -md2 -md5 -sha1 -mdc2 -clrext \
+ -extfile -extensions -engine' -- $cur ) )
+ fi
+ ;;
+ @(md5|md4|md2|sha1|sha|mdc2|ripemd160))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c -d' -- $cur ) )
+ else
+ _filedir
+ fi
+ ;;
+ esac
+ fi
+
+ return 0
+}
+complete -F _openssl $default openssl
+}
+
+# screen(1) completion
+#
+have screen &&
+_screen()
+{
+ local cur prev preprev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ [ "$COMP_CWORD" -ge 2 ] && preprev=${COMP_WORDS[COMP_CWORD-2]}
+
+ if [ "$preprev" = "-d" -o "$preprev" = "-D" -a "$prev" = "-r" -o \
+ "$prev" = "-R" ]; then
+ # list all
+ COMPREPLY=( $( command screen -ls | \
+ sed -ne 's|^['$'\t'']\+\('$cur'[0-9]\+\.[^'$'\t'']\+\).*$|\1|p' ) )
+ else
+ case "$prev" in
+ -[rR])
+ # list detached
+ COMPREPLY=( $( command screen -ls | \
+ sed -ne 's|^['$'\t'']\+\('$cur'[0-9]\+\.[^'$'\t'']\+\).*Detached.*$|\1|p' ) )
+ ;;
+ -[dDx])
+ # list attached
+ COMPREPLY=( $( command screen -ls | \
+ sed -ne 's|^['$'\t'']\+\('$cur'[0-9]\+\.[^'$'\t'']\+\).*Attached.*$|\1|p' ) )
+ ;;
+ -s)
+ # shells
+ COMPREPLY=( $( grep ^${cur:-[^#]} /etc/shells ) )
+ ;;
+ *)
+ ;;
+ esac
+ fi
+
+ return 0
+} &&
+complete -F _screen $default screen
+
+# lftp(1) bookmark completion
+#
+have lftp &&
+_lftp()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ] && [ -f ~/.lftp/bookmarks ]; then
+ COMPREPLY=( $( compgen -W '$( sed -ne "s/^\(.*\)'$'\t''.*$/\1/p" \
+ ~/.lftp/bookmarks )' -- $cur ) )
+ fi
+
+ return 0
+} &&
+complete -F _lftp $default lftp
+
+# ncftp(1) bookmark completion
+#
+have ncftp &&
+_ncftp()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ] && [ -f ~/.ncftp/bookmarks ]; then
+ COMPREPLY=( $( compgen -W '$( sed -ne "s/^\([^,]\{1,\}\),.*$/\1/p" \
+ ~/.ncftp/bookmarks )' -- $cur ) )
+ fi
+
+ return 0
+} &&
+complete -F _ncftp $default ncftp
+
+# gdb(1) completion
+#
+have gdb &&
+_gdb()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -c -- $cur ) )
+ elif [ $COMP_CWORD -eq 2 ]; then
+ prev=${prev##*/}
+ COMPREPLY=( $( compgen -fW "$( command ps axo comm,pid | \
+ awk '{if ($1 ~ /^'"$prev"'/) print $2}' ) )" \
+ -- "$cur" ) )
+ fi
+} &&
+complete -F _gdb $filenames gdb
+
+# Postgresql completion
+#
+have psql && {
+_pg_databases()
+{
+ return
+ COMPREPLY=( $( psql -l 2>/dev/null | \
+ sed -e '1,/^-/d' -e '/^(/,$d' | \
+ awk '{print $1}' | grep "^$cur" ) )
+}
+
+_pg_users()
+{
+ #COMPREPLY=( $( psql -qtc 'select usename from pg_user' template1 2>/dev/null | \
+ # grep "^ $cur" ) )
+ #[ ${#COMPREPLY[@]} -eq 0 ] &&
+ COMPREPLY=( $( compgen -u -- $cur ) )
+}
+
+# createdb(1) completion
+#
+_createdb()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(h|-host=))
+ _known_hosts
+ return 0
+ ;;
+ -@(U|-username=))
+ _pg_users
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-D -T -E -h -p -U -W -e -q \
+ --location= --template= --encoding= --host= --port= \
+ --username= --password --echo --quiet --help' -- $cur ))
+ else
+ _pg_databases
+ fi
+}
+complete -F _createdb $default createdb
+
+# dropdb(1) completion
+#
+_dropdb()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(h|-host=))
+ _known_hosts
+ return 0
+ ;;
+ -@(U|-username=))
+ _pg_users
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-h -p -U -W -e -q \
+ --host= --port= --username= --password \
+ --interactive --echo --quiet --help' -- $cur ) )
+ else
+ _pg_databases
+ fi
+}
+complete -F _dropdb $default dropdb
+
+# psql(1) completion
+#
+_psql()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -h|--host)
+ _known_hosts
+ return 0
+ ;;
+ -U|--username)
+ _pg_users
+ return 0
+ ;;
+ -d|--dbname)
+ _pg_databases
+ return 0
+ ;;
+ -@(o|f)|--output|--file)
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # return list of available options
+ COMPREPLY=( $( compgen -W '-a --echo-all -A --no-align \
+ -c --command -d --dbname -e --echo-queries \
+ -E --echo-hidden -f --file -F --filed-separator \
+ -h --host -H --html -l --list -n -o --output \
+ -p --port -P --pset -q -R --record-separator \
+ -s --single-step -S --single-line -t --tuples-only \
+ -T --table-attr -U --username -v --variable \
+ -V --version -W --password -x --expanded -X --nopsqlrc \
+ -? --help ' -- $cur ) )
+ else
+ # return list of available databases
+ _pg_databases
+ fi
+}
+complete -F _psql $default psql
+}
+
+_longopt()
+{
+ local cur opt
+
+ cur=`_get_cword`
+
+ if [[ "$cur" == --*=* ]]; then
+ opt=${cur%%=*}
+ # cut backslash that gets inserted before '=' sign
+ opt=${opt%\\*}
+ cur=${cur#*=}
+ _filedir
+ COMPREPLY=( $( compgen -P "$opt=" -W '${COMPREPLY[@]}' -- $cur))
+ return 0
+ fi
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( $1 --help 2>&1 | sed -e '/--/!d' \
+ -e 's/.*\(--[-A-Za-z0-9]\+=\?\).*/\1/' | \
+ command grep "^$cur" | sort -u ) )
+ elif [[ "$1" == @(mk|rm)dir ]]; then
+ _filedir -d
+ else
+ _filedir
+ fi
+}
+# makeinfo and texi2dvi are defined elsewhere.
+for i in a2ps autoconf automake bc gprof ld nm objcopy objdump readelf strip \
+ bison cpio diff patch enscript cp df dir du ln ls mkfifo mknod mv rm \
+ touch vdir awk gperf grep grub indent less m4 sed shar date \
+ tee who texindex cat csplit cut expand fmt fold head \
+ md5sum nl od paste pr ptx sha1sum sort split tac tail tr unexpand \
+ uniq wc ldd bash id irb mkdir rmdir; do
+ have $i && complete -F _longopt $filenames $i
+done
+
+# These commands use filenames, so '-o filenames' is not needed.
+for i in env netstat seq uname units wget; do
+ have $i && complete -F _longopt $default $i
+done
+unset i
+
+# gcc(1) completion
+#
+# The only unusual feature is that we don't parse "gcc --help -v" output
+# directly, because that would include the options of all the other backend
+# tools (linker, assembler, preprocessor, etc) without any indication that
+# you cannot feed such options to the gcc driver directly. (For example, the
+# linker takes a -z option, but you must type -Wl,-z for gcc.) Instead, we
+# ask the driver ("g++") for the name of the compiler ("cc1"), and parse the
+# --help output of the compiler.
+#
+have gcc &&
+_gcc()
+{
+ local cur cc backend
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _expand || return 0
+
+ case "$1" in
+ gcj)
+ backend=jc1
+ ;;
+ gpc)
+ backend=gpc1
+ ;;
+ *77)
+ backend=f771
+ ;;
+ *)
+ backend=cc1 # (near-)universal backend
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ cc=$( $1 -print-prog-name=$backend )
+ # sink stderr:
+ # for C/C++/ObjectiveC it's useless
+ # for FORTRAN/Java it's an error
+ COMPREPLY=( $( $cc --help 2>/dev/null | tr '\t' ' ' | \
+ sed -e '/^ *-/!d' -e 's/ *-\([^ ]*\).*/-\1/' | \
+ command grep "^$cur" | sort -u ) )
+ else
+ _filedir
+ fi
+} &&
+complete $filenames -F _gcc gcc g++ c++ g77 gcj gpc
+[ $UNAME = GNU -o $UNAME = Linux -o $UNAME = Cygwin ] && \
+[ -n "${have:-}" ] && complete $filenames -F _gcc cc
+
+# Linux cardctl(8) completion
+#
+have cardctl &&
+_cardctl()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W 'status config ident suspend \
+ resume reset eject insert scheme' \
+ -- $cur ) )
+ fi
+} &&
+complete -F _cardctl cardctl
+
+# This function is required by _dpkg() and _dpkg-reconfigure()
+#
+have dpkg && {
+_comp_dpkg_installed_packages()
+{
+ grep -A 1 "Package: $1" /var/lib/dpkg/status | \
+ grep -B 1 -E "ok installed|half-installed|unpacked| \
+ half-configured|config-files" | \
+ grep "Package: $1" | cut -d\ -f2
+}
+
+# Debian dpkg(8) completion
+#
+_dpkg()
+{
+ local cur prev i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ i=$COMP_CWORD
+
+ _expand || return 0
+
+ # find the last option flag
+ if [[ $cur != -* ]]; then
+ while [[ $prev != -* && $i != 1 ]]; do
+ i=$((i-1))
+ prev=${COMP_WORDS[i-1]}
+ done
+ fi
+
+ case "$prev" in
+ -@(c|i|A|I|f|e|x|X|-@(install|unpack|record-avail|contents|info|fsys-tarfile|field|control|extract)))
+ _filedir '?(u)deb'
+ return 0
+ ;;
+ -@(b|-build))
+ _filedir -d
+ return 0
+ ;;
+ -@(s|p|l|-@(status|print-avail|list)))
+ COMPREPLY=( $( apt-cache pkgnames $cur 2>/dev/null ) )
+ return 0
+ ;;
+ -@(S|-search))
+ _filedir
+ return 0
+ ;;
+ -@(r|L|P|-@(remove|purge|listfiles)))
+ COMPREPLY=( $( _comp_dpkg_installed_packages $cur ) )
+ return 0
+ ;;
+ *)
+
+ COMPREPLY=( $( compgen -W '-i --install --unpack -A --record-avail \
+ --configure -r --remove -P --purge --get-selections \
+ --set-selections --update-avail --merge-avail \
+ --clear-avail --command-fd --forget-old-unavail -s \
+ --status -p --print-avail -L --listfiles -l --list \
+ -S --search -C --audit --print-architecture \
+ --print-gnu-build-architecture \
+ --print-installation-architecture \
+ --compare-versions --help --version --force-help \
+ --force-all --force-auto-select --force-downgrade \
+ --force-configure-any --force-hold --force-bad-path \
+ --force-not-root --force-overwrite \
+ --force-overwrite-diverted --force-bad-verify \
+ --force-depends-version --force-depends \
+ --force-confnew --force-confold --force-confdef \
+ --force-confmiss --force-conflicts --force-architecture\
+ --force-overwrite-dir --force-remove-reinstreq \
+ --force-remove-essential -Dh \
+ --debug=help --licence --admindir= --root= --instdir= \
+ -O --selected-only -E --skip-same-version \
+ -G --refuse-downgrade -B --auto-deconfigure \
+ --no-debsig --no-act -D --debug= --status-fd \
+ -b --build -I --info -f --field -c --contents \
+ -x --extract -X --vextract --fsys-tarfile -e --control \
+ --ignore-depends= --abort-after' -- $cur ) )
+ ;;
+ esac
+
+
+}
+complete -F _dpkg $filenames dpkg dpkg-deb
+}
+
+# Debian GNU dpkg-reconfigure(8) completion
+#
+have dpkg-reconfigure &&
+_dpkg_reconfigure()
+{
+ local cur prev opt
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+
+ case "$prev" in
+ -@(f|-frontend))
+ opt=( $( echo /usr/share/perl5/Debconf/FrontEnd/* ) )
+ opt=( ${opt[@]##*/} )
+ opt=( ${opt[@]%.pm} )
+ COMPREPLY=( $( compgen -W '${opt[@]}' -- $cur ) )
+ return 0
+ ;;
+ -@(p|-priority))
+ COMPREPLY=( $( compgen -W 'low medium high critical' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-f --frontend -p --priority -a --all \
+ -u --unseen-only -h --help -s --showold \
+ --force --terse' -- $cur ) )
+ else
+ COMPREPLY=( $( _comp_dpkg_installed_packages $cur ) )
+ fi
+} &&
+complete -F _dpkg_reconfigure $default dpkg-reconfigure
+
+# Debian dpkg-source completion
+#
+have dpkg-source &&
+_dpkg_source()
+{
+ local cur prev options work i action packopts unpackopts
+
+ packopts="-c -l -F -V -T -D -U -W -E -sa -i -I -sk -sp -su -sr -ss -sn -sA -sK -sP -sU -sR"
+ unpackopts="-sp -sn -su"
+ options=`echo "-x -b $packopts $unpackopts" | xargs echo | sort -u | xargs echo`
+
+ COMPREPLY=()
+ if [ "$1" != "dpkg-source" ]; then
+ exit 1
+ fi
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ action="options"
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[$i]} == "-x" ]]; then
+ action=unpack
+ elif [[ ${COMP_WORDS[$i]} == "-b" ]]; then
+ action=pack
+ elif [[ ${COMP_WORDS[$i]} == "-h" ]]; then
+ action=help
+ fi
+ done
+ # if currently seeing a complete option, return just itself.
+ for i in $options; do
+ if [ "$cur" = "$i" ]; then
+ COMPREPLY=( "$cur" )
+ return 0
+ fi
+ done
+ case "$action" in
+ "unpack")
+ if [ "$cur" = "-" -o "$cur" = "-s" ]; then
+ COMPREPLY=( $unpackots )
+ return 0
+ fi
+ case "$prev" in
+ "-x")
+ COMPREPLY=( $( compgen -d -- "$cur" ) \
+ $( compgen -f -X '!*.dsc' -- "$cur" ) )
+ return 0
+ ;;
+ *)
+ COMPREPLY=( $unpackopts $(compgen -d -f -- "$cur" ) )
+ return 0
+ ;;
+ esac
+ return 0
+ ;;
+ "pack")
+ if [ "$cur" = "-" ]; then
+ COMPREPLY=( $packopts )
+ return 0
+ fi
+ if [ "$cur" = "-s" ]; then
+ COMPREPLY=( "-sa" "-sk" "-sp" "-su" "-sr" "-ss" "-sn" \
+ "-sA" "-sK" "-sP" "-sU" "-sR" )
+ return 0
+ fi
+ case "$prev" in
+ "-b")
+ COMPREPLY=( $( compgen -d -- "$cur" ) )
+ return 0
+ ;;
+ "-c"|"-l"|"-T"|"-i"|"-I")
+ # -c: get controlfile
+ # -l: get per-version info from this file
+ # -T: read variables here, not debian/substvars
+ # -i: <regexp> filter out files to ignore diffs of.
+ # -I: filter out files when building tarballs.
+ # return directory names and file names
+ COMPREPLY=( $( compgen -d -f ) )
+ return 0
+ ;;
+ "-F")
+ # -F: force change log format
+ COMPREPLY=( $( ( cd /usr/lib/dpkg/parsechangelog; compgen -f "$cur" ) ) )
+ return 0
+ ;;
+ "-V"|"-D")
+ # -V: set a substitution variable
+ # we don't know anything about possible variables or values
+ # so we don't try to suggest any completion.
+ COMPREPLY=()
+ return 0
+ ;;
+ "-D")
+ # -D: override or add a .dsc field and value
+ # if $cur doesn't contain a = yet, suggest variable names
+ if echo -- "$cur" | grep -q "="; then
+ # $cur contains a "="
+ COMPREPLY=()
+ return 0
+ else
+ COMPREPLY=( Format Source Version Binary Maintainer Uploader Architecture Standards-Version Build-Depends Files )
+ return 0
+ fi
+ ;;
+ "-U")
+ # -U: remove a field
+ # Suggest possible fieldnames
+ COMPREPLY=( Format Source Version Binary Maintainer Uploader Architecture Standards-Version Build-Depends Files )
+ return 0
+ ;;
+ *)
+ COMPREPLY=( $packopts )
+ return 0
+ ;;
+ esac
+ return 0
+ ;;
+ *)
+ # if seeing a partial option, return possible completions.
+ if [ "$cur" = "-s" ]; then
+ COMPREPLY=( "-sa" "-sk" "-sp" "-su" "-sr" "-ss" "-sn" \
+ "-sA" "-sK" "-sP" "-sU" "-sR" )
+ return 0
+ fi
+ # else return all possible options.
+ COMPREPLY=( $options )
+ return 0
+ ;;
+ esac
+} &&
+complete -F _dpkg_source dpkg-source
+
+# Debian Linux dselect(8) completion.
+#
+have dselect &&
+_dselect()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --admindir)
+ _filedir -d
+ return 0
+ ;;
+
+ -@(D|debug))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--admindir --help --version --licence \
+ --license --expert --debug' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W 'access update select install config \
+ remove quit' -- $cur ) )
+ fi
+
+
+ return 0
+} &&
+complete -F _dselect $filenames dselect
+
+# Java completion
+#
+
+# available path elements completion
+have java && {
+_java_path()
+{
+ cur=${cur##*:}
+ _filedir '@(jar|zip)'
+}
+
+# exact classpath determination
+_java_find_classpath()
+{
+ local i
+
+ # search first in current options
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == -@(cp|classpath) ]]; then
+ classpath=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+
+ # default to environment
+ [ -z "$classpath" ] && classpath=$CLASSPATH
+
+ # default to current directory
+ [ -z "$classpath" ] && classpath=.
+}
+
+# exact sourcepath determination
+_java_find_sourcepath()
+{
+ local i
+
+ # search first in current options
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == -sourcepath ]]; then
+ sourcepath=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+
+ # default to classpath
+ [ -z "$sourcepath" ] && _java_find_classpath
+ sourcepath=$classpath
+}
+
+# available classes completion
+_java_classes()
+{
+ local classpath i
+
+ # find which classpath to use
+ _java_find_classpath
+
+ # convert package syntax to path syntax
+ cur=${cur//.//}
+ # parse each classpath element for classes
+ for i in ${classpath//:/ }; do
+ if [ -r $i ] && [[ "$i" == *.@(jar|zip) ]]; then
+ if type zipinfo &> /dev/null; then
+ COMPREPLY=( "${COMPREPLY[@]}" $( zipinfo -1 \
+ "$i" | grep "^$cur" | grep '\.class$' | \
+ grep -v "\\$" ) )
+ else
+ COMPREPLY=( "${COMPREPLY[@]}" $( jar tf "$i" \
+ "$cur" | grep "\.class$" | grep -v "\\$" ) )
+ fi
+
+ elif [ -d $i ]; then
+ i=${i%/}
+ COMPREPLY=( "${COMPREPLY[@]}" $( find "$i" -type f \
+ -path "$i/$cur*.class" 2>/dev/null | \
+ grep -v "\\$" | sed -e "s|^$i/||" ) )
+ fi
+ done
+
+ # remove class extension
+ COMPREPLY=( ${COMPREPLY[@]%.class} )
+ # convert path syntax to package syntax
+ COMPREPLY=( ${COMPREPLY[@]//\//.} )
+}
+
+# available packages completion
+_java_packages()
+{
+ local sourcepath i
+
+ # find wich sourcepath to use
+ _java_find_sourcepath
+
+ # convert package syntax to path syntax
+ cur=${cur//.//}
+ # parse each sourcepath element for packages
+ for i in ${sourcepath//:/ }; do
+ if [ -d $i ]; then
+ COMPREPLY=( "${COMPREPLY[@]}" $( command ls -F -d \
+ $i/$cur* 2>/dev/null | sed -e 's|^'$i'/||' ) )
+ fi
+ done
+ # keep only packages
+ COMPREPLY=( $( echo "${COMPREPLY[@]}" | tr " " "\n" | grep "/$" ) )
+ # remove packages extension
+ COMPREPLY=( ${COMPREPLY[@]%/} )
+ # convert path syntax to package syntax
+ cur=${COMPREPLY[@]//\//.}
+}
+
+# java completion
+#
+_java()
+{
+ local cur prev i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ for ((i=1; i < $COMP_CWORD; i++)); do
+ case ${COMP_WORDS[$i]} in
+ -cp|-classpath)
+ ((i++)) # skip the classpath string.
+ ;;
+ -*)
+ # this is an option, not a class/jarfile name.
+ ;;
+ *)
+ # once we've seen a class, just do filename completion
+ _filedir
+ return 0
+ ;;
+ esac
+ done
+
+ case $prev in
+ -@(cp|classpath))
+ _java_path
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # relevant options completion
+ COMPREPLY=( $( compgen -W '-client -hotspot -server -classic \
+ -cp -classpath -D -verbose -verbose:class \
+ -verbose:gc -version:jni -version \
+ -showversion -? -help -X -jar \
+ -ea -enableassertions -da -disableassertions \
+ -esa -enablesystemassertions \
+ -dsa -disablesystemassertions ' -- $cur ) )
+ else
+ if [[ "$prev" == -jar ]]; then
+ # jar file completion
+ _filedir jar
+ else
+ # classes completion
+ _java_classes
+ fi
+ fi
+}
+complete -F _java $filenames java
+}
+
+# javadoc completion
+#
+have javadoc &&
+_javadoc()
+{
+ COMPREPLY=()
+ local cur prev
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ -@(overview|helpfile|stylesheetfile))
+ _filedir
+ return 0
+ ;;
+ -d)
+ _filedir -d
+ return 0
+ ;;
+ -@(classpath|bootclasspath|docletpath|sourcepath|extdirs))
+ _java_path
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # relevant options completion
+ COMPREPLY=( $( compgen -W '-overview -public -protected \
+ -package -private -help -doclet -docletpath \
+ -sourcepath -classpath -exclude -subpackages \
+ -breakiterator -bootclasspath -source -extdirs \
+ -verbose -locale -encoding -J -d -use -version \
+ -author -docfilessubdirs -splitindex \
+ -windowtitle -doctitle -header -footer -bottom \
+ -link -linkoffline -excludedocfilessubdir \
+ -group -nocomment -nodeprecated -noqualifier \
+ -nosince -nodeprecatedlist -notree -noindex \
+ -nohelp -nonavbar -quiet -serialwarn -tag \
+ -taglet -tagletpath -charset -helpfile \
+ -linksource -stylesheetfile -docencoding' -- \
+ $cur ) )
+ else
+ # source files completion
+ _filedir java
+ # packages completion
+ _java_packages
+ fi
+} &&
+complete -F _javadoc $filenames javadoc
+
+# javac completion
+#
+have javac &&
+_javac()
+{
+ COMPREPLY=()
+ local cur prev
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ -d)
+ _filedir -d
+ return 0
+ ;;
+ -@(classpath|bootclasspath|sourcepath|extdirs))
+ _java_path
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # relevant options completion
+ COMPREPLY=( $( compgen -W '-g -g:none -g:lines -g:vars\
+ -g:source -O -nowarn -verbose -deprecation -classpath\
+ -sourcepath -bootclasspath -extdirs -d -encoding -source\
+ -target -help' -- $cur ) )
+ else
+ # source files completion
+ _filedir java
+ fi
+} &&
+complete -F _javac $filenames javac
+
+# PINE address-book completion
+#
+have pine &&
+_pineaddr()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( compgen -W '$( awk "{print \$1}" ~/.addressbook 2>/dev/null)' \
+ -- $cur ) )
+} &&
+complete -F _pineaddr $default pine
+
+# mutt completion
+#
+# Mutt doesn't have an "addressbook" like Pine, but it has aliases and
+# a "query" function to retrieve addresses, so that's what we use here.
+have mutt || have muttng && {
+_muttaddr()
+{
+ _muttaliases
+ _muttquery
+ return 0
+}
+
+_muttconffiles()
+{
+ local file sofar
+ local -a newconffiles
+
+ sofar=" $1 "
+ shift
+ while [[ "$1" ]]; do
+ newconffiles=( $(sed -rn 's|^source[[:space:]]+([^[:space:]]+).*$|\1|p' $(eval echo $1) ) )
+ for file in "${newconffiles[@]}"; do
+ [[ ! "$file" ]] || [[ "${sofar/ ${file} / }" != "$sofar" ]] &&
+ continue
+ sofar="$sofar $file"
+ sofar=" $(eval _muttconffiles \"$sofar\" $file) "
+ done
+ shift
+ done
+ echo $sofar
+}
+
+_muttaliases()
+{
+ local cur muttrc
+ local -a conffiles aliases
+ cur=`_get_cword`
+
+ [ -f ~/.${muttcmd}/${muttcmd}rc ] && muttrc="~/.${muttcmd}/${muttcmd}rc"
+ [ -f ~/.${muttcmd}rc ] && muttrc="~/.${muttcmd}rc"
+ [ -z "$muttrc" ] && return 0
+
+ conffiles=( $(eval _muttconffiles $muttrc $muttrc) )
+ aliases=( $( sed -rn 's|^alias[[:space:]]+([^[:space:]]+).*$|\1|p' \
+ $(eval echo "${conffiles[@]}") ) )
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "${aliases[*]}" -- $cur ) )
+
+ return 0
+}
+
+_muttquery()
+{
+ local cur querycmd
+ local -a queryresults
+ cur=`_get_cword`
+
+ querycmd="$( $muttcmd -Q query_command | sed -r 's|^query_command=\"(.*)\"$|\1|; s|%s|'$cur'|' )"
+ if [ -z "$cur" -o -z "$querycmd" ]; then
+ queryresults=()
+ else
+ queryresults=( $( $querycmd | \
+ sed -nr '2,$s|^([^[:space:]]+).*|\1|p' ) )
+ fi
+
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "${queryresults[*]}" \
+ -- $cur ) )
+
+ return 0
+}
+
+_muttfiledir()
+{
+ local cur folder spoolfile
+ cur=`_get_cword`
+
+ # This is currently not working so well. Perhaps this function should
+ # just call _filedir() for the moment.
+ if [[ $cur == [=+]* ]]; then
+ folder="$( $muttcmd -Q folder | sed -r 's|^folder=\"(.*)\"$|\1|' )"
+ : folder:=~/Mail
+
+ # Match any file in $folder beginning with $cur
+ # (minus the leading '=' sign).
+ COMPREPLY=( $( compgen -f -- "$folder/${cur:1}" ) )
+ COMPREPLY=( ${COMPREPLY[@]#$folder/} )
+ return 0
+ elif [ "$cur" == !* ]; then
+ spoolfile="$( $muttcmd -Q spoolfile | sed -r 's|^spoolfile=\"(.*)\"$|\1|' )"
+ [ ! -z "$spoolfile" ] && eval cur="${cur/^!/$spoolfile}";
+ fi
+ _filedir
+
+ return 0
+}
+
+_mutt()
+{
+ local cur prev
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ COMPREPLY=()
+
+ [ ${COMP_WORDS[0]} == muttng ] && muttcmd="muttng" || muttcmd="mutt"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=( $( compgen -W '-A -a -b -c -e -f -F -H -i -m -n \
+ -p -Q -R -s -v -x -y -z -Z -h' \
+ -- $cur ) )
+ return 0
+ ;;
+ *)
+ case "$prev" in
+ -@(a|f|F|H|i))
+ _muttfiledir
+ return 0
+ ;;
+ -A)
+ _muttaliases
+ return 0
+ ;;
+ -@(e|m|Q|s|h|p|R|v|y|z|Z))
+ return 0
+ ;;
+ *)
+ _muttaddr
+ return 0
+ ;;
+ esac
+ ;;
+ esac
+
+}
+complete -F _mutt $default $filenames mutt muttng
+}
+
+_configure_func()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ # if $COMP_CONFIGURE_HINTS is not null, then completions of the form
+ # --option=SETTING will include 'SETTING' as a contextual hint
+ [[ "$cur" != -* ]] && return 0
+
+ if [ -n "$COMP_CONFIGURE_HINTS" ]; then
+ COMPREPLY=( $( $1 --help | awk '/^ --[A-Za-z]/ { print $1; if ($2 ~ /--[A-Za-z]/) print $2 }' | sed -e 's/[[,].*//g' | grep ^$cur ) )
+
+ else
+ COMPREPLY=( $( $1 --help | awk '/^ --[A-Za-z]/ { print $1; if ($2 ~ /--[A-Za-z]/) print $2 }' | sed -e 's/[[,=].*//g' | grep ^$cur ) )
+ fi
+}
+complete -F _configure_func $default configure
+
+# Debian reportbug(1) completion
+#
+have reportbug &&
+_reportbug()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -f|--filename|-i|--include|--mta|-o|--output)
+ _filedir
+ return 0
+ ;;
+ -B|--bts)
+ COMPREPLY=( $( compgen -W "debian guug kde mandrake help" -- \
+ $cur ))
+ return 0
+ ;;
+ -e|--editor|--mua)
+ COMP_WORDS=(COMP_WORDS[0] $cur)
+ COMP_CWORD=1
+ _command
+ return 0
+ ;;
+ --mode)
+ COMPREPLY=( $( compgen -W "novice standard expert" -- $cur ) )
+ return 0
+ ;;
+ -S|--severity)
+ COMPREPLY=( $( compgen -W "grave serious important normal \
+ minor wishlist" -- $cur ) )
+ return 0
+ ;;
+ -u|--ui|--interface)
+ COMPREPLY=( $( compgen -W "newt text gnome" -- $cur ) )
+ return 0
+ ;;
+ -t|--type)
+ COMPREPLY=( $( compgen -W "gnats debbugs" -- $cur ) )
+ return 0
+ ;;
+ -T|--tags)
+ COMPREPLY=( $( compgen -W "none patch security upstream sid \
+ woody potato sarge fixed" -- $cur ))
+ return 0
+ ;;
+ *)
+ ;;
+ esac
+
+ COMPREPLY=($( compgen -W '-h --help -v --version -a --af -b \
+ --no-query-bts --query-bts -B --bts -c --configure \
+ --no-config-files --check-available -d --debug \
+ --no-check-available -e --editor --email -f \
+ --filename -g --gnupg -H --header -i --include -j \
+ --justification -l --ldap --no-ldap -L --list-cc -m \
+ --maintonly --mode --mua --mta --mutt -n --mh --nmh \
+ -o --output -p --print -P --pgp --proxy --http_proxy\
+ -q --quiet -Q --query-only --realname --report-quiet \
+ --reply-to --replyto -s --subject -S --severity \
+ --smtphost -t --type -T --tags --template -V -x \
+ --no-cc --package-version -z --no-compress \
+ --ui --interface -u \
+ wnpp boot-floppies kernel-image' -- $cur ) \
+ $( apt-cache pkgnames -- $cur 2> /dev/null ) )
+ _filedir
+ return 0
+} &&
+complete -F _reportbug $filenames reportbug
+
+# Debian querybts(1) completion
+#
+have querybts &&
+_querybts()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -B|--bts)
+ COMPREPLY=( $( compgen -W "debian guug kde mandrake help" -- \
+ $cur ))
+ return 0
+ ;;
+ -u|--ui|--interface)
+ COMPREPLY=($( compgen -W "newt text gnome" -- $cur ))
+ return 0
+ ;;
+ *)
+ ;;
+ esac
+
+ COMPREPLY=($( compgen -W '-h --help -v --version -A --archive \
+ -B --bts -l --ldap --no-ldap --proxy= --http_proxy= \
+ -s --source -w --web -u --ui --interface \
+ wnpp boot-floppies' -- $cur ) \
+ $( apt-cache pkgnames -- $cur 2> /dev/null ) )
+} &&
+complete -F _querybts $filenames querybts
+
+# update-alternatives completion
+#
+have update-alternatives && {
+installed_alternatives()
+{
+ local admindir
+ # find the admin dir
+ for i in alternatives dpkg/alternatives rpm/alternatives; do
+ [ -d /var/lib/$i ] && admindir=/var/lib/$i && break
+ done
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == --admindir ]]; then
+ admindir=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+ COMPREPLY=( $( command ls $admindir | grep "^$cur" ) )
+}
+
+_update_alternatives()
+{
+ local cur prev mode args i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --@(altdir|admindir))
+ _filedir -d
+ return 0
+ ;;
+ --@(help|version))
+ return 0
+ ;;
+ esac
+
+ # find wich mode to use and how many real args used so far
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == --@(install|remove|auto|display|config|remove-all) ]]; then
+ mode=${COMP_WORDS[i]}
+ args=$(($COMP_CWORD - i))
+ break
+ fi
+ done
+
+ case $mode in
+ --install)
+ case $args in
+ 1)
+ _filedir
+ ;;
+ 2)
+ installed_alternatives
+ ;;
+ 3)
+ _filedir
+ ;;
+ esac
+ ;;
+ --remove)
+ case $args in
+ 1)
+ installed_alternatives
+ ;;
+ 2)
+ _filedir
+ ;;
+ esac
+ ;;
+ --auto)
+ installed_alternatives
+ ;;
+ --remove-all)
+ installed_alternatives
+ ;;
+ --display)
+ installed_alternatives
+ ;;
+ --config)
+ installed_alternatives
+ ;;
+ *)
+ COMPREPLY=( $( compgen -W '--verbose --quiet --help --version \
+ --altdir --admindir' -- $cur ) \
+ $( compgen -W '--install --remove --auto --display \
+ --config' -- $cur ) )
+ esac
+}
+complete -F _update_alternatives update-alternatives
+}
+
+# Python completion
+#
+have python &&
+_python()
+{
+ local prev cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]##*/}
+
+ case "$prev" in
+ -Q)
+ COMPREPLY=( $( compgen -W "old new warn warnall" -- $cur ) )
+ return 0
+ ;;
+ -W)
+ COMPREPLY=( $( compgen -W "ignore default all module once error" -- $cur ) )
+ return 0
+ ;;
+ -c)
+ _filedir '@(py|pyc|pyo)'
+ return 0
+ ;;
+ !(python|-?))
+ [[ ${COMP_WORDS[COMP_CWORD-2]} != -@(Q|W) ]] && _filedir
+ ;;
+ esac
+
+
+ # if '-c' is already given, complete all kind of files.
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[i]} == -c ]]; then
+ _filedir
+ fi
+ done
+
+
+ if [[ "$cur" != -* ]]; then
+ _filedir '@(py|pyc|pyo)'
+ else
+ COMPREPLY=( $( compgen -W "- -d -E -h -i -O -Q -S -t -u \
+ -U -v -V -W -x -c" -- $cur ) )
+ fi
+
+
+
+ return 0
+} &&
+complete -F _python $filenames python
+
+# Perl completion
+#
+have perl &&
+{
+_perlmodules()
+{
+ COMPREPLY=( $( compgen -P "$prefix" -W "$( perl -e 'sub mods { my ($base,$dir)=@_; return if $base !~ /^\Q$ENV{cur}/; chdir($dir) or return; for (glob(q[*.pm])) {s/\.pm$//; print qq[$base$_\n]}; mods(/^(?:[.\d]+|$Config{archname}-$Config{osname}|auto)$/ ? undef : qq[${base}${_}\\\\:\\\\:],qq[$dir/$_]) for grep {-d} glob(q[*]); } mods(undef,$_) for @INC;' )" -- $cur ) )
+}
+
+_perl()
+{
+ local cur prev prefix temp
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ prefix=""
+
+ # completing an option (may or may not be separated by a space)
+ if [[ "$cur" == -?* ]]; then
+ temp=$cur
+ prev=${temp:0:2}
+ cur=${temp:2}
+ prefix=$prev
+ fi
+
+ # only handle module completion for now
+ case "$prev" in
+ -I|-x)
+ COMPREPLY=( $( compgen -d -P "$prev" -- "$cur" ) )
+ return 0
+ ;;
+ -m|-M)
+ _perlmodules
+ return 0
+ ;;
+ esac
+
+ # handle case where first parameter is not a dash option
+ if [[ "${COMP_WORDS[COMP_CWORD]}" != -* ]]; then
+ _filedir
+ return 0
+ fi
+
+ # complete using basic options
+ COMPREPLY=( $( compgen -W '-C -s -T -u -U -W -X -h -v -V -c -w -d -D -p \
+ -n -a -F -l -0 -I -m -M -P -S -x -i -e ' -- $cur ) )
+ return 0
+}
+complete -F _perl $filenames perl
+
+_perldoc()
+{
+ local cur prev prefix temp
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ prefix=""
+
+ # completing an option (may or may not be separated by a space)
+ if [[ "$cur" == -?* ]]; then
+ temp=$cur
+ prev=${temp:0:2}
+ cur=${temp:2}
+ prefix=$prev
+ fi
+
+ # complete builtin perl functions
+ case $prev in
+ -f)
+ COMPREPLY=( $( compgen -W 'chomp chop chr crypt hex index lc \
+ lcfirst length oct ord pack q qq reverse rindex sprintf \
+ substr tr uc ucfirst y m pos quotemeta s split study qr abs \
+ atan2 cos exp hex int log oct rand sin sqrt srand pop push \
+ shift splice unshift grep join map qw reverse sort unpack \
+ delete each exists keys values binmode close closedir \
+ dbmclose dbmopen die eof fileno flock format getc print \
+ printf read readdir rewinddir seek seekdir select syscall \
+ sysread sysseek syswrite tell telldir truncate warn write \
+ pack read syscall sysread syswrite unpack vec -X chdir chmod \
+ chown chroot fcntl glob ioctl link lstat mkdir open opendir \
+ readlink rename rmdir stat symlink umask unlink utime caller \
+ continue do dump eval exit goto last next redo return \
+ sub wantarray caller import local my our package use defined \
+ formline reset scalar undef \
+ alarm exec fork getpgrp getppid getpriority kill pipe qx \
+ setpgrp setpriority sleep system times wait waitpid \
+ import no package require use bless dbmclose dbmopen package \
+ ref tie tied untie use accept bind connect getpeername \
+ getsockname getsockopt listen recv send setsockopt shutdown \
+ socket socketpair msgctl msgget msgrcv msgsnd semctl semget \
+ semop shmctl shmget shmread shmwrite endgrent endhostent \
+ endnetent endpwent getgrent getgrgid getgrnam getlogin \
+ getpwent getpwnam getpwuid setgrent setpwent endprotoent \
+ endservent gethostbyaddr gethostbyname gethostent \
+ getnetbyaddr getnetbyname getnetent getprotobyname \
+ getprotobynumber getprotoent getservbyname getservbyport \
+ getservent sethostent setnetent setprotoent setservent \
+ gmtime localtime time times' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '-h -v -t -u -m -l -F -X -f -q' -- $cur ))
+ return 0
+ ;;
+ */*)
+ return 0
+ ;;
+ *)
+ _perlmodules
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W '$( PAGER=cat man perl 2>/dev/null | sed -ne "/perl.*Perl overview/,/perlwin32/s/^[^a-z0-9]*\([a-z0-9]*\).*$/\1/p")' -- $cur ) )
+
+ return 0
+ ;;
+ esac
+}
+complete -F _perldoc $default perldoc
+}
+
+# rcs(1) completion
+#
+have rcs &&
+_rcs()
+{
+ local cur prev file dir i
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ file=${cur##*/}
+ dir=${cur%/*}
+
+ # deal with relative directory
+ [ "$file" = "$dir" ] && dir=.
+
+ COMPREPLY=( $( compgen -f "$dir/RCS/$file" ) )
+
+ for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
+ file=${COMPREPLY[$i]##*/}
+ dir=${COMPREPLY[$i]%RCS/*}
+ COMPREPLY[$i]=$dir$file
+ done
+
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -G "$dir/$file*,v" ) )
+
+ for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
+ COMPREPLY[$i]=${COMPREPLY[$i]%,v}
+ done
+
+ # default to files if nothing returned and we're checking in.
+ # otherwise, default to directories
+ [ ${#COMPREPLY[@]} -eq 0 -a $1 = ci ] && _filedir || _filedir -d
+} &&
+complete -F _rcs $filenames ci co rlog rcs rcsdiff
+
+# lilo(8) completion
+#
+have lilo && {
+_lilo_labels()
+{
+ COMPREPLY=( $( awk -F'=' '/label/ {print $2}' \
+ /etc/lilo.conf | sed -e 's/"//g' | grep "^$cur" ) )
+}
+
+_lilo()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ -@(C|i|m|s|S))
+ _filedir
+ return 0
+ ;;
+ -r)
+ _filedir -d
+ return 0
+ ;;
+ -@(I|D|R))
+ # label completion
+ _lilo_labels
+ return 0
+ ;;
+ -@(A|b|M|u|U))
+ # device completion
+ cur=${cur:=/dev/}
+ _filedir
+ return 0
+ ;;
+ -T)
+ # topic completion
+ COMPREPLY=( $( compgen -W 'help ChRul EBDA geom geom= \
+ table= video' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ # relevant options completion
+ COMPREPLY=( $( compgen -W '-A -b -c -C -d -f -g -i -I -l -L -m \
+ -M -p -P -q -r -R -s -S -t -T -u -U -v -V -w -x -z' -- \
+ $cur ) )
+ fi
+}
+complete -F _lilo lilo
+}
+
+# links completion
+#
+have links &&
+_links()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ case "$cur" in
+ --*)
+ COMPREPLY=( $( compgen -W '--help' -- $cur ) )
+ ;;
+ -*)
+ COMPREPLY=( $( compgen -W '-async-dns -max-connections \
+ -max-connections-to-host -retries \
+ -receive-timeout -unrestartable-receive-timeout\
+ -format-cache-size -memory-cache-size \
+ -http-proxy -ftp-proxy -download-dir \
+ -assume-codepage -anonymous -dump -no-connect \
+ -source -version -help' -- $cur ) )
+ ;;
+ *)
+ if [ -r ~/.links/links.his ]; then
+ COMPREPLY=( $( compgen -W '$( < ~/.links/links.his )' \
+ -- $cur ) )
+ fi
+ _filedir '@(htm|html)'
+ return 0
+ ;;
+ esac
+
+ return 0
+} &&
+complete -F _links $filenames links
+
+[ $UNAME = FreeBSD ] && {
+# FreeBSD package management tool completion
+#
+_pkg_delete()
+{
+ local cur pkgdir prev
+
+ pkgdir=${PKG_DBDIR:-/var/db/pkg}/
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ [ "$prev" = "-o" -o "$prev" = "-p" -o "$prev" = "-W" ] && return 0
+
+ COMPREPLY=( $( compgen -d $pkgdir$cur ) )
+ COMPREPLY=( ${COMPREPLY[@]#$pkgdir} )
+
+ return 0
+}
+complete -F _pkg_delete $dirnames pkg_delete pkg_info
+have pkg_deinstall && complete -F _pkg_delete $dirnames pkg_deinstall
+
+# FreeBSD kernel module commands
+#
+_kldload()
+{
+ local cur moddir
+
+ moddir=/modules/
+ [ -d $moddir ] || moddir=/boot/kernel/
+ cur=`_get_cword`
+
+ COMPREPLY=( $( compgen -f $moddir$cur ) )
+ COMPREPLY=( ${COMPREPLY[@]#$moddir} )
+ COMPREPLY=( ${COMPREPLY[@]%.ko} )
+
+ return 0
+}
+complete -F _kldload $filenames kldload
+
+_kldunload()
+{
+ local cur
+ cur=`_get_cword`
+ COMPREPLY=( $(kldstat | sed -ne "s/^.*[ \t]\+\($cur[a-z_]\+\).ko$/\1/p") )
+}
+complete -F _kldunload $filenames kldunload
+}
+
+# FreeBSD portupgrade completion
+#
+have portupgrade &&
+_portupgrade()
+{
+ local cur pkgdir prev
+
+ pkgdir=${PKG_DBDIR:-/var/db/pkg}/
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ [ "$prev" = "-l" -o "$prev" = "-L" -o "$prev" = "-o" ] && return 0
+
+ COMPREPLY=( $( compgen -d $pkgdir$cur ) )
+ COMPREPLY=( ${COMPREPLY[@]#$pkgdir} )
+ COMPREPLY=( ${COMPREPLY[@]%-*} )
+
+ return 0
+} &&
+complete -F _portupgrade $dirnames portupgrade
+
+# FreeBSD portinstall completion
+#
+have portinstall &&
+_portinstall()
+{
+ local cur portsdir prev indexfile
+ local -a COMPREPLY2
+
+ portsdir=${PORTSDIR:-/usr/ports}/
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ # First try INDEX-5
+ indexfile=$portsdir/INDEX-5
+ # Then INDEX if INDEX-5 does not exist or system is not FreeBSD 5.x
+ [ "${OSTYPE%.*}" = "freebsd5" -a -f $indexfile ] ||
+ indexfile=$portsdir/INDEX
+
+ [ "$prev" = "-l" -o "$prev" = "-L" -o "$prev" = "-o" ] && return 0
+
+ COMPREPLY=( $( egrep "^$cur" < $indexfile | cut -d'|' -f1 ) )
+ COMPREPLY2=( $( egrep "^[^\|]+\|$portsdir$cur" < $indexfile | \
+ cut -d'|' -f2 ) )
+ COMPREPLY2=( ${COMPREPLY2[@]#$portsdir} )
+ COMPREPLY=( "${COMPREPLY[@]}" "${COMPREPLY2[@]}" )
+
+ return 0
+} &&
+complete -F _portinstall $dirnames portinstall
+
+# Slackware Linux removepkg completion
+#
+have removepkg && [ -f /etc/slackware-version ] &&
+_removepkg()
+{
+ local packages cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( (cd /var/log/packages; compgen -f -- "$cur") ) )
+} &&
+complete -F _removepkg $filenames removepkg &&
+ complete $dirnames -f -X '!*.tgz' installpkg upgradepkg explodepkg
+
+# look(1) completion
+#
+have look &&
+_look()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD = 1 ]; then
+ COMPREPLY=( $( compgen -W '$(look $cur)' ) )
+ fi
+} &&
+complete -F _look $default look
+
+# ypcat(1) and ypmatch(1) completion
+#
+have ypmatch &&
+_ypmatch()
+{
+ local cur map
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ [ $1 = ypcat ] && [ $COMP_CWORD -gt 1 ] && return 0
+ [ $1 = ypmatch ] && [ $COMP_CWORD -gt 2 ] && return 0
+
+ if [ $1 = ypmatch ] && [ $COMP_CWORD -eq 1 ] && \
+ [ ${#COMP_WORDS[@]} -eq 3 ]; then
+ map=${COMP_WORDS[2]}
+ COMPREPLY=( $( compgen -W '$( ypcat $map | \
+ cut -d':' -f 1 )' -- $cur) )
+ else
+ [ $1 = ypmatch ] && [ $COMP_CWORD -ne 2 ] && return 0
+ COMPREPLY=( $( compgen -W \
+ '$( echo $(ypcat -x | cut -d"\"" -f 2))' -- $cur))
+ fi
+
+ return 0
+} &&
+complete -F _ypmatch ypmatch ypcat
+
+# mplayer(1) completion
+#
+have mplayer && {
+_mplayer_options_list()
+{
+ cur=${cur%\\}
+ COMPREPLY=( $( $1 $2 help 2> /dev/null | \
+ sed -e '1,/^Available/d' | awk '{print $1}' | \
+ sed -e 's/:$//' -e 's/^'${2#-}'$//' -e 's/<.*//' | \
+ grep "^$cur" ) )
+}
+
+_mplayer()
+{
+ local cmd cur prev skinsdir IFS=$' \t\n' i j k=0
+
+ COMPREPLY=()
+ cmd=${COMP_WORDS[0]}
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(ac|afm|vc|vfm|ao|vo|vop|fstype))
+ _mplayer_options_list mplayer $prev
+ return 0
+ ;;
+ -@(oac|ovc|of))
+ _mplayer_options_list mencoder $prev
+ return 0
+ ;;
+ -audiofile)
+ _filedir '@(mp3|MP3|mpg|MPG|ogg|OGG|wav|WAV|mid|MID|flac|FLAC|mka|MKA)'
+ return 0
+ ;;
+ -font)
+ _filedir '@(desc|ttf)'
+ return 0
+ ;;
+ -sub)
+ _filedir '@(srt|SRT|sub|SUB|txt|TXT|utf|UTF|rar|RAR|mpsub|smi|js|ssa|SSA|aas|AAS)'
+ return 0
+ ;;
+ -vobsub)
+ _filedir '@(idx|IDX|ifo|IFO|sub|SUB)'
+ IFS=$'\t\n'
+ COMPREPLY=( $( for i in "${COMPREPLY[@]}"; do
+ if [ -f $i -a -r $i ]; then
+ echo ${i%.*}
+ else
+ echo $i
+ fi
+ done ) )
+ IFS=$' \t\n'
+ return 0
+ ;;
+ -ifo)
+ _filedir '@(ifo|IFO)'
+ return 0
+ ;;
+ -cuefile)
+ _filedir '@(bin|BIN|cue|CUE)'
+ return 0
+ ;;
+ -skin)
+ # if you don't have installed mplayer in /usr you
+ # may want to set the MPLAYER_SKINS_DIR global variable
+ if [ -n "$MPLAYER_SKINS_DIR" ]; then
+ skinsdir=$MPLAYER_SKINS_DIR
+ else
+ skinsdir=/usr/share/mplayer/Skin
+ fi
+
+ IFS=$'\t\n'
+ for i in ~/.mplayer/Skin $skinsdir; do
+ if [ -d $i -a -r $i ]; then
+ for j in $( compgen -d $i/$cur ); do
+ COMPREPLY[$k]=${j#$i/}
+ k=$((++k))
+ done
+ fi
+ done
+ IFS=$' \t\n'
+ return 0
+ ;;
+ -@(mixer|@(cdrom|dvd)-device|dvdauth|fb|zrdev))
+ cur=${cur:=/dev/}
+ _filedir
+ return 0
+ ;;
+ -@(edl?(out)|lircconf|menu-cfg|playlist|csslib|dumpfile)| \
+ -@(subfile|vobsub|aofile|fbmodeconfig|include|o|dvdkey)| \
+ -passlogfile)
+ _filedir
+ return 0
+ ;;
+ -@(auto@(q|sync)|loop|menu-root|speed|sstep|aid|alang)| \
+ -@(?(@(audio|sub)-)demuxer|bandwidth|cache|chapter)| \
+ -@(dvd?(angle)|fps|frames|mc|passwd|user|sb|srate|ss|vcd)| \
+ -@(vi?(d|vo)|ffactor|sid|slang|spu@(align|aa|gauss))| \
+ -@(vobsubid|delay|bpp|brightness|contrast|dfbopts|display)| \
+ -@(fbmode|geometry|guiwid|hue|icelayer|screen[wh]|wid)| \
+ -@(monitor@(aspect|-@(dotclock|[hv]freq))|panscan|saturation)| \
+ -@(xineramascreen|zr@(crop|norm|quality|[xy]doff|[vh]dec))| \
+ -@(aspect|pp|x|y|xy|z|stereo|audio-@(density|delay|preload))| \
+ -@(endpos|osdlevel|ffourcc|sws|channels|skiplimit|format)| \
+ -@(ofps|aa@(driver|@(osd|sub)color)|vobsubout?(i@(ndex|d)))| \
+ -sub@(-bg-@(alpha|color)|cp|delay|fps|pos|align|width)| \
+ -sub@(font-@(blur|outline|autoscale|encoding|@(osd|text)-scale)))
+ return 0
+ ;;
+ -lavdopts)
+ COMPREPLY=( $( compgen -W 'ec er= bug= idct= gray' \
+ -- $cur ) )
+ return 0
+ ;;
+ -lavcopts)
+ COMPREPLY=( $( compgen -W 'vcodec= vqmin= vqscale= \
+ vqmax= mbqmin= mbqmax= vqdiff= \
+ vmax_b_frames= vme= vhq v4mv \
+ keyint= vb_strategy= vpass= \
+ aspect= vbitrate= vratetol= \
+ vrc_maxrate= vrc_minrate= \
+ vrc_buf_size= vb_qfactor= vi_qfactor= \
+ vb_qoffset= vi_qoffset= vqblur= \
+ vqcomp= vrc_eq= vrc_override= \
+ vrc_init_cplx= vqsquish= vlelim= \
+ vcelim= vstrict= vdpart vpsize= gray \
+ vfdct= idct= lumi_mask= dark_mask= \
+ tcplx_mask= scplx_mask= naq ildct \
+ format= pred qpel precmp= cmp= \
+ subcmp= predia= dia= trell last_pred= \
+ preme= subq= psnr mpeg_quant aic umv' \
+ -- $cur ) )
+ return 0
+ ;;
+ -ssf)
+ COMPREPLY=( $( compgen -W 'lgb= cgb= ls= cs= chs= \
+ cvs=' -- $cur ) )
+ return 0
+ ;;
+ -jpeg)
+ COMPREPLY=( $( compgen -W 'noprogressive progressive \
+ nobaseline baseline optimize= \
+ smooth= quality= outdir=' -- $cur ) )
+ return 0
+ ;;
+ -xvidopts)
+ COMPREPLY=( $( compgen -W 'dr2 nodr2' -- $cur ) )
+ return 0
+ ;;
+ -xvidencopts)
+ COMPREPLY=( $( compgen -W 'pass= bitrate= \
+ fixed_quant= me_quality= 4mv \
+ rc_reaction_delay_factor= \
+ rc_averaging_period= rc_buffer= \
+ quant_range= min_key_interval= \
+ max_key_interval= mpeg_quant \
+ mod_quant lumi_mask hintedme \
+ hintfile debug keyframe_boost= \
+ kfthreshold= kfreduction=' -- $cur ) )
+ return 0
+ ;;
+ -divx4opts)
+ COMPREPLY=( $( compgen -W 'br= key= deinterlace q= \
+ min_quant= max_quant= rc_period= \
+ rc_reaction_period= crispness= \
+ rc_reaction_ratio= pass= vbrpass= \
+ help' -- $cur ) )
+ return 0
+ ;;
+ -info)
+ COMPREPLY=( $( compgen -W 'name= artist= genre= \
+ subject= copyright= srcform= \
+ comment= help' -- $cur ) )
+ return 0
+ ;;
+ -lameopts)
+ COMPREPLY=( $( compgen -W 'vbr= abr cbr br= q= aq= \
+ ratio= vol= mode= padding= fast \
+ preset= help' -- $cur ) )
+ return 0
+ ;;
+ -rawaudio)
+ COMPREPLY=( $( compgen -W 'on channels= rate= \
+ samplesize= format=' -- $cur ) )
+ return 0
+ ;;
+ -rawvideo)
+ COMPREPLY=( $( compgen -W 'on fps= sqcif qcif cif \
+ 4cif pal ntsc w= h= y420 yv12 yuy2 \
+ y8 format= size=' -- $cur ) )
+ return 0
+ ;;
+ -aop)
+ COMPREPLY=( $( compgen -W 'list= delay= format= fout= \
+ volume= mul= softclip' -- $cur ) )
+ return 0
+ ;;
+ -dxr2)
+ COMPREPLY=( $( compgen -W 'ar-mode= iec958-encoded \
+ iec958-decoded mute ucode= 75ire bw \
+ color interlaced macrovision= norm= \
+ square-pixel ccir601-pixel cr-left= \
+ cr-right= cr-top= cr-bot= ck-rmin= \
+ ck-gmin= ck-bmin= ck-rmax= ck-gmax= \
+ ck-bmax= ck-r= ck-g= ck-b= \
+ ignore-cache= ol-osd= olh-cor= \
+ olw-cor= olx-cor= oly-cor= overlay \
+ overlay-ratio= update-cache' -- $cur ))
+ return 0
+ ;;
+ -tv)
+ COMPREPLY=( $( compgen -W 'on noaudio driver= device= \
+ input= freq= outfmt= width= height= \
+ buffersize= norm= channel= chanlist= \
+ audiorate= forceaudio alsa amode= \
+ forcechan= adevice= audioid= volume= \
+ bass= treble= balance= fps= \
+ channels= immediatemode=' -- $cur ) )
+ return 0
+ ;;
+ -mf)
+ COMPREPLY=( $( compgen -W 'on w= h= fps= type=' \
+ -- $cur ) )
+ return 0
+ ;;
+ -cdda)
+ COMPREPLY=( $( compgen -W 'speed= paranoia= \
+ generic-dev= sector-size= overlap= \
+ toc-bias toc-offset= skip noskip' \
+ -- $cur ) )
+ return 0
+ ;;
+ -input)
+ COMPREPLY=( $( compgen -W 'conf= ar-delay ar-rate \
+ keylist cmdlist js-dev file' -- $cur ) )
+ return 0
+ ;;
+ -af)
+ COMPREPLY=( $( compgen -W 'resample resample= \
+ channels channels= format format= \
+ volume volume= delay delay= pan \
+ pan= sub sub= surround surround=' \
+ -- $cur ) )
+ return 0
+ ;;
+ -af-adv)
+ COMPREPLY=( $( compgen -W 'force= list=' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ case "$cur" in
+ -*)
+ COMPREPLY=( $( compgen -W '-aid -alang -audio-demuxer \
+ -audiofile -cdrom-device -cache -cdda \
+ -channels -chapter -csslib -demuxer \
+ -dvd -dvd-device -dvdangle -dvdauth \
+ -dvdkey -dvdnav -forceidx -fps -frames \
+ -hr-mp3-seek -idx -mc -mf -ni -nobps \
+ -passwd -rawaudio -rtsp-stream-over-tcp\
+ -skipopening -sb -srate -ss -tv -user \
+ -vcd -vid -vivo -ifo -ffactor -font \
+ -noautosub -nooverlapsub -sid -slang \
+ -sub -subcc -subcp -sub-demuxer \
+ -subdelay -subfont-autoscale \
+ -subfont-blur -subfont-encoding \
+ -subfont-osd-scale -subfont-outline \
+ -subfont-text-scale -subfps -subfile \
+ -subpos -unicode -utf8 -vobsub \
+ -vobsubid -ac -afm -aspect -flip \
+ -lavdopts -noaspect -nosound -pp -ssf \
+ -stereo -sws -vc -vfm -vop -xvidopts\
+ -xy -zoom -bandwidth -cuefile \
+ -noextbased -rawvideo -overlapsub \
+ -sub-bg-alpha -sub-bg-color -subalign \
+ -subwidth -sub-no-text-pp -spualign \
+ -spuaa -spugauss -pphelp -verbose -v \
+ -noni -noidx -nohr-mp3-seek -extbased \
+ -bps -oldpp -nozoom -noflip -nounicode \
+ -noutf8' -- $cur ) )
+ # add mplayer specific options
+ [[ "$cmd" == @(?(g)mplayer) ]] && COMPREPLY=( "${COMPREPLY[@]}" \
+ $(compgen -W '-autoq -autosync -benchmark \
+ -framedrop -h -help -hardframedrop \
+ -identify -input -lircconf -loop \
+ -nojoystick -nolirc -nortc -playlist \
+ -quiet -really-quiet -rnd -sdp -skin \
+ -slave -softsleep -speed -sstep \
+ -use-stdin -dumpaudio -dumpfile \
+ -dumpstream -dumpvideo -dumpmicrodvdsub\
+ -dumpmpsub -dumpsrtsub -dumpjacosub \
+ -dumpsami -dumpsub -osdlevel -af \
+ -af-adv -ao -aofile -aop -delay -mixer \
+ -nowaveheader -bpp -brightness \
+ -contrast -display -double -dr -dxr2 \
+ -fb -fbmode -fbmodeconfig -forcexv -fs \
+ -geometry -hue -icelayer -jpeg \
+ -monitor-dotclock -monitor-hfreq \
+ -monitor-vfreq -monitoraspect \
+ -nograbpointer -noslices -panscan \
+ -rootwin -saturation -screenw -screenh \
+ -stop-xscreensaver -vm -vo -vsync -wid \
+ -xineramascreen -z -zrbw -zrcrop \
+ -zrdev -zrfd -zrhelp -zrnorm -zrquality \
+ -zrvdec -zrhdec -zrxdoff -zrydoff -y \
+ -edl -edlout -enqueue -fixed-vo \
+ -menu -menu-root -menu-cfg -shuffle \
+ -format -aahelp -dfbopts -fstype \
+ -guiwid -nokeepaspect -x --help \
+ -aaosdcolor -aasubcolor -aadriver \
+ -aaextended -aaeight' -- $cur) )
+ # add mencoder specific options
+ [[ "$cmd" = mencoder ]] && COMPREPLY=( "${COMPREPLY[@]}" \
+ $(compgen -W '-audio-density -audio-delay \
+ -audio-preload -divx4opts -endpos \
+ -ffourcc -include -info -lameopts \
+ -lavcopts -noskip -o -oac -ofps -ovc \
+ -passlogfile -skiplimit -vobsubout \
+ -vobsuboutindex -vobsuboutid \
+ -xvidencopts -of --verbose' -- $cur) )
+ ;;
+ *)
+ _filedir '@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|ASF|vob|VOB|bin|BIN|dat|DAT|vcd|VCD|ps|PS|pes|PES|fli|FLI|flv|FLV|viv|VIV|rm?(j)|RM?(J)|ra?(m)|RA?(M)|yuv|YUV|mov|MOV|qt|QT|mp[34]|MP[34]|m4v|M4V|og[gm]|OG[GM]|wav|WAV|dump|DUMP|mk[av]|MK[AV]|m4a|M4A|aac|AAC|m2v|M2V|dv|DV|rmvb|RMVB|mid|MID|ts|TS|3gp|mpc|MPC|flac|FLAC|flv|FLV|divx|DIVX)'
+ ;;
+ esac
+
+ return 0
+}
+complete $filenames -F _mplayer mplayer mencoder gmplayer kplayer
+}
+
+# KDE dcop completion
+#
+have dcop &&
+_dcop()
+{
+ local cur compstr
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ if [ -z $cur ]; then
+ compstr=${COMP_WORDS[*]}
+ else
+ compstr=$( command echo ${COMP_WORDS[*]} | sed "s/ $cur$//" )
+ fi
+ COMPREPLY=( $( compgen -W '$( command $compstr | sed s/\(.*\)// )' -- $cur ) )
+} &&
+complete -F _dcop dcop
+
+# wvdial(1) completion
+#
+have wvdial &&
+_wvdial()
+{
+ local cur prev config i IFS=$'\t\n'
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ --config)
+ _filedir
+ return 0
+ ;;
+ esac
+
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '--config --chat \
+ --remotename --help --version --no-syslog' \
+ -- $cur ) )
+ ;;
+ *)
+ # start with global and personal config files
+ config="/etc/wvdial.conf"$'\t'"$HOME/.wvdialrc"
+ # replace with command line config file if present
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" == "--config" ]]; then
+ config=${COMP_WORDS[i+1]}
+ break
+ fi
+ done
+ # parse config files for sections and
+ # remove default section
+ COMPREPLY=( $( sed -ne \
+ "s|^\[Dialer \($cur.*\)\]$|\1|p" \
+ $config 2>/dev/null |grep -v '^Defaults$'))
+ # escape spaces
+ COMPREPLY=${COMPREPLY// /\\ }
+ ;;
+ esac
+
+} &&
+complete -F _wvdial wvdial
+
+# gpg(1) completion
+#
+have gpg &&
+_gpg()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(s|-sign|-clearsign|-decrypt-files|-load-extension))
+ _filedir
+ return 0
+ ;;
+ --@(export|@(?(l|nr|nrl)sign|edit)-key))
+ # return list of public keys
+ COMPREPLY=( $( compgen -W "$( gpg --list-keys 2>/dev/null | sed -ne 's@^pub.*/\([^ ]*\).*\(<\([^>]*\)>\).*$@\1 \3@p')" -- "$cur" ))
+ return 0
+ ;;
+ -@(r|-recipient))
+ COMPREPLY=( $( compgen -W "$( gpg --list-keys 2>/dev/null | sed -ne 's@^pub.*<\([^>]*\)>.*$@\1@p')" -- "$cur" ))
+ if [ -e ~/.gnupg/gpg.conf ]; then
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$( sed -ne 's@^[ \t]*group[ \t][ \t]*\([^=]*\).*$@\1@p' ~/.gnupg/gpg.conf )" -- "$cur") )
+ fi
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-s -b -e -f -c -d -a -r -u -Z -o -v\
+ -q -n -N $(gpg --dump-options)' -- $cur ) )
+ fi
+
+} &&
+complete -F _gpg $default gpg
+
+# iconv(1) completion
+#
+have iconv &&
+_iconv()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(f|t|-@(from|to)-code))
+ COMPREPLY=( $( compgen -W \
+ '$( iconv --list | sed -e "s@//@@;" )' -- "$cur" ) )
+ return 0
+ ;;
+ esac
+
+
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $( compgen -W '--from-code -f --to-code -t --list
+ --output -o --verbose' -- "$cur" ) )
+ return 0
+ fi
+} &&
+complete -F _iconv $default iconv
+
+# dict(1) completion
+#
+{ have dict || have rdict; } && {
+_dictdata()
+{
+ dict $host $port $1 2>/dev/null | sed -ne \
+ 's/^['$'\t '']['$'\t '']*\([^'$'\t '']*\).*$/\1/p'
+}
+
+_dict()
+{
+ local cur prev host port db dictfile
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ dictfile=/usr/share/dict/words
+
+ for (( i=1; i < COMP_CWORD; i++ )); do
+ case "${COMP_WORDS[i]}" in
+ -@(h|--host))
+ host=${COMP_WORDS[i+1]}
+ [ -n "$host" ] && host="-h $host"
+ i=$((++i))
+ ;;
+ -@(p|-port))
+ port=${COMP_WORDS[i+1]}
+ [ -n "$port" ] && port="-p $port"
+ i=$((++i))
+ ;;
+ -@(d|-database))
+ db=${COMP_WORDS[i+1]}
+ [ -n "$db" ] && host="-d $db"
+ i=$((++i))
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ if [[ "$cur" = -* ]]; then
+ COMPREPLY=( $( compgen -W '-h --host -p --port -d --database \
+ -m --match -s --strategy -c --config -C \
+ --nocorrect -D --dbs -S --strats -H \
+ --serverhelp -i --info -I --serverinfo \
+ -a --noauth -u --user -k --key -V --version \
+ -L --license --help -v --verbose -r --raw \
+ -P --pager --debug --html --pipesize --client' \
+ -- "$cur" ) )
+ return 0
+ fi
+
+ case "$prev" in
+ -@(d|-database|i|info))
+ COMPREPLY=( $( compgen -W '$( _dictdata -D )' -- "$cur" ) )
+ return 0
+ ;;
+ -@(s|-strategy))
+ COMPREPLY=( $( compgen -W '$( _dictdata -S )' -- "$cur" ) )
+ return 0
+ ;;
+ *)
+ ;;
+ esac
+
+ [ -r $dictfile ] && \
+ COMPREPLY=( $( compgen -W '$( cat $dictfile )' -- "$cur" ) )
+}
+complete -F _dict $default dict rdict
+}
+
+# cdrecord(1) completion
+#
+have cdrecord &&
+_cdrecord()
+{
+ local cur prev i generic_options track_options track_mode
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # foo=bar style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case "$prev" in
+ @(text|cue)file)
+ _filedir
+ return 0
+ ;;
+ blank)
+ COMPREPLY=( $( compgen -W 'help all fast \
+ track unreserve trtail unclose session' \
+ -- $cur ) )
+ return 0
+ ;;
+ driveropts)
+ COMPREPLY=( $( compgen -W 'burnfree noburnfree\
+ varirec= audiomaster forcespeed noforcespeed\
+ speedread nospeedread singlesession \
+ nosinglesession hidecdr nohidecdr tattooinfo\
+ tattoofile=' -- $cur ) )
+ return 0
+ ;;
+ esac
+ fi
+
+ generic_options=(-version -v -V -d -silent -s -force -immed -dummy \
+ -dao -raw -raw96r -raw96p -raw16 -multi -msinfo -toc \
+ -atip -fix -nofix -waiti -load -lock -eject -format \
+ -setdropts -checkdrive -prcap -inq -scanbus -reset \
+ -abort -overburn -ignsize -useinfo -packet -noclose \
+ -text debug= kdebug= kd= minbuf= speed= blank= fs= \
+ dev= gracetime= timeout= driver= driveropts= \
+ defpregap= pktsize= mcn= textfile= cuefile=)
+ track_options=(-audio -swab -data -mode2 -xa -xa1 -xa2 -xamix -cdi \
+ -isosize -pad padsize= -nopad -shorttrack -noshorttrack\
+ pregap= -preemp -nopreemp -copy -nocopy -scms tcsize= \
+ isrc= index=)
+ # look if previous was either a file or a track option
+ track_mode=0
+ if [ $COMP_CWORD -gt 1 ]; then
+ if [ -f "$prev" ]; then
+ track_mode=1
+ else
+ for (( i=0; i < ${#track_options[@]}; i++ )); do
+ if [[ "${track_options[i]}" == "$prev" ]]; then
+ track_mode=1
+ break
+ fi
+ done
+ fi
+ fi
+
+ # files are always eligible completion
+ _filedir
+ # track options are always available
+ COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W '${track_options[@]}' -- $cur ) )
+ # general options are no more available after file or track option
+ if [ $track_mode -eq 0 ]; then
+ COMPREPLY=( "${COMPREPLY[@]}" \
+ $( compgen -W '${generic_options[@]}' -- $cur ) )
+ fi
+
+} &&
+complete -F _cdrecord $filenames cdrecord
+
+# mkisofs(8) completion
+#
+have mkisofs &&
+_mkisofs()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(o|abstract|biblio|check-session|copyright|log-file|root-info|prep-boot|*-list))
+ _filedir
+ return 0
+ ;;
+ -*-charset)
+ COMPREPLY=( $( mkisofs -input-charset help 2>&1 | \
+ tail +3 | grep "^$cur") )
+ return 0
+ ;;
+ -uid)
+ _uids
+ return 0
+ ;;
+ -gid)
+ _gids
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-abstract -A -allow-lowercase \
+ -allow-multidot -biblio -cache-inodes \
+ -no-cache-inodes -b -eltorito-alt-boot -B -G \
+ -hard-disk-boot -no-emul-boot -no-boot \
+ -boot-load-seg -boot-load-size \
+ -boot-info-table -C -c -check-oldname \
+ -check-session -copyright -d -D -dir-mode \
+ -dvd-video -f -file-mode -gid -gui \
+ -graft-points -hide -hide-list -hidden \
+ -hidden-list -hide-joliet -hide-joliet-list \
+ -hide-joliet-trans-tbl -hide-rr-moved \
+ -input-charset -output-charset -iso-level -J \
+ -joliet-long -jcharset -l -L -log-file -m \
+ -exclude-list -max-iso9660-filenames -M -N \
+ -new-dir-mode -nobak -no-bak -force-rr -no-rr \
+ -no-split-symlink-components \
+ -no-split-symlink-fields -o -pad -no-pad \
+ -path-list -P -p -print-size -quiet -R -r \
+ -relaxed-filenames -sort -split-output \
+ -stream-media-size -stream-file-name -sysid -T\
+ -table-name -ucs-level -udf -uid \
+ -use-fileversion -U -no-iso-translate -V \
+ -volset -volset-size -volset-seqno -v -x -z \
+ -hfs -apple -map -magic -hfs-creator \
+ -hfs-type -probe -no-desktop -mac-name \
+ -boot-hfs-file -part -auto -cluster-size \
+ -hide-hfs -hide-hfs-list -hfs-volid \
+ -icon-position -root-info -prep-boot \
+ -input-hfs-charset -output-hfs-charset \
+ -hfs-unlock -hfs-bless -hfs-parms --cap \
+ --netatalk --double --ethershare --ushare \
+ --exchange --sgi --xinet --macbin --single \
+ --dave --sfm --osx-double --osx-hfs' -- $cur ))
+ else
+ _filedir
+ fi
+
+} &&
+complete -F _mkisofs $filenames mkisofs
+
+# mc(1) completion
+#
+have mc &&
+_mc()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # -name value style option
+ case "$prev" in
+ -@(e|v|l|P))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ # --name=value style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case "$prev" in
+ --@(edit|view|ftplog|printwd))
+ _filedir
+ return 0
+ ;;
+ esac
+ fi
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a --stickchars -b --nocolor -c \
+ --color -C --colors= -d --nomouse -e --edit= -f \
+ --datadir -k --resetsoft -l --ftplog= -P --printwd= \
+ -s --slow -t --termcap -u --nosubshell -U --subshell \
+ -v --view= -V --version -x --xterm -h --help' -- $cur ) )
+ else
+ _filedir -d
+ fi
+} &&
+complete -F _mc $filenames mc
+
+# yum(8) completion
+#
+have yum && {
+_yum()
+{
+ local cur prev special
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ )); do
+ if [[ ${COMP_WORDS[i]} == @(install|update|upgrade|remove|erase|deplist) ]]; then
+ special=${COMP_WORDS[i]}
+ fi
+ done
+
+ if [ -n "$special" ]; then
+ case $special in
+ install|deplist)
+ COMPREPLY=( $( compgen -W '$( yum -C list | cut -d" " -f1 )' -- $cur ) )
+ return 0
+ ;;
+ *)
+ _rpm_installed_packages
+ return 0
+ ;;
+ esac
+ fi
+
+ case $cur in
+ --*)
+ COMPREPLY=( $( compgen -W '--installroot --version --help --enablerepo --disablerepo --exclude --obsoletes --noplugins' -- $cur ) )
+ return 0
+ ;;
+ -*)
+ COMPREPLY=( $( compgen -W '-c -e -d -y -t -R -C -h' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ case $prev in
+ list)
+ COMPREPLY=( $( compgen -W 'all available updates installed extras obsoletes recent' -- $cur ) )
+ ;;
+ clean)
+ COMPREPLY=( $( compgen -W 'packages headers metadata cache dbcache all' -- $cur ) )
+ ;;
+ localinstall)
+ _filedir rpm
+ ;;
+ -c)
+ _filedir
+ ;;
+ --installroot)
+ _filedir -d
+ ;;
+ *)
+ COMPREPLY=( $( compgen -W 'install update check-update upgrade remove list \
+ search info provides clean groupinstall groupupdate \
+ grouplist deplist erase groupinfo groupremove \
+ localinstall localupdate makecache resolvedep \
+ shell whatprovides' -- $cur ) )
+ ;;
+ esac
+}
+complete -F _yum $filenames yum
+
+# yum-arch(8) completion
+#
+_yum_arch()
+{
+ local cur
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ case "$cur" in
+ -*)
+ COMPREPLY=( $( compgen -W '-d -v -vv -n -c -z -s -l -q' -- $cur ) )
+ ;;
+ *)
+ _filedir -d
+ ;;
+ esac
+
+ return 0
+
+}
+complete -F _yum_arch $filenames yum-arch
+}
+
+# ImageMagick completion
+#
+have convert && {
+_ImageMagick()
+{
+ local prev
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -channel)
+ COMPREPLY=( $( compgen -W 'Red Green Blue Opacity \
+ Matte Cyan Magenta Yellow Black' -- $cur ) )
+ return 0
+ ;;
+ -colormap)
+ COMPREPLY=( $( compgen -W 'shared private' -- $cur ) )
+ return 0
+ ;;
+ -colorspace)
+ COMPREPLY=( $( compgen -W 'GRAY OHTA RGB Transparent \
+ XYZ YCbCr YIQ YPbPr YUV CMYK' -- $cur ) )
+ return 0
+ ;;
+ -compose)
+ COMPREPLY=( $( compgen -W 'Over In Out Atop Xor Plus \
+ Minus Add Subtract Difference Multiply Bumpmap\
+ Copy CopyRed CopyGreen CopyBlue CopyOpacity' \
+ -- $cur ) )
+ return 0
+ ;;
+ -compress)
+ COMPREPLY=( $( compgen -W 'None BZip Fax Group4 JPEG \
+ Lossless LZW RLE Zip' -- $cur ) )
+ return 0
+ ;;
+ -dispose)
+ COMPREPLY=( $( compgen -W 'Undefined None Background \
+ Previous' -- $cur ) )
+ return 0
+ ;;
+ -encoding)
+ COMPREPLY=( $( compgen -W 'AdobeCustom AdobeExpert \
+ AdobeStandard AppleRoman BIG5 GB2312 Latin2 \
+ None SJIScode Symbol Unicode Wansung' -- $cur))
+ return 0
+ ;;
+ -endian)
+ COMPREPLY=( $( compgen -W 'MSB LSB' -- $cur ) )
+ return 0
+ ;;
+ -filter)
+ COMPREPLY=( $( compgen -W 'Point Box Triangle Hermite \
+ Hanning Hamming Blackman Gaussian Quadratic \
+ Cubic Catrom Mitchell Lanczos Bessel Sinc' \
+ -- $cur ) )
+ return 0
+ ;;
+ -format)
+ COMPREPLY=( $( convert -list format | \
+ awk '/ [r-][w-][+-] / {print $1}' | \
+ tr -d '*' | tr [:upper:] [:lower:] | \
+ grep "^$cur" ) )
+ return 0
+ ;;
+ -gravity)
+ COMPREPLY=( $( compgen -W 'Northwest North NorthEast \
+ West Center East SouthWest South SouthEast' \
+ -- $cur ) )
+ return 0
+ ;;
+ -intent)
+ COMPREPLY=( $( compgen -W 'Absolute Perceptual \
+ Relative Saturation' -- $cur ) )
+ return 0
+ ;;
+ -interlace)
+ COMPREPLY=( $( compgen -W 'None Line Plane Partition' \
+ -- $cur ) )
+ return 0
+ ;;
+ -limit)
+ COMPREPLY=( $( compgen -W 'Disk File Map Memory' \
+ -- $cur ) )
+ return 0
+ ;;
+ -list)
+ COMPREPLY=( $( compgen -W 'Delegate Format Magic \
+ Module Resource Type' -- $cur ) )
+ return 0
+ ;;
+ -map)
+ COMPREPLY=( $( compgen -W 'best default gray red \
+ green blue' -- $cur ) )
+ _filedir
+ return 0
+ ;;
+ -noise)
+ COMPREPLY=( $( compgen -W 'Uniform Gaussian \
+ Multiplicative \
+ Impulse Laplacian Poisson' -- $cur ) )
+ return 0
+ ;;
+ -preview)
+ COMPREPLY=( $( compgen -W 'Rotate Shear Roll Hue \
+ Saturation Brightness Gamma Spiff \
+ Dull Grayscale Quantize Despeckle \
+ ReduceNoise AddNoise Sharpen Blur \
+ Treshold EdgeDetect Spread Shade \
+ Raise Segment Solarize Swirl Implode \
+ Wave OilPaint CharcoalDrawing JPEG' \
+ -- $cur ) )
+ return 0
+ ;;
+ -@(mask|profile|texture|tile|write))
+ _filedir
+ return 0
+ ;;
+ -type)
+ COMPREPLY=( $( compgen -W 'Bilevel Grayscale Palette \
+ PaletteMatte TrueColor TrueColorMatte \
+ ColorSeparation ColorSeparationlMatte \
+ Optimize' -- $cur ) )
+ return 0
+ ;;
+ -units)
+ COMPREPLY=( $( compgen -W 'Undefined PixelsPerInch \
+ PixelsPerCentimeter' -- $cur ) )
+ return 0
+ ;;
+ -virtual-pixel)
+ COMPREPLY=( $( compgen -W 'Constant Edge mirror tile' \
+ -- $cur ) )
+ return 0
+ ;;
+ -visual)
+ COMPREPLY=( $( compgen -W 'StaticGray GrayScale \
+ StaticColor PseudoColor TrueColor \
+ DirectColor defaut visualid' -- $cur ))
+ return 0
+ ;;
+ esac
+}
+
+_convert()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-adjoin -affine -antialias -append \
+ -authenticate -average -background -black-threshold \
+ -blue-primary -blur -border -bordercolor -channel \
+ -charcoal -chop -clip -coalesce -colorize -colors \
+ -colorspace -comment -compress -contrast -convolve \
+ -crop -cycle -debug -deconstruct -delay -density \
+ -depth -despeckle -display -dispose -dither -draw \
+ -edge -emboss -encoding -endian -enhance -equalize \
+ -extract -fill -filter -flatten -flip -flop -font \
+ -frame -fuzz -gamma -gaussian -geometry \
+ -green-primary -gravity -help -implode -intent \
+ -interlace -label -lat -level -limit -list -log -loop \
+ -map -mask -matte -median -modulate -monochrome \
+ -morph -mosaic -negate -noop -noise -normalize \
+ -opaque -ordered-dither -page -paint -ping -pointsize \
+ -preview -profile -quality -raise -random-threshold \
+ -region -raise -red-primary -render -resize -resample \
+ -roll -rotate -sample -sampling-factor -scale -scene \
+ -seed -segment -shade -sharpen -shave -shear -size \
+ -solarize -spread -stroke -strokewidth -swirl \
+ -texture -threshold -thumbnail -tile -transform \
+ -transparent -treedepth -trim -type -undercolor \
+ -units -unsharp -verbose -version -view \
+ -virtual-pixel -wave -white-point -white-threshold \
+ -write' -- $cur ) )
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+adjoin +append +compress \
+ +contrast +debug +dither +endian +gamma +label +map \
+ +mask +matte +negate +noise +page +raise +render \
+ +write' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _convert $filenames convert
+
+_mogrify()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-affine -antialias -authenticate \
+ -background -black-threshold -blue-primary -blur \
+ -border -bordercolor -channel -charcoal -chop \
+ -colorize -colors -colorspace -comment -compress \
+ -contrast -convolve -crop -cycle -debug -delay \
+ -density -depth -despeckle -display -dispose -dither \
+ -draw -edge -emboss -encoding -endian -enhance \
+ -equalize -extract -fill -filter -flip -flop -font \
+ -format -frame -fuzz -gamma -gaussian -geometry \
+ -green-primary -implode -interlace -help -label -lat \
+ -level -limit -list -log -loop -map -mask -matte \
+ -median -modulate -monochrome -negate -noop \
+ -normalize -opaque -page -paint -fill -ordered-dither \
+ -pointsize -profile -quality -raise -random-threshold \
+ -red-primary -region -resample -resize -roll -rotate \
+ -sample -sampling-factor -scale -scene -seed -segment \
+ -shade -sharpen -shear -size -solarize -spread \
+ -stroke -strokewidth -swirl -texture -threshold \
+ -thumbnail -tile -transform -transparent -treedepth \
+ -trim -type -undercolor -units -unsharp -verbose \
+ -version -view -virtual-pixel -wave -white-point \
+ -white-threshold' -- $cur ) )
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+compress +contrast +debug +dither \
+ +endian +gamma +label +map +mask +matte +negate +page \
+ +raise' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _mogrify $filenames mogrify
+
+_display()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-authenticate -backdrop -border \
+ -colormap -colors -colorspace -comment -compress \
+ -contrast -crop -debug -delay -density -depth \
+ -despeckle -display -dispose -dither -edge -endian \
+ -enhance -extract -filter -flip -flop -frame -gamma \
+ -geometry -help -immutable -interlace -label -limit \
+ -log -map -matte -monochrome -negate -noop -page \
+ -quality -raise -remote -roll -rotate -sample \
+ -sampling-factor -scene -segment -sharpen -size \
+ -texture -treedepth -trim -update -verbose -version \
+ -virtual-pixel -window -window_group -write' -- $cur))
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+compress +contrast +debug +dither \
+ +endian +gamma +label +map +matte +negate +page \
+ +raise +write' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _display $filenames display
+
+_animate()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-authenticate -backdrop -colormap \
+ -colors -colorspace -crop -debug -delay -density \
+ -depth -display -dither -extract -gamma -geometry \
+ -help -interlace -limit -log -matte -map -monochrome \
+ -noop -pause -remote -rotate -sampling-factor -scene \
+ -size -treedepth -trim -verbose -version -visual \
+ -virtual-pixel -window' -- $cur ) )
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+debug +dither +gamma +map +matte' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _animate $filenames animate
+
+_identify()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-authenticate -debug -density \
+ -depth -extract -format -help -interlace -limit -list \
+ -log -size -sampling-factor -verbose -version \
+ -virtual-pixel' -- $cur ) )
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+debug ' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _identify $filenames identify
+
+_montage()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-adjoin -affine -authenticate \
+ -blue-primary -blur -colors -colorspace -comment \
+ -compose -compress -crop -debug -density -depth \
+ -display -dispose -dither -draw -encoding -endian \
+ -extract -fill -filter -flip -flop -frame -gamma \
+ -geometry -gravity -green-primary -interlace -help \
+ -label -limit -log -matte -mode -monochrome -noop \
+ -page -pointsize -quality -red-primary -resize \
+ -rotate -sampling-factor -scene -shadow -size \
+ -stroke -texture -thumbnail -tile -transform \
+ -transparent -treedepth -trim -type -verbose \
+ -version -virtual-pixel -white-point' -- $cur ) )
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+adjoin +compress +debug +dither \
+ +endian +gamma +label +matte +page' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _montage $filenames montage
+
+_composite()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _ImageMagick
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-affine -authenticate \
+ -blue-primary -colors -colorspace -comment -compose \
+ -compress -debug -density -depth -displace -display \
+ -dispose -dissolve -dither -encoding -endian -extract \
+ -filter -font -geometry -gravity -green-primary -help \
+ -interlace -label -limit -log -matte -monochrome \
+ -negate -page -profile -quality -red-primary -rotate \
+ -resize -sampling-factor -scene -sharpen -size \
+ -stegano -stereo -thumbnail -tile -transform \
+ -treedepth -type -units -unsharp -verbose -version \
+ -virtual-pixel -watermark -white-point -write' \
+ -- $cur ) )
+ elif [[ "$cur" == +* ]]; then
+ COMPREPLY=( $( compgen -W '+compress +debug +dither +endian +label \
+ +matte +negate +page +write' -- $cur ) )
+ else
+ _filedir
+ fi
+}
+complete -F _composite $filenames composite
+}
+
+# dd(1) completion
+#
+have dd &&
+_dd()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ case "$cur" in
+ if=*|of=*)
+ cur=${cur#*=}
+ _filedir
+ return 0
+ ;;
+ conv=*)
+ cur=${cur#*=}
+ COMPREPLY=( $( compgen -W 'ascii ebcdic ibm block unblock \
+ lcase notrunc ucase swab noerror sync' \
+ -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ _expand || return 0
+
+ COMPREPLY=( $( compgen -W '--help --version' -- $cur ) \
+ $( compgen -W 'bs cbs conv count ibs if obs of seek skip'\
+ -S '=' -- $cur ) )
+} &&
+complete -F _dd $nospace $filenames dd
+
+# CUPS cancel(1) completion
+#
+have cancel &&
+_cancel()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( lpstat | cut -d' ' -f1 | grep "^$cur" ) )
+} &&
+complete -F _cancel $filenames cancel
+
+# aspell(1) completion
+#
+have aspell && {
+_aspell_dictionary()
+{
+ local datadir
+ datadir=/usr/lib/aspell
+ COMPREPLY=( $( command ls $datadir/*.@(multi|alias) ) )
+ COMPREPLY=( ${COMPREPLY[@]%.@(multi|alias)} )
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]#$datadir/}' -- $cur ) )
+}
+
+_aspell()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # --name value style option
+ case "$prev" in
+ @(-c|-p|check))
+ _filedir
+ return 0
+ ;;
+ @(dump|create|merge))
+ COMPREPLY=( $( compgen -W 'master personal repl' -- $cur ) )
+ return 0
+ ;;
+ -d)
+ _aspell_dictionary
+ return 0
+ ;;
+ esac
+
+ # --name=value style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case "$prev" in
+ --@(conf|personal|repl|per-conf))
+ _filedir
+ return 0
+ ;;
+ --@(conf-dir|data-dir|dict-dir|home-dir|local-data-dir|prefix))
+ _filedir -d
+ return 0
+ ;;
+ --master)
+ _aspell_dictionary
+ return 0
+ ;;
+ --mode)
+ COMPREPLY=( $( compgen -W 'none url email sgml tex' -- $cur ) )
+ return 0
+ ;;
+ --sug-mode)
+ COMPREPLY=( $( compgen -W 'ultra fast normal bad-speller' -- $cur ) )
+ return 0
+ ;;
+ --keymapping)
+ COMPREPLY=( $( compgen -W 'aspell ispell' -- $cur ) )
+ return 0
+ ;;
+ esac
+ fi
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--conf= --conf-dir= --data-dir= --dict-dir= \
+ --encoding= --add-filter= --rem-filter= --mode= -e \
+ -H -t --add-extra-dicts= --rem-extra-dicts= \
+ --home-dir= -W --ignore= --ignore-accents \
+ --dont-ignore-accents --ignore-case --dont-ignore-case \
+ --ignore-repl --dont-ignore-repl --jargon= --keyboard= \
+ --lang= --language-tag= --local-data-dir= -d --master= \
+ --module= --add-module-search-order= \
+ --rem-module-search-order= --per-conf= -p --personal= \
+ --prefix= --repl= -C -B --run-together --dont-run-together \
+ --run-together-limit= --run-together-min= --save-repl \
+ --dont-save-repl --set-prefix --dont-set-prefix --size= \
+ --spelling= --strip-accents --dont-strip-accents \
+ --sug-mode= --add-word-list-path= --rem-word-list-path= \
+ -b -x --backup -b|-x --dont-backup --reverse --dont-reverse \
+ --time --dont-time --keymapping= --add-email-quote= \
+ --rem-email-quote= --email-margin= --add-tex-command= \
+ --rem-tex-command= --tex-check-comments \
+ --dont-tex-check-comments --add-tex-extension= \
+ --rem-tex-extension= --add-sgml-check= --rem-sgml-check= \
+ --add-sgml-extension= --rem-sgml-extension=' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W '-? help -c check -a pipe -l list \
+ config config soundslike filter -v version dump \
+ create merge' -- $cur ) )
+ fi
+
+}
+complete -F _aspell $filenames aspell
+}
+
+# xmms(1) completion
+#
+have xmms &&
+_xmms()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-h --help -r --rew -p --play \
+ -u --pause -s --stop -t --play-pause -f --fwd -e \
+ --enqueue -m --show-main-window -i --sm-client-id \
+ -v --version' -- $cur ) )
+ else
+ _filedir '@(mp[23]|MP[23]|ogg|OGG|wav|WAV|pls|m3u|xm|mod|s[3t]m|it|mtm|ult|flac)'
+
+ fi
+
+} &&
+complete -F _xmms $filenames xmms
+
+# info(1) completion
+#
+have info &&
+_info()
+{
+ local cur infopath UNAME
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _expand || return 0
+
+ # default completion if parameter contains /
+ if [[ "$cur" == */* ]]; then
+ _filedir
+ return 0
+ fi
+
+ infopath='/usr/share/info'
+
+ if [ "${INFOPATH: -1:1}" == ':' ]; then
+ infopath=${INFOPATH}${infopath}
+ elif [ ${INFOPATH:+set} ]; then
+ infopath=$INFOPATH
+ fi
+
+ infopath=$infopath:
+ if [ -n "$cur" ]; then
+ infopath="${infopath//://$cur* }"
+ else
+ infopath="${infopath//:// }"
+ fi
+
+ # redirect stderr for when path doesn't exist
+ COMPREPLY=( $( eval command ls "$infopath" 2>/dev/null ) )
+ # weed out directory path names and paths to info pages
+ COMPREPLY=( ${COMPREPLY[@]##*/?(:)} )
+ # weed out info dir file
+ for (( i=0 ; i < ${#COMPREPLY[@]} ; ++i )); do
+ if [ "${COMPREPLY[$i]}" == 'dir' ]; then
+ unset COMPREPLY[$i];
+ fi;
+ done
+ # strip suffix from info pages
+ COMPREPLY=( ${COMPREPLY[@]%.@(gz|bz2)} )
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]%.*}' -- "${cur//\\\\/}" ) )
+
+ return 0
+} &&
+complete -F _info $filenames info
+
+# dhclient(1) completion
+#
+have dhclient && _dhclient()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(cf|lf|pf|sf))
+ _filedir
+ return 0
+ ;;
+ -s)
+ _known_hosts
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-p -d -q -1 -r -lf -pf \
+ -cf -sf -s -g -n -nw -w' -- $cur ) )
+ else
+ _available_interfaces
+ fi
+} &&
+complete -F _dhclient dhclient
+
+# lvm(8) completion
+#
+have lvm && {
+_volumegroups()
+{
+ COMPREPLY=( $(compgen -W "$( vgscan 2>/dev/null | \
+ sed -n -e 's|.*Found.*"\(.*\)".*$|\1|p' )" -- $cur ) )
+}
+
+_physicalvolumes()
+{
+ COMPREPLY=( $(compgen -W "$( pvscan 2>/dev/null | \
+ sed -n -e 's|^.*PV \(.*\) VG.*$|\1|p' )" -- $cur ) )
+}
+
+_logicalvolumes()
+{
+ COMPREPLY=( $(compgen -W "$( lvscan 2>/dev/null | \
+ sed -n -e "s|^.*'\(.*\)'.*$|\1|p" )" -- $cur ) )
+}
+
+_units()
+{
+ COMPREPLY=( $( compgen -W 'h s b k m g t H K M G T' -- $cur ) )
+}
+
+_sizes()
+{
+ COMPREPLY=( $( compgen -W 'k K m M g G t T' -- $cur ) )
+}
+
+_args()
+{
+ args=0
+ if [[ "${COMP_WORDS[0]}" == lvm ]]; then
+ offset=2
+ else
+ offset=1
+ fi
+ for (( i=$offset; i < COMP_CWORD; i++ )); do
+ if [[ "${COMP_WORDS[i]}" != -* ]]; then
+ args=$(($args + 1))
+ fi
+ done
+}
+
+_lvmdiskscan()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -h -? --help -l \
+ --lvmpartition -v --verbose --version' -- $cur ) )
+ fi
+}
+complete -F _lvmdiskscan lvmdiskscan
+
+_pvscan()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -e \
+ --exported -n --novolumegroup -h -? \
+ --help --ignorelockingfailure -P \
+ --partial -s --short -u --uuid -v \
+ --verbose --version' -- $cur ) )
+ fi
+}
+complete -F _pvscan pvscan
+
+_pvs()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(o|O|-options|-sort))
+ COMPREPLY=( $( compgen -W 'pv_fmt pv_uuid \
+ pv_size pv_free pv_used pv_name \
+ pv_attr pv_pe_count \
+ pv_pe_alloc_count' -- $cur ) )
+ return 0
+ ;;
+ --units)
+ _units
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--aligned -a --all -d --debug \
+ -h -? --help --ignorelockingfailure --noheadings \
+ --nosuffix -o --options -O --sort \
+ --separator --unbuffered --units \
+ -v --verbose --version' -- $cur ) )
+ else
+ _physicalvolumes
+ fi
+}
+complete -F _pvs pvs
+
+_pvdisplay()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --units)
+ _units
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c --colon -C --columns --units \
+ -v --verbose -d --debug -h --help --version' -- $cur ) )
+ else
+ _physicalvolumes
+ fi
+}
+complete -F _pvdisplay pvdisplay
+
+_pvchange()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|x|-autobackup|--allocatable))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a --all -A --autobackup \
+ -d --debug -h --help -t --test -u --uuid -x \
+ --allocatable -v --verbose --addtag --deltag \
+ --version' -- $cur ) )
+ else
+ _physicalvolumes
+ fi
+}
+complete -F _pvchange pvchange
+
+_pvcreate()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --restorefile)
+ _filedir
+ return 0
+ ;;
+ -@(M|-metadatatype))
+ COMPREPLY=( $( compgen -W '1 2' -- $cur ) )
+ return 0
+ ;;
+ --metadatacopies)
+ COMPREPLY=( $( compgen -W '0 1 2' -- $cur ) )
+ return 0
+ ;;
+ --@(metadatasize|setphysicalvolumesize))
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--restorefile -d --debug -f \
+ --force -h -? --help --labelsector -M --metadatatype \
+ --metadatacopies --metadatasize \
+ --setphysicalvolumesize -t --test -u --uuid uuid -v \
+ --verbose -y --yes --version' -- $cur ) )
+ else
+ _physicalvolumes
+ fi
+}
+complete -F _pvcreate pvcreate
+
+_pvmove()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(n|-name))
+ _logicalvolumes
+ return 0
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--abort -A --autobackup \
+ -b --background -d --debug -f --force -h -? \
+ --help -i --interval -t --test -v --verbose \
+ --version -n --name' -- $cur ) )
+ else
+ _physicalvolumes
+ fi
+}
+complete -F _pvmove pvmove
+
+_pvremove()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -f --force -h -? \
+ --help -y --yes -t --test -v --verbose \
+ --version' -- $cur ) )
+ else
+ _physicalvolumes
+ fi
+}
+complete -F _pvremove pvremove
+
+_vgscan()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -h --help \
+ --ignorelockingfailure --mknodes -P \
+ --partial -v --verbose --version' -- $cur ) )
+ fi
+}
+complete -F _vgscan vgscan
+
+_vgs()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(o|O|-options|-sort))
+ COMPREPLY=( $( compgen -W 'vg_fmt vg_uuid vg_name \
+ vg_attr vg_size vg_free vg_sysid \
+ vg_extent_size vg_extent_count vg_free_count \
+ max_lv max_pv pv_count lv_count snap_count \
+ vg_seqno' -- $cur ) )
+ return 0
+ ;;
+ --units)
+ _units
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--aligned -d --debug \
+ -h --help --ignorelockingfailure --noheadings \
+ --nosuffix -o --options -O --sort -P --partial \
+ --separator --unbuffered --units \
+ -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgs vgs
+
+_vgdisplay()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --units)
+ _units
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c --colon -C --columns --units \
+ -P --partial -A --activevolumegroups -v --verbose \
+ -d --debug -h --help --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgdisplay vgdisplay
+
+_vgchange()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(a|A|x|-available|-autobackup|-resizeable))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup --alloc -P \
+ --partial -d --debug -h --help --ignorelockingfailure \
+ -t --test -u --uuid -v --verbose --version -a \
+ --available -x --resizeable -l --logicalvolume \
+ --addtag --deltag' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgchange vgchange
+
+_vgcreate()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(M|-metadatatype))
+ COMPREPLY=( $( compgen -W '1 2' -- $cur ) )
+ return 0
+ ;;
+ -@(s|-physicalextentsize))
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup --addtag \
+ --alloc -d --debug -h --help -l --maxlogicalvolumes \
+ -M --metadatatype -p --maxphysicalvolumes -s \
+ --physicalextentsize -t --test -v --verbose \
+ --version' -- $cur ) )
+ else
+ _args
+ if [ $args -eq 0 ]; then
+ _volumegroups
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _vgcreate vgcreate
+
+_vgremove()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -h --help -t --test \
+ -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgremove vgremove
+
+_vgrename()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d --debug -h \
+ -? --help -t --test -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgrename vgrename
+
+_vgreduce()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a --all -A --autobackup -d \
+ --debug -h --help --removemissing -t --test -v \
+ --verbose --version' -- $cur ) )
+
+ else
+ _args
+ if [ $args -eq 0 ]; then
+ _volumegroups
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _vgreduce vgreduce
+
+_vgextend()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(L|-size))
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d --debug -h \
+ -? --help -t --test -v --verbose --version' -- $cur ) )
+ else
+ _args
+ if [ $args -eq 0 ]; then
+ _volumegroups
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _vgextend vgextend
+
+_vgport()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a --all -d --debug -h \
+ -? --help -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgport vgimport vgexport
+
+_vgck()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -h \
+ -? --help -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgck vgck
+
+_vgconvert()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(M|-metadatatype))
+ COMPREPLY=( $( compgen -W '1 2' -- $cur ) )
+ return 0
+ ;;
+ --metadatacopies)
+ COMPREPLY=( $( compgen -W '0 1 2' -- $cur ) )
+ return 0
+ ;;
+ --metadatasize)
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -h --help --labelsector \
+ -M --metadatatype --metadatacopies --metadatasize \
+ -t --test -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgconvert vgconvert
+
+_vgcfgbackup()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(f|-file))
+ _filedir
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -f --file -h --help \
+ --ignorelockingfailure -P --partial -v --verbose \
+ --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgcfgbackup vgcfgbackup
+
+_vgcfgrestore()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(f|-file))
+ _filedir
+ return 0
+ ;;
+ -@(M|-metadatatype))
+ COMPREPLY=( $( compgen -W '1 2' -- $cur ) )
+ return 0
+ ;;
+ -@(n|-name))
+ _volumegroups
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -f --file -l --list \
+ -h --help -M --Metadatatype -n --name -t --test \
+ -v --verbose --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgcfgrestore vgcfgrestore
+
+_vgmerge()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d --debug \
+ -h --help -l --list -t --test -v --verbose \
+ --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgmerge vgmerge
+
+_vgsplit()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(M|-metadatatype))
+ COMPREPLY=( $( compgen -W '1 2' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d --debug \
+ -h --help -l --list -M --metadatatype -t --test \
+ -v --verbose --version' -- $cur ) )
+ else
+ _args
+ if [ $args -eq 0 -o $args -eq 1 ]; then
+ _volumegroups
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _vgsplit vgsplit
+
+_vgmknodes()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-d --debug -h --help -v --verbose \
+ --version' -- $cur ) )
+ else
+ _volumegroups
+ fi
+}
+complete -F _vgmknodes vgmknodes
+
+_lvscan()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-b --blockdevice -d --debug \
+ -h -? --help --ignorelockingfailure -P \
+ --partial -v --verbose --version' -- $cur ) )
+ fi
+}
+complete -F _lvscan lvscan
+
+_lvs()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(o|O|-options|-sort))
+ COMPREPLY=( $( compgen -W 'lv_uuid lv_name \
+ lv_attr lv_minor lv_size seg_count \
+ origin snap_percent segtype stripes \
+ stripesize chunksize seg_start \
+ seg_size' -- $cur ) )
+ return 0
+ ;;
+ --units)
+ _units
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--aligned -d --debug \
+ -h --help --ignorelockingfailure --noheadings \
+ --nosuffix -o --options -O --sort -P --partial \
+ --segments --separator --unbuffered --units \
+ -v --verbose --version' -- $cur ) )
+ else
+ _logicalvolumes
+ fi
+}
+complete -F _lvs lvs
+
+_lvdisplay()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ --units)
+ _units
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-c --colon -C --columns --units \
+ -P --partial -m --maps -v --verbose -d --debug -h \
+ --help --version' -- $cur ) )
+ else
+ _logicalvolumes
+ fi
+}
+complete -F _lvdisplay lvdisplay
+
+_lvchange()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(a|A|C|M|-available|-autobackup|-continguous|-persistent))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(p|-permission))
+ COMPREPLY=( $( compgen -W 'r rw' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -a --available \
+ --addtag --alloc -C --contiguous -d --debug --deltag \
+ -f --force -h --help --ignorelockingfailure -M \
+ --persistent --major major --minor minor -P --partial \
+ -p --permission -r --readahead --refresh -t --test \
+ -v --verbose --version' -- $cur ) )
+ else
+ _logicalvolumes
+ fi
+}
+complete -F _lvchange lvchange
+
+_lvcreate()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|C|M|Z|-autobackup|-continguous|-persistent|-zero))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(L|-size))
+ _sizes
+ return 0
+ ;;
+ -@(p|-permission))
+ COMPREPLY=( $( compgen -W 'r rw' -- $cur ) )
+ return 0
+ ;;
+ -@(n|-name))
+ _logicalvolumes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup --addtag --alloc \
+ -C --contiguous -d --debug -h -? --help -i --stripes \
+ -I --stripesize -l --extents -L --size -M --persistent \
+ --major --minor -n --name -p --permission -r \
+ --readahead -t --test --type -v --verbose -Z --zero \
+ --version' -- $cur ) )
+ else
+ _args
+ if [ $args -eq 0 ]; then
+ _volumegroups
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _lvcreate lvcreate
+
+_lvremove()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d --debug -f \
+ --force -h -? --help -t --test -v --verbose \
+ --version' -- $cur ) )
+ else
+ _logicalvolumes
+ fi
+}
+complete -F _lvremove lvremove
+
+_lvrename()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d --debug -h \
+ -? --help -t --test -v --verbose --version' -- $cur ) )
+ else
+ _logicalvolumes
+ fi
+}
+complete -F _lvrename lvrename
+
+_lvreduce()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(L|-size))
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup -d \
+ --debug -f --force -h --help -l --extents \
+ -L --size -n --nofsck -r --resizefs -t --test \
+ -v --verbose --version' -- $cur ) )
+ else
+ _logicalvolumes
+ fi
+}
+complete -F _lvreduce lvreduce
+
+_lvresize()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(L|-size))
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup --alloc -d \
+ --debug -h --help -i --stripes -I --stripesize \
+ -l --extents -L --size -n --nofsck -r --resizefs \
+ -t --test --type -v --verbose --version' -- $cur ) )
+ else
+ _args
+ if [ $args -eq 0 ]; then
+ _logicalvolumes
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _lvresize lvresize
+
+_lvextend()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -@(A|-autobackup))
+ COMPREPLY=( $( compgen -W 'y n' -- $cur ) )
+ return 0
+ ;;
+ -@(L|-size))
+ _sizes
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-A --autobackup --alloc -d \
+ --debug -h --help -i --stripes -I --stripesize \
+ -l --extents -L --size -n --nofsck -r --resizefs \
+ -t --test --type -v --verbose --version' -- $cur ) )
+ else
+ _args
+ if [ $args -eq 0 ]; then
+ _logicalvolumes
+ else
+ _physicalvolumes
+ fi
+ fi
+}
+complete -F _lvextend lvextend
+
+_lvm()
+{
+ local prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W 'dumpconfig help lvchange \
+ lvcreate lvdisplay lvextend lvmchange \
+ lvmdiskscan lvmsadc lvmsar lvreduce \
+ lvremove lvrename lvresize lvs lvscan \
+ pvchange pvcreate pvdata pvdisplay pvmove \
+ pvremove pvresize pvs pvscan vgcfgbackup \
+ vgcfgrestore vgchange vgck vgconvert \
+ vgcreate vgdisplay vgexport vgextend \
+ vgimport vgmerge vgmknodes vgreduce \
+ vgremove vgrename vgs vgscan vgsplit \
+ version' -- $cur ) )
+ else
+ case ${COMP_WORDS[1]} in
+ pvchange)
+ _pvchange
+ ;;
+ pvcreate)
+ _pvcreate
+ ;;
+ pvdisplay)
+ _pvdisplay
+ ;;
+ pvmove)
+ _pvmove
+ ;;
+ pvremove)
+ _pvremove
+ ;;
+ pvresize)
+ _pvresize
+ ;;
+ pvs)
+ _pvs
+ ;;
+ pvscan)
+ _pvscan
+ ;;
+ vgcfgbackup)
+ _vgcfgbackup
+ ;;
+ vgcfgrestore)
+ _vgcfgrestore
+ ;;
+ vgchange)
+ _vgchange
+ ;;
+ vgck)
+ _vgck
+ ;;
+ vgconvert)
+ _vgconvert
+ ;;
+ vgcreate)
+ _vgcreate
+ ;;
+ vgdisplay)
+ _vgdisplay
+ ;;
+ vgexport)
+ _vgexport
+ ;;
+ vgextend)
+ _vgextend
+ ;;
+ vgimport)
+ _vgimport
+ ;;
+ vgmerge)
+ _vgmerge
+ ;;
+ vgmknodes)
+ _vgmknodes
+ ;;
+ vgreduce)
+ _vgreduce
+ ;;
+ vgremove)
+ _vgremove
+ ;;
+ vgrename)
+ _vgrename
+ ;;
+ vgs)
+ _vgs
+ ;;
+ vgscan)
+ _vgscan
+ ;;
+ vgsplit)
+ _vgsplit
+ ;;
+ lvchange)
+ _lvchange
+ ;;
+ lvcreate)
+ _lvcreate
+ ;;
+ lvdisplay)
+ _lvdisplay
+ ;;
+ lvextend)
+ _lvextend
+ ;;
+ lvreduce)
+ _lvreduce
+ ;;
+ lvremove)
+ _lvremove
+ ;;
+ lvrename)
+ _lvrename
+ ;;
+ lvresize)
+ _lvresize
+ ;;
+ lvs)
+ _lvs
+ ;;
+ lvscan)
+ _lvscan
+ ;;
+ esac
+ fi
+}
+complete -F _lvm lvm
+}
+
+# mkinitrd(8) completion
+#
+have mkinitrd &&
+_mkinitrd()
+{
+ local cur args
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # --name value style option
+ case "$prev" in
+ --preload)
+ _modules
+ return 0
+ ;;
+ esac
+
+ # --name=value style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case "$prev" in
+ --@(with|builtin))
+ _modules
+ return 0
+ ;;
+ --@(fstab|dsdt))
+ _filedir
+ return 0
+ ;;
+ --tmpdir)
+ _filedir -d
+ return 0
+ ;;
+ esac
+ fi
+
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--version -v -f --preload \
+ --with= --omit-scsi-modules --omit-raid-modules \
+ --images-version --fstab= --nocompress --builtin= \
+ --nopivot --noudev --allow-missing --tmpdir= \
+ --initrdfs= --dsdt= --lvm-version= --froce-usb' \
+ -- $cur ) )
+ else
+ _count_args
+
+ case $args in
+ 1)
+ _filedir
+ ;;
+ 2)
+ COMPREPLY=( $( command ls /lib/modules | grep "^$cur" ) )
+ ;;
+ esac
+ fi
+
+} &&
+complete -F _mkinitrd mkinitrd
+
+# pkgconfig(1) completion
+#
+have pkg-config &&
+_pkg_config()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ # return list of available options
+ COMPREPLY=( $( compgen -W '-version --modversion \
+ --atleast-pkgconfig-version= --libs --libs-only-l \
+ --libs-only-other --libs-only-L --cflags \
+ --cflags-only-I --cflags-only-other --variable= \
+ --define-variable= --exists --uninstalled \
+ --atleast-version= --exact-version= --max-version= \
+ --list-all --debug --print-errors --silence-errors \
+ --errors-to-stdout -? --help --usage' -- $cur))
+ else
+ COMPREPLY=( $( pkg-config --list-all 2>/dev/null | \
+ awk '{print $1}' | grep "^$cur" ) )
+ fi
+} &&
+complete -F _pkg_config pkg-config
+
+
+# cpio(1) completion
+#
+have cpio && {
+_cpio_format()
+{
+ COMPREPLY=( $( compgen -W 'bin odc newc crc tar ustar hpbin hpodc' -- $cur ) )
+}
+
+_cpio()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # --name value style option
+ case $prev in
+ -H)
+ _cpio_format
+ return 0
+ ;;
+ -@(E|F|I))
+ _filedir
+ return 0
+ ;;
+ -R)
+ _usergroup
+ return 0
+ ;;
+ esac
+
+ # --name=value style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case $prev in
+ --format)
+ _cpio_format
+ return 0
+ ;;
+ --@(file|pattern-file))
+ _filedir
+ return 0
+ ;;
+ --owner)
+ _usergroup
+ return 0
+ ;;
+ --rsh-command)
+ COMPREPLY=( $( compgen -c -- $cur ) )
+ return 0
+ ;;
+ esac
+ fi
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W '-o --create -i --extract -p --pass-through' -- $cur) )
+ else
+ case ${COMP_WORDS[1]} in
+ -@(o|-create))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-0 -a -c -v -A -B\
+ -L -V -C -H -M -O -F --file= --format=\
+ --message= --null --reset-access-time\
+ --verbose --dot --append --block-size=\
+ --dereference --io-size= --quiet\
+ --force-local --rsh-command= --help\
+ --version' -- $cur ) )
+ fi
+ ;;
+ -@(i|-extract))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-b -c -d -f -m -n -r\
+ -t -s -u -v -B -S -V -C -E -H -M -R -I\
+ -F --file= --make-directories\
+ --nonmatching\
+ --preserve-modification-time\
+ --numeric-uid-gid --rename -t --list\
+ --swap-bytes --swap --dot\
+ --unconditional --verbose --block-size=\
+ --swap-halfwords --io-size=\
+ --pattern-file= --format= --owner=\
+ --no-preserve-owner --message=\
+ --force-local --no-absolute-filenames\
+ --sparse --only-verify-crc --quiet\
+ --rsh-command= --help\
+ --version' -- $cur ) )
+ fi
+ ;;
+ -@(p|-pass-through))
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-0 -a -d -l -m -u -v\
+ -L -V -R --null --reset-access-time\
+ --make-directories --link --quiet\
+ --preserve-modification-time\
+ --unconditional --verbose --dot\
+ --dereference --owner=\
+ --no-preserve-owner --sparse --help\
+ --version' -- $cur ) )
+ else
+ _filedir -d
+ fi
+ ;;
+ esac
+ fi
+}
+complete -F _cpio cpio
+}
+
+# id(1) completion
+#
+have id &&
+_id()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-a -g --group -G --groups -n --name\
+ -r --real -u --user --help --version' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -u $cur ) )
+ fi
+} &&
+complete -F _id id
+
+# getent(1) completion
+#
+have getent &&
+_getent()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ passwd)
+ COMPREPLY=( $( compgen -u $cur ) )
+ return 0
+ ;;
+ group)
+ COMPREPLY=( $( compgen -g $cur ) )
+ return 0
+ ;;
+ services)
+ COMPREPLY=( $( compgen -s $cur ) )
+ return 0
+ ;;
+ hosts)
+ COMPREPLY=( $( compgen -A hostname $cur ) )
+ return 0
+ ;;
+ protocols)
+ COMPREPLY=( $( getent protocols | awk '{print $1}' | grep "^$cur" ) )
+ return 0
+ ;;
+ networks)
+ COMPREPLY=( $( getent networks | awk '{print $1}' | grep "^$cur" ) )
+ return 0
+ ;;
+ esac
+
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ COMPREPLY=( $( compgen -W 'passwd group hosts services protocols networks' -- $cur ) )
+ fi
+} &&
+complete -F _getent getent
+
+# ntpdate(1) completion
+#
+have ntpdate &&
+_ntpdate()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ -k)
+ _filedir
+ return 0
+ ;;
+ -U)
+ COMPREPLY=( $( compgen -u $cur ) )
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-4 -6 -b -B -d -Q -q -s -u -v -a\
+ -e -k -p -o -r -t' -- $cur ) )
+ else
+ _known_hosts
+ fi
+} &&
+complete -F _ntpdate ntpdate
+
+# smartctl(8) completion
+#
+have smartctl && {
+_smartctl_quietmode()
+{
+ COMPREPLY=( $( compgen -W 'errorsonly silent' -- $cur ) )
+}
+_smartctl_device()
+{
+ COMPREPLY=( $( compgen -W 'ata scsi 3ware' -- $cur ) )
+}
+_smartctl_tolerance()
+{
+ COMPREPLY=( $( compgen -W 'warn exit ignore' -- $cur ) )
+}
+_smartctl_badsum()
+{
+ COMPREPLY=( $( compgen -W 'normal conservative permissive verypermissive' -- $cur ) )
+}
+_smartctl_report()
+{
+ COMPREPLY=( $( compgen -W 'ioctl ataioctl scsiioctl' -- $cur ) )
+}
+_smartctl_feature()
+{
+ COMPREPLY=( $( compgen -W 'on off' -- $cur ) )
+}
+_smartctl_log()
+{
+ COMPREPLY=( $( compgen -W 'error selftest selective directory' -- $cur ) )
+}
+_smartctl_vendorattribute()
+{
+ COMPREPLY=( $( compgen -W 'help 9,minutes 9,seconds 9,halfminutes \
+ 9,temp 192,emergencyretractcyclect 193,loadunload \
+ 194,10xCelsius 194,unknown 198,offlinescanuncsectorct \
+ 200,writeerrorcount 201,detectedtacount 220,temp' -- $cur ) )
+}
+_smartctl_firmwarebug()
+{
+ COMPREPLY=( $( compgen -W 'none samsung samsung2' -- $cur ) )
+}
+_smartctl_presets()
+{
+ COMPREPLY=( $( compgen -W 'use ignore show showall' -- $cur ) )
+}
+_smartctl_test()
+{
+ COMPREPLY=( $( compgen -W 'offline short long conveyance select afterselect,on afterselect,off pending' -- $cur ) )
+}
+
+_smartctl()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ # --name value style option
+ case "$prev" in
+ -q)
+ _smartctl_quietmode
+ ;;
+ -d)
+ _smartctl_device
+ return 0
+ ;;
+ -t)
+ _smartctl_tolerance
+ return 0
+ ;;
+ -b)
+ _smartctl_badsum
+ return 0
+ ;;
+ -r)
+ _smartctl_report
+ return 0
+ ;;
+ -s)
+ _smartctl_feature
+ return 0
+ ;;
+ -o)
+ _smartctl_feature
+ return 0
+ ;;
+ -S)
+ _smartctl_feature
+ return 0
+ ;;
+ -l)
+ _smartctl_log
+ return 0
+ ;;
+ -v)
+ _smartctl_vendorattribute
+ return 0
+ ;;
+ -F)
+ _smartctl_firmwarebug
+ return 0
+ ;;
+ -P)
+ _smartctl_presets
+ return 0
+ ;;
+ -t)
+ _smartctl_test
+ return 0
+ ;;
+ esac
+
+ # --name=value style option
+ if [[ "$cur" == *=* ]]; then
+ prev=${cur/=*/}
+ cur=${cur/*=/}
+ case "$prev" in
+ --quietmode)
+ _smartctl_quietmode
+ return 0
+ ;;
+ --device)
+ _smartctl_device
+ return 0
+ ;;
+ --tolerance)
+ _smartctl_tolerance
+ return 0
+ ;;
+ --badsum)
+ _smartctl_badsum
+ return 0
+ ;;
+ --report)
+ _smartctl_report
+ return 0
+ ;;
+ --smart)
+ _smartctl_feature
+ return 0
+ ;;
+ --offlineauto)
+ _smartctl_feature
+ return 0
+ ;;
+ --saveauto)
+ _smartctl_feature
+ return 0
+ ;;
+ --log)
+ _smartctl_log
+ return 0
+ ;;
+ --vendorattribute)
+ _smartctl_vendorattribute
+ return 0
+ ;;
+ --firmwarebug)
+ _smartctl_firmwarebug
+ return 0
+ ;;
+ --presets)
+ _smartctl_presets
+ return 0
+ ;;
+ --test)
+ _smartctl_test
+ return 0
+ ;;
+ esac
+ fi
+
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-h --help --usage -V --version \
+ --copyright --license-i --info -a --all -q \
+ --quietmode= -d --device= -T --tolerance= -b --badsum= \
+ -r --report= -s --smart= -o --offlineauto= -S \
+ --saveauto= -H --health -c --capabilities -A \
+ --attributes -l --log= -v --vendorattribute= -F \
+ --firmwarebug= -P --presets= -t --test= -C \
+ --captive -X --abort' -- $cur ) )
+ else
+ cur=${cur:=/dev/}
+ _filedir
+ fi
+}
+complete -F _smartctl smartctl
+}
+
+# vncviewer(1) completion
+#
+have vncviewer &&
+_vncviewer()
+{
+ local cur prev
+ local -a config
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case "$prev" in
+ -via)
+ _known_hosts -a
+ ;;
+ *)
+ # ssh into the the server, find and ping the broadcast address, then
+ # sort and show the results.
+ COMPREPLY=( $( ssh -o 'Batchmode yes' $prev \
+ "ping -bnc 4 255.255.255.255" 2>/dev/null | \
+ awk -F ' ' '{print $4}' | \
+ sort -n | uniq | egrep '[0-9]+\.[0-9]+\.' 2>/dev/null ) )
+ esac
+
+ return 0
+} &&
+complete -F _vncviewer vncviewer
+
+# sysctl(8) completion
+#
+have sysctl &&
+_sysctl()
+{
+ local cur
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ COMPREPLY=( $( compgen -W "$(sysctl -N -a 2>/dev/null)" -- $cur ) )
+
+ return 0
+} &&
+complete -F _sysctl sysctl
+
+# update-rc.d(8) completion
+#
+# Copyright (C) 2004 Servilio Afre Puentes <servilio@gmail.com>
+#
+have update-rc.d &&
+_update_rc_d()
+{
+ local cur prev sysvdir services options valid_options
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \
+ || sysvdir=/etc/init.d
+
+ services=( $(echo $sysvdir/!(README*|*.sh|*.dpkg*|*.rpm*)) )
+ services=( ${services[@]#$sysvdir/} )
+ options=( -f -n )
+
+ if [[ $COMP_CWORD -eq 1 || "$prev" == -* ]]; then
+ valid_options=( $( \
+ echo "${COMP_WORDS[@]} ${options[@]}" \
+ | tr " " "\n" \
+ | sed -ne "/$( echo "${options[@]}" | sed "s/ /\\|/g" )/p" \
+ | sort | uniq -u \
+ ) )
+ COMPREPLY=( $( compgen -W '${options[@]} ${services[@]}' \
+ -X '$( echo ${COMP_WORDS[@]} | tr " " "|" )' -- $cur ) )
+ elif [[ "$prev" == ?($( echo ${services[@]} | tr " " "|" )) ]]; then
+ COMPREPLY=( $( compgen -W 'remove defaults start stop' -- $cur ) )
+ elif [[ "$prev" == defaults && "$cur" == [0-9] ]]; then
+ COMPREPLY=( 0 1 2 3 4 5 6 7 8 9 )
+ elif [[ "$prev" == defaults && "$cur" == [sk]?([0-9]) ]]; then
+ COMPREPLY=( 0 1 2 3 4 5 6 7 8 9 )
+ elif [[ "$prev" == defaults && -z "$cur" ]]; then
+ COMPREPLY=( 0 1 2 3 4 5 6 7 8 9 s k )
+ elif [[ "$prev" == ?(start|stop) ]]; then
+ if [[ "$cur" == [0-9] || -z "$cur" ]]; then
+ COMPREPLY=( 0 1 2 3 4 5 6 7 8 9 )
+ elif [[ "$cur" == [0-9][0-9] ]]; then
+ COMPREPLY=( $cur )
+ else
+ COMPREPLY=()
+ fi
+ elif [[ "$prev" == ?([0-9][0-9]|[0-6S]) ]]; then
+ if [[ -z "$cur" ]]; then
+ if [[ $prev == [0-9][0-9] ]]; then
+ COMPREPLY=( 0 1 2 3 4 5 6 S )
+ else
+ COMPREPLY=( 0 1 2 3 4 5 6 S . )
+ fi
+ elif [[ "$cur" == [0-6S.] ]]; then
+ COMPREPLY=( $cur )
+ else
+ COMPREPLY=()
+ fi
+ elif [[ "$prev" == "." ]]; then
+ COMPREPLY=( $(compgen -W "start stop" -- $cur) )
+ else
+ COMPREPLY=()
+ fi
+
+ return 0
+} &&
+complete -F _update_rc_d update-rc.d
+
+# invoke-rc.d(8) completion
+#
+# Copyright (C) 2004 Servilio Afre Puentes <servilio@gmail.com>
+#
+have invoke-rc.d &&
+_invoke_rc_d()
+{
+ local cur prev sysvdir services options valid_options
+
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \
+ || sysvdir=/etc/init.d
+
+ services=( $(echo $sysvdir/!(README*|*.sh|*.dpkg*|*.rpm*)) )
+ services=( ${services[@]#$sysvdir/} )
+ options=( --help --quiet --force --try-anyway --disclose-deny --query --no-fallback )
+
+ if [[ ($COMP_CWORD -eq 1) || ("$prev" == --* ) ]]; then
+ valid_options=( $( \
+ echo ${COMP_WORDS[@]} ${options[@]} \
+ | tr " " "\n" \
+ | sed -ne "/$( echo ${options[@]} | sed "s/ /\\\\|/g" )/p" \
+ | sort | uniq -u \
+ ) )
+ COMPREPLY=( $( compgen -W '${valid_options[@]} ${services[@]}' -- \
+ $cur ) )
+ elif [ -x $sysvdir/$prev ]; then
+ COMPREPLY=( $( compgen -W '`sed -ne "y/|/ /; \
+ s/^.*Usage:[ ]*[^ ]*[ ]*{*\([^}\"]*\).*$/\1/p" \
+ $sysvdir/$prev`' -- \
+ $cur ) )
+ else
+ COMPREPLY=()
+ fi
+
+ return 0
+} &&
+complete -F _invoke_rc_d invoke-rc.d
+
+# minicom(1) completion
+#
+have minicom &&
+_minicom()
+{
+ local cur prev
+
+ COMPREPLY=()
+ cur=`_get_cword`
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+
+ case $prev in
+ -@(a|c))
+ COMPREPLY=( $( compgen -W 'on off' -- $cur ) )
+ return 0
+ ;;
+ -@(S|C))
+ _filedir
+ return 0
+ ;;
+ -P)
+ COMPREPLY=( $( command ls /dev/tty* ) )
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]} ${COMPREPLY[@]#/dev/}' -- $cur ) )
+ return 0
+ ;;
+ esac
+
+
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '-s -o -m -M -z -l -L -w -a -t \
+ -c -S -d -p -C -T -8' -- $cur ) )
+ else
+ COMPREPLY=( $( command ls /etc/minicom/minirc.* 2>/dev/null | sed -e 's|/etc/minicom/minirc.||' | grep "^$cur" ) )
+ fi
+} &&
+complete -F _minicom minicom
+
+# svn completion
+#
+have svn &&
+{
+_svn()
+{
+ local cur prev commands options command
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ commands='add blame praise annotate ann cat checkout co cleanup commit \
+ ci copy cp delete del remove rm diff di export help ? h import \
+ info list ls lock log merge mkdir move mv rename ren \
+ propdel pdel pd propedit pedit pe propget pget pg \
+ proplist plist pl propset pset ps resolved revert \
+ status stat st switch sw unlock update up'
+
+ if [[ $COMP_CWORD -eq 1 ]] ; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--version' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
+ fi
+ else
+
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ case $prev in
+ --config-dir)
+ _filedir -d
+ return 0;
+ ;;
+ -@(F|-file|-targets))
+ _filedir
+ return 0;
+ ;;
+ --encoding)
+ COMPREPLY=( $( compgen -W \
+ '$( iconv --list | sed -e "s@//@@;" )' \
+ -- "$cur" ) )
+ return 0;
+ ;;
+ --@(editor|diff|diff3)-cmd)
+ COMP_WORDS=(COMP_WORDS[0] $cur)
+ COMP_CWORD=1
+ _command
+ return 0;
+ ;;
+ esac
+
+ command=${COMP_WORDS[1]}
+
+ if [[ "$cur" == -* ]]; then
+ # possible options for the command
+ case $command in
+ add)
+ options='--auto-props --no-auto-props \
+ --force --targets --no-ignore \
+ --non-recursive -N -q --quiet'
+ ;;
+ @(blame|annotate|ann|praise))
+ options='-r --revisions --username \
+ --password --no-auth-cache \
+ --non-interactive -v \
+ --verbose --incremental --xml'
+ ;;
+ cat)
+ options='-r --revision --username \
+ --password --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(checkout|co))
+ options='-r --revision -q --quiet -N \
+ --non-recursive --username \
+ --password --no-auth-cache \
+ --non-interactive \
+ --ignore-externals'
+ ;;
+ cleanup)
+ options='--diff3-cmd'
+ ;;
+ @(commit|ci))
+ options='-m --message -F --file \
+ --encoding --force-log -q \
+ --quiet --non-recursive -N \
+ --targets --editor-cmd \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive --no-unlock'
+ ;;
+ @(copy|cp))
+ options='-m --message -F --file \
+ --encoding --force-log -r \
+ --revision -q --quiet \
+ --editor-cmd -username \
+ --password --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(delete|del|remove|rm))
+ options='--force -m --message -F \
+ --file --encoding --force-log \
+ -q --quiet --targets \
+ --editor-cmd -username \
+ --password --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(diff|di))
+ options='-r --revision -x --extensions \
+ --diff-cmd --no-diff-deleted \
+ -N --non-recursive --username \
+ --password --no-auth-cache \
+ --non-interactive --force \
+ --old --new --notice-ancestry'
+ ;;
+ export)
+ options='-r --revision -q --quiet \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive -N \
+ --non-recursive --force \
+ --native-eol --ignore-externals'
+ ;;
+ import)
+ options='--auto-props --no-auto-props \
+ -m --message -F --file \
+ --encoding --force-log -q \
+ --quiet --non-recursive \
+ --no-ignore --editor-cmd \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive'
+ ;;
+ info)
+ options='--username --password \
+ --no-auth-cache \
+ --non-interactive -r \
+ --revision --xml --targets \
+ -R --recursive --incremental'
+ ;;
+ @(list|ls))
+ options='-r --revision -v --verbose -R \
+ --recursive --username \
+ --password --no-auth-cache \
+ --non-interactive \
+ --incremental --xml'
+ ;;
+ lock)
+ options='-m --message -F --file \
+ --encoding --force-log \
+ --targets --force --username \
+ --password --no-auth-cache \
+ --non-interactive'
+ ;;
+ log)
+ options='-r --revision -v --verbose \
+ --targets --username \
+ --password --no-auth-cache \
+ --non-interactive \
+ --stop-on-copy --incremental \
+ --xml -q --quiet --limit'
+ ;;
+ merge)
+ options='-r --revision -N \
+ --non-recursive -q --quiet \
+ --force --dry-run --diff3-cmd \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive \
+ --ignore-ancestry'
+ ;;
+ mkdir)
+ options='-m --message -F --file \
+ --encoding --force-log -q \
+ --quiet --editor-cmd \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(move|mv|rename|ren))
+ options='-m --message -F --file \
+ --encoding --force-log -r \
+ --revision -q --quiet \
+ --force --editor-cmd \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(propdel|pdel|pd))
+ options='-q --quiet -R --recursive -r \
+ --revision --revprop \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(propedit|pedit|pe))
+ options='-r --revision --revprop \
+ --encoding --editor-cmd \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive --force'
+ ;;
+ @(propget|pget|pg))
+ options='-R --recursive -r --revision \
+ --revprop --strict --username \
+ --password --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(proplist|plist|pl))
+ options='-v --verbose -R --recursive \
+ -r --revision --revprop -q \
+ --quiet --username --password \
+ --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(propset|pset|ps))
+ options='-F --file -q --quiet \
+ --targets -R --recursive \
+ --revprop --encoding \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive -r \
+ --revision --force'
+ ;;
+ resolved)
+ options='--targets -R --recursive -q \
+ --quiet'
+ ;;
+ revert)
+ options='--targets -R --recursive -q \
+ --quiet'
+ ;;
+ @(status|stat|st))
+ options='-u --show-updates -v \
+ --verbose -N --non-recursive \
+ -q --quiet --username \
+ --password --no-auth-cache \
+ --non-interactive --no-ignore \
+ --ignore-externals \
+ --incremental --xml'
+ ;;
+ @(switch|sw))
+ options='--relocate -r --revision -N \
+ --non-recursive -q --quiet \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive --diff3-cmd'
+ ;;
+ unlock)
+ options='--targets --force --username \
+ --password --no-auth-cache \
+ --non-interactive'
+ ;;
+ @(update|up))
+ options='-r --revision -N \
+ --non-recursive -q --quiet \
+ --username --password \
+ --no-auth-cache \
+ --non-interactive \
+ --diff3-cmd --ignore-externals'
+ ;;
+ esac
+ options="$options --help -h --config-dir"
+
+ COMPREPLY=( $( compgen -W "$options" -- $cur ) )
+ else
+ if [[ "$command" == @(help|h|\?) ]]; then
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
+ else
+ _filedir
+ fi
+ fi
+ fi
+
+ return 0
+}
+complete -F _svn $default svn
+
+_svnadmin()
+{
+ local cur prev commands options mode
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ commands='create deltify dump help ? hotcopy list-dblogs \
+ list-unused-dblogs load lslocks lstxns recover rmlocks \
+ rmtxns setlog verify'
+
+ if [[ $COMP_CWORD -eq 1 ]] ; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--version' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
+ fi
+ else
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ case $prev in
+ --config-dir)
+ _filedir -d
+ return 0;
+ ;;
+ --fs-type)
+ COMPREPLY=( $( compgen -W 'fsfs bdb' -- $cur ) )
+ return 0;
+ ;;
+ esac
+
+ command=${COMP_WORDS[1]}
+
+ if [[ "$cur" == -* ]]; then
+ # possible options for the command
+ case $command in
+ create)
+ options='--bdb-txn-nosync \
+ --bdb-log-keep --config-dir \
+ --fs-type'
+ ;;
+ deltify)
+ options='-r --revision -q --quiet'
+ ;;
+ dump)
+ options='-r --revision --incremental \
+ -q --quiet --deltas'
+ ;;
+ hotcopy)
+ options='--clean-logs'
+ ;;
+ load)
+ options='--ignore-uuid --force-uuid \
+ --parent-dir -q --quiet \
+ --use-pre-commit-hook \
+ --use-post-commit-hook'
+ ;;
+ rmtxns)
+ options='-q --quiet'
+ ;;
+ setlog)
+ options='-r --revision --bypass-hooks'
+ ;;
+ esac
+
+ options="$options --help -h"
+ COMPREPLY=( $( compgen -W "$options" -- $cur ) )
+ else
+ if [[ "$command" == @(help|h|\?) ]]; then
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
+ else
+ _filedir
+ fi
+ fi
+ fi
+
+ return 0
+}
+complete -F _svnadmin $default svnadmin
+
+_svnlook()
+{
+ local cur prev commands options mode
+
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ commands='author cat changed date diff dirs-changed help ? h history \
+ info lock log propget pget pg proplist plist pl tree uuid \
+ youngest'
+
+ if [[ $COMP_CWORD -eq 1 ]] ; then
+ if [[ "$cur" == -* ]]; then
+ COMPREPLY=( $( compgen -W '--version' -- $cur ) )
+ else
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
+ fi
+ else
+ command=${COMP_WORDS[1]}
+
+ if [[ "$cur" == -* ]]; then
+ # possible options for the command
+ case $command in
+ @(author|cat|date|dirs-changed|info|log))
+ options='-r --revision -t \
+ --transaction'
+ ;;
+ changed)
+ options='-r --revision -t \
+ --transaction --copy-info'
+ ;;
+ diff)
+ options='-r --revision -t \
+ --transaction \
+ --no-diff-deleted \
+ --no-diff-added \
+ --diff-copy-from'
+ ;;
+ history)
+ options='-r --revision --show-ids'
+ ;;
+ prop@(get|list))
+ options='-r --revision -t \
+ --transaction --revprop'
+ ;;
+ tree)
+ options='-r --revision -t \
+ --transaction --show-ids \
+ --full-paths'
+ ;;
+ esac
+
+ options="$options --help -h"
+ COMPREPLY=( $( compgen -W "$options" -- $cur ) )
+ else
+ if [[ "$command" == @(help|h|\?) ]]; then
+ COMPREPLY=( $( compgen -W "$commands" -- $cur ) )
+ else
+ _filedir
+ fi
+ fi
+ fi
+
+ return 0
+}
+complete -F _svnlook $default svnlook
+}
+
+_filedir_xspec()
+{
+ local IFS cur xspec
+
+ IFS=$'\t\n'
+ COMPREPLY=()
+ cur=`_get_cword`
+
+ _expand || return 0
+
+ # get first exclusion compspec that matches this command
+ xspec=$( sed -ne $'/^complete .*[ \t]'${1##*/}$'\([ \t]\|$\)/{p;q;}' \
+ $BASH_COMPLETION )
+ # prune to leave nothing but the -X spec
+ xspec=${xspec#*-X }
+ xspec=${xspec%% *}
+
+ local toks=( ) tmp
+
+ while read -r tmp; do
+ [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp
+ done < <( compgen -d -- "$(quote_readline "$cur")" )
+
+ while read -r tmp; do
+ [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp
+ done < <( eval compgen -f -X $xspec -- "\$(quote_readline "\$cur")" )
+
+ COMPREPLY=( "${toks[@]}" )
+}
+list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' \
+ $BASH_COMPLETION | \
+ # read exclusion compspecs
+ (
+ while read line
+ do
+ # ignore compspecs that are commented out
+ if [ "${line#\#}" != "$line" ]; then continue; fi
+ line=${line%# START exclude*}
+ line=${line%# FINISH exclude*}
+ line=${line##*\'}
+ list=( "${list[@]}" $line )
+ done
+ echo "${list[@]}"
+ )
+ ) )
+# remove previous compspecs
+if [ ${#list[@]} -gt 0 ]; then
+ eval complete -r ${list[@]}
+ # install new compspecs
+ eval complete -F _filedir_xspec $filenames "${list[@]}"
+fi
+unset list
+
+# source completion directory definitions
+if [ -d $BASH_COMPLETION_DIR -a -r $BASH_COMPLETION_DIR -a \
+ -x $BASH_COMPLETION_DIR ]; then
+ for i in $BASH_COMPLETION_DIR/*; do
+ [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|.rpm*) ]] &&
+ [ \( -f $i -o -h $i \) -a -r $i ] && . $i
+ done
+fi
+unset i
+
+# source user completion file
+[ $BASH_COMPLETION != ~/.bash_completion -a -r ~/.bash_completion ] \
+ && . ~/.bash_completion
+unset -f have
+unset UNAME RELEASE default dirnames filenames have nospace bashdefault \
+ plusdirs
+
+set $BASH_COMPLETION_ORIGINAL_V_VALUE
+unset BASH_COMPLETION_ORIGINAL_V_VALUE
+
+### Local Variables:
+### mode: shell-script
+### End:
diff --git a/usr/src/cmd/nsadmin/bash/bash_completion.d/dladm b/usr/src/cmd/nsadmin/bash/bash_completion.d/dladm
new file mode 100644
index 0000000000..179227b2a2
--- /dev/null
+++ b/usr/src/cmd/nsadmin/bash/bash_completion.d/dladm
@@ -0,0 +1,34 @@
+_dladm()
+{
+ local cur prev opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ if [[ ${prev} == 'dladm' ]]; then
+ local cmds="rename-link show-link create-aggr delete-aggr add-aggr \
+ remove-aggr modify-aggr show-aggr scan-wifi connect-wifi \
+ disconnect-wifi show-wifi set-linkprop reset-linkprop \
+ show-linkprop show-ether create-secobj delete-secobj show-secobj \
+ create-vlan delete-vlan show-vlan create-iptun delete-iptun \
+ modify-iptun show-iptun delete-phys show-phys create-vnic \
+ delete-vnic show-vnic create-part delete-part show-part show-ib \
+ create-etherstub delete-etherstub show-etherstub create-bridge \
+ modify-bridge delete-bridge add-bridge remove-bridge show-bridge \
+ show-bridge show-usage"
+
+ COMPREPLY=( $(compgen -W "$cmds" -- ${cur}) )
+ # The -z takes a zone option, ignore everything else
+ elif [[ ${prev} =~ -.*z$ ]]; then
+ local zones=$(zoneadm list -c | grep -v '^global$')
+ COMPREPLY=( $(compgen -W "${zones}" -- ${cur}) )
+ elif [[ ${prev} =~ 'delete-vnic' ]]; then
+ local vnics=$(dladm show-vnic -p -o link)
+ COMPREPLY=( $(compgen -W "${vnics}" -- ${cur}) )
+ elif [[ ${prev} =~ 'delete-etherstub' ]]; then
+ local stubs=$(dladm show-etherstub -p)
+ COMPREPLY=( $(compgen -W "${stubs}" -- ${cur}) )
+ fi
+}
+
+complete -F _dladm dladm
diff --git a/usr/src/cmd/nsadmin/bash/bash_completion.d/machines b/usr/src/cmd/nsadmin/bash/bash_completion.d/machines
new file mode 100644
index 0000000000..05de1b75a4
--- /dev/null
+++ b/usr/src/cmd/nsadmin/bash/bash_completion.d/machines
@@ -0,0 +1,19 @@
+_machine()
+{
+ local cur prev opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ if [[ ${prev} == 'machine-json' ]]; then
+ machines=$(zoneadm list -cp | grep -v ':global:' | cut -d':' -f2,5 | tr ':' '\n' | sort | uniq)
+ COMPREPLY=( $(compgen -W "${machines}" -- ${cur}) )
+ else
+ # Just expand files by default
+ COMPREPLY=( $(compgen -f -- ${cur}) )
+ fi
+
+ return 0
+}
+
+complete -F _machine machine-json
diff --git a/usr/src/cmd/nsadmin/bash/bash_completion.d/vms b/usr/src/cmd/nsadmin/bash/bash_completion.d/vms
new file mode 100644
index 0000000000..71bcac5994
--- /dev/null
+++ b/usr/src/cmd/nsadmin/bash/bash_completion.d/vms
@@ -0,0 +1,62 @@
+_vmadm()
+{
+ local cur prev opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ up_patterns=$(printf " running *\$\n halting *\$\n")
+
+ if [[ ${prev} == 'vmadm' ]]; then
+ COMPREPLY=( $(compgen -W "boot destroy dump kill halt list reboot reset info nmi" -- ${cur}) )
+ else
+ case ${prev} in
+ boot)
+ local not_running=$(vmadm list -v | grep -v "^UUID" | \
+ /usr/xpg4/bin/grep -v -e "${up_patterns}" | cut -d' ' -f1)
+ COMPREPLY=( $(compgen -W "${not_running}" -- ${cur}) )
+ ;;
+ info|kill)
+ local running=$(vmadm list -v | grep -v "^UUID" | \
+ /usr/xpg4/bin/grep -e "${up_patterns}" | cut -d ' ' -f1)
+ COMPREPLY=( $(compgen -W "${running}" -- ${cur}) )
+ ;;
+ halt|reboot|reset|nmi|screenshot)
+ local running=$(vmadm list -v | grep -v "^UUID" | \
+ grep " running *$" | cut -d ' ' -f1)
+ COMPREPLY=( $(compgen -W "${running}" -- ${cur}) )
+ ;;
+ dump|destroy)
+ local all=$(vmadm list)
+ COMPREPLY=( $(compgen -W "${all}" -- ${cur}) )
+ ;;
+ *)
+ # Just expand files by default
+ COMPREPLY=( $(compgen -f -- ${cur}) )
+ ;;
+ esac
+ fi
+
+ return 0
+}
+
+_vmcfg()
+{
+ local cur prev opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ if [[ ${prev} == 'vmcfg' ]]; then
+ vms=$(vmadm list)
+ COMPREPLY=( $(compgen -W "${vms}" -- ${cur}) )
+ else
+ # Just expand files by default
+ COMPREPLY=( $(compgen -f -- ${cur}) )
+ fi
+
+ return 0
+}
+
+complete -F _vmadm vmadm
+complete -F _vmcfg vmcfg
diff --git a/usr/src/cmd/nsadmin/bash/bash_completion.d/zone_alias b/usr/src/cmd/nsadmin/bash/bash_completion.d/zone_alias
new file mode 100644
index 0000000000..5ae8e1d7c7
--- /dev/null
+++ b/usr/src/cmd/nsadmin/bash/bash_completion.d/zone_alias
@@ -0,0 +1,42 @@
+_zone_alias()
+{
+ local RES alias completed_alias results_arr uuid
+ # Attempt alias -> uuid mapping
+ alias="${COMP_WORDS[COMP_CWORD]}"
+ RES=$(vmadm list -H -o alias,uuid | awk -v alias="$alias" '
+ BEGIN { count = 0; uuid = ""; }
+ $1 == alias { count = 1; aliases[1] = $1; uuid = $2; exit;}
+ $1 ~ "^"alias { count += 1; aliases[count] = $1; uuid = $2; }
+ END { if (count == 1) {
+ print "smartos_alias_completed " aliases[1] " " uuid;
+ } else {
+ for (i=1; i <= count; i++) {
+ print aliases[i]
+ }
+ }
+ }
+ ')
+ results_arr=( $RES )
+ # we use 'smartos_alias_completed' as a flag to determine that
+ # a single alias was matched.
+ if [[ "${results_arr[0]}" == "smartos_alias_completed" ]]; then
+ completed_alias="${results_arr[1]}"
+ uuid="${results_arr[2]}"
+ if [[ -n "$SMARTOS_MULTILINE_ALIAS_COMPLETION" ]]; then
+ tput sc
+ tput bold
+ echo "[completed alias: ${completed_alias}]"
+ tput rc
+ tput sgr0
+ COMPREPLY=$uuid
+ elif [[ "$completed_alias" == "$alias" ]]; then
+ COMPREPLY=$uuid
+ else
+ COMPREPLY=$completed_alias
+ compopt -o nospace
+ fi
+ else
+ COMPREPLY=( $(compgen -W "$RES" -- ${cur}) )
+ fi
+ return 0
+}
diff --git a/usr/src/cmd/nsadmin/bash/bash_completion.d/zones b/usr/src/cmd/nsadmin/bash/bash_completion.d/zones
new file mode 100644
index 0000000000..e4bc5b4155
--- /dev/null
+++ b/usr/src/cmd/nsadmin/bash/bash_completion.d/zones
@@ -0,0 +1,50 @@
+_zlogin()
+{
+ local cur prev opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ # The -e and -l take non-zone arguments, otherwise complete zone
+ if [[ ${prev} != '-e' ]] && [[ ${prev} != '-l' ]]; then
+ local running=$(zoneadm list | grep -v '^global$')
+ COMPREPLY=( $(compgen -W "${running}" -- ${cur}) )
+ fi
+ if [[ -n "$COMPREPLY" ]]; then
+ return 0
+ fi
+
+ _zone_alias
+ return 0
+}
+
+_dash_z_zone()
+{
+ local cur prev opts base
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ # The -z takes a zone option, ignore everything else
+ if [[ ${prev} =~ -.*z$ ]]; then
+ local zones=$(zoneadm list -c | grep -v '^global$')
+ COMPREPLY=( $(compgen -W "${zones}" -- ${cur}) )
+ if [[ -n "$COMPREPLY" ]]; then
+ return 0
+ fi
+ _zone_alias
+ fi
+ return 0
+}
+
+complete -F _zlogin zlogin
+complete -F _dash_z_zone zoneadm
+complete -F _dash_z_zone zonecfg
+complete -F _dash_z_zone svcs
+complete -F _dash_z_zone svcadm
+complete -F _dash_z_zone svcprop
+complete -F _dash_z_zone pgrep
+complete -F _dash_z_zone pkill
+complete -F _dash_z_zone ps
+complete -F _dash_z_zone ptree
+complete -F _dash_z_zone wall
diff --git a/usr/src/cmd/nsadmin/bashrc.sh b/usr/src/cmd/nsadmin/bashrc.sh
deleted file mode 100644
index 938b0da67e..0000000000
--- a/usr/src/cmd/nsadmin/bashrc.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Define default prompt to <username>@<hostname>:<path><"($|#) ">
-# and print '#' for user "root" and '$' for normal users.
-#
-typeset +x PS1="\u@\h:\w\\$ "
diff --git a/usr/src/cmd/nsadmin/dot-bash_profile.sh b/usr/src/cmd/nsadmin/dot-bash_profile.sh
new file mode 100644
index 0000000000..dc732f6814
--- /dev/null
+++ b/usr/src/cmd/nsadmin/dot-bash_profile.sh
@@ -0,0 +1,12 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+#
+# Copyright (c) 2014, Joyent, Inc.
+#
+
+[ -f /root/.profile ] && source /root/.profile
+[ -f /root/.bashrc ] && source /root/.bashrc
diff --git a/usr/src/cmd/nsadmin/dot-bashrc.sh b/usr/src/cmd/nsadmin/dot-bashrc.sh
new file mode 100644
index 0000000000..0f06d70ece
--- /dev/null
+++ b/usr/src/cmd/nsadmin/dot-bashrc.sh
@@ -0,0 +1,57 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+#
+# Copyright (c) 2014, Joyent, Inc.
+#
+
+if [ "$PS1" ]; then
+ mt_tty=$(/usr/bin/tty 2>/dev/null)
+ if [[ $mt_tty =~ ^/dev/term/[abcd] ]]; then
+ # If we're on the serial console, we generally won't know how
+ # big our terminal is. Attempt to ask it using control sequences
+ # and resize our pty accordingly.
+ mt_output=$(/usr/lib/measure_terminal 2>/dev/null)
+ if [[ $? -eq 0 ]]; then
+ eval "$mt_output"
+ else
+ # We could not read the size, but we should set a 'sane'
+ # default as the dimensions of the previous user's terminal
+ # persist on the tty device.
+ export LINES=25
+ export COLUMNS=80
+ fi
+ /usr/bin/stty rows ${LINES} columns ${COLUMNS} 2>/dev/null
+ fi
+ unset mt_output mt_tty
+ shopt -s checkwinsize
+ if [[ -f /.dcinfo ]]; then
+ . /.dcinfo
+ DC_NAME="${SDC_DATACENTER_NAME}"
+ fi
+ if [[ -n "${DC_NAME}" ]]; then
+ PS1="[\u@\h (${DC_NAME}) \w]\\$ "
+ else
+ PS1="[\u@\h \w]\\$ "
+ fi
+ alias ll='ls -lF'
+ alias ls='ls --color=auto'
+ [ -n "${SSH_CLIENT}" ] && export PROMPT_COMMAND='echo -ne "\033]0;${HOSTNAME} \007" && history -a'
+fi
+
+# Load bash completion
+[ -f /etc/bash/bash_completion ] && . /etc/bash/bash_completion
+
+svclog() {
+ if [[ -z "$PAGER" ]]; then
+ PAGER=less
+ fi
+ $PAGER `svcs -L $1`
+}
+
+svclogf() {
+ /usr/bin/tail -f `svcs -L $1`
+}
diff --git a/usr/src/cmd/nsadmin/dot-profile.sh b/usr/src/cmd/nsadmin/dot-profile.sh
index a45e47b58d..fa6fb19714 100644
--- a/usr/src/cmd/nsadmin/dot-profile.sh
+++ b/usr/src/cmd/nsadmin/dot-profile.sh
@@ -1,14 +1,19 @@
#
-# Uncommenting PATH below will place /usr/gnu/bin at front,
-# adds /usr/sbin and /sbin to the end.
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
-# export PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin
+
#
-# Define default prompt to <username>@<hostname>:<path><"($|#) ">
-# and print '#' for user "root" and '$' for normal users.
+# Copyright 2019 Joyent, Inc.
#
-# override default prompt for bash
-# case "$0" in
-# -bash)
-# export PS1="\u@\h:\w\\$ "
-# esac
+
+PATH=/usr/bin:/usr/sbin:/smartdc/bin:/opt/smartdc/bin:/opt/local/bin:/opt/local/sbin:/opt/tools/bin:/opt/tools/sbin:/opt/smartdc/agents/bin
+MANPATH=/usr/share/man:/smartdc/man:/opt/smartdc/man:/opt/local/man:/opt/tools/man
+PAGER=less
+# If pkgsrc-tools is set up and the mozilla-rootcerts package is installed
+# configure the platform curl to use it.
+if [[ -f /opt/tools/share/mozilla-rootcerts/cacert.pem ]]; then
+ CURL_CA_BUNDLE=/opt/tools/share/mozilla-rootcerts/cacert.pem
+fi
+export PATH MANPATH PAGER CURL_CA_BUNDLE
diff --git a/usr/src/cmd/nsadmin/etc-profile.sh b/usr/src/cmd/nsadmin/etc-profile.sh
index c1dfae8eb8..b59a80791b 100644
--- a/usr/src/cmd/nsadmin/etc-profile.sh
+++ b/usr/src/cmd/nsadmin/etc-profile.sh
@@ -21,6 +21,7 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+#
# The profile that all logins get before using their own .profile.
@@ -41,19 +42,10 @@ fi
# -rsh is given its environment in its .profile.
case "$0" in
--bash)
- # set prompt for bash
- PS1="\u@\h:\w\\$ "
- export PS1
- ;;
-esac
-
-case "$0" in
-sh | -ksh | -ksh93 | -jsh | -bash | -zsh)
if [ ! -f .hushlogin ]
then
- /usr/sbin/quota
# Allow the user to break the Message-Of-The-Day only.
trap "trap '' 2" 2
/bin/cat -s /etc/motd
@@ -61,12 +53,12 @@ case "$0" in
/bin/mail -E
case $? in
- 0)
+ 0)
echo "You have new mail."
- ;;
- 2)
+ ;;
+ 2)
echo "You have mail."
- ;;
+ ;;
esac
fi
esac
diff --git a/usr/src/cmd/nsadmin/etc-skel-bashrc.sh b/usr/src/cmd/nsadmin/etc-skel-bashrc.sh
new file mode 100644
index 0000000000..128f6b79d7
--- /dev/null
+++ b/usr/src/cmd/nsadmin/etc-skel-bashrc.sh
@@ -0,0 +1,7 @@
+#
+# Define default prompt to <username>@<hostname>:<path><"($|#) ">
+# and print '#' for user "root" and '$' for normal users.
+#
+PS1='${LOGNAME}@$(/usr/bin/hostname):$(
+ [[ "${LOGNAME}" == "root" ]] && printf "%s" "${PWD/${HOME}/~}# " ||
+ printf "%s" "${PWD/${HOME}/~}\$ ")'
diff --git a/usr/src/cmd/nsadmin/system b/usr/src/cmd/nsadmin/system
index 29da0b787c..8ab13b7d3f 100644
--- a/usr/src/cmd/nsadmin/system
+++ b/usr/src/cmd/nsadmin/system
@@ -23,6 +23,7 @@
* SYSTEM SPECIFICATION FILE
*
+*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* It is not recommended to edit this file directly but rather
@@ -34,6 +35,10 @@
* recommendations on naming fragment files.
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+*
+* As SmartOS ships with /etc/ off a ramdisk, we don't support using the
+* /etc/system.d mechanism.
+*
* moddir:
*
@@ -108,3 +113,53 @@
*
* set test_module:debug = 0x13
+set ibft_noprobe=1
+
+set noexec_user_stack=1
+set noexec_user_stack_log=1
+set rlim_fd_cur=65536
+
+* Ensure that c-states are disabled
+set idle_cpu_no_deep_c=1
+
+* 10 GbE Tuning
+set ip:ip_squeue_fanout=1
+
+*
+* Machines should take a crash dump and reboot when receiving an NMI
+*
+set pcplusmp:apic_panic_on_nmi=1
+set apix:apic_panic_on_nmi=1
+
+*
+* Don't use multi-threaded fast crash dump or a high compression level
+*
+set dump_plat_mincpu=0
+set dump_bzip2_level=1
+
+*
+* Want additional crash dump metrics
+*
+set dump_metrics_on=1
+
+*
+* The traditional (and essentially entirely brain dead) cfgadm(1M)-centric
+* model of hotpluggin' appears to be basically unnecessary. This tunable
+* enables the system to create device nodes for newly inserted devices
+* automatically. See: usr/src/uts/common/io/sata/impl/sata.c:97
+*
+set sata:sata_auto_online=1
+
+*
+* We want to limit the time spent in any one I/O to 10 seconds for targets
+* that are not optical. This is still a very long time; our queue depth is
+* typically 10 or less, and disks will usually fail a command after 2-3s.
+* So we'd have to have multiple reads of bad sectors queued up to have any
+* chance of timing out. In practice, timeouts occur because of problems with
+* disk controllers or firmware, not media errors, and in those cases it will
+* not help at all to wait longer.
+*
+set sd:sd_io_time=10
+
+* Use hires tick to improve some scheduling latency issues
+set hires_tick=1
diff --git a/usr/src/cmd/ssh/etc/Makefile b/usr/src/cmd/nsadmin/zshrc
index 66a60e0705..1e9c83e57f 100644
--- a/usr/src/cmd/ssh/etc/Makefile
+++ b/usr/src/cmd/nsadmin/zshrc
@@ -18,41 +18,14 @@
#
# CDDL HEADER END
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+
+#
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
-
-MANIFEST = ssh.xml
-SVCMETHOD = sshd
-
-include ../../Makefile.cmd
-
-ETCSSHDIR= $(ROOTETC)/ssh
-DIRS= $(ETCSSHDIR)
-
-FILES= sshd_config ssh_config
-
-ETCSSHFILES= $(FILES:%=$(ETCSSHDIR)/%)
-
-$(ETCSSHFILES) := FILEMODE= 644
-
-ROOTMANIFESTDIR = $(ROOTSVCNETWORK)
-
-$(ETCSSHDIR)/% : %
- $(INS.file)
-
-$(DIRS):
- $(INS.dir)
-
-$(POFILE):
-
-SMOFF += signed
-
-all lint clean clobber _msg:
-
-install: all $(DIRS) $(ETCSSHFILES) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
-
-check: $(CHKMANIFEST)
+# ident "@(#)zshrc 1.1 10/02/08 SMI"
+#
-include ../../Makefile.targ
+# Turn on the "new" completion system. See zshcompsys(1).
+autoload -Uz compinit
+compinit -i
diff --git a/usr/src/cmd/nscd/Makefile b/usr/src/cmd/nscd/Makefile
index 9103db70ae..9bd4d3e18f 100644
--- a/usr/src/cmd/nscd/Makefile
+++ b/usr/src/cmd/nscd/Makefile
@@ -30,6 +30,7 @@ MANIFEST= name-service-cache.xml
SVCMETHOD= svc-nscd
include ../Makefile.cmd
+include ../Makefile.ctf
ROOTMANIFESTDIR= $(ROOTSVCSYSTEM)
diff --git a/usr/src/cmd/passwd/Makefile b/usr/src/cmd/passwd/Makefile
index 561357a16c..079e8b6050 100644
--- a/usr/src/cmd/passwd/Makefile
+++ b/usr/src/cmd/passwd/Makefile
@@ -33,6 +33,8 @@ lint := LDLIBS += -lpasswdutil
LDFLAGS += $(ZIGNORE)
LDLIBS += -lbsm -lpam -lnsl
+CPPFLAGS += -D__EXTENSIONS__
+
FILEMODE = 06555
XGETFLAGS += -a -x $(PROG).xcl
diff --git a/usr/src/cmd/pgrep/Makefile b/usr/src/cmd/pgrep/Makefile
index 67993f0ff2..09fb900da7 100644
--- a/usr/src/cmd/pgrep/Makefile
+++ b/usr/src/cmd/pgrep/Makefile
@@ -22,6 +22,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
PROG = pgrep
PKILLFILE = pkill
@@ -31,13 +33,14 @@ ROOTLINKS = $(ROOTBIN)/$(PKILLFILE)
OBJS = pgrep.o idtab.o psexp.o
SRCS = $(OBJS:.o=.c)
POFILES = $(OBJS:.o=.po)
-lint := LINTFLAGS = -ux
include ../Makefile.cmd
CLOBBERFILES += $(PKILLFILE)
+
CFLAGS += $(CCVERBOSE)
-CERRWARN += -_gcc=-Wno-parentheses
+CSTD = $(CSTD_GNU99)
+
LDLIBS += -luutil -lproject -lcontract
POFILE = ppgrep.po
@@ -69,6 +72,4 @@ $(ROOTLINKS): $(ROOTPROG)
clean:
$(RM) $(OBJS)
-lint: lint_SRCS
-
include ../Makefile.targ
diff --git a/usr/src/cmd/pgrep/idtab.c b/usr/src/cmd/pgrep/idtab.c
index 52d6e88cdb..56db6eab91 100644
--- a/usr/src/cmd/pgrep/idtab.c
+++ b/usr/src/cmd/pgrep/idtab.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
#include <libintl.h>
#include <string.h>
@@ -61,7 +63,8 @@ idtab_append(idtab_t *idt, idkey_t id)
if (idt->id_nelems >= idt->id_size) {
size = idt->id_size ? idt->id_size * IDTAB_GROW : IDTAB_DEFSIZE;
- if (data = realloc(idt->id_data, sizeof (idkey_t) * size)) {
+ if ((data = realloc(idt->id_data,
+ sizeof (idkey_t) * size)) != NULL) {
idt->id_data = data;
idt->id_size = size;
} else {
diff --git a/usr/src/cmd/pgrep/pgrep.c b/usr/src/cmd/pgrep/pgrep.c
index 4531f11267..0fda6733fb 100644
--- a/usr/src/cmd/pgrep/pgrep.c
+++ b/usr/src/cmd/pgrep/pgrep.c
@@ -24,6 +24,10 @@
*/
/* Copyright (c) 2012 by Delphix. All rights reserved */
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
@@ -59,11 +63,11 @@
#define TEXT_DOMAIN "SYS_TEST"
#endif
-#define OPT_SETB 0x0001 /* Set the bits specified by o_bits */
-#define OPT_CLRB 0x0002 /* Clear the bits specified by o_bits */
-#define OPT_FUNC 0x0004 /* Call the function specified by o_func */
-#define OPT_STR 0x0008 /* Set the string specified by o_ptr */
-#define OPT_CRIT 0x0010 /* Option is part of selection criteria */
+#define OPT_SETB 0x0001 /* Set the bits specified by o_bits */
+#define OPT_CLRB 0x0002 /* Clear the bits specified by o_bits */
+#define OPT_FUNC 0x0004 /* Call the function specified by o_func */
+#define OPT_STR 0x0008 /* Set the string specified by o_ptr */
+#define OPT_CRIT 0x0010 /* Option is part of selection criteria */
#define F_LONG_FMT 0x0001 /* Match against long format cmd */
#define F_NEWEST 0x0002 /* Match only newest pid */
@@ -138,7 +142,7 @@ static optdesc_t g_optdtab[] = {
{ 0, 0, 0, 0 }, /* 'k' */
{ OPT_SETB, F_LONG_OUT, 0, &g_flags }, /* 'l' */
{ 0, 0, 0, 0 }, /* 'm' */
- { OPT_SETB, F_NEWEST, 0, &g_flags }, /* -n */
+ { OPT_SETB, F_NEWEST, 0, &g_flags }, /* -n */
{ OPT_SETB, F_OLDEST, 0, &g_flags }, /* -o */
{ 0, 0, 0, 0 }, /* 'p' */
{ 0, 0, 0, 0 }, /* 'q' */
@@ -173,7 +177,7 @@ static pid_t g_pid; /* Current pid */
static int g_signal = SIGTERM; /* Signal to send */
static void
-print_proc(psinfo_t *psinfo)
+print_proc(psinfo_t *psinfo, char *argv __unused, size_t len __unused)
{
if (g_flags & F_OUTPUT)
(void) printf("%s%d", g_delim, (int)psinfo->pr_pid);
@@ -183,7 +187,7 @@ print_proc(psinfo_t *psinfo)
}
}
-static char *
+static void
mbstrip(char *buf, size_t nbytes)
{
wchar_t wc;
@@ -191,6 +195,7 @@ mbstrip(char *buf, size_t nbytes)
int n;
buf[nbytes - 1] = '\0';
+
p = buf;
while (*p != '\0') {
@@ -212,30 +217,23 @@ mbstrip(char *buf, size_t nbytes)
p += n;
}
}
-
- return (buf);
}
static void
-print_proc_long(psinfo_t *psinfo)
+print_proc_long(psinfo_t *psinfo, char *argv, size_t len)
{
- char *name;
-
- if (g_flags & F_LONG_FMT)
- name = mbstrip(psinfo->pr_psargs, PRARGSZ);
- else
- name = psinfo->pr_fname;
+ mbstrip(argv, len);
if (g_flags & F_OUTPUT)
- (void) printf("%s%5d %s", g_delim, (int)psinfo->pr_pid, name);
+ (void) printf("%s%5d %s", g_delim, (int)psinfo->pr_pid, argv);
else {
- (void) printf("%5d %s", (int)psinfo->pr_pid, name);
+ (void) printf("%5d %s", (int)psinfo->pr_pid, argv);
g_flags |= F_OUTPUT;
}
}
static void
-kill_proc(psinfo_t *psinfo)
+kill_proc(psinfo_t *psinfo, char *argv __unused, size_t len __unused)
{
if (psinfo->pr_pid > 0 && kill(psinfo->pr_pid, g_signal) == -1)
uu_warn(gettext("Failed to signal pid %d"),
@@ -268,6 +266,46 @@ open_proc_dir(const char *dirpath)
return (dirp);
}
+static void
+get_argv(int flags, psinfo_t *ps, char *buf, size_t bufsize)
+{
+ char *path = NULL;
+ ssize_t size = 0;
+ int fd;
+
+ if (!(flags & F_LONG_FMT)) {
+ (void) strlcpy(buf, ps->pr_fname, bufsize);
+ return;
+ }
+
+ if (getenv("SHORT_PSARGS") != NULL) {
+ (void) strlcpy(buf, ps->pr_psargs, bufsize);
+ return;
+ }
+
+ if (asprintf(&path, "%s/%d/cmdline", g_procdir,
+ (int)ps->pr_pid) != -1 && (fd = open(path, O_RDONLY)) != -1) {
+ size = read(fd, buf, bufsize);
+ (void) close(fd);
+ }
+
+ free(path);
+
+ if (size <= 0) {
+ (void) strlcpy(buf, ps->pr_psargs, bufsize);
+ } else {
+ buf[bufsize - 1] = '\0';
+ for (char *cp = buf; cp - buf < size; cp++) {
+ if (*cp == '\0' && (cp - buf) + 1 < size)
+ *cp = ' ';
+ }
+ }
+
+ for (ssize_t i = strlen(buf) - 1; i >= 0 && isspace(buf[i]); i--) {
+ buf[i] = '\0';
+ }
+}
+
#define NEWER(ps1, ps2) \
((ps1.pr_start.tv_sec > ps2.pr_start.tv_sec) || \
(ps1.pr_start.tv_sec == ps2.pr_start.tv_sec && \
@@ -275,9 +313,10 @@ open_proc_dir(const char *dirpath)
static int
scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp,
- void (*funcp)(psinfo_t *))
+ void (*funcp)(psinfo_t *, char *, size_t))
{
char procpath[MAXPATHLEN];
+ char argv[PRMAXARGVLEN] = "";
psinfo_t ps, ops;
dirent_t *dent;
int procfd;
@@ -285,9 +324,6 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp,
int reverse = (g_flags & F_REVERSE) ? 1 : 0;
int ovalid = 0, nmatches = 0, flags = 0;
- if (g_flags & F_LONG_FMT)
- flags |= PSEXP_PSARGS;
-
if (g_flags & F_EXACT_MATCH)
flags |= PSEXP_EXACT;
@@ -302,12 +338,17 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp,
if ((procfd = open(procpath, O_RDONLY)) == -1)
continue;
- if ((read(procfd, &ps, sizeof (ps)) == sizeof (psinfo_t)) &&
- (ps.pr_nlwp != 0) && (ps.pr_pid != g_pid) &&
- (psexp_match(psexp, &ps, flags) ^ reverse)) {
+ if (read(procfd, &ps, sizeof (ps)) != sizeof (psinfo_t)) {
+ (void) close(procfd);
+ continue;
+ }
+
+ get_argv(g_flags, &ps, argv, sizeof (argv));
+
+ if ((ps.pr_nlwp != 0) && (ps.pr_pid != g_pid) &&
+ (psexp_match(psexp, &ps, argv, flags) ^ reverse)) {
if (g_flags & F_NEWEST) {
- /* LINTED - opsinfo use ok */
if (!ovalid || NEWER(ps, ops)) {
(void) memcpy(&ops, &ps,
sizeof (psinfo_t));
@@ -320,7 +361,7 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp,
ovalid = 1;
}
} else {
- (*funcp)(&ps);
+ (*funcp)(&ps, argv, sizeof (argv));
nmatches++;
}
}
@@ -329,7 +370,8 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp,
}
if ((g_flags & (F_NEWEST | F_OLDEST)) && ovalid) {
- (*funcp)(&ops);
+ (*funcp)(&ops, argv, sizeof (argv));
+
nmatches++;
}
@@ -592,11 +634,13 @@ print_usage(FILE *stream)
int
main(int argc, char *argv[])
{
- void (*funcp)(psinfo_t *);
+ void (*funcp)(psinfo_t *, char *, size_t);
const char *optstr;
optdesc_t *optd;
int nmatches, c;
+ const char *zroot;
+ char buf[PATH_MAX];
DIR *dirp;
@@ -626,6 +670,12 @@ main(int argc, char *argv[])
opterr = 0;
+ zroot = zone_get_nroot();
+ if (zroot != NULL) {
+ (void) snprintf(buf, sizeof (buf), "%s/%s", zroot, g_procdir);
+ g_procdir = buf;
+ }
+
while (optind < argc) {
while ((c = getopt(argc, argv, optstr)) != (int)EOF) {
diff --git a/usr/src/cmd/pgrep/psexp.c b/usr/src/cmd/pgrep/psexp.c
index be14393bd1..abb8699523 100644
--- a/usr/src/cmd/pgrep/psexp.c
+++ b/usr/src/cmd/pgrep/psexp.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
#include <string.h>
#include <stdlib.h>
@@ -110,10 +112,9 @@ psexp_compile(psexp_t *psexp)
psexp->__f1.id_data && !idtab_search(&psexp->__f1, psinfo->__f2)
int
-psexp_match(psexp_t *psexp, psinfo_t *psinfo, int flags)
+psexp_match(psexp_t *psexp, psinfo_t *psinfo, const char *argv, int flags)
{
regmatch_t pmatch;
- const char *s;
if (NOMATCH(ps_euids, pr_euid))
return (0);
@@ -139,14 +140,11 @@ psexp_match(psexp_t *psexp, psinfo_t *psinfo, int flags)
return (0);
if (psexp->ps_pat != NULL) {
- s = (flags & PSEXP_PSARGS) ?
- psinfo->pr_psargs : psinfo->pr_fname;
-
- if (regexec(&psexp->ps_reg, s, 1, &pmatch, 0) != 0)
+ if (regexec(&psexp->ps_reg, argv, 1, &pmatch, 0) != 0)
return (0);
if ((flags & PSEXP_EXACT) &&
- (pmatch.rm_so != 0 || s[pmatch.rm_eo] != '\0'))
+ (pmatch.rm_so != 0 || argv[pmatch.rm_eo] != '\0'))
return (0);
}
diff --git a/usr/src/cmd/pgrep/psexp.h b/usr/src/cmd/pgrep/psexp.h
index 741050cbe4..7de6742311 100644
--- a/usr/src/cmd/pgrep/psexp.h
+++ b/usr/src/cmd/pgrep/psexp.h
@@ -24,11 +24,13 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
#ifndef _PSEXP_H
#define _PSEXP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <procfs.h>
#include <regex.h>
@@ -39,8 +41,7 @@ extern "C" {
#include "idtab.h"
-#define PSEXP_PSARGS 0x1 /* Match against psargs rather than fname */
-#define PSEXP_EXACT 0x2 /* Match must be exact (entire string) */
+#define PSEXP_EXACT 0x1 /* Match must be exact (entire string) */
typedef struct psexp {
idtab_t ps_euids; /* Table of effective uids to match */
@@ -54,14 +55,14 @@ typedef struct psexp {
idtab_t ps_taskids; /* Table of task ids to match */
idtab_t ps_zoneids; /* Table of zone ids to match */
idtab_t ps_ctids; /* Table of contract ids to match */
- const char *ps_pat; /* Uncompiled fname/psargs regexp pattern */
- regex_t ps_reg; /* Compiled fname/psargs regexp */
+ const char *ps_pat; /* Uncompiled fname/argv regexp pattern */
+ regex_t ps_reg; /* Compiled fname/argv regexp */
} psexp_t;
extern void psexp_create(psexp_t *);
extern void psexp_destroy(psexp_t *);
extern int psexp_compile(psexp_t *);
-extern int psexp_match(psexp_t *, psinfo_t *, int);
+extern int psexp_match(psexp_t *, psinfo_t *, const char *, int);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/prstat/prstat.c b/usr/src/cmd/prstat/prstat.c
index 0ff4f51bcd..f40219d75a 100644
--- a/usr/src/cmd/prstat/prstat.c
+++ b/usr/src/cmd/prstat/prstat.c
@@ -182,6 +182,33 @@ optdesc_t opts = {
-1 /* sort in decreasing order */
};
+
+static int
+proc_snprintf(char *_RESTRICT_KYWD s, size_t n,
+ const char *_RESTRICT_KYWD fmt, ...)
+{
+ static boolean_t ptools_zroot_valid = B_FALSE;
+ static const char *ptools_zroot = NULL;
+ va_list args;
+ int ret, nret = 0;
+
+ if (ptools_zroot_valid == B_FALSE) {
+ ptools_zroot_valid = B_TRUE;
+ ptools_zroot = zone_get_nroot();
+ }
+
+ if (ptools_zroot != NULL) {
+ nret = snprintf(s, n, "%s", ptools_zroot);
+ if (nret > n)
+ return (nret);
+ }
+ va_start(args, fmt);
+ ret = vsnprintf(s + nret, n - nret, fmt, args);
+ va_end(args);
+
+ return (ret + nret);
+}
+
/*
* Print timestamp as decimal reprentation of time_t value (-d u was specified)
* or the standard date format (-d d was specified).
@@ -849,9 +876,9 @@ lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage)
static int
read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize)
{
- char procfile[MAX_PROCFS_PATH];
+ char procfile[PATH_MAX];
- (void) snprintf(procfile, MAX_PROCFS_PATH,
+ (void) proc_snprintf(procfile, PATH_MAX,
"/proc/%s/%s", pidstr, file);
if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL)
return (1);
@@ -1415,6 +1442,7 @@ main(int argc, char **argv)
int timeout;
struct pollfd pollset;
char key;
+ char procpath[PATH_MAX];
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
@@ -1425,7 +1453,7 @@ main(int argc, char **argv)
pagesize = sysconf(_SC_PAGESIZE);
while ((opt = getopt(argc, argv,
- "vcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF) {
+ "vVcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF) {
switch (opt) {
case 'r':
opts.o_outpmode |= OPT_NORESOLVE;
@@ -1505,6 +1533,9 @@ main(int argc, char **argv)
while (p = strtok(NULL, ", "))
add_uid(&ruid_tbl, p);
break;
+ case 'V':
+ /* obsolete argument - accepted for compatability */
+ break;
case 'p':
fill_table(&pid_tbl, optarg, 'p');
break;
@@ -1614,7 +1645,8 @@ main(int argc, char **argv)
list_setkeyfunc(NULL, &opts, &lgroups, LT_LGRPS);
if (opts.o_outpmode & OPT_TERMCAP)
curses_on();
- if ((procdir = opendir("/proc")) == NULL)
+ (void) proc_snprintf(procpath, sizeof (procpath), "/proc");
+ if ((procdir = opendir(procpath)) == NULL)
Die(gettext("cannot open /proc directory\n"));
if (opts.o_outpmode & OPT_TTY) {
(void) printf(gettext("Please wait...\r"));
diff --git a/usr/src/cmd/prstat/prstat.h b/usr/src/cmd/prstat/prstat.h
index e205a98bd2..7d3913f731 100644
--- a/usr/src/cmd/prstat/prstat.h
+++ b/usr/src/cmd/prstat/prstat.h
@@ -73,6 +73,7 @@ extern "C" {
#define OPT_ZONES 0x2000 /* report about zones */
#define OPT_PSETS 0x4000 /* report for specified psets */
#define OPT_LGRP 0x8000 /* report home lgroups */
+ /* 0x10000 available for re-use */
#define OPT_UDATE 0x20000 /* print unix timestamp */
#define OPT_DDATE 0x40000 /* print timestamp in date(1) format */
#define OPT_NORESOLVE 0x80000 /* no nsswitch lookups */
diff --git a/usr/src/cmd/prtconf/prtconf.c b/usr/src/cmd/prtconf/prtconf.c
index 9865a9190e..613fcea78c 100644
--- a/usr/src/cmd/prtconf/prtconf.c
+++ b/usr/src/cmd/prtconf/prtconf.c
@@ -344,10 +344,11 @@ main(int argc, char *argv[])
sizeof (hw_provider));
/*
* If 0 bytes are returned (the system returns '1', for the \0),
- * we're probably on x86, default to "Unknown Hardware Vendor".
+ * we're probably on x86, and there has been no si-hw-provider
+ * set in /etc/bootrc, default to Joyent.
*/
if (ret <= 1) {
- (void) strncpy(hw_provider, "Unknown Hardware Vendor",
+ (void) strncpy(hw_provider, "Joyent",
sizeof (hw_provider));
}
(void) printf("System Configuration: %s %s\n", hw_provider,
diff --git a/usr/src/cmd/ps/ps.c b/usr/src/cmd/ps/ps.c
index 1a3e91689a..1387a9440a 100644
--- a/usr/src/cmd/ps/ps.c
+++ b/usr/src/cmd/ps/ps.c
@@ -27,7 +27,7 @@
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -64,6 +64,8 @@
#include <sys/pset.h>
#include <project.h>
#include <zone.h>
+#include <assert.h>
+#include <stdbool.h>
#define min(a, b) ((a) > (b) ? (b) : (a))
#define max(a, b) ((a) < (b) ? (b) : (a))
@@ -288,7 +290,7 @@ static int nzoneid = 0;
static int kbytes_per_page;
static int pidwidth;
-static char *procdir = "/proc"; /* standard /proc directory */
+static char procdir[MAXPATHLEN]; /* standard /proc directory */
static struct ughead euid_tbl; /* table to store selected euid's */
static struct ughead ruid_tbl; /* table to store selected real uid's */
@@ -337,10 +339,22 @@ static int pidcmp(const void *p1, const void *p2);
extern int ucbmain(int, char **);
static int stdmain(int, char **);
+/* also used by ucbps.c */
+void get_psargs(bool, bool, psinfo_t *, char *, size_t);
+void print_psargs(char *, int);
+
int
main(int argc, char **argv)
{
const char *me;
+ const char *zroot = zone_get_nroot();
+
+ /*
+ * If this is a branded zone, the native procfs may mounted in a
+ * non-standard location. Apply such a path prefix if it exists.
+ */
+ (void) snprintf(procdir, sizeof (procdir), "%s/proc", zroot != NULL ?
+ zroot : "");
/*
* The original two ps'es are linked in a single binary;
@@ -1362,14 +1376,12 @@ prfind(int found, psinfo_t *psinfo, char **tpp)
static void
prcom(psinfo_t *psinfo, char *ttyp)
{
- char *cp;
- long tm;
- int bytesleft;
- int wcnt, length;
- wchar_t wchar;
+ long tm;
+ int wcnt;
struct passwd *pwd;
- int zombie_lwp;
- char zonename[ZONENAME_MAX];
+ int zombie_lwp;
+ char zonename[ZONENAME_MAX];
+ char psargs[PRMAXARGVLEN] = "";
/*
* If process is zombie, call zombie print routine and return.
@@ -1558,44 +1570,22 @@ prcom(psinfo_t *psinfo, char *ttyp)
if (psinfo->pr_time.tv_nsec > 500000000)
tm++;
}
- (void) printf(" %4ld:%.2ld", tm / 60, tm % 60); /* [L]TIME */
+ (void) printf(" %4ld:%.2ld ", tm / 60, tm % 60); /* [L]TIME */
if (zombie_lwp) {
- (void) printf(" <defunct>\n");
+ (void) printf("<defunct>\n");
return;
}
if (!fflg) { /* CMD */
wcnt = namencnt(psinfo->pr_fname, 16, 8);
- (void) printf(" %.*s\n", wcnt, psinfo->pr_fname);
+ (void) printf("%.*s\n", wcnt, psinfo->pr_fname);
return;
}
-
- /*
- * PRARGSZ == length of cmd arg string.
- */
- psinfo->pr_psargs[PRARGSZ-1] = '\0';
- bytesleft = PRARGSZ;
- for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
- length = mbtowc(&wchar, cp, MB_LEN_MAX);
- if (length == 0)
- break;
- if (length < 0 || !iswprint(wchar)) {
- if (length < 0)
- length = 1;
- if (bytesleft <= length) {
- *cp = '\0';
- break;
- }
- /* omit the unprintable character */
- (void) memmove(cp, cp+length, bytesleft-length);
- length = 0;
- }
- bytesleft -= length;
- }
- wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, lflg ? 35 : PRARGSZ);
- (void) printf(" %.*s\n", wcnt, psinfo->pr_psargs);
+ get_psargs(false, fflg, psinfo, psargs, sizeof (psargs));
+ print_psargs(psargs, 0);
+ printf("\n");
}
/*
@@ -1650,20 +1640,98 @@ print_time(time_t tim, int width)
(void) printf("%*s", width, buf);
}
+void
+get_psargs(bool comm, bool full, psinfo_t *psinfo, char *buf, size_t bufsize)
+{
+ char *path = NULL;
+ ssize_t size = 0;
+ char *cp;
+ int fd;
+
+ assert(psinfo->pr_psargs[PRARGSZ - 1] == '\0');
+
+ if (full && getenv("SHORT_PSARGS") == NULL &&
+ asprintf(&path, "%s/%d/cmdline", procdir,
+ (int)psinfo->pr_pid) != -1 && (fd = open(path, O_RDONLY)) != -1) {
+ size = read(fd, buf, bufsize);
+ (void) close(fd);
+ }
+
+ free(path);
+
+ if (size <= 0) {
+ (void) strlcpy(buf, psinfo->pr_psargs, bufsize);
+ } else {
+ ssize_t i;
+
+ buf[bufsize - 1] = '\0';
+
+ for (cp = buf; cp - buf < size; cp++) {
+ if (*cp == '\0' && (cp - buf) + 1 < size)
+ *cp = ' ';
+ }
+
+ for (i = strlen(buf) - 1; i >= 0 && isspace(buf[i]); i--) {
+ buf[i] = '\0';
+ }
+ }
+
+ if (comm && (cp = strpbrk(buf, " \t\r\v\f\n")) != NULL)
+ *cp = '\0';
+}
+
+void
+print_psargs(char *psargs, int width)
+{
+ int bytesleft;
+ int length;
+ char *cp;
+ int wcnt;
+
+ bytesleft = strlen(psargs);
+
+ for (cp = psargs; *cp != '\0'; cp += length) {
+ wchar_t wchar;
+
+ length = mbtowc(&wchar, cp, MB_LEN_MAX);
+
+ if (length == 0)
+ break;
+
+ if (length < 0 || !iswprint(wchar)) {
+ if (length < 0)
+ length = 1;
+ if (bytesleft <= length) {
+ *cp = '\0';
+ break;
+ }
+ /* omit the unprintable character */
+ (void) memmove(cp, cp + length, bytesleft - length);
+ bytesleft -= length;
+ length = 0;
+ }
+ bytesleft -= length;
+ }
+
+ wcnt = namencnt(psargs, PRMAXARGVLEN, width);
+
+ if (width != 0) {
+ (void) printf("%.*s", width, psargs);
+ } else {
+ (void) printf("%-.*s", wcnt, psargs);
+ }
+}
+
static void
print_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
{
+ char psargs[PRMAXARGVLEN] = "";
int width = f->width;
struct passwd *pwd;
struct group *grp;
time_t cputime;
- int bytesleft;
int wcnt;
- wchar_t wchar;
- char *cp;
- int length;
ulong_t mask;
- char c = '\0', *csave = NULL;
int zombie_lwp;
zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
@@ -1916,12 +1984,11 @@ print_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
(void) printf("%s", "<defunct>");
break;
}
- csave = strpbrk(psinfo->pr_psargs, " \t\r\v\f\n");
- if (csave) {
- c = *csave;
- *csave = '\0';
- }
- /* FALLTHROUGH */
+
+ get_psargs(true, false, psinfo, psargs, sizeof (psargs));
+ print_psargs(psargs, f->next != NULL ? width : 0);
+ break;
+
case F_ARGS:
/*
* PRARGSZ == length of cmd arg string.
@@ -1930,38 +1997,11 @@ print_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
(void) printf("%-*s", width, "<defunct>");
break;
}
- psinfo->pr_psargs[PRARGSZ-1] = '\0';
- bytesleft = PRARGSZ;
- for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
- length = mbtowc(&wchar, cp, MB_LEN_MAX);
- if (length == 0)
- break;
- if (length < 0 || !iswprint(wchar)) {
- if (length < 0)
- length = 1;
- if (bytesleft <= length) {
- *cp = '\0';
- break;
- }
- /* omit the unprintable character */
- (void) memmove(cp, cp+length, bytesleft-length);
- length = 0;
- }
- bytesleft -= length;
- }
- wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, width);
- /*
- * Print full width unless this is the last format.
- */
- if (f->next != NULL)
- (void) printf("%-*.*s", width, wcnt,
- psinfo->pr_psargs);
- else
- (void) printf("%-.*s", wcnt,
- psinfo->pr_psargs);
- if (f->fname == F_COMM && csave)
- *csave = c;
+
+ get_psargs(false, fflg, psinfo, psargs, sizeof (psargs));
+ print_psargs(psargs, f->next != NULL ? width : 0);
break;
+
case F_TASKID:
(void) printf("%*d", width, (int)psinfo->pr_taskid);
break;
@@ -2422,7 +2462,8 @@ namencnt(char *cmd, int csisize, int scrsize)
return (8); /* default to use for illegal chars */
if ((nscrsz = wcwidth(wchar)) <= 0)
return (8);
- if (csiwcnt + ncsisz > csisize || scrwcnt + nscrsz > scrsize)
+ if (csiwcnt + ncsisz > csisize ||
+ (scrsize != 0 && scrwcnt + nscrsz > scrsize))
break;
csiwcnt += ncsisz;
scrwcnt += nscrsz;
diff --git a/usr/src/cmd/ps/ucbps.c b/usr/src/cmd/ps/ucbps.c
index 3110e95313..c368426184 100644
--- a/usr/src/cmd/ps/ucbps.c
+++ b/usr/src/cmd/ps/ucbps.c
@@ -21,7 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -65,8 +65,10 @@
#include <wctype.h>
#include <stdarg.h>
#include <sys/proc.h>
+#include <sys/procfs.h>
#include <priv_utils.h>
#include <zone.h>
+#include <stdbool.h>
#define NTTYS 2 /* max ttys that can be specified with the -t option */
/* only one tty can be specified with SunOS ps */
@@ -101,6 +103,7 @@ static int nflg; /* Numerical output */
static int pflg; /* Specific process id passed as argument */
static int Uflg; /* Update private database, ups_data */
static int errflg;
+static int wflag;
static char *gettty();
static char argbuf[ARGSIZ];
@@ -133,8 +136,7 @@ static void getarg(void);
static void prtime(timestruc_t st);
static void przom(psinfo_t *psinfo);
static int num(char *);
-static int preadargs(int, psinfo_t *, char *);
-static int preadenvs(int, psinfo_t *, char *);
+static int preadenvs(int, psinfo_t *, char *, size_t);
static int prcom(int, psinfo_t *, char *);
static int namencnt(char *, int, int);
static int pscompare(const void *, const void *);
@@ -142,12 +144,18 @@ static char *err_string(int);
extern int scrwidth(wchar_t); /* header file? */
+/* from ps.c */
+void get_psargs(bool, bool, psinfo_t *, char *, size_t);
+void print_psargs(char *, int);
+
int
ucbmain(int argc, char **argv)
{
psinfo_t info; /* process information structure from /proc */
- char *psargs = NULL; /* pointer to buffer for -w and -ww options */
- char *svpsargs = NULL;
+ /*
+ * This can also store env vars, so we bump up the size.
+ */
+ char psargs[PRMAXARGVLEN * 2] = "";
struct psent *psent;
int entsize;
int nent;
@@ -236,11 +244,12 @@ ucbmain(int argc, char **argv)
case 'U': /* update private database ups_data */
Uflg++;
break;
- case 'w': /* increase display width */
+ case 'w':
if (twidth < 132)
twidth = 132;
- else /* second w option */
+ if (wflag)
twidth = NCARGS;
+ wflag++;
break;
case 'v': /* display virtual memory format */
vflg++;
@@ -372,15 +381,9 @@ ucbmain(int argc, char **argv)
(void) sprintf(hdr, "%*s TT S TIME COMMAND",
pidwidth + 1, "PID");
- twidth = twidth - strlen(hdr) + 6;
+ twidth = twidth - strlen(hdr) + 7;
(void) printf("%s\n", hdr);
- if (twidth > PRARGSZ && (psargs = malloc(twidth)) == NULL) {
- (void) fprintf(stderr, "ps: no memory\n");
- exit(1);
- }
- svpsargs = psargs;
-
/*
* Determine which processes to print info about by searching
* the /proc directory and looking at each process.
@@ -410,7 +413,7 @@ retry:
if ((psfd = open(psname, O_RDONLY)) == -1)
continue;
asfd = -1;
- if (psargs != NULL || eflg) {
+ if (eflg) {
/* now we need the proc_owner privilege */
(void) __priv_bracket(PRIV_ON);
@@ -470,26 +473,20 @@ retry:
if (!found && !tflg && !aflg && info.pr_euid != my_uid)
goto closeit;
- /*
- * Read the args for the -w and -ww cases
- */
- if (asfd > 0) {
- if ((psargs != NULL &&
- preadargs(asfd, &info, psargs) == -1) ||
- (eflg && preadenvs(asfd, &info, psargs) == -1)) {
- int saverr = errno;
+ get_psargs(false, wflag, &info, psargs, sizeof (psargs));
- (void) close(asfd);
- if (saverr == EAGAIN)
- goto retry;
- if (saverr != ENOENT)
- (void) fprintf(stderr,
- "ps: read() on %s: %s\n",
- asname, err_string(saverr));
- continue;
+ if (eflg && asfd > 0 &&
+ preadenvs(asfd, &info, psargs, sizeof (psargs)) == -1) {
+ int saverr = errno;
+
+ (void) close(asfd);
+ if (saverr == EAGAIN)
+ goto retry;
+ if (saverr != ENOENT) {
+ (void) fprintf(stderr, "ps: read() on %s: %s\n",
+ asname, err_string(saverr));
}
- } else {
- psargs = info.pr_psargs;
+ continue;
}
if (nent >= entsize) {
@@ -507,22 +504,17 @@ retry:
exit(1);
}
*psent[nent].psinfo = info;
- if (psargs == NULL)
- psent[nent].psargs = NULL;
- else {
- if ((psent[nent].psargs = malloc(strlen(psargs)+1))
- == NULL) {
- (void) fprintf(stderr, "ps: no memory\n");
- exit(1);
- }
- (void) strcpy(psent[nent].psargs, psargs);
+
+ if ((psent[nent].psargs = strndup(psargs, twidth)) == NULL) {
+ (void) fprintf(stderr, "ps: no memory\n");
+ exit(1);
}
+
psent[nent].found = found;
nent++;
closeit:
if (asfd > 0)
(void) close(asfd);
- psargs = svpsargs;
}
/* revert to non-privileged user */
@@ -553,100 +545,17 @@ usage() /* print usage message and quit */
}
/*
- * Read the process arguments from the process.
- * This allows >PRARGSZ characters of arguments to be displayed but,
- * unlike pr_psargs[], the process may have changed them.
- */
-#define NARG 100
-static int
-preadargs(int pfd, psinfo_t *psinfo, char *psargs)
-{
- off_t argvoff = (off_t)psinfo->pr_argv;
- size_t len;
- char *psa = psargs;
- int bsize = twidth;
- int narg = NARG;
- off_t argv[NARG];
- off_t argoff;
- off_t nextargoff;
- int i;
-#ifdef _LP64
- caddr32_t argv32[NARG];
- int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64);
-#endif
-
- if (psinfo->pr_nlwp == 0 ||
- strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0)
- goto out;
-
- (void) memset(psa, 0, bsize--);
- nextargoff = 0;
- errno = EIO;
- while (bsize > 0) {
- if (narg == NARG) {
- (void) memset(argv, 0, sizeof (argv));
-#ifdef _LP64
- if (is32) {
- if ((i = pread(pfd, argv32, sizeof (argv32),
- argvoff)) <= 0) {
- if (i == 0 || errno == EIO)
- break;
- return (-1);
- }
- for (i = 0; i < NARG; i++)
- argv[i] = argv32[i];
- } else
-#endif
- if ((i = pread(pfd, argv, sizeof (argv),
- argvoff)) <= 0) {
- if (i == 0 || errno == EIO)
- break;
- return (-1);
- }
- narg = 0;
- }
- if ((argoff = argv[narg++]) == 0)
- break;
- if (argoff != nextargoff &&
- (i = pread(pfd, psa, bsize, argoff)) <= 0) {
- if (i == 0 || errno == EIO)
- break;
- return (-1);
- }
- len = strlen(psa);
- psa += len;
- *psa++ = ' ';
- bsize -= len + 1;
- nextargoff = argoff + len + 1;
-#ifdef _LP64
- argvoff += is32? sizeof (caddr32_t) : sizeof (caddr_t);
-#else
- argvoff += sizeof (caddr_t);
-#endif
- }
- while (psa > psargs && isspace(*(psa-1)))
- psa--;
-
-out:
- *psa = '\0';
- if (strlen(psinfo->pr_psargs) > strlen(psargs))
- (void) strcpy(psargs, psinfo->pr_psargs);
-
- return (0);
-}
-
-/*
* Read environment variables from the process.
* Append them to psargs if there is room.
*/
+#define NARG 100
static int
-preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
+preadenvs(int pfd, psinfo_t *psinfo, char *psargs, size_t bufsize)
{
off_t envpoff = (off_t)psinfo->pr_envp;
int len;
char *psa;
- char *psainit;
- int bsize;
+ int remaining;
int nenv = NARG;
off_t envp[NARG];
off_t envoff;
@@ -657,18 +566,18 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64);
#endif
- psainit = psa = (psargs != NULL)? psargs : psinfo->pr_psargs;
+ psa = psargs;
len = strlen(psa);
psa += len;
- bsize = twidth - len - 1;
+ remaining = bufsize - len - 1;
- if (bsize <= 0 || psinfo->pr_nlwp == 0 ||
+ if (remaining <= 0 || psinfo->pr_nlwp == 0 ||
strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0)
return (0);
nextenvoff = 0;
errno = EIO;
- while (bsize > 0) {
+ while (remaining > 0) {
if (nenv == NARG) {
(void) memset(envp, 0, sizeof (envp));
#ifdef _LP64
@@ -694,7 +603,7 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
if ((envoff = envp[nenv++]) == 0)
break;
if (envoff != nextenvoff &&
- (i = pread(pfd, psa+1, bsize, envoff)) <= 0) {
+ (i = pread(pfd, psa+1, remaining, envoff)) <= 0) {
if (i == 0 || errno == EIO)
break;
return (-1);
@@ -702,7 +611,7 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
*psa++ = ' ';
len = strlen(psa);
psa += len;
- bsize -= len + 1;
+ remaining -= len + 1;
nextenvoff = envoff + len + 1;
#ifdef _LP64
envpoff += is32? sizeof (caddr32_t) : sizeof (caddr_t);
@@ -710,7 +619,7 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs)
envpoff += sizeof (caddr_t);
#endif
}
- while (psa > psainit && isspace(*(psa-1)))
+ while (psa > psargs && isspace(*(psa-1)))
psa--;
*psa = '\0';
@@ -842,12 +751,9 @@ prtpct(ushort_t pct)
static int
prcom(int found, psinfo_t *psinfo, char *psargs)
{
- char *cp;
char *tp;
- char *psa;
long tm;
- int i, wcnt, length;
- wchar_t wchar;
+ int wcnt;
struct tty *ttyp;
/*
@@ -867,7 +773,6 @@ prcom(int found, psinfo_t *psinfo, char *psargs)
* info. If 't' is set, check if term is in list of desired terminals
* and print it if it is.
*/
- i = 0;
tp = gettty(psinfo);
if (*tp == '?' && !found && !xflg)
@@ -999,37 +904,9 @@ prcom(int found, psinfo_t *psinfo, char *psargs)
(void) printf(" %.*s", wcnt, psinfo->pr_fname);
return (1);
}
- /*
- * PRARGSZ == length of cmd arg string.
- */
- if (psargs == NULL) {
- psa = &psinfo->pr_psargs[0];
- i = PRARGSZ;
- tp = &psinfo->pr_psargs[PRARGSZ];
- } else {
- psa = psargs;
- i = strlen(psargs);
- tp = psa + i;
- }
- for (cp = psa; cp < tp; /* empty */) {
- if (*cp == 0)
- break;
- length = mbtowc(&wchar, cp, MB_LEN_MAX);
- if (length < 0 || !iswprint(wchar)) {
- (void) printf(" [ %.16s ]", psinfo->pr_fname);
- return (1);
- }
- cp += length;
- }
- wcnt = namencnt(psa, i, maxlen);
-#if 0
- /* dumps core on really long strings */
- (void) printf(" %.*s", wcnt, psa);
-#else
- (void) putchar(' ');
- (void) fwrite(psa, 1, wcnt, stdout);
-#endif
+ printf(" ");
+ print_psargs(psargs, wflag < 2 ? maxlen : 0);
return (1);
}
diff --git a/usr/src/cmd/ptools/Makefile.bld b/usr/src/cmd/ptools/Makefile.bld
index 8db9c449fe..efbfee9d04 100644
--- a/usr/src/cmd/ptools/Makefile.bld
+++ b/usr/src/cmd/ptools/Makefile.bld
@@ -22,6 +22,7 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
#
# Copyright 2019 Joyent, Inc.
@@ -79,6 +80,12 @@ CERRWARN_pwait += -_smatch=off
CERRWARN += $(CERRWARN_$(PROG))
+#
+# Common code definitions
+#
+COBJS = ptools_common.o
+CINC = -I../../common
+
# pargs depends on ../../common/elfcap components
# pmadvise depends on pmap components
@@ -89,14 +96,32 @@ CPPFLAGS_pargs = -I$(ELFCAP)
OBJS_pargs = elfcap.o
SRCS_pargs = $(ELFCAP)/elfcap.c
-CPPFLAGS_pmap = -I$(PMAP)
-OBJS_pmap = pmap_common.o
+CPPFLAGS_pmap = -I$(PMAP) $(CINC)
+OBJS_pmap = pmap_common.o $(COBJS)
SRCS_pmap = $(PMAP)/pmap_common.c
-CPPFLAGS_pmadvise = -I$(PMAP)
-OBJS_pmadvise = pmap_common.o
+CPPFLAGS_pmadvise = -I$(PMAP) $(CINC)
+OBJS_pmadvise = pmap_common.o $(COBJS)
SRCS_pmadvise = $(PMAP)/pmap_common.c
+CPPFLAGS_preap = $(CINC)
+OBJS_preap = $(COBJS)
+
+CPPFLAGS_psig = $(CINC)
+OBJS_psig = $(COBJS)
+
+CPPFLAGS_ptime = $(CINC)
+OBJS_ptime = $(COBJS)
+
+CPPFLAGS_ptree = $(CINC)
+OBJS_ptree = $(COBJS)
+
+CPPFLAGS_pwait = $(CINC)
+OBJS_pwait = $(COBJS)
+
+CPPFLAGS_pwdx = $(CINC)
+OBJS_pwdx = $(COBJS)
+
LN_pargs = penv pauxv
CPPFLAGS += $(CPPFLAGS_$(PROG))
@@ -124,6 +149,10 @@ pmap_common.o: $(PMAP)/pmap_common.c
$(COMPILE.c) $<
$(POST_PROCESS_O)
+%.o: ../../common/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
all: $(PROG) $(LN_$(PROG))
ROOTBINLN=$(LN_$(PROG):%=$(ROOTBIN)/%)
diff --git a/usr/src/cmd/ptools/common/ptools_common.c b/usr/src/cmd/ptools/common/ptools_common.c
new file mode 100644
index 0000000000..a747ab213e
--- /dev/null
+++ b/usr/src/cmd/ptools/common/ptools_common.c
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/feature_tests.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <zone.h>
+
+/*
+ * Common routines for ptools.
+ */
+
+int
+proc_snprintf(char *_RESTRICT_KYWD s, size_t n,
+ const char *_RESTRICT_KYWD fmt, ...)
+{
+ static boolean_t ptools_zroot_valid = B_FALSE;
+ static const char *ptools_zroot = NULL;
+ va_list args;
+ int ret, nret = 0;
+
+ if (ptools_zroot_valid == B_FALSE) {
+ ptools_zroot_valid = B_TRUE;
+ ptools_zroot = zone_get_nroot();
+ }
+
+ if (ptools_zroot != NULL) {
+ nret = snprintf(s, n, "%s", ptools_zroot);
+ if (nret > n)
+ return (nret);
+ }
+ va_start(args, fmt);
+ ret = vsnprintf(s + nret, n - nret, fmt, args);
+ va_end(args);
+
+ return (ret + nret);
+}
diff --git a/usr/src/cmd/ptools/common/ptools_common.h b/usr/src/cmd/ptools/common/ptools_common.h
new file mode 100644
index 0000000000..52bcae9e51
--- /dev/null
+++ b/usr/src/cmd/ptools/common/ptools_common.h
@@ -0,0 +1,36 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _PTOOLS_COMMON_H
+#define _PTOOLS_COMMON_H
+
+#include <sys/feature_tests.h>
+
+/*
+ * Common functions for the ptools.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int proc_snprintf(char *_RESTRICT_KYWD, size_t,
+ const char *_RESTRICT_KYWD, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PTOOLS_COMMON_H */
diff --git a/usr/src/cmd/ptools/pargs/pargs.c b/usr/src/cmd/ptools/pargs/pargs.c
index 55876dea65..6d82af21ba 100644
--- a/usr/src/cmd/ptools/pargs/pargs.c
+++ b/usr/src/cmd/ptools/pargs/pargs.c
@@ -823,6 +823,7 @@ static struct aux_id aux_arr[] = {
{ AT_BASE, "AT_BASE", at_null },
{ AT_FLAGS, "AT_FLAGS", at_null },
{ AT_ENTRY, "AT_ENTRY", at_null },
+ { AT_RANDOM, "AT_RANDOM", at_null },
{ AT_SUN_UID, "AT_SUN_UID", at_uid },
{ AT_SUN_RUID, "AT_SUN_RUID", at_uid },
{ AT_SUN_GID, "AT_SUN_GID", at_gid },
@@ -842,9 +843,11 @@ static struct aux_id aux_arr[] = {
{ AT_SUN_AUXFLAGS, "AT_SUN_AUXFLAGS", at_flags },
{ AT_SUN_EMULATOR, "AT_SUN_EMULATOR", at_str },
{ AT_SUN_BRANDNAME, "AT_SUN_BRANDNAME", at_str },
+ { AT_SUN_BRAND_NROOT, "AT_SUN_BRAND_NROOT", at_str },
{ AT_SUN_BRAND_AUX1, "AT_SUN_BRAND_AUX1", at_null },
{ AT_SUN_BRAND_AUX2, "AT_SUN_BRAND_AUX2", at_null },
{ AT_SUN_BRAND_AUX3, "AT_SUN_BRAND_AUX3", at_null },
+ { AT_SUN_BRAND_AUX4, "AT_SUN_BRAND_AUX4", at_null },
{ AT_SUN_COMMPAGE, "AT_SUN_COMMPAGE", at_null },
{ AT_SUN_FPTYPE, "AT_SUN_FPTYPE", at_null },
{ AT_SUN_FPSIZE, "AT_SUN_FPSIZE", at_null }
diff --git a/usr/src/cmd/ptools/pfiles/pfiles.c b/usr/src/cmd/ptools/pfiles/pfiles.c
index dd5ce4af11..474650faa4 100644
--- a/usr/src/cmd/ptools/pfiles/pfiles.c
+++ b/usr/src/cmd/ptools/pfiles/pfiles.c
@@ -511,6 +511,7 @@ show_sockaddr(const char *str, const struct sockaddr *sa, socklen_t len)
case AF_KEY: p = "AF_KEY"; break;
case AF_POLICY: p = "AF_POLICY"; break;
case AF_LINK: p = "AF_LINK"; break;
+ case AF_LX_NETLINK: p = "AF_LX_NETLINK"; break;
}
(void) printf("\t%s: %s\n", str, p);
diff --git a/usr/src/cmd/ptools/pflags/pflags.c b/usr/src/cmd/ptools/pflags/pflags.c
index 8054a80d3c..f19a945d95 100644
--- a/usr/src/cmd/ptools/pflags/pflags.c
+++ b/usr/src/cmd/ptools/pflags/pflags.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#include <stdio.h>
@@ -469,6 +469,9 @@ prwhy(int why)
case PR_SUSPENDED:
str = "PR_SUSPENDED";
break;
+ case PR_BRAND:
+ str = "PR_BRAND";
+ break;
default:
str = buf;
(void) sprintf(str, "%d", why);
diff --git a/usr/src/cmd/ptools/pmap/pmap.c b/usr/src/cmd/ptools/pmap/pmap.c
index 78bfa6b596..03f8bde791 100644
--- a/usr/src/cmd/ptools/pmap/pmap.c
+++ b/usr/src/cmd/ptools/pmap/pmap.c
@@ -22,6 +22,7 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -42,6 +43,7 @@
#include <sys/mman.h>
#include <sys/lgrp_user.h>
#include <libproc.h>
+#include "ptools_common.h"
#include "pmap_common.h"
@@ -199,7 +201,7 @@ main(int argc, char **argv)
const char *bar;
struct rlimit rlim;
struct stat64 statbuf;
- char buf[128];
+ char buf[PATH_MAX];
int mapfd;
int prg_gflags = PGRAB_RDONLY;
int prr_flags = 0;
@@ -358,7 +360,7 @@ main(int argc, char **argv)
proc_unctrl_psinfo(&psinfo);
if (Pstate(Pr) != PS_DEAD) {
- (void) snprintf(buf, sizeof (buf),
+ (void) proc_snprintf(buf, sizeof (buf),
"/proc/%d/map", (int)psinfo.pr_pid);
if ((mapfd = open(buf, O_RDONLY)) < 0) {
(void) fprintf(stderr, "%s: cannot "
@@ -590,7 +592,7 @@ rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd)
prmap_t *prmapp, *pmp;
ssize_t n;
- (void) snprintf(mapname, sizeof (mapname),
+ (void) proc_snprintf(mapname, sizeof (mapname),
"/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid);
if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) {
@@ -631,7 +633,7 @@ xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap)
prxmap_t *prmapp, *pmp;
ssize_t n;
- (void) snprintf(mapname, sizeof (mapname),
+ (void) proc_snprintf(mapname, sizeof (mapname),
"/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid);
if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) {
diff --git a/usr/src/cmd/ptools/pmap/pmap_common.c b/usr/src/cmd/ptools/pmap/pmap_common.c
index fff55ffdbc..81f42d67f7 100644
--- a/usr/src/cmd/ptools/pmap/pmap_common.c
+++ b/usr/src/cmd/ptools/pmap/pmap_common.c
@@ -37,6 +37,7 @@
#include <sys/types.h>
#include "pmap_common.h"
+#include "ptools_common.h"
/*
* We compare the high memory addresses since stacks are faulted in from
@@ -88,7 +89,7 @@ make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr,
return (NULL);
/* first see if we can find a path via /proc */
- (void) snprintf(path, sizeof (path), "/proc/%d/path/%s",
+ (void) proc_snprintf(path, sizeof (path), "/proc/%d/path/%s",
(int)Psp->pr_pid, mapname);
len = readlink(path, buf, bufsz - 1);
if (len >= 0) {
@@ -97,7 +98,7 @@ make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr,
}
/* fall back to object information reported by /proc */
- (void) snprintf(path, sizeof (path),
+ (void) proc_snprintf(path, sizeof (path),
"/proc/%d/object/%s", (int)Psp->pr_pid, mapname);
if (stat(path, &statb) == 0) {
dev_t dev = statb.st_dev;
diff --git a/usr/src/cmd/ptools/preap/preap.c b/usr/src/cmd/ptools/preap/preap.c
index 8d30b8027c..6d8eb75611 100644
--- a/usr/src/cmd/ptools/preap/preap.c
+++ b/usr/src/cmd/ptools/preap/preap.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -37,6 +35,8 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <libproc.h>
+#include <limits.h>
+#include "ptools_common.h"
#define NOREAP_TIME 60 /* wait 60 seconds before allow a reap */
@@ -53,11 +53,11 @@ intr(int sig)
static int
open_usage(pid_t pid, int *perr)
{
- char path[64];
+ char path[PATH_MAX];
struct stat64 st;
int fd;
- (void) snprintf(path, sizeof (path), "/proc/%d/usage", (int)pid);
+ (void) proc_snprintf(path, sizeof (path), "/proc/%d/usage", (int)pid);
/*
* Attempt to open the usage file, and return the fd if we can
diff --git a/usr/src/cmd/ptools/psig/psig.c b/usr/src/cmd/ptools/psig/psig.c
index 2790463b9a..6733c7b8d4 100644
--- a/usr/src/cmd/ptools/psig/psig.c
+++ b/usr/src/cmd/ptools/psig/psig.c
@@ -21,6 +21,7 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -35,6 +36,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <libproc.h>
+#include "ptools_common.h"
/* evil knowledge of libc internals */
#include "../../../lib/libc/inc/thr_uberdata.h"
@@ -170,7 +172,7 @@ lwp_iter(void *cd, const lwpstatus_t *lwpstatus)
static int
look(char *arg)
{
- char pathname[100];
+ char pathname[PATH_MAX];
struct stat statb;
int fd = -1;
int sig, gcode;
@@ -197,7 +199,8 @@ look(char *arg)
(void) memcpy(&psinfo, psinfop, sizeof (psinfo_t));
proc_unctrl_psinfo(&psinfo);
- (void) sprintf(pathname, "/proc/%d/sigact", (int)psinfo.pr_pid);
+ (void) proc_snprintf(pathname, sizeof (pathname), "/proc/%d/sigact",
+ (int)psinfo.pr_pid);
if ((fd = open(pathname, O_RDONLY)) < 0) {
perr("open sigact");
goto look_error;
@@ -211,7 +214,7 @@ look(char *arg)
action = malloc(maxsig * sizeof (struct sigaction));
if (action == NULL) {
(void) fprintf(stderr,
- "%s: cannot malloc() space for %d sigaction structures\n",
+ "%s: cannot malloc() space for %d sigaction structures\n",
command, maxsig);
goto look_error;
}
diff --git a/usr/src/cmd/ptools/ptime/ptime.c b/usr/src/cmd/ptools/ptime/ptime.c
index 2da2f8d281..b1f53593c2 100644
--- a/usr/src/cmd/ptools/ptime/ptime.c
+++ b/usr/src/cmd/ptools/ptime/ptime.c
@@ -41,6 +41,8 @@
#include <sys/time.h>
#include <signal.h>
#include <libproc.h>
+#include <limits.h>
+#include "ptools_common.h"
static int look(pid_t);
static void hr_min_sec(char *, long);
@@ -189,7 +191,7 @@ main(int argc, char **argv)
static int
look(pid_t pid)
{
- char pathname[100];
+ char pathname[PATH_MAX];
int rval = 0;
int fd;
psinfo_t psinfo;
@@ -203,7 +205,8 @@ look(pid_t pid)
if (proc_get_psinfo(pid, &psinfo) < 0)
return (perr("read psinfo"));
- (void) sprintf(pathname, "/proc/%d/usage", (int)pid);
+ (void) proc_snprintf(pathname, sizeof (pathname), "/proc/%d/usage",
+ (int)pid);
if ((fd = open(pathname, O_RDONLY)) < 0)
return (perr("open usage"));
diff --git a/usr/src/cmd/ptools/pwait/pwait.c b/usr/src/cmd/ptools/pwait/pwait.c
index 0733c355cf..ec11573477 100644
--- a/usr/src/cmd/ptools/pwait/pwait.c
+++ b/usr/src/cmd/ptools/pwait/pwait.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdio_ext.h>
#include <ctype.h>
@@ -39,6 +37,8 @@
#include <poll.h>
#include <procfs.h>
#include <sys/resource.h>
+#include <limits.h>
+#include "ptools_common.h"
static int count_my_files();
static char *command;
@@ -49,6 +49,7 @@ static char *command;
int
main(int argc, char **argv)
{
+ char buf[PATH_MAX];
unsigned long remain = 0;
struct pollfd *pollfd;
struct pollfd *pfd;
@@ -75,10 +76,12 @@ main(int argc, char **argv)
(void) fprintf(stderr, "usage:\t%s [-v] pid ...\n", command);
(void) fprintf(stderr, " (wait for processes to terminate)\n");
(void) fprintf(stderr,
- " -v: verbose; report terminations to standard out\n");
+ " -v: verbose; report terminations to standard out\n");
return (2);
}
+ (void) proc_snprintf(buf, sizeof (buf), "/proc/");
+
/* make sure we have enough file descriptors */
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
int nfiles = count_my_files();
@@ -87,8 +90,8 @@ main(int argc, char **argv)
rlim.rlim_cur = argc + nfiles + SLOP;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
(void) fprintf(stderr,
- "%s: insufficient file descriptors\n",
- command);
+ "%s: insufficient file descriptors\n",
+ command);
return (2);
}
}
@@ -108,11 +111,11 @@ main(int argc, char **argv)
if (strchr(arg, '/') != NULL)
(void) strncpy(psinfofile, arg, sizeof (psinfofile));
else {
- (void) strcpy(psinfofile, "/proc/");
+ (void) strcpy(psinfofile, buf);
(void) strncat(psinfofile, arg, sizeof (psinfofile)-6);
}
(void) strncat(psinfofile, "/psinfo",
- sizeof (psinfofile)-strlen(psinfofile));
+ sizeof (psinfofile)-strlen(psinfofile));
pfd = &pollfd[i];
if ((pfd->fd = open(psinfofile, O_RDONLY)) >= 0) {
@@ -126,7 +129,7 @@ main(int argc, char **argv)
pfd->revents = 0;
} else if (errno == ENOENT) {
(void) fprintf(stderr, "%s: no such process: %s\n",
- command, arg);
+ command, arg);
} else {
perror(arg);
}
@@ -160,9 +163,9 @@ main(int argc, char **argv)
if (pread(pfd->fd, &psinfo,
sizeof (psinfo), (off_t)0)
== sizeof (psinfo)) {
- (void) printf(
- "%s: terminated, wait status 0x%.4x\n",
- arg, psinfo.pr_wstat);
+ (void) printf("%s: terminated, "
+ "wait status 0x%.4x\n",
+ arg, psinfo.pr_wstat);
} else {
(void) printf(
"%s: terminated\n", arg);
@@ -170,10 +173,10 @@ main(int argc, char **argv)
}
if (pfd->revents & POLLNVAL)
(void) printf("%s: system process\n",
- arg);
+ arg);
if (pfd->revents & ~(POLLPRI|POLLHUP|POLLNVAL))
(void) printf("%s: unknown error\n",
- arg);
+ arg);
}
(void) close(pfd->fd);
diff --git a/usr/src/cmd/ptools/pwdx/pwdx.c b/usr/src/cmd/ptools/pwdx/pwdx.c
index adf42c0877..4a2c6f0c3f 100644
--- a/usr/src/cmd/ptools/pwdx/pwdx.c
+++ b/usr/src/cmd/ptools/pwdx/pwdx.c
@@ -22,10 +22,9 @@
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <unistd.h>
#include <string.h>
@@ -33,6 +32,8 @@
#include <libproc.h>
#include <sys/param.h>
+#include "ptools_common.h"
+
static char *command;
static int
@@ -49,7 +50,7 @@ show_cwd(const char *arg)
return (1);
}
- (void) snprintf(proc, sizeof (proc), "/proc/%d/path/cwd",
+ (void) proc_snprintf(proc, sizeof (proc), "/proc/%d/path/cwd",
(int)p.pr_pid);
if ((ret = readlink(proc, cwd, sizeof (cwd) - 1)) <= 0) {
diff --git a/usr/src/cmd/rcap/common/utils.c b/usr/src/cmd/rcap/common/utils.c
index 799fdcef23..dd511c7c50 100644
--- a/usr/src/cmd/rcap/common/utils.c
+++ b/usr/src/cmd/rcap/common/utils.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -257,77 +258,3 @@ xatoi(char *p)
return (i);
}
}
-
-/*
- * get_running_zones() calls zone_list(2) to find out how many zones are
- * running. It then calls zone_list(2) again to fetch the list of running
- * zones (stored in *zents).
- */
-int
-get_running_zones(uint_t *nzents, zone_entry_t **zents)
-{
- zoneid_t *zids;
- uint_t nzents_saved;
- int i;
- zone_entry_t *zentp;
- zone_state_t zstate;
-
- *zents = NULL;
- if (zone_list(NULL, nzents) != 0) {
- warn(gettext("could not get zoneid list\n"));
- return (E_ERROR);
- }
-
-again:
- if (*nzents == 0)
- return (E_SUCCESS);
-
- if ((zids = (zoneid_t *)calloc(*nzents, sizeof (zoneid_t))) == NULL) {
- warn(gettext("out of memory: zones will not be capped\n"));
- return (E_ERROR);
- }
-
- nzents_saved = *nzents;
-
- if (zone_list(zids, nzents) != 0) {
- warn(gettext("could not get zone list\n"));
- free(zids);
- return (E_ERROR);
- }
- if (*nzents != nzents_saved) {
- /* list changed, try again */
- free(zids);
- goto again;
- }
-
- *zents = calloc(*nzents, sizeof (zone_entry_t));
- if (*zents == NULL) {
- warn(gettext("out of memory: zones will not be capped\n"));
- free(zids);
- return (E_ERROR);
- }
-
- zentp = *zents;
- for (i = 0; i < *nzents; i++) {
- char name[ZONENAME_MAX];
-
- if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
- warn(gettext("could not get name for "
- "zoneid %d\n"), zids[i]);
- continue;
- }
-
- (void) strlcpy(zentp->zname, name, sizeof (zentp->zname));
- zentp->zid = zids[i];
- if (zone_get_state(name, &zstate) != Z_OK ||
- zstate != ZONE_STATE_RUNNING)
- continue;
-
-
- zentp++;
- }
- *nzents = zentp - *zents;
-
- free(zids);
- return (E_SUCCESS);
-}
diff --git a/usr/src/cmd/rcap/common/utils.h b/usr/src/cmd/rcap/common/utils.h
index 7196cfb4ce..cf2e17c080 100644
--- a/usr/src/cmd/rcap/common/utils.h
+++ b/usr/src/cmd/rcap/common/utils.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#ifndef _UTILS_H
@@ -98,7 +99,6 @@ extern void vdprintfe(int, const char *, va_list);
extern void dprintfe(int, char *, ...);
extern void hrt2ts(hrtime_t, timestruc_t *);
extern int xatoi(char *);
-extern int get_running_zones(uint_t *, zone_entry_t **);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/rcap/rcapadm/rcapadm.c b/usr/src/cmd/rcap/rcapadm/rcapadm.c
index 92888b2071..b92115469a 100644
--- a/usr/src/cmd/rcap/rcapadm/rcapadm.c
+++ b/usr/src/cmd/rcap/rcapadm/rcapadm.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -145,20 +146,29 @@ out:
scf_handle_destroy(h);
}
+static int
+set_zone_cap(char *zonename, uint64_t mcap)
+{
+ char cmd[128 + ZONENAME_MAX];
+
+ (void) snprintf(cmd, sizeof (cmd), "/usr/bin/prctl -r "
+ "-n zone.max-physical-memory -v %llu -i zone %s", mcap, zonename);
+ return (system(cmd));
+}
+
/*
* Update the in-kernel memory cap for the specified zone.
*/
static int
update_zone_mcap(char *zonename, char *maxrss)
{
- zoneid_t zone_id;
uint64_t num;
if (getzoneid() != GLOBAL_ZONEID || zonecfg_in_alt_root())
return (E_SUCCESS);
/* get the running zone from the kernel */
- if ((zone_id = getzoneidbyname(zonename)) == -1) {
+ if (getzoneidbyname(zonename) == -1) {
(void) fprintf(stderr, gettext("zone '%s' must be running\n"),
zonename);
return (E_ERROR);
@@ -169,7 +179,7 @@ update_zone_mcap(char *zonename, char *maxrss)
return (E_ERROR);
}
- if (zone_setattr(zone_id, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) {
+ if (set_zone_cap(zonename, num) == -1) {
(void) fprintf(stderr, gettext("could not set memory "
"cap for zone '%s'\n"), zonename);
return (E_ERROR);
diff --git a/usr/src/cmd/rcap/rcapd/Makefile b/usr/src/cmd/rcap/rcapd/Makefile
index 77f4d6812e..355b5eef0a 100644
--- a/usr/src/cmd/rcap/rcapd/Makefile
+++ b/usr/src/cmd/rcap/rcapd/Makefile
@@ -22,6 +22,8 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2020 Joyent, Inc.
+#
include ../../Makefile.cmd
include ../../Makefile.cmd.64
@@ -62,7 +64,7 @@ LINTSRCS = rcapd_main.c \
$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
CPPFLAGS += -DDEBUG_MSG
CPPFLAGS += -I$(COMMON_DIR)
-LDLIBS += -lkstat -lproc -lproject -lzonecfg -lumem -lscf
+LDLIBS += -lkstat -lproc -lproject -lumem -lscf
LDLIBS += $(EXTRA_LDLIBS)
LINTFLAGS64 += -u
diff --git a/usr/src/cmd/rcap/rcapd/rcapd_collection_zone.c b/usr/src/cmd/rcap/rcapd/rcapd_collection_zone.c
index db86aa6276..88403dda37 100644
--- a/usr/src/cmd/rcap/rcapd/rcapd_collection_zone.c
+++ b/usr/src/cmd/rcap/rcapd/rcapd_collection_zone.c
@@ -21,16 +21,17 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <procfs.h>
#include <project.h>
#include <stdlib.h>
#include <strings.h>
#include <zone.h>
#include <libzonecfg.h>
+#include <dirent.h>
+#include <libproc.h>
#include "rcapd.h"
#include "utils.h"
@@ -39,61 +40,117 @@ extern boolean_t gz_capped;
/* round up to next y = 2^n */
#define ROUNDUP(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
-static void
-update_zone(zone_entry_t *zent, void *walk_data)
+static struct ps_prochandle *
+grab_zone_proc(zoneid_t zid)
{
- void(*update_notification_cb)(char *, char *, int, uint64_t, int) =
- (void(*)(char *, char *, int, uint64_t, int))walk_data;
- int changes;
- int64_t max_rss;
+ DIR *dirp;
+ struct dirent *dentp;
+ int pid, pid_self, tmp;
+ psinfo_t psinfo;
+ struct ps_prochandle *pr = NULL;
+
+ pid_self = getpid();
+
+ if ((dirp = opendir("/proc")) == NULL)
+ return (NULL);
+
+ while (dentp = readdir(dirp)) {
+ pid = atoi(dentp->d_name);
+
+ /* Skip self */
+ if (pid == pid_self)
+ continue;
+
+ if (proc_get_psinfo(pid, &psinfo) != 0)
+ continue;
+
+ if (psinfo.pr_zoneid != zid)
+ continue;
+
+ /* attempt to grab process */
+ if ((pr = Pgrab(pid, 0, &tmp)) != NULL) {
+ if (Psetflags(pr, PR_RLC) != 0) {
+ Prelease(pr, 0);
+ }
+ if (Pcreate_agent(pr) == 0) {
+ if (pr_getzoneid(pr) != zid) {
+ Prelease(pr, 0);
+ continue;
+ }
+
+ (void) closedir(dirp);
+ return (pr);
+ } else {
+ Prelease(pr, 0);
+ }
+ }
+ }
+
+ (void) closedir(dirp);
+ return (NULL);
+}
+
+static uint64_t
+get_zone_cap(zoneid_t zid)
+{
+ rctlblk_t *rblk;
uint64_t mcap;
- lcollection_t *lcol;
- rcid_t colid;
+ struct ps_prochandle *pr;
- if (zone_getattr(zent->zid, ZONE_ATTR_PHYS_MCAP, &mcap,
- sizeof (mcap)) != -1 && mcap != 0)
- max_rss = ROUNDUP(mcap, 1024) / 1024;
- else
- max_rss = 0;
-
- if (zent->zid == GLOBAL_ZONEID) {
- if (max_rss > 0)
- gz_capped = B_TRUE;
- else
- gz_capped = B_FALSE;
+ if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL)
+ return (UINT64_MAX);
+
+ if ((pr = grab_zone_proc(zid)) == NULL) {
+ free(rblk);
+ return (UINT64_MAX);
}
+ if (pr_getrctl(pr, "zone.max-physical-memory", NULL, rblk,
+ RCTL_FIRST)) {
+ Pdestroy_agent(pr);
+ Prelease(pr, 0);
+ free(rblk);
+ return (UINT64_MAX);
+ }
- colid.rcid_type = RCIDT_ZONE;
- colid.rcid_val = zent->zid;
+ Pdestroy_agent(pr);
+ Prelease(pr, 0);
- lcol = lcollection_insert_update(&colid, max_rss, zent->zname,
- &changes);
- if (update_notification_cb != NULL)
- update_notification_cb("zone", zent->zname, changes, max_rss,
- (lcol != NULL) ? lcol->lcol_mark : 0);
+ mcap = rctlblk_get_value(rblk);
+ free(rblk);
+ return (mcap);
}
-
+/*
+ * For zones, rcapd only caps the global zone, since each non-global zone
+ * caps itself.
+ */
/* ARGSUSED */
void
lcollection_update_zone(lcollection_update_type_t ut,
void(*update_notification_cb)(char *, char *, int, uint64_t, int))
{
- int i;
- uint_t nzents;
- zone_entry_t *zents;
-
- /*
- * Enumerate running zones.
- */
- if (get_running_zones(&nzents, &zents) != 0)
- return;
-
- for (i = 0; i < nzents; i++) {
- update_zone(&zents[i], (void *)update_notification_cb);
+ int changes;
+ int64_t max_rss;
+ uint64_t mcap;
+ lcollection_t *lcol;
+ rcid_t colid;
+ mcap = get_zone_cap(GLOBAL_ZONEID);
+ if (mcap != 0 && mcap != UINT64_MAX) {
+ max_rss = ROUNDUP(mcap, 1024) / 1024;
+ gz_capped = B_TRUE;
+ } else {
+ max_rss = UINT64_MAX / 1024;
+ gz_capped = B_FALSE;
}
- free(zents);
+ colid.rcid_type = RCIDT_ZONE;
+ colid.rcid_val = GLOBAL_ZONEID;
+
+ lcol = lcollection_insert_update(&colid, max_rss, GLOBAL_ZONENAME,
+ &changes);
+ if (update_notification_cb != NULL)
+ update_notification_cb("zone", GLOBAL_ZONENAME, changes,
+ max_rss, (lcol != NULL) ? lcol->lcol_mark : 0);
}
diff --git a/usr/src/cmd/rcap/rcapd/rcapd_scanner.c b/usr/src/cmd/rcap/rcapd/rcapd_scanner.c
index 3f09a7f4ed..458e8f3bef 100644
--- a/usr/src/cmd/rcap/rcapd/rcapd_scanner.c
+++ b/usr/src/cmd/rcap/rcapd/rcapd_scanner.c
@@ -21,6 +21,7 @@
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2012 Joyent, Inc. All rights reserved.
*/
#include <sys/mman.h>
@@ -549,7 +550,7 @@ pageout(pid_t pid, struct ps_prochandle *Pr, caddr_t start, caddr_t end)
errno = 0;
res = pr_memcntl(Pr, start, (end - start), MC_SYNC,
- (caddr_t)(MS_ASYNC | MS_INVALIDATE), 0, 0);
+ (caddr_t)(MS_ASYNC | MS_INVALCURPROC), 0, 0);
debug_high("pr_memcntl [%p-%p): %d", (void *)start, (void *)end, res);
/*
diff --git a/usr/src/cmd/rcap/rcapstat/Makefile b/usr/src/cmd/rcap/rcapstat/Makefile
index 1b4e0e6180..a886b05782 100644
--- a/usr/src/cmd/rcap/rcapstat/Makefile
+++ b/usr/src/cmd/rcap/rcapstat/Makefile
@@ -22,6 +22,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2020 Joyent, Inc.
+#
.KEEP_STATE:
.SUFFIXES:
@@ -29,7 +31,7 @@
include ../../Makefile.cmd
COMMON_DIR= ../common # for Makefile.com
-SRCS = rcapstat.c \
+SRCS = rcapstat.c \
utils.c
LINTSRCS = $(COMMON_DIR)/utils.c \
@@ -41,9 +43,9 @@ STATCOMMONDIR = $(SRC)/cmd/stat/common
STAT_COMMON_OBJS = timestamp.o
STAT_COMMON_SRCS = $(STAT_COMMON_OBJS:%.o=$(STATCOMMONDIR)/%.c)
-$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
-CPPFLAGS += -I$(COMMON_DIR) -I$(STATCOMMONDIR)
-LDLIBS += -lumem -lzonecfg -lscf
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+CPPFLAGS += -I$(COMMON_DIR) -I$(STATCOMMONDIR)
+LDLIBS += -lumem -lscf
LDFLAGS += $(MAPFILE.NGB:%=-M%)
LINTFLAGS += $(LDLIBS) -mnu
@@ -54,7 +56,7 @@ OBJS = $(SRCS:%.c=%.o) rcapd_conf.o
POFILES = $(OBJS:%.o=%.po)
POFILE = p$(PROG).po
-CLOBBERFILES += rcapd_conf.c $(POFILES) $(POFILE)
+CLOBBERFILES += rcapd_conf.c $(POFILES) $(POFILE)
.NO_PARALLEL:
.PARALLEL: $(OBJS) $(LINTFILES)
diff --git a/usr/src/cmd/rcap/rcapstat/rcapstat.c b/usr/src/cmd/rcap/rcapstat/rcapstat.c
index 0632250fed..2838c6e5d5 100644
--- a/usr/src/cmd/rcap/rcapstat/rcapstat.c
+++ b/usr/src/cmd/rcap/rcapstat/rcapstat.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -72,6 +73,8 @@ typedef struct col {
static col_t *col_head;
static int ncol;
+#define RCAPD_NA "rcapd is not active (try zonememstat)\n"
+
static col_t *
col_find(rcid_t id)
{
@@ -152,7 +155,7 @@ read_stats(rcid_type_t stat_type)
struct stat st;
if ((fd = open(STAT_FILE_DEFAULT, O_RDONLY)) < 0) {
- warn(gettext("rcapd is not active\n"));
+ warn(gettext(RCAPD_NA));
return (E_ERROR);
}
@@ -173,7 +176,7 @@ read_stats(rcid_type_t stat_type)
pid = hdr.rs_pid;
(void) snprintf(procfile, 20, "/proc/%lld/psinfo", pid);
if ((proc_fd = open(procfile, O_RDONLY)) < 0) {
- warn(gettext("rcapd is not active\n"));
+ warn(gettext(RCAPD_NA));
(void) close(fd);
return (E_ERROR);
}
diff --git a/usr/src/cmd/savecore/Makefile.com b/usr/src/cmd/savecore/Makefile.com
index 1f6e09b231..c4ba4f89f0 100644
--- a/usr/src/cmd/savecore/Makefile.com
+++ b/usr/src/cmd/savecore/Makefile.com
@@ -21,7 +21,7 @@
#
# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
PROG= savecore
SRCS= ../savecore.c ../../../uts/common/os/compress.c
@@ -54,12 +54,14 @@ BZIP2OBJS = bz2blocksort.o \
bz2crctable.o \
bz2huffman.o
+CHACHAOBJ = chacha.o
+
.KEEP_STATE:
all: $(PROG)
-$(PROG): $(OBJS) $(BZIP2OBJS)
- $(LINK.c) -o $(PROG) $(OBJS) $(BZIP2OBJS) $(LDLIBS)
+$(PROG): $(OBJS) $(BZIP2OBJS) $(CHACHAOBJ)
+ $(LINK.c) -o $(PROG) $(OBJS) $(BZIP2OBJS) $(CHACHAOBJ) $(LDLIBS)
$(POST_PROCESS)
clean:
@@ -95,3 +97,8 @@ include ../../Makefile.targ
bz2%.o: ../../../common/bzip2/%.c
$(COMPILE.c) -o $@ -I$(SRC)/common -I$(SRC)/common/bzip2 $<
$(POST_PROCESS_O)
+
+%.o: ../../../common/crypto/chacha/%.c
+ $(COMPILE.c) -o $@ -I$(SRC)/common -I$(SRC)/common/crypto/chacha $<
+ $(POST_PROCESS_O)
+
diff --git a/usr/src/cmd/savecore/savecore.c b/usr/src/cmd/savecore/savecore.c
index 9b8e43e488..e0e281f61e 100644
--- a/usr/src/cmd/savecore/savecore.c
+++ b/usr/src/cmd/savecore/savecore.c
@@ -42,6 +42,8 @@
#include <atomic.h>
#include <libnvpair.h>
#include <libintl.h>
+#include <assert.h>
+#include <strings.h>
#include <sys/mem.h>
#include <sys/statvfs.h>
#include <sys/dumphdr.h>
@@ -55,6 +57,7 @@
#include <sys/fm/util.h>
#include <fm/libfmevent.h>
#include <sys/int_fmtio.h>
+#include <crypto/chacha/chacha.h>
/* fread/fwrite buffer size */
@@ -74,6 +77,8 @@ static long pagesize; /* dump pagesize */
static int dumpfd = -1; /* dumpfile descriptor */
static boolean_t have_dumpfile = B_TRUE; /* dumpfile existence */
static dumphdr_t corehdr, dumphdr; /* initial and terminal dumphdrs */
+static dump_crypt_t dcrypt; /* dump encryption header */
+static size_t dumphdr_size; /* size of dump header */
static boolean_t dump_incomplete; /* dumphdr indicates incomplete */
static boolean_t fm_panic; /* dump is the result of fm_panic */
static offset_t endoff; /* offset of end-of-dump header */
@@ -165,7 +170,8 @@ static void
usage(void)
{
(void) fprintf(stderr,
- "usage: %s [-L | -r] [-vd] [-f dumpfile] [dirname]\n", progname);
+ "usage: %s [-L | -r] [-vd] [-k keyfile] [-f dumpfile] [dirname]\n",
+ progname);
exit(1);
}
@@ -329,6 +335,19 @@ Pwrite(int fd, void *buf, size_t size, off64_t off)
strerror(errno));
}
+static void
+Read(int fd, void *buf, size_t size)
+{
+ ssize_t sz = read(fd, buf, size);
+
+ if (sz < 0)
+ logprint(SC_SL_ERR | SC_EXIT_ERR,
+ "read: %s", strerror(errno));
+ else if (sz != size)
+ logprint(SC_SL_ERR | SC_EXIT_ERR,
+ "read: size %ld != %ld", sz, size);
+}
+
static void *
Zalloc(size_t size)
{
@@ -362,9 +381,9 @@ read_dumphdr(void)
dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
- Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr));
pagesize = dumphdr.dump_pagesize;
+ dumphdr_size = sizeof (dumphdr);
if (dumphdr.dump_magic != DUMP_MAGIC)
logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x",
@@ -384,6 +403,20 @@ read_dumphdr(void)
"dump is from %u-bit kernel - cannot save on %u-bit kernel",
dumphdr.dump_wordsize, DUMP_WORDSIZE);
+ if (dumphdr.dump_flags & DF_ENCRYPTED) {
+ /*
+ * If our dump is encrypted, our encryption header follows
+ * our dump header. Read it, and then increment our
+ * dumphdr_size to assure that reads of data following the
+ * encryption header account for it.
+ */
+ Pread(dumpfd, &dcrypt, sizeof (dcrypt),
+ endoff + sizeof (dumphdr));
+ dumphdr_size += sizeof (dcrypt);
+ }
+
+ Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + dumphdr_size);
+
if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) {
if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION)
logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
@@ -500,19 +533,76 @@ build_dump_map(int corefd, const pfn_t *pfn_table)
free(inbuf);
}
+static void
+Decrypt(offset_t dumpoff, len_t nb, char *buf, size_t sz, uint8_t *key)
+{
+ size_t nelems = nb / sizeof (uint64_t), i;
+ uint64_t *clear = (uint64_t *)buf;
+ uint64_t *stream = (uint64_t *)(buf + sz);
+ uint64_t *crypt = (uint64_t *)(buf + (2 * sz));
+ uint64_t ctr = dumpoff >> DUMP_CRYPT_BLOCKSHIFT;
+ chacha_ctx_t ctx;
+
+ /*
+ * If our size is not 8-byte aligned, prepare our ciphertext to the
+ * next 8-byte boundary.
+ */
+ if (nb & (sizeof (uint64_t) - 1)) {
+ assert(nb < sz);
+ nelems++;
+ }
+
+ chacha_keysetup(&ctx, key, DUMP_CRYPT_KEYLEN * 8, 0);
+ chacha_ivsetup(&ctx, dcrypt.dump_crypt_nonce, (uint8_t *)&ctr);
+
+ for (i = 0; i < nelems; i++) {
+ stream[i] = dumpoff;
+ dumpoff += sizeof (uint64_t);
+ }
+
+ chacha_encrypt_bytes(&ctx, (uint8_t *)stream, (uint8_t *)crypt, nb);
+
+ for (i = 0; i < nelems; i++)
+ clear[i] ^= crypt[i];
+}
+
+static void
+Verify(uint8_t *key)
+{
+ chacha_ctx_t ctx;
+ uint8_t hmac[DUMP_CRYPT_HMACLEN];
+
+ chacha_keysetup(&ctx, key, DUMP_CRYPT_KEYLEN * 8, 0);
+ chacha_ivsetup(&ctx, dcrypt.dump_crypt_nonce, NULL);
+
+ chacha_encrypt_bytes(&ctx, (uint8_t *)&dumphdr.dump_utsname,
+ (uint8_t *)hmac, DUMP_CRYPT_HMACLEN);
+
+ if (bcmp(hmac, &dcrypt.dump_crypt_hmac, DUMP_CRYPT_HMACLEN) == 0)
+ return;
+
+ logprint(SC_SL_NONE | SC_EXIT_ERR,
+ "provided key does not match encryption key");
+}
+
/*
* Copy whole sections of the dump device to the file.
*/
static void
Copy(offset_t dumpoff, len_t nb, offset_t *offp, int fd, char *buf,
- size_t sz)
+ size_t sz, uint8_t *key)
{
size_t nr;
offset_t off = *offp;
while (nb > 0) {
nr = sz < nb ? sz : (size_t)nb;
+
Pread(dumpfd, buf, nr, dumpoff);
+
+ if (dumphdr.dump_flags & DF_ENCRYPTED)
+ Decrypt(dumpoff, nr, buf, sz, key);
+
Pwrite(fd, buf, nr, off);
off += nr;
dumpoff += nr;
@@ -567,21 +657,56 @@ CopyPages(offset_t *offp, int fd, char *buf, size_t sz)
* Update corehdr with new offsets.
*/
static void
-copy_crashfile(const char *corefile)
+copy_crashfile(const char *corefile, const char *keyfile)
{
int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ uint8_t keybuf[DUMP_CRYPT_KEYLEN];
size_t bufsz = FBUFSIZE;
- char *inbuf = Zalloc(bufsz);
+ char *inbuf;
offset_t coreoff;
size_t nb;
+ uint8_t *key = NULL;
+
+ if (dumphdr.dump_flags & DF_ENCRYPTED) {
+ int keyfd;
+
+ if (dcrypt.dump_crypt_algo != DUMP_CRYPT_ALGO_CHACHA20) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "unrecognized dump "
+ "encryption algorithm %u", dcrypt.dump_crypt_algo);
+ }
+
+ if (keyfile == NULL) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "dump is encrypted; "
+ "key must be provided");
+ }
- logprint(SC_SL_ERR | SC_IF_VERBOSE,
- "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
+ keyfd = Open(keyfile, O_RDONLY, 0600);
+ Read(keyfd, keybuf, sizeof (keybuf));
+ (void) close(keyfd);
+
+ /*
+ * For the encrypted case, we triple our buffer size to
+ * allow for the stream buffer and the ciphertext buffer.
+ */
+ inbuf = Zalloc(bufsz * 3);
+ key = keybuf;
+ Verify(key);
+
+ logprint(SC_SL_ERR | SC_IF_VERBOSE, "Decrypting and copying "
+ "%s to %s/%s\n", dumpfile, savedir, corefile);
+ } else {
+ inbuf = Zalloc(bufsz);
+
+ logprint(SC_SL_ERR | SC_IF_VERBOSE,
+ "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
+ }
/*
- * This dump file is still compressed
+ * This dump file is still compressed -- but it will no longer be
+ * encrypted.
*/
corehdr.dump_flags |= DF_COMPRESSED | DF_VALID;
+ corehdr.dump_flags &= ~DF_ENCRYPTED;
/*
* Leave room for corehdr, it is updated and written last
@@ -595,7 +720,7 @@ copy_crashfile(const char *corefile)
coreoff = roundup(coreoff, pagesize);
corehdr.dump_ksyms = coreoff;
Copy(dumphdr.dump_ksyms, dumphdr.dump_ksyms_csize, &coreoff, corefd,
- inbuf, bufsz);
+ inbuf, bufsz, key);
/*
* Save the pfn table.
@@ -603,7 +728,7 @@ copy_crashfile(const char *corefile)
coreoff = roundup(coreoff, pagesize);
corehdr.dump_pfn = coreoff;
Copy(dumphdr.dump_pfn, dumphdr.dump_npages * sizeof (pfn_t), &coreoff,
- corefd, inbuf, bufsz);
+ corefd, inbuf, bufsz, key);
/*
* Save the dump map.
@@ -611,7 +736,7 @@ copy_crashfile(const char *corefile)
coreoff = roundup(coreoff, pagesize);
corehdr.dump_map = coreoff;
Copy(dumphdr.dump_map, dumphdr.dump_nvtop * sizeof (mem_vtop_t),
- &coreoff, corefd, inbuf, bufsz);
+ &coreoff, corefd, inbuf, bufsz, key);
/*
* Save the data pages.
@@ -620,7 +745,7 @@ copy_crashfile(const char *corefile)
corehdr.dump_data = coreoff;
if (datahdr.dump_data_csize != 0)
Copy(dumphdr.dump_data, datahdr.dump_data_csize, &coreoff,
- corefd, inbuf, bufsz);
+ corefd, inbuf, bufsz, key);
else
CopyPages(&coreoff, corefd, inbuf, bufsz);
@@ -1657,6 +1782,8 @@ main(int argc, char *argv[])
struct rlimit rl;
long filebounds = -1;
char namelist[30], corefile[30], boundstr[30];
+ char *keyfile = NULL;
+
dumpfile = NULL;
startts = gethrtime();
@@ -1672,7 +1799,7 @@ main(int argc, char *argv[])
if (savedir != NULL)
savedir = strdup(savedir);
- while ((c = getopt(argc, argv, "Lvcdmf:r")) != EOF) {
+ while ((c = getopt(argc, argv, "Lvcdmf:rk:")) != EOF) {
switch (c) {
case 'L':
livedump++;
@@ -1696,6 +1823,9 @@ main(int argc, char *argv[])
dumpfile = optarg;
filebounds = getbounds(dumpfile);
break;
+ case 'k':
+ keyfile = optarg;
+ break;
case '?':
usage();
}
@@ -1756,6 +1886,18 @@ main(int argc, char *argv[])
read_dumphdr();
+ if (dumphdr.dump_flags & DF_ENCRYPTED) {
+ if (filemode) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "saved dump file is "
+ "erroneously encrypted");
+ }
+
+ if (!csave) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "dump is encrypted; "
+ "cannot be saved uncompressed");
+ }
+ }
+
/*
* We want this message to go to the log file, but not the console.
* There's no good way to do that with the existing syslog facility.
@@ -1860,7 +2002,7 @@ main(int argc, char *argv[])
"Saving compressed system crash dump in %s/%s",
savedir, corefile);
- copy_crashfile(corefile);
+ copy_crashfile(corefile, keyfile);
/*
* Raise a fault management event that indicates the system
@@ -1876,7 +2018,7 @@ main(int argc, char *argv[])
char *metrics = Zalloc(metrics_size + 1);
Pread(dumpfd, metrics, metrics_size, endoff +
- sizeof (dumphdr) + sizeof (datahdr));
+ dumphdr_size + sizeof (datahdr));
if (sec < 1)
sec = 1;
diff --git a/usr/src/cmd/sed/main.c b/usr/src/cmd/sed/main.c
index c928131958..b148f7293e 100644
--- a/usr/src/cmd/sed/main.c
+++ b/usr/src/cmd/sed/main.c
@@ -2,7 +2,7 @@
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
* Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.com>
* Copyright (c) 2011 Gary Mills
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1992 Diomidis Spinellis.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -43,9 +43,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
-#include <getopt.h>
#include <libgen.h>
-#include <libintl.h>
#include <limits.h>
#include <locale.h>
#include <regex.h>
@@ -54,6 +52,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libintl.h>
#include "defs.h"
#include "extern.h"
@@ -108,11 +107,6 @@ static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */
static const char *inplace; /* Inplace edit file extension. */
ulong_t linenum;
-static const struct option lopts[] = {
- {"in-place", optional_argument, NULL, 'i'},
- {NULL, 0, NULL, 0}
-};
-
static void add_compunit(enum e_cut, char *);
static void add_file(char *);
static void usage(void);
@@ -134,18 +128,14 @@ main(int argc, char *argv[])
fflag = 0;
inplace = NULL;
- while ((c = getopt_long(argc, argv, "EI::ae:f:i::lnr", lopts, NULL)) !=
- -1)
+ while ((c = getopt(argc, argv, "EI:ae:f:i:lnr")) != -1)
switch (c) {
case 'r': /* Gnu sed compat */
case 'E':
rflags = REG_EXTENDED;
break;
case 'I':
- if (optarg != NULL)
- inplace = optarg;
- else
- inplace = "";
+ inplace = optarg;
ispan = 1; /* span across input files */
break;
case 'a':
@@ -162,10 +152,7 @@ main(int argc, char *argv[])
add_compunit(CU_FILE, optarg);
break;
case 'i':
- if (optarg != NULL)
- inplace = optarg;
- else
- inplace = "";
+ inplace = optarg;
ispan = 0; /* don't span across input files */
break;
case 'l':
@@ -206,8 +193,8 @@ main(int argc, char *argv[])
static void
usage(void)
{
- (void) fputs(_("usage: sed script [-Ealn] [-i[extension]] [file...]\n"
- " sed [-Ealn] [-i[extension]] [-e script]... "
+ (void) fputs(_("usage: sed script [-Ealn] [-i extension] [file...]\n"
+ " sed [-Ealn] [-i extension] [-e script]... "
"[-f script_file]... [file...]\n"),
stderr);
exit(1);
diff --git a/usr/src/cmd/sendmail/src/Makefile b/usr/src/cmd/sendmail/src/Makefile
index 8791902399..e488312e99 100644
--- a/usr/src/cmd/sendmail/src/Makefile
+++ b/usr/src/cmd/sendmail/src/Makefile
@@ -46,8 +46,7 @@ LDFLAGS += $(MAPFILES:%=-M%)
LDLIBS += ../libsmutil/libsmutil.a ../libsm/libsm.a -lresolv -lsocket \
-lnsl ../db/libdb.a -lldap -lsldap -lwrap -lumem \
- -lssl -lcrypto -lsasl
-NATIVE_LIBS += libssl.so libcrypto.so
+ -lsunw_ssl -lsunw_crypto -lsasl
INCPATH= -I. -I../include -I../db
diff --git a/usr/src/cmd/sgs/elfdump/Makefile.targ b/usr/src/cmd/sgs/elfdump/Makefile.targ
index 6122df233d..48bbbbbb87 100644
--- a/usr/src/cmd/sgs/elfdump/Makefile.targ
+++ b/usr/src/cmd/sgs/elfdump/Makefile.targ
@@ -79,6 +79,8 @@ delete:
package \
install: all $(VAR_SGSBINPROG) $(VAR_SGSCCSLINK)
+ -$(RM) $(ROOTPROG)
+ -$(LN) $(ISAEXEC) $(ROOTPROG)
include $(SRC)/cmd/Makefile.targ
include $(SRC)/cmd/sgs/Makefile.targ
diff --git a/usr/src/cmd/sgs/elfdump/amd64/Makefile b/usr/src/cmd/sgs/elfdump/amd64/Makefile
index ec8341a69b..7c3f1eb876 100644
--- a/usr/src/cmd/sgs/elfdump/amd64/Makefile
+++ b/usr/src/cmd/sgs/elfdump/amd64/Makefile
@@ -39,6 +39,8 @@ CONVLIBDIR = $(CONVLIBDIR64)
VAR_SGSBINPROG= $(VAR_SGSBINPROG64)
VAR_SGSCCSLINK= $(VAR_SGSCCSLINK64)
+install: all $(ROOTPROG64)
+
include ../Makefile.targ
include ../../Makefile.sub.64
diff --git a/usr/src/cmd/sgs/elfdump/i386/Makefile b/usr/src/cmd/sgs/elfdump/i386/Makefile
index d3cb302ac1..95390a2899 100644
--- a/usr/src/cmd/sgs/elfdump/i386/Makefile
+++ b/usr/src/cmd/sgs/elfdump/i386/Makefile
@@ -30,4 +30,6 @@ include ../Makefile.com
ARCH = i386
+install: all $(ROOTPROG32)
+
include ../Makefile.targ
diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h
index 4133866e86..2c78d95b04 100644
--- a/usr/src/cmd/sgs/include/conv.h
+++ b/usr/src/cmd/sgs/include/conv.h
@@ -280,7 +280,7 @@ typedef union {
} Conv_bnd_obj_buf_t;
/* conv_phdr_flags() */
-#define CONV_PHDR_FLAGS_BUFSIZE 88
+#define CONV_PHDR_FLAGS_BUFSIZE 244
typedef union {
Conv_inv_buf_t inv_buf;
char buf[CONV_PHDR_FLAGS_BUFSIZE];
diff --git a/usr/src/cmd/sgs/lex/common/main.c b/usr/src/cmd/sgs/lex/common/main.c
index 17ba4808a4..a1fd526cf9 100644
--- a/usr/src/cmd/sgs/lex/common/main.c
+++ b/usr/src/cmd/sgs/lex/common/main.c
@@ -30,11 +30,15 @@
/* Copyright 1976, Bell Telephone Laboratories, Inc. */
+/* Copyright (c) 2013, joyent, Inc. All rights reserved. */
+
#include <string.h>
#include "once.h"
#include "sgs.h"
#include <locale.h>
#include <limits.h>
+#include <unistd.h>
+#include <libgen.h>
static wchar_t L_INITIAL[] = {'I', 'N', 'I', 'T', 'I', 'A', 'L', 0};
static void get1core(void);
@@ -46,6 +50,25 @@ static void get3core(void);
static void free3core(void);
#endif
+static int
+lex_construct_path(char *buf, size_t size, const char *file, int type)
+{
+ int ret;
+ char origin[PATH_MAX];
+
+ if (type != 0) {
+ ret = readlink("/proc/self/path/a.out", origin, PATH_MAX - 1);
+ if (ret < 0)
+ error(
+ "lex: failed to read origin from /proc\n");
+ origin[ret] = '\0';
+ return (snprintf(buf, size, "%s/../%s/%s", dirname(origin),
+ NBASE, file));
+ }
+
+ return (snprintf(buf, size, "%s/%s/%s", NPREFIX, NBASE, file));
+}
+
int
main(int argc, char **argv)
{
@@ -53,6 +76,7 @@ main(int argc, char **argv)
int c;
char *apath = NULL;
char *ypath;
+ char pathbuf[PATH_MAX];
Boolean eoption = 0, woption = 0;
sargv = argv;
@@ -224,6 +248,11 @@ main(int argc, char **argv)
free3core();
#endif
+ /*
+ * Try to find the file relative to $ORIGIN. Note that we don't touch
+ * antyhing related to -Y. In fact, unfortunately it's always been
+ * ignored it seems.
+ */
if (handleeuc) {
if (ratfor)
error("Ratfor is not supported by -w or -e option.");
@@ -232,9 +261,19 @@ main(int argc, char **argv)
else
ypath = ratfor ? RATNAME : CNAME;
- if (apath != NULL)
- ypath = strcat(apath, strrchr(ypath, '/'));
- fother = fopen(ypath, "r");
+ if (apath == NULL) {
+ (void) lex_construct_path(pathbuf, sizeof (pathbuf), ypath, 1);
+ fother = fopen(pathbuf, "r");
+ if (fother == NULL) {
+ (void) lex_construct_path(pathbuf, sizeof (pathbuf),
+ ypath, 0);
+ fother = fopen(pathbuf, "r");
+ }
+ } else {
+ apath = strcat(apath, "/");
+ ypath = strcat(apath, ypath);
+ fother = fopen(ypath, "r");
+ }
if (fother == NULL)
error("Lex driver missing, file %s", ypath);
while ((i = getc(fother)) != EOF)
diff --git a/usr/src/cmd/sgs/lex/common/once.h b/usr/src/cmd/sgs/lex/common/once.h
index 014ca00b17..9e4b0e5e00 100644
--- a/usr/src/cmd/sgs/lex/common/once.h
+++ b/usr/src/cmd/sgs/lex/common/once.h
@@ -26,11 +26,11 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
+/* Copyright (c) 2013, joyent, Inc. All rights reserved. */
+
#ifndef _ONCE_H
#define _ONCE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "ldefs.h"
/* once.c */
@@ -73,9 +73,11 @@ int peek = '\n'; /* next input character */
CHR *pushptr = pushc;
CHR *slptr = slist;
-#define CNAME "/usr/share/lib/ccs/ncform"
-#define RATNAME "/usr/share/lib/ccs/nrform"
-#define EUCNAME "/usr/share/lib/ccs/nceucform"
+#define NPREFIX "/usr"
+#define NBASE "/share/lib/ccs/"
+#define CNAME "ncform"
+#define RATNAME "nrform"
+#define EUCNAME "nceucform"
int ccount = 1;
int casecount = 1;
diff --git a/usr/src/cmd/sgs/libconv/common/corenote.c b/usr/src/cmd/sgs/libconv/common/corenote.c
index bf6d109916..f86d534450 100644
--- a/usr/src/cmd/sgs/libconv/common/corenote.c
+++ b/usr/src/cmd/sgs/libconv/common/corenote.c
@@ -78,7 +78,7 @@ const char *
conv_cnote_auxv_type(Word type, Conv_fmt_flags_t fmt_flags,
Conv_inv_buf_t *inv_buf)
{
- static const Msg types_0_22[] = {
+ static const Msg types_0_25[] = {
MSG_AUXV_AT_NULL, MSG_AUXV_AT_IGNORE,
MSG_AUXV_AT_EXECFD, MSG_AUXV_AT_PHDR,
MSG_AUXV_AT_PHENT, MSG_AUXV_AT_PHNUM,
@@ -90,10 +90,11 @@ conv_cnote_auxv_type(Word type, Conv_fmt_flags_t fmt_flags,
MSG_AUXV_AT_HWCAP, MSG_AUXV_AT_CLKTCK,
MSG_AUXV_AT_FPUCW, MSG_AUXV_AT_DCACHEBSIZE,
MSG_AUXV_AT_ICACHEBSIZE, MSG_AUXV_AT_UCACHEBSIZE,
- MSG_AUXV_AT_IGNOREPPC
+ MSG_AUXV_AT_IGNOREPPC, MSG_AUXV_AT_SECURE,
+ MSG_AUXV_AT_BASE_PLATFORM, MSG_AUXV_AT_RANDOM
};
- static const conv_ds_msg_t ds_types_0_22 = {
- CONV_DS_MSG_INIT(0, types_0_22) };
+ static const conv_ds_msg_t ds_types_0_25 = {
+ CONV_DS_MSG_INIT(0, types_0_25) };
static const Msg types_2000_2011[] = {
MSG_AUXV_AT_SUN_UID, MSG_AUXV_AT_SUN_RUID,
@@ -112,7 +113,7 @@ conv_cnote_auxv_type(Word type, Conv_fmt_flags_t fmt_flags,
MSG_AUXV_AT_SUN_EMULATOR, MSG_AUXV_AT_SUN_BRANDNAME,
MSG_AUXV_AT_SUN_BRAND_AUX1, MSG_AUXV_AT_SUN_BRAND_AUX2,
MSG_AUXV_AT_SUN_BRAND_AUX3, MSG_AUXV_AT_SUN_HWCAP2,
- 0, 0,
+ MSG_AUXV_AT_SUN_BRAND_NROOT, MSG_AUXV_AT_SUN_BRAND_AUX4,
MSG_AUXV_AT_SUN_COMMPAGE, MSG_AUXV_AT_SUN_FPTYPE,
MSG_AUXV_AT_SUN_FPSIZE
};
@@ -120,7 +121,7 @@ conv_cnote_auxv_type(Word type, Conv_fmt_flags_t fmt_flags,
CONV_DS_MSG_INIT(2014, types_2014_2028) };
static const conv_ds_t *ds[] = {
- CONV_DS_ADDR(ds_types_0_22), CONV_DS_ADDR(ds_types_2000_2011),
+ CONV_DS_ADDR(ds_types_0_25), CONV_DS_ADDR(ds_types_2000_2011),
CONV_DS_ADDR(ds_types_2014_2028), NULL };
return (conv_map_ds(ELFOSABI_NONE, EM_NONE, type, ds, fmt_flags,
diff --git a/usr/src/cmd/sgs/libconv/common/corenote.msg b/usr/src/cmd/sgs/libconv/common/corenote.msg
index a36f2bddf7..78951cfb1d 100644
--- a/usr/src/cmd/sgs/libconv/common/corenote.msg
+++ b/usr/src/cmd/sgs/libconv/common/corenote.msg
@@ -80,6 +80,9 @@
@ MSG_AUXV_AT_ICACHEBSIZE "ICACHEBSIZE"
@ MSG_AUXV_AT_UCACHEBSIZE "UCACHEBSIZE"
@ MSG_AUXV_AT_IGNOREPPC "IGNOREPPC"
+@ MSG_AUXV_AT_SECURE "SECURE"
+@ MSG_AUXV_AT_BASE_PLATFORM "BASE_PLATFORM"
+@ MSG_AUXV_AT_RANDOM "RANDOM"
@ MSG_AUXV_AT_SUN_UID "SUN_UID"
@ MSG_AUXV_AT_SUN_RUID "SUN_RUID"
@ MSG_AUXV_AT_SUN_GID "SUN_GID"
@@ -102,6 +105,8 @@
@ MSG_AUXV_AT_SUN_BRAND_AUX2 "SUN_BRAND_AUX2"
@ MSG_AUXV_AT_SUN_BRAND_AUX3 "SUN_BRAND_AUX3"
@ MSG_AUXV_AT_SUN_HWCAP2 "SUN_HWCAP2"
+@ MSG_AUXV_AT_SUN_BRAND_NROOT "SUN_BRAND_NROOT"
+@ MSG_AUXV_AT_SUN_BRAND_AUX4 "SUN_BRAND_AUX4"
@ MSG_AUXV_AT_SUN_COMMPAGE "SUN_COMMPAGE"
@ MSG_AUXV_AT_SUN_FPTYPE "SUN_FPTYPE"
@ MSG_AUXV_AT_SUN_FPSIZE "SUN_FPSIZE"
diff --git a/usr/src/cmd/sgs/libconv/common/phdr.c b/usr/src/cmd/sgs/libconv/common/phdr.c
index d2b29a201f..382a1bf9f1 100644
--- a/usr/src/cmd/sgs/libconv/common/phdr.c
+++ b/usr/src/cmd/sgs/libconv/common/phdr.c
@@ -25,6 +25,10 @@
*/
/*
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ */
+
+/*
* String conversion routines for program header attributes.
*/
#include <stdio.h>
@@ -95,6 +99,7 @@ error "PT_NUM has grown. Update phdrs[]"
{ PT_GNU_EH_FRAME, LIN, MSG_PT_GNU_EH_FRAME },
{ PT_GNU_STACK, LIN, MSG_PT_GNU_STACK },
{ PT_GNU_RELRO, LIN, MSG_PT_GNU_RELRO },
+ { PT_PAX_FLAGS, LIN, MSG_PT_PAX_FLAGS },
{ 0 }
};
@@ -109,6 +114,7 @@ error "PT_NUM has grown. Update phdrs[]"
{ PT_GNU_EH_FRAME, LIN, MSG_PT_GNU_EH_FRAME_CF },
{ PT_GNU_STACK, LIN, MSG_PT_GNU_STACK_CF },
{ PT_GNU_RELRO, LIN, MSG_PT_GNU_RELRO_CF },
+ { PT_PAX_FLAGS, LIN, MSG_PT_PAX_FLAGS_CF },
{ 0 }
};
@@ -123,6 +129,7 @@ error "PT_NUM has grown. Update phdrs[]"
{ PT_GNU_EH_FRAME, LIN, MSG_PT_GNU_EH_FRAME_CFNP },
{ PT_GNU_STACK, LIN, MSG_PT_GNU_STACK_CFNP },
{ PT_GNU_RELRO, LIN, MSG_PT_GNU_RELRO_CFNP },
+ { PT_PAX_FLAGS, LIN, MSG_PT_PAX_FLAGS_CFNP },
{ 0 }
};
@@ -137,6 +144,7 @@ error "PT_NUM has grown. Update phdrs[]"
{ PT_GNU_EH_FRAME, LIN, MSG_PT_GNU_EH_FRAME_NF },
{ PT_GNU_STACK, LIN, MSG_PT_GNU_STACK_NF },
{ PT_GNU_RELRO, LIN, MSG_PT_GNU_RELRO_NF },
+ { PT_PAX_FLAGS, LIN, MSG_PT_PAX_FLAGS_NF },
{ 0 }
};
@@ -214,6 +222,18 @@ conv_phdr_flags_strings(Conv_fmt_flags_t fmt_flags)
MSG_PF_X_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_PF_W_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_PF_R_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_PAGEEXEC_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_NOPAGEEXEC_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_SEGMEXEC_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_NOSEGMEXEC_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_MPROTECT_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_NOMPROTECT_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_RANDEXEC_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_NORANDEXEC_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_EMUTRAMP_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_NOEMUTRAMP_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_RANDMMAP_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_PF_NORANDMMAP_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_PF_SUNW_FAILURE_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_PF_SUNW_KILLED_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_PF_SUNW_SIGINFO_CF_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
@@ -237,11 +257,24 @@ conv_phdr_flags_strings(Conv_fmt_flags_t fmt_flags)
#define ALL ELFOSABI_NONE, EM_NONE
#define SOL ELFOSABI_SOLARIS, EM_NONE
+#define LIN ELFOSABI_LINUX, EM_NONE
static const Val_desc2 vda_cf[] = {
{ PF_X, ALL, MSG_PF_X_CF },
{ PF_W, ALL, MSG_PF_W_CF },
{ PF_R, ALL, MSG_PF_R_CF },
+ { PF_PAGEEXEC, LIN, MSG_PF_PAGEEXEC_CF },
+ { PF_NOPAGEEXEC, LIN, MSG_PF_NOPAGEEXEC_CF },
+ { PF_SEGMEXEC, LIN, MSG_PF_SEGMEXEC_CF },
+ { PF_NOSEGMEXEC, LIN, MSG_PF_NOSEGMEXEC_CF },
+ { PF_MPROTECT, LIN, MSG_PF_MPROTECT_CF },
+ { PF_NOMPROTECT, LIN, MSG_PF_NOMPROTECT_CF },
+ { PF_RANDEXEC, LIN, MSG_PF_RANDEXEC_CF },
+ { PF_NORANDEXEC, LIN, MSG_PF_NORANDEXEC_CF },
+ { PF_EMUTRAMP, LIN, MSG_PF_EMUTRAMP_CF },
+ { PF_NOEMUTRAMP, LIN, MSG_PF_NOEMUTRAMP_CF },
+ { PF_RANDMMAP, LIN, MSG_PF_RANDMMAP_CF },
+ { PF_NORANDMMAP, LIN, MSG_PF_NORANDMMAP_CF },
{ PF_SUNW_FAILURE, SOL, MSG_PF_SUNW_FAILURE_CF },
{ PF_SUNW_KILLED, SOL, MSG_PF_SUNW_KILLED_CF },
{ PF_SUNW_SIGINFO, SOL, MSG_PF_SUNW_SIGINFO_CF },
@@ -251,6 +284,18 @@ conv_phdr_flags_strings(Conv_fmt_flags_t fmt_flags)
{ PF_X, ALL, MSG_PF_X_NF },
{ PF_W, ALL, MSG_PF_W_NF },
{ PF_R, ALL, MSG_PF_R_NF },
+ { PF_PAGEEXEC, LIN, MSG_PF_PAGEEXEC_NF },
+ { PF_NOPAGEEXEC, LIN, MSG_PF_NOPAGEEXEC_NF },
+ { PF_SEGMEXEC, LIN, MSG_PF_SEGMEXEC_NF },
+ { PF_NOSEGMEXEC, LIN, MSG_PF_NOSEGMEXEC_NF },
+ { PF_MPROTECT, LIN, MSG_PF_MPROTECT_NF },
+ { PF_NOMPROTECT, LIN, MSG_PF_NOMPROTECT_NF },
+ { PF_RANDEXEC, LIN, MSG_PF_RANDEXEC_NF },
+ { PF_NORANDEXEC, LIN, MSG_PF_NORANDEXEC_NF },
+ { PF_EMUTRAMP, LIN, MSG_PF_EMUTRAMP_NF },
+ { PF_NOEMUTRAMP, LIN, MSG_PF_NOEMUTRAMP_NF },
+ { PF_RANDMMAP, LIN, MSG_PF_RANDMMAP_NF },
+ { PF_NORANDMMAP, LIN, MSG_PF_NORANDMMAP_NF },
{ PF_SUNW_FAILURE, SOL, MSG_PF_SUNW_FAILURE_NF },
{ PF_SUNW_KILLED, SOL, MSG_PF_SUNW_KILLED_NF },
{ PF_SUNW_SIGINFO, SOL, MSG_PF_SUNW_SIGINFO_NF },
@@ -262,6 +307,7 @@ conv_phdr_flags_strings(Conv_fmt_flags_t fmt_flags)
#undef ALL
#undef SOL
+#undef LIN
}
const char *
diff --git a/usr/src/cmd/sgs/libconv/common/phdr.msg b/usr/src/cmd/sgs/libconv/common/phdr.msg
index 789832a16a..e84182277b 100644
--- a/usr/src/cmd/sgs/libconv/common/phdr.msg
+++ b/usr/src/cmd/sgs/libconv/common/phdr.msg
@@ -24,6 +24,8 @@
# Use is subject to license terms.
#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+
@ MSG_PT_NULL "[ PT_NULL ]" # 0
@ MSG_PT_NULL_CF "PT_NULL"
@ MSG_PT_NULL_CFNP "NULL"
@@ -79,6 +81,10 @@
@ MSG_PT_GNU_RELRO_CF "PT_GNU_RELRO"
@ MSG_PT_GNU_RELRO_CFNP "GNU_RELRO"
@ MSG_PT_GNU_RELRO_NF "gnu_relro"
+@ MSG_PT_PAX_FLAGS "[ PT_PAX_FLAGS ]" # 0x65041580
+@ MSG_PT_PAX_FLAGS_CF "PT_PAX_FLAGS"
+@ MSG_PT_PAX_FLAGS_CFNP "PAX_FLAGS"
+@ MSG_PT_PAX_FLAGS_NF "pax_flags"
@ MSG_PT_SUNWBSS "[ PT_SUNWBSS ]" # 0x6ffffffa
@ MSG_PT_SUNWBSS_CF "PT_SUNWBSS"
@@ -103,6 +109,30 @@
@ MSG_PF_W_NF "w"
@ MSG_PF_R_CF "PF_R" # 0x4
@ MSG_PF_R_NF "r"
+@ MSG_PF_PAGEEXEC_CF "PF_PAGEEXEC" # 0x00000010
+@ MSG_PF_PAGEEXEC_NF "pageexec"
+@ MSG_PF_NOPAGEEXEC_CF "PF_NOPAGEEXEC" # 0x00000020
+@ MSG_PF_NOPAGEEXEC_NF "nopageexec"
+@ MSG_PF_SEGMEXEC_CF "PF_SEGMEXEC" # 0x00000040
+@ MSG_PF_SEGMEXEC_NF "segmexec"
+@ MSG_PF_NOSEGMEXEC_CF "PF_NOSEGMEXEC" # 0x00000080
+@ MSG_PF_NOSEGMEXEC_NF "nosegmexec"
+@ MSG_PF_MPROTECT_CF "PF_MPROTECT" # 0x00000100
+@ MSG_PF_MPROTECT_NF "mprotect"
+@ MSG_PF_NOMPROTECT_CF "PF_NOMPROTECT" # 0x00000200
+@ MSG_PF_NOMPROTECT_NF "nomprotect"
+@ MSG_PF_RANDEXEC_CF "PF_RANDEXEC" # 0x00000400
+@ MSG_PF_RANDEXEC_NF "randexec"
+@ MSG_PF_NORANDEXEC_CF "PF_NORANDEXEC" # 0x00000800
+@ MSG_PF_NORANDEXEC_NF "norandexec"
+@ MSG_PF_EMUTRAMP_CF "PF_EMUTRAMP" # 0x00001000
+@ MSG_PF_EMUTRAMP_NF "emutramp"
+@ MSG_PF_NOEMUTRAMP_CF "PF_NOEMUTRAMP" # 0x00002000
+@ MSG_PF_NOEMUTRAMP_NF "noemutramp"
+@ MSG_PF_RANDMMAP_CF "PF_RANDMMAP" # 0x00004000
+@ MSG_PF_RANDMMAP_NF "randmmap"
+@ MSG_PF_NORANDMMAP_CF "PF_NORANDMMAP" # 0x00008000
+@ MSG_PF_NORANDMMAP_NF "norandmmap"
@ MSG_PF_SUNW_FAILURE_CF "PF_SUNW_FAILURE" # 0x00100000
@ MSG_PF_SUNW_FAILURE_NF "sunw_failure"
@ MSG_PF_SUNW_KILLED_CF "PF_SUNW_KILLED" # 0x00200000
diff --git a/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg b/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg
index fbc595f5f4..5b0ad9533a 100644
--- a/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg
+++ b/usr/src/cmd/sgs/librtld_db/common/librtld_db.msg
@@ -24,6 +24,10 @@
# Use is subject to license terms.
#
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
# Message file for cmd/sgs/librtld_db.
@ MSG_ID_LIBRTLD_DB
@@ -104,7 +108,7 @@
@ MSG_DB_RDOBJPADE "rtld_db: rd_objpad_enable(padsize=0x%llx)"
@ MSG_DB_64BIT_PREFIX "64/"
@ MSG_DB_BRAND_HELPERPATH_PREFIX "%s/%s/%s/%s%s_librtld_db.so.1"
-@ MSG_DB_BRAND_HELPERPATH "%s/%s/%s%s_librtld_db.so.1"
+@ MSG_DB_BRAND_HELPERPATH "%s/%s/%s/%s%s_librtld_db.so.1"
@ MSG_DB_HELPERNOOPS "rtld_db: helper lib loaded but ops not preset"
@ MSG_DB_HELPERLOADED "rtld_db: helper library loaded for brand \"%s\""
@ MSG_DB_HELPERLOADFAILED "rtld_db: couldn't load brand helper library %s"
diff --git a/usr/src/cmd/sgs/librtld_db/common/rd_elf.c b/usr/src/cmd/sgs/librtld_db/common/rd_elf.c
index 737fb2ee0f..c78d39e714 100644
--- a/usr/src/cmd/sgs/librtld_db/common/rd_elf.c
+++ b/usr/src/cmd/sgs/librtld_db/common/rd_elf.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
#include <stdlib.h>
#include <stdio.h>
#include <proc_service.h>
@@ -38,6 +42,14 @@
#include <sys/param.h>
/*
+ * We want to include zone.h to pull in the prototype for zone_get_nroot(),
+ * but we need to avoid pulling in <sys/stream.h>, which has a definition
+ * of M_DATA that conflicts with the ELF-related definition in machdep_*.h.
+ */
+#define _SYS_STREAM_H
+#include <zone.h>
+
+/*
* 64-bit builds are going to compile this module twice, the
* second time with _ELF64 defined. These defines should make
* all the necessary adjustments to the code.
@@ -283,7 +295,9 @@ _rd_reset32(struct rd_agent *rap)
* If we are debugging a branded executable, load the appropriate
* helper library, and call its initialization routine. Being unable
* to load the helper library is not a critical error. (Hopefully
- * we'll still be able to access some objects in the target.)
+ * we'll still be able to access some objects in the target.) Note
+ * that we pull in the native root here to allow for helper libraries
+ * to be properly found from within the branded zone.
*/
ps_pbrandname = (ps_pbrandname_fp_t)dlsym(RTLD_PROBE, "ps_pbrandname");
while ((ps_pbrandname != NULL) &&
@@ -294,17 +308,23 @@ _rd_reset32(struct rd_agent *rap)
isa = MSG_ORIG(MSG_DB_64BIT_PREFIX);
#endif /* _LP64 */
- if (rtld_db_helper_path[0] != '\0')
+ if (rtld_db_helper_path[0] != '\0') {
(void) snprintf(brandlib, MAXPATHLEN,
MSG_ORIG(MSG_DB_BRAND_HELPERPATH_PREFIX),
rtld_db_helper_path,
MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
brandname);
- else
+ } else {
+ const char *nroot = zone_get_nroot();
+
+ if (nroot == NULL)
+ nroot = "";
+
(void) snprintf(brandlib, MAXPATHLEN,
- MSG_ORIG(MSG_DB_BRAND_HELPERPATH),
+ MSG_ORIG(MSG_DB_BRAND_HELPERPATH), nroot,
MSG_ORIG(MSG_DB_HELPER_PREFIX), brandname, isa,
brandname);
+ }
rap->rd_helper.rh_dlhandle = dlopen(brandlib,
RTLD_LAZY | RTLD_LOCAL);
diff --git a/usr/src/cmd/sgs/rtld/common/_rtld.h b/usr/src/cmd/sgs/rtld/common/_rtld.h
index ece14a855e..83b7071471 100644
--- a/usr/src/cmd/sgs/rtld/common/_rtld.h
+++ b/usr/src/cmd/sgs/rtld/common/_rtld.h
@@ -26,7 +26,7 @@
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
#ifndef __RTLD_H
#define __RTLD_H
@@ -589,6 +589,8 @@ extern const char *rpl_ldflags; /* replaceable LD_FLAGS string */
extern const char *rpl_libpath; /* replaceable LD_LIBRARY string */
extern Alist *rpl_libdirs; /* and its associated Pdesc list */
extern const char *rpl_preload; /* replaceable LD_PRELOAD string */
+extern const char *rpl_ldtoxic; /* replaceable LD_TOXIC_PATH string */
+extern Alist *rpl_toxdirs; /* and associated Pdesc list */
extern const char *prm_audit; /* permanent LD_AUDIT string */
extern const char *prm_debug; /* permanent LD_DEBUG string */
diff --git a/usr/src/cmd/sgs/rtld/common/analyze.c b/usr/src/cmd/sgs/rtld/common/analyze.c
index 91a7546e85..c9e66b1293 100644
--- a/usr/src/cmd/sgs/rtld/common/analyze.c
+++ b/usr/src/cmd/sgs/rtld/common/analyze.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
/*
@@ -834,6 +835,57 @@ is_so_loaded(Lm_list *lml, const char *name, int *in_nfavl)
}
/*
+ * Walk the toxic path list and determine if the object in question has violated
+ * the toxic path. When evaluating the toxic path we need to ensure that we
+ * match any path that's a subdirectory of a listed entry. In other words if
+ * /foo/bar is toxic, something in /foo/bar/baz/ is no good. However, we need to
+ * ensure that we don't mark /foo/barbaz/ as bad.
+ */
+static int
+is_load_toxic(Lm_list *lml, Rt_map *nlmp)
+{
+ const char *fpath;
+ size_t flen;
+ Pdesc *pdp;
+ Aliste idx;
+
+ fpath = PATHNAME(nlmp);
+
+ /*
+ * If we have a NULL path name, that indicates that rtld is processing
+ * an in-memory shared object. For example, trying to run ldd or doing
+ * an LD_PRELOAD on an object file. In those cases, we'll always allow
+ * it.
+ */
+ if (fpath == NULL)
+ return (0);
+
+ flen = strlen(fpath);
+
+ for (ALIST_TRAVERSE(rpl_toxdirs, idx, pdp)) {
+ if (pdp->pd_plen == 0)
+ continue;
+
+ if (strncmp(pdp->pd_pname, fpath, pdp->pd_plen) == 0) {
+ if (pdp->pd_pname[pdp->pd_plen-1] != '/') {
+ /*
+ * Path didn't end in a /, make sure
+ * we're at a directory boundary
+ * nonetheless.
+ */
+ if (flen > pdp->pd_plen &&
+ fpath[pdp->pd_plen] == '/')
+ return (1);
+ continue;
+ }
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
* Tracing is enabled by the LD_TRACE_LOADED_OPTIONS environment variable which
* is normally set from ldd(1). For each link map we load, print the load name
* and the full pathname of the associated object.
@@ -2169,6 +2221,17 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode,
uint_t rdflags;
/*
+ * If this dependency is associated with a toxic path, then we must
+ * honor the user's request to die.
+ */
+ if (is_load_toxic(lml, nlmp) != 0) {
+ eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TOXIC_FILE),
+ PATHNAME(nlmp));
+ rtldexit(lml, 1);
+
+ }
+
+ /*
* If this dependency is associated with a required version ensure that
* the version is present in the loaded file.
*/
diff --git a/usr/src/cmd/sgs/rtld/common/globals.c b/usr/src/cmd/sgs/rtld/common/globals.c
index bb47b12540..45c08f8286 100644
--- a/usr/src/cmd/sgs/rtld/common/globals.c
+++ b/usr/src/cmd/sgs/rtld/common/globals.c
@@ -24,6 +24,7 @@
* All Rights Reserved
*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -132,6 +133,8 @@ const char *rpl_ldflags = NULL; /* replaceable LD_FLAGS string */
const char *rpl_libpath = NULL; /* replaceable LD_LIBRARY_PATH string */
Alist *rpl_libdirs = NULL; /* and associated Pdesc list */
const char *rpl_preload = NULL; /* replaceable LD_PRELOAD string */
+const char *rpl_ldtoxic = NULL; /* replaceable LD_TOXIC string */
+Alist *rpl_toxdirs = NULL; /* and associated Pdesc list */
const char *prm_audit = NULL; /* permanent LD_AUDIT string */
const char *prm_debug = NULL; /* permanent LD_DEBUG string */
diff --git a/usr/src/cmd/sgs/rtld/common/rtld.msg b/usr/src/cmd/sgs/rtld/common/rtld.msg
index 94c5c5bf51..0c0cff9e86 100644
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg
@@ -21,6 +21,7 @@
#
# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, Joyent, Inc. All rights reserved.
#
@ _START_
@@ -99,9 +100,14 @@
@ MSG_SYS_MPROT "%s: mprotect failed: %s"
@ MSG_SYS_MMAPANON "mmap anon failed: %s"
+# Secure path failures
+
@ MSG_SEC_OPEN "%s: open failed: No such file in secure directories"
@ MSG_SEC_ILLEGAL "%s: open failed: illegal insecure pathname"
+# Toxic failures
+
+@ MSG_TOXIC_FILE "%s: dependency marked as toxic"
# Configuration failures
@@ -396,6 +402,7 @@
@ MSG_LD_PROFILE_OUTPUT "PROFILE_OUTPUT"
@ MSG_LD_SFCAP "SFCAP"
@ MSG_LD_SIGNAL "SIGNAL"
+@ MSG_LD_TOXICPATH "TOXIC_PATH"
@ MSG_LD_TRACE_OBJS "TRACE_LOADED_OBJECTS"
@ MSG_LD_TRACE_OBJS_E "TRACE_LOADED_OBJECTS_E"
@ MSG_LD_TRACE_OBJS_A "TRACE_LOADED_OBJECTS_A"
diff --git a/usr/src/cmd/sgs/rtld/common/setup.c b/usr/src/cmd/sgs/rtld/common/setup.c
index 862bb7d61f..98e3ba5d33 100644
--- a/usr/src/cmd/sgs/rtld/common/setup.c
+++ b/usr/src/cmd/sgs/rtld/common/setup.c
@@ -28,7 +28,7 @@
* All Rights Reserved
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
/*
@@ -819,6 +819,14 @@ setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz,
return (0);
}
+ /*
+ * Initialize our toxic paths
+ */
+ if (rpl_ldtoxic != NULL) {
+ (void) expand_paths(mlmp, rpl_ldtoxic, &rpl_toxdirs,
+ AL_CNT_SEARCH, 0, PD_TKN_CAP);
+ }
+
#if defined(_ELF64)
/*
* If this is a 64-bit process, determine whether this process has
diff --git a/usr/src/cmd/sgs/rtld/common/util.c b/usr/src/cmd/sgs/rtld/common/util.c
index 7d3d193c4c..ebdd9e1943 100644
--- a/usr/src/cmd/sgs/rtld/common/util.c
+++ b/usr/src/cmd/sgs/rtld/common/util.c
@@ -24,6 +24,7 @@
* All Rights Reserved
*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
/*
@@ -1428,6 +1429,7 @@ static u_longlong_t cmdisa = 0; /* command line (-e) ISA */
#define ENV_FLG_CAP_FILES 0x0080000000000ULL
#define ENV_FLG_DEFERRED 0x0100000000000ULL
#define ENV_FLG_NOENVIRON 0x0200000000000ULL
+#define ENV_FLG_TOXICPATH 0x0400000000000ULL
#define SEL_REPLACE 0x0001
#define SEL_PERMANT 0x0002
@@ -1601,8 +1603,7 @@ ld_generic_env(const char *s1, size_t len, const char *s2, Word *lmflags,
if ((len == MSG_LD_FLAGS_SIZE) && (strncmp(s1,
MSG_ORIG(MSG_LD_FLAGS), MSG_LD_FLAGS_SIZE) == 0)) {
select |= SEL_ACT_SPEC_1;
- str = (select & SEL_REPLACE) ? &rpl_ldflags :
- &prm_ldflags;
+ str = &rpl_ldflags;
variable = ENV_FLG_FLAGS;
}
}
@@ -1813,6 +1814,8 @@ ld_generic_env(const char *s1, size_t len, const char *s2, Word *lmflags,
* In case an auditor is called, which in turn might exec(2) a
* subprocess, this variable is disabled, so that any subprocess
* escapes ldd(1) processing.
+ *
+ * Also, look for LD_TOXIC_PATH
*/
else if (*s1 == 'T') {
if (((len == MSG_LD_TRACE_OBJS_SIZE) &&
@@ -1850,7 +1853,13 @@ ld_generic_env(const char *s1, size_t len, const char *s2, Word *lmflags,
select |= SEL_ACT_LML;
val = LML_FLG_TRC_SEARCH;
variable = ENV_FLG_TRACE_PTHS;
+ } else if ((len == MSG_LD_TOXICPATH_SIZE) && (strncmp(s1,
+ MSG_ORIG(MSG_LD_TOXICPATH), MSG_LD_TOXICPATH_SIZE) == 0)) {
+ select |= SEL_ACT_SPEC_1;
+ str = &rpl_ldtoxic;
+ variable = ENV_FLG_TOXICPATH;
}
+
}
/*
* LD_UNREF and LD_UNUSED (internal, used by ldd(1)).
@@ -1974,7 +1983,8 @@ ld_generic_env(const char *s1, size_t len, const char *s2, Word *lmflags,
*lmtflags &= ~val;
} else if (select & SEL_ACT_SPEC_1) {
/*
- * variable is either ENV_FLG_FLAGS or ENV_FLG_LIBPATH
+ * variable is either ENV_FLG_FLAGS, ENV_FLG_LIBPATH, or
+ * ENV_FLG_TOXICPATH
*/
if (env_flags & ENV_TYP_NULL)
*str = NULL;
diff --git a/usr/src/cmd/sgs/yacc/common/dextern.h b/usr/src/cmd/sgs/yacc/common/dextern.h
index e90aa60468..54b441cac4 100644
--- a/usr/src/cmd/sgs/yacc/common/dextern.h
+++ b/usr/src/cmd/sgs/yacc/common/dextern.h
@@ -26,11 +26,13 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
#ifndef _DEXTERN_H
#define _DEXTERN_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <inttypes.h>
#include <ctype.h>
@@ -42,6 +44,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <wctype.h>
+#include <limits.h>
#ifdef __cplusplus
extern "C" {
@@ -301,6 +304,12 @@ extern int wscmp(const wchar_t *, const wchar_t *);
extern char *parser;
+#ifndef PBUFSIZE
+#define PBUFSIZE PATH_MAX
+#endif
+
+extern char pbuf[PBUFSIZE];
+
/* default settings for a number of macros */
/* name of yacc tempfiles */
@@ -324,7 +333,11 @@ extern char *parser;
#endif
#ifndef PARSER
-#define PARSER "/usr/share/lib/ccs/yaccpar"
+#define PARSER "/share/lib/ccs/yaccpar"
+#endif
+
+#ifndef PARSERPREFIX
+#define PARSERPREFIX "/usr"
#endif
/*
diff --git a/usr/src/cmd/sgs/yacc/common/y1.c b/usr/src/cmd/sgs/yacc/common/y1.c
index 845f82d367..0e67d9047b 100644
--- a/usr/src/cmd/sgs/yacc/common/y1.c
+++ b/usr/src/cmd/sgs/yacc/common/y1.c
@@ -26,7 +26,9 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
#include "dextern.h"
#include <sys/param.h>
@@ -34,6 +36,7 @@
#include <unistd.h>
#include <locale.h>
#include <stdarg.h> /* For error() */
+#include <libgen.h>
static void mktbls(void);
static void others(void);
@@ -236,6 +239,25 @@ mktbls()
lsetsize = INIT_LSIZE + 1;
}
+static int
+yacc_assemble_path(char *buf, size_t size, const char *file, int type)
+{
+ int ret;
+ char origin[PATH_MAX];
+
+ if (type != 0) {
+ ret = readlink("/proc/self/path/a.out", origin, PATH_MAX - 1);
+ if (ret < 0)
+ error(gettext(
+ "yacc: failed to read origin from /proc\n"));
+ origin[ret] = '\0';
+ return (snprintf(buf, size, "%s/../%s", dirname(origin),
+ file));
+ }
+
+ return (snprintf(buf, size, "%s/%s", PARSERPREFIX, file));
+}
+
/* put out other arrays, copy the parsers */
static void
others()
@@ -244,7 +266,17 @@ others()
int c, i, j;
int tmpline;
- finput = fopen(parser, "r");
+ if (parser == NULL) {
+ parser = pbuf;
+ (void) yacc_assemble_path(pbuf, PBUFSIZE, PARSER, 1);
+ finput = fopen(parser, "r");
+ if (finput == NULL) {
+ (void) yacc_assemble_path(pbuf, PBUFSIZE, PARSER, 0);
+ finput = fopen(parser, "r");
+ }
+ } else {
+ finput = fopen(parser, "r");
+ }
if (finput == NULL)
/*
* TRANSLATION_NOTE -- This is a message from yacc.
diff --git a/usr/src/cmd/sgs/yacc/common/y2.c b/usr/src/cmd/sgs/yacc/common/y2.c
index fbdaf19445..0d97f4260f 100644
--- a/usr/src/cmd/sgs/yacc/common/y2.c
+++ b/usr/src/cmd/sgs/yacc/common/y2.c
@@ -26,6 +26,10 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
#include "dextern.h"
#include "sgs.h"
#include <stdio.h>
@@ -58,7 +62,8 @@ char *infile; /* input file name */
static int numbval; /* value of an input number */
static int toksize = NAMESIZE;
static wchar_t *tokname; /* input token name */
-char *parser = PARSER; /* location of common parser */
+char *parser = NULL; /* location of common parser */
+char pbuf[PBUFSIZE];
static void finact(void);
static wchar_t *cstash(wchar_t *);
diff --git a/usr/src/cmd/smbios/Makefile b/usr/src/cmd/smbios/Makefile
index 9b2f9fb528..391fe3e53f 100644
--- a/usr/src/cmd/smbios/Makefile
+++ b/usr/src/cmd/smbios/Makefile
@@ -22,6 +22,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2018 Joyent, Inc.
+#
PROG = smbios
OBJS = smbios.o
@@ -35,6 +37,8 @@ LDLIBS += -lsmbios -ljedec
FILEMODE = 0555
STRIPFLAG =
+LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
+
.KEEP_STATE:
all: $(PROG)
diff --git a/usr/src/cmd/smbios/smbios.c b/usr/src/cmd/smbios/smbios.c
index dedfe29e9c..399a85501e 100644
--- a/usr/src/cmd/smbios/smbios.c
+++ b/usr/src/cmd/smbios/smbios.c
@@ -21,7 +21,7 @@
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
* Copyright 2020 Oxide Computer Company
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -388,10 +388,30 @@ print_system(smbios_hdl_t *shp, FILE *fp)
(void) smbios_info_system(shp, &s);
+ /*
+ * SMBIOS definition section 3.3.2.1 is clear that the first three
+ * fields are little-endian, but this utility traditionally got this
+ * wrong, and followed RFC 4122. We keep this old behavior, but also
+ * provide a corrected UUID.
+ */
oprintf(fp, " UUID: ");
- for (i = 0; i < s.smbs_uuidlen; i++) {
+ oprintf(fp, "%02x%02x%02x%02x-%02x%02x-%02x%02x-",
+ s.smbs_uuid[0], s.smbs_uuid[1], s.smbs_uuid[2], s.smbs_uuid[3],
+ s.smbs_uuid[4], s.smbs_uuid[5], s.smbs_uuid[6], s.smbs_uuid[7]);
+ for (i = 8; i < s.smbs_uuidlen; i++) {
+ oprintf(fp, "%02x", s.smbs_uuid[i]);
+ if (i == 9)
+ oprintf(fp, "-");
+ }
+ oprintf(fp, "\n");
+
+ oprintf(fp, " UUID (Endian-corrected): ");
+ oprintf(fp, "%08x-%04hx-%04hx-", *((uint_t *)&s.smbs_uuid[0]),
+ *((ushort_t *)&s.smbs_uuid[4]),
+ *((ushort_t *)&s.smbs_uuid[6]));
+ for (i = 8; i < s.smbs_uuidlen; i++) {
oprintf(fp, "%02x", s.smbs_uuid[i]);
- if (i == 3 || i == 5 || i == 7 || i == 9)
+ if (i == 9)
oprintf(fp, "-");
}
oprintf(fp, "\n");
diff --git a/usr/src/cmd/ssh/THIRDPARTYLICENSE.descrip b/usr/src/cmd/ssh/THIRDPARTYLICENSE.descrip
deleted file mode 100644
index 7e936fffc7..0000000000
--- a/usr/src/cmd/ssh/THIRDPARTYLICENSE.descrip
+++ /dev/null
@@ -1 +0,0 @@
-OPENSSH SOFTWARE
diff --git a/usr/src/cmd/ssh/doc/LICENCE b/usr/src/cmd/ssh/doc/LICENCE
deleted file mode 100644
index 04d6fe18e3..0000000000
--- a/usr/src/cmd/ssh/doc/LICENCE
+++ /dev/null
@@ -1,194 +0,0 @@
-This file is part of the ssh software.
-
-The licences which components of this software falls under are as
-follows. First, we will summarize and say that that all components
-are under a BSD licence, or a licence more free than that.
-
-OpenSSH contains no GPL code.
-
-1)
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose. Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
-
- [Tatu continues]
- * However, I am not implying to give any licenses to any patents or
- * copyrights held by third parties, and the software includes parts that
- * are not under my direct control. As far as I know, all included
- * source code is used in accordance with the relevant license agreements
- * and can be used freely for any purpose (the GNU license being the most
- * restrictive); see below for details.
-
- [However, none of that term is relevant at this point in time. All of
- these restrictively licenced software components which he talks about
- have been removed from OpenSSH, ie.
-
- - RSA is no longer included, found in the OpenSSL library
- - IDEA is no longer included, it's use is depricated
- - DES is now external, in the OpenSSL library
- - GMP is no longer used, and instead we call BN code from OpenSSL
- - Zlib is now external, in a library
- - The make-ssh-known-hosts script is no longer included
- - TSS has been removed
- - MD5 is now external, in the OpenSSL library
- - RC4 support has been replaced with ARC4 support from OpenSSL
- - Blowfish is now external, in the OpenSSL library
-
- [The licence continues]
-
- Note that any information and cryptographic algorithms used in this
- software are publicly available on the Internet and at any major
- bookstore, scientific library, and patent office worldwide. More
- information can be found e.g. at "http://www.cs.hut.fi/crypto".
-
- The legal status of this program is some combination of all these
- permissions and restrictions. Use only at your own responsibility.
- You will be responsible for any legal consequences yourself; I am not
- making any claims whether possessing or using this is legal or not in
- your country, and I am not taking any responsibility on your behalf.
-
-
- NO WARRANTY
-
- BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- REPAIR OR CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGES.
-
-2)
- The 32-bit CRC implementation in crc32.c is due to Gary S. Brown.
- Comments in the file indicate it may be used for any purpose without
- restrictions:
-
- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
- * code or tables extracted from it, as desired without restriction.
-
-3)
- The 32-bit CRC compensation attack detector in deattack.c was
- contributed by CORE SDI S.A. under a BSD-style license. See
- http://www.core-sdi.com/english/ssh/ for details.
-
- * Cryptographic attack detector for ssh - source code
- *
- * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
- *
- * All rights reserved. Redistribution and use in source and binary
- * forms, with or without modification, are permitted provided that
- * this copyright notice is retained.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
- * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
- * SOFTWARE.
- *
- * Ariel Futoransky <futo@core-sdi.com>
- * <http://www.core-sdi.com>
-
-3a)
- Various parts are from the University of California.
-
- * Copyright (c) 1983, 1987, 1989-1995
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
-
- * Copyright (c) 1989, 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
-
-4)
- Remaining components of the software are provided under a standard
- 2-term BSD licence with the following names as copyright holders:
-
- Markus Friedl
- Theo de Raadt
- Niels Provos
- Dug Song
- Aaron Campbell
-
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/usr/src/cmd/ssh/etc/ssh.xml b/usr/src/cmd/ssh/etc/ssh.xml
deleted file mode 100644
index f5fb471669..0000000000
--- a/usr/src/cmd/ssh/etc/ssh.xml
+++ /dev/null
@@ -1,177 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
-<!--
- CDDL HEADER START
-
- The contents of this file are subject to the terms of the
- Common Development and Distribution License (the "License").
- You may not use this file except in compliance with the License.
-
- You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- or http://www.opensolaris.org/os/licensing.
- See the License for the specific language governing permissions
- and limitations under the License.
-
- When distributing Covered Code, include this CDDL HEADER in each
- file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- If applicable, add the following below this CDDL HEADER, with the
- fields enclosed by brackets "[]" replaced with your own identifying
- information: Portions Copyright [yyyy] [name of copyright owner]
-
- CDDL HEADER END
-
- Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- Use is subject to license terms.
-
- Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-
- NOTE: This service manifest is not editable; its contents will
- be overwritten by package or patch operations, including
- operating system upgrade. Make customizations in a different
- file.
--->
-
-<service_bundle type='manifest' name='SUNWsshdr:ssh'>
-
-<service
- name='network/ssh'
- type='service'
- version='1'>
-
- <create_default_instance enabled='false' />
-
- <single_instance />
-
- <dependency name='fs-local'
- grouping='require_all'
- restart_on='none'
- type='service'>
- <service_fmri
- value='svc:/system/filesystem/local' />
- </dependency>
-
- <dependency name='fs-autofs'
- grouping='optional_all'
- restart_on='none'
- type='service'>
- <service_fmri value='svc:/system/filesystem/autofs' />
- </dependency>
-
- <dependency name='net-loopback'
- grouping='require_all'
- restart_on='none'
- type='service'>
- <service_fmri value='svc:/network/loopback' />
- </dependency>
-
- <dependency name='net-physical'
- grouping='require_all'
- restart_on='none'
- type='service'>
- <service_fmri value='svc:/network/physical' />
- </dependency>
-
- <dependency name='cryptosvc'
- grouping='require_all'
- restart_on='none'
- type='service'>
- <service_fmri value='svc:/system/cryptosvc' />
- </dependency>
-
- <dependency name='utmp'
- grouping='require_all'
- restart_on='none'
- type='service'>
- <service_fmri value='svc:/system/utmp' />
- </dependency>
-
- <dependency name='network_ipfilter'
- grouping='optional_all'
- restart_on='error'
- type='service'>
- <service_fmri value='svc:/network/ipfilter:default' />
- </dependency>
-
- <dependency name='config_data'
- grouping='require_all'
- restart_on='restart'
- type='path'>
- <service_fmri
- value='file://localhost/etc/ssh/sshd_config' />
- </dependency>
-
- <dependent
- name='ssh_multi-user-server'
- grouping='optional_all'
- restart_on='none'>
- <service_fmri
- value='svc:/milestone/multi-user-server' />
- </dependent>
-
- <exec_method
- type='method'
- name='start'
- exec='/lib/svc/method/sshd start'
- timeout_seconds='60'/>
-
- <exec_method
- type='method'
- name='stop'
- exec=':kill'
- timeout_seconds='60' />
-
- <exec_method
- type='method'
- name='refresh'
- exec='/lib/svc/method/sshd restart'
- timeout_seconds='60' />
-
- <property_group name='startd'
- type='framework'>
- <!-- sub-process core dumps shouldn't restart session -->
- <propval name='ignore_error'
- type='astring' value='core,signal' />
- </property_group>
-
- <property_group name='general' type='framework'>
- <!-- to start stop sshd -->
- <propval name='action_authorization' type='astring'
- value='solaris.smf.manage.ssh' />
- </property_group>
-
- <property_group name='firewall_context' type='com.sun,fw_definition'>
- <propval name='name' type='astring' value='ssh' />
- <propval name='ipf_method' type='astring'
- value='/lib/svc/method/sshd ipfilter' />
- </property_group>
-
- <property_group name='firewall_config' type='com.sun,fw_configuration'>
- <propval name='policy' type='astring' value='use_global' />
- <propval name='block_policy' type='astring'
- value='use_global' />
- <propval name='apply_to' type='astring' value='' />
- <propval name='apply_to_6' type='astring' value='' />
- <propval name='exceptions' type='astring' value='' />
- <propval name='exceptions_6' type='astring' value='' />
- <propval name='target' type='astring' value='' />
- <propval name='target_6' type='astring' value='' />
- <propval name='value_authorization' type='astring'
- value='solaris.smf.value.firewall.config' />
- </property_group>
-
- <stability value='Unstable' />
-
- <template>
- <common_name>
- <loctext xml:lang='C'>
- SSH server
- </loctext>
- </common_name>
- <documentation>
- <manpage title='sshd' section='1M' manpath='/usr/share/man' />
- </documentation>
- </template>
-
-</service>
-
-</service_bundle>
diff --git a/usr/src/cmd/ssh/etc/ssh_config b/usr/src/cmd/ssh/etc/ssh_config
deleted file mode 100644
index cdb9d97d45..0000000000
--- a/usr/src/cmd/ssh/etc/ssh_config
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (c) 2001 by Sun Microsystems, Inc.
-# All rights reserved.
-#
-# ident "%Z%%M% %I% %E% SMI"
-#
-# This file provides defaults for ssh(1).
-# The values can be changed in per-user configuration files $HOME/.ssh/config
-# or on the command line of ssh(1).
-
-# Configuration data is parsed as follows:
-# 1. command line options
-# 2. user-specific file
-# 3. system-wide file /etc/ssh/ssh_config
-#
-# Any configuration value is only changed the first time it is set.
-# host-specific definitions should be at the beginning of the
-# configuration file, and defaults at the end.
-
-# Example (matches compiled in defaults):
-#
-# Host *
-# ForwardAgent no
-# ForwardX11 no
-# PubkeyAuthentication yes
-# PasswordAuthentication yes
-# FallBackToRsh no
-# UseRsh no
-# BatchMode no
-# CheckHostIP yes
-# StrictHostKeyChecking ask
-# EscapeChar ~
diff --git a/usr/src/cmd/ssh/etc/sshd b/usr/src/cmd/ssh/etc/sshd
deleted file mode 100644
index d52b1afd25..0000000000
--- a/usr/src/cmd/ssh/etc/sshd
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/sbin/sh
-#
-# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-#
-
-. /lib/svc/share/ipf_include.sh
-. /lib/svc/share/smf_include.sh
-
-SSHDIR=/etc/ssh
-KEYGEN="/usr/bin/ssh-keygen -q"
-PIDFILE=/var/run/sshd.pid
-
-# Checks to see if RSA, and DSA host keys are available
-# if any of these keys are not present, the respective keys are created.
-create_key()
-{
- keypath=$1
- keytype=$2
-
- if [ ! -f $keypath ]; then
- #
- # HostKey keywords in sshd_config may be preceded or
- # followed by a mix of any number of space or tabs,
- # and optionally have an = between keyword and
- # argument. We use two grep invocations such that we
- # can match HostKey case insensitively but still have
- # the case of the path name be significant, keeping
- # the pattern somewhat more readable.
- #
- # The character classes below contain one literal
- # space and one literal tab.
- #
- grep -i "^[ ]*HostKey[ ]*=\{0,1\}[ ]*$keypath" \
- $SSHDIR/sshd_config | grep "$keypath" > /dev/null 2>&1
-
- if [ $? -eq 0 ]; then
- echo Creating new $keytype public/private host key pair
- $KEYGEN -f $keypath -t $keytype -N ''
- if [ $? -ne 0 ]; then
- echo "Could not create $keytype key: $keypath"
- exit $SMF_EXIT_ERR_CONFIG
- fi
- fi
- fi
-}
-
-create_ipf_rules()
-{
- FMRI=$1
- ipf_file=`fmri_to_file ${FMRI} $IPF_SUFFIX`
- ipf6_file=`fmri_to_file ${FMRI} $IPF6_SUFFIX`
- policy=`get_policy ${FMRI}`
-
- #
- # Get port from /etc/ssh/sshd_config
- #
- tports=`grep "^Port" /etc/ssh/sshd_config 2>/dev/null | \
- awk '{print $2}'`
-
- echo "# $FMRI" >$ipf_file
- echo "# $FMRI" >$ipf6_file
- for port in $tports; do
- generate_rules $FMRI $policy "tcp" $port $ipf_file
- generate_rules $FMRI $policy "tcp" $port $ipf6_file _6
- done
-}
-
-# This script is being used for two purposes: as part of an SMF
-# start/stop/refresh method, and as a sysidconfig(1M)/sys-unconfig(1M)
-# application.
-#
-# Both, the SMF methods and sysidconfig/sys-unconfig use different
-# arguments..
-
-case $1 in
- # sysidconfig/sys-unconfig arguments (-c and -u)
-'-c')
- /usr/bin/ssh-keygen -A
- if [ $? -ne 0 ]; then
- create_key $SSHDIR/ssh_host_rsa_key rsa
- create_key $SSHDIR/ssh_host_dsa_key dsa
- fi
- ;;
-
-'-u')
- # sys-unconfig(1M) knows how to remove ssh host keys, so there's
- # nothing to do here.
- :
- ;;
-
- # SMF arguments (start and restart [really "refresh"])
-
-'ipfilter')
- create_ipf_rules $2
- ;;
-
-'start')
- #
- # If host keys don't exist when the service is started, create
- # them; sysidconfig is not run in every situation (such as on
- # the install media).
- #
- /usr/bin/ssh-keygen -A
- if [ $? -ne 0 ]; then
- create_key $SSHDIR/ssh_host_rsa_key rsa
- create_key $SSHDIR/ssh_host_dsa_key dsa
- fi
-
- /usr/lib/ssh/sshd
- ;;
-
-'restart')
- if [ -f "$PIDFILE" ]; then
- /usr/bin/kill -HUP `/usr/bin/cat $PIDFILE`
- fi
- ;;
-
-*)
- echo "Usage: $0 { start | restart }"
- exit 1
- ;;
-esac
-
-exit $?
diff --git a/usr/src/cmd/ssh/etc/sshd_config b/usr/src/cmd/ssh/etc/sshd_config
deleted file mode 100644
index fd4aa5df46..0000000000
--- a/usr/src/cmd/ssh/etc/sshd_config
+++ /dev/null
@@ -1,145 +0,0 @@
-#
-# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
-#
-# Configuration file for sshd(1m) (see also sshd_config(4))
-#
-
-# Protocol versions supported
-#
-# The sshd shipped in this release of Solaris has support for major versions
-# 1 and 2. It is recommended due to security weaknesses in the v1 protocol
-# that sites run only v2 if possible. Support for v1 is provided to help sites
-# with existing ssh v1 clients/servers to transition.
-# Support for v1 may not be available in a future release of Solaris.
-#
-# To enable support for v1 an RSA1 key must be created with ssh-keygen(1).
-# RSA and DSA keys for protocol v2 are created by /etc/init.d/sshd if they
-# do not already exist, RSA1 keys for protocol v1 are not automatically created.
-
-# Uncomment ONLY ONE of the following Protocol statements.
-
-# Only v2 (recommended)
-Protocol 2
-
-# Both v1 and v2 (not recommended)
-#Protocol 2,1
-
-# Only v1 (not recommended)
-#Protocol 1
-
-# Listen port (the IANA registered port number for ssh is 22)
-Port 22
-
-# The default listen address is all interfaces, this may need to be changed
-# if you wish to restrict the interfaces sshd listens on for a multi homed host.
-# Multiple ListenAddress entries are allowed.
-
-# IPv4 only
-#ListenAddress 0.0.0.0
-# IPv4 & IPv6
-ListenAddress ::
-
-# If port forwarding is enabled (default), specify if the server can bind to
-# INADDR_ANY.
-# This allows the local port forwarding to work when connections are received
-# from any remote host.
-GatewayPorts no
-
-# X11 tunneling options
-X11Forwarding yes
-X11DisplayOffset 10
-X11UseLocalhost yes
-
-# The maximum number of concurrent unauthenticated connections to sshd.
-# start:rate:full see sshd(1) for more information.
-# The default is 10 unauthenticated clients.
-#MaxStartups 10:30:60
-
-# Banner to be printed before authentication starts.
-#Banner /etc/issue
-
-# Should sshd print the /etc/motd file and check for mail.
-# On Solaris it is assumed that the login shell will do these (eg /etc/profile).
-PrintMotd no
-
-# KeepAlive specifies whether keep alive messages are sent to the client.
-# See sshd(1) for detailed description of what this means.
-# Note that the client may also be sending keep alive messages to the server.
-KeepAlive yes
-
-# Syslog facility and level
-SyslogFacility auth
-LogLevel info
-
-#
-# Authentication configuration
-#
-
-# Host private key files
-# Must be on a local disk and readable only by the root user (root:sys 600).
-HostKey /etc/ssh/ssh_host_rsa_key
-HostKey /etc/ssh/ssh_host_dsa_key
-
-# Length of the server key
-# Default 768, Minimum 512
-ServerKeyBits 768
-
-# sshd regenerates the key every KeyRegenerationInterval seconds.
-# The key is never stored anywhere except the memory of sshd.
-# The default is 1 hour (3600 seconds).
-KeyRegenerationInterval 3600
-
-# Ensure secure permissions on users .ssh directory.
-StrictModes yes
-
-# Length of time in seconds before a client that hasn't completed
-# authentication is disconnected.
-# Default is 600 seconds. 0 means no time limit.
-LoginGraceTime 600
-
-# Maximum number of retries for authentication
-# Default is 6. Default (if unset) for MaxAuthTriesLog is MaxAuthTries / 2
-MaxAuthTries 6
-MaxAuthTriesLog 3
-
-# Are logins to accounts with empty passwords allowed.
-# If PermitEmptyPasswords is no, pass PAM_DISALLOW_NULL_AUTHTOK
-# to pam_authenticate(3PAM).
-PermitEmptyPasswords no
-
-# To disable tunneled clear text passwords, change PasswordAuthentication to no.
-PasswordAuthentication yes
-
-# Are root logins permitted using sshd.
-# Note that sshd uses pam_authenticate(3PAM) so the root (or any other) user
-# maybe denied access by a PAM module regardless of this setting.
-# Valid options are yes, without-password, no.
-PermitRootLogin no
-
-# sftp subsystem
-Subsystem sftp internal-sftp
-
-
-# SSH protocol v1 specific options
-#
-# The following options only apply to the v1 protocol and provide
-# some form of backwards compatibility with the very weak security
-# of /usr/bin/rsh. Their use is not recommended and the functionality
-# will be removed when support for v1 protocol is removed.
-
-# Should sshd use .rhosts and .shosts for password less authentication.
-IgnoreRhosts yes
-RhostsAuthentication no
-
-# Rhosts RSA Authentication
-# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts.
-# If the user on the client side is not root then this won't work on
-# Solaris since /usr/bin/ssh is not installed setuid.
-RhostsRSAAuthentication no
-
-# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication.
-#IgnoreUserKnownHosts yes
-
-# Is pure RSA authentication allowed.
-# Default is yes
-RSAAuthentication yes
diff --git a/usr/src/cmd/stat/Makefile b/usr/src/cmd/stat/Makefile
index 34149b2b37..faffc6a437 100644
--- a/usr/src/cmd/stat/Makefile
+++ b/usr/src/cmd/stat/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2011, 2012, Joyent, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/stat/Makefile
@@ -27,7 +27,14 @@
include ../Makefile.cmd
-SUBDIRS= arcstat iostat mpstat vmstat fsstat kstat
+SUBDIRS= arcstat \
+ fsstat \
+ iostat \
+ kstat \
+ mpstat \
+ vfsstat \
+ vmstat \
+ ziostat
all := TARGET = all
install := TARGET = install
diff --git a/usr/src/cmd/stat/arcstat/Makefile b/usr/src/cmd/stat/arcstat/Makefile
index 6ae60a8d3d..a98e2fee7e 100644
--- a/usr/src/cmd/stat/arcstat/Makefile
+++ b/usr/src/cmd/stat/arcstat/Makefile
@@ -11,6 +11,7 @@
#
# Copyright 2014 Adam Stevko. All rights reserved.
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
#
include $(SRC)/cmd/Makefile.cmd
diff --git a/usr/src/cmd/stat/arcstat/arcstat.pl b/usr/src/cmd/stat/arcstat/arcstat.pl
index d4f12a9e1c..d4f12a9e1c 100755..100644
--- a/usr/src/cmd/stat/arcstat/arcstat.pl
+++ b/usr/src/cmd/stat/arcstat/arcstat.pl
diff --git a/usr/src/cmd/ssh/Makefile b/usr/src/cmd/stat/vfsstat/Makefile
index c68aa94238..04b5085243 100644
--- a/usr/src/cmd/ssh/Makefile
+++ b/usr/src/cmd/stat/vfsstat/Makefile
@@ -18,41 +18,24 @@
#
# CDDL HEADER END
#
-
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
#
-include ../Makefile.cmd
+include $(SRC)/cmd/Makefile.cmd
-SUBDIRS= \
- etc
-
-CLOBBERFILES += $(MSGFILE) THIRDPARTYLICENSE
+PROG= vfsstat
.KEEP_STATE:
-all := TARGET= all
-clean := TARGET= clean
-clobber := TARGET= clobber
-install := TARGET= install
+all: $(PROG)
-all clean install: $(SUBDIRS)
+install: all .WAIT $(ROOTPROG)
-lint:
+clean:
-clobber: $(SUBDIRS) clobber_local
-clobber_local:
- $(RM) $(CLOBBERFILES)
+$(ROOTBINPROG): $(PROG)
+ $(INS.file)
-all install: THIRDPARTYLICENSE
-
-$(SUBDIRS): FRC
- cd $@; pwd; $(MAKE) $(TARGET)
-
-# skip the summary; just include the actual license clauses.
-THIRDPARTYLICENSE: doc/LICENCE
- $(SED) -n '/1)/,$$p' doc/LICENCE > $@
+lint:
-FRC:
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/stat/vfsstat/vfsstat.pl b/usr/src/cmd/stat/vfsstat/vfsstat.pl
new file mode 100644
index 0000000000..a3780b8e63
--- /dev/null
+++ b/usr/src/cmd/stat/vfsstat/vfsstat.pl
@@ -0,0 +1,227 @@
+#!/usr/perl5/bin/perl -w
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011 Joyent, Inc.
+#
+# vfsstat - report VFS statistics per zone
+#
+# USAGE: vfsstat [-hIMrzZ] [interval [count]]
+# -h # help
+# -I # print results per interval (where applicable)
+# -M # print results in MB/s
+# -r # print data in comma-separated format
+# -z # hide zones with no VFS activity
+# -Z # print data for all zones
+#
+# eg, vfsstat # print summary since zone boot
+# vfsstat 1 # print continually every 1 second
+# vfsstat 1 5 # print 5 times, every 1 second
+#
+# NOTES:
+#
+# - The calculations and output fields emulate those from iostat(1M) as closely
+# as possible. When only one zone is actively performing disk I/O, the
+# results from iostat(1M) in the global zone and vfsstat in the local zone
+# should be almost identical. Note that many VFS read operations are handled
+# by the ARC, so vfsstat and iostat(1M) will be similar only when most
+# requests are missing in the ARC.
+#
+# - As with iostat(1M), a result of 100% for VFS read and write utilization does
+# not mean that the syscall layer is fully saturated. Instead, that
+# measurement just shows that at least one operation was pending over the last
+# quanta of time examined. Since the VFS layer can process more than one
+# operation concurrently, this measurement will frequently be 100% but the VFS
+# layer can still accept additional requests.
+#
+# - This script is based on Brendan Gregg's K9Toolkit examples:
+#
+# http://www.brendangregg.com/k9toolkit.html
+#
+
+use Getopt::Std;
+use Sun::Solaris::Kstat;
+my $Kstat = Sun::Solaris::Kstat->new();
+
+# Process command line args
+usage() if defined $ARGV[0] and $ARGV[0] eq "--help";
+getopts('hIMrzZ') or usage();
+usage() if defined $main::opt_h;
+$main::opt_h = 0;
+
+my $USE_MB = defined $main::opt_M ? $main::opt_M : 0;
+my $USE_INTERVAL = defined $main::opt_I ? $main::opt_I : 0;
+my $USE_COMMA = defined $main::opt_r ? $main::opt_r : 0;
+my $HIDE_ZEROES = defined $main::opt_z ? $main::opt_z : 0;
+my $ALL_ZONES = defined $main::opt_Z ? $main::opt_Z : 0;
+
+my ($interval, $count);
+if ( defined($ARGV[0]) ) {
+ $interval = $ARGV[0];
+ $count = defined ($ARGV[1]) ? $ARGV[1] : 2**32;
+ usage() if ($interval == 0);
+} else {
+ $interval = 1;
+ $count = 1;
+}
+
+my $HEADER_FMT = $USE_COMMA ?
+ "r/%s,w/%s,%sr/%s,%sw/%s,ractv,wactv,read_t,writ_t,%%r,%%w," .
+ "d/%s,del_t,zone\n" :
+ " r/%s w/%s %sr/%s %sw/%s ractv wactv read_t writ_t " .
+ "%%r %%w d/%s del_t zone\n";
+my $DATA_FMT = $USE_COMMA ?
+ "%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%d,%d,%.1f,%.1f,%s,%d\n" :
+ "%5.1f %5.1f %5.1f %5.1f %5.1f %5.1f %6.1f %6.1f %3d %3d " .
+ "%5.1f %6.1f %s (%d)\n";
+
+my $BYTES_PREFIX = $USE_MB ? "M" : "k";
+my $BYTES_DIVISOR = $USE_MB ? 1024 * 1024 : 1024;
+my $INTERVAL_SUFFIX = $USE_INTERVAL ? "i" : "s";
+my $NANOSEC = 1000000000;
+
+my @fields = ( 'reads', 'writes', 'nread', 'nwritten', 'rtime', 'wtime',
+ 'rlentime', 'wlentime', 'delay_cnt', 'delay_time', 'snaptime' );
+
+chomp(my $curzone = (`/sbin/zonename`));
+
+my %old = ();
+my $rows_printed = 0;
+
+for (my $ii = 0; $ii < $count; $ii++) {
+ # Read list of visible zones and their zone IDs
+ my @zones = ();
+ my %zoneids = ();
+ my $zoneadm = `zoneadm list -p | cut -d: -f1,2`;
+ @lines = split(/\n/, $zoneadm);
+ foreach $line (@lines) {
+ @tok = split(/:/, $line);
+ $zoneids->{$tok[1]} = $tok[0];
+ push(@zones, $tok[1]);
+ }
+
+ $Kstat->update();
+
+ # Print the column header every 20 rows
+ if ($rows_printed == 0 || $ALL_ZONES) {
+ printf($HEADER_FMT, $INTERVAL_SUFFIX, $INTERVAL_SUFFIX,
+ $BYTES_PREFIX, $INTERVAL_SUFFIX, $BYTES_PREFIX,
+ $INTERVAL_SUFFIX, $INTERVAL_SUFFIX);
+ }
+
+ $rows_printed = $rows_printed >= 20 ? 0 : $rows_printed + 1;
+
+ foreach $zone (@zones) {
+ if ((!$ALL_ZONES) && ($zone ne $curzone)) {
+ next;
+ }
+
+ if (! defined $old->{$zone}) {
+ $old->{$zone} = ();
+ foreach $field (@fields) { $old->{$zone}->{$field} = 0; }
+ }
+
+ #
+ # Kstats have a 30-character limit (KSTAT_STRLEN) on their
+ # names, so if the zone name exceeds that limit, use the first
+ # 30 characters.
+ #
+ my $trimmed_zone = substr($zone, 0, 30);
+ my $zoneid = $zoneids->{$zone};
+
+ print_stats($zone, $zoneid,
+ $Kstat->{'zone_vfs'}{$zoneid}{$trimmed_zone}, $old->{$zone});
+ }
+
+ sleep ($interval);
+}
+
+exit(0);
+
+sub print_stats {
+ my $zone = $_[0];
+ my $zoneid = $_[1];
+ my $data = $_[2];
+ my $old = $_[3];
+
+ my $etime = $data->{'snaptime'} -
+ ($old->{'snaptime'} > 0 ? $old->{'snaptime'} : $data->{'crtime'});
+
+ # Calculate basic statistics
+ my $rate_divisor = $USE_INTERVAL ? 1 : $etime;
+ my $reads = ($data->{'reads'} - $old->{'reads'}) / $rate_divisor;
+ my $writes = ($data->{'writes'} - $old->{'writes'}) / $rate_divisor;
+ my $nread = ($data->{'nread'} - $old->{'nread'}) /
+ $rate_divisor / $BYTES_DIVISOR;
+ my $nwritten = ($data->{'nwritten'} - $old->{'nwritten'}) /
+ $rate_divisor / $BYTES_DIVISOR;
+
+ # Calculate transactions per second
+ my $r_tps = ($data->{'reads'} - $old->{'reads'}) / $etime;
+ my $w_tps = ($data->{'writes'} - $old->{'writes'}) / $etime;
+
+ # Calculate average length of active queue
+ my $r_actv = (($data->{'rlentime'} - $old->{'rlentime'}) / $NANOSEC) /
+ $etime;
+ my $w_actv = (($data->{'wlentime'} - $old->{'wlentime'}) / $NANOSEC) /
+ $etime;
+
+ # Calculate average service time
+ # multiply by 1000 to convert to usecs for conssistency with del_t
+ my $read_t = ($r_tps > 0 ? $r_actv * (1000 / $r_tps) : 0.0) * 1000;
+ my $writ_t = ($w_tps > 0 ? $w_actv * (1000 / $w_tps) : 0.0) * 1000;
+
+ # Calculate I/O throttle delay metrics
+ my $delays = $data->{'delay_cnt'} - $old->{'delay_cnt'};
+ my $d_tps = $delays / $etime;
+ my $del_t = $delays > 0 ?
+ ($data->{'delay_time'} - $old->{'delay_time'}) / $delays : 0.0;
+
+ # Calculate the % time the VFS layer is active
+ my $r_b_pct = ((($data->{'rtime'} - $old->{'rtime'}) / $NANOSEC) /
+ $etime) * 100;
+ my $w_b_pct = ((($data->{'wtime'} - $old->{'wtime'}) / $NANOSEC) /
+ $etime) * 100;
+
+ if (! $HIDE_ZEROES || $reads != 0.0 || $writes != 0.0 ||
+ $nread != 0.0 || $nwritten != 0.0) {
+ printf($DATA_FMT, $reads, $writes, $nread, $nwritten, $r_actv,
+ $w_actv, $read_t, $writ_t, $r_b_pct, $w_b_pct,
+ $d_tps, $del_t, substr($zone, 0, 8), $zoneid);
+ }
+
+ # Save current calculations for next loop
+ foreach (@fields) { $old->{$_} = $data->{$_}; }
+}
+
+sub usage {
+ print STDERR <<END;
+USAGE: vfsstat [-hIMrzZ] [interval [count]]
+ eg, vfsstat # print summary since zone boot
+ vfsstat 1 # print continually every 1 second
+ vfsstat 1 5 # print 5 times, every 1 second
+ vfsstat -I # print results per interval (where applicable)
+ vfsstat -M # print results in MB/s
+ vfsstat -r # print results in comma-separated format
+ vfsstat -z # hide zones with no VFS activity
+ vfsstat -Z # print results for all zones
+END
+ exit 1;
+}
diff --git a/usr/src/cmd/stat/ziostat/Makefile b/usr/src/cmd/stat/ziostat/Makefile
new file mode 100644
index 0000000000..c338b59678
--- /dev/null
+++ b/usr/src/cmd/stat/ziostat/Makefile
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+
+PROG= ziostat
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all .WAIT $(ROOTPROG)
+
+clean:
+
+$(ROOTBINPROG): $(PROG)
+ $(INS.file)
+
+lint:
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/stat/ziostat/ziostat.pl b/usr/src/cmd/stat/ziostat/ziostat.pl
new file mode 100755
index 0000000000..cf95d2f5a5
--- /dev/null
+++ b/usr/src/cmd/stat/ziostat/ziostat.pl
@@ -0,0 +1,204 @@
+#!/usr/perl5/bin/perl -w
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011 Joyent, Inc.
+#
+# ziostat - report I/O statistics per zone
+#
+# USAGE: ziostat [-hIMrzZ] [interval [count]]
+# -h # help
+# -I # print results per interval (where applicable)
+# -M # print results in MB/s
+# -r # print data in comma-separated format
+# -z # hide zones with no ZFS I/O activity
+# -Z # print data for all zones
+#
+# eg, ziostat # print summary since zone boot
+# ziostat 1 # print continually every 1 second
+# ziostat 1 5 # print 5 times, every 1 second
+#
+# NOTES:
+#
+# - The calculations and output fields emulate those from iostat(1M) as closely
+# as possible. When only one zone is actively performing disk I/O, the
+# results from iostat(1M) in the global zone and ziostat in the local zone
+# should be almost identical.
+#
+# - As with iostat(1M), a result of 100% for disk utilization does not mean that
+# the disk is fully saturated. Instead, that measurement just shows that at
+# least one operation was pending over the last quanta of time examined.
+# Since disk devices can process more than one operation concurrently, this
+# measurement will frequently be 100% but the disk can still offer higher
+# performance.
+#
+# - This script is based on Brendan Gregg's K9Toolkit examples:
+#
+# http://www.brendangregg.com/k9toolkit.html
+#
+
+use Getopt::Std;
+use Sun::Solaris::Kstat;
+my $Kstat = Sun::Solaris::Kstat->new();
+
+# Process command line args
+usage() if defined $ARGV[0] and $ARGV[0] eq "--help";
+getopts('hIMrzZ') or usage();
+usage() if defined $main::opt_h;
+$main::opt_h = 0;
+
+my $USE_MB = defined $main::opt_M ? $main::opt_M : 0;
+my $USE_INTERVAL = defined $main::opt_I ? $main::opt_I : 0;
+my $USE_COMMA = defined $main::opt_r ? $main::opt_r : 0;
+my $HIDE_ZEROES = defined $main::opt_z ? $main::opt_z : 0;
+my $ALL_ZONES = defined $main::opt_Z ? $main::opt_Z : 0;
+
+my ($interval, $count);
+if ( defined($ARGV[0]) ) {
+ $interval = $ARGV[0];
+ $count = defined ($ARGV[1]) ? $ARGV[1] : 2**32;
+ usage() if ($interval == 0);
+} else {
+ $interval = 1;
+ $count = 1;
+}
+
+my $HEADER_FMT = $USE_COMMA ?
+ "r/%s,%sr/%s,actv,wsvc_t,asvc_t,%%b,zone\n" :
+ " r/%s %sr/%s actv wsvc_t asvc_t %%b zone\n";
+my $DATA_FMT = $USE_COMMA ?
+ "%.1f,%.1f,%.1f,%.1f,%.1f,%d,%s,%d\n" :
+ " %6.1f %6.1f %6.1f %6.1f %6.1f %3d %s (%d)\n";
+
+my $BYTES_PREFIX = $USE_MB ? "M" : "k";
+my $BYTES_DIVISOR = $USE_MB ? 1024 * 1024 : 1024;
+my $INTERVAL_SUFFIX = $USE_INTERVAL ? "i" : "s";
+my $NANOSEC = 1000000000;
+
+my @fields = ( 'reads', 'nread', 'waittime', 'rtime', 'rlentime', 'snaptime' );
+
+chomp(my $curzone = (`/sbin/zonename`));
+
+# Read list of visible zones and their zone IDs
+my @zones = ();
+my %zoneids = ();
+my $zoneadm = `zoneadm list -p | cut -d: -f1,2`;
+@lines = split(/\n/, $zoneadm);
+foreach $line (@lines) {
+ @tok = split(/:/, $line);
+ $zoneids->{$tok[1]} = $tok[0];
+ push(@zones, $tok[1]);
+}
+
+my %old = ();
+my $rows_printed = 0;
+
+$Kstat->update();
+
+for (my $ii = 0; $ii < $count; $ii++) {
+ # Print the column header every 20 rows
+ if ($rows_printed == 0 || $ALL_ZONES) {
+ printf($HEADER_FMT, $INTERVAL_SUFFIX, $BYTES_PREFIX,
+ $INTERVAL_SUFFIX, $INTERVAL_SUFFIX);
+ }
+
+ $rows_printed = $rows_printed >= 20 ? 0 : $rows_printed + 1;
+
+ foreach $zone (@zones) {
+ if ((!$ALL_ZONES) && ($zone ne $curzone)) {
+ next;
+ }
+
+ if (! defined $old->{$zone}) {
+ $old->{$zone} = ();
+ foreach $field (@fields) { $old->{$zone}->{$field} = 0; }
+ }
+
+ #
+ # Kstats have a 30-character limit (KSTAT_STRLEN) on their
+ # names, so if the zone name exceeds that limit, use the first
+ # 30 characters.
+ #
+ my $trimmed_zone = substr($zone, 0, 30);
+ my $zoneid = $zoneids->{$zone};
+
+ print_stats($zone, $zoneid,
+ $Kstat->{'zone_zfs'}{$zoneid}{$trimmed_zone}, $old->{$zone});
+ }
+
+ sleep ($interval);
+ $Kstat->update();
+}
+
+sub print_stats {
+ my $zone = $_[0];
+ my $zoneid = $_[1];
+ my $data = $_[2];
+ my $old = $_[3];
+
+ my $etime = $data->{'snaptime'} -
+ ($old->{'snaptime'} > 0 ? $old->{'snaptime'} : $data->{'crtime'});
+
+ # Calculate basic statistics
+ my $rate_divisor = $USE_INTERVAL ? 1 : $etime;
+ my $reads = ($data->{'reads'} - $old->{'reads'}) / $rate_divisor;
+ my $nread = ($data->{'nread'} - $old->{'nread'}) /
+ $rate_divisor / $BYTES_DIVISOR;
+
+ # Calculate overall transactions per second
+ my $ops = $data->{'reads'} - $old->{'reads'};
+ my $tps = $ops / $etime;
+
+ # Calculate average length of disk run queue
+ my $actv = (($data->{'rlentime'} - $old->{'rlentime'}) / $NANOSEC) /
+ $etime;
+
+ # Calculate average disk wait and service times
+ my $wsvc = $ops > 0 ? (($data->{'waittime'} - $old->{'waittime'}) /
+ 1000000) / $ops : 0.0;
+ my $asvc = $tps > 0 ? $actv * (1000 / $tps) : 0.0;
+
+ # Calculate the % time the disk run queue is active
+ my $b_pct = ((($data->{'rtime'} - $old->{'rtime'}) / $NANOSEC) /
+ $etime) * 100;
+
+ if (! $HIDE_ZEROES || $reads != 0.0 || $nread != 0.0 ) {
+ printf($DATA_FMT, $reads, $nread, $actv, $wsvc, $asvc,
+ $b_pct, substr($zone, 0, 8), $zoneid);
+ }
+
+ # Save current calculations for next loop
+ foreach (@fields) { $old->{$_} = $data->{$_}; }
+}
+
+sub usage {
+ print STDERR <<END;
+USAGE: ziostat [-hIMrzZ] [interval [count]]
+ eg, ziostat # print summary since zone boot
+ ziostat 1 # print continually every 1 second
+ ziostat 1 5 # print 5 times, every 1 second
+ ziostat -I # print results per interval (where applicable)
+ ziostat -M # print results in MB/s
+ ziostat -r # print results in comma-separated format
+ ziostat -z # hide zones with no ZFS I/O activity
+ ziostat -Z # print results for all zones
+END
+ exit 1;
+}
diff --git a/usr/src/cmd/svc/configd/backend.c b/usr/src/cmd/svc/configd/backend.c
index b7ed400cfd..4c3a7d0816 100644
--- a/usr/src/cmd/svc/configd/backend.c
+++ b/usr/src/cmd/svc/configd/backend.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
*/
/*
@@ -2194,7 +2195,24 @@ backend_tx_begin(backend_type_t t, backend_tx_t **txp)
UPDATE_TOTALS((*txp)->bt_be, bt_exec, ts, vts);
if (r == SQLITE_FULL)
(*txp)->bt_full = 1;
- r = backend_error((*txp)->bt_be, r, errmsg);
+ /*
+ * We explicitly handle an ENOSPC error here for the beginning of the
+ * transaction, instead of in backend_error, which calls backend_panic
+ * for this case, resulting in the death of svc.configd. That may be
+ * appropriate in other cases, but in this case we would rather fail so
+ * that configd remains up and the caller gets an approprate error. The
+ * failure mode is that there is not enough swap space to open the
+ * non-persistent database, so there won't be enough space to restart
+ * configd, leaving SMF in a state requiring manual intervention.
+ */
+ if (r == SQLITE_CANTOPEN && errno == ENOSPC &&
+ (*txp)->bt_type == BACKEND_TYPE_NONPERSIST) {
+ configd_info("Warning: no space to open %s\n",
+ bes[BACKEND_TYPE_NONPERSIST]->be_path);
+ r = REP_PROTOCOL_FAIL_NO_RESOURCES;
+ } else {
+ r = backend_error((*txp)->bt_be, r, errmsg);
+ }
if (r != REP_PROTOCOL_SUCCESS) {
assert(r != REP_PROTOCOL_DONE);
diff --git a/usr/src/cmd/svc/configd/rc_node.c b/usr/src/cmd/svc/configd/rc_node.c
index a5b968c53c..33cb2be7a2 100644
--- a/usr/src/cmd/svc/configd/rc_node.c
+++ b/usr/src/cmd/svc/configd/rc_node.c
@@ -24,6 +24,9 @@
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
/*
* rc_node.c - In-memory SCF object management
diff --git a/usr/src/cmd/svc/milestone/Makefile b/usr/src/cmd/svc/milestone/Makefile
index 901727dc9f..576576ba2e 100644
--- a/usr/src/cmd/svc/milestone/Makefile
+++ b/usr/src/cmd/svc/milestone/Makefile
@@ -21,6 +21,8 @@
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
#
+# Copyright 2019 Joyent, Inc.
+#
include ../../Makefile.cmd
@@ -30,6 +32,7 @@ BUILTXML= \
console-login.xml
FSSVCS= \
+ joyent-fs.xml \
local-fs.xml \
minimal-fs.xml \
root-fs.xml \
@@ -38,6 +41,7 @@ FSSVCS= \
FSMANIFESTS= $(FSSVCS:%=$(ROOTSVCSYSTEMFILESYSTEM)/%)
NETSVCS= \
+ network-early-admin.xml \
network-initial.xml \
network-install.xml \
network-iptun.xml \
@@ -75,8 +79,12 @@ SYSTEMSVCS= \
early-manifest-import.xml \
identity.xml \
manifest-import.xml \
+ mdata.xml \
process-security.xml \
rmtmpfiles.xml \
+ smartdc-config.xml \
+ smartdc-init.xml \
+ smartdc-ur.xml \
vtdaemon.xml
SYSTEMMANIFESTS = $(SYSTEMSVCS:%=$(ROOTSVCSYSTEM)/%)
@@ -103,6 +111,7 @@ SVCMETHOD=\
console-login \
devices-audio \
devices-local \
+ fs-joyent \
fs-local \
fs-minimal \
fs-root \
@@ -110,6 +119,9 @@ SVCMETHOD=\
identity-domain \
identity-node \
manifest-import \
+ mdata-execute \
+ mdata-fetch \
+ net-early-admin \
net-loc \
net-loopback \
net-init \
@@ -122,6 +134,11 @@ SVCMETHOD=\
net-routing-setup \
net-svc \
rmtmpfiles \
+ smartdc-config \
+ smartdc-init \
+ smartdc-ur \
+ sysidtool-net \
+ sysidtool-system \
vtdaemon
$(ROOTSVCMETHOD) := FILEMODE = 0555
@@ -161,4 +178,4 @@ $(ROOTSVCSYSTEM)/svc/%: %
$(ROOT)/lib/svc/share/%: %.share
$(INS.rename)
-clean lint _msg:
+clean _msg:
diff --git a/usr/src/cmd/svc/milestone/console-login b/usr/src/cmd/svc/milestone/console-login
index c7003b103b..8ddaaf29ac 100644
--- a/usr/src/cmd/svc/milestone/console-login
+++ b/usr/src/cmd/svc/milestone/console-login
@@ -23,6 +23,7 @@
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
#
# This method script manages all vt logins including system
# console login.
@@ -38,18 +39,29 @@
. /lib/svc/share/smf_include.sh
-if [ "$1" != "default" ]; then
- if smf_dont_configure_vt; then
- /usr/sbin/svcadm disable $SMF_FMRI
- exit $SMF_EXIT_OK
- fi
-fi
-
getproparg() {
val=`svcprop -p $2 $SMF_FMRI`
[ -n "$val" ] && [ "$val" != "\"\"" ] && echo $1 $val
}
+# The service configuration invokes this script with "%i", the name of the
+# instance, as the first argument.
+instance="$1"
+if [ -z "$instance" ]; then
+ exit $SMF_EXIT_ERR_CONFIG
+fi
+
+case "$instance" in
+vt*)
+ # This instance is for one of the virtual terminal devices. Check to
+ # see if the vt subsystem is initialised:
+ if smf_dont_configure_vt; then
+ /usr/sbin/svcadm disable "$SMF_FMRI"
+ exit $SMF_EXIT_OK
+ fi
+ ;;
+esac
+
args="-g"
val=`svcprop -p ttymon/device $SMF_FMRI`
@@ -61,6 +73,20 @@ if [ "$val" = "/dev/vt/1" ]; then
exit $SMF_EXIT_ERR_CONFIG
fi
+# In SmartOS we use ttyb for metadata so we set to a non-existent device here
+# to disable the service and exit.
+if [[ ${val} == "/dev/term/b" && \
+ $(sysinfo | json "Product") == "SmartDC HVM" ]]; then
+
+ val=/dev/do_not_use_ttyb_in_a_vm
+fi
+
+if [[ ! -e $val ]]; then
+ # This device doesn't exist, can't run a tty on it.
+ /usr/sbin/svcadm disable $SMF_FMRI
+ exit $SMF_EXIT_OK
+fi
+
args="$args -d $val"
args="$args `getproparg -l ttymon/label`"
diff --git a/usr/src/cmd/svc/milestone/fs-joyent b/usr/src/cmd/svc/milestone/fs-joyent
new file mode 100755
index 0000000000..0a9dc065a3
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/fs-joyent
@@ -0,0 +1,312 @@
+#!/bin/bash
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2020 Joyent, Inc.
+#
+
+set -o xtrace
+
+fatal()
+{
+ echo "Error: $1"
+ exit $SMF_EXIT_ERR_FATAL
+}
+
+. /lib/svc/share/smf_include.sh
+. /lib/svc/share/fs_include.sh
+. /lib/sdc/usb-key.sh
+
+# first of all, if we aren't the global zone this doesn't make any sense to run
+
+smf_is_globalzone || exit $SMF_EXIT_OK
+
+# We need the links to /dev/dsk. Rather than trying to play games with manually
+# invoking syseventd ask devfsadm to do some work.
+/usr/sbin/devfsadm -c disk
+
+function destroy_zpools
+{
+ for pool in $(zpool list -p -o name | grep -v NAME) ; do
+ zpool destroy -f ${pool}
+ done
+}
+
+function mount_zfs
+{
+ local dataset=$1
+ local mountpoint=$2
+ local output=
+
+ #
+ # Try to mount the ZFS dataset. If the mountpoint is busy, wait five
+ # seconds and try again. Fail if the mount attempt returns EBUSY three
+ # consecutive times.
+ #
+ for i in {1..3}; do
+ output=$(mount -F zfs ${dataset} ${mountpoint} 2>&1)
+ if [[ $? -eq 0 ]]; then
+ break
+ fi
+
+ if [ "${output}" == "mount failed: Device busy" ]; then
+ sleep 5
+ else
+ echo ${output} 1>&2
+ return
+ fi
+ done
+
+ # The mount attempt must have failed
+ echo ${output} 1>&2
+}
+
+function unlock_pool
+{
+ local pool=$1
+
+ # If the key is already loaded, don't bother trying again
+ local keystatus="$(zfs get -Hpo value keystatus $pool)"
+ if [[ "$keystatus" == "available" ]]; then
+ return
+ fi
+
+ kbmadm unlock $pool && return
+
+ echo "Failed to unlock $pool; recovery may be required" | \
+ tee -a /dev/console >&2
+
+ exit $SMF_EXIT_ERR_FATAL
+}
+
+/bin/bootparams | grep "^noimport=true" >/dev/null
+if [ $? -ne 0 ]; then
+ # If the zpool doesn't exist, then there's nothing to mount.
+
+ # Assume the system zpool is zones, but if a different system pool
+ # identifies itself (by virtue of the .system_pool file being present in the
+ # pool's root dataset), then use that system pool instead.
+ SYS_ZPOOL=zones
+
+ # Import specified zpools, or all zpools available
+ pools=$(/bin/bootparams | egrep "^zpools?=" | cut -d= -f2 | tr , ' ')
+ if [ -z ${pools} ]; then
+ pools=$(zpool import | grep "pool:" | awk '{print $2}')
+ fi
+
+ for pool in $pools; do
+ zpool import -f $pool || continue
+
+ is_encr="$(zfs get -Hpo value encryption $pool)"
+
+ [[ "$is_encr" != "off" ]] && unlock_pool $pool
+
+ # Due to early, failed attempts to support the filesystem_limits
+ # feature we now need to ensure the dependent feature is enabled.
+ zpool set feature@extensible_dataset=enabled $pool
+ if [[ -f /$pool/.system_pool ]]; then
+ SYS_ZPOOL=$pool
+ [[ "$is_encr" != "off" ]] && kbmadm set-syspool $pool
+ fi
+ done
+
+ svccfg -s svc:/system/smartdc/init setprop \
+ config/zpool=${SYS_ZPOOL}
+ svccfg -s svc:/system/smartdc/init:default refresh
+
+ # If the destroy_zpools boot parameter is set, destroy all zpools
+ /bin/bootparams | grep "^destroy_zpools=true" >/dev/null
+ if [ $? -eq 0 ]; then
+ destroy_zpools
+ fi
+
+ # A machine is reset to its original unsetup state (i.e. a 'factory reset')
+ # when the smartdc:factoryreset ZFS user property is set on the var dataset.
+ reset=$(zfs get -H -o value smartdc:factoryreset ${SYS_ZPOOL}/var)
+ if [ "${reset}" == "yes" ]; then
+ destroy_zpools
+ fi
+
+ # Capture the zpool's status output in the method's log file for
+ # troubleshooting.
+ #
+ # Note: It is critical that we do not run 'status -v'. If there are errors
+ # in the zpool error log and the zpool is large (e.g. > 200TB), then the
+ # lookup for the error file names can take a very long time (several hours).
+ # This would block the system boot until it completed.
+ zpool status ${SYS_ZPOOL}
+ if [ $? -eq 0 ]; then
+
+ # Stash the SUNWdefault.xml file so we can update the
+ # persistent version after mounting zones/config.
+ cp /etc/zones/SUNWdefault.xml /tmp/
+
+ # Mount and configure all system datasets
+ mount_zfs ${SYS_ZPOOL}/var /var
+ mount_zfs ${SYS_ZPOOL}/config /etc/zones
+ mount_zfs ${SYS_ZPOOL}/opt /opt
+
+ # Update the the persistent SUNWdefault.xml file to match the
+ # contents on ramdisk now that zones/config is mounted.
+ cp /tmp/SUNWdefault.xml /etc/zones/
+ rm -f /tmp/SUNWdefault.xml
+
+ #
+ # We include a manifest of all files shipped in the platform image,
+ # along with an MD5 hash of their contents. This was originally
+ # shipped as "/var/log/manifest", but once a machine is set up, "/var"
+ # now comes from the pool. The upshot of this is that every SmartOS
+ # machine has the manifest from the platform at setup time stored in
+ # "/var/log/manifest". Now that the manifest has moved to an
+ # accessible location, we should remove this file and replace it with a
+ # symbolic link.
+ #
+ if [[ -f '/var/log/manifest' && ! -L '/var/log/manifest' &&
+ ! -e '/var/log/manifest.original' ]]; then
+ mv '/var/log/manifest' '/var/log/manifest.original'
+ ln -s '../../usr/share/smartos/manifest' '/var/log/manifest'
+ fi
+
+ if [[ -z $(/bin/bootparams | grep '^smartos=true') ]]; then
+ mkdir -p /opt/smartdc/agents/smf
+ mount -O -F lofs /var/svc/manifest/site /opt/smartdc/agents/smf
+ fi
+
+ if [[ -n $(/bin/bootparams | grep '^headnode=true') || \
+ -n $(/bin/bootparams | grep '^smartos=true') ]]; then
+ mkdir /usbkey
+ mount_zfs ${SYS_ZPOOL}/usbkey /usbkey
+ fi
+
+ if [[ -n $(/bin/bootparams | grep '^smartos=true') ]]; then
+ mount -F lofs /usbkey/shadow /etc/shadow
+ mount -F lofs /usbkey/ssh /etc/ssh
+ fi
+
+ swap -a /dev/zvol/dsk/${SYS_ZPOOL}/swap || \
+ fatal "failed to configure swap device"
+
+ #
+ # Configure the dump device on top of a ZFS volume. In addition to the
+ # usual dumpadm(1m) call, there are two prerequisites for using this
+ # volume as a dump device: (1) that zvol must be using the noparity
+ # checksum algorithem, and (2) the MULTI_VDEV_CRASH_DUMP ZFS feature
+ # must be enabled. Prerequisite (1) is necessary since the exact
+ # on-disk value for ZIO_CHECKSUM_NOPARITY has changed, so to avoid a
+ # flag day on all systems, this service just sets that property again
+ # every time.
+ #
+ zfs set checksum=noparity ${SYS_ZPOOL}/dump || \
+ fatal "failed to set checksum=noparity on dump zvol"
+ zpool set feature@multi_vdev_crash_dump=enabled ${SYS_ZPOOL} || \
+ fatal "failed to enable multi_vdev_crash_dump ZFS feature"
+ dumpadm -y -d /dev/zvol/dsk/${SYS_ZPOOL}/dump || \
+ fatal "failed to configure dump device"
+
+ zfs list -H -o name ${SYS_ZPOOL}/cores/global >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ # Booting for the first time on a CN whose cores dataset is setup
+ # in the 6.x style. Convert to the new style.
+ zfs destroy -r ${SYS_ZPOOL}/cores
+ zfs create -o compression=gzip -o mountpoint=none ${SYS_ZPOOL}/cores
+ zfs create -o quota=10g -o mountpoint=/${SYS_ZPOOL}/global/cores \
+ ${SYS_ZPOOL}/cores/global
+ fi
+
+ ln -s /${SYS_ZPOOL}/global/cores /cores
+
+ [[ -f /${SYS_ZPOOL}/currbooted ]] && \
+ mv /${SYS_ZPOOL}/currbooted /${SYS_ZPOOL}/lastbooted
+ uname -v >/${SYS_ZPOOL}/currbooted
+ fi
+fi
+
+
+# The rest only applies to the headnode
+/bin/bootparams | grep "^headnode=true" >/dev/null || exit $SMF_EXIT_OK
+
+# If we rebooted during an upgrade, we're in deep trouble.
+if [ -d /var/upgrade_in_progress ]; then
+ echo "ERROR: An upgrade was in progress when the system rebooted." \
+ >/dev/console
+ echo " The system is in an indeterminate state, unable to continue." \
+ >/dev/console
+ exit $SMF_EXIT_ERR_FATAL
+fi
+
+COPYINPOINT=`svcprop -p "joyentfs/usb_copy_path" ${SMF_FMRI}`
+DEBUG=`svcprop -p "joyentfs/debug" ${SMF_FMRI}`
+
+if [[ -d /mnt ]]; then
+ chown root:root /mnt
+ chmod 700 /mnt
+else
+ mkdir -m 700 /mnt
+fi
+
+function make_usb_copy_if_possible
+{
+ [[ -n "${SYS_ZPOOL}" ]] || fatal "don't know system zpool name"
+
+ zpool list -Ho name | grep "^${SYS_ZPOOL}\$"
+ if [[ $? != 0 ]]; then
+ echo "skipping USB copy setup: no ${SYS_ZPOOL} zpool" >/dev/console
+ # Still return OK, because this is the expected case for first headnode
+ # boot.
+ return 0
+ fi
+
+ USBDATASET=${SYS_ZPOOL}/usbkey
+ if ! zfs list -Ho name | grep "^${USBDATASET}\$" >/dev/null; then
+ echo "skipping USB copy setup: no zones/usbkey dataset" >/dev/console
+ # Still return OK, because as of HEAD-2343 a CN being converted to a HN
+ # will not yet have this dataset on its first boot as an HN.
+ return 0
+ fi
+
+ echo "" > /dev/console
+ echo "Moving files from USB boot device onto disk storage." > /dev/console
+ echo "This may take several minutes. Please note the time..." > /dev/console
+ echo "" > /dev/console
+ echo "" > /dev/console
+
+ mkdir ${COPYINPOINT}
+ mount_zfs ${USBDATASET} ${COPYINPOINT}
+
+ (cd ${USBMOUNTPOINT}; rsync -av --log-file=/dev/console --exclude private --exclude os * ${COPYINPOINT})
+ if [[ -d ${USBMOUNTPOINT}/os ]]; then
+ (cd ${USBMOUNTPOINT}/os ; \
+ for dir in $(ls -d *); do
+ # source comes from pcfs which we've got lowering the case
+ # of everything, but we normally use capital T and Z for
+ # buildstamp, so fix it here.
+ source_dir=${dir}
+ target_dir=$(echo ${dir} | tr "[:lower:]" "[:upper:]")
+ mkdir -p ${COPYINPOINT}/os
+ echo "Copying: ${source_dir}/ ${COPYINPOINT}/os/${target_dir}" > /dev/console
+ rsync -a ${source_dir}/ ${COPYINPOINT}/os/${target_dir}
+ done
+ )
+ fi
+
+ echo "" > /dev/console
+ echo "Done copying files from USB device" > /dev/console
+ return 0
+}
+
+USBMOUNTPOINT=$(mount_usb_key "")
+if [[ $? -ne 0 ]]; then
+ fatal "couldn't mount USB key"
+fi
+
+make_usb_copy_if_possible
+exit $?
diff --git a/usr/src/cmd/svc/milestone/fs-root b/usr/src/cmd/svc/milestone/fs-root
index 9652eaaf94..f9de44c831 100644
--- a/usr/src/cmd/svc/milestone/fs-root
+++ b/usr/src/cmd/svc/milestone/fs-root
@@ -22,6 +22,7 @@
#
# Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2016 Joyent, Inc.
#
# Make sure that the libraries essential to this stage of booting can be found.
@@ -64,92 +65,27 @@ if smf_is_nonglobalzone; then
exit $SMF_EXIT_OK
fi
-#
-# Root is already mounted (by the kernel), but still needs to be
-# checked, possibly remounted and entered into mnttab. First
-# mount /usr if it is a separate file system. If the file system
-# type is something other than zfs, mount it read-only. This must
-# be done first to allow utilities such as fsck and setmnt to
-# reside on /usr minimizing the space required by the root file
-# system.
-#
-readvfstab "/usr" < $vfstab
-if [ -n "$mountp" ]; then
- if [ "$fstype" = zfs ]; then
- mountfs - /usr $fstype $mntopts - || exit $SMF_EXIT_ERR_FATAL
- else
- #
- # Must use -o largefiles here to ensure the
- # read-only mount does not fail as a result of
- # having a large file present on /usr. This gives
- # fsck a chance to fix up the largefiles flag
- # before we remount /usr read-write.
- #
- if [ "x$mntopts" = x- ]; then
- mntopts='ro,largefiles'
- else
- checkopt largefiles $mntopts
- if [ "x$option" != xlargefiles ]; then
- mntopts="largefiles,$mntopts"
- fi
-
- checkopt ro $mntopts
- if [ "x$option" != xro ]; then
- mntopts="ro,$mntopts"
- fi
-
- #
- # Requesting logging on a read-only mount
- # causes errors to be displayed, so remove
- # "logging" from the list of options for now.
- # The read-write mount performed later will
- # specify the logging option if appropriate.
- #
-
- checkopt logging $mntopts
- if [ "x$option" = xlogging ]; then
- mntopts="$otherops"
- fi
- fi
-
- mountfs -O /usr $fstype $mntopts - || exit $SMF_EXIT_ERR_FATAL
- fi
-fi
+/sbin/mount -F ufs -o remount,rw,nologging /devices/ramdisk:a /
+/usr/sbin/lofiadm -X -a /usr.lgz
#
-# if we are booted from zfs, the /usr mount probably won't be a
-# legacy mount. Use the standard zfs mount command instead.
-
-readmnttab "/" < /etc/mnttab
-if [ "$fstype" = zfs ]; then
- mountp=`/sbin/zfs get -H -o value mountpoint $special/usr 2>/dev/null`
- #
- # if mountp = /usr, there is a non-legacy mount of /usr
- # in the boot environment being booted.
- #
- if [ "x$mountp" = "x/usr" ] ; then
- /sbin/zfs mount $special/usr
- if [ $? != 0 ] ; then
- msg='zfs-mount failed'
- echo $msg
- echo "$SMF_FMRI:" $msg >/dev/msglog
- exit $SMF_EXIT_ERR_FATAL
- fi
+# Prior to mounting /usr, devfsadm is not yet available. As such, we must
+# locate the lofi block device node in /devices rather than in /dev. This
+# path has changed over time so we try both the old (pre-partition support)
+# and new paths.
+#
+lofi_devices_path='/devices/pseudo/lofi@1:disk'
+if [ ! -b "$lofi_devices_path" ]; then
+ lofi_devices_path='/devices/pseudo/lofi@0:1'
+ if [ ! -b "$lofi_devices_path" ]; then
+ echo 'could not locate lofi block device in /devices' >&2
+ exit $SMF_EXIT_ERR_FATAL
fi
fi
-#
-# Also mount /boot now so that things like keymap.sh can access
-# boot properties through eeprom. Readonly isn't required because
-# /boot (and other pcfs filesystems) aren't fsck'ed at boot yet.
-# Also, we don't account for caching /boot as it must be on a local
-# disk. So what's in vfstab is fine as it stands; just look to see
-# if it's there and avoid the mount if not.
-#
-readvfstab "/boot" < $vfstab
-
-if [ -n "$mountp" ]; then
- mountfs - /boot $fstype $mntopts - || exit $SMF_EXIT_ERR_FATAL
+if ! /sbin/mount -F ufs -o ro "$lofi_devices_path" /usr; then
+ echo "could not mount /usr from $lofi_devices_path" >&2
+ exit $SMF_EXIT_ERR_FATAL
fi
#
diff --git a/usr/src/cmd/svc/milestone/fs-usr b/usr/src/cmd/svc/milestone/fs-usr
index 715cb1bca3..e4b6a263e1 100644
--- a/usr/src/cmd/svc/milestone/fs-usr
+++ b/usr/src/cmd/svc/milestone/fs-usr
@@ -19,171 +19,23 @@
#
# CDDL HEADER END
#
-
#
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
# All rights reserved.
# Copyright 2016 Nexenta Systems, Inc.
+# Copyright 2012, Joyent, Inc. All rights reserved.
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
-
. /lib/svc/share/smf_include.sh
-. /lib/svc/share/fs_include.sh
-
-UPDATEFILE=/etc/svc/volatile/boot_archive_needs_update
-
-#
-# Once root is read/write we can enable the dedicated dumpdevice if it exists
-# locally. This is an optimization as svc-dumpadm will attempt do this later.
-#
-dump_setup()
-{
- [ -r /etc/dumpadm.conf ] && . /etc/dumpadm.conf
-
- readswapdev $DUMPADM_DEVICE < $vfstab
-
- #
- # Make sure that the dump save area has been configured before
- # proceeding. If the variable has not been defined or does not exist
- # then bail out early. This will prevent us from configuring a
- # dump save area before a hostname has been configured (i.e after
- # sys-unconfig has been invoked).
- #
- [ -z "$DUMPADM_SAVDIR" ] && return
-
- #
- # If we have a dedicated dump device, then go ahead and configure it.
- #
- if [ "x$special" != "x$DUMPADM_DEVICE" ]; then
- if [ -x /usr/sbin/dumpadm -a -b $DUMPADM_DEVICE ]; then
- /usr/sbin/dumpadm -u || exit $SMF_EXIT_ERR_CONFIG
- fi
- fi
-}
-
-#
-# Write a unique id into this kernel image; this will be included
-# in the dump header and panicbuf of any crashdump of this image.
-#
-if [ -x /usr/sbin/dumpadm ]; then
- /usr/sbin/dumpadm -i
-fi
-
-rootiszfs=0
-# get the fstype of root
-readmnttab / </etc/mnttab
-if [ "$fstype" = zfs ] ; then
- rootiszfs=1
- dump_setup
-fi
-
-#
-# Add physical swap.
-#
-/sbin/swapadd -1
-
-#
-# Check and remount the / (root) file system.
-# For NFS mounts, force the llock option on.
-#
-if smf_is_globalzone && [ $rootiszfs = 0 ]; then
- readvfstab / < $vfstab
- checkfs $fsckdev $fstype $mountp || exit $SMF_EXIT_ERR_FATAL
- checkopt "llock" $mntopts
- mntopts='remount'
-
- [ -n "$otherops" ] && mntopts="${mntopts},${otherops}"
- [ "$fstype" = nfs ] && mntopts="${mntopts},llock"
-
- mountfs -m $mountp $fstype $mntopts - || exit $SMF_EXIT_ERR_FATAL
-fi
-
-#
-# Check and remount the /usr file system (formerly mounted read-only).
-# Unless root is zfs, in which case we've already mounted /usr read-write
-#
-if [ "$rootiszfs" = 0 ] ; then
- readvfstab /usr < $vfstab
- if [ "$mountp" ]; then
- checkopt ro $mntopts
- if [ "x$option" != xro ]; then
- checkfs $fsckdev $fstype $mountp ||
- exit $SMF_EXIT_ERR_FATAL
- if [ "x$mntopts" != x- ]; then
- mntopts="remount,$mntopts"
- else
- mntopts="remount"
- fi
-
- mountfs - /usr $fstype $mntopts - ||
- exit $SMF_EXIT_ERR_FATAL
- fi
- fi
-fi
-
-#
-# Check and mount the /usr/platform file system. This should only be
-# present when a SunOS 5.5 (Solaris 2.5) or greater client is being
-# administered by a SunOS 5.4 or less host.
-#
-readvfstab /usr/platform < $vfstab
-if [ "$mountp" ]; then
- checkfs $fsckdev $fstype $mountp || exit $SMF_EXIT_ERR_FATAL
- mountfs - $mountp $fstype $mntopts - || exit $SMF_EXIT_ERR_FATAL
-fi
-
-#
-# Mount the fd file systems if mount point exists.
-#
-readvfstab /dev/fd < $vfstab
-if [ "$mountp" -a -d /dev/fd ]; then
- mountfs - /dev/fd - - - || exit $SMF_EXIT_ERR_FATAL
-fi
-
-if [ -f "${UPDATEFILE}" ]; then
- /usr/sbin/bootadm update-archive
- if [ $? != 0 ]; then
- cecho ""
- cecho "WARNING: Automatic update of the boot archive failed."
- cecho "Update the archives using 'bootadm update-archive'"
- cecho "command and then reboot the system from the same device"
- cecho "that was previously booted."
- cecho ""
- exit $SMF_EXIT_ERR_FATAL
- fi
- rm -f $UPDATEFILE
- cecho ""
- cecho "WARNING: Reboot required."
- cecho "The system has updated the cache of files (boot archive) that"
- cecho "is used during the early boot sequence. To avoid booting and"
- cecho "running the system with the previously out-of-sync version of"
- cecho "these files, the system will be restarted."
- cecho ""
+mount /dev/fd
- bootcmd=`/usr/sbin/eeprom bootcmd | /usr/bin/sed -e 's#bootcmd=##g'`
- if [ `uname -p` = "i386" ]; then
- /usr/sbin/reboot -f dryrun
- if [ $? = 0 ]; then
- /usr/sbin/reboot -f -- "$bootcmd"
- exit $SMF_EXIT_OK
- fi
- boot_prop=`/usr/sbin/svccfg -s svc:/system/boot-config:default \
- listprop config/auto-reboot-safe | \
- /usr/bin/nawk '{ print $3}'`
- if [ "$boot_prop" = "true" ]; then
- /usr/sbin/reboot -p
- exit $SMF_EXIT_OK
- fi
- cecho ""
- cecho "It has not been possible to restart automatically."
- cecho "Reboot the system from the same device that was"
- cecho "previously booted."
- cecho ""
- exit $SMF_EXIT_ERR_FATAL
- fi
- /usr/sbin/reboot -- "$bootcmd"
+if smf_is_globalzone; then
+ # svc.startd makes a backup of the repo on boot. Since this is a
+ # live-image, the backup takes up an unnecessary 4MB in memory, so remove
+ # it now.
+ rm -f /etc/svc/repository-*
fi
exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/svc/milestone/identity-node b/usr/src/cmd/svc/milestone/identity-node
index c9b20ba669..6b740f3dd1 100644
--- a/usr/src/cmd/svc/milestone/identity-node
+++ b/usr/src/cmd/svc/milestone/identity-node
@@ -27,18 +27,30 @@
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+# Copyright 2019 Joyent, Inc.
+#
. /lib/svc/share/smf_include.sh
. /lib/svc/share/net_include.sh
+set -o xtrace
+
# Make sure that the libraries essential to this stage of booting can be found.
LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH
#
-# If DHCP was used on a primary interface then set the hostname
-# that was returned. If no hostname was returned, set the name
-# to be "unknown". The hostname must be set to something, because
+# For the GZ, use one of the following values for hostname, in order:
+# * DHCP hostname (if set on a primary interface)
+# * hostname value from config file
+# * hostname bootparam
+# * if not a headnode:
+# * admin MAC address
+# * any other MAC address
+#
+# If none of the above could be found, default to "headnode" for headnodes, and
+# "unknown" for non-headnodes.
+#
+# The hostname must be set to something, because
# tooltalk will hang unless the name can be locally resolved.
# Sendmail also requires the name to be resolvable locally.
# Later, in inetsvc, we create a name "unknown" and create a entry
@@ -51,44 +63,124 @@ LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH
# kernel if /etc/nodename does not exist, as is expected on an initial boot.
#
+set_gz_hostname() {
+ hostname=${CONFIG_hostname}
+ if [ -z "$hostname" ] || [ "$hostname" == "unknown" ]; then
+ hostname=$SYSINFO_Bootparam_hostname
+ fi
+
+ if [ -n "$hostname" ] && [ "$hostname" != "unknown" ]; then
+ return
+ fi
+
+ # $headnode is set by load_sdc_config()
+ if [ "$headnode" == "true" ]; then
+ hostname="headnode"
+ return
+ fi
+
+ if [[ -n ${SYSINFO_NIC_admin} ]]; then
+ eval "admin_mac=\${SYSINFO_Network_Interface_${SYSINFO_NIC_admin}_MAC_Address}"
+ if [[ -n ${admin_mac} ]]; then
+ hostname=$(echo "${admin_mac}" | tr ':' '-')
+ return
+ fi
+ fi
+
+ fallback_mac=$(set | grep "^SYSINFO_Network_Interface_.*_MAC_Address" | head -n1 | cut -d'=' -f2)
+ if [[ -n ${fallback_mac} ]]; then
+ hostname=$(echo "${fallback_mac}" | tr ':' '-')
+ return
+ fi
+
+ hostname="unknown"
+}
+
+
smf_netstrategy
case "$_INIT_NET_STRATEGY" in
- "dhcp") hostname=`/sbin/dhcpinfo Hostname` ;;
- "rarp") hostname=`/sbin/hostconfig -h -p bootparams`
- trap 'intr=1' 2 3
- while [ -z "$hostname" -a ! -f /etc/.UNCONFIGURED -a \
- -z "$intr" ]; do
- echo "re-trying host configuration..."
- # Restrict this to IPv4 interfaces.
- /sbin/ifconfig -adD4 auto-revarp up
- hostname=`/sbin/hostconfig -h -p bootparams`
- done
- trap 2 3 ;;
- "none") hostname="`shcat /etc/nodename 2>/dev/null`"
- if [ -z "$hostname" ]; then
- if smf_is_globalzone; then
- hostname=`/sbin/hostconfig -h -p bootparams`
- else
- hostname=`/sbin/uname -n`
- fi
- fi ;;
+ "dhcp") hostname=`/sbin/dhcpinfo Hostname` ;;
+ "rarp") hostname=`/sbin/hostconfig -h -p bootparams`
+ trap 'intr=1' 2 3
+ while [ -z "$hostname" -a ! -f /etc/.UNCONFIGURED -a \
+ -z "$intr" ]; do
+ echo "re-trying host configuration..."
+ # Restrict this to IPv4 interfaces.
+ /sbin/ifconfig -adD4 auto-revarp up
+ hostname=`/sbin/hostconfig -h -p bootparams`
+ done
+ trap 2 3 ;;
+ # /etc/nodename defaults to "unknown" on SmartOS
+ "none") hostname="`shcat /etc/nodename 2>/dev/null`"
+ if [ -z "$hostname" ]; then
+ if smf_is_globalzone; then
+ hostname=`/sbin/hostconfig -h -p bootparams`
+ else
+ hostname=`/sbin/uname -n`
+ fi
+ fi ;;
esac
+# Load sysinfo variables with SYSINFO_ prefix and config variables with
+# CONFIG_ prefix.
+# Note: since we're still starting up, "soft" values like network IP and such could
+# not be set yet.
+
+if smf_is_globalzone; then
+ . /lib/sdc/config.sh
+
+ load_sdc_sysinfo
+
+ if boot_file_config_enabled; then
+ load_boot_file_config
+ else
+ load_sdc_config
+ fi
+fi
+
#
# If the netstrategy was unsuccessful and we haven't got a locally configured
# name, default to "unknown"
#
-if [ -z "$hostname" ]; then
- hostname="`shcat /etc/nodename 2>/dev/null`"
- if [ -z "$hostname" ]; then
- hostname="unknown"
- fi
+if [ -z "$hostname" ] || [ "$hostname" == "unknown" ]; then
+ hostname="`shcat /etc/nodename 2>/dev/null`"
+ if [ -z "$hostname" ] || [ "$hostname" == "unknown" ]; then
+ if smf_is_globalzone; then
+ set_gz_hostname
+ else
+ hostname="unknown"
+ fi
+ fi
+fi
+
+if smf_is_globalzone; then
+ echo "$hostname" > /etc/nodename
fi
/sbin/uname -S $hostname
-echo "Hostname: `/sbin/uname -n`" > /dev/msglog
+# Reloading sysinfo here serves two purposes:
+# - getting the IP info (which should exist now)
+# - updating the host info (which we just set)
+eval $(/usr/bin/sysinfo -f -p | sed -e "s/^/SYSINFO_/")
+
+# Try to add the /etc/hosts entry if we can find an IP
+if [[ -n ${SYSINFO_NIC_admin} ]]; then
+ eval "ipaddr=\${SYSINFO_Network_Interface_${SYSINFO_NIC_admin}_IPv4_Address}"
+fi
+if [[ -z ${ipaddr} ]]; then
+ ipaddr=$(set | grep "^SYSINFO_Network_Interface_.*_IPv4_Address" | head -n1 | cut -d'=' -f2)
+fi
+if [[ -n ${ipaddr} ]]; then
+ fullname=""
+
+ if [ -n "$CONFIG_dns_domain" ]; then
+ fullname=" ${hostname}.${CONFIG_dns_domain}"
+ fi
+
+ printf "${ipaddr}\t${hostname}${fullname}\n" >> /etc/hosts
+fi
# Reset the library path now that we are past the critical stage
unset LD_LIBRARY_PATH
diff --git a/usr/src/cmd/svc/milestone/joyent-fs.xml b/usr/src/cmd/svc/milestone/joyent-fs.xml
new file mode 100644
index 0000000000..f21eae27d8
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/joyent-fs.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:filesystem-joyent'>
+
+<service
+ name='system/filesystem/smartdc'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <single_instance/>
+
+ <dependency
+ name='usr'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/usr' />
+ </dependency>
+
+ <dependency
+ name='kbmd'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/kbmd:default' />
+ </dependency>
+
+ <!--
+ Start method timeout is infinite to handle potentially unbounded
+ fsck times.
+ -->
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/fs-joyent'
+ timeout_seconds='0' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':true'
+ timeout_seconds='0' />
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring' value='transient' />
+ </property_group>
+ <property_group name='joyentfs' type='application'>
+ <stability value='Evolving'/>
+ <propval name='debug' type='boolean' value='false'/>
+ <propval name='usb_copy_path' type='astring' value='/usbkey'/>
+ <propval name='usb_mountpoint' type='astring' value='usbkey'/>
+ </property_group>
+
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Joyent file system mounts
+ </loctext>
+ </common_name>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/milestone/make-console-login-xml b/usr/src/cmd/svc/milestone/make-console-login-xml
index a8e516fe9f..2b78164e78 100644
--- a/usr/src/cmd/svc/milestone/make-console-login-xml
+++ b/usr/src/cmd/svc/milestone/make-console-login-xml
@@ -24,6 +24,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
cat >console-login.xml <<EOF
<?xml version="1.0"?>
@@ -31,6 +33,8 @@ cat >console-login.xml <<EOF
Copyright 2008 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
+ Copyright 2015 Joyent, Inc.
+
NOTE: This service manifest is not editable; its contents will
be overwritten by package or patch operations, including
operating system upgrade. Make customizations in a different
@@ -125,14 +129,14 @@ cat >console-login.xml <<EOF
<property_group name='ttymon' type='application'>
<propval name='value_authorization' type='astring'
value='solaris.smf.value.vt' />
- <propval name='device' type='astring' value='/dev/console' />
+ <propval name='device' type='astring' value='/dev/wscons' />
<propval name='label' type='astring' value='console' />
<propval name='timeout' type='count' value='0' />
<propval name='nohangup' type='boolean' value='true' />
<propval name='modules' type='astring'
value='ldterm,ttcompat' />
<propval name='prompt' type='astring'
- value='\`uname -n\` console login:' />
+ value='\`uname -n\` wscons login:' />
<propval name='terminal_type' type='astring'
value='' />
</property_group>
@@ -140,8 +144,39 @@ cat >console-login.xml <<EOF
<instance name='default' enabled='true'>
</instance>
+EOF
+
+for tty in a b c d; do
+ cat >>console-login.xml <<EOF
+<instance name='tty$tty' enabled='true'>
+
+ <dependency
+ name='system-console'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/console-login:default' />
+ </dependency>
+
+ <!-- these are passed to ttymon in the method script -->
+ <property_group name='ttymon' type='application'>
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.vt' />
+ <propval name='device' type='astring' value='/dev/term/$tty' />
+ <propval name='label' type='astring' value='115200' />
+ <propval name='timeout' type='count' value='0' />
+ <propval name='nohangup' type='boolean' value='true' />
+ <propval name='modules' type='astring'
+ value='ldterm,ttcompat' />
+ <propval name='prompt' type='astring'
+ value='\`uname -n\` tty$tty login:' />
+ <propval name='terminal_type' type='astring'
+ value='xterm' />
+ </property_group>
+</instance>
EOF
+done
# Note that this script file is normally parsed during build by sh(1).
# When the parser encounters an EOF token (like the one above), it
@@ -328,7 +363,7 @@ Sets the initial value of the TERM environment variable
<visibility value='readwrite'/>
<cardinality min='1' max='1'/>
</prop_pattern>
- </pg_pattern>
+ </pg_pattern>
</template>
</service>
diff --git a/usr/src/cmd/svc/milestone/manifest-import b/usr/src/cmd/svc/milestone/manifest-import
index 81cd780583..43fb677b92 100644
--- a/usr/src/cmd/svc/milestone/manifest-import
+++ b/usr/src/cmd/svc/milestone/manifest-import
@@ -74,13 +74,17 @@ function svccfg_apply {
}
#
-# If the smf repository has file entries that are missing
+# If the smf/manifest table has file entries that are missing
# then there is work to be done by the cleanup process.
#
function cleanup_needwork {
- smfmfiles=`svcprop -p manifestfiles '*' 2>/dev/null |
- nawk -v early="$early" '$2 == "astring" &&
- (early != "true" || $3 ~ "^/lib/") { print $3 }'`
+ if [ "$early" == true ]; then
+ smfmfiles=`/usr/bin/svcprop smf/manifest | \
+ awk '(/^lib_/ && /\/manifestfile /) {print $3}'`
+ else
+ smfmfiles=`/usr/bin/svcprop smf/manifest | \
+ awk '/\/manifestfile / {print $3}'`
+ fi
nw=`/lib/svc/bin/mfstscan $smfmfiles 2>&1 1>/dev/null`
[ "$nw" ] && return 1
@@ -201,8 +205,13 @@ function import_manifests {
rm -f $logf
- nonsite_dirs=`/usr/bin/find $basedir/* -name site \
- -prune -o -type d -print -prune`
+ if [ "${basedir}" == "/opt/custom/smf" ]; then
+ # Special case where we will just import from the root, not subdirs
+ nonsite_dirs=${basedir}
+ else
+ nonsite_dirs=`/usr/bin/find $basedir/* -name site \
+ -prune -o -type d -print -prune`
+ fi
if [ -n "$_MFST_DEBUG" ]; then
nonsite_manifests=`/lib/svc/bin/mfstscan $nonsite_dirs`
@@ -454,6 +463,10 @@ else
import_manifests "/lib/svc/manifest" true
import_manifests "/var/svc/manifest" true
+ if [ -d "/opt/custom/smf" ]; then
+ import_manifests "/opt/custom/smf" true
+ fi
+
#
# Apply profiles
#
@@ -472,9 +485,9 @@ fi
# 6. Final actions.
#
-if $activity; then
- /usr/sbin/svcadm _smf_backup "manifest_import" || true
-fi
+#if $activity; then
+# /usr/sbin/svcadm _smf_backup "manifest_import" || true
+#fi
#
# If the filesystem is NOT read only then move the repo back to perm
diff --git a/usr/src/cmd/svc/milestone/mdata-execute b/usr/src/cmd/svc/milestone/mdata-execute
new file mode 100755
index 0000000000..fca08ffbc7
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/mdata-execute
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at http://smartos.org/CDDL
+#
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file.
+#
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+#
+
+set -o xtrace
+
+. /lib/svc/share/smf_include.sh
+smf_is_globalzone && exit ${SMF_EXIT_OK}
+
+# If we got as far as running the user-script the 'provision' was a success
+# from here out a failure will leave the zone running.
+if [ -f /var/svc/provisioning ]; then
+ mv /var/svc/provision{ing,_success}
+fi
+
+if [[ -x /var/svc/mdata-operator-script ]]; then
+ /var/svc/mdata-operator-script
+ operator_script_exit=$?
+ if [[ ${operator_script_exit} -gt 0 ]]; then
+ echo "WARNING: operator-script failed: exited ${operator_script_exit}" \
+ >&2
+ fi
+fi
+
+user_script_exit=${SMF_EXIT_OK}
+if [ -x /var/svc/mdata-user-script ]; then
+ /var/svc/mdata-user-script
+ [ $? -gt 0 ] && user_script_exit=${SMF_EXIT_ERR_FATAL}
+fi
+
+exit ${user_script_exit}
diff --git a/usr/src/cmd/svc/milestone/mdata-fetch b/usr/src/cmd/svc/milestone/mdata-fetch
new file mode 100755
index 0000000000..cb7222f445
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/mdata-fetch
@@ -0,0 +1,477 @@
+#!/usr/bin/bash
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at http://smartos.org/CDDL
+#
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file.
+#
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2017, Joyent, Inc. All rights reserved.
+#
+
+export PS4='[\D{%FT%TZ}] ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+export PATH=/usr/bin:/usr/sbin:$PATH
+
+set -o xtrace
+
+. /lib/svc/share/smf_include.sh
+smf_is_globalzone && exit ${SMF_EXIT_OK}
+
+if [ ! -x /usr/sbin/mdata-get ]; then
+ echo "Metadata mdata-get tool not found."
+ exit ${SMF_EXIT_ERR_FATAL}
+fi
+
+function fatal() {
+ if [[ -n $1 ]]; then
+ echo "FATAL: $*" >&2
+ fi
+ exit ${SMF_EXIT_ERR_FATAL}
+}
+
+# Test if an address looks like an IPv4 address.
+function isIPv4() {
+ [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]
+}
+
+# Test if an address looks like an IPv4 address + CIDR.
+function isIPv4AndCIDR() {
+ [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$ ]]
+}
+
+# Test if an address looks like an IPv6 address.
+function isIPv6() {
+ [[ "$1" =~ ^[0-9a-f]*:[0-9a-f]*:[:0-9a-f]*$ ]]
+}
+
+# Test if an address looks like an IPv6 address + CIDR.
+function isIPv6AndCIDR() {
+ [[ "$1" =~ ^[0-9a-f]*:[0-9a-f]*:[:0-9a-f]*/[0-9]{1,3}$ ]]
+}
+
+# For old zones that were created prior to OS-2253 and bumping the mdata:fetch
+# start timeout, we need to fix this otherwise we could timeout waiting for the
+# socket.
+cur_timeout=$(svcprop -p start/timeout_seconds svc:/smartdc/mdata:fetch)
+if [[ -z ${cur_timeout} || ${cur_timeout} -lt 1800 ]]; then
+ # The current manifest has an old timeout value, fix in case we timeout
+ # here. XXX we can still hit OS-2296 here where smf will forget that we
+ # set this.
+ svccfg -s svc:/smartdc/mdata:fetch 'setprop start/timeout_seconds = 1800'
+ svcadm refresh svc:/smartdc/mdata:fetch
+fi
+
+# This waits until /.zonecontrol/metadata.sock exists then exits 0
+/usr/vm/sbin/filewait /.zonecontrol/metadata.sock
+
+if [[ ! -e /.zonecontrol/metadata.sock ]]; then
+ # this is a bug since filewait should not have returned until file existed.
+ fatal "missing /.zonecontrol/metadata.sock, Unable to start mdata:fetch"
+fi
+
+# Update sysinfo to ensure values that come from metadata are populated.
+/usr/bin/sysinfo -fu
+
+echo "Retrieving metadata user-data"
+/usr/sbin/mdata-get user-data >/var/db/mdata-user-data.new
+case $? in
+ 0)
+ echo "Metadata user-data successfuly retrieved."
+ mv /var/db/mdata-user-data{.new,}
+ ;;
+ 1)
+ echo "Metadata user-data not defined."
+ rm -f /var/db/mdata-user-data{,.new}
+ ;;
+ *)
+ echo "Metadata couldn't be retrieved."
+ exit ${SMF_EXIT_ERR_FATAL}
+ ;;
+esac
+
+echo "Retrieving metadata user-script..."
+/usr/sbin/mdata-get user-script >/var/svc/mdata-user-script.new
+case $? in
+ 0)
+ echo "Metadata user-script successfuly retrieved."
+ mv /var/svc/mdata-user-script{.new,}
+ chmod +x /var/svc/mdata-user-script
+ ;;
+ 1)
+ echo "Metadata user-script not defined."
+ rm -f /var/svc/mdata-user-script{,.new}
+ ;;
+ *)
+ echo "Metadata couldn't be retrieved."
+ exit ${SMF_EXIT_ERR_FATAL}
+ ;;
+esac
+
+echo "Retrieving metadata operator-script..."
+/usr/sbin/mdata-get sdc:operator-script >/var/svc/mdata-operator-script.new
+case $? in
+ 0)
+ echo "Metadata operator-script successfuly retrieved."
+ mv /var/svc/mdata-operator-script{.new,}
+ chmod +x /var/svc/mdata-operator-script
+ ;;
+ 1)
+ echo "Metadata operator-script not defined."
+ rm -f /var/svc/mdata-operator-script{,.new}
+ ;;
+ *)
+ echo "Metadata couldn't be retrieved."
+ exit ${SMF_EXIT_ERR_FATAL}
+ ;;
+esac
+
+echo "Retrieving tmpfs value..."
+tmpfs=$(/usr/sbin/mdata-get sdc:tmpfs)
+if [[ $? == 0 && -n ${tmpfs} && -f /etc/vfstab ]]; then
+ check="swap - /tmp tmpfs";
+
+ if [[ ${tmpfs} == "0" ]]; then
+ # When tmpfs is set 0, we remove any entry from /etc/vfstab but cannot
+ # adjust the "live" value as current /tmp will be in-use. On reboot the
+ # new value will take effect.
+
+ grep -v "^${check}" /etc/vfstab > /etc/vfstab.new \
+ && mv /etc/vfstab.new /etc/vfstab
+ else
+ new="swap - /tmp tmpfs - yes size=${tmpfs}m";
+ if ! /usr/bin/grep "^${new}" /etc/vfstab; then
+ if ! /usr/bin/grep "^${check}" /etc/vfstab; then
+ # no tmpfs line. add it.
+ echo "${new}" >> /etc/vfstab
+ else
+ # existing tmpfs line, but wrong value. fix it.
+ /usr/bin/sed -i "" -e "s|^swap.*/tmp.*tmpfs.*$|${new}|" /etc/vfstab
+ echo $?
+ fi
+
+ if mount | grep "^/tmp"; then
+ # Also fix current size, since /etc/vfstab didn't have our correct line
+ # but only if we have /tmp mounted at all. If not, we'll have to wait
+ # until the next reboot since /tmp will be in-use.
+ /usr/sbin/mount -F tmpfs -o remount,size=${tmpfs}m /tmp
+ fi
+
+ fi
+ fi
+fi
+
+#
+# If we have NFS volumes, we'll add them to vfstab, and enable the nfs/client
+# service so that will mount the volumes for us.
+#
+echo "Retrieving volume metadata..."
+
+volumes_added=0
+while IFS="|" read -r nfsvolume mountpoint name mode type; do
+
+ cat >&2 <<EOF
+*** VOLUME ***
+NFSVOLUME: ${nfsvolume}
+MOUNTPOINT: ${mountpoint}
+MODE: ${mode}
+NAME: ${name}
+TYPE: ${type}
+EOF
+
+ if [[ -n ${type} && ${type} != "tritonnfs" ]]; then
+ fatal "unsupported volume type: ${type}"
+ fi
+
+ # if we don't have volume and mountpoint, we can't add vfstab lines
+ if [[ -z ${nfsvolume} || -z ${mountpoint} ]]; then
+ fatal "invalid volume specification (need both volume & mountpoint)"
+ fi
+
+ if ! grep "^${nfsvolume}[ ]" /etc/vfstab; then
+ if [[ -z ${mode} ]]; then
+ mode="rw"
+ fi
+
+ if [[ ${mode} != "rw" && ${mode} != "ro" ]]; then
+ fatal "invalid volume mode: '${mode}'"
+ fi
+
+ line=$(printf "%s - %s nfs - yes %s\n" "${nfsvolume}" "${mountpoint}" "${mode}")
+ volumes_added=$((${volumes_added}+1))
+
+ mkdir -p ${mountpoint}
+ echo "${line}" >> /etc/vfstab
+ fi
+done < <(/usr/sbin/mdata-get sdc:volumes \
+ | /usr/bin/json \
+ -d '|' \
+ -a nfsvolume mountpoint name mode type)
+
+if [[ ${volumes_added} -gt 0 ]]; then
+ for svc in \
+ svc:/network/nfs/nlockmgr:default \
+ svc:/network/nfs/status:default \
+ svc:/network/rpc/bind:default \
+ svc:/network/nfs/client:default \
+ ; do
+
+ svcadm enable ${svc} || fatal "Unable to enable ${svc}"
+ done
+fi
+
+# We use the special sdc:nics value here though this is not an interface for
+# use elsewhere. If this is changed please also update agent.js in the metadata
+# agent.
+#
+# We run this every startup in case nics have changed since last boot. As
+# network/physical has an optional_all dependency on this service, we'll have
+# had our chance to write these files out before networking comes up. This
+# might eventually be replaced by network/physical grabbing data directly.
+echo "Retrieving nics data..."
+while IFS="|" read -r iface ip ips netmask primary gateway gateways; do
+
+ # if we don't have interface name, we don't know what files to write out.
+ if [[ -z ${iface} ]]; then
+ continue;
+ fi
+
+ # A VM created on an older platform may not have the "ips" or "gateways"
+ # properties, so we will need to grab the older "ip" and "gateway" versions
+ # instead.
+ [[ -z $ips ]] && ips=$ip
+ [[ -z $gateways ]] && gateways=$gateway
+
+ # We remove the hostname.netX file first, so we can append to a clean file
+ rm -f /etc/hostname.${iface}
+
+ # remove any existing DHCP or addrconf configuration, since we'll create one
+ # if it belongs later
+ rm -f /etc/dhcp.${iface}
+ rm -f /etc/addrconf.${iface}
+
+ OLDIFS=$IFS
+ IFS=$','
+ for ip in $ips; do
+ # so it shows up in the logs
+ echo "iface[${iface}] ip[${ip}] netmask[${netmask}]" \
+ "primary[${primary}] gateway[${gateway}]"
+
+ [[ -z ${ip} ]] && continue;
+
+ if [[ ${ip} == "dhcp" ]]; then
+ touch /etc/dhcp.${iface}
+ if hostname=`mdata-get sdc:hostname`; then
+ echo "inet ${hostname}" >> /etc/hostname.${iface}
+ fi
+ elif [[ ${ip} == "addrconf" ]]; then
+ touch /etc/addrconf.${iface}
+ elif isIPv4 ${ip} && [[ -n ${netmask} ]]; then
+ # We're using an older configuration where the routing prefix is
+ # specified using a mask instead of CIDR notation. We'll need to
+ # invoke ifconfig differently.
+ echo "${ip} netmask ${netmask} up" >> /etc/hostname.${iface}
+ elif isIPv4AndCIDR ${ip} \
+ || isIPv6AndCIDR ${ip} \
+ || isIPv6 ${ip}; then
+ # Either a routing prefix was specified, or, in the case of IPv6, we
+ # won't specify one and fall back on NDP to find it when we configure
+ # our interfaces.
+ echo "${ip} up" >> /etc/hostname.${iface}
+ fi
+ done
+
+ if [[ ${primary} == "true" ]]; then
+ rm -f /etc/defaultrouter
+ for gateway in $gateways; do
+ if [[ -n ${gateway} ]] && isIPv4 ${gateway}; then
+ echo "${gateway}" >> /etc/defaultrouter
+ fi
+ done
+ fi
+ IFS=$OLDIFS
+
+ # XXX we leave old hostname.netX files around and just replace when we have
+ # one next.
+done < <(/usr/sbin/mdata-get sdc:nics \
+ | /usr/bin/json \
+ -d '|' \
+ -e 'this.ips = this.ips ? this.ips.join(",") : ""' \
+ -e 'this.gateways = this.gateways ? this.gateways.join(",") : ""' \
+ -a interface ip ips netmask primary gateway gateways)
+
+# rebuild resolv.conf
+resolvers=$(mdata-get sdc:resolvers)
+resolvers_result=$?
+
+# Determine if resolv.conf is managed for us
+maintain_resolvers=$(mdata-get sdc:maintain_resolvers)
+maintain_result=$?
+if [[ ${maintain_result} != 0 ]]; then
+ echo "Error getting maintain_resolvers, code: ${maintain_result}"
+ maintain_resolvers="false"
+fi
+
+# If this is our first boot, write an initial set of resolvers
+if [[ -f /var/svc/provisioning ]]; then
+ echo "First boot: writing resolvers"
+ maintain_resolvers="true"
+fi
+
+if [[ ${resolvers_result} == 0 && ${maintain_resolvers} == "true" ]]; then
+
+ # if dns_domain is missing or broken, we still write out, just w/o search
+ search="search $(mdata-get sdc:dns_domain)"
+ if [[ $? != 0 ]]; then
+ search=
+ fi
+
+ if [[ ${resolvers} == "[]" ]]; then
+ nameservers=
+ else
+ nameservers=$(echo ${resolvers} | json -a | sed -e "s/^/nameserver /")
+ fi
+
+ rm -f /etc/.resolv.conf.tmp
+ if [[ -n ${search} ]]; then
+ echo "${search}" > /etc/.resolv.conf.tmp
+ fi
+ if [[ -n ${nameservers} ]]; then
+ echo "${nameservers}" >> /etc/.resolv.conf.tmp
+ fi
+
+ cp /etc/.resolv.conf.tmp /etc/resolv.conf \
+ && cat /etc/.resolv.conf.tmp >&2 \
+ && rm -f /etc/.resolv.conf.tmp
+else
+ if [[ ${resolvers_result} == 0 ]]; then
+ echo "Error getting resolvers, code: ${resolvers_result}"
+ fi
+
+ if [[ ${maintain_resolvers} == "true" ]]; then
+ echo "Not setting resolvers, maintain_resolvers=${maintain_resolvers}"
+ fi
+fi
+
+
+# Fetch routes
+
+# It is possible to specify the same route in several different ways using
+# route(1m). We therefore use route(1m) itself to manage adding, deleting
+# and determining duplicates.
+zone_routes_file=/etc/inet/static_routes
+vmadm_routes_file=/etc/inet/static_routes.vmadm
+tmpdir=$(mktemp -d /tmp/mdata.XXXXXX)
+
+if [ -z $tmpdir ]; then
+ echo "Error creating temporary directory."
+ exit ${SMF_EXIT_ERR_FATAL}
+fi
+
+# directory structure for the new copy of static_routes.vmadm (the one that
+# will replace the current static_routes.vmadm once all of the adds and
+# deletes have been applied):
+new_root=${tmpdir}/new-routes
+new_inet=${new_root}/etc/inet
+# directory structure for the previous copy of static_routes.vmadm (used to
+# determine routes that have been removed since the last time mdata-fetch
+# was run):
+old_root=${tmpdir}/old-routes
+old_inet=${old_root}/etc/inet
+# directory structure for the zone's persistent routes - those not created
+# by vmadm (used to determine if vmadm routes are duplicates):
+zone_root=${tmpdir}/zone-routes
+zone_inet=${zone_root}/etc/inet
+
+mkdir -p $new_inet
+mkdir -p ${old_root}/etc/inet
+mkdir -p ${zone_root}/etc/inet
+
+if [[ -f ${vmadm_routes_file} ]]; then
+ cp $vmadm_routes_file ${old_inet}/static_routes
+fi
+
+function route_in_per_zone_file()
+{
+ cp $zone_routes_file $zone_inet
+ output=$(route -pR $zone_root add $* 2>&1)
+ [[ $output =~ "entry exists" ]]
+}
+
+# If re-running this script after initial boot, network/physical and
+# network/routing-setup are already enabled, so apply routing adds and
+# deletes manually
+if [[ $(/usr/bin/svcs -H -o state network/routing-setup) == "online" ]]; then
+ routing_up="true"
+fi
+
+while IFS="|" read -r gateway dst linklocal; do
+ echo "route: gateway[${gateway}] dst[${dst}] linklocal[${linklocal}]"
+ route_type=""
+ if [[ ${linklocal} == "true" ]]; then
+ route_type="-interface "
+ fi
+ route_str="${route_type}${dst} ${gateway}"
+
+ if route_in_per_zone_file $route_str; then
+ echo "not adding duplicate route: ${route_str}"
+ # the zone has also defined this route; do nothing
+ else
+ echo "adding route to file: ${route_str}"
+ route -pR $new_root add $route_str
+ if [[ -n "${routing_up}" ]]; then
+ route add $route_str
+ fi
+ fi
+
+ route -pR $old_root delete $route_str
+done < <(/usr/sbin/mdata-get sdc:routes \
+ | /usr/bin/json -d '|' -a gateway dst linklocal)
+
+
+# Anything left in the old static_routes file is a delete. Don't delete the
+# route from the routing tables if there's a duplicate route in the zone's
+# static_routes file
+if [[ -f ${old_inet}/static_routes ]]; then
+ egrep -v "^(#|$)" ${old_inet}/static_routes | while read -r route_str; do
+ if [[ "${route_str}" == "" ]]; then
+ continue
+ fi
+
+ if route_in_per_zone_file "$route_str"; then
+ echo "not deleting duplicate route: ${route_str}"
+ else
+ if [[ -n "${routing_up}" ]]; then
+ route delete $route_str
+ fi
+ fi
+ done
+fi
+
+if [[ -f ${new_inet}/static_routes ]]; then
+ cp ${new_inet}/static_routes ${vmadm_routes_file}
+else
+ rm ${vmadm_routes_file}
+fi
+rm -rf $tmpdir
+
+
+# Unconditionally enable mdata:execute, so that the last provisioning step
+# is always taken (regardless of whether user-script exists or not)
+svcadm enable smartdc/mdata:execute
+
+exit ${SMF_EXIT_OK}
diff --git a/usr/src/cmd/svc/milestone/mdata.xml b/usr/src/cmd/svc/milestone/mdata.xml
new file mode 100644
index 0000000000..152a7cb485
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/mdata.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<service_bundle type="manifest" name="mdata">
+ <service name="smartdc/mdata" type="service" version="1">
+ <dependency name="filesystem" grouping="require_all" restart_on="error" type="service">
+ <service_fmri value="svc:/system/filesystem/minimal" />
+ </dependency>
+ <property_group name="startd" type="framework">
+ <propval name="duration" type="astring" value="transient" />
+ <propval name="ignore_error" type="astring" value="core,signal" />
+ </property_group>
+ <instance name="fetch" enabled="true">
+ <dependency name="boot-file" grouping="exclude_all" restart_on="refresh" type="path">
+ <service_fmri value="file://localhost/tmp/.FIRST_REBOOT_NOT_YET_COMPLETE"/>
+ </dependency>
+ <dependency name="rmtmpfiles" grouping="optional_all" restart_on="error" type="service">
+ <service_fmri value="svc:/system/rmtmpfiles" />
+ </dependency>
+ <exec_method type="method" name="start" exec="/lib/svc/method/mdata-fetch" timeout_seconds="1800" />
+ <exec_method type="method" name="stop" exec=":true" timeout_seconds="60" />
+ </instance>
+ <instance name="execute" enabled="false">
+ <dependency name="network" grouping="require_all" restart_on="error" type="service">
+ <service_fmri value="svc:/milestone/multi-user:default" />
+ </dependency>
+ <dependency name="mdata" grouping="require_all" restart_on="error" type="service">
+ <service_fmri value="svc:/smartdc/mdata:fetch" />
+ </dependency>
+ <exec_method type="method" name="start" exec="/lib/svc/method/mdata-execute" timeout_seconds="300" />
+ <exec_method type="method" name="stop" exec=":true" timeout_seconds="60" />
+ </instance>
+ <stability value="Evolving" />
+ <template>
+ <common_name>
+ <loctext xml:lang="C">Joyent SDC metadata handler</loctext>
+ </common_name>
+ </template>
+ </service>
+</service_bundle>
diff --git a/usr/src/cmd/svc/milestone/minimal-fs.xml b/usr/src/cmd/svc/milestone/minimal-fs.xml
index b7af22bfcd..844760baa1 100644
--- a/usr/src/cmd/svc/milestone/minimal-fs.xml
+++ b/usr/src/cmd/svc/milestone/minimal-fs.xml
@@ -44,11 +44,11 @@
<single_instance/>
<dependency
- name='usr'
+ name='joyent'
grouping='require_all'
restart_on='none'
type='service'>
- <service_fmri value='svc:/system/filesystem/usr' />
+ <service_fmri value='svc:/system/filesystem/smartdc' />
</dependency>
<dependency
diff --git a/usr/src/cmd/svc/milestone/net-early-admin b/usr/src/cmd/svc/milestone/net-early-admin
new file mode 100644
index 0000000000..cda730f81e
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/net-early-admin
@@ -0,0 +1,237 @@
+#!/bin/ksh93
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+# Traditionally, when a Triton compute node boots, the network is not
+# configured until after the local filesystems are mounted (in fact
+# network/physical:default depends upon /system/filesystem/smartdc). Most
+# obviously, in the case of a head node or a standalone SmartOS install, the
+# network configuration is stored on the local zpool, so the network cannot
+# be configured until this happens.
+#
+# For Triton compute nodes with encrypted zpools, we must enable the admin
+# network before the local zpool filesytems are online -- we have to be able
+# to communicate to the head node services to obtain the pin to unlock the
+# local zpool. For PXE booted Triton compute nodes, we therefore configure
+# the admin network sooner via the network/early-admin:default service. When
+# network/physical:default runs, it will skip the configuration of the admin
+# network and configuring the remaining interfaces.
+#
+# If we are not a Triton compute node, we exit successfully almost immediately
+# without configuring the admin network. When the network/physical:default
+# service runs, it will configure all the network interfaces as it traditionally
+# has
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+. /lib/svc/share/smf_include.sh
+. /lib/sdc/config.sh
+. /lib/sdc/network.sh
+
+PS4='+ [$LINENO] '
+
+set -o xtrace
+
+if ! smf_is_globalzone; then
+ echo "Non-global zone; no action required; exiting"
+ exit $SMT_EXIT_OK
+fi
+
+if ! boot_file_config_enabled; then
+ echo "Boot-time networking files not present; exiting"
+ exit $SMF_EXIT_OK
+fi
+
+function fatal
+{
+ # XXX: For SMF methods, does it matter/better to redirect to stderr?
+ echo "Error: $*" >&2
+ exit $SMF_EXIT_ERR_FATAL
+}
+
+if ! boot_file_config_valid; then
+ echo "ERROR: boot-time network config file incorrect" >&2
+ exit $SMF_EXIT_ERR_CONFIG
+fi
+
+unset aggrs
+unset tags
+typeset -A tagv
+typeset -A aggr_links aggr_mode
+typeset -A ip ip6 netmask gateway gateway6 mtu mac
+/usr/lib/sdc/net-boot-config | while IFS="=" read var value; do
+ if [[ "$var" =~ _nic$ ]]; then
+ name=${var%_nic}
+ tags+=("${name}")
+ tagv[$name]="$value"
+ elif [[ "$var" =~ _aggr$ ]]; then
+ name=${var%_aggr}
+ aggrs+=(${name})
+ aggr_links[$name]="${value//,/ }"
+ elif [[ "$var" =~ _lacp_mode$ ]]; then
+ name=${var%_lacp_mode}
+ aggr_mode[$name]="$value"
+ elif [[ "$var" =~ _mtu$ ]]; then
+ (( value < 1500 || value > 9000 )) &&
+ fatal "ERROR: $var MTU value \'$value\' is not in" \
+ "range [1500, 9000]"
+
+ name=${var%_mtu}
+ mtu[$name]="$value"
+ elif [[ "$var" =~ _ip$ ]]; then
+ name=${var%_ip}
+ ip[$name]="$value"
+ elif [[ "$var" =~ _ip6$ ]]; then
+ name=${var%_ip6}
+ ip6[$name]="$value"
+ elif [[ "$var" =~ _netmask$ ]]; then
+ name=${var%_netmask}
+ netmask[$name]="$value"
+ elif [[ "$var" =~ _gateway$ ]]; then
+ name=${var%_gateway}
+ gateway[$name]="$value"
+ elif [[ "$var" =~ _gateway6$ ]]; then
+ name=${var%_gateway6}
+ gateway6[$name]="$value"
+ elif [[ "$var" =~ _mac$ ]]; then
+ name=${var%_mac}
+ mac[$name]="$value"
+ elif [[ "$var" == "dns_resolvers" ]]; then
+ dns_resolvers=(${value//,/ })
+ fi
+
+ eval "CONFIG_$var"="$value"
+done
+
+# This must happen befor any other dladm commands (which includes log_if_state)
+# or else dladm commands can fail
+dladm init-phys
+
+log_if_state before
+
+typeset -A mac_to_link
+out=$(dladm show-phys -mpo link,address)
+(( $? == 0 )) || fatal "dladm show-phys failed"
+while IFS=: read link addr; do
+ macaddr=$(normalize_mac $addr)
+ mac_to_link["$macaddr"]="$link"
+done <<< "$out"
+
+ADMIN_NIC_TAG=${CONFIG_admin_tag:-"admin"}
+[[ -n "${tagv[$ADMIN_NIC_TAG]}" ]] || \
+ fatal "ERROR: admin nic tag '$ADMIN_NIC_TAG' not present"
+
+nic="${tagv[$ADMIN_NIC_TAG]}"
+
+if [[ -n "${aggr_links[$nic]}" ]]; then
+ mode=${aggr_mode[$nic]:-"off"}
+
+ for l in ${aggr_links[$nic]}; do
+ [[ -n "${mac_to_link[$l]}" ]] || fatal "MAC '$l' not present"
+ links+="${mac_to_link[$l]} "
+ done
+ links="${links% }"
+
+ echo "Creating aggr: $nic (mode=$mode, links=${links})"
+ dladm create-aggr -l ${links// / -l } -L $mode $nic
+elif valid_mac "$nic"; then
+ [[ -n "${mac_to_link[$nic]}" ]] || \
+ fatal "ERROR: admin mac address $nic not found on system"
+ nic=${mac_to_link[$nic]}
+else
+ fatal "ERROR: Invalid value of ${ADMIN_NIC_TAG}_nic ($nic)"
+fi
+
+# If there are other nic tags configured on the same link as
+# the admin tag, find the largest MTU to use to set the
+# datalink MTU
+dlmtu="${mtu[$ADMIN_NIC_TAG]}"
+for tag in ${tags[@]}; do
+ tagmac="${tagv[$tag]}"
+
+ # If the 'mac' for the nic tag is actually an aggr, the
+ # tag will appear in $aggr_links (and we want to use that as
+ # the link name). If it is not an aggr, we need to map the
+ # MAC address to the link name so we can check if $tag
+ # resides on the same link as the admin interface
+ if [[ -n "${aggr_links[$tagmac]}" ]]; then
+ link="$tagmac"
+ else
+ link="${mac_to_link[$tagmac]}"
+ fi
+
+ if [[ "$link" == "$nic" && $dlmtu -lt ${mtu[$tag]} ]]; then
+ dlmtu=${mtu[$tag]}
+ fi
+done
+
+if [[ -n "$dlmtu" ]]; then
+ dladm set-linkprop -p mtu=$dlmtu $nic || \
+ fatal "ERROR: Failed to set mtu on aggr $nic to $dlmtu"
+fi
+
+driver=${nic%%[0-9]*}
+get_link_state $nic
+if [[ "$link_state" == "down" ]]; then
+ echo "admin nic '${nic}' is down: unplumbing"
+ /sbin/ifconfig $nic down unplumb
+ wait_for_nic_state $nic "unknown"
+fi
+
+# There's some sort of race condition in the bnx driver: if the plumb
+# command comes too soon after the unplumb, the interface can come up
+# in a state where it never fires interrupts for link state changes.
+if [[ "$driver" == "bnx" ]]; then
+ sleep 5
+fi
+
+/sbin/ifconfig $nic plumb mtu ${mtu[$ADMIN_NIC_TAG]}
+wait_for_nic_state $nic "up"
+
+if [[ -n "${ip[$ADMIN_NIC_TAG]}" ]]; then
+ /sbin/ifconfig $nic inet ${ip[$ADMIN_NIC_TAG]} \
+ netmask ${netmask[$ADMIN_NIC_TAG]:-"+"} up
+ [[ -n "${gateway[$ADMIN_NIC_TAG]}" ]] && \
+ /usr/sbin/route add default ${gateway[$ADMIN_NIC_TAG]}
+fi
+
+if [[ -n "${ip6[$ADMIN_NIC_TAG]}" ]]; then
+ /sbin/ifconfig $nic inet6 plumb mtu ${mtu[$ADMIN_NIC_TAG]}
+ [[ "${ip6[$ADMIN_NIC_TAG]}" != "addrconf" ]] && \
+ /sbin/ifconfig $nic inet6 addif ${ip6[$ADMIN_NIC_TAG]} preferred up
+ [[ -n "${gateway6[$ADMIN_NIC_TAG]}" ]] && \
+ /usr/sbin/route add -inet6 default ${gateway6[$ADMIN_NIC_TAG]}
+fi
+
+# Add just the routes reachable through the admin network -- usually these are
+# only present with rack aware networking (RAN)
+/usr/lib/sdc/net-boot-config --routes | while read dst gw; do
+ if ! ip_in_net $gw ${ip[$ADMIN_NIC_TAG]} ${netmask[$ADMIN_NIC_TAG]}; then
+ continue
+ fi
+ route add "$dst" "$gw"
+done
+
+if [[ -n "${CONFIG_dns_domain}" && -n ${dns_resolvers[0]} ]]; then
+ echo "search ${CONFIG_dns_domain}" > /etc/resolv.conf
+ for serv in ${dns_resolvers[@]}; do
+ echo "nameserver $serv" >> /etc/resolv.conf
+ done
+fi
+
+touch /etc/svc/volatile/.early_admin_setup
+
+log_if_state after
diff --git a/usr/src/cmd/svc/milestone/net-physical b/usr/src/cmd/svc/milestone/net-physical
index 89784dcbbc..90f6f7aff5 100644
--- a/usr/src/cmd/svc/milestone/net-physical
+++ b/usr/src/cmd/svc/milestone/net-physical
@@ -1,4 +1,4 @@
-#!/sbin/sh
+#!/usr/bin/ksh93
#
# CDDL HEADER START
#
@@ -19,527 +19,839 @@
#
# CDDL HEADER END
#
-#
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2012 Milan Jurik. All rights reserved.
+# Copyright 2019 Joyent, Inc.
#
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
# All rights reserved.
#
. /lib/svc/share/smf_include.sh
-. /lib/svc/share/net_include.sh
+. /lib/sdc/config.sh
+. /lib/sdc/network.sh
+
+set -o errexit
+set -o xtrace
#
# In a shared-IP zone we need this service to be up, but all of the work
-# it tries to do is irrelevant (and will actually lead to the service
-# failing if we try to do it), so just bail out.
+# it tries to do is irrelevant (and will actually lead to the service
+# failing if we try to do it), so just bail out.
# In the global zone and exclusive-IP zones we proceed.
#
-smf_configure_ip || exit $SMF_EXIT_OK
-
+smf_configure_ip || exit ${SMF_EXIT_OK}
# Make sure that the libraries essential to this stage of booting can be found.
LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH
+# Time (in seconds) to wait for admin NIC to get DHCP address before continuing.
+ADMIN_DHCP_TIMEOUT=300
+ActiveAggrLinks=
+typeset -A ActiveAggrLinks
+
smf_netstrategy
-if smf_is_globalzone; then
- net_reconfigure || exit $SMF_EXIT_ERR_CONFIG
-
- # Update PVID on interfaces configured with VLAN 1
- update_pvid
-
- #
- # Upgrade handling. The upgrade file consists of a series of dladm(1M)
- # commands. Note that after we are done, we cannot rename the upgrade
- # script file as the file system is still read-only at this point.
- # Defer this to the manifest-import service.
- #
- upgrade_script=/var/svc/profile/upgrade_datalink
- if [ -f "${upgrade_script}" ]; then
- . "${upgrade_script}"
- fi
-
- #
- # Upgrade handling for ibd:
- # After we are done with the upgrade handling, we can not set the
- # ibd/ibd_upgraded property to "true" as the file system is
- # read-only at this point. It will be done later by ibd-post-upgrade
- # service.
- #
- if [ -x /sbin/ibd_upgrade ]; then
- ibd_upgraded=`/bin/svcprop -c -p ibd/ibd_upgraded \
- $SMF_FMRI 2> /dev/null`
- if [ "$ibd_upgraded" != "true" ]; then
- /sbin/ibd_upgrade -v
- fi
- fi
-
- #
- # Bring up simnets, link aggregations and initialize security objects.
- # Note that link property initialization is deferred until after
- # IP interfaces are plumbed to ensure that the links will not
- # be unloaded (and the property settings lost). We should bring
- # up simnets prior to VLANs/Aggrs to enable creation of VLANs/Aggrs
- # over simnets.
- #
- /sbin/dladm up-simnet
- /sbin/dladm up-aggr
- /sbin/dladm up-vlan
- /sbin/dladm up-part
- /sbin/dladm init-secobj
- #
- # Bring up VNICs
- #
- /sbin/dladm up-vnic
- #
- # Create flows via flowadm.
- #
- /sbin/flowadm init-flow
-fi
+function add_active_aggr_links
+{
+ set -o xtrace
+ typeset alink
-#
-# If the system was net booted by DHCP, hand DHCP management off to the
-# DHCP agent (ifconfig communicates to the DHCP agent through the
-# loopback interface).
-#
-if [ -n "$_INIT_NET_IF" -a "$_INIT_NET_STRATEGY" = "dhcp" ]; then
- /sbin/dhcpagent -a
-fi
+ for alink in ${2//,/ }; do
+ ActiveAggrLinks[$alink]=$1
+ done
+}
-#
-# The network initialization is done early to support diskless and
-# dataless configurations. For IPv4 interfaces that were configured by
-# the kernel (e.g. those on diskless machines) and not configured by
-# DHCP, reset the netmask using the local "/etc/netmasks" file if one
-# exists, and then reset the broadcast address based on the netmask.
-#
-/sbin/ifconfig -auD4 netmask + broadcast +
+# Waits for up to 10 seconds for the link state to change to the given value
+function wait_for_admin_nic_state
+{
+ wait_for_nic_state "${SYSINFO_NIC_admin}" "$1"
+}
-is_iptun ()
+# Plumbs the admin interface, and attempts to work around poorly-behaved
+# drivers that can't handle plumb commands too quickly after one another
+function plumb_admin
{
- intf=$1
- # Is this a persistent IP tunnel link?
- /sbin/dladm show-iptun -P $intf > /dev/null 2>&1
- if [ $? -eq 0 ]; then
- return 0
- fi
- # Is this an implicit IP tunnel (i.e., ip.tun0)
- ORIGIFS="$IFS"
- IFS="$IFS."
- set -- $intf
- IFS="$ORIGIFS"
- if [ $# -eq 2 -a \( "$1" = "ip" -o "$1" = "ip6" \) ]; then
- #
- # It looks like one, but another type of link might be
- # using a name that looks like an implicit IP tunnel.
- # If dladm show-link -P finds it, then it's not an IP
- # tunnel.
- #
- /sbin/dladm show-link -Pp $intf > /dev/null 2>&1
- if [ $? -eq 0 ]; then
- return 1
- else
- return 0
- fi
- fi
- return 1
+ set -o xtrace
+ driver=${SYSINFO_NIC_admin%%[0-9]*}
+ get_link_state ${SYSINFO_NIC_admin}
+ if [[ "$link_state" == "down" ]]; then
+ echo "admin nic '${SYSINFO_NIC_admin}' is down: unplumbing"
+ /sbin/ifconfig ${SYSINFO_NIC_admin} down unplumb
+ wait_for_admin_nic_state "unknown"
+ fi
+
+ # There's some sort of race condition in the bnx driver: if the plumb
+ # command comes too soon after the unplumb, the interface can come up
+ # in a state where it never fires interrupts for link state changes.
+ if [[ "$driver" == "bnx" ]]; then
+ sleep 5
+ fi
+ /sbin/ifconfig ${SYSINFO_NIC_admin} plumb mtu ${CONFIG_admin_mtu:-1500}
+ wait_for_admin_nic_state "up"
}
-#
-# All the IPv4 and IPv6 interfaces are plumbed before doing any
-# interface configuration. This prevents errors from plumb failures
-# getting mixed in with the configured interface lists that the script
-# outputs.
-#
+# Creates, plumbs and brings up a vnic with the specified inet parameters
+function vnic_up
+{
+ set -o xtrace
+
+ typeset link="$1"
+ typeset iface="$2"
+ typeset ip="$3"
+ typeset netmask="$4"
+ typeset vlan_id="$5"
+ typeset mac_addr="$6"
+ typeset dhcp_primary="$7"
+ typeset mtu="$8"
+ typeset details=
+ typeset vlan_opt=
+ typeset mac_addr_opt=
+ typeset prop_opt=
+
+ details="link='${link}', iface='${iface}', ip='${ip}'"
+ details="${details}, netmask='${netmask}, vlan_id='${vlan_id}'"
+
+ if [[ -z ${link} ]] || [[ -z ${iface} ]] || \
+ [[ -z ${ip} ]] || ([[ ${ip} != "dhcp" ]] && [[ -z ${netmask} ]]); then
+ echo "WARNING: not bringing up nic (insufficient configuration): " \
+ "$details"
+ return
+ fi
+
+ eval "vnic_already_up=\${vnic_${iface}_up}"
+ if [[ -n "${vnic_already_up}" ]]; then
+ echo "vnic already up: $details"
+ return
+ fi
+
+ if [[ -n ${mac_addr} ]] && [[ -n ${ActiveAggrLinks[${mac_addr}]} ]]; then
+ echo "WARNING: trying to assign MAC address \"${mac_addr}\" to vnic," \
+ " but it already belongs to link aggr " \
+ "\"${ActiveAggrLinks[${mac_addr}]}\""
+ return
+ fi
+
+ echo "Bringing up nic: $details"
+
+ if [[ -n ${vlan_id} ]] && [[ ${vlan_id} != 0 ]]; then
+ vlan_opt="-v ${vlan_id}"
+ fi
+
+ if [[ -n ${mac_addr} ]]; then
+ mac_addr_opt="-m ${mac_addr}"
+ fi
+
+ if [[ -n ${mtu} ]]; then
+ valid_mtu ${iface} ${mtu}
+ prop_opt="-p mtu=${mtu}"
+ fi
+
+ /usr/sbin/dladm create-vnic -t -l ${link} ${prop_opt} ${vlan_opt} \
+ ${mac_addr_opt} ${iface}
+ if [[ $? -ne 0 ]]; then
+ echo "Failed to create VNIC ${iface}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+
+ /sbin/ifconfig ${iface} plumb
+ if [[ $? -ne 0 ]]; then
+ echo "Failed to plumb ${iface}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+
+ if [[ ${ip} == "dhcp" ]]; then
+ # We ignore errors here because the most common one is that DHCP
+ # is already running.
+
+ if [[ -n ${dhcp_primary} ]]; then
+ /sbin/ifconfig ${iface} dhcp primary || /bin/true
+ else
+ /sbin/ifconfig ${iface} dhcp || /bin/true
+ fi
+ else
+ /sbin/ifconfig ${iface} inet ${ip} netmask ${netmask} up
+ fi
+ eval "vnic_${iface}_up=true"
+}
-#
-# First deal with /etc/hostname
-#
-# Get the list of IPv4 interfaces to configure by breaking
-# /etc/hostname.* into separate args by using "." as a shell separator
-# character.
-#
-interface_names="`echo /etc/hostname.*[0-9] 2>/dev/null`"
-if [ "$interface_names" != "/etc/hostname.*[0-9]" ]; then
- ORIGIFS="$IFS"
- IFS="$IFS."
- set -- $interface_names
- IFS="$ORIGIFS"
- while [ $# -ge 2 ]; do
- shift
- intf_name=$1
- while [ $# -gt 1 -a "$2" != "/etc/hostname" ]; do
- intf_name="$intf_name.$2"
- shift
- done
- shift
-
- # skip IP tunnel interfaces plumbed by net-iptun.
- if is_iptun $intf_name; then
- continue
- fi
-
- read one rest < /etc/hostname.$intf_name
- if [ "$one" = ipmp ]; then
- ipmp_list="$ipmp_list $intf_name"
- else
- inet_list="$inet_list $intf_name"
- fi
- done
-fi
+# Creates, plumbs and brings up a vnic with the specified inet6 parameters
+function vnic_up6
+{
+ set -o xtrace
+
+ typeset link="$1"
+ typeset iface="$2"
+ typeset ip="$3"
+ typeset vlan_id="$4"
+ typeset mac_addr="$5"
+ typeset mtu="$6"
+ typeset details=
+ typeset vlan_opt=
+ typeset mac_addr_opt=
+ typeset prop_opt=
+
+ details="link='${link}', iface='${iface}', ip6='${ip}'"
+ details="${details}, vlan_id='${vlan_id}'"
+
+ if [[ -z ${link} ]] || [[ -z ${iface} ]] || [[ -z ${ip} ]]; then
+ echo "WARNING: not bringing up nic (insufficient configuration): " \
+ "$details"
+ return
+ fi
+
+ if [[ -n ${mac_addr} ]] && [[ -n ${ActiveAggrLinks[${mac_addr}]} ]]; then
+ echo "WARNING: trying to assign MAC address \"${mac_addr}\" to vnic," \
+ " but it already belongs to link aggr " \
+ "\"${ActiveAggrLinks[${mac_addr}]}\""
+ return
+ fi
+
+ # only bring up nic if not already up
+ eval "vnic_already_up=\${vnic_${iface}_up}"
+ if [[ -z "${vnic_already_up}" ]]; then
+ echo "Bringing up nic: $details"
+
+ if [[ -n ${vlan_id} ]] && [[ ${vlan_id} != 0 ]]; then
+ vlan_opt="-v ${vlan_id}"
+ fi
+
+ if [[ -n ${mac_addr} ]]; then
+ mac_addr_opt="-m ${mac_addr}"
+ fi
+
+ if [[ -n ${mtu} ]]; then
+ valid_mtu ${iface} ${mtu}
+ prop_opt="-p mtu=${mtu}"
+ fi
+
+ /usr/sbin/dladm create-vnic -t -l ${link} ${prop_opt} ${vlan_opt} \
+ ${mac_addr_opt} ${iface}
+ if [[ $? -ne 0 ]]; then
+ echo "Failed to create VNIC ${iface}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+ fi
+
+ /sbin/ifconfig ${iface} inet6 plumb
+ if [[ $? -ne 0 ]]; then
+ echo "Failed to plumb ${iface}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+
+ if [[ -n ${ip} ]]; then
+ /sbin/ifconfig ${iface} inet6 up
+ fi
+ if [[ ${ip} != "addrconf" ]]; then
+ /sbin/ifconfig ${iface} inet6 \
+ addif ${ip} preferred up
+ fi
+ eval "vnic_${iface}_up=true"
+}
-#
-# Get the list of IPv6 interfaces to configure by breaking
-# /etc/hostname6.* into separate args by using "." as a shell separator
-# character.
-#
-interface_names="`echo /etc/hostname6.*[0-9] 2>/dev/null`"
-if [ "$interface_names" != "/etc/hostname6.*[0-9]" ]; then
- ORIGIFS="$IFS"
- IFS="$IFS."
- set -- $interface_names
- IFS="$ORIGIFS"
- while [ $# -ge 2 ]; do
- shift
- intf_name=$1
- while [ $# -gt 1 -a "$2" != "/etc/hostname6" ]; do
- intf_name="$intf_name.$2"
- shift
- done
- shift
-
- # skip IP tunnel interfaces plumbed by net-iptun.
- if is_iptun $intf_name; then
- continue
- fi
-
- read one rest < /etc/hostname6.$intf_name
- if [ "$one" = ipmp ]; then
- ipmp6_list="$ipmp6_list $intf_name"
- else
- inet6_list="$inet6_list $intf_name"
- fi
- done
-fi
+# If there are aggregations in sysinfo, set them up.
+function create_aggrs
+{
+ set -o xtrace
+ typeset links macs mode mtu
+ if [[ -z "${SYSINFO_Aggregations}" ]]; then
+ return 0
+ fi
+
+ aggrs=(${SYSINFO_Aggregations//,/ })
+ for aggr in "${aggrs[@]}"; do
+ eval "links=\${SYSINFO_Aggregation_${aggr}_Interfaces}"
+ eval "macs=\${SYSINFO_Aggregation_${aggr}_MACs}"
+ eval "mode=\${SYSINFO_Aggregation_${aggr}_LACP_mode}"
+ eval "mtu=\${CONFIG_${aggr}_mtu}"
+ [[ -z "$mode" ]] && mode="off"
+
+ echo "Creating aggr: ${aggr} (mode=${mode}, links=${links})"
+ dladm create-aggr -l ${links//,/ -l } -L ${mode} ${aggr}
+ if [[ $? -eq 0 ]]; then
+ add_active_aggr_links ${aggr} ${macs}
+ fi
+
+ if [[ -n "$mtu" ]]; then
+ dladm set-linkprop -p mtu=${mtu} ${aggr}
+ if [[ $? -ne 0 ]]; then
+ echo "Failed to set mtu on aggr ${aggr} to ${mtu}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+ fi
+ done
+
+ # Creating the aggregations may affect the nic tags in sysinfo, so update:
+ /usr/bin/sysinfo -u
+ load_sdc_sysinfo
+}
#
-# Create all of the IPv4 IPMP interfaces.
+# Try various config parameters to set the default route
#
-if [ -n "$ipmp_list" ]; then
- set -- $ipmp_list
- while [ $# -gt 0 ]; do
- if /sbin/ifconfig $1 ipmp; then
- ipmp_created="$ipmp_created $1"
- else
- ipmp_failed="$ipmp_failed $1"
- fi
- shift
- done
- [ -n "$ipmp_failed" ] && warn_failed_ifs "create IPv4 IPMP" \
- "$ipmp_failed"
-fi
+function set_default_route
+{
+ set -o xtrace
+ typeset default_gw
-#
-# Step through the IPv4 interface list and try to plumb every interface.
-# Generate list of plumbed and failed IPv4 interfaces.
-#
-if [ -n "$inet_list" ]; then
- set -- $inet_list
- while [ $# -gt 0 ]; do
- /sbin/ifconfig $1 plumb
- if /sbin/ifconfig $1 inet >/dev/null 2>&1; then
- inet_plumbed="$inet_plumbed $1"
- else
- inet_failed="$inet_failed $1"
- fi
- shift
- done
- [ -n "$inet_failed" ] && warn_failed_ifs "plumb IPv4" "$inet_failed"
-fi
+ if [[ -n "${CONFIG_headnode_default_gateway}" ]]; then
+ default_gw="${CONFIG_headnode_default_gateway}"
-# Run autoconf to connect to a WLAN if the interface is a wireless one
-if [ -x /sbin/wificonfig -a -n "$inet_plumbed" ]; then
- set -- $inet_plumbed
- while [ $# -gt 0 ]; do
- if [ -r /dev/wifi/$1 ]; then
- /sbin/wificonfig -i $1 startconf >/dev/null
- fi
- shift
- done
-fi
+ elif [[ -n ${CONFIG_admin_gateway} ]]; then
+ default_gw="${CONFIG_admin_gateway}"
-#
-# Step through the IPv6 interface list and plumb every interface.
-# Generate list of plumbed and failed IPv6 interfaces. Each plumbed
-# interface will be brought up later, after processing any contents of
-# the /etc/hostname6.* file.
-#
-if [ -n "$inet6_list" ]; then
- set -- $inet6_list
- while [ $# -gt 0 ]; do
- /sbin/ifconfig $1 inet6 plumb
- if /sbin/ifconfig $1 inet6 >/dev/null 2>&1; then
- inet6_plumbed="$inet6_plumbed $1"
- else
- inet6_failed="$inet6_failed $1"
- fi
- shift
- done
- [ -n "$inet6_failed" ] && warn_failed_ifs "plumb IPv6" "$inet6_failed"
-fi
+ elif [[ -n ${BOOT_admin_gateway} ]]; then
+ default_gw=${BOOT_admin_gateway}
-#
-# Create all of the IPv6 IPMP interfaces.
-#
-if [ -n "$ipmp6_list" ]; then
- set -- $ipmp6_list
- while [ $# -gt 0 ]; do
- if /sbin/ifconfig $1 inet6 ipmp; then
- ipmp6_created="$ipmp6_created $1"
- else
- ipmp6_failed="$ipmp6_failed $1"
- fi
- shift
- done
- [ -n "$ipmp6_failed" ] && warn_failed_ifs "create IPv6 IPMP" \
- "$ipmp6_failed"
-fi
+ elif [[ -n ${CONFIG_external_gateway} ]]; then
+ default_gw=${CONFIG_external_gateway}
+ fi
-#
-# Finally configure interfaces set up with ipadm. Any /etc/hostname*.intf
-# files take precedence over ipadm defined configurations except when
-# we are in a non-global zone and Layer-3 protection of IP addresses is
-# enforced on the interface by the global zone.
-#
-for showif_output in `/sbin/ipadm show-if -p -o ifname,state,current`; do
- intf=`echo $showif_output | /usr/bin/cut -f1 -d:`
- state=`echo $showif_output | /usr/bin/cut -f2 -d:`
- current=`echo $showif_output | /usr/bin/cut -f3 -d:`
- if [[ "$state" != "disabled" && $current != *Z* ]]; then
- #
- # skip if not a persistent interface, or if it should get IP
- # configuration from the global zone ('Z' flag is set)
- #
- continue;
- elif is_iptun $intf; then
- # skip IP tunnel interfaces plumbed by net-iptun
- continue;
- elif [ -f /etc/hostname.$intf ] || [ -f /etc/hostname6.$intf ]; then
- if [[ $current != *Z* ]]; then
- echo "found /etc/hostname.$intf "\
- "or /etc/hostname6.$intf, "\
- "ignoring ipadm configuration" > /dev/msglog
- continue;
- else
- echo "Ignoring /etc/hostname*.$intf" > /dev/msglog
- /sbin/ifconfig $intf unplumb > /dev/null 2>&1
- /sbin/ifconfig $intf inet6 unplumb > /dev/null 2>&1
- fi
- fi
-
- # Enable the interface managed by ipadm
- /sbin/ipadm enable-if -t $intf
-done
+ if [[ -n ${default_gw} ]]; then
+ echo "${default_gw}" > /etc/defaultrouter
+ fi
-#
-# Process the /etc/hostname[6].* files for IPMP interfaces. Processing these
-# before non-IPMP interfaces avoids accidental implicit IPMP group creation.
-#
-[ -n "$ipmp_created" ] && if_configure inet "IPMP" $ipmp_created
-[ -n "$ipmp6_created" ] && if_configure inet6 "IPMP" $ipmp6_created
+ if [[ -n ${CONFIG_admin_gateway6} ]]; then
+ default_gw6="${CONFIG_admin_gateway6}"
-#
-# Process the /etc/hostname[6].* files for non-IPMP interfaces.
-#
-[ -n "$inet_plumbed" ] && if_configure inet "" $inet_plumbed
-[ -n "$inet6_plumbed" ] && if_configure inet6 "" $inet6_plumbed
+ elif [[ -n ${BOOT_admin_gateway6} ]]; then
+ default_gw6=${BOOT_admin_gateway6}
+
+ elif [[ -n ${CONFIG_external_gateway6} ]]; then
+ default_gw6=${CONFIG_external_gateway6}
+ fi
+
+ if [[ -n ${default_gw6} ]]; then
+ # add static route
+ /usr/sbin/route add -inet6 default ${default_gw6}
+ fi
+}
#
-# For the IPv4 and IPv6 interfaces that failed to plumb, find (or create)
-# IPMP meta-interfaces to host their data addresses.
+# Go through and set up the MTU for all of the various nic tags
#
-[ -n "$inet_failed" ] && move_addresses inet
-[ -n "$inet6_failed" ] && move_addresses inet6
-
-# Run DHCP if requested. Skip boot-configured interface.
-interface_names="`echo /etc/dhcp.*[0-9] 2>/dev/null`"
-if [ "$interface_names" != '/etc/dhcp.*[0-9]' ]; then
- #
- # First find the primary interface. Default to the first
- # interface if not specified. First primary interface found
- # "wins". Use care not to "reconfigure" a net-booted interface
- # configured using DHCP. Run through the list of interfaces
- # again, this time trying DHCP.
- #
- i4d_fail=
- firstif=
- primary=
- ORIGIFS="$IFS"
- IFS="${IFS}."
- set -- $interface_names
-
- while [ $# -ge 2 ]; do
- shift
- [ -z "$firstif" ] && firstif=$1
-
- for i in `shcat /etc/dhcp\.$1`; do
- if [ "$i" = primary ]; then
- primary=$1
- break
- fi
- done
-
- [ -n "$primary" ] && break
- shift
- done
-
- [ -z "$primary" ] && primary="$firstif"
- cmdline=`shcat /etc/dhcp\.${primary}`
-
- if [ "$_INIT_NET_IF" != "$primary" ]; then
- echo "starting DHCP on primary interface $primary"
- /sbin/ifconfig $primary auto-dhcp primary $cmdline
- # Exit code 4 means ifconfig timed out waiting for dhcpagent
- [ $? != 0 ] && [ $? != 4 ] && i4d_fail="$i4d_fail $primary"
- fi
-
- set -- $interface_names
-
- while [ $# -ge 2 ]; do
- shift
- cmdline=`shcat /etc/dhcp\.$1`
- if [ "$1" != "$primary" -a \
- "$1" != "$_INIT_NET_IF" ]; then
- echo "starting DHCP on interface $1"
- /sbin/ifconfig $1 dhcp start wait 0 $cmdline
- # Exit code can't be timeout when wait is 0
- [ $? != 0 ] && i4d_fail="$i4d_fail $1"
- fi
- shift
- done
- IFS="$ORIGIFS"
- unset ORIGIFS
- [ -n "$i4d_fail" ] && warn_failed_ifs "configure IPv4 DHCP" "$i4d_fail"
-fi
+function setup_mtu
+{
+ set -o xtrace
+ typeset tag oldifs val mac link curmtu
+ typeset -A mtus
+ typeset -A tagmap
+
+ set -o xtrace
+ oldifs=$IFS
+ IFS=,
+ for tag in ${SYSINFO_Nic_Tags}; do
+ eval "val=\${CONFIG_${tag}_mtu}"
+ eval "mac=\${CONFIG_${tag}_nic}"
+ [[ -z "$val" ]] && continue
+
+ valid_mtu ${tag} $val
+
+ #
+ # Note, it doesn't matter what tag we use for a given mac
+ # address, because we'll always get the same link name later on.
+ #
+ if [[ -z "${tagmap[$mac]}" ]]; then
+ tagmap[$mac]=$tag
+ fi
+
+ if [[ -z "${mtus[$mac]}" ]]; then
+ mtus[$mac]=$val
+ elif [[ "${mtus[$mac]}" -lt $val ]]; then
+ mtus[$mac]=$val
+ fi
+ done
+ IFS=$oldifs
+
+ for mac in ${!mtus[@]}; do
+ tag=${tagmap[$mac]}
+ eval "link=\${SYSINFO_NIC_${tag}}"
+ if [[ -z "${link}" ]]; then
+ echo "/usbkey/config error: Missing link name for ${tag}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+
+ #
+ # Check the current MTU of the device. To help out devices which
+ # don't support the setting of the MTU (here's looking at you
+ # bnx), if the MTU is identical to its default, don't do
+ # anything and save the poor folks stuck with bnx some grief.
+ #
+ curmtu=$(/usr/sbin/dladm show-linkprop -c -o value -p mtu ${link})
+ [[ $? -eq 0 ]] && [[ "$curmtu" -eq "${mtus[$mac]}" ]] && continue
+
+ if ! /usr/sbin/dladm set-linkprop -p mtu=${mtus[$mac]} ${link}; then
+ echo "Failed to set mtu to ${mtus[$mac]} for link ${link}"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+ done
+}
-# In order to avoid bringing up the interfaces that have
-# intentionally been left down, perform RARP only if the system
-# has no configured hostname in /etc/nodename
-hostname="`shcat /etc/nodename 2>/dev/null`"
-if [ "$_INIT_NET_STRATEGY" = "rarp" -o -z "$hostname" ]; then
- /sbin/ifconfig -adD4 auto-revarp netmask + broadcast + up
+
+# Helper function for plumbing an interface for an address family once
+typeset -A plumbedifs
+function plumbif
+{
+ iface=$1
+ inet=$2
+ addrtype=$3
+ if [[ -z ${plumbedifs[${iface},${inet}]} ]]; then
+ plumbedifs[${iface},${inet}]="true"
+ /sbin/ifconfig ${iface} ${inet} plumb
+ if [[ ! ${addrtype} =~ "^vrrp" ]]; then
+ /sbin/ifconfig ${iface} ${inet} up
+ fi
+ fi
+}
+
+if smf_is_globalzone; then
+ EARLY_ADMIN=
+ [[ -f /etc/svc/volatile/.early_admin_setup ]] && EARLY_ADMIN=1
+ [[ -n "$EARLY_ADMIN" ]] || /usr/sbin/dladm init-phys
+
+ # The next command is for logging purposes only
+ log_if_state before
+
+ # Load sysinfo variables with SYSINFO_ prefix: we primarily care about
+ # the NIC_variables, which contain the actual interface name for a nic
+ # tag (it has mapped the foo_nic=<MAC address> variables to interface
+ # names for us).
+ load_sdc_sysinfo
+
+ if boot_file_config_enabled; then
+ # We have a boot-time networking file present - use its values rather
+ # than ones from the config file or bootparams
+ if ! boot_file_config_valid; then
+ echo "ERROR: boot-time network config file incorrect"
+ exit ${SMF_EXIT_ERR_CONFIG}
+ fi
+
+ load_boot_file_config
+
+ # NOTE: some of the routes boot_file_config_init tries to add may
+ # fail if they are admin network routes added by the
+ # network/early-admin service. This is expected and not a problem.
+ boot_file_config_init
+ else
+ # Load config variables with CONFIG_ prefix,
+ # and sets the headnode variable
+ load_sdc_config
+ # Load boot params with BOOT_ prefix
+ load_sdc_bootparams
+ fi
+
+ # Set up etherstubs
+ for stub in $(echo "${CONFIG_etherstub}" | sed -e "s/,/ /g"); do
+ /usr/sbin/dladm create-etherstub -t $stub || echo "ERROR: could not create etherstub ${stub}."
+ done
+
+ # Create aggregations
+ create_aggrs
+
+ # Make any mtu adjustments that may be necessary
+ setup_mtu
+
+ # Setup admin NIC
+ ADMIN_NIC_TAG=${CONFIG_admin_tag:-"admin"}
+
+ # If there is no NIC with the admin tag, and the config has
+ # admin_nic_autoselect=true, designate the first NIC reported
+ # by dladm for admin use. This is useful in environments where
+ # the NICs are known to change beneath us.
+ if [[ "${BOOT_smartos}" == "true" ]] && \
+ [[ "${CONFIG_admin_nic_autoselect}" == "true" ]] && \
+ ! nictagadm exists $ADMIN_NIC_TAG ; then
+ autoselected_admin_nic=$(dladm show-phys -m -p -o address | head -n1)
+ if [[ -z ${autoselected_admin_nic} ]] ; then
+ echo "ERROR: no NICs found, unable to autoselect admin NIC."
+ exit ${SMF_EXIT_ERR_CONFIG}
+ fi
+
+ nictagadm add $ADMIN_NIC_TAG "${autoselected_admin_nic}"
+ if [[ $? -ne 0 ]] ; then
+ echo "ERROR: unable to add admin tag to NIC ${autoselected_admin_nic}"
+ exit ${SMF_EXIT_ERR_FATAL}
+ fi
+
+ SYSINFO_NIC_admin=$(dladm show-phys -m -p -o link | head -n1)
+ if [[ -n ${SYSINFO_NIC_admin} ]] ; then
+ echo "Autoselected ${SYSINFO_NIC_admin} for use as admin NIC."
+ fi
+
+ nictagadm list
+ elif [[ -v CONFIG_admin_tag ]]; then
+ #
+ # This handles the case when the 'admin_tag' property is set to
+ # override the default admin nic tag.
+ #
+ eval SYSINFO_NIC_admin='$'SYSINFO_NIC_${CONFIG_admin_tag}
+
+ eval CONFIG_admin_ip='$'CONFIG_${CONFIG_admin_tag}_ip
+ eval CONFIG_admin_ip6='$'CONFIG_${CONFIG_admin_tag}_ip6
+ eval CONFIG_admin_netmask='$'CONFIG_${CONFIG_admin_tag}_netmask
+ eval CONFIG_admin_mtu='$'CONFIG_${CONFIG_admin_tag}_mtu
+ eval CONFIG_admin_gateway='$'CONFIG_${CONFIG_admin_tag}_gateway
+ eval CONFIG_admin_gateway6='$'CONFIG_${CONFIG_admin_tag}_gateway6
+ fi
+
+ if [[ -z "${SYSINFO_NIC_admin}" ]]; then
+ echo "ERROR: admin NIC not found, unable to bring up admin network."
+ exit ${SMF_EXIT_ERR_CONFIG}
+ fi
+
+ [[ -n "$EARLY_ADMIN" ]] || plumb_admin
+
+ # If we performed early configuration of the admin network and
+ # the admin interface is on a link aggregation, the aggregation
+ # has already been configured. Add it to the list of active aggrs
+ # so the checks in vnic_up[6] are aware of it.
+ if [[ -n "$EARLY_ADMIN" && "${SYSINFO_NIC_admin}" =~ aggr[0-9]+$ ]]; then
+ eval "macs=\${SYSINFO_Aggregation_${SYSINFO_NIC_admin}_MACs}"
+
+ add_active_aggr_links ${SYSINFO_NIC_admin} $macs
+ fi
+
+ # Prefer the config file for admin nic values, but use
+ # bootparams if present
+ admin_ip=${CONFIG_admin_ip}
+ if [[ -z "$admin_ip" ]]; then
+ admin_ip=${BOOT_admin_ip}
+ fi
+
+ admin_netmask=${CONFIG_admin_netmask}
+ if [[ -z "$admin_netmask" ]]; then
+ admin_netmask=${BOOT_admin_netmask}
+ fi
+
+ admin_ip6=${CONFIG_admin_ip6}
+ if [[ -z "$admin_ip6" ]]; then
+ admin_ip6=${BOOT_admin_ip6}
+ fi
+
+ if [[ $admin_ip == 'none' ]]; then
+ echo 'INFO: not configuring IP on admin interface (admin_ip=none)'
+ elif [[ -n "$EARLY_ADMIN" ]]; then
+ echo 'INFO: admin interface already configured (early setup)'
+ ADMIN_NIC_UP=true
+ elif [[ -n $admin_ip ]] && [[ -n $admin_netmask ]]; then
+ /sbin/ifconfig ${SYSINFO_NIC_admin} inet ${admin_ip} \
+ netmask ${admin_netmask} up
+ ADMIN_NIC_UP=true
+
+ # also setup resolv.conf if we can
+ if [[ -n ${CONFIG_dns_domain} ]] && [[ -n ${CONFIG_dns_resolvers} ]]; then
+ echo "search ${CONFIG_dns_domain}" > /etc/resolv.conf
+ if [[ -n ${CONFIG_binder_admin_ips} ]]; then
+ for serv in $(echo "${CONFIG_binder_admin_ips}" | sed -e "s/,/ /g"); do
+ echo "nameserver ${serv}" >> /etc/resolv.conf
+ done
+ fi
+ for serv in $(echo "${CONFIG_dns_resolvers}" | sed -e "s/,/ /g"); do
+ echo "nameserver ${serv}" >> /etc/resolv.conf
+ done
+ fi
+ else
+ if [[ ${headnode} == "true" ]]; then
+ echo "ERROR: headnode but no admin_{ip,netmask} in config, not bringing up admin network."
+ # Set a flag, but try to plumb the other interfaces anyway
+ ADMIN_NIC_MISCONFIGURED=true
+ else
+ # We ignore errors here because the most common one is that DHCP is
+ # already running.
+ /sbin/ifconfig ${SYSINFO_NIC_admin} dhcp || /bin/true
+
+ # Wait for DHCP
+ timeout=${ADMIN_DHCP_TIMEOUT}
+ dhcp_admin_ip=$(/sbin/ifconfig ${SYSINFO_NIC_admin} | grep inet | awk '{ print $2 }')
+ while [[ (-z ${dhcp_admin_ip} || ${dhcp_admin_ip} == "0.0.0.0") && ${timeout} -gt 0 ]]; do
+ dhcp_admin_ip=$(/sbin/ifconfig ${SYSINFO_NIC_admin} | grep inet | awk '{ print $2 }')
+ timeout=$((${timeout} - 1))
+ sleep 1
+ done
+
+ ADMIN_NIC_UP=true
+ fi
+ fi
+
+ if [[ -n ${admin_ip6} && -z "$EARLY_ADMIN" ]]; then
+ # Plumb interface for inet6
+ ifconfig ${SYSINFO_NIC_admin} inet6 \
+ plumb mtu ${CONFIG_admin_mtu:-1500} up
+
+ # Autodiscovery IPv6 using SLAAC
+ # NOTE: in.ndpd will be started later, due to plumbing the interface.
+ # this means autodiscovery also happens when configuring a
+ # static address.
+ #
+ # in.ndpd also sets a default route and this can't be disabled.
+
+ # Configure static IPv6
+ if [[ ${admin_ip6} != "addrconf" ]]; then
+ /sbin/ifconfig ${SYSINFO_NIC_admin} inet6 \
+ addif ${admin_ip6} preferred up
+ fi
+
+ ADMIN_NIC_UP=true
+
+ # don't setup resolv.conf, IPv6 addresses already work
+ fi
+
+ # If on Parallels or VirtualBox, create a bridge which
+ # allows traffic to flow correctly to the host-only network
+ if [[ "${ADMIN_NIC_UP}" == "true" ]] \
+ && [[ ${SYSINFO_Product} == "Parallels Virtual Platform" \
+ || ${SYSINFO_Product} == "VirtualBox" ]] \
+ && [[ -z $(/usr/sbin/dladm show-bridge -p vmwarebr) ]]; then
+ /usr/sbin/dladm create-bridge -l ${SYSINFO_NIC_admin} vmwarebr
+ fi
+
+ # Setup the external NIC. The installer may have already set up external0,
+ # so, if it exists, we're not going to try and set up the vnic again.
+ if [[ -n ${SYSINFO_NIC_external} ]] \
+ && ! dladm show-vnic external0 > /dev/null; then
+
+ if [[ -n "${CONFIG_external_ip}" ]]; then
+ vnic_up "${SYSINFO_NIC_external}" "external0" \
+ "${CONFIG_external_ip}" "${CONFIG_external_netmask}" \
+ "${CONFIG_external_vlan_id}" "${CONFIG_external_mac}" \
+ "primary" "${CONFIG_external_mtu}"
+ fi
+
+ if [[ -n "${CONFIG_external_ip6}" ]]; then
+ vnic_up6 "${SYSINFO_NIC_external}" "external0" \
+ "${CONFIG_external_ip6}" \
+ "${CONFIG_external_vlan_id}" "${CONFIG_external_mac}" \
+ "${CONFIG_external_mtu}"
+ fi
+ fi
+
+ set_default_route
+
+ # Setup extra nics, if specified in the config file
+ nic_tags="${SYSINFO_Nic_Tags}"
+ if [[ -n "${nic_tags}" ]]; then
+ tags=(${nic_tags//,/ })
+
+ if boot_file_config_enabled; then
+ bootparam_ip_keys=""
+ bootparam_ip6_keys=""
+ config_ip_keys=${CONFIG_bootfile_ip_keys//,/ }
+ config_ip6_keys=${CONFIG_bootfile_ip6_keys//,/ }
+ else
+ bootparam_ip_keys=$(sdc_bootparams_keys | grep -- "-ip$" || true)
+ bootparam_ip6_keys=$(sdc_bootparams_keys | grep -- "-ip6$" || true)
+ config_ip_keys=$(sdc_config_keys | grep "_ip$" || true)
+ config_ip6_keys=$(sdc_config_keys | grep "_ip6$" || true)
+ fi
+
+ for tag in "${tags[@]}"; do
+
+ eval "link=\${SYSINFO_NIC_${tag}}"
+ if [[ -z "${link}" ]]; then
+ echo "WARNING: No link found with tag '${tag}'"
+ continue
+ fi
+
+ for key in ${config_ip_keys}; do
+ if [[ ${key} == ${tag}[0-9]_ip ]] || [[ ${key} == ${tag}[0-9][0-9]_ip ]]; then
+ iface=${key//_ip/}
+ #echo " iface=$iface"
+ eval "ip=\${CONFIG_${iface}_ip}"
+ eval "netmask=\${CONFIG_${iface}_netmask}"
+ eval "vlan=\${CONFIG_${iface}_vlan_id}"
+ eval "macaddr=\${CONFIG_${iface}_mac}"
+ eval "mtu=\${CONFIG_${iface}_mtu}"
+
+ echo vnic_up "${link}" "${iface}" "${ip}" "${netmask}" "${vlan}" "${macaddr}" "${mtu}"
+ vnic_up "${link}" "${iface}" "${ip}" "${netmask}" \
+ "${vlan}" "${macaddr}" "" "${mtu}"
+ fi
+ done
+
+ for key in ${bootparam_ip_keys}; do
+ if [[ ${key} == ${tag}[0-9]-ip ]] || [[ ${key} == ${tag}[0-9][0-9]-ip ]]; then
+ iface=${key//-ip/}
+ eval "ip=\${BOOT_${iface}_ip}"
+ eval "netmask=\${BOOT_${iface}_netmask}"
+ eval "vlan=\${BOOT_${iface}_vlan_id}"
+ eval "macaddr=\${BOOT_${iface}_mac}"
+ eval "mtu=\${CONFIG_${iface}_mtu}"
+ echo vnic_up "${link}" "${iface}" "${ip}" "${netmask}" "${vlan}" "${macaddr}" "${mtu}"
+ vnic_up "${link}" "${iface}" "${ip}" "${netmask}" \
+ "${vlan}" "${macaddr}" "" "${mtu}"
+ fi
+ done
+
+ for key in ${config_ip6_keys}; do
+ if [[ ${key} == ${tag}[0-9]_ip6 ]] || [[ ${key} == ${tag}[0-9][0-9]_ip6 ]]; then
+ iface=${key//_ip6/}
+ #echo " iface=$iface"
+ eval "ip=\${CONFIG_${iface}_ip6}"
+ eval "vlan=\${CONFIG_${iface}_vlan_id}"
+ eval "macaddr=\${CONFIG_${iface}_mac}"
+ eval "mtu=\${CONFIG_${iface}_mtu}"
+
+ echo vnic_up6 "${link}" "${iface}" "${ip}" "${vlan}" "${macaddr}" "${mtu}"
+ vnic_up6 "${link}" "${iface}" "${ip}" \
+ "${vlan}" "${macaddr}" "${mtu}"
+ fi
+ done
+
+ for key in ${bootparam_ip6_keys}; do
+ if [[ ${key} == ${tag}[0-9]-ip6 ]] || [[ ${key} == ${tag}[0-9][0-9]-ip6 ]]; then
+ iface=${key//-ip6/}
+ eval "ip=\${BOOT_${iface}_ip6}"
+ eval "vlan=\${BOOT_${iface}_vlan_id}"
+ eval "macaddr=\${BOOT_${iface}_mac}"
+ eval "mtu=\${CONFIG_${iface}_mtu}"
+ echo vnic_up6 "${link}" "${iface}" "${ip}" "${vlan}" "${macaddr}" "${mtu}"
+ vnic_up6 "${link}" "${iface}" "${ip}" \
+ "${vlan}" "${macaddr}" "${mtu}"
+ fi
+ done
+
+ done
+ fi
+else
+ # Non-global zones
+
+ # Bring up statically assigned interfaces, and find the primary DHCP
+ # interface, if it exists
+ while IFS=: read -r iface addrtype; do
+ # Keep track of whether or not we've configured our first IPv4
+ # address on this interface
+ first_ipv4_configured=""
+ iface_configured=""
+
+ if [[ -f /etc/dhcp.${iface} ]]; then
+ plumbif ${iface} inet ${addrtype}
+ if [[ -z "${primary}" ]]; then
+ /sbin/ifconfig ${iface} auto-dhcp primary
+ primary=${iface}
+ else
+ /sbin/ifconfig ${iface} auto-dhcp
+ fi
+ first_ipv4_configured="true"
+ iface_configured="true"
+ fi
+
+ if [[ -f /etc/hostname.${iface} ]]; then
+ while read ifparams; do
+ # For IPv4, we need to set the address on the first logical
+ # interface. For IPv6, the address on the first interface is
+ # the link-local address, and can't be changed.
+ #
+ # Lines starting with inet indicate the hostname for that
+ # interface, and are used by dhcpagent. Skip over them.
+ if [[ -f /etc/dhcp.${iface} && "${ifparams}" == inet* ]]; then
+ continue
+ elif [[ "${ifparams}" == {3}({1,3}(\d).){1,3}(\d)* ]]; then
+ plumbif ${iface} inet ${addrtype}
+ if [[ -z "${first_ipv4_configured}" ]]; then
+ first_ipv4_configured="true"
+ ifcommand="inet"
+ else
+ ifcommand="inet addif"
+ fi
+ else
+ plumbif ${iface} inet6 ${addrtype}
+ ifcommand="inet6 addif"
+ fi
+
+ # vrrp interfaces can't be brought up with ifconfig: vrrpadm
+ # handles that instead
+ if [[ "${addrtype}" =~ "^vrrp" ]]; then
+ /sbin/ifconfig ${iface} ${ifcommand} \
+ `printf "%s" "${ifparams}" | sed -e 's/ up//'`
+ else
+ /sbin/ifconfig ${iface} ${ifcommand} ${ifparams} up
+ fi
+
+ iface_configured="true"
+ done < /etc/hostname.${iface}
+ fi
+
+ if [[ -f /etc/addrconf.${iface} ]]; then
+ # Enable the NDP daemon, so that once this script finishes, we'll
+ # be able to pick up router advertisments and finish configuring
+ # the network interface. We then just need to plumb the interface,
+ # and let in.ndpd take care of configuring addresses.
+ svcadm enable svc:/network/routing/ndp:default
+ plumbif ${iface} inet6 ${addrtype}
+ iface_configured="true"
+ fi
+
+ # If we didn't configure the device at all, mark it for DHCP if we
+ # don't do DHCP on anyone else.
+ if [[ -z ${iface_configured} && -z "${first_iface}" ]]; then
+ first_iface=${iface}
+ fi
+ done < <(/usr/sbin/dladm show-vnic -p -o link,macaddrtype 2>/dev/null)
+
+ if [[ -z "${primary}" && -n "${first_iface}" ]]; then
+ first_iface_type=$(dladm show-vnic ${first_iface} -p -o macaddrtype)
+ plumbif ${first_iface} inet ${first_iface_type}
+ /sbin/ifconfig ${first_iface} auto-dhcp
+ primary=${first_iface}
+ fi
+
+ while IFS=: read -r iface addrtype; do
+ if [[ "${iface}" == "${primary}"
+ || -f /etc/hostname.${iface}
+ || -f /etc/dhcp.${iface}
+ || -f /etc/addrconf.${iface}
+ || "${addrtype}" =~ "^vrrp" ]]; then
+ continue
+ fi
+
+ plumbif ${iface} inet ${addrtype}
+ /sbin/ifconfig ${iface} auto-dhcp start wait 0
+ done < <(/usr/sbin/dladm show-vnic -p -o link,macaddrtype 2>/dev/null)
fi
-#
-# If the /etc/defaultrouter file exists, process it now so that the next
-# stage of booting will have access to NFS.
-#
-if [ -f /etc/defaultrouter ]; then
- while read router rubbish; do
- case "$router" in
- '#'* | '') ;; # Ignore comments, empty lines
- *) /sbin/route -n add default -gateway $router ;;
- esac
- done </etc/defaultrouter
+log_if_state after
+
+# Since we hopefully made networking changes here, update the sysinfo cache
+if smf_is_globalzone; then
+ /usr/bin/sysinfo -u
fi
-#
-# If we get here and were not asked to plumb any IPv4 interfaces, look
-# for boot properties that direct us.
-#
-# - The "network-interface" property is required and indicates the
-# interface name.
-# - The "xpv-hcp" property, if present, is used by the hypervisor
-# tools to indicate how the specified interface should be configured.
-# Permitted values are "dhcp" and "off", where "off" indicates static
-# IP configuration.
-#
-# In the case where "xpv-hcp" is set to "dhcp", no further properties
-# are required or examined.
-#
-# In the case where "xpv-hcp" is not present or set to "off", the
-# "host-ip" and "subnet-mask" properties are used to configure
-# the specified interface. The "router-ip" property, if present,
-# is used to add a default route.
-#
-nic="`/sbin/devprop network-interface`"
-if smf_is_globalzone && [ -z "$inet_list" ] && [ -n "$nic" ]; then
- hcp="`/sbin/devprop xpv-hcp`"
- case "$hcp" in
- "dhcp")
- /sbin/ifconfig $nic plumb 2>/dev/null
- [ -n "`/sbin/ifconfig $nic 2>/dev/null`" ] && (
- # The interface is successfully plumbed, so
- # modify "inet_list" to force the exit code
- # checks to work.
- inet_list=$nic;
- # Given that this is the only IPv4 interface,
- # we assert that it is primary.
- echo "starting DHCP on primary interface $primary";
- /sbin/ifconfig $nic auto-dhcp primary;
- # Exit code 4 means ifconfig timed out waiting
- # for dhcpagent
- [ $? != 0 ] && [ $? != 4 ] && \
- i4d_fail="$i4d_fail $nic";
- )
- ;;
-
- "off"|"")
- /sbin/devprop host-ip subnet-mask router-ip | (
- read ip;
- read mask;
- read router;
- [ -n "$ip" ] && [ -n "$mask" ] && \
- /sbin/ifconfig $nic plumb 2>/dev/null
- [ -n "`/sbin/ifconfig $nic 2>/dev/null`" ] && (
- # The interface is successfully
- # plumbed, so modify "inet_list" to
- # force the exit code checks to work.
- inet_list=$nic;
- /sbin/ifconfig $nic inet $ip \
- netmask $mask broadcast + up 2>/dev/null;
- [ -n "$router" ] && route add \
- default $router 2>/dev/null;
- )
- )
- ;;
- esac
+# Enable symmetric routing: when there are multiple nics configured, always
+# take into account the interface a packet is being sent over when
+# selecting a route. This prevents packets being sent with another nic's
+# source IP.
+/usr/sbin/ndd -set /dev/ip ip_strict_src_multihoming 1
+
+# If the admin nic was missing config options, exit with a config error
+if [[ -n "${ADMIN_NIC_MISCONFIGURED}" ]]; then
+ exit ${SMF_EXIT_ERR_CONFIG}
fi
-#
-# We tell smf this service is online if any of the following is true:
-# - no interfaces were configured for plumbing and no DHCP failures
-# - any non-loopback IPv4 interfaces are up and have a non-zero address
-# - there are any DHCP interfaces started
-# - any non-loopback IPv6 interfaces are up
-#
-# If we weren't asked to configure any interfaces, exit
-if [ -z "$inet_list" ] && [ -z "$inet6_list" ]; then
- # Config error if DHCP was attempted without plumbed interfaces
- [ -n "$i4d_fail" ] && exit $SMF_EXIT_ERR_CONFIG
- exit $SMF_EXIT_OK
+if [[ $admin_ip == 'none' ]]; then
+ #
+ # We're done, even if there are not any usable IP addresses.
+ #
+ exit $SMF_EXIT_OK
fi
# Any non-loopback IPv4 interfaces with usable addresses up?
-if [ -n "`/sbin/ifconfig -a4u`" ]; then
- /sbin/ifconfig -a4u | while read intf addr rest; do
- [ $intf = inet ] && [ $addr != 127.0.0.1 ] &&
- [ $addr != 0.0.0.0 ] && exit $SMF_EXIT_OK
- done && exit $SMF_EXIT_OK
+if [[ -n "`/sbin/ifconfig -a4u`" ]]; then
+ /sbin/ifconfig -a4u | while read intf addr rest; do
+ [[ ${intf} == "inet" ]] && [[ ${addr} != "127.0.0.1" ]] &&
+ [[ ${addr} != "0.0.0.0" ]] && exit ${SMF_EXIT_OK}
+ done && exit ${SMF_EXIT_OK}
fi
# Any DHCP interfaces started?
-[ -n "`/sbin/ifconfig -a4 dhcp status 2>/dev/null`" ] && exit $SMF_EXIT_OK
+[[ -n "`/sbin/ifconfig -a4 dhcp status 2>/dev/null`" ]] && exit ${SMF_EXIT_OK}
# Any non-loopback IPv6 interfaces up?
-if [ -n "`/sbin/ifconfig -au6`" ]; then
- /sbin/ifconfig -au6 | while read intf addr rest; do
- [ $intf = inet6 ] && [ $addr != ::1/128 ] && exit $SMF_EXIT_OK
- done && exit $SMF_EXIT_OK
+if [[ -n "`/sbin/ifconfig -au6`" ]]; then
+ /sbin/ifconfig -au6 | while read intf addr rest; do
+ [[ ${intf} = "inet6" ]] && [[ ${addr} != "::1/128" ]] && exit ${SMF_EXIT_OK}
+ done && exit ${SMF_EXIT_OK}
fi
# This service was supposed to configure something yet didn't. Exit
# with config error.
-exit $SMF_EXIT_ERR_CONFIG
+exit ${SMF_EXIT_ERR_CONFIG}
diff --git a/usr/src/cmd/svc/milestone/net-routing-setup b/usr/src/cmd/svc/milestone/net-routing-setup
index 6ab1a6c7f0..0b294c2630 100644
--- a/usr/src/cmd/svc/milestone/net-routing-setup
+++ b/usr/src/cmd/svc/milestone/net-routing-setup
@@ -21,11 +21,15 @@
#
#
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# Copyright (c) 2012 Joyent, Inc. All rights reserved.
# This script configures IP routing.
. /lib/svc/share/smf_include.sh
+set -o xtrace
+
#
# In a shared-IP zone we need this service to be up, but all of the work
# it tries to do is irrelevant (and will actually lead to the service
@@ -80,6 +84,17 @@ fi
#
smf_netstrategy
+#
+# Read /etc/inet/static_routes.vmadm and add each link-local route.
+#
+if [ -f /etc/inet/static_routes.vmadm ]; then
+ echo "Adding vmadm persistent link-local routes:"
+ /usr/bin/egrep -v "^(#|$)" /etc/inet/static_routes.vmadm |
+ /usr/bin/grep -- "-interface " | while read line; do
+ /usr/sbin/route add $line
+ done
+fi
+
if [ "$_INIT_NET_STRATEGY" = "dhcp" ] && \
[ -n "`/sbin/dhcpinfo Router`" ]; then
defrouters=`/sbin/dhcpinfo Router`
@@ -156,7 +171,8 @@ fi
# however, as persistent daemon state is now controlled by SMF.
#
ipv4_routing_set=`/usr/bin/svcprop -p routeadm/ipv4-routing-set $SMF_FMRI`
-if [ -z "$defrouters" ]; then
+smartos_param=`/usr/bin/bootparams | grep "^smartos"`
+if [ -z "$defrouters" ] && [ "$smartos_param" != "" ]; then
#
# Set default value for ipv4-routing to enabled. If routeadm -e/-d
# has not yet been run by the administrator, we apply this default.
@@ -210,5 +226,22 @@ if [ -f /etc/inet/static_routes ]; then
done
fi
+#
+# Read /etc/inet/static_routes.vmadm and add each non-link-local route.
+#
+if [ -f /etc/inet/static_routes.vmadm ]; then
+ echo "Adding vmadm persistent routes:"
+ /usr/bin/egrep -v "^(#|$)" /etc/inet/static_routes.vmadm |
+ /usr/bin/grep -v -- "-interface " | while read line; do
+ /usr/sbin/route add $line
+ done
+fi
+
+#
+# Log the result
+#
+echo "Routing setup complete:"
+/usr/bin/netstat -rn
+
# Clear exit status.
exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/svc/milestone/network-early-admin.xml b/usr/src/cmd/svc/milestone/network-early-admin.xml
new file mode 100644
index 0000000000..6566f31bff
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/network-early-admin.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2019, Joyent, Inc.
+
+ This file and its contents are supplied under the terms of the
+ Common Development and Distribution License ("CDDL"), version 1.0.
+ You may only use this file in accordance with the terms of version
+ 1.0 of the CDDL.
+
+ A full copy of the text of the CDDL should have accompanied this
+ source. A copy of the CDDL is also available via the Internet at
+ http://www.illumos.org/license/CDDL.
+
+-->
+
+<service_bundle type='manifest' name='network-early-admin'>
+
+<service
+ name='network/early-admin'
+ type='service'
+ version='1'>
+
+ <!-- ifconfig needs loopback for IPC with dhcpagent -->
+ <dependency
+ name='network'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ <service_fmri value='svc:/network/datalink-management' />
+ <service_fmri value='svc:/network/ip-interface-management' />
+ </dependency>
+
+ <instance name='default' enabled='true'>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/net-early-admin'
+ timeout_seconds='600' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':true'
+ timeout_seconds='3' />
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring' value='transient' />
+ </property_group>
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Triton admin network on compute nodes
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='ifconfig' section='1M'
+ manpath='/usr/share/man' />
+ <manpage title='dladm' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+
+ </instance>
+
+ <stability value='Unstable' />
+
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/milestone/network-location.xml b/usr/src/cmd/svc/milestone/network-location.xml
index aad337f42f..5e23d92481 100644
--- a/usr/src/cmd/svc/milestone/network-location.xml
+++ b/usr/src/cmd/svc/milestone/network-location.xml
@@ -81,14 +81,6 @@
</dependency>
<dependency
- name='location_netcfg'
- grouping='require_all'
- restart_on='none'
- type='service'>
- <service_fmri value='svc:/network/netcfg:default' />
- </dependency>
-
- <dependency
name='filesystem'
grouping='require_all'
restart_on='none'
diff --git a/usr/src/cmd/svc/milestone/network-physical.xml b/usr/src/cmd/svc/milestone/network-physical.xml
index fdc9e4bdf8..f26c9647a1 100644
--- a/usr/src/cmd/svc/milestone/network-physical.xml
+++ b/usr/src/cmd/svc/milestone/network-physical.xml
@@ -47,7 +47,13 @@
<service_fmri value='svc:/network/loopback' />
</dependency>
- <instance name='default' enabled='true'>
+ <dependency
+ name='joyent'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/smartdc' />
+ </dependency>
<!--
physical:default and physical:nwam are mutually exclusive.
@@ -55,13 +61,25 @@
does not work.
-->
<dependency
- name='physical_nwam'
- grouping='exclude_all'
+ name='mdata-fetch'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/smartdc/mdata:fetch' />
+ </dependency>
+
+ <!-- Prevent this and network/early-admin from trying to configure the
+ admin interface at the same time -->
+ <dependency
+ name='early-admin'
+ grouping='optional_all'
restart_on='none'
type='service'>
- <service_fmri value='svc:/network/physical:nwam' />
+ <service_fmri value='svc:/network/early-admin:default' />
</dependency>
+ <instance name='default' enabled='true'>
+
<exec_method
type='method'
name='start'
@@ -92,82 +110,6 @@
</instance>
- <instance name='nwam' enabled='false'>
-
- <exec_method
- type='method'
- name='start'
- exec='/lib/svc/method/net-nwam start'
- timeout_seconds='120' >
- <method_context>
- <method_credential user='root' group='root'
- supp_groups='netadm' privileges='zone' />
- </method_context>
- </exec_method>
-
- <exec_method
- type='method'
- name='stop'
- exec='/lib/svc/method/net-nwam stop'
- timeout_seconds='60' >
- <method_context>
- <method_credential user='root' group='root'
- supp_groups='netadm' privileges='zone' />
- </method_context>
- </exec_method>
-
- <exec_method
- type='method'
- name='refresh'
- exec='/lib/svc/method/net-nwam refresh'
- timeout_seconds='60' >
- <method_context>
- <method_credential user='root' group='root'
- supp_groups='netadm' privileges='zone' />
- </method_context>
- </exec_method>
-
- <property_group name='general' type='framework'>
- <!-- to start/stop NWAM services -->
- <propval name='action_authorization' type='astring'
- value='solaris.smf.manage.nwam' />
- <propval name='value_authorization' type='astring'
- value='solaris.smf.manage.nwam' />
- </property_group>
-
- <property_group name='nwamd' type='application'>
- <stability value='Unstable' />
- <propval name='debug' type='boolean' value='false' />
- <propval name='autoconf' type='boolean' value='false' />
- <propval name='ncu_wait_time' type='count' value='60' />
- <propval name='condition_check_interval' type='count'
- value='120' />
- <propval name='scan_interval' type='count' value='120' />
- <propval name='scan_level' type='astring' value='weak' />
- <propval name='strict_bssid' type='boolean' value='false' />
- <propval name='active_ncp' type='astring' value='Automatic' />
- <propval name='value_authorization' type='astring'
- value='solaris.smf.value.nwam' />
- </property_group>
-
- <template>
- <common_name>
- <loctext xml:lang='C'>
- physical network interface autoconfiguration
- </loctext>
- </common_name>
- <documentation>
- <manpage title='nwamd' section='1M'
- manpath='/usr/share/man' />
- <doc_link
- name='Network Auto-Magic OpenSolaris Project Page'
- uri='http://hub.opensolaris.org/bin/view/Project+nwam/'
- />
- </documentation>
- </template>
-
- </instance>
-
<stability value='Unstable' />
</service>
diff --git a/usr/src/cmd/svc/milestone/network-routing-setup.xml b/usr/src/cmd/svc/milestone/network-routing-setup.xml
index b34d578e2a..85a74756da 100644
--- a/usr/src/cmd/svc/milestone/network-routing-setup.xml
+++ b/usr/src/cmd/svc/milestone/network-routing-setup.xml
@@ -40,11 +40,19 @@
<!-- loopback/physical network configuration is required -->
<dependency
- name='network'
- grouping='optional_all'
+ name='loopback'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+ <dependency
+ name='physical'
+ grouping='require_all'
restart_on='none'
type='service'>
- <service_fmri value='svc:/milestone/network' />
+ <service_fmri value='svc:/network/physical' />
</dependency>
<!-- usr filesystem required to run routing-related commands -->
diff --git a/usr/src/cmd/svc/milestone/network.xml b/usr/src/cmd/svc/milestone/network.xml
index 75b5578f44..48386ebf73 100644
--- a/usr/src/cmd/svc/milestone/network.xml
+++ b/usr/src/cmd/svc/milestone/network.xml
@@ -54,6 +54,14 @@
<service_fmri value='svc:/network/physical' />
</dependency>
+ <dependency
+ name='routing-setup'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/routing-setup' />
+ </dependency>
+
<exec_method
type='method'
name='start'
diff --git a/usr/src/cmd/svc/milestone/single-user.xml b/usr/src/cmd/svc/milestone/single-user.xml
index 8797f13c47..579ecb5ddd 100644
--- a/usr/src/cmd/svc/milestone/single-user.xml
+++ b/usr/src/cmd/svc/milestone/single-user.xml
@@ -68,7 +68,7 @@
<dependency
name='manifests'
- grouping='require_all'
+ grouping='optional_all'
restart_on='none'
type='service'>
<service_fmri value='svc:/system/manifest-import' />
diff --git a/usr/src/cmd/svc/milestone/smartdc-config b/usr/src/cmd/svc/milestone/smartdc-config
new file mode 100755
index 0000000000..510c93add6
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/smartdc-config
@@ -0,0 +1,211 @@
+#!/bin/bash
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+#
+# Despite its "smartdc/config" name, this service is used both for SmartOS and
+# Triton. It has two jobs:
+#
+# During an initial setup, this runs through the initial (possibly interactive)
+# configuration.
+#
+# During normal operation, it does some miscellaneous configuration based on
+# /usbkey/config (which, under Triton, will have already been updated from the
+# USB key by svc:/system/filesystem/smartdc:default).
+#
+
+set -o errexit
+set -o xtrace
+
+. /lib/svc/share/smf_include.sh
+. /lib/sdc/config.sh
+
+export PATH="/usr/sbin:/sbin:/usr/bin"
+
+set_root_password() {
+ enc_password=$1
+
+ sed -e "s|^root:[^\:]*:|root:${enc_password}:|" /etc/shadow > /etc/shadow.new \
+ && chmod 400 /etc/shadow.new \
+ && mv /etc/shadow.new /etc/shadow
+}
+
+case "$1" in
+'start')
+
+ # If we're a headnode, see if we have to do interactive configuration.
+ if /bin/bootparams | grep "^headnode=true" > /dev/null 2>&1; then
+ USB_PATH=/mnt/`svcprop -p "joyentfs/usb_mountpoint" svc:/system/filesystem/smartdc:default`
+
+ # Check for config and run interactive if it doesn't exist.
+ if [[ ! -f ${USB_PATH}/config ]]; then
+ if /bin/bootparams | grep "^noimport=true" >/dev/null 2>&1; then
+ # Skipping interactive config, bypass rest of script.
+ exit $SMF_EXIT_OK
+ fi
+
+ /smartdc/lib/sdc-on-tty -d /dev/console \
+ ${USB_PATH}/scripts/prompt-config.sh "${USB_PATH}"
+
+ # If user quit from interactive configuration then we're done.
+ [[ ! -f ${USB_PATH}/config ]] && exit $SMF_EXIT_OK
+ fi
+ elif /bin/bootparams | grep "^smartos=true" > /dev/null 2>&1; then
+ USB_PATH=/`svcprop -p "joyentfs/usb_copy_path" svc:/system/filesystem/smartdc:default`
+
+ # Check for config and run interactive if it doesn't exist.
+ if [[ ! -f ${USB_PATH}/config ]]; then
+ if /bin/bootparams | grep "^noimport=true" >/dev/null 2>&1; then
+ # Skipping interactive config, bypass rest of script.
+ exit $SMF_EXIT_OK
+ fi
+
+ /smartdc/lib/sdc-on-tty -d /dev/console \
+ /smartdc/lib/smartos_prompt_config.sh "${USB_PATH}"
+
+ # If user quit from interactive configuration then we're done.
+ [[ ! -f ${USB_PATH}/config ]] && exit $SMF_EXIT_OK
+ fi
+ fi
+
+ # This puts config vars in CONFIG_
+ load_sdc_config
+ load_sdc_sysinfo
+
+ # Write the info about this datacenter to /.dcinfo so we can use in the GZ
+ echo "SDC_DATACENTER_NAME='${CONFIG_datacenter_name}'" > /.dcinfo
+
+ if [[ -n "${SYSINFO_Bootparam_smartos}" && -f /usbkey/shadow ]]; then
+ echo "setting root password from /usbkey/shadow"
+ # Boot parameter takes precidence over config
+ elif [[ -n "${SYSINFO_Bootparam_root_shadow}" ]]; then
+ set_root_password "${SYSINFO_Bootparam_root_shadow}"
+ echo "Set root password boot parameters."
+ elif [[ -n "${CONFIG_root_shadow}" ]]; then
+ set_root_password "${CONFIG_root_shadow}"
+ echo "Set root password from config."
+ else
+ echo "No root shadow entry in the config, cannot set."
+ fi
+
+ # Set authorized_keys for root
+ if [[ -n "${CONFIG_root_authorized_keys_file}" ]] \
+ && [[ -n "${CONFIG_config_inc_dir}" ]] \
+ && [[ -d "${CONFIG_config_inc_dir}" ]] \
+ && [[ -f "${CONFIG_config_inc_dir}/${CONFIG_root_authorized_keys_file}" ]]; then
+
+ mkdir -p /root/.ssh
+ cp "${CONFIG_config_inc_dir}/${CONFIG_root_authorized_keys_file}" /root/.ssh/authorized_keys
+ chmod 0600 /root/.ssh/authorized_keys
+ chmod 0700 /root/.ssh
+ fi
+
+ if [[ -n "${CONFIG_ntp_conf_file}" ]] \
+ && [[ -n "${CONFIG_config_inc_dir}" ]] \
+ && [[ -d "${CONFIG_config_inc_dir}" ]] \
+ && [[ -f "${CONFIG_config_inc_dir}/${CONFIG_ntp_conf_file}" ]]; then
+ #
+ # We were given a valid NTP configuration file, so use it without
+ # modification:
+ #
+ cp "${CONFIG_config_inc_dir}/${CONFIG_ntp_conf_file}" \
+ /etc/inet/ntp.conf
+ echo "Copied NTP configuration."
+ else
+ #
+ # If we have an admin network defined, allow time service from this
+ # network:
+ #
+ ntp_aflag=
+ if [[ -n ${CONFIG_admin_network} && -n ${CONFIG_admin_netmask} ]]; then
+ if [[ "${CONFIG_admin_network}" != "..." ]]; then
+ ntp_aflag="-a ${CONFIG_admin_network}/${CONFIG_admin_netmask}"
+ fi
+ fi
+
+ #
+ # If we were given a list of servers, use it:
+ #
+ ntp_hosts="${CONFIG_ntp_hosts}"
+ if [[ -z "${ntp_hosts}" ]]; then
+ #
+ # Otherwise, use the default SmartOS vendor pool from the NTP
+ # Pool Project:
+ #
+ ntp_hosts='0.smartos.pool.ntp.org'
+ fi
+
+ #
+ # Generate NTP configuration:
+ #
+ if ! /smartdc/lib/ntp_config -f /etc/inet/ntp.conf \
+ -s "${ntp_hosts}" ${ntp_aflag}; then
+ echo "FATAL: could not configure NTP" >&2
+ exit ${SMF_EXIT_ERR_CONFIG}
+ fi
+ echo "Generated NTP configuration."
+ fi
+
+ # set the keymap. For dvorak for instance
+ if [[ -n ${CONFIG_default_keymap} ]]; then
+ /usr/bin/loadkeys ${CONFIG_default_keymap}
+ fi
+
+ #
+ # In SmartOS, disabling SMT via the boot option is a pain, so we support a
+ # config option in /usbkey/config, the official mechanism for permanent
+ # configuration. We'd like to do this earlier but we have to wait for
+ # /usbkey to be mounted first. This does imply we've potentially handed out
+ # "too many" interrupts for the set of CPUs remaining online.
+ #
+ if [[ -n $(/bin/bootparams | grep '^smartos=true') ]]; then
+ if [[ "$CONFIG_smt_enabled" = "false" ]]; then
+ psradm -aS || exit $SMF_EXIT_ERR_FATAL
+ fi
+ fi
+
+ # Enable virtual terminals to support interactive installation
+ vtdaemon="svc:/system/vtdaemon"
+ svccfg -s ${vtdaemon} setprop options/hotkeys=true
+ svcadm refresh ${vtdaemon}
+ svcadm enable ${vtdaemon}
+ svcadm enable svc:/system/console-login:vt2
+ svcadm enable svc:/system/console-login:vt3
+ svcadm enable svc:/system/console-login:vt4
+ svcadm enable svc:/system/console-login:vt5
+ svcadm enable svc:/system/console-login:vt6
+
+ # force update of sysinfo (and dump to stdout so we have in the log)
+ sysinfo -f
+
+ ;;
+
+'stop')
+ ;;
+
+*)
+ echo "Usage: $0 { start | stop }"
+ exit $SMF_EXIT_ERR_FATAL
+ ;;
+esac
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/svc/milestone/smartdc-config.xml b/usr/src/cmd/svc/milestone/smartdc-config.xml
new file mode 100644
index 0000000000..bf84d1991b
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/smartdc-config.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2011 Joyent, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='smartdc:config'>
+
+<!--
+ This service applies inital configuration for the GZ in smartdc.
+-->
+<service
+ name='system/smartdc/config'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <single_instance />
+
+ <!--
+ dependency/dependent info
+ We need to wait for fs-joyent to be done so we can access the USB key
+ We need to run before sysconfig so interactive configuration can talk
+ on the console
+ (sysconfig)
+ We don't want anything else running which spews on console
+ (system/identy)
+ We don't want manifest import scribbling on the console while running
+ (manifest-import)
+ network/physical can't run without a config file
+ (network/physical)
+ -->
+ <dependency
+ name='filesystem-joyent'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/filesystem/smartdc' />
+ </dependency>
+
+ <!--
+ We don't want ssh starting if we haven't updated the passwords/keys
+ -->
+ <dependent
+ name='ssh_multi-user-server'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/ssh' />
+ </dependent>
+
+ <!-- Make ntp wait so we can setup the config. -->
+ <dependent
+ name='ntp'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/ntp' />
+ </dependent>
+
+ <dependent
+ name='headnode_config'
+ grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value='svc:/milestone/sysconfig' />
+ </dependent>
+
+ <dependent
+ name='identity'
+ grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/identity:node' />
+ </dependent>
+
+ <dependent
+ name='headnode_no_output'
+ grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/manifest-import' />
+ </dependent>
+
+ <dependent
+ name='network-physical'
+ grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/physical:default' />
+ </dependent>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/smartdc-config %m'
+ timeout_seconds='0'>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/lib/svc/method/smartdc-config %m'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring' value='transient' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ SmartDC live-image config management service
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='smartdc' section='5' manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/milestone/smartdc-init b/usr/src/cmd/svc/milestone/smartdc-init
new file mode 100755
index 0000000000..1b2a550095
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/smartdc-init
@@ -0,0 +1,246 @@
+#!/bin/bash
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2018, Joyent, Inc.
+#
+
+export PS4='[\D{%FT%TZ}] ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+set -o xtrace
+
+. /lib/svc/share/smf_include.sh
+. /lib/sdc/config.sh
+
+# Make sure working directory is / to prevent unmounting problems.
+cd /
+PATH=/usr/sbin:/usr/bin; export PATH
+
+wait_and_clear()
+{
+ while [ true ]; do
+ # It seems like jobs -p can miscount if we don't run jobs first
+ jobs >/dev/null
+ local cnt=`jobs -p | wc -l`
+ [ $cnt -eq 0 ] && break
+ for s in `svcs -x | nawk '{
+ if ($1 ~ /^svc:/) nm=$1
+ if ($1 == "State:" && $2 == "maintenance") print nm
+ }'`
+ do
+ svcadm clear $s
+ done
+ sleep 1
+ done
+}
+
+# Sets the default firewall rules for a node (unless they're already set)
+set_default_fw_rules() {
+ local fw_default_v
+ if [[ -f /var/fw/.default_rules_setup ]]; then
+ read fw_default_v < /var/fw/.default_rules_setup
+ else
+ fw_default_v=0
+ fi
+
+ # Handle empty files from before we started versioning default rules
+ if [[ -z $fw_default_v ]]; then
+ fw_default_v=1
+ fi
+
+ if [[ $fw_default_v -lt 1 ]]; then
+ /usr/sbin/fwadm add -f - <<RULES
+{
+ "rules": [
+ {
+ "description": "allow all ICMPv4 types",
+ "rule": "FROM any TO all vms ALLOW icmp type all",
+ "enabled": true,
+ "global": true
+ }
+ ]
+}
+RULES
+ [[ $? -ne 0 ]] && return 1
+ echo 1 > /var/fw/.default_rules_setup
+ fi
+
+ if [[ $fw_default_v -lt 2 ]]; then
+ /usr/sbin/fwadm add -f - <<RULES
+{
+ "rules": [
+ {
+ "description": "allow all ICMPv6 types",
+ "rule": "FROM any TO all vms ALLOW icmp6 type all",
+ "enabled": true,
+ "global": true
+ }
+ ]
+}
+RULES
+ [[ $? -ne 0 ]] && return 1
+ echo 2 > /var/fw/.default_rules_setup
+ fi
+}
+
+configure_fwadm()
+{
+ if [[ ! -d /var/log/fw/logs ]]; then
+ mkdir -p /var/log/fw/logs
+ mv /var/log/fw/*-*.log /var/log/fw/logs
+ fi
+
+ # See also OS-2635
+ if [[ -f /var/log/fw/fw.log.0 ]]; then
+ for file in /var/log/fw/fw.log.[0-9]*; do
+ mv ${file} "/var/log/fw/fwadm_$(uname -n)_$(stat -c "%y" ${file} | cut -d'.' -f1 | tr ' ' 'T').log"
+ done
+ fi
+ if [[ -f /var/log/fw/fw.log ]]; then
+ mv /var/log/fw/fw.log /var/log/fw/fwadm.log
+ fi
+
+ if [[ ! -e /var/log/fw/fwadm.log ]]; then
+ touch /var/log/fw/fwadm.log
+ fi
+}
+
+configure_vmadm()
+{
+ # ensure /var/log/vm exists for VM.log logs
+ mkdir -p /var/log/vm/logs
+
+ # See also OS-2635
+ if [[ -f /var/log/vm/vm.log.0 ]]; then
+ for file in /var/log/vm/vm.log.[0-9]*; do
+ mv ${file} "/var/log/vm/vmadm_$(uname -n)_$(stat -c "%y" ${file} | cut -d'.' -f1 | tr ' ' 'T').log"
+ done
+ fi
+ if [[ -f /var/log/vm/vm.log ]]; then
+ mv /var/log/vm/vm.log /var/log/vm/vmadm.log
+ fi
+
+ # need to create this file so rotation works
+ if [[ ! -e /var/log/vm/vmadm.log ]]; then
+ touch /var/log/vm/vmadm.log
+ fi
+}
+
+update_root_password()
+{
+
+ enc_password=`nawk -F= '{
+ if ($1 == "root_shadow")
+ print substr($2, 2, length($2) - 2)
+ }' /opt/smartdc/config/node.config`
+
+ [[ -z "$enc_password" ]] && return 0
+
+ sed -e "s|^root:[^\:]*:|root:${enc_password}:|" /etc/shadow \
+ >/etc/shadow.new \
+ && chmod 400 /etc/shadow.new \
+ && mv /etc/shadow.new /etc/shadow
+}
+
+# Loads config file for the node. These are the config values from the headnode
+# plus authorized keys and anything else we want.
+# This function is only invoked on a compute node.
+install_config()
+{
+ # On standalone machines we don't do this update
+ [[ -n $(/usr/bin/bootparams | grep "^standalone=true") ]] && return 0
+
+ load_sdc_config
+
+ curl -k -o /tmp/node.config --silent \
+ "http://${CONFIG_assets_admin_ip}/extra/joysetup/node.config"
+
+ [[ ! -f /tmp/node.config ]] && return 0
+ grep datacenter_name /tmp/node.config >/dev/null 2>&1
+ if [ $? != 0 ]; then
+ # There is no valid config file served by the assets zone
+ rm -f /tmp/node.config
+ return 0
+ fi
+
+ # Install the file if the local copy is different
+ diff /tmp/node.config /opt/smartdc/config/node.config >/dev/null 2>&1
+ if [ $? != 0 ]; then
+ printf "Updating config file\n" >/dev/console
+ mkdir -p /opt/smartdc/config
+ mv /tmp/node.config /opt/smartdc/config
+ update_root_password
+ else
+ rm -f /tmp/node.config
+ fi
+}
+
+case "$1" in
+'start')
+
+ # Always setup socket filter no matter what happens next.
+ /sbin/soconfig -F datafilt datafilt prog '2:2:0,2:2:6,26:2:0,26:2:6'
+
+ USBMOUNT=
+
+ # If we're not importing the pools, we shouldn't try to setup as a headnode
+ # (since there'll be no zpool)
+ if /bin/bootparams | grep "^noimport=true" > /dev/null 2>&1; then
+ exit $SMF_EXIT_OK
+ fi
+
+ # If we're a headnode, we'll not have AMQP args on the cmdline, and we want
+ # to run an initial_script first anyway.
+ if /bin/bootparams | grep "^headnode=true" > /dev/null 2>&1; then
+ USBMOUNT=/mnt/`svcprop -p joyentfs/usb_mountpoint svc:/system/filesystem/smartdc:default`
+
+ # No config file (e.g. user quit during interactive configuration), so
+ # treat as if "noimport=true".
+ [[ ! -f $USBMOUNT/config ]] && exit $SMF_EXIT_OK
+
+ initial_script=${USBMOUNT}/$(grep "^initial_script=" $USBMOUNT/config.inc/generic 2>/dev/null | cut -d'=' -f2-)
+ if [ -n ${initial_script} ] && [ -e ${initial_script} ]; then
+ # Execute the script
+ ${initial_script}
+ result=$?
+ if [ ${result} -eq 2 ]; then
+ # we're rebooting, no need to start ur
+ echo "REBOOTING!" >> /dev/console
+ enable_ur="false"
+ elif [ ${result} -ne 0 ]; then
+ echo "WARNING: initial_script failed with exit code [${result}]."
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+ fi
+ elif /bin/bootparams | grep "^smartos=true" > /dev/null 2>&1; then
+ set_default_fw_rules
+ else
+ install_config
+ fi
+
+ configure_fwadm
+ configure_vmadm
+
+ if /bin/bootparams | grep "^headnode=true" > /dev/null 2>&1; then
+ /usr/sbin/umount $USBMOUNT
+ fi
+
+ ;;
+
+'stop')
+ ;;
+
+*)
+ echo "Usage: $0 { start | stop }"
+ exit $SMF_EXIT_ERR_FATAL
+ ;;
+esac
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/svc/milestone/smartdc-init.xml b/usr/src/cmd/svc/milestone/smartdc-init.xml
new file mode 100644
index 0000000000..266aac53df
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/smartdc-init.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2012 Joyent, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='Joyent:joyent'>
+
+<!--
+ This service imports the zone's zpool on bootup, before zones try to
+ start. It also sets up configuration data on that zpool, if necessary.
+-->
+<service
+ name='system/smartdc/init'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <single_instance />
+
+ <!--
+ dependency info
+ This depends on the system/zones svc which seems weird since that
+ svc runs late in boot because it depends on milestone/multi-user-server.
+ Our svc does the initial setup of the infrastructure zones on the
+ headnode so we need the system/zones svc to run first so that we can
+ install and boot the infrastructure zones. The reason this seems
+ weird is that this svc also sets up the zpool when we first boot,
+ before we reboot to install the infrastructure zones, so it might seem
+ like it should run early in boot, but it can't because of the zone
+ issue described above.
+
+ The dependency on network/physical is needed since all of the earlier
+ svcs which have a dependency on network/physical are using optional_all.
+ That makes sense for those svcs since they can come up without a
+ network, but for SmartOS, by this point we require the network to be
+ there.
+ -->
+ <dependency
+ name='zones'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/zones' />
+ </dependency>
+
+ <dependency
+ name='net-physical'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/physical' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/smartdc-init %m'
+ timeout_seconds='0'>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/lib/svc/method/smartdc-init %m'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring' value='transient' />
+ </property_group>
+
+ <!--
+ The zpool holding the zones (this must be imported).
+ -->
+ <property_group name='config' type='application'>
+ <propval name='zpool' type='astring' value='zones' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Joyent live-image management service
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='zones' section='5' manpath='/usr/share/man' />
+ <manpage
+ title='zpool'
+ section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/milestone/smartdc-ur b/usr/src/cmd/svc/milestone/smartdc-ur
new file mode 100755
index 0000000000..2c32482368
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/smartdc-ur
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010-2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+
+set -o xtrace
+
+. /lib/svc/share/smf_include.sh
+. /lib/sdc/config.sh
+
+PATH=/usr/sbin:/usr/bin; export PATH
+
+if [[ -n "$(/bin/bootparams | grep "^standalone=true")" ||
+ -n "$(/bin/bootparams | grep "^smartos=true")" ]]; then
+ # Standalone and SmartOS systems do not need ur
+ svcadm disable "${SMF_FMRI}"
+ exit $SMF_EXIT_OK
+fi
+
+case "$1" in
+'start')
+ #
+ # Grab AMQP parameters from the kernel command line or headnode config
+ #
+
+ load_sdc_config
+ load_sdc_sysinfo
+
+ if [[ -n ${SYSINFO_Bootparam_rabbitmq} ]]; then
+ rabbit=${SYSINFO_Bootparam_rabbitmq}
+ fi
+ if [[ -z ${rabbit} ]] && [[ -n ${CONFIG_rabbitmq} ]]; then
+ rabbit=${CONFIG_rabbitmq}
+ fi
+
+ if [[ -z $rabbit ]]; then
+ echo "unable to find AMQP parameters!"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+
+ export AMQP_LOGIN=$(echo $rabbit | cut -d: -f1)
+ export AMQP_PASSWORD=$(echo $rabbit | cut -d: -f2)
+ export AMQP_HOST=$(echo $rabbit | cut -d: -f3)
+ export AMQP_PORT=$(echo $rabbit | cut -d: -f4)
+ export NODE_PATH=/usr/node/node_modules
+
+ /usr/bin/ctrun -l child -o noorphan /smartdc/ur-agent/ur-agent 2>&1 &
+
+ ;;
+
+'stop')
+ ;;
+
+*)
+ echo "Usage: $0 { start | stop }"
+ exit $SMF_EXIT_ERR_FATAL
+ ;;
+esac
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/svc/milestone/smartdc-ur.xml b/usr/src/cmd/svc/milestone/smartdc-ur.xml
new file mode 100644
index 0000000000..7ee78dcb02
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/smartdc-ur.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-->
+
+<!--
+ Copyright (c) 2014, Joyent, Inc.
+-->
+
+<service_bundle type="manifest" name="ur">
+ <service name="smartdc/agent/ur" type="service" version="0.0.1">
+
+ <create_default_instance enabled="true"/>
+ <single_instance/>
+
+ <dependency name="smartdc-init" grouping="require_all" restart_on="error" type="service">
+ <service_fmri value="svc:/milestone/single-user"/>
+ </dependency>
+
+ <exec_method
+ type="method"
+ name="start"
+ exec="/lib/svc/method/smartdc-ur %m"
+ timeout_seconds="60">
+ <method_context>
+ <method_credential user="root" group="staff"/>
+ </method_context>
+ </exec_method>
+
+ <exec_method type="method" name="restart" exec=":kill" timeout_seconds="60">
+ <method_context>
+ <method_credential user="root" group="staff"/>
+ </method_context>
+ </exec_method>
+
+ <exec_method type="method" name="stop" exec=":kill" timeout_seconds="60">
+ <method_context>
+ <method_credential user="root" group="staff"/>
+ </method_context>
+ </exec_method>
+
+ <property_group name="startd" type="framework">
+ <propval name="ignore_error" type="astring" value="core,signal"/>
+ </property_group>
+
+ <property_group name="application" type="application">
+ </property_group>
+
+ <stability value="Evolving"/>
+
+ <template>
+ <common_name>
+ <loctext xml:lang="C">Ur Agent (node)</loctext>
+ </common_name>
+ </template>
+
+ </service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/milestone/sysidtool-net b/usr/src/cmd/svc/milestone/sysidtool-net
new file mode 100755
index 0000000000..538d17bba1
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/sysidtool-net
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# This exists solely to support the service on older SmartOS zone images.
+
+exit 0
diff --git a/usr/src/cmd/svc/milestone/sysidtool-system b/usr/src/cmd/svc/milestone/sysidtool-system
new file mode 100755
index 0000000000..538d17bba1
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/sysidtool-system
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# This exists solely to support the service on older SmartOS zone images.
+
+exit 0
diff --git a/usr/src/cmd/svc/profile/Makefile b/usr/src/cmd/svc/profile/Makefile
index 2b00542413..8c44470471 100644
--- a/usr/src/cmd/svc/profile/Makefile
+++ b/usr/src/cmd/svc/profile/Makefile
@@ -23,6 +23,7 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright 2019 Peter Tribble.
+# Copyright 2019 Joyent, Inc.
#
include ../../Makefile.cmd
@@ -32,6 +33,7 @@ FILEMODE = 0444
ROOTPROFILE = $(ROOT)/etc/svc/profile
PROFILESRCS = \
+ generic.xml \
generic_open.xml \
generic_limited_net.xml \
inetd_generic.xml \
@@ -60,7 +62,7 @@ TEST = /usr/bin/test
LISTSVCS = listsvcs.pl
install: all $(PROFILES)
- $(RM) $(ROOTPROFILE)/platform.xml
+ $(CP) platform_none.xml $(ROOTPROFILE)/platform.xml
# SUNW,Sun-Fire-V890
$(RM) $(ROOTPROFILE)/platform_SUNW,Sun-Fire-V890.xml
$(LN) $(ROOTPROFILE)/platform_SUNW,Sun-Fire-880.xml \
@@ -87,7 +89,7 @@ $(CHECK_OPEN) $(CHECK_LMTD): \
@$(COMM) -23 $@.enabled $@.all | $(TEE) $@.notcovered
@$(TEST) ! -s $@.notcovered && $(TOUCH) $@
-lint _msg:
+_msg:
clobber clean:
$(RM) $(CHECK_OPEN)* $(CHECK_LMTD)*
diff --git a/usr/src/cmd/svc/profile/generic.xml b/usr/src/cmd/svc/profile/generic.xml
new file mode 100644
index 0000000000..61232545dd
--- /dev/null
+++ b/usr/src/cmd/svc/profile/generic.xml
@@ -0,0 +1,397 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ Copyright 2019 Joyent, Inc.
+
+ The purpose of the limited_net profile is to provide a set of
+ active services that allow one to connect to the machine via ssh
+ (requires sshd). The services which are deactivated here are those
+ that are at odds with this goal. Those which are activated are
+ explicit requirements for the goal's satisfaction.
+
+ NOTE: Service profiles delivered by this package are not editable,
+ and their contents will be overwritten by package or patch
+ operations, including operating system upgrade. Make customizations
+ in a distinct file. The paths, /etc/svc/profile/site.xml and
+ /var/svc/profile/site.xml, are distinguished locations for site-specific
+ service profile, treated otherwise equivalently to this file.
+-->
+<service_bundle type='profile' name='generic_limited_net'
+ xmlns:xi='http://www.w3.org/2003/XInclude' >
+
+ <!--
+ svc.startd(1M) services
+ -->
+ <service name='system/cryptosvc' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/coreadm' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/metainit' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='system/cron' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/dbus' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/extended-accounting' version='1' type='service'>
+ <instance name='flow' enabled='false'/>
+ <instance name='process' enabled='false'/>
+ <instance name='task' enabled='false'/>
+ <instance name='net' enabled='false'/>
+ </service>
+ <service name='system/identity' version='1' type='service'>
+ <instance name='domain' enabled='true'/>
+ </service>
+ <service name='system/intrd' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/keymap' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/picl' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/sac' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='system/scheduler' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/system-log' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/utmp' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/zones' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/rcap' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/hotplug' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='network/rpc/bind' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/name-service-cache' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='network/netmask' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/status' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/nlockmgr' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/client' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/server' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/rquota' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/cbd' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/nfs/mapid' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/smb/client' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='network/ssh' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='network/smtp' version='1' type='service'>
+ <instance name='sendmail' enabled='false'/>
+ </service>
+ <service name='network/sendmail-client' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/inetd' version='1' type='restarter'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='system/filesystem/autofs' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='system/filesystem/rmvolmgr' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='system/power' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+
+ <service name='network/dns/multicast' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+ <service name='network/dhcp-server' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='network/ntp' version='1' type='service'>
+ <instance name='default' enabled='true' />
+ </service>
+ <service name='network/rarp' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='network/slp' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='network/security/kadmin' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='network/security/krb5_prop' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='network/security/krb5kdc' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+
+ <service name='application/management/net-snmp' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/management/seaport' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/management/snmpdx' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/management/wbem' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/print/ipp-listener' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/print/ppd-cache-update' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/print/rfc1179' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/cups/in-lpd' version='1' type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='application/stosreg' version='1' type='service'>
+ <instance name='default' enabled='true' />
+ </service>
+
+ <!--
+ default inetd(1M) services
+ -->
+ <service name='network/finger' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/ftp' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/login' version='1' type='service'>
+ <instance name='rlogin' enabled='false'/>
+ <instance name='klogin' enabled='false'/>
+ <instance name='eklogin' enabled='false'/>
+ </service>
+ <service name='network/shell' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ <instance name='kshell' enabled='false'/>
+ </service>
+ <service name='network/telnet' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ non-default inetd(1M) services
+ -->
+ <service name='network/uucp' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/chargen' version='1' type='service'>
+ <instance name='stream' enabled='false'/>
+ <instance name='dgram' enabled='false'/>
+ </service>
+ <service name='network/daytime' version='1' type='service'>
+ <instance name='stream' enabled='false'/>
+ <instance name='dgram' enabled='false'/>
+ </service>
+ <service name='network/discard' version='1' type='service'>
+ <instance name='stream' enabled='false'/>
+ <instance name='dgram' enabled='false'/>
+ </service>
+ <service name='network/echo' version='1' type='service'>
+ <instance name='stream' enabled='false'/>
+ <instance name='dgram' enabled='false'/>
+ </service>
+ <service name='network/time' version='1' type='service'>
+ <instance name='stream' enabled='false'/>
+ <instance name='dgram' enabled='false'/>
+ </service>
+ <service name='network/comsat' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rexec' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/talk' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/stdiscover' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/stlisten' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ default inetd(1M) RPC services enabled
+ -->
+ <service name='network/rpc/gss' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/mdcomm' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/smserver' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/security/ktkt_warn' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ default inetd(1M) RPC services disabled
+ -->
+ <service name='network/rpc/rstat' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/rusers' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/meta' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/metamed' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/metamh' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ non-default inetd(1M) RPC services disabled
+ -->
+ <service name='network/rpc/rex' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/spray' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+ <service name='network/rpc/wall' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ Disable Avahi mDNS bridge service
+ -->
+ <service name='system/avahi-bridge-dsd' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ Enable CDE/ToolTalk/GDM services.
+ -->
+ <service name='network/rpc/cde-ttdbserver' version='1' type='service'>
+ <instance name='tcp' enabled='false' />
+ </service>
+ <service name='application/graphical-login/gdm' version='1'
+ type='service'>
+ <instance name='default' enabled='false' />
+ </service>
+ <service name='network/rpc/cde-calendar-manager' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ Disable X11 services.
+ -->
+ <service name='application/x11/xfs' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ pkg.depotd service
+ -->
+ <service name='system/pkgserv' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <!--
+ Enable VNC config service for xVM
+ -->
+ <service name='system/xvm/vnc-config' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='system/xvm/ipagent' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='application/print/service-selector' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='system/dumpadm' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
+
+ <service name='system/metasync' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='application/font/fc-cache' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='system/consolekit' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='application/opengl/ogl-select' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+ <service name='system/hal' version='1' type='service'>
+ <instance name='default' enabled='false'/>
+ </service>
+
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/shell/smf_include.sh b/usr/src/cmd/svc/shell/smf_include.sh
index 4acbed7d90..a5e3431d5b 100644
--- a/usr/src/cmd/svc/shell/smf_include.sh
+++ b/usr/src/cmd/svc/shell/smf_include.sh
@@ -22,6 +22,7 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2012 Joyent, Inc. All rights reserved.
# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
# Copyright 2012 Joyent, Inc. All rights reserved.
#
diff --git a/usr/src/cmd/svc/startd/graph.c b/usr/src/cmd/svc/startd/graph.c
index f63be7f941..d514b19c38 100644
--- a/usr/src/cmd/svc/startd/graph.c
+++ b/usr/src/cmd/svc/startd/graph.c
@@ -145,6 +145,8 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <fm/libfmevent.h>
#include <libscf.h>
#include <libscf_priv.h>
@@ -4846,6 +4848,20 @@ vertex_subgraph_dependencies_shutdown(scf_handle_t *h, graph_vertex_t *v,
was_up = up_state(old_state);
now_up = up_state(v->gv_state);
+ if (halting != -1 && old_state == RESTARTER_STATE_DISABLED &&
+ v->gv_state != RESTARTER_STATE_DISABLED) {
+ /*
+ * We're halting and we have a svc which is transitioning to
+ * offline in parallel. This leads to a race condition where
+ * gt_enter_offline might re-enable the svc after we disabled
+ * it. Since we're halting, we want to ensure no svc ever
+ * transitions out of the disabled state. In this case, modify
+ * the flags to keep us on the halting path.
+ */
+ was_up = 0;
+ now_up = 0;
+ }
+
if (!was_up && now_up) {
++non_subgraph_svcs;
} else if (was_up && !now_up) {
@@ -6785,6 +6801,9 @@ repository_event_thread(void *unused)
char *fmri = startd_alloc(max_scf_fmri_size);
char *pg_name = startd_alloc(max_scf_value_size);
int r;
+ int fd;
+
+ (void) pthread_setname_np(pthread_self(), "repository_event");
(void) pthread_setname_np(pthread_self(), "repository_event");
@@ -6809,6 +6828,14 @@ retry:
goto retry;
}
+ if ((fd = open("/etc/svc/volatile/startd.ready", O_RDONLY | O_CREAT,
+ S_IRUSR)) < 0) {
+ log_error(LOG_WARNING, "Couldn't create startd.ready file\n",
+ SCF_GROUP_FRAMEWORK, scf_strerror(scf_error()));
+ } else {
+ (void) close(fd);
+ }
+
/*CONSTCOND*/
while (1) {
ssize_t res;
diff --git a/usr/src/cmd/svc/startd/method.c b/usr/src/cmd/svc/startd/method.c
index 1c5549179c..2629b74210 100644
--- a/usr/src/cmd/svc/startd/method.c
+++ b/usr/src/cmd/svc/startd/method.c
@@ -100,34 +100,18 @@ static uint_t method_events[] = {
* method_record_start(restarter_inst_t *)
* Record a service start for rate limiting. Place the current time
* in the circular array of instance starts.
+ *
+ * Save the critical_failure_period and critical_failure_allowed with either
+ * the defaults or the svc properties startd/critical_failure_count and
+ * startd/critical_failure_period.
+ * ri_crit_fail_allowed is capped at RINST_START_TIMES.
*/
static void
method_record_start(restarter_inst_t *inst)
{
- int index = inst->ri_start_index++ % RINST_START_TIMES;
-
- inst->ri_start_time[index] = gethrtime();
-}
-
-/*
- * method_rate_critical(restarter_inst_t *)
- * Return true if the average start interval is less than the permitted
- * interval. The implicit interval defaults to RINST_FAILURE_RATE_NS and
- * RINST_START_TIMES but may be overridden with the svc properties
- * startd/critical_failure_count and startd/critical_failure_period
- * which represent the number of failures to consider and the amount of
- * time in seconds in which that number may occur, respectively. Note that
- * this time is measured as of the transition to 'enabled' rather than wall
- * clock time.
- * Implicit success if insufficient measurements for an average exist.
- */
-int
-method_rate_critical(restarter_inst_t *inst)
-{
+ int index;
+ uint_t critical_failure_allowed = RINST_START_TIMES;
hrtime_t critical_failure_period;
- uint_t critical_failure_count = RINST_START_TIMES;
- uint_t n = inst->ri_start_index;
- hrtime_t avg_ns = 0;
uint64_t scf_fr, scf_st;
scf_propvec_t *prop = NULL;
scf_propvec_t restart_critical[] = {
@@ -151,17 +135,48 @@ method_rate_critical(restarter_inst_t *inst)
* in seconds but tracked in ns
*/
critical_failure_period = (hrtime_t)scf_fr * NANOSEC;
- critical_failure_count = (uint_t)scf_st;
+ critical_failure_allowed = (uint_t)scf_st;
+
+ if (critical_failure_allowed > RINST_START_TIMES)
+ critical_failure_allowed = RINST_START_TIMES;
+ if (critical_failure_allowed < 1)
+ critical_failure_allowed = 1;
+
}
- if (inst->ri_start_index < critical_failure_count)
+
+ inst->ri_crit_fail_allowed = critical_failure_allowed;
+ inst->ri_crit_fail_period = critical_failure_period;
+
+ index = inst->ri_start_index++ % critical_failure_allowed;
+ inst->ri_start_time[index] = gethrtime();
+}
+
+/*
+ * method_rate_critical(restarter_inst_t *)
+ * Return true if the number of failures within the interval
+ * ri_crit_fail_period exceeds ri_crit_fail_allowed. The allowed failure
+ * count defaults to RINST_START_TIMES and the implicit interval defaults
+ * to RINST_FAILURE_RATE_NS but may be overridden with the svc properties
+ * startd/critical_failure_count and startd/critical_failure_period which
+ * represent the acceptable number of failures and the amount of time in
+ * seconds in which that number may occur, respectively. Note that this time
+ * is measured as of the transition to 'enabled' rather than wall clock
+ * time. Implicitly not critical if insufficient failures have occured.
+ */
+int
+method_rate_critical(restarter_inst_t *inst)
+{
+ uint_t n = inst->ri_start_index;
+ uint_t fail_allowed = inst->ri_crit_fail_allowed;
+ hrtime_t diff_ns;
+
+ if (n < fail_allowed)
return (0);
- avg_ns =
- (inst->ri_start_time[(n - 1) % critical_failure_count] -
- inst->ri_start_time[n % critical_failure_count]) /
- (critical_failure_count - 1);
+ diff_ns = inst->ri_start_time[(n - 1) % fail_allowed] -
+ inst->ri_start_time[n % fail_allowed];
- return (avg_ns < critical_failure_period);
+ return (diff_ns < inst->ri_crit_fail_period);
}
/*
diff --git a/usr/src/cmd/svc/startd/startd.h b/usr/src/cmd/svc/startd/startd.h
index d230ed1490..df3e98a27b 100644
--- a/usr/src/cmd/svc/startd/startd.h
+++ b/usr/src/cmd/svc/startd/startd.h
@@ -398,7 +398,7 @@ typedef enum {
#define RINST_RETAKE_MASK 0x0f000000
-#define RINST_START_TIMES 5 /* failures to consider */
+#define RINST_START_TIMES 10 /* up to 10 fails to consider */
#define RINST_FAILURE_RATE_NS 600000000000LL /* 1 failure/10 minutes */
#define RINST_WT_SVC_FAILURE_RATE_NS NANOSEC /* 1 failure/second */
@@ -420,6 +420,8 @@ typedef struct restarter_inst {
hrtime_t ri_start_time[RINST_START_TIMES];
uint_t ri_start_index; /* times started */
+ uint_t ri_crit_fail_allowed;
+ hrtime_t ri_crit_fail_period;
uu_list_node_t ri_link;
pthread_mutex_t ri_lock;
diff --git a/usr/src/cmd/svc/svcadm/Makefile b/usr/src/cmd/svc/svcadm/Makefile
index 07d22a2226..fae2142dac 100644
--- a/usr/src/cmd/svc/svcadm/Makefile
+++ b/usr/src/cmd/svc/svcadm/Makefile
@@ -21,6 +21,7 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2012, Joyent, Inc. All rights reserved.
#
PROG = svcadm
@@ -49,7 +50,11 @@ $(PROG): $(OBJS)
$(POFILE): $(POFILES)
cat $(POFILES) > $(POFILE)
-install: all $(ROOTUSRSBINPROG)
+install: all $(ROOTSBINPROG) $(ROOTUSRSBINPROG)
+
+$(ROOTUSRSBINPROG):
+ -$(RM) $@
+ -$(SYMLINK) ../../sbin/$(PROG) $@
clean:
$(RM) $(OBJS)
diff --git a/usr/src/cmd/svc/svccfg/Makefile b/usr/src/cmd/svc/svccfg/Makefile
index 16312b56f7..ece4cb765e 100644
--- a/usr/src/cmd/svc/svccfg/Makefile
+++ b/usr/src/cmd/svc/svccfg/Makefile
@@ -107,6 +107,7 @@ lint := SVCCFG_EXTRA_LIBS = -lscf -ll -luutil -lumem -lmd5 -lnvpair
LDLIBS += $(SVCCFG_EXTRA_LIBS)
+$(NATIVE_BUILD)NATIVE_LIBS += libl.so libumem.so libmd5.so libnvpair.so libc.so
$(NATIVE_BUILD)CC = $(NATIVECC)
$(NATIVE_BUILD)LD = $(NATIVELD)
$(NATIVE_BUILD)CFLAGS = $(NATIVE_CFLAGS)
diff --git a/usr/src/cmd/svc/svcs/Makefile b/usr/src/cmd/svc/svcs/Makefile
index aac8f82e0a..10cbbe2127 100644
--- a/usr/src/cmd/svc/svcs/Makefile
+++ b/usr/src/cmd/svc/svcs/Makefile
@@ -34,7 +34,7 @@ include ../../Makefile.cmd
include ../../Makefile.ctf
POFILE = $(PROG)_all.po
-LDLIBS += -lcontract -lscf -luutil -lumem -lnvpair -lzonecfg -lproc
+LDLIBS += -lcontract -lscf -luutil -lumem -lnvpair -lzonecfg -lsasl -lproc
CPPFLAGS += -I ../common
lint := LINTFLAGS = -mux
diff --git a/usr/src/cmd/svc/svcs/explain.c b/usr/src/cmd/svc/svcs/explain.c
index 331a5375fd..8a8dfa043b 100644
--- a/usr/src/cmd/svc/svcs/explain.c
+++ b/usr/src/cmd/svc/svcs/explain.c
@@ -196,6 +196,7 @@ static char *emsg_invalid_dep;
extern scf_handle_t *h;
extern char *g_zonename;
+extern char *g_zonealias;
/* ARGSUSED */
static int
@@ -2017,6 +2018,9 @@ print_service(inst_t *svcp, int verbose)
if (g_zonename != NULL)
(void) printf(gettext(" Zone: %s\n"), g_zonename);
+ if (g_zonealias != NULL)
+ (void) printf(gettext(" Alias: %s\n"), g_zonealias);
+
stime = svcp->stime.tv_sec;
tmp = localtime(&stime);
diff --git a/usr/src/cmd/svc/svcs/svcs.c b/usr/src/cmd/svc/svcs/svcs.c
index b6cf4f7fd1..402b40f4ca 100644
--- a/usr/src/cmd/svc/svcs/svcs.c
+++ b/usr/src/cmd/svc/svcs/svcs.c
@@ -60,6 +60,7 @@
#include <sys/ctfs.h>
#include <sys/stat.h>
+#include <sasl/saslutil.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -138,6 +139,9 @@ static int first_paragraph = 1; /* For -l mode. */
static char *common_name_buf; /* Sized for maximal length value. */
char *locale; /* Current locale. */
char *g_zonename; /* zone being operated upon */
+char *g_zonealias; /* alias for zone, if any */
+static char g_aliasdec[MAXPATHLEN / 4 * 3]; /* decoded zone alias buffer */
+static char g_aliasbuf[MAXPATHLEN]; /* base64 encoded zone alias buffer */
/*
* Pathname storage for path generated from the fmri.
@@ -244,7 +248,25 @@ ht_free(void)
static void
ht_init(void)
{
- assert(ht_buckets == NULL);
+ if (ht_buckets != NULL) {
+ /*
+ * If we already have a hash table (e.g., because we are
+ * processing multiple zones), destroy it before creating
+ * a new one.
+ */
+ struct ht_elem *elem, *next;
+ int i;
+
+ for (i = 0; i < ht_buckets_num; i++) {
+ for (elem = ht_buckets[i]; elem != NULL; elem = next) {
+ next = elem->next;
+ free((char *)elem->fmri);
+ free(elem);
+ }
+ }
+
+ free(ht_buckets);
+ }
ht_buckets_num = 8;
ht_buckets = safe_malloc(sizeof (*ht_buckets) * ht_buckets_num);
@@ -3684,6 +3706,24 @@ again:
assert(opt_zone == NULL || zids == NULL);
if (opt_zone == NULL) {
+ zone_status_t status;
+
+ if (zone_getattr(zids[zent], ZONE_ATTR_STATUS,
+ &status, sizeof (status)) < 0 ||
+ status != ZONE_IS_RUNNING) {
+ /*
+ * If this zone is not running or we cannot
+ * get its status, we do not want to attempt
+ * to bind an SCF handle to it, lest we
+ * accidentally interfere with a zone that
+ * is not yet running by looking up a door
+ * to its svc.configd (which could potentially
+ * block a mount with an EBUSY).
+ */
+ zent++;
+ goto nextzone;
+ }
+
if (getzonenamebyid(zids[zent++],
zonename, sizeof (zonename)) < 0) {
uu_warn(gettext("could not get name for "
@@ -3706,18 +3746,46 @@ again:
uu_die(gettext("invalid zone '%s'\n"), g_zonename);
scf_value_destroy(zone);
+
+ /*
+ * On SmartOS, there may be a base64-encoded string attribute
+ * named 'alias' associated with this zone. This alias is
+ * useful, so we attempt to make it available when we are
+ * displaying -xZ output. If it's not available or not
+ * decodable, we just ignore it.
+ */
+ if (g_zonename != NULL) {
+ unsigned len;
+ struct zone_attrtab zattrs;
+ zone_dochandle_t zhdl = zonecfg_init_handle();
+
+ bzero(&zattrs, sizeof (zattrs));
+ (void) strcpy(zattrs.zone_attr_name, "alias");
+
+ if (zhdl != NULL &&
+ zonecfg_get_handle(g_zonename, zhdl) == Z_OK &&
+ zonecfg_lookup_attr(zhdl, &zattrs) == Z_OK &&
+ zonecfg_get_attr_string(&zattrs, g_aliasbuf,
+ sizeof (g_aliasbuf)) == Z_OK &&
+ sasl_decode64(g_aliasbuf, strlen(g_aliasbuf),
+ g_aliasdec, sizeof (g_aliasdec), &len) == SASL_OK) {
+ g_aliasdec[len] = '\0';
+ g_zonealias = g_aliasdec;
+ } else {
+ g_zonealias = NULL;
+ }
+ zonecfg_fini_handle(zhdl);
+ }
}
if (scf_handle_bind(h) == -1) {
if (g_zonename != NULL) {
- uu_warn(gettext("Could not bind to repository "
+ if (show_zones)
+ goto nextzone;
+
+ uu_die(gettext("Could not bind to repository "
"server for zone %s: %s\n"), g_zonename,
scf_strerror(scf_error()));
-
- if (!show_zones)
- return (UU_EXIT_FATAL);
-
- goto nextzone;
}
uu_die(gettext("Could not bind to repository server: %s. "
@@ -3776,7 +3844,7 @@ again:
if (opt_mode == 'L') {
if ((err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
- print_log, NULL, &exit_status, uu_warn)) != 0) {
+ print_log, NULL, errarg, errfunc)) != 0) {
uu_warn(gettext("failed to iterate over "
"instances: %s\n"), scf_strerror(err));
exit_status = UU_EXIT_FATAL;
diff --git a/usr/src/cmd/syslogd/syslog.conf b/usr/src/cmd/syslogd/syslog.conf
index 1ed7a40d39..a894b3ed90 100644
--- a/usr/src/cmd/syslogd/syslog.conf
+++ b/usr/src/cmd/syslogd/syslog.conf
@@ -54,3 +54,7 @@ user.err /var/adm/messages
user.alert `root, operator'
user.emerg *
)
+
+auth.info /var/log/auth.log
+mail.info /var/log/postfix.log
+#local0.info /var/log/courier.log
diff --git a/usr/src/cmd/syslogd/system-log b/usr/src/cmd/syslogd/system-log
index b7608219fc..7f7ad92d96 100644
--- a/usr/src/cmd/syslogd/system-log
+++ b/usr/src/cmd/syslogd/system-log
@@ -21,10 +21,12 @@
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2016, Joyent, Inc. All rights reserved.
#
-# ident "%Z%%M% %I% %E% SMI"
OLD_CONF=/etc/default/syslogd
+DFLT_SUM="7c87d765805cc45a0dad9fb5c86cc4f2"
+CONF_SUM="$DFLT_SUM"
. /lib/svc/share/smf_include.sh
@@ -52,14 +54,72 @@ convert()
rm -f ${OLD_CONF}.new
}
-if [ ! -f /etc/syslog.conf ]; then
- echo "/etc/syslog.conf is missing. Exiting."
- exit $SMF_EXIT_ERR_CONFIG
+#
+# If the rsyslog.conf file doesn't exist and the syslog.conf file has not
+# been customized, generate the default rsyslog.conf.
+#
+generate_rsyslog_conf()
+{
+ if [ ! -f /etc/syslog.conf ]; then
+ return
+ fi
+
+ CONF_SUM=`nawk '{
+ if (substr($1, 1, 1) != "#" && NF != 0) print $0
+ }' /etc/syslog.conf | sum -x md5`
+
+ if [ "$CONF_SUM" != "$DFLT_SUM" ]; then
+ return
+ fi
+
+ cat <<-DONE >/etc/rsyslog.conf
+ #
+ # Sample rsyslog configuration file
+ #
+
+ $ModLoad immark
+ $ModLoad imsolaris
+ $ModLoad imtcp
+ $ModLoad imudp
+
+ *.err;kern.notice;auth.notice /dev/sysmsg
+ *.err;kern.debug;daemon.notice;mail.crit /var/adm/messages
+
+ *.alert;kern.err;daemon.err operator
+ *.alert root
+
+ *.emerg *
+
+ mail.debug /var/log/syslog
+
+ auth.info /var/log/auth.log
+ mail.info /var/log/postfix.log
+ DONE
+}
+
+if [ ! -f /etc/rsyslog.conf -a -x /usr/sbin/rsyslogd ]; then
+ generate_rsyslog_conf
fi
-if [ ! -x /usr/sbin/syslogd ]; then
- echo "Executable /usr/sbin/syslogd not found. Exiting"
- exit $SMF_EXIT_ERR_CONFIG
+if [ -f /etc/rsyslog.conf ]; then
+ if [ ! -x /usr/sbin/rsyslogd ]; then
+ echo "Executable /usr/sbin/rsyslogd not found or not executable. Exiting."
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+else
+ #
+ # Fall back to old syslogd
+ #
+ echo "/etc/rsyslog.conf is missing. Using syslogd instead."
+ if [ ! -f /etc/syslog.conf ]; then
+ echo "/etc/syslog.conf is missing. Exiting."
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+
+ if [ ! -x /usr/sbin/syslogd ]; then
+ echo "Executable /usr/sbin/syslogd not found or not executable. Exiting."
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
fi
if smf_is_globalzone; then
@@ -80,6 +140,27 @@ if [ ! -f /var/adm/messages ]; then
/usr/bin/cp /dev/null /var/adm/messages
/usr/bin/chmod 0644 /var/adm/messages
fi
+
+if [ -f /etc/rsyslog.conf ]; then
+ #
+ # If we have a config file for the old syslogd, only run rsyslogd
+ # if there are no customizations in the old syslog.conf file.
+ #
+ if [ -f /etc/syslog.conf ]; then
+ CONF_SUM=`nawk '{
+ if (substr($1, 1, 1) != "#" && NF != 0) print $0
+ }' /etc/syslog.conf | sum -x md5`
+ fi
+
+ if [ "$CONF_SUM" == "$DFLT_SUM" ]; then
+ /usr/sbin/rsyslogd -c5 -n &
+ exit $SMF_EXIT_OK
+ fi
+fi
+
+#
+# Run the old syslogd
+#
remote=`awk -F= '
/^LOG_FROM_REMOTE=[yY][Ee][Ss]/ {print "true"}
/^LOG_FROM_REMOTE=[Nn][Oo]/ {print "false"}' < ${OLD_CONF}`
@@ -96,3 +177,10 @@ case ${remote} in
esac
/usr/sbin/syslogd >/dev/msglog 2>&1 &
+
+if [ -f /etc/rsyslog.conf ]; then
+ logger -p daemon.err \
+ "Not using rsyslogd because there is a custom /etc/syslog.conf file"
+fi
+
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/tail/Makefile b/usr/src/cmd/tail/Makefile
index 6f50c71fb7..7afc25b187 100644
--- a/usr/src/cmd/tail/Makefile
+++ b/usr/src/cmd/tail/Makefile
@@ -22,6 +22,7 @@ OBJS= forward.o misc.o read.o reverse.o tail.o
SRCS= $(OBJS:%.o=%.c)
include ../Makefile.cmd
+include ../Makefile.ctf
CLOBBERFILES= $(PROG)
CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
@@ -46,6 +47,10 @@ $(PROG): $(OBJS)
$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
$(POST_PROCESS)
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
install: all .WAIT $(ROOTPROG) $(ROOTXPG4PROG)
$(ROOTXPG4PROG):
diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c
index 6a77a9d9ce..c679988bd5 100644
--- a/usr/src/cmd/truss/print.c
+++ b/usr/src/cmd/truss/print.c
@@ -874,7 +874,9 @@ prt_mc4(private_t *pri, int raw, long val) /* print memcntl() (4th) argument */
return;
case MC_SYNC:
- if ((val & ~(MS_SYNC|MS_ASYNC|MS_INVALIDATE)) == 0) {
+ if ((val &
+ ~(MS_SYNC|MS_ASYNC|MS_INVALIDATE|MS_INVALCURPROC))
+ == 0) {
*(s = pri->code_buf) = '\0';
if (val & MS_SYNC)
(void) strlcat(s, "|MS_SYNC", CBSIZE);
@@ -883,6 +885,9 @@ prt_mc4(private_t *pri, int raw, long val) /* print memcntl() (4th) argument */
if (val & MS_INVALIDATE)
(void) strlcat(s, "|MS_INVALIDATE",
CBSIZE);
+ if (val & MS_INVALCURPROC)
+ (void) strlcat(s, "|MS_INVALCURPROC",
+ CBSIZE);
}
break;
@@ -2097,6 +2102,8 @@ udp_optname(private_t *pri, long val)
case UDP_EXCLBIND: return ("UDP_EXCLBIND");
case UDP_RCVHDR: return ("UDP_RCVHDR");
case UDP_NAT_T_ENDPOINT: return ("UDP_NAT_T_ENDPOINT");
+ case UDP_SRCPORT_HASH: return ("UDP_SRCPORT_HASH");
+ case UDP_SND_TO_CONNECTED: return ("UDP_SND_TO_CONNECTED");
default: (void) snprintf(pri->code_buf,
sizeof (pri->code_buf), "0x%lx",
@@ -2545,7 +2552,7 @@ prt_zga(private_t *pri, int raw, long val)
case ZONE_ATTR_BOOTARGS: s = "ZONE_ATTR_BOOTARGS"; break;
case ZONE_ATTR_BRAND: s = "ZONE_ATTR_BRAND"; break;
case ZONE_ATTR_FLAGS: s = "ZONE_ATTR_FLAGS"; break;
- case ZONE_ATTR_PHYS_MCAP: s = "ZONE_ATTR_PHYS_MCAP"; break;
+ case ZONE_ATTR_DID: s = "ZONE_ATTR_DID"; break;
}
}
diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c
index 343d18a120..9e4d1780f4 100644
--- a/usr/src/cmd/truss/systable.c
+++ b/usr/src/cmd/truss/systable.c
@@ -29,6 +29,9 @@
/* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
+/*
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@@ -1716,9 +1719,10 @@ const char * const afcodes[] = {
"POLICY", /* 29 */
"RDS", /* 30 */
"TRILL", /* 31 */
- "PACKET" /* 32 */
+ "PACKET", /* 32 */
+ "LX_NETLINK" /* 33 */
};
-#if MAX_AFCODES != 33
+#if MAX_AFCODES != 34
#error Need to update address-family table
#endif
diff --git a/usr/src/cmd/varpd/Makefile b/usr/src/cmd/varpd/Makefile
new file mode 100644
index 0000000000..ea37ac6f71
--- /dev/null
+++ b/usr/src/cmd/varpd/Makefile
@@ -0,0 +1,75 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+PROG= varpd
+OBJS = varpd.o
+SRCS = $(OBJS:%.o=../%.c)
+MANIFEST = varpd.xml
+ROOTLIBVARPD = $(ROOTLIB)/varpd
+ROOTLIBVARPDPROG= $(PROG:%=$(ROOTLIBVARPD)/%)
+
+
+include ../Makefile.cmd
+include ../Makefile.ctf
+
+ROOTMANIFESTDIR= $(ROOTSVCNETWORK)
+
+CLEANFILES += $(OBJS)
+CPPFLAGS += -D_REENTRANT
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lvarpd -lumem -lscf
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+
+#
+# Our debug only umem related functions cause lint to get confused.
+#
+LINTFLAGS += -erroff=E_NAME_DEF_NOT_USED2
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+lint: lint_PROG
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+check: $(CHKMANIFEST)
+
+clobber: clean
+ $(RM) $(PROG)
+
+install: $(PROG) $(ROOTLIBVARPDPROG) $(ROOTMANIFEST)
+
+$(ROOTLIBVARPD):
+ $(INS.dir)
+
+$(ROOTLIBVARPD)/%: % $(ROOTLIBVARPD)
+ $(INS.file)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/varpd/varpd.c b/usr/src/cmd/varpd/varpd.c
new file mode 100644
index 0000000000..896f39733a
--- /dev/null
+++ b/usr/src/cmd/varpd/varpd.c
@@ -0,0 +1,526 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2018 Joyent, Inc.
+ */
+
+/*
+ * virtual arp daemon -- varpd
+ *
+ * The virtual arp daemon is the user land counterpart to the overlay driver. To
+ * truly understand its purpose and how it fits into things, you should read the
+ * overlay big theory statement in uts/common/io/overlay/overlay.c.
+ *
+ * varod's purpose it to provide a means for looking up the destination on the
+ * underlay network for a host on an overlay network and to also be a door
+ * server such that dladm(1M) via libdladm can configure and get useful status
+ * information. The heavy lifting is all done by libvarpd and the various lookup
+ * plugins.
+ *
+ * When varpd first starts up, we take of chdiring into /var/run/varpd, which is
+ * also where we create /var/run/varpd.door, our door server. After that we
+ * daemonize and only after we daemonize do we go ahead and load plugins. The
+ * reason that we don't load plugins before daemonizing is that they could very
+ * well be creating threads and thus lose them all. In general, we want to make
+ * things easier on our children and not require them to be fork safe.
+ *
+ * Once it's spun up, the main varpd thread sits in sigsuspend and really just
+ * hangs out waiting for something, libvarpd handles everything else.
+ */
+
+#include <libvarpd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <limits.h>
+#include <sys/corectl.h>
+#include <signal.h>
+#include <strings.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <thread.h>
+#include <priv.h>
+#include <libscf.h>
+
+#define VARPD_EXIT_REQUESTED SMF_EXIT_OK
+#define VARPD_EXIT_FATAL SMF_EXIT_ERR_FATAL
+#define VARPD_EXIT_USAGE SMF_EXIT_ERR_CONFIG
+
+#define VARPD_RUNDIR "/var/run/varpd"
+#define VARPD_DEFAULT_DOOR "/var/run/varpd/varpd.door"
+
+#define VARPD_PG "varpd"
+#define VARPD_PROP_INC "include_path"
+
+static varpd_handle_t *varpd_handle;
+static const char *varpd_pname;
+static volatile boolean_t varpd_exit = B_FALSE;
+
+/*
+ * Debug builds are automatically wired up for umem debugging.
+ */
+#ifdef DEBUG
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents");
+}
+#endif /* DEBUG */
+
+static void
+varpd_vwarn(FILE *out, const char *fmt, va_list ap)
+{
+ int error = errno;
+
+ (void) fprintf(out, "%s: ", varpd_pname);
+ (void) vfprintf(out, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fprintf(out, ": %s\n", strerror(error));
+}
+
+static void
+varpd_fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ varpd_vwarn(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(VARPD_EXIT_FATAL);
+}
+
+static void
+varpd_dfatal(int dfd, const char *fmt, ...)
+{
+ int status = VARPD_EXIT_FATAL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ varpd_vwarn(stdout, fmt, ap);
+ va_end(ap);
+
+ /* Take a single shot at this */
+ (void) write(dfd, &status, sizeof (status));
+ exit(status);
+}
+
+/* ARGSUSED */
+static int
+varpd_plugin_walk_cb(varpd_handle_t *vph, const char *name, void *unused)
+{
+ (void) printf("loaded %s!\n", name);
+ return (0);
+}
+
+static int
+varpd_dir_setup(void)
+{
+ int fd;
+
+ if (mkdir(VARPD_RUNDIR, 0700) != 0) {
+ if (errno != EEXIST)
+ varpd_fatal("failed to create %s: %s", VARPD_RUNDIR,
+ strerror(errno));
+ }
+
+ fd = open(VARPD_RUNDIR, O_RDONLY);
+ if (fd < 0)
+ varpd_fatal("failed to open %s: %s", VARPD_RUNDIR,
+ strerror(errno));
+
+ if (fchown(fd, UID_NETADM, GID_NETADM) != 0)
+ varpd_fatal("failed to chown %s: %s\n", VARPD_RUNDIR,
+ strerror(errno));
+
+ return (fd);
+}
+
+/*
+ * Because varpd is generally run under SMF, we opt to keep its stdout and
+ * stderr to be whatever our parent set them up to be.
+ */
+static void
+varpd_fd_setup(void)
+{
+ int dupfd;
+
+ closefrom(STDERR_FILENO + 1);
+ dupfd = open(_PATH_DEVNULL, O_RDONLY);
+ if (dupfd < 0)
+ varpd_fatal("failed to open %s: %s", _PATH_DEVNULL,
+ strerror(errno));
+ if (dup2(dupfd, STDIN_FILENO) == -1)
+ varpd_fatal("failed to dup out stdin: %s", strerror(errno));
+}
+
+/*
+ * We borrow fmd's daemonization style. Basically, the parent waits for the
+ * child to successfully set up a door and recover all of the old configurations
+ * before we say that we're good to go.
+ */
+static int
+varpd_daemonize(int dirfd)
+{
+ char path[PATH_MAX];
+ struct rlimit rlim;
+ sigset_t set, oset;
+ int estatus, pfds[2];
+ pid_t child;
+ priv_set_t *pset;
+
+ /*
+ * Set a per-process core path to be inside of /var/run/varpd. Make sure
+ * that we aren't limited in our dump size.
+ */
+ (void) snprintf(path, sizeof (path),
+ "/var/run/varpd/core.%s.%%p", varpd_pname);
+ (void) core_set_process_path(path, strlen(path) + 1, getpid());
+
+ rlim.rlim_cur = RLIM_INFINITY;
+ rlim.rlim_max = RLIM_INFINITY;
+ (void) setrlimit(RLIMIT_CORE, &rlim);
+
+ /*
+ * Claim as many file descriptors as the system will let us.
+ */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ (void) setrlimit(RLIMIT_NOFILE, &rlim);
+ }
+
+ /*
+ * chdir /var/run/varpd
+ */
+ if (fchdir(dirfd) != 0)
+ varpd_fatal("failed to chdir to %s", VARPD_RUNDIR);
+
+
+ /*
+ * At this point block all signals going in so we don't have the parent
+ * mistakingly exit when the child is running, but never block SIGABRT.
+ */
+ if (sigfillset(&set) != 0)
+ abort();
+ if (sigdelset(&set, SIGABRT) != 0)
+ abort();
+ if (sigprocmask(SIG_BLOCK, &set, &oset) != 0)
+ abort();
+
+ /*
+ * Do the fork+setsid dance.
+ */
+ if (pipe(pfds) != 0)
+ varpd_fatal("failed to create pipe for daemonizing");
+
+ if ((child = fork()) == -1)
+ varpd_fatal("failed to fork for daemonizing");
+
+ if (child != 0) {
+ /* We'll be exiting shortly, so allow for silent failure */
+ (void) close(pfds[1]);
+ if (read(pfds[0], &estatus, sizeof (estatus)) ==
+ sizeof (estatus))
+ _exit(estatus);
+
+ if (waitpid(child, &estatus, 0) == child && WIFEXITED(estatus))
+ _exit(WEXITSTATUS(estatus));
+
+ _exit(VARPD_EXIT_FATAL);
+ }
+
+ /*
+ * Drop privileges here.
+ *
+ * We should make sure we keep around PRIV_NET_PRIVADDR and
+ * PRIV_SYS_DLCONFIG, but drop everything else; however, keep basic
+ * privs and have our child drop them.
+ *
+ * We should also run as netadm:netadm and drop all of our groups.
+ */
+ if (setgroups(0, NULL) != 0)
+ abort();
+ if (setgid(GID_NETADM) == -1 || seteuid(UID_NETADM) == -1)
+ abort();
+ if ((pset = priv_allocset()) == NULL)
+ abort();
+ priv_basicset(pset);
+ if (priv_delset(pset, PRIV_PROC_EXEC) == -1 ||
+ priv_delset(pset, PRIV_PROC_INFO) == -1 ||
+ priv_delset(pset, PRIV_PROC_FORK) == -1 ||
+ priv_delset(pset, PRIV_PROC_SESSION) == -1 ||
+ priv_delset(pset, PRIV_FILE_LINK_ANY) == -1 ||
+ priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1 ||
+ priv_addset(pset, PRIV_NET_PRIVADDR) == -1) {
+ abort();
+ }
+ /*
+ * Remove privs from the permitted set. That will cause them to be
+ * removed from the effective set. We want to make sure that in the case
+ * of a vulnerability, something can't get back in here and wreak more
+ * havoc. But if we want non-basic privs in the effective set, we have
+ * to request them explicitly.
+ */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) == -1)
+ abort();
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) == -1)
+ abort();
+
+ priv_freeset(pset);
+
+ if (close(pfds[0]) != 0)
+ abort();
+ if (setsid() == -1)
+ abort();
+ if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0)
+ abort();
+ (void) umask(0022);
+
+ return (pfds[1]);
+}
+
+static int
+varpd_setup_lookup_threads(void)
+{
+ int ret;
+ long i, ncpus = sysconf(_SC_NPROCESSORS_ONLN) * 2 + 1;
+
+ if (ncpus <= 0)
+ abort();
+ for (i = 0; i < ncpus; i++) {
+ thread_t thr;
+
+ ret = thr_create(NULL, 0,
+ (void *(*)(void *))libvarpd_overlay_lookup_run,
+ varpd_handle, THR_DETACHED | THR_DAEMON, &thr);
+ if (ret != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static void
+varpd_cleanup(void)
+{
+ varpd_exit = B_TRUE;
+}
+
+/*
+ * Load default information from SMF and apply any of if necessary. We recognize
+ * the following properties:
+ *
+ * varpd/include_path Treat these as a series of -i options.
+ *
+ * If we're not under SMF, just move on.
+ */
+static void
+varpd_load_smf(int dfd)
+{
+ char *fmri, *inc;
+ scf_simple_prop_t *prop;
+
+ if ((fmri = getenv("SMF_FMRI")) == NULL)
+ return;
+
+ if ((prop = scf_simple_prop_get(NULL, fmri, VARPD_PG,
+ VARPD_PROP_INC)) == NULL)
+ return;
+
+ while ((inc = scf_simple_prop_next_astring(prop)) != NULL) {
+ int err = libvarpd_plugin_load(varpd_handle, inc);
+ if (err != 0) {
+ varpd_dfatal(dfd, "failed to load from %s: %s\n",
+ inc, strerror(err));
+ }
+ }
+
+ scf_simple_prop_free(prop);
+}
+
+/*
+ * There are a bunch of things we need to do to be a proper daemon here.
+ *
+ * o Ensure that /var/run/varpd exists or create it
+ * o make stdin /dev/null (stdout?)
+ * o Ensure any other fds that we somehow inherited are closed, eg.
+ * closefrom()
+ * o Properly daemonize
+ * o Mask all signals except sigabrt before creating our first door -- all
+ * other doors will inherit from that.
+ * o Have the main thread sigsuspend looking for most things that are
+ * actionable...
+ */
+int
+main(int argc, char *argv[])
+{
+ int err, c, dirfd, dfd, i;
+ const char *doorpath = VARPD_DEFAULT_DOOR;
+ sigset_t set;
+ struct sigaction act;
+ int nincpath = 0, nextincpath = 0;
+ char **incpath = NULL;
+
+ varpd_pname = basename(argv[0]);
+
+ /*
+ * We want to clean up our file descriptors before we do anything else
+ * as we can't assume that libvarpd won't open file descriptors, etc.
+ */
+ varpd_fd_setup();
+
+ if ((err = libvarpd_create(&varpd_handle)) != 0) {
+ varpd_fatal("failed to open a libvarpd handle");
+ return (1);
+ }
+
+ while ((c = getopt(argc, argv, ":i:d:")) != -1) {
+ switch (c) {
+ case 'i':
+ if (nextincpath == nincpath) {
+ if (nincpath == 0)
+ nincpath = 16;
+ else
+ nincpath *= 2;
+ incpath = realloc(incpath, sizeof (char *) *
+ nincpath);
+ if (incpath == NULL) {
+ (void) fprintf(stderr, "failed to "
+ "allocate memory for the %dth "
+ "-I option: %s\n", nextincpath + 1,
+ strerror(errno));
+ }
+
+ }
+ incpath[nextincpath] = optarg;
+ nextincpath++;
+ break;
+ case 'd':
+ doorpath = optarg;
+ break;
+ default:
+ (void) fprintf(stderr, "unknown option: %c\n", c);
+ return (1);
+ }
+ }
+
+ dirfd = varpd_dir_setup();
+
+ (void) libvarpd_plugin_walk(varpd_handle, varpd_plugin_walk_cb, NULL);
+
+ dfd = varpd_daemonize(dirfd);
+
+ /*
+ * Now that we're in the child, go ahead and load all of our plug-ins.
+ * We do this, in part, because these plug-ins may need threads of their
+ * own and fork won't preserve those and we'd rather the plug-ins don't
+ * have to learn about fork-handlers.
+ */
+ for (i = 0; i < nextincpath; i++) {
+ err = libvarpd_plugin_load(varpd_handle, incpath[i]);
+ if (err != 0) {
+ varpd_dfatal(dfd, "failed to load from %s: %s\n",
+ incpath[i], strerror(err));
+ }
+ }
+
+ varpd_load_smf(dfd);
+
+ if ((err = libvarpd_persist_enable(varpd_handle, VARPD_RUNDIR)) != 0)
+ varpd_dfatal(dfd, "failed to enable varpd persistence: %s\n",
+ strerror(err));
+
+ if ((err = libvarpd_persist_restore(varpd_handle)) != 0)
+ varpd_dfatal(dfd, "failed to enable varpd persistence: %s\n",
+ strerror(err));
+
+ /*
+ * The ur-door thread will inherit from this signal mask. So set it to
+ * what we want before doing anything else. In addition, so will our
+ * threads that handle varpd lookups.
+ */
+ if (sigfillset(&set) != 0)
+ varpd_dfatal(dfd, "failed to fill a signal set...");
+
+ if (sigdelset(&set, SIGABRT) != 0)
+ varpd_dfatal(dfd, "failed to unmask SIGABRT");
+
+ if (sigprocmask(SIG_BLOCK, &set, NULL) != 0)
+ varpd_dfatal(dfd, "failed to set our door signal mask");
+
+ if ((err = varpd_setup_lookup_threads()) != 0)
+ varpd_dfatal(dfd, "failed to create lookup threads: %s\n",
+ strerror(err));
+
+ if ((err = libvarpd_door_server_create(varpd_handle, doorpath)) != 0)
+ varpd_dfatal(dfd, "failed to create door server at %s: %s\n",
+ doorpath, strerror(err));
+
+ /*
+ * At this point, finish up signal intialization and finally go ahead,
+ * notify the parent that we're okay, and enter the sigsuspend loop.
+ */
+ bzero(&act, sizeof (struct sigaction));
+ act.sa_handler = varpd_cleanup;
+ if (sigfillset(&act.sa_mask) != 0)
+ varpd_dfatal(dfd, "failed to fill sigaction mask");
+ act.sa_flags = 0;
+ if (sigaction(SIGHUP, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register HUP handler");
+ if (sigdelset(&set, SIGHUP) != 0)
+ varpd_dfatal(dfd, "failed to remove HUP from mask");
+ if (sigaction(SIGQUIT, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register QUIT handler");
+ if (sigdelset(&set, SIGQUIT) != 0)
+ varpd_dfatal(dfd, "failed to remove QUIT from mask");
+ if (sigaction(SIGINT, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register INT handler");
+ if (sigdelset(&set, SIGINT) != 0)
+ varpd_dfatal(dfd, "failed to remove INT from mask");
+ if (sigaction(SIGTERM, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register TERM handler");
+ if (sigdelset(&set, SIGTERM) != 0)
+ varpd_dfatal(dfd, "failed to remove TERM from mask");
+
+ err = 0;
+ (void) write(dfd, &err, sizeof (err));
+ (void) close(dfd);
+
+ for (;;) {
+ if (sigsuspend(&set) == -1)
+ if (errno == EFAULT)
+ abort();
+ if (varpd_exit == B_TRUE)
+ break;
+ }
+
+ libvarpd_door_server_destroy(varpd_handle);
+ libvarpd_destroy(varpd_handle);
+
+ return (VARPD_EXIT_REQUESTED);
+}
diff --git a/usr/src/cmd/varpd/varpd.xml b/usr/src/cmd/varpd/varpd.xml
new file mode 100644
index 0000000000..df7015a3d6
--- /dev/null
+++ b/usr/src/cmd/varpd/varpd.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+This file and its contents are supplied under the terms of the
+Common Development and Distribution License ("CDDL"), version 1.0.
+You may only use this file in accordance with the terms of version
+1.0 of the CDDL.
+
+A full copy of the text of the CDDL should have accompanied this
+source. A copy of the CDDL is also available via the Internet at
+http://www.illumos.org/license/CDDL.
+
+Copyright 2018, Joyent, Inc.
+-->
+
+<service_bundle type="manifest" name="illumos:varpd" >
+
+ <service name="network/varpd" type="service" version="1" >
+
+ <create_default_instance enabled="true" />
+
+ <single_instance/>
+
+ <dependency name="varpd-network-physical"
+ grouping="require_all"
+ restart_on="none"
+ type="service">
+ <service_fmri value="svc:/network/physical:default" />
+ </dependency>
+
+ <dependency name="varpd-device-local"
+ grouping="require_all"
+ restart_on="none"
+ type="service">
+ <service_fmri value="svc:/system/device/local:default" />
+ </dependency>
+
+ <exec_method
+ type="method"
+ name="start"
+ exec="/usr/lib/varpd/varpd"
+ timeout_seconds="60" />
+
+ <exec_method
+ type="method"
+ name="stop"
+ exec=":kill"
+ timeout_seconds="10" />
+
+ <property_group name='varpd' type='application'>
+ <property name='include_path' type='astring'>
+ <astring_list>
+ <value_node value='/usr/lib/varpd'/>
+ </astring_list>
+ </property>
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang="C">virtual ARP daemon
+ </loctext>
+ </common_name>
+ </template>
+ </service>
+</service_bundle>
diff --git a/usr/src/cmd/vi/port/Makefile b/usr/src/cmd/vi/port/Makefile
index f85351d89a..bd35a08e69 100644
--- a/usr/src/cmd/vi/port/Makefile
+++ b/usr/src/cmd/vi/port/Makefile
@@ -79,6 +79,9 @@ $(XPG6) := CFLAGS += -DXPG4 -DXPG6 -I$(SRC)/lib/libc/inc
CPPFLAGS += -DUSG -DSTDIO -DVMUNIX -DTABS=8 -DSINGLE -DTAG_STACK
+# vi intentionally uses foo[-1] as a sentinal value to q*column()
+$(__GNUC4)CERRWARN += -_gcc=-Wno-array-bounds
+
# vi maintains its own versions of various routines from libc and libcurses,
# so localize all symbols to avoid name space collisions.
LDFLAGS += $(MAPFILE.NGB:%=-M%)
diff --git a/usr/src/cmd/vi/port/ex_cmdsub.c b/usr/src/cmd/vi/port/ex_cmdsub.c
index 9004ac7271..7e2cd4740d 100644
--- a/usr/src/cmd/vi/port/ex_cmdsub.c
+++ b/usr/src/cmd/vi/port/ex_cmdsub.c
@@ -1740,7 +1740,7 @@ char *prompt;
/* In ex mode, let the system hassle with setting no echo */
if (!inopen)
- return (unsigned char *)getpass(prompt);
+ return (unsigned char *)getpass((const char *)prompt);
viprintf("%s", prompt); flush();
for (p=pbuf; (c = getkey())!='\n' && c!=EOF && c!='\r';) {
if (p < &pbuf[8])
diff --git a/usr/src/cmd/vndadm/Makefile b/usr/src/cmd/vndadm/Makefile
new file mode 100644
index 0000000000..2b9ca6c3c1
--- /dev/null
+++ b/usr/src/cmd/vndadm/Makefile
@@ -0,0 +1,67 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2018 Joyent, Inc. All rights reserved.
+#
+
+PROG= vndadm
+OBJS = vndadm.o
+SRCS = $(OBJS:%.o=../%.c)
+
+
+include ../Makefile.cmd
+include ../Makefile.ctf
+
+CLEANFILES += $(OBJS)
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lvnd
+LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+all := TARGET += all
+clean := TARGET += clean
+clobber := TARGET += clobber
+install := TARGET += install
+lint := TARGET += lint
+
+SUBDIRS = test
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean: $(SUBDIRS)
+ -$(RM) $(CLEANFILES)
+
+lint: lint_PROG $(SUBDIRS)
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+clobber: clean $(SUBDIRS)
+ $(RM) $(PROG)
+
+install: $(PROG) $(ROOTUSRSBINPROG) $(SUBDIRS)
+
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/vndadm/test/Makefile b/usr/src/cmd/vndadm/test/Makefile
new file mode 100644
index 0000000000..12ef2c3a3c
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+SUBDIRS = scripts tst
+
+include Makefile.subdirs
+include Makefile.com
diff --git a/usr/src/cmd/vndadm/test/Makefile.com b/usr/src/cmd/vndadm/test/Makefile.com
new file mode 100644
index 0000000000..cb096952ca
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/Makefile.com
@@ -0,0 +1,43 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+include $(SRC)/cmd/Makefile.cmd
+
+#
+# Force c99 for everything
+#
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+#
+# Deal with odd lint bits.
+#
+LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2
+
+#
+# Install related definitions
+#
+ROOTOPTPKG = $(ROOT)/opt/vndtest
+ROOTBIN = $(ROOTOPTPKG)/bin
+ROOTTST = $(ROOTOPTPKG)/tst
+ROOTTSTDIR = $(ROOTTST)/$(TSTDIR)
+ROOTTSTEXES = $(EXETESTS:%=$(ROOTTSTDIR)/%)
+ROOTTSTSH = $(SHTESTS:%=$(ROOTTSTDIR)/%)
+ROOTOUT = $(OUTFILES:%=$(ROOTTSTDIR)/%)
+ROOTTESTS = $(ROOTTSTEXES) $(ROOTTSTSH) $(ROOTOUT)
+FILEMODE = 0555
+LDLIBS = $(LDLIBS.cmd)
+LINTEXE = $(EXETESTS:%.exe=%.exe.ln)
diff --git a/usr/src/cmd/vndadm/test/Makefile.subdirs b/usr/src/cmd/vndadm/test/Makefile.subdirs
new file mode 100644
index 0000000000..957448c23b
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/Makefile.subdirs
@@ -0,0 +1,29 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+.KEEP_STATE:
+
+all := TARGET += all
+clean := TARGET += clean
+clobber := TARGET += clobber
+install := TARGET += install
+lint := TARGET += lint
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/vndadm/test/Makefile.targ b/usr/src/cmd/vndadm/test/Makefile.targ
new file mode 100644
index 0000000000..bcbd3c8f35
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/Makefile.targ
@@ -0,0 +1,59 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+$(ROOTOPTPKG):
+ $(INS.dir)
+
+$(ROOTBIN): $(ROOTOPTPKG)
+ $(INS.dir)
+
+$(ROOTBIN)/%: %.ksh $(ROOTBIN)
+ $(INS.rename)
+
+$(ROOTTST): $(ROOTOPTPKG)
+ $(INS.dir)
+
+$(ROOTTSTDIR): $(ROOTTST)
+ $(INS.dir)
+
+$(ROOTTSTDIR)/%.ksh: %.ksh $(ROOTTSTDIR)
+ $(INS.file)
+
+$(ROOTTSTDIR)/%.out: %.out $(ROOTTSTDIR)
+ $(INS.file)
+
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.exe: %.o $(SUPOBJS)
+ $(LINK.c) -o $@ $< $(SUPOBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(ROOTTSTDIR)/%.exe: %.exe $(ROOTTSTDIR)
+ $(INS.file)
+
+all: install
+
+%.exe.ln: %.c $(SUPOBJS)
+ $(LINT.c) $< $(LDLIBS)
+
+lint: $(LINTEXE)
+
+clean:
+ -$(RM) *.o $(CLEANFILES)
+
+clobber: clean
+ -$(RM) $(CLOBBERFILES)
diff --git a/usr/src/cmd/vndadm/test/scripts/Makefile b/usr/src/cmd/vndadm/test/scripts/Makefile
new file mode 100644
index 0000000000..d0f58918f9
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/scripts/Makefile
@@ -0,0 +1,28 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+SRCS = vndtest
+SCRIPTS = $(SRCS:%=$(ROOTBIN)/%)
+
+SCRIPTS := FILEMODE = 0555
+CLOBBERFILES = $(SCRIPTS)
+
+install: $(SCRIPTS)
+
+lint:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/vndadm/test/scripts/vndtest.ksh b/usr/src/cmd/vndadm/test/scripts/vndtest.ksh
new file mode 100755
index 0000000000..224306ffe9
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/scripts/vndtest.ksh
@@ -0,0 +1,298 @@
+#!/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+#
+# vnd test suite driver
+#
+unalias -a
+
+vt_arg0=$(basename $0)
+vt_root="$(dirname $0)/.."
+vt_ksh="/usr/bin/ksh"
+vt_outdir=
+vt_keep=
+vt_all=
+vt_tests=
+vt_stub=
+vt_vnics="vndtest1 vndtest2 vndtest3 vndtest4 vndtest5"
+vt_tnum=0
+vt_tfail=0
+vt_tsuc=0
+
+function usage
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] || echo "$msg" 2>&1
+ cat <<USAGE >&2
+Usage: $vt_arg0 [ -o dir ] [ -k ] [ -a | test ... ]
+
+ -o dir Sets 'dir' as the output directory
+ -a Runs all tests, ignores tests passed in
+ -k Keep output from all tests, not just failures
+ -m mdb binary to test
+USAGE
+ exit 2
+}
+
+function fatal
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$vt_arg0: $msg" >&2
+ exit 1
+}
+
+function setup_outdir
+{
+ vt_outdir="$vt_outdir/$vt_arg0.$$"
+ mkdir -p $vt_outdir || fatal "failed to make output dir $vt_outdir"
+}
+
+function setup_etherstub
+{
+ vt_ether="vndstub$$"
+
+ dladm create-etherstub -t $vt_ether || \
+ fatal "failed to create etherstub"
+}
+
+function cleanup_vnd
+{
+ typeset over=$1
+ typeset vnddevs vn
+
+ vnddevs=$(vndadm list -p -d: -o datalink,name)
+ [[ $? -eq 0 ]] || fatal "failed to list vnics"
+ for v in $vnddevs; do
+ vn=$(echo $v | awk 'BEGIN{ FS=":"}
+ { if ($1 == targ) { print $2 } }' targ=$over)
+ [[ -z "$vn" ]] && continue
+ vndadm destroy $vn || fatal "failed to destroy $vn"
+ done
+}
+
+function create_vnics
+{
+ for n in $vt_vnics; do
+ dladm create-vnic -t -l $vt_ether $n || fatal \
+ "failed to create vnic $n over $vt_ether"
+ done
+}
+
+function cleanup_vnics
+{
+ typeset nics vn
+
+ nics=$(dladm show-vnic -p -o over,link)
+ [[ $? -eq 0 ]] || fatal "failed to list vnics"
+ for n in $nics; do
+ vn=$(echo $n | awk 'BEGIN{ FS=":"}
+ { if ($1 == targ) { print $2 } }' targ=$vt_ether )
+ [[ -z "$vn" ]] && continue
+ cleanup_vnd $vn
+ #
+ # There may or may not be an IP device on our nics...
+ #
+ ifconfig $vn down unplumb 2>/dev/null || /bin/true
+ dladm delete-vnic $vn || fatal "failed to delete vnic $n"
+ done
+
+}
+
+function cleanup_etherstub
+{
+ cleanup_vnics
+ dladm delete-etherstub -t $vt_ether || \
+ fatal "failed to delete etherstub"
+}
+
+function run_single
+{
+ typeset name=$1
+ typeset expect base ext exe command odir res reason
+ typeset iserr
+
+ [[ -z "$name" ]] && fail "missing test to run"
+ base=${name##*/}
+ ext=${base##*.}
+ expect=${base%%.*}
+ odir="$vt_outdir/current"
+ [[ -z "$ext" ]] && fatal "found test without ext: $name"
+ [[ -z "$expect" ]] && fatal "found test without prefix: $name"
+
+ [[ "$expect" == "create" || "$expect" == "ecreate" ]] && create_vnics
+ if [[ "$expect" == "err" || "$expect" == "ecreate" ]]; then
+ iserr="yup"
+ else
+ iserr=""
+ fi
+
+ case "$ext" in
+ "ksh")
+ command="$vt_ksh ./$base"
+ ;;
+ "exe")
+ command="./$base"
+ ;;
+ "out")
+ #
+ # This is the file format for checking output against.
+ #
+ return 0
+ ;;
+ *)
+ echo "skipping test $name (unknown extensino)"
+ return 0
+ ;;
+ esac
+
+ echo "Executing test $name ... \c"
+ mkdir -p "$odir" >/dev/null || fatal "can't make output directory"
+ cd $(dirname $name) || fatal "failed to enter test directory"
+ $command $vt_vnics > "$odir/stdout" 2>"$odir/stderr"
+ res=$?
+ cd - > /dev/null || fatal "failed to leave test directory"
+
+ if [[ -f "$name.out" ]] && \
+ ! diff "$name.out" "$odir/stdout" >/dev/null; then
+ cp $name.out $odir/$base.out
+ reason="stdout mismatch"
+ elif [[ -n "$iserr" && $res -eq 0 ]]; then
+ reason="test exited $res, not non-zero"
+ elif [[ -z "$iserr" && $res -ne 0 ]]; then
+ reason="test exited $res, not zero"
+ fi
+
+ if [[ -n "$reason" ]]; then
+ echo "$reason"
+ ((vt_tfail++))
+ mv "$odir" "$vt_outdir/failure.$vt_tfail" || fatal \
+ "failed to move test output directory"
+ cp "$name" "$vt_outdir/failure.$vt_tfail/$(basename $name)" || \
+ fatal "failed to copy test into output directory"
+ else
+ echo "passed"
+ ((vt_tsuc++))
+ mv "$odir" "$vt_outdir/success.$vt_tsuc" || fatal \
+ "failed to move test directory"
+ fi
+
+ [[ "$expect" == "create" || "$expect" == "ecreate" ]] && cleanup_vnics
+
+ ((vt_tnum++))
+}
+
+function run_all
+{
+ typeset tests t dir
+
+ tests=$(ls -1 $vt_root/*/*/@(ecreate|create|tst|err).*.@(ksh|exe))
+ for t in $tests; do
+ run_single $t
+ done
+}
+
+function welcome
+{
+ cat <<WELCOME
+Starting tests...
+output directory: $vt_outdir
+WELCOME
+}
+
+function cleanup
+{
+ [[ -n "$vt_keep" ]] && return
+ rm -rf "$vt_outdir"/success.* || fatal \
+ "failed to remove successful test cases"
+ if [[ $vt_tfail -eq 0 ]]; then
+ rmdir "$vt_outdir" || fatal \
+ "failed to remove test output directory"
+ fi
+}
+
+function goodbye
+{
+ cat <<EOF
+
+-------------
+Results
+-------------
+
+Tests passed: $vt_tsuc
+Tests failed: $vt_tfail
+Tests ran: $vt_tnum
+
+EOF
+ if [[ $vt_tfail -eq 0 ]]; then
+ echo "Congrats, vnd isn't completely broken, the tests pass".
+ else
+ echo "Some tests failed, you have some work to do."
+ fi
+}
+
+while getopts ":ahko:m:" c $@; do
+ case "$c" in
+ a)
+ vt_all="y"
+ ;;
+ k)
+ vt_keep="y"
+ ;;
+ o)
+ vt_outdir="$OPTARG"
+ ;;
+ h)
+ usage
+ ;;
+ :)
+ usage "option requires an argument -- $OPTARG"
+ ;;
+ *)
+ usage "invalid option -- $OPTARG"
+ ;;
+ esac
+done
+
+shift $((OPTIND-1))
+
+[[ $(zonename) != "global" ]] && fatal "vndtest only runs in the global zone"
+
+[[ -z "$vt_all" && $# == 0 ]] && usage "no tests to run"
+
+[[ -z "$vt_outdir" ]] && vt_outdir="$PWD"
+
+setup_outdir
+setup_etherstub
+welcome
+
+if [[ ! -z "$vt_all" ]]; then
+ run_all
+else
+ for t in $@; do
+ [[ -f $t ]] || fatal "cannot find test $t"
+ run_single $t
+ done
+fi
+
+cleanup_etherstub
+goodbye
+cleanup
+
+#
+# Exit 1 if we have tests that return non-zero
+#
+[[ $vt_tfai -eq 0 ]]
diff --git a/usr/src/cmd/vndadm/test/tst/Makefile b/usr/src/cmd/vndadm/test/tst/Makefile
new file mode 100644
index 0000000000..9b1ba29429
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+SUBDIRS = cmd dld ioctl lib
+
+include ../Makefile.subdirs
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/Makefile b/usr/src/cmd/vndadm/test/tst/cmd/Makefile
new file mode 100644
index 0000000000..1ca20bf749
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/Makefile
@@ -0,0 +1,34 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+TSTDIR = cmd
+COMMONSH = cmd.common.ksh
+SHTESTS = $(COMMONSH) \
+ create.list.ksh \
+ create.sdev.ksh \
+ create.setbuf.ksh \
+ ecreate.destroy.ksh \
+ ecreate.setbadprop.ksh \
+ ecreate.setbadvalue.ksh \
+ ecreate.setbuftoobig.ksh \
+ ecreate.setrdonlyprop.ksh
+
+OUTFILES = create.list.ksh.out
+
+include ../../Makefile.com
+
+install: $(ROOTTESTS)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/cmd.common.ksh b/usr/src/cmd/vndadm/test/tst/cmd/cmd.common.ksh
new file mode 100644
index 0000000000..31e4e8bf5c
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/cmd.common.ksh
@@ -0,0 +1,33 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Common ksh-based utilities
+#
+
+vt_arg0=$(basename $0)
+
+function fatal
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$vt_arg0: $msg" >&2
+ exit 1
+}
+
+[[ -z "$1" ]] && fatal "missing required vnic"
+[[ -z "$2" ]] && fatal "missing required vnic"
+[[ -z "$3" ]] && fatal "missing required vnic"
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh b/usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh
new file mode 100644
index 0000000000..fdec9a85be
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh
@@ -0,0 +1,30 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Basic device listing
+#
+
+. ./cmd.common.ksh
+
+#
+# Use what we hope is a relatively unique name
+#
+cl_name="triforceofcourage0"
+vndadm create -l $1 $cl_name || fatal "failed to create vnd device"
+vndadm list -p -o name,zone $cl_name
+vndadm list -p -d: -o zone,name $cl_name
+vndadm destroy $cl_name || fatal "failed to destroy vnd device"
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh.out b/usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh.out
new file mode 100644
index 0000000000..d208b38aab
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/create.list.ksh.out
@@ -0,0 +1,2 @@
+triforceofcourage0 global
+global:triforceofcourage0
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/create.sdev.ksh b/usr/src/cmd/vndadm/test/tst/cmd/create.sdev.ksh
new file mode 100644
index 0000000000..b816ade1de
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/create.sdev.ksh
@@ -0,0 +1,25 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Verify that our sdev links exist
+#
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd"
+[[ -c /dev/vnd/$1 ]] || fatal "missing link"
+[[ -c /dev/vnd/zone/$(zonename)/$1 ]] || fatal "missing per-zone link"
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/create.setbuf.ksh b/usr/src/cmd/vndadm/test/tst/cmd/create.setbuf.ksh
new file mode 100644
index 0000000000..d50edbead4
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/create.setbuf.ksh
@@ -0,0 +1,34 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Set and validate the buffer size properties. Valiate that we can set
+# the value using the various number analogues, eg. 1024K, etc.
+#
+set -o pipefail
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd device"
+vndadm set $1 rxbuf=1M
+cur=$(vndadm get -p $1 rxbuf | nawk '{ print $4 }')
+[[ $? -eq 0 ]] || fatal "failed to get rxbuf"
+[[ $cur -eq 1048576 ]] || fatal "rxbuf is $cur, not 1M"
+
+vndadm set $1 txbuf=1024K
+cur=$(vndadm get -p $1 rxbuf | nawk '{ print $4 }')
+[[ $? -eq 0 ]] || fatal "failed to get txbuf"
+[[ $cur -eq 1048576 ]] || fatal "txbuf is $cur, not 1M"
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/ecreate.destroy.ksh b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.destroy.ksh
new file mode 100644
index 0000000000..e3c4931018
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.destroy.ksh
@@ -0,0 +1,25 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure that destroy on a previously destroyed link fails
+#
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd device"
+vndadm destroy $1 || fatal "failed to destroy vnd device"
+vndadm destroy $1
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadprop.ksh b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadprop.ksh
new file mode 100644
index 0000000000..30c27575b1
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadprop.ksh
@@ -0,0 +1,24 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure that we can't set a non-existant proprety
+#
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd device"
+vndadm set $1 ganon=ganondorf
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadvalue.ksh b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadvalue.ksh
new file mode 100644
index 0000000000..056b24a817
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbadvalue.ksh
@@ -0,0 +1,24 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure that we can't set something to a garbage value
+#
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd device"
+vndadm set $1 rxbuf=hello
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbuftoobig.ksh b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbuftoobig.ksh
new file mode 100644
index 0000000000..551e20461c
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setbuftoobig.ksh
@@ -0,0 +1,24 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure that we can't set a buffer value to a ridiculous size
+#
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd device"
+vndadm set $1 rxsize=1T
diff --git a/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setrdonlyprop.ksh b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setrdonlyprop.ksh
new file mode 100644
index 0000000000..4beb53e227
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/cmd/ecreate.setrdonlyprop.ksh
@@ -0,0 +1,24 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure that we can't set a read only property.
+#
+
+. ./cmd.common.ksh
+
+vndadm create $1 || fatal "failed to bring up vnd device"
+vndadm set $1 mintu=100
diff --git a/usr/src/cmd/vndadm/test/tst/dld/Makefile b/usr/src/cmd/vndadm/test/tst/dld/Makefile
new file mode 100644
index 0000000000..3088812630
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/dld/Makefile
@@ -0,0 +1,27 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+TSTDIR = dld
+COMMONSH = dld.common.ksh
+SHTESTS = $(COMMONSH) \
+ ecreate.ipfirst.ksh \
+ ecreate.vndfirst.ksh \
+ create.reuse.ksh
+
+include ../../Makefile.com
+
+install: $(ROOTTESTS)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/vndadm/test/tst/dld/create.reuse.ksh b/usr/src/cmd/vndadm/test/tst/dld/create.reuse.ksh
new file mode 100644
index 0000000000..bc2ffde7f6
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/dld/create.reuse.ksh
@@ -0,0 +1,31 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure that we can reuse a data link
+#
+
+. ./dld.common.ksh
+
+dld_nic=$1
+[[ -z "$1" ]] && fatal "missing required vnic"
+
+vndadm create $dld_nic || fatal "failed to bring up vnd"
+vndadm destroy $dld_nic || fatal "failed to bring down vnd"
+ifconfig $dld_nic plumb up || fatal "failed to bring up IP"
+ifconfig $dld_nic down unplumb || fatal "failed to bring down IP"
+vndadm create $dld_nic || fatal "failed to bring up vnd"
+vndadm destroy $dld_nic || fatal "failed to bring down vnd"
diff --git a/usr/src/cmd/vndadm/test/tst/dld/dld.common.ksh b/usr/src/cmd/vndadm/test/tst/dld/dld.common.ksh
new file mode 100644
index 0000000000..7a2e0a8e2b
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/dld/dld.common.ksh
@@ -0,0 +1,29 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Common ksh-based utilities
+#
+
+vt_arg0=$(basename $0)
+
+function fatal
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$vt_arg0: $msg" >&2
+ exit 1
+}
diff --git a/usr/src/cmd/vndadm/test/tst/dld/ecreate.ipfirst.ksh b/usr/src/cmd/vndadm/test/tst/dld/ecreate.ipfirst.ksh
new file mode 100644
index 0000000000..e6409781cb
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/dld/ecreate.ipfirst.ksh
@@ -0,0 +1,27 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure vnd fails to come up when IP is up
+#
+
+. ./dld.common.ksh
+
+dld_nic=$1
+[[ -z "$1" ]] && fatal "missing required vnic"
+
+ifconfig $dld_nic plumb up || fatal "failed to bring up IP"
+vndadm create $dld_nic
diff --git a/usr/src/cmd/vndadm/test/tst/dld/ecreate.vndfirst.ksh b/usr/src/cmd/vndadm/test/tst/dld/ecreate.vndfirst.ksh
new file mode 100644
index 0000000000..ee7a13c09c
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/dld/ecreate.vndfirst.ksh
@@ -0,0 +1,27 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Make sure IP fails to come up when vnd is up
+#
+
+. ./dld.common.ksh
+
+dld_nic=$1
+[[ -z "$1" ]] && fatal "missing required vnic"
+
+vndadm create $dld_nic || fatal "failed to bring up vnd"
+ifconfig $dld_nic plumb up
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/Makefile b/usr/src/cmd/vndadm/test/tst/ioctl/Makefile
new file mode 100644
index 0000000000..fe074f32b0
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/Makefile
@@ -0,0 +1,49 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+TSTDIR = ioctl
+EXETESTS = \
+ create.attach.exe \
+ create.attachnolink.exe \
+ create.badlinkname.exe \
+ create.doublelink.exe \
+ create.gioctlattach.exe \
+ create.link.exe \
+ create.linkexists.exe \
+ create.ngioctlfault.exe \
+ create.nopriv1.exe \
+ create.nopriv2.exe \
+ create.nopriv3.exe \
+ create.nopriv4.exe \
+ create.olink.exe \
+ create.olinknopriv.exe \
+ create.rmenolink.exe \
+ tst.attachrdonly.exe \
+ tst.basicopenctl.exe \
+ tst.badioctl.exe \
+ tst.gioctlfault.exe \
+ tst.gioctlnattach.exe \
+ tst.openctlbadflags.exe
+SHTESTS = \
+ tst.iocsize.ksh
+SUPBOBJS =
+
+CLOBBERFILES = $(EXETESTS)
+
+include ../../Makefile.com
+
+install: $(ROOTTESTS)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.attach.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.attach.c
new file mode 100644
index 0000000000..d7bca5cce3
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.attach.c
@@ -0,0 +1,63 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Simply attach a nic
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.attachnolink.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.attachnolink.c
new file mode 100644
index 0000000000..43c6c99af5
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.attachnolink.c
@@ -0,0 +1,67 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Try to attach to a non-existant vnic
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ /*
+ * All datalink names have numbers, so we can pick a datalink which
+ * doesn't exist by not using numbers...
+ */
+ (void) strlcpy(via.via_name, "enolink", VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == -1);
+ assert(via.via_errno == VND_E_NODATALINK);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.badlinkname.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.badlinkname.c
new file mode 100644
index 0000000000..e3a067d5ce
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.badlinkname.c
@@ -0,0 +1,119 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Test that we can't link a nic with invalid names
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+static const char *names[] = {
+ /* Reserved names */
+ "ctl",
+ "zone",
+ /* Invalid characters */
+ "The fight of the century",
+ "Link/Ganon",
+ "happens@7pm",
+ "#testing",
+ "asdf!!",
+ "power&courage&wisdom",
+ "over9000?",
+ "you're",
+ "100$",
+ "(function",
+ "x)",
+ "2^128",
+ "1++",
+ "No.",
+ "99%",
+ "*****",
+ "r|m",
+ "=0",
+ "`p0",
+ "goodbye~",
+ "however;",
+ "\"hesaid",
+ "shesaid\'",
+ /* emoji pile of poo */
+ "\xF0\x9F\x92\xA9",
+ NULL
+};
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret, i;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+ vnd_ioc_unlink_t viu;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ for (i = 0; names[i] != NULL; i++) {
+ (void) strlcpy(vil.vil_name, names[i], VND_NAMELEN);
+ (void) fprintf(stderr, "Trying to create [%s]\n", names[i]);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == -1);
+ assert(vil.vil_errno == VND_E_BADNAME);
+ }
+
+ /* Finally, the missing null terminator */
+ for (i = 0; i < VND_NAMELEN; i++)
+ vil.vil_name[i] = 'a';
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == -1);
+ assert(vil.vil_errno == VND_E_BADNAME);
+
+ viu.viu_errno = 0;
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(ret == -1);
+ assert(viu.viu_errno == VND_E_NOTLINKED);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.doublelink.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.doublelink.c
new file mode 100644
index 0000000000..dcf4f311e9
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.doublelink.c
@@ -0,0 +1,82 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Link a nic, first should work, second will fail.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+ vnd_ioc_unlink_t viu;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(vil.vil_name, argv[1], VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == 0);
+ assert(vil.vil_errno == 0);
+
+ (void) strlcpy(vil.vil_name, "dup", VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == -1);
+ assert(vil.vil_errno == VND_E_LINKED);
+ viu.viu_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(ret == 0);
+ assert(viu.viu_errno == 0);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.gioctlattach.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.gioctlattach.c
new file mode 100644
index 0000000000..3d6f43377b
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.gioctlattach.c
@@ -0,0 +1,69 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Ensure that we can't run global ioctls on an attached handle
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ via.via_name[0] = 'a';
+ via.via_name[1] = '\0';
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == -1);
+ assert(via.via_errno == VND_E_ATTACHED);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.link.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.link.c
new file mode 100644
index 0000000000..16569d58cd
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.link.c
@@ -0,0 +1,76 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Link a nic
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+ vnd_ioc_unlink_t viu;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(vil.vil_name, argv[1], VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == 0);
+ assert(vil.vil_errno == 0);
+
+ viu.viu_errno = 0;
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(ret == 0);
+ assert(viu.viu_errno == 0);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.linkexists.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.linkexists.c
new file mode 100644
index 0000000000..4e3be0db5d
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.linkexists.c
@@ -0,0 +1,90 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Try to create two devices with the same link name.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, fd2, ret;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+ vnd_ioc_unlink_t viu;
+
+ if (argc < 3) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+ fd2 = open(VND_PATH, O_RDWR);
+ assert(fd2 > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(via.via_name, argv[2], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd2, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(vil.vil_name, "dup", VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == 0);
+ assert(vil.vil_errno == 0);
+
+ (void) strlcpy(vil.vil_name, "dup", VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd2, VND_IOC_LINK, &vil);
+ assert(ret == -1);
+ assert(vil.vil_errno == VND_E_LINKEXISTS);
+
+ viu.viu_errno = 0;
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(ret == 0);
+ assert(viu.viu_errno == 0);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.ngioctlfault.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.ngioctlfault.c
new file mode 100644
index 0000000000..bf174f1a8f
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.ngioctlfault.c
@@ -0,0 +1,96 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Pass bad addresses to all of our non-global ioctls
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+static int requests[] = {
+ VND_IOC_LINK,
+ VND_IOC_UNLINK,
+ VND_IOC_GETRXBUF,
+ VND_IOC_SETRXBUF,
+ VND_IOC_GETTXBUF,
+ VND_IOC_SETTXBUF,
+ VND_IOC_GETMINTU,
+ VND_IOC_GETMAXTU,
+ VND_IOC_GETMAXBUF,
+ -1
+};
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret, i;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+ vnd_ioc_unlink_t viu;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(vil.vil_name, argv[1], VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == 0);
+ assert(vil.vil_errno == 0);
+
+ for (i = 0; requests[i] != -1; i++) {
+ ret = ioctl(fd, requests[i], (void *)(uintptr_t)i);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+ }
+
+
+ viu.viu_errno = 0;
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(ret == 0);
+ assert(viu.viu_errno == 0);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv1.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv1.c
new file mode 100644
index 0000000000..6d5ad0eec2
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv1.c
@@ -0,0 +1,69 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to attach a device without PRIV_NET_CONFIG
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <priv.h>
+#include <string.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdio.h>
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ priv_set_t *ps;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ ps = priv_allocset();
+ assert(ps != NULL);
+ assert(priv_addset(ps, PRIV_SYS_NET_CONFIG) == 0);
+ assert(setppriv(PRIV_OFF, PRIV_PERMITTED, ps) == 0);
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd >= 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == -1);
+ assert(errno == EPERM);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv2.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv2.c
new file mode 100644
index 0000000000..6b38f159a0
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv2.c
@@ -0,0 +1,69 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to attach a device without PRIV_NET_RAWACCESS
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <priv.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ priv_set_t *ps;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ ps = priv_allocset();
+ assert(ps != NULL);
+ assert(priv_addset(ps, PRIV_NET_RAWACCESS) == 0);
+ assert(setppriv(PRIV_OFF, PRIV_PERMITTED, ps) == 0);
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd >= 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == -1);
+ assert(errno == EPERM);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv3.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv3.c
new file mode 100644
index 0000000000..a8c43fc46d
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv3.c
@@ -0,0 +1,70 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to attach a device without PRIV_NET_CONFIG and PRIV_NET_RAWACCESS
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <priv.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ priv_set_t *ps;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ ps = priv_allocset();
+ assert(ps != NULL);
+ assert(priv_addset(ps, PRIV_SYS_NET_CONFIG) == 0);
+ assert(priv_addset(ps, PRIV_NET_RAWACCESS) == 0);
+ assert(setppriv(PRIV_OFF, PRIV_PERMITTED, ps) == 0);
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd >= 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == -1);
+ assert(errno == EPERM);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv4.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv4.c
new file mode 100644
index 0000000000..aed0204544
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv4.c
@@ -0,0 +1,75 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to link a device without PRIV_NET_CONFIG
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <priv.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ priv_set_t *ps;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd >= 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+
+ ps = priv_allocset();
+ assert(ps != NULL);
+ assert(priv_addset(ps, PRIV_SYS_NET_CONFIG) == 0);
+ assert(setppriv(PRIV_OFF, PRIV_PERMITTED, ps) == 0);
+
+ (void) strlcpy(vil.vil_name, argv[1], VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == -1);
+ assert(errno == EPERM);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv5.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv5.c
new file mode 100644
index 0000000000..2db8ecc95f
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.nopriv5.c
@@ -0,0 +1,77 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to open a device without PRIV_NET_RAWACCESS
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <priv.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, fd2, ret;
+ priv_set_t *ps;
+ char *path;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd >= 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+
+ ps = priv_allocset();
+ assert(ps != NULL);
+ assert(priv_addset(ps, PRIV_SYS_NET_RAWACCESS) == 0);
+ assert(setppriv(PRIV_OFF, PRIV_PERMITTED, ps) == 0);
+
+ (void) asprintf(&path, "/dev/vnd/%s", argv[1]);
+ assert(path != NULL);
+ fd2 = open(path, O_RDWR);
+ assert(fd2 == -1);
+ assert(errno == EPERM);
+
+ free(path);
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.olink.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.olink.c
new file mode 100644
index 0000000000..0f9292bbae
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.olink.c
@@ -0,0 +1,77 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Open a /dev/vnd/%s link
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ char *path;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(vil.vil_name, argv[1], VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == 0);
+ assert(vil.vil_errno == 0);
+
+ ret = asprintf(&path, "/dev/vnd/%s", argv[1]);
+ assert(ret != -1);
+
+ ret = open(path, O_RDONLY);
+ assert(ret > 0);
+ assert(close(ret) == 0);
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.olinknopriv.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.olinknopriv.c
new file mode 100644
index 0000000000..338218e751
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.olinknopriv.c
@@ -0,0 +1,83 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to open a /dev/vnd/%s without PRIV_NET_RAWACCESS
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <priv.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ char *path;
+ priv_set_t *ps;
+ vnd_ioc_attach_t via;
+ vnd_ioc_link_t vil;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ (void) strlcpy(vil.vil_name, argv[1], VND_NAMELEN);
+ vil.vil_errno = 0;
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(ret == 0);
+ assert(vil.vil_errno == 0);
+
+ ret = asprintf(&path, "/dev/vnd/%s", argv[1]);
+ assert(ret != -1);
+
+ ps = priv_allocset();
+ assert(ps != NULL);
+ assert(priv_addset(ps, PRIV_NET_RAWACCESS) == 0);
+ assert(setppriv(PRIV_OFF, PRIV_PERMITTED, ps) == 0);
+
+ ret = open(path, O_RDWR);
+ assert(ret == -1);
+ assert(errno == EPERM);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/create.rmenolink.c b/usr/src/cmd/vndadm/test/tst/ioctl/create.rmenolink.c
new file mode 100644
index 0000000000..d44e6512a7
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/create.rmenolink.c
@@ -0,0 +1,69 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Verify that unlink fails when we're not linked.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+ vnd_ioc_unlink_t viu;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == 0);
+ assert(via.via_errno == 0);
+
+ viu.viu_errno = 0;
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(ret == -1);
+ assert(viu.viu_errno == VND_E_NOTLINKED);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.attachrdonly.c b/usr/src/cmd/vndadm/test/tst/ioctl/tst.attachrdonly.c
new file mode 100644
index 0000000000..29def6182d
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.attachrdonly.c
@@ -0,0 +1,63 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Fail to attach when /dev/vnd/ctl is opened read only.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ vnd_ioc_attach_t via;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= VND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDONLY);
+ assert(fd > 0);
+
+ (void) strlcpy(via.via_name, argv[1], VND_NAMELEN);
+ via.via_zoneid = 0;
+ via.via_errno = 0;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, &via);
+ assert(ret == -1);
+ assert(errno == EBADF);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.badioctl.c b/usr/src/cmd/vndadm/test/tst/ioctl/tst.badioctl.c
new file mode 100644
index 0000000000..f26722f035
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.badioctl.c
@@ -0,0 +1,79 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Throw a bunch of bad ioctls at us and make sure that we get ENOTTY.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <limits.h>
+#include <assert.h>
+
+/*
+ * We're including a bunch of bad header files that have ioctl numbers that we
+ * know we shouldn't.
+ */
+#include <sys/ipd.h>
+#include <sys/dtrace.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+/*
+ * A series of bad requests
+ */
+static int requests[] = {
+ 0,
+ 1,
+ 42,
+ 169,
+ 4096,
+ INT_MAX,
+ IPDIOC_CORRUPT,
+ IPDIOC_REMOVE,
+ DTRACEIOC_CONF,
+ DTRACEIOC_REPLICATE,
+ -1
+};
+
+int
+main(void)
+{
+ int fd, i;
+
+ fd = open(VND_PATH, O_RDONLY);
+ if (fd < 0) {
+ (void) fprintf(stderr, "failed to open %s read only: %s\n",
+ VND_PATH, strerror(errno));
+ return (1);
+ }
+
+ for (i = 0; requests[i] != -1; i++) {
+ int ret;
+ ret = ioctl(fd, requests[i], NULL);
+ assert(ret == -1);
+ assert(errno == ENOTTY);
+ }
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.basicopenctl.c b/usr/src/cmd/vndadm/test/tst/ioctl/tst.basicopenctl.c
new file mode 100644
index 0000000000..852ad5550f
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.basicopenctl.c
@@ -0,0 +1,76 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Ensure that we can do a basic open of the device for read, write, and
+ * read/write.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(void)
+{
+ int fd;
+
+ fd = open(VND_PATH, O_RDONLY);
+ if (fd < 0) {
+ (void) fprintf(stderr, "failed to open %s read only: %s\n",
+ VND_PATH, strerror(errno));
+ return (1);
+ }
+
+ if (close(fd) != 0) {
+ (void) fprintf(stderr, "failed to close vnd fd: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR);
+ if (fd < 0) {
+ (void) fprintf(stderr, "failed to open %s read/write: %s\n",
+ VND_PATH, strerror(errno));
+ return (1);
+ }
+
+ if (close(fd) != 0) {
+ (void) fprintf(stderr, "failed to close vnd fd: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_WRONLY);
+ if (fd < 0) {
+ (void) fprintf(stderr, "failed to open %s write only: %s\n",
+ VND_PATH, strerror(errno));
+ return (1);
+ }
+
+ if (close(fd) != 0) {
+ (void) fprintf(stderr, "failed to close vnd fd: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlfault.c b/usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlfault.c
new file mode 100644
index 0000000000..b581b5dd4c
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlfault.c
@@ -0,0 +1,78 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Pass pointers to arbitrary addresses and make sure we properly get EFAULT for
+ * all the global ioctls.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(void)
+{
+ int fd, ret;
+ vnd_ioc_attach_t *via;
+ vnd_ioc_list_t *vil;
+ vnd_ioc_buf_t *vib;
+
+ fd = open(VND_PATH, O_RDWR);
+ if (fd < 0) {
+ (void) fprintf(stderr, "failed to open %s r/w: %s\n", VND_PATH,
+ strerror(errno));
+ return (1);
+ }
+
+ via = (vnd_ioc_attach_t *)(uintptr_t)23;
+ vil = (vnd_ioc_list_t *)(uintptr_t)42;
+ vib = (vnd_ioc_buf_t *)(uintptr_t)169;
+
+ ret = ioctl(fd, VND_IOC_ATTACH, NULL);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+ ret = ioctl(fd, VND_IOC_LIST, NULL);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+ ret = ioctl(fd, VND_IOC_GETMAXBUF, NULL);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+
+ ret = ioctl(fd, VND_IOC_ATTACH, via);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+ ret = ioctl(fd, VND_IOC_LIST, vil);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+ ret = ioctl(fd, VND_IOC_GETMAXBUF, vib);
+ assert(ret == -1);
+ assert(errno == EFAULT);
+
+ assert(close(fd) == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlnattach.c b/usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlnattach.c
new file mode 100644
index 0000000000..98acffa194
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.gioctlnattach.c
@@ -0,0 +1,100 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Here we test that all the ioctls which require us to be on a local device
+ * fail to work. Specifically, the errno should be VND_E_NOTATTACHED
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <limits.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <sys/vnd.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+static int vib_ioc[] = {
+ VND_IOC_GETRXBUF,
+ VND_IOC_SETRXBUF,
+ VND_IOC_GETTXBUF,
+ VND_IOC_SETTXBUF,
+ VND_IOC_GETMINTU,
+ VND_IOC_GETMAXTU,
+ -1
+};
+
+int
+main(void)
+{
+ int fd, ret, i;
+ vnd_ioc_link_t vil;
+ vnd_ioc_unlink_t viu;
+ vnd_ioc_buf_t vib;
+ frameio_t *fio;
+ char buf[1];
+
+ fd = open(VND_PATH, O_RDWR);
+ if (fd < 0) {
+ (void) fprintf(stderr, "failed to open %s r/w: %s\n", VND_PATH,
+ strerror(errno));
+ return (1);
+ }
+
+ bzero(&vil, sizeof (vnd_ioc_link_t));
+ vil.vil_name[0] = 'a';
+ bzero(&viu, sizeof (vnd_ioc_unlink_t));
+ bzero(&vib, sizeof (vnd_ioc_buf_t));
+ fio = malloc(sizeof (frameio_t) + sizeof (framevec_t));
+ assert(fio != NULL);
+ fio->fio_version = FRAMEIO_CURRENT_VERSION;
+ fio->fio_nvpf = 1;
+ fio->fio_nvecs = 1;
+ fio->fio_vecs[0].fv_buf = buf;
+ fio->fio_vecs[0].fv_buflen = 1;
+
+ ret = ioctl(fd, VND_IOC_LINK, &vil);
+ assert(vil.vil_errno == VND_E_NOTATTACHED);
+ ret = ioctl(fd, VND_IOC_UNLINK, &viu);
+ assert(viu.viu_errno == VND_E_NOTLINKED);
+
+ for (i = 0; vib_ioc[i] != -1; i++) {
+ bzero(&vib, sizeof (vib));
+ ret = ioctl(fd, vib_ioc[i], &vib);
+ assert(vib.vib_errno == VND_E_NOTATTACHED);
+ }
+
+ /* The frameio ioctls only use standard errnos */
+ ret = ioctl(fd, VND_IOC_FRAMEIO_READ, fio);
+ assert(ret == -1);
+ assert(errno == ENXIO);
+ ret = ioctl(fd, VND_IOC_FRAMEIO_WRITE, fio);
+ assert(ret == -1);
+ assert(errno == ENXIO);
+
+ free(fio);
+ assert(close(fd) == 0);
+
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.iocsize.ksh b/usr/src/cmd/vndadm/test/tst/ioctl/tst.iocsize.ksh
new file mode 100644
index 0000000000..9b30043d47
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.iocsize.ksh
@@ -0,0 +1,54 @@
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# Ensure structure sizes for both ILP32 and LP64 are the same
+#
+
+vt_arg0=$(basename $0)
+vt_structs="vnd_ioc_attach_t vnd_ioc_link_t vnd_ioc_unlink_t"
+vt_structs="$vt_structs vnd_ioc_nonblock_t vnd_ioc_buf_t vnd_ioc_info_t"
+
+vt_t32="/tmp/vnd.iocsize.32.$$"
+vt_t64="/tmp/vnd.iocsize.64.$$"
+
+function fatal
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$vt_arg0: $msg" >&2
+ exit 1
+}
+
+function dump_types
+{
+ typeset file=$1
+ typeset lib=$2
+ typeset t
+
+ for t in $vn_structs; do
+ mdb -e \'::print -at $t\' $lib >> $file || fatal \
+ "failed to dump type $t from $lib"
+ done
+}
+
+rm -f $vt_t32 $vt_t64 || fatal "failed to cleanup old temp files"
+touch $vt_t32 $vt_t64 || fatal "failed to create temp files"
+
+dump_types $vt_t32 /usr/lib/libvnd.so.1
+dump_types $vt_t64 /usr/lib/64/libvnd.so.1
+
+diff $vt_t32 $vt_t64
diff --git a/usr/src/cmd/vndadm/test/tst/ioctl/tst.openctlbadflags.c b/usr/src/cmd/vndadm/test/tst/ioctl/tst.openctlbadflags.c
new file mode 100644
index 0000000000..65e48029b7
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/ioctl/tst.openctlbadflags.c
@@ -0,0 +1,88 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Make sure that we can't open the vnd control device with invalid flags.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+#define VND_PATH "/dev/vnd/ctl"
+
+int
+main(void)
+{
+ int fd;
+
+ fd = open(VND_PATH, O_RDONLY | O_EXCL);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_EXCL!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR | O_EXCL);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_EXCL!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_WRONLY | O_EXCL);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_EXCL!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDONLY | O_NDELAY);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_NDELAY!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR | O_NDELAY);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_NDELAY!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_WRONLY | O_NDELAY);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_NDELAY!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDONLY | O_NDELAY | O_EXCL);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_NDELAY | O_EXCL!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_RDWR | O_NDELAY | O_EXCL);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_NDELAY | O_EXCL!");
+ return (1);
+ }
+
+ fd = open(VND_PATH, O_WRONLY | O_NDELAY | O_EXCL);
+ if (fd != -1) {
+ (void) fprintf(stderr, "somehow opened vnd O_NDELAY | O_EXCL!");
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/Makefile b/usr/src/cmd/vndadm/test/tst/lib/Makefile
new file mode 100644
index 0000000000..d7a1ed8fa5
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/Makefile
@@ -0,0 +1,44 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+TSTDIR = lib
+EXETESTS = \
+ create.basic.exe \
+ create.badlink.exe \
+ create.badpropid.exe \
+ create.badpropsize.exe \
+ create.badzone.exe \
+ create.enomem.exe \
+ create.frameioeagain.exe \
+ create.open.exe \
+ create.propiter.exe \
+ create.proprdonly.exe \
+ err.badclose.exe \
+ tst.badopen.exe \
+ tst.strerror.exe \
+ tst.strsyserror.exe
+OUTFILES = tst.strerror.exe.out
+SHTESTS =
+SUPBOBJS =
+
+CLOBBERFILES = $(EXETESTS)
+
+include ../../Makefile.com
+
+LDLIBS += -lvnd
+
+install: $(ROOTTESTS)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.badlink.c b/usr/src/cmd/vndadm/test/tst/lib/create.badlink.c
new file mode 100644
index 0000000000..aefec3ed44
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.badlink.c
@@ -0,0 +1,39 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Make sure that we can't create something in the context of a datalink that
+ * doesn't exist.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <libvnd.h>
+
+int
+main(void)
+{
+ int syserr;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+
+ vhp = vnd_create(NULL, "foobar", "foobar", &vnderr, &syserr);
+ (void) printf("%d, %d\n", vnderr, syserr);
+ assert(vhp == NULL);
+ assert(vnderr == VND_E_NODATALINK);
+ assert(syserr == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.badpropid.c b/usr/src/cmd/vndadm/test/tst/lib/create.badpropid.c
new file mode 100644
index 0000000000..15334fa31c
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.badpropid.c
@@ -0,0 +1,76 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Make sure that we can't get and set nonexisting properties.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr, ret;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ ret = vnd_prop_get(vhp, VND_PROP_MAX, NULL, 0);
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_BADPROP);
+ assert(vnd_syserrno(vhp) == 0);
+
+ ret = vnd_prop_get(vhp, VND_PROP_MAX + 5, NULL, 0);
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_BADPROP);
+ assert(vnd_syserrno(vhp) == 0);
+
+ ret = vnd_prop_set(vhp, VND_PROP_MAX, NULL, 0);
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_BADPROP);
+ assert(vnd_syserrno(vhp) == 0);
+
+ ret = vnd_prop_set(vhp, VND_PROP_MAX + 5, NULL, 0);
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_BADPROP);
+ assert(vnd_syserrno(vhp) == 0);
+
+ ret = vnd_prop_writeable(VND_PROP_MAX, NULL);
+ assert(ret == -1);
+
+ ret = vnd_prop_writeable(VND_PROP_MAX + 5, NULL);
+ assert(ret == -1);
+
+ vnd_close(vhp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.badpropsize.c b/usr/src/cmd/vndadm/test/tst/lib/create.badpropsize.c
new file mode 100644
index 0000000000..d5fefd3764
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.badpropsize.c
@@ -0,0 +1,63 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Validate that we can't set properties with bogus sizes.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <limits.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr, ret, i;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ for (i = 0; i < VND_PROP_MAX; i++) {
+ ret = vnd_prop_get(vhp, i, NULL, INT32_MAX);
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_BADPROPSIZE);
+ assert(vnd_syserrno(vhp) == 0);
+
+ ret = vnd_prop_set(vhp, i, NULL, INT32_MAX);
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_BADPROPSIZE);
+ assert(vnd_syserrno(vhp) == 0);
+ }
+
+ vnd_close(vhp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.badzone.c b/usr/src/cmd/vndadm/test/tst/lib/create.badzone.c
new file mode 100644
index 0000000000..30f9612963
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.badzone.c
@@ -0,0 +1,43 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Make sure that we can't create something in the context of a zone that
+ * doesn't exist.
+ */
+
+#include <assert.h>
+#include <sys/zone.h>
+#include <string.h>
+#include <libvnd.h>
+
+int
+main(void)
+{
+ int syserr;
+ vnd_errno_t vnderr;
+ char zname[ZONENAME_MAX+4];
+ vnd_handle_t *vhp;
+
+ (void) memset(zname, 'a', sizeof (zname));
+ zname[ZONENAME_MAX+3] = '\0';
+
+ vhp = vnd_create(zname, "foobar", "foobar", &vnderr, &syserr);
+ assert(vhp == NULL);
+ assert(vnderr == VND_E_NOZONE);
+ assert(syserr == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.basic.c b/usr/src/cmd/vndadm/test/tst/lib/create.basic.c
new file mode 100644
index 0000000000..5335f8cbb4
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.basic.c
@@ -0,0 +1,49 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Simple create and destroy.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+ vnd_close(vhp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.enomem.c b/usr/src/cmd/vndadm/test/tst/lib/create.enomem.c
new file mode 100644
index 0000000000..9203e369ae
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.enomem.c
@@ -0,0 +1,91 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Verify that we can't allocate a handle when in an ENOMEM situation.
+ */
+
+#include <procfs.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/sysmacros.h>
+#include <assert.h>
+#include <strings.h>
+
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int fd;
+ int syserr;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+ pstatus_t status;
+ void *addr;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ fd = open("/proc/self/status", O_RDONLY);
+ if (fd < 0)
+ exit(1);
+ if (read(fd, &status, sizeof (status)) != sizeof (status))
+ exit(1);
+
+ addr = mmap((caddr_t)P2ROUNDUP(status.pr_brkbase +
+ status.pr_brksize, 0x1000), 0x1000,
+ PROT_READ, MAP_ANON | MAP_FIXED | MAP_PRIVATE, -1, 0);
+ if (addr == (void *)-1) {
+ perror("mmap");
+ exit(1);
+ }
+
+ /* malloc an approximate size of the vnd_handle_t */
+ for (;;) {
+ void *buf;
+
+ buf = malloc(8);
+ if (buf == NULL)
+ break;
+ }
+
+ for (;;) {
+ void *buf;
+
+ buf = malloc(4);
+ if (buf == NULL)
+ break;
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp == NULL);
+ assert(vnderr == VND_E_NOMEM);
+ assert(syserr == 0);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.frameioeagain.c b/usr/src/cmd/vndadm/test/tst/lib/create.frameioeagain.c
new file mode 100644
index 0000000000..6cb14fb7df
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.frameioeagain.c
@@ -0,0 +1,80 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Create a datalink, set it to non-blocking mode and ensure that we get EAGAIN
+ * from frame I/O calls. Note that if this test is not plumbed up over an
+ * etherstub, then it is likely that other traffic will appear on the device and
+ * this will fail. Note that the test suite always creates these devices over an
+ * etherstub.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr, ret, fd;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+ frameio_t *fio;
+ char buf[1520];
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ fd = vnd_pollfd(vhp);
+ ret = fcntl(fd, F_SETFL, O_NONBLOCK);
+ assert(ret == 0);
+
+ fio = malloc(sizeof (frameio_t) +
+ sizeof (framevec_t));
+ assert(fio != NULL);
+ fio->fio_version = FRAMEIO_CURRENT_VERSION;
+ fio->fio_nvpf = 1;
+ fio->fio_nvecs = 1;
+
+ fio->fio_vecs[0].fv_buf = buf;
+ fio->fio_vecs[0].fv_buflen = sizeof (buf);
+
+ ret = vnd_frameio_read(vhp, fio);
+ (void) printf("%d, %d\n", ret, errno);
+ assert(ret == -1);
+ assert(errno == EAGAIN);
+
+ vnd_close(vhp);
+ free(fio);
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.open.c b/usr/src/cmd/vndadm/test/tst/lib/create.open.c
new file mode 100644
index 0000000000..9cb1d7e40e
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.open.c
@@ -0,0 +1,56 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Make sure we can open a created datalink.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp, *vhp2;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ vhp2 = vnd_open(NULL, argv[1], &vnderr, &syserr);
+ assert(vhp2 != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ vnd_close(vhp2);
+ vnd_close(vhp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.propiter.c b/usr/src/cmd/vndadm/test/tst/lib/create.propiter.c
new file mode 100644
index 0000000000..a0b46180f7
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.propiter.c
@@ -0,0 +1,79 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Ensure that vnd_prop_iter sees all props;
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <libvnd.h>
+
+static boolean_t *g_props;
+
+/* ARGSUSED */
+static int
+prop_cb(vnd_handle_t *vhp, vnd_prop_t prop, void *unused)
+{
+ assert(prop < VND_PROP_MAX);
+ g_props[prop] = B_TRUE;
+
+ return (0);
+}
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr, i, ret;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ g_props = malloc(sizeof (boolean_t) * VND_PROP_MAX);
+ if (g_props == NULL) {
+ (void) fprintf(stderr, "failed to alloc memory for %d "
+ "boolean_t\n", VND_PROP_MAX);
+ return (1);
+ }
+ for (i = 0; i < VND_PROP_MAX; i++)
+ g_props[i] = B_FALSE;
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ ret = vnd_prop_iter(vhp, prop_cb, NULL);
+ assert(ret == 0);
+
+ for (i = 0; i < VND_PROP_MAX; i++)
+ assert(g_props[i] == B_TRUE);
+
+ free(g_props);
+ vnd_close(vhp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/create.proprdonly.c b/usr/src/cmd/vndadm/test/tst/lib/create.proprdonly.c
new file mode 100644
index 0000000000..18b1f7d58d
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/create.proprdonly.c
@@ -0,0 +1,63 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Validate that we can't set read only properties
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <limits.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr, ret;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+ vnd_prop_buf_t vpb;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_create(NULL, argv[1], argv[1], &vnderr, &syserr);
+ assert(vhp != NULL);
+ assert(vnderr == 0);
+ assert(syserr == 0);
+
+ ret = vnd_prop_get(vhp, VND_PROP_MINTU, &vpb,
+ sizeof (vnd_prop_buf_t));
+ assert(ret == 0);
+
+ ret = vnd_prop_set(vhp, VND_PROP_MINTU, &vpb,
+ sizeof (vnd_prop_buf_t));
+ assert(ret == -1);
+ assert(vnd_errno(vhp) == VND_E_PROPRDONLY);
+ assert(vnd_syserrno(vhp) == 0);
+
+ vnd_close(vhp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/err.badclose.c b/usr/src/cmd/vndadm/test/tst/lib/err.badclose.c
new file mode 100644
index 0000000000..8c832506a0
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/err.badclose.c
@@ -0,0 +1,33 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * This program should segfault.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <libvnd.h>
+
+int
+main(void)
+{
+ vnd_handle_t *vhp = (void *)0x42;
+ vnd_close(vhp);
+ /* This should not be reached */
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/tst.badopen.c b/usr/src/cmd/vndadm/test/tst/lib/tst.badopen.c
new file mode 100644
index 0000000000..4f67ce79ed
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/tst.badopen.c
@@ -0,0 +1,49 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Make sure we can't open a vnd device that doesn't exist
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <assert.h>
+#include <libvnd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int syserr;
+ vnd_errno_t vnderr;
+ vnd_handle_t *vhp;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, "missing arguments...\n");
+ return (1);
+ }
+
+ if (strlen(argv[1]) >= LIBVND_NAMELEN) {
+ (void) fprintf(stderr, "vnic name too long...\n");
+ return (1);
+ }
+
+ vhp = vnd_open(NULL, argv[1], &vnderr, &syserr);
+ assert(vhp == NULL);
+ assert(vnderr == VND_E_SYS);
+ assert(syserr == ENOENT);
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/tst.strerror.c b/usr/src/cmd/vndadm/test/tst/lib/tst.strerror.c
new file mode 100644
index 0000000000..a99a9ecbf6
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/tst.strerror.c
@@ -0,0 +1,30 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Verify that all the error strings we care about match what we expect.
+ */
+
+#include <stdio.h>
+#include <libvnd.h>
+
+int
+main(void)
+{
+ int i;
+ for (i = 0; i <= VND_E_UNKNOWN + 1; i++)
+ (void) printf("[%s]\n", vnd_strerror(i));
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/test/tst/lib/tst.strerror.exe.out b/usr/src/cmd/vndadm/test/tst/lib/tst.strerror.exe.out
new file mode 100644
index 0000000000..83dbcdfdb4
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/tst.strerror.exe.out
@@ -0,0 +1,37 @@
+[no error]
+[not enough memory available]
+[no such datalink]
+[datalink not of type DL_ETHER]
+[unknown dlpi failure]
+[DL_ATTACH_REQ failed]
+[DL_BIND_REQ failed]
+[DL_PROMISCON_REQ failed]
+[DLD_CAPAB_DIRECT enable failed]
+[bad datalink capability]
+[bad datalink subcapability]
+[bad dld version]
+[failed to create kstats]
+[no such vnd link]
+[netstack doesn't exist]
+[device already associated]
+[device already attached]
+[device already linked]
+[invalid name]
+[permission denied]
+[no such zone]
+[failed to initialize vnd stream module]
+[device not attached]
+[device not linked]
+[another device has the same link name]
+[failed to create minor node]
+[requested buffer size is too large]
+[requested buffer size is too small]
+[unable to obtain exclusive access to dlpi link, link busy]
+[DLD direct capability not supported over data link]
+[invalid property size]
+[invalid property]
+[property is read only]
+[unexpected system error]
+[capabilities invalid, pass-through module detected]
+[unknown error]
+[unknown error]
diff --git a/usr/src/cmd/vndadm/test/tst/lib/tst.strsyserror.c b/usr/src/cmd/vndadm/test/tst/lib/tst.strsyserror.c
new file mode 100644
index 0000000000..b95e6372e4
--- /dev/null
+++ b/usr/src/cmd/vndadm/test/tst/lib/tst.strsyserror.c
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Verify that the error message from libvnd's strsyserrno is the same as the
+ * underlying strerror function's. It should be. We'll just check an assortment
+ * of errnos.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libvnd.h>
+
+int
+main(void)
+{
+ int i;
+ const char *vnd, *libc;
+ for (i = 0; i < 42; i++) {
+ vnd = vnd_strsyserror(i);
+ libc = strerror(i);
+ if ((vnd != NULL && libc == NULL) ||
+ (vnd == NULL && libc != NULL)) {
+ (void) fprintf(stderr, "errno %d, vnd: %p, libc: %p",
+ i, (void *)vnd, (void *)libc);
+ return (1);
+ }
+ if (vnd != NULL && strcmp(vnd, libc) != 0) {
+ (void) fprintf(stderr,
+ "errno %d: libc and vnd disagree.\n", i);
+ (void) fprintf(stderr, "vnd: %s\n", vnd);
+ (void) fprintf(stderr, "libc: %s\n", libc);
+ return (1);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/vndadm/vndadm.c b/usr/src/cmd/vndadm/vndadm.c
new file mode 100644
index 0000000000..6811663696
--- /dev/null
+++ b/usr/src/cmd/vndadm/vndadm.c
@@ -0,0 +1,872 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zone.h>
+
+#include <libvnd.h>
+
+typedef int (*vndadm_print_t)(vnd_handle_t *, vnd_prop_t);
+typedef int (*vndadm_parse_t)(char *, void **, size_t *);
+
+typedef struct vndadm_proptbl {
+ const char *vp_name;
+ vndadm_print_t vp_print;
+ vndadm_parse_t vp_parse;
+} vndadm_proptbl_t;
+
+/*
+ * Forwards
+ */
+static int usage(const char *, ...);
+static int vndadm_print_size(vnd_handle_t *, vnd_prop_t);
+static int vndadm_print_number(vnd_handle_t *, vnd_prop_t);
+static int vndadm_parse_size(char *, void **, size_t *);
+
+/*
+ * Globals
+ */
+static char *vnd_pname;
+
+static void
+vnd_vwarn(vnd_errno_t verr, int syserr, const char *format, va_list alist)
+{
+ (void) fprintf(stderr, "%s: ", vnd_pname);
+ (void) vfprintf(stderr, format, alist);
+ if (strchr(format, '\n') == NULL) {
+ (void) fprintf(stderr, ": %s\n", verr != VND_E_SYS ?
+ vnd_strerror(verr) : vnd_strsyserror(syserr));
+ }
+}
+
+static void
+vnd_libwarn(vnd_errno_t verr, int syserr, const char *format, ...)
+{
+ va_list alist;
+
+ va_start(alist, format);
+ vnd_vwarn(verr, syserr, format, alist);
+ va_end(alist);
+}
+
+static void
+vnd_warn(const char *format, ...)
+{
+ va_list alist;
+
+ va_start(alist, format);
+ vnd_vwarn(0, 0, format, alist);
+ va_end(alist);
+}
+
+static vndadm_proptbl_t vndadm_propname_tbl[] = {
+ { "rxbuf", vndadm_print_size,
+ vndadm_parse_size }, /* VND_PROP_RXBUF */
+ { "txbuf", vndadm_print_size,
+ vndadm_parse_size }, /* VND_PROP_TXBUF */
+ { "maxsize", vndadm_print_size, NULL }, /* VND_PROP_MAXBUF */
+ { "mintu", vndadm_print_number, NULL }, /* VND_PROP_MINTU */
+ { "maxtu", vndadm_print_number, NULL }, /* VND_PROP_MAXTU */
+ NULL /* VND_PROP_MAX */
+};
+
+static const char *
+vndadm_prop_to_name(vnd_prop_t prop)
+{
+ if (prop > VND_PROP_MAX)
+ return (NULL);
+
+ return (vndadm_propname_tbl[prop].vp_name);
+}
+
+static vnd_prop_t
+vndadm_name_to_prop(const char *name)
+{
+ int i;
+
+ for (i = 0; i < VND_PROP_MAX; i++) {
+ if (strcmp(name, vndadm_propname_tbl[i].vp_name) == 0)
+ return (i);
+ }
+
+ return (VND_PROP_MAX);
+}
+
+static int
+vndadm_print_size(vnd_handle_t *vhp, vnd_prop_t prop)
+{
+ vnd_prop_buf_t buf;
+
+ if (vnd_prop_get(vhp, prop, &buf, sizeof (buf)) != 0) {
+ vnd_libwarn(vnd_errno(vhp), vnd_syserrno(vhp),
+ "failed to get property %s", vndadm_prop_to_name(prop));
+ return (1);
+ }
+
+ (void) printf("%lld", buf.vpb_size);
+ return (0);
+}
+
+static int
+vndadm_print_number(vnd_handle_t *vhp, vnd_prop_t prop)
+{
+ vnd_prop_buf_t buf;
+
+ if (vnd_prop_get(vhp, prop, &buf, sizeof (buf)) != 0) {
+ vnd_libwarn(vnd_errno(vhp), vnd_syserrno(vhp),
+ "failed to get property %s", vndadm_prop_to_name(prop));
+ return (1);
+ }
+
+ (void) printf("%lld", buf.vpb_size);
+ return (0);
+}
+
+static int
+vndadm_parse_size(char *str, void **bufp, size_t *sizep)
+{
+ char *end;
+ unsigned long long val, orig;
+ vnd_prop_buf_t *buf;
+
+ errno = 0;
+ val = strtoull(str, &end, 10);
+ if (errno != 0) {
+ vnd_warn("%s: not a number\n", str);
+ return (1);
+ }
+
+ orig = val;
+ switch (*end) {
+ case 'g':
+ case 'G':
+ val *= 1024;
+ if (val < orig)
+ goto overflow;
+ /*FALLTHRU*/
+ case 'm':
+ case 'M':
+ val *= 1024;
+ if (val < orig)
+ goto overflow;
+ /*FALLTHRU*/
+ case 'k':
+ case 'K':
+ val *= 1024;
+ if (val < orig)
+ goto overflow;
+ end++;
+ break;
+ default:
+ break;
+ }
+
+ if (*end == 'b' || *end == 'B')
+ end++;
+ if (*end != '\0') {
+ vnd_warn("%s: not a number", str);
+ return (1);
+ }
+
+ buf = malloc(sizeof (vnd_prop_buf_t));
+ if (buf == NULL) {
+ vnd_warn("failed to allocate memory for setting a property");
+ return (1);
+ }
+
+ buf->vpb_size = val;
+ *bufp = buf;
+ *sizep = sizeof (vnd_prop_buf_t);
+
+ return (0);
+
+overflow:
+ vnd_warn("value overflowed: %s\n", str);
+ return (1);
+}
+
+static void
+vndadm_create_usage(FILE *out)
+{
+ (void) fprintf(out, "\tcreate:\t\t[-z zonename] -l datalink name\n");
+}
+
+static int
+vndadm_create(int argc, char *argv[])
+{
+ int c, syserr;
+ vnd_errno_t vnderr;
+ const char *datalink = NULL;
+ const char *linkname = NULL;
+ const char *zonename = NULL;
+ vnd_handle_t *vhp;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, ":z:l:")) != -1) {
+ switch (c) {
+ case 'l':
+ datalink = optarg;
+ break;
+ case 'z':
+ zonename = optarg;
+ break;
+ case ':':
+ return (usage("-%c requires an operand\n", optopt));
+ case '?':
+ return (usage("unknown option: -%c\n", optopt));
+ default:
+ abort();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ return (usage("missing required link name\n"));
+ } else if (argc > 1) {
+ return (usage("create: too many arguments for link name, "
+ "pick one\n"));
+ }
+ linkname = argv[0];
+ if (datalink == NULL)
+ datalink = linkname;
+
+ vhp = vnd_create(zonename, datalink, linkname, &vnderr, &syserr);
+ if (vhp == NULL) {
+ vnd_libwarn(vnderr, syserr,
+ "failed to create datapath link %s", linkname);
+ return (1);
+ }
+
+ vnd_close(vhp);
+ return (0);
+}
+
+static void
+vndadm_destroy_usage(FILE *out)
+{
+ (void) fprintf(out, "\tdestroy:\t[-z zonename] [link]...\n");
+}
+
+static int
+vndadm_destroy(int argc, char *argv[])
+{
+ vnd_handle_t *vhp;
+ int c, syserr;
+ vnd_errno_t vnderr;
+ const char *zonename = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, ":z:")) != -1) {
+ switch (c) {
+ case 'z':
+ zonename = optarg;
+ break;
+ case ':':
+ return (usage("-%c requires an operand\n", optopt));
+ case '?':
+ return (usage("unknown option: -%c\n", optopt));
+ default:
+ abort();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ return (usage("extraneous arguments\n"));
+ }
+
+ vhp = vnd_open(zonename, argv[0], &vnderr, &syserr);
+ if (vhp == NULL) {
+ vnd_libwarn(vnderr, syserr, "failed to open link: %s", argv[0]);
+ return (1);
+ }
+
+ if (vnd_unlink(vhp) != 0) {
+ vnd_libwarn(vnd_errno(vhp), vnd_syserrno(vhp),
+ "failed to destroy link %s", argv[0]);
+ return (1);
+ }
+
+ vnd_close(vhp);
+ return (0);
+}
+
+static void
+vndadm_list_usage(FILE *out)
+{
+ (void) fprintf(out, "\tlist:\t\t[-p] [-d delim] [-o field,...] "
+ "[-z zonename] [link]...\n");
+}
+
+#define VNDADM_LIST_NFIELDS 3
+
+typedef struct vndadm_list_cb {
+ int vsc_argc;
+ char **vsc_argv;
+ int vsc_found;
+ boolean_t vsc_parse;
+ const char *vsc_delim;
+ int vsc_order[VNDADM_LIST_NFIELDS];
+ int vsc_last;
+ zoneid_t vsc_zid;
+} vndadm_list_cb_t;
+
+typedef struct vndadm_list_field {
+ const char *vlf_name;
+ const char *vlf_header;
+ int vlf_size;
+ void (*vlf_print)(struct vndadm_list_field *, vnd_info_t *, boolean_t);
+ void (*vlf_parse)(struct vndadm_list_field *, vnd_info_t *, boolean_t);
+} vndadm_list_field_t;
+
+static void
+vlf_print_link(vndadm_list_field_t *vlfp, vnd_info_t *viip,
+ boolean_t last)
+{
+ if (last == B_TRUE) {
+ (void) printf("%s", viip->vi_name);
+ } else {
+ (void) printf("%-*s", vlfp->vlf_size, viip->vi_name);
+ }
+}
+
+/* ARGSUSED */
+static void
+vlf_parse_link(vndadm_list_field_t *vlfp, vnd_info_t *viip,
+ boolean_t last)
+{
+ (void) printf("%s", viip->vi_name);
+}
+
+static void
+vlf_print_datalink(vndadm_list_field_t *vlfp, vnd_info_t *viip,
+ boolean_t last)
+{
+ if (last == B_TRUE) {
+ (void) printf("%s", viip->vi_datalink);
+ } else {
+ (void) printf("%-*s", vlfp->vlf_size, viip->vi_datalink);
+ }
+}
+
+/* ARGSUSED */
+static void
+vlf_parse_datalink(vndadm_list_field_t *vlfp, vnd_info_t *viip,
+ boolean_t last)
+{
+ (void) printf("%s", viip->vi_datalink);
+}
+
+static void
+vlf_print_zone(vndadm_list_field_t *vlfp, vnd_info_t *viip,
+ boolean_t last)
+{
+ char buf[ZONENAME_MAX];
+
+ if (getzonenamebyid(viip->vi_zone, buf, sizeof (buf)) <= 0)
+ (void) strlcpy(buf, "<unknown>", sizeof (buf));
+
+ if (last == B_TRUE) {
+ (void) printf("%s", buf);
+ } else {
+ (void) printf("%-*s", vlfp->vlf_size, buf);
+ }
+}
+
+/* ARGSUSED */
+static void
+vlf_parse_zone(vndadm_list_field_t *vlfp, vnd_info_t *viip,
+ boolean_t last)
+{
+ char buf[ZONENAME_MAX];
+
+ if (getzonenamebyid(viip->vi_zone, buf, sizeof (buf)) <= 0)
+ (void) strlcpy(buf, "<unknown>", sizeof (buf));
+
+ (void) printf("%s", buf);
+}
+
+static vndadm_list_field_t vlf_tbl[] = {
+ { "name", "NAME", 16, vlf_print_link, vlf_parse_link },
+ { "datalink", "DATALINK", 16, vlf_print_datalink, vlf_parse_datalink },
+ { "zone", "ZONENAME", 32, vlf_print_zone, vlf_parse_zone },
+ { NULL }
+};
+
+
+static int
+vndadm_list_f(vnd_info_t *viip, void *arg)
+{
+ int i;
+ boolean_t found;
+ vndadm_list_cb_t *vscp = arg;
+
+ if (vscp->vsc_zid != ALL_ZONES && vscp->vsc_zid != viip->vi_zone)
+ return (0);
+
+ if (vscp->vsc_argc != 0) {
+ found = B_FALSE;
+ for (i = 0; i < vscp->vsc_argc; i++) {
+ if (strcmp(viip->vi_name, vscp->vsc_argv[i]) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ }
+ if (found == B_FALSE)
+ return (0);
+ vscp->vsc_found++;
+ }
+
+ for (i = 0; i < VNDADM_LIST_NFIELDS && vscp->vsc_order[i] != -1; i++) {
+ boolean_t last = i == vscp->vsc_last;
+ if (vscp->vsc_parse == B_TRUE)
+ vlf_tbl[vscp->vsc_order[i]].vlf_parse(
+ &vlf_tbl[vscp->vsc_order[i]], viip, last);
+ else
+ vlf_tbl[vscp->vsc_order[i]].vlf_print(
+ &vlf_tbl[vscp->vsc_order[i]], viip, last);
+
+ if (last == B_FALSE)
+ (void) printf("%s", vscp->vsc_delim);
+ }
+ (void) printf("\n");
+
+ return (0);
+}
+
+static int
+vndadm_list(int argc, char *argv[])
+{
+ int c, i, syserr;
+ vnd_errno_t vnderr;
+ boolean_t parse = B_FALSE;
+ const char *zonename = NULL, *delim = NULL;
+ char *fields = NULL;
+ vndadm_list_cb_t vsc;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, ":pd:o:z:")) != -1) {
+ switch (c) {
+ case 'p':
+ parse = B_TRUE;
+ break;
+ case 'd':
+ delim = optarg;
+ break;
+ case 'o':
+ fields = optarg;
+ break;
+ case 'z':
+ zonename = optarg;
+ break;
+ case ':':
+ return (usage("-%c requires an operand\n", optopt));
+ case '?':
+ return (usage("unknown option: -%c\n", optopt));
+ default:
+ abort();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ vsc.vsc_argc = argc;
+ vsc.vsc_argv = argv;
+ vsc.vsc_found = 0;
+ if (zonename != NULL) {
+ vsc.vsc_zid = getzoneidbyname(zonename);
+ if (vsc.vsc_zid == -1) {
+ vnd_warn("no such zone: %s\n", zonename);
+ return (1);
+ }
+ } else {
+ vsc.vsc_zid = ALL_ZONES;
+ }
+
+ /* Sanity check parseable related stuff */
+ if (delim != NULL && parse == B_FALSE) {
+ return (usage("-d cannot be used without -p\n"));
+ }
+
+ if (parse == B_TRUE && fields == NULL) {
+ return (usage("-p cannot be used without -o\n"));
+ }
+
+ /* validate our fields, if any */
+ if (fields != NULL) {
+ char *c, *n;
+ int floc = 0;
+
+ c = fields;
+ for (;;) {
+ if (floc >= VNDADM_LIST_NFIELDS) {
+ return (usage("too many fields specified "
+ "for -o\n"));
+ }
+
+ n = strchr(c, ',');
+ if (n != NULL)
+ *n = '\0';
+
+ for (i = 0; i < VNDADM_LIST_NFIELDS; i++) {
+ if (strcasecmp(c, vlf_tbl[i].vlf_name) == 0)
+ break;
+ }
+ if (i == VNDADM_LIST_NFIELDS) {
+ vnd_warn("invalid field for -o: %s\nvalid "
+ "fields are:", c);
+ for (i = 0; i < VNDADM_LIST_NFIELDS; i++)
+ vnd_warn(" %s", vlf_tbl[i].vlf_name);
+ vnd_warn("\n");
+ return (usage(NULL));
+ }
+ vsc.vsc_order[floc] = i;
+ floc++;
+
+ if (n == NULL)
+ break;
+ c = n + 1;
+ }
+
+ vsc.vsc_last = floc - 1;
+ while (floc < VNDADM_LIST_NFIELDS)
+ vsc.vsc_order[floc++] = -1;
+ } else {
+ vsc.vsc_order[0] = 0;
+ vsc.vsc_order[1] = 1;
+ vsc.vsc_order[2] = 2;
+ }
+
+ vsc.vsc_parse = parse;
+ vsc.vsc_delim = delim;
+ if (vsc.vsc_delim == NULL)
+ vsc.vsc_delim = " ";
+
+ if (vsc.vsc_parse != B_TRUE) {
+ for (i = 0; i < VNDADM_LIST_NFIELDS && vsc.vsc_order[i] != -1;
+ i++) {
+ if (i + 1 == VNDADM_LIST_NFIELDS) {
+ (void) printf("%s\n",
+ vlf_tbl[vsc.vsc_order[i]].vlf_header);
+ continue;
+ }
+ (void) printf("%-*s ",
+ vlf_tbl[vsc.vsc_order[i]].vlf_size,
+ vlf_tbl[vsc.vsc_order[i]].vlf_header);
+ }
+ }
+
+ if (vnd_walk(vndadm_list_f, &vsc, &vnderr, &syserr) != 0) {
+ vnd_libwarn(vnderr, syserr, "failed to walk vnd links");
+ return (1);
+ }
+
+ if (argc > 0 && vsc.vsc_found == 0) {
+ vnd_warn("no links matched requested names\n");
+ return (1);
+ }
+
+ return (0);
+}
+
+typedef struct vndadm_get {
+ boolean_t vg_parse;
+ const char *vg_delim;
+ const char *vg_link;
+ int vg_argc;
+ char **vg_argv;
+} vndadm_get_t;
+
+static int
+vndadm_get_cb(vnd_handle_t *vhp, vnd_prop_t prop, void *arg)
+{
+ boolean_t writeable;
+ const char *perm;
+ vndadm_get_t *vgp = arg;
+ const char *name = vndadm_prop_to_name(prop);
+
+ /* Verify if this is a prop we're supposed to print */
+ if (vgp->vg_argc > 0) {
+ int i;
+ boolean_t found = B_FALSE;
+ for (i = 0; i < vgp->vg_argc; i++) {
+ if (strcmp(name, vgp->vg_argv[i]) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ }
+ if (found == B_FALSE)
+ return (0);
+ }
+
+ if (vnd_prop_writeable(prop, &writeable) != 0)
+ abort();
+
+ perm = writeable ? "rw" : "r-";
+
+ if (vgp->vg_parse == B_TRUE) {
+ (void) printf("%s%s%s%s%s%s", vgp->vg_link, vgp->vg_delim,
+ name, vgp->vg_delim, perm, vgp->vg_delim);
+ } else {
+ (void) printf("%-13s %-16s %-5s ", vgp->vg_link, name, perm);
+ }
+
+ if (vndadm_propname_tbl[prop].vp_print != NULL) {
+ if (vndadm_propname_tbl[prop].vp_print(vhp, prop) != 0)
+ return (1);
+ } else {
+ (void) printf("-");
+ }
+ (void) printf("\n");
+ return (0);
+}
+
+static int
+vndadm_get(int argc, char *argv[])
+{
+ vnd_handle_t *vhp;
+ boolean_t parse = B_FALSE;
+ vndadm_get_t vg;
+ int c, syserr;
+ vnd_errno_t vnderr;
+ const char *zonename = NULL, *delim = NULL;
+
+ if (argc <= 0) {
+ return (usage("get requires a link name\n"));
+ }
+
+ optind = 0;
+ while ((c = getopt(argc, argv, ":pd:z:")) != -1) {
+ switch (c) {
+ case 'p':
+ parse = B_TRUE;
+ break;
+ case 'd':
+ delim = optarg;
+ break;
+ case 'z':
+ zonename = optarg;
+ break;
+ case ':':
+ return (usage("-%c requires an operand\n", optopt));
+ case '?':
+ return (usage("unknown option: -%c\n", optopt));
+ default:
+ abort();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ return (usage("missing required link\n"));
+ }
+
+ vhp = vnd_open(zonename, argv[0], &vnderr, &syserr);
+ if (vhp == NULL) {
+ vnd_libwarn(vnderr, syserr, "failed to open link: %s", argv[0]);
+ return (1);
+ }
+
+ vg.vg_argc = argc - 1;
+ vg.vg_argv = argv + 1;
+ vg.vg_link = argv[0];
+ vg.vg_parse = parse;
+ vg.vg_delim = delim != NULL ? delim : " ";
+ if (vg.vg_parse == B_FALSE)
+ (void) printf("%-13s %-16s %-5s %s\n", "LINK", "PROPERTY",
+ "PERM", "VALUE");
+
+ if (vnd_prop_iter(vhp, vndadm_get_cb, &vg) != 0)
+ return (1);
+
+ return (0);
+}
+
+static void
+vndadm_get_usage(FILE *out)
+{
+ (void) fprintf(out,
+ "\tget:\t\t[-p] [-d delim] [-z zonename] link [prop]...\n");
+}
+
+static int
+vndadm_set(int argc, char *argv[])
+{
+ vnd_handle_t *vhp;
+ int c, i, syserr;
+ vnd_errno_t vnderr;
+ const char *zonename = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, ":z:")) != -1) {
+ switch (c) {
+ case 'z':
+ zonename = optarg;
+ break;
+ case ':':
+ return (usage("-%c requires an operand\n", optopt));
+ case '?':
+ return (usage("unknown option: -%c\n", optopt));
+ default:
+ abort();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ return (usage("missing arguments to set\n"));
+ }
+
+ vhp = vnd_open(zonename, argv[0], &vnderr, &syserr);
+ if (vhp == NULL) {
+ vnd_libwarn(vnderr, syserr, "failed to open link: %s", argv[0]);
+ return (1);
+ }
+
+ for (i = 1; i < argc; i++) {
+ char *eq, *key, *value;
+ boolean_t writeable;
+ vnd_prop_t prop;
+ void *buf;
+ size_t psize;
+ int ret;
+
+ key = argv[i];
+ eq = strchr(key, '=');
+ if (eq == NULL) {
+ vnd_warn("invalid property name=value: %s\n", key);
+ return (1);
+ }
+ *eq = '\0';
+ value = eq + 1;
+ if (*value == '\0') {
+ vnd_warn("property value required for %s\n", key);
+ return (1);
+ }
+ prop = vndadm_name_to_prop(key);
+ if (prop == VND_PROP_MAX) {
+ vnd_warn("unknown property: %s\n", key);
+ return (1);
+ }
+
+ if (vnd_prop_writeable(prop, &writeable) != 0)
+ abort();
+ if (writeable != B_TRUE) {
+ vnd_warn("property %s is read-only\n", key);
+ return (1);
+ }
+ assert(vndadm_propname_tbl[prop].vp_parse != NULL);
+
+ /*
+ * vp_parse functions should say what explicitly is invalid. We
+ * should indicate that the property failed.
+ */
+ ret = vndadm_propname_tbl[prop].vp_parse(value, &buf, &psize);
+ if (ret != 0) {
+ vnd_warn("failed to set property %s\n", key);
+ return (1);
+ }
+
+ ret = vnd_prop_set(vhp, prop, buf, psize);
+ free(buf);
+ if (ret != 0) {
+ vnd_libwarn(vnd_errno(vhp), vnd_syserrno(vhp),
+ "failed to set property %s", key);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+static void
+vndadm_set_usage(FILE *out)
+{
+ (void) fprintf(out, "\tset:\t\t[-z zonename] link prop=val...\n");
+}
+
+typedef struct vnd_cmdtab {
+ const char *vc_name;
+ int (*vc_op)(int, char *[]);
+ void (*vc_usage)(FILE *);
+} vnd_cmdtab_t;
+
+static vnd_cmdtab_t vnd_tab[] = {
+ { "create", vndadm_create, vndadm_create_usage },
+ { "destroy", vndadm_destroy, vndadm_destroy_usage },
+ { "list", vndadm_list, vndadm_list_usage },
+ { "get", vndadm_get, vndadm_get_usage },
+ { "set", vndadm_set, vndadm_set_usage },
+ { NULL, NULL }
+};
+
+static int
+usage(const char *format, ...)
+{
+ vnd_cmdtab_t *tab;
+ const char *help = "usage: %s <subcommand> <args> ...\n";
+
+ if (format != NULL) {
+ va_list alist;
+
+ va_start(alist, format);
+ (void) fprintf(stderr, "%s: ", vnd_pname);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ }
+ (void) fprintf(stderr, help, vnd_pname);
+ for (tab = vnd_tab; tab->vc_name != NULL; tab++)
+ tab->vc_usage(stderr);
+
+ return (2);
+}
+
+int
+main(int argc, char *argv[])
+{
+ vnd_cmdtab_t *tab;
+
+ vnd_pname = basename(argv[0]);
+ if (argc < 2) {
+ return (usage(NULL));
+ }
+
+ for (tab = vnd_tab; tab->vc_name != NULL; tab++) {
+ if (strcmp(argv[1], tab->vc_name) == 0) {
+ argc -= 2; argv += 2;
+ assert(argc >= 0);
+ return (tab->vc_op(argc, argv));
+ }
+ }
+
+ return (usage("unknown sub-command '%s'\n", argv[1]));
+}
diff --git a/usr/src/cmd/vndstat/Makefile b/usr/src/cmd/vndstat/Makefile
new file mode 100644
index 0000000000..c77eef3887
--- /dev/null
+++ b/usr/src/cmd/vndstat/Makefile
@@ -0,0 +1,33 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+PROG= vndstat
+
+include ../Makefile.cmd
+
+LDLIBS += -lkstat
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTPROG)
+
+clean:
+ $(RM) $(PROG)
+
+lint: lint_PROG
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/vndstat/vndstat.c b/usr/src/cmd/vndstat/vndstat.c
new file mode 100644
index 0000000000..6f6c76fc12
--- /dev/null
+++ b/usr/src/cmd/vndstat/vndstat.c
@@ -0,0 +1,542 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/kstat.h>
+#include <kstat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <alloca.h>
+#include <signal.h>
+#include <sys/varargs.h>
+#include <sys/int_limits.h>
+#include <sys/sysmacros.h>
+
+#define KSTAT_FIELD_USEINSTANCE 0x01
+#define KSTAT_FIELD_NODELTA 0x02
+#define KSTAT_FIELD_FILLER 0x04
+#define KSTAT_FIELD_STRING 0x08
+#define KSTAT_FIELD_UNIT 0x10
+#define KSTAT_FIELD_LJUST 0x20
+
+typedef struct kstat_field {
+ char *ksf_header; /* header for field */
+ char *ksf_name; /* name of stat, if any */
+ int ksf_width; /* width for field in output line */
+ uint32_t ksf_flags; /* flags for this field, if any */
+ char *ksf_suffix; /* optional suffix for units */
+ int ksf_hint; /* index hint for field in kstat */
+} kstat_field_t;
+
+typedef struct kstat_instance {
+ char ksi_name[KSTAT_STRLEN]; /* name of the underlying kstat */
+ int ksi_instance; /* instance identifer of this kstat */
+ kstat_t *ksi_ksp; /* pointer to the kstat */
+ uint64_t *ksi_data[2]; /* pointer to two generations of data */
+ hrtime_t ksi_snaptime[2]; /* hrtime for data generations */
+ int ksi_gen; /* current generation */
+ struct kstat_instance *ksi_next; /* next in instance list */
+} kstat_instance_t;
+
+const char *g_cmd = "vndstat";
+
+static void
+kstat_nicenum(uint64_t num, char *buf, size_t buflen)
+{
+ uint64_t n = num;
+ int index = 0;
+ char u;
+
+ while (n >= 1024) {
+ n /= 1024;
+ index++;
+ }
+
+ u = " KMGTPE"[index];
+
+ if (index == 0) {
+ (void) snprintf(buf, buflen, "%llu", n);
+ } else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
+ /*
+ * If this is an even multiple of the base, always display
+ * without any decimal precision.
+ */
+ (void) snprintf(buf, buflen, "%llu%c", n, u);
+ } else {
+ /*
+ * We want to choose a precision that reflects the best choice
+ * for fitting in 5 characters. This can get rather tricky when
+ * we have numbers that are very close to an order of magnitude.
+ * For example, when displaying 10239 (which is really 9.999K),
+ * we want only a single place of precision for 10.0K. We could
+ * develop some complex heuristics for this, but it's much
+ * easier just to try each combination in turn.
+ */
+ int i;
+ for (i = 2; i >= 0; i--) {
+ if (snprintf(buf, buflen, "%.*f%c", i,
+ (double)num / (1ULL << 10 * index), u) <= 5)
+ break;
+ }
+ }
+}
+
+static void
+fatal(char *fmt, ...)
+{
+ va_list ap;
+ int error = errno;
+
+ va_start(ap, fmt);
+
+ (void) fprintf(stderr, "%s: ", g_cmd);
+ /*LINTED*/
+ (void) vfprintf(stderr, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fprintf(stderr, ": %s\n", strerror(error));
+
+ exit(EXIT_FAILURE);
+}
+
+int
+kstat_field_hint(kstat_t *ksp, kstat_field_t *field)
+{
+ kstat_named_t *nm = KSTAT_NAMED_PTR(ksp);
+ int i;
+
+ assert(ksp->ks_type == KSTAT_TYPE_NAMED);
+
+ for (i = 0; i < ksp->ks_ndata; i++) {
+ if (strcmp(field->ksf_name, nm[i].name) == 0)
+ return (field->ksf_hint = i);
+ }
+
+ fatal("could not find field '%s' in %s:%d\n",
+ field->ksf_name, ksp->ks_name, ksp->ks_instance);
+
+ return (0);
+}
+
+int
+kstat_instances_compare(const void *lhs, const void *rhs)
+{
+ kstat_instance_t *l = *((kstat_instance_t **)lhs);
+ kstat_instance_t *r = *((kstat_instance_t **)rhs);
+ int rval;
+
+ if ((rval = strcmp(l->ksi_name, r->ksi_name)) != 0)
+ return (rval);
+
+ if (l->ksi_instance < r->ksi_instance)
+ return (-1);
+
+ if (l->ksi_instance > r->ksi_instance)
+ return (1);
+
+ return (0);
+}
+
+void
+kstat_instances_update(kstat_ctl_t *kcp, kstat_instance_t **head,
+ boolean_t (*interested)(kstat_t *))
+{
+ int ninstances = 0, i;
+ kstat_instance_t **sorted, *ksi, *next;
+ kstat_t *ksp;
+ kid_t kid;
+
+ if ((kid = kstat_chain_update(kcp)) == 0 && *head != NULL)
+ return;
+
+ if (kid == -1)
+ fatal("failed to update kstat chain");
+
+ for (ksi = *head; ksi != NULL; ksi = ksi->ksi_next)
+ ksi->ksi_ksp = NULL;
+
+ for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
+ kstat_instance_t *last = NULL;
+
+ if (!interested(ksp))
+ continue;
+
+ /*
+ * Now look to see if we have this instance and name. (Yes,
+ * this is a linear search; we're assuming that this list is
+ * modest in size.)
+ */
+ for (ksi = *head; ksi != NULL; ksi = ksi->ksi_next) {
+ last = ksi;
+
+ if (ksi->ksi_instance != ksp->ks_instance)
+ continue;
+
+ if (strcmp(ksi->ksi_name, ksp->ks_name) != 0)
+ continue;
+
+ ksi->ksi_ksp = ksp;
+ ninstances++;
+ break;
+ }
+
+ if (ksi != NULL)
+ continue;
+
+ if ((ksi = malloc(sizeof (kstat_instance_t))) == NULL)
+ fatal("could not allocate memory for stat instance");
+
+ bzero(ksi, sizeof (kstat_instance_t));
+ (void) strlcpy(ksi->ksi_name, ksp->ks_name, KSTAT_STRLEN);
+ ksi->ksi_instance = ksp->ks_instance;
+ ksi->ksi_ksp = ksp;
+ ksi->ksi_next = NULL;
+
+ if (last == NULL) {
+ assert(*head == NULL);
+ *head = ksi;
+ } else {
+ last->ksi_next = ksi;
+ }
+
+ ninstances++;
+ }
+
+ /*
+ * Now we know how many instances we have; iterate back over them,
+ * pruning the stale ones and adding the active ones to a holding
+ * array in which to sort them.
+ */
+ sorted = (void *)alloca(ninstances * sizeof (kstat_instance_t *));
+ ninstances = 0;
+
+ for (ksi = *head; ksi != NULL; ksi = next) {
+ next = ksi->ksi_next;
+
+ if (ksi->ksi_ksp == NULL) {
+ free(ksi);
+ } else {
+ sorted[ninstances++] = ksi;
+ }
+ }
+
+ if (ninstances == 0) {
+ *head = NULL;
+ return;
+ }
+
+ qsort(sorted, ninstances, sizeof (kstat_instance_t *),
+ kstat_instances_compare);
+
+ *head = sorted[0];
+
+ for (i = 0; i < ninstances; i++) {
+ ksi = sorted[i];
+ ksi->ksi_next = i < ninstances - 1 ? sorted[i + 1] : NULL;
+ }
+}
+
+void
+kstat_instances_read(kstat_ctl_t *kcp, kstat_instance_t *instances,
+ kstat_field_t *fields)
+{
+ kstat_instance_t *ksi;
+ int i, nfields;
+
+ for (nfields = 0; fields[nfields].ksf_header != NULL; nfields++)
+ continue;
+
+ for (ksi = instances; ksi != NULL; ksi = ksi->ksi_next) {
+ kstat_t *ksp = ksi->ksi_ksp;
+
+ if (ksp == NULL)
+ continue;
+
+ if (kstat_read(kcp, ksp, NULL) == -1) {
+ if (errno == ENXIO) {
+ /*
+ * Our kstat has been removed since the update;
+ * NULL it out to prevent us from trying to read
+ * it again (and to indicate that it should not
+ * be displayed) and drive on.
+ */
+ ksi->ksi_ksp = NULL;
+ continue;
+ }
+
+ fatal("failed to read kstat %s:%d",
+ ksi->ksi_name, ksi->ksi_instance);
+ }
+
+ if (ksp->ks_type != KSTAT_TYPE_NAMED) {
+ fatal("%s:%d is not a named kstat", ksi->ksi_name,
+ ksi->ksi_instance);
+ }
+
+ if (ksi->ksi_data[0] == NULL) {
+ size_t size = nfields * sizeof (uint64_t) * 2;
+ uint64_t *data;
+
+ if ((data = malloc(size)) == NULL)
+ fatal("could not allocate memory");
+
+ bzero(data, size);
+ ksi->ksi_data[0] = data;
+ ksi->ksi_data[1] = &data[nfields];
+ }
+
+ for (i = 0; i < nfields; i++) {
+ kstat_named_t *nm = KSTAT_NAMED_PTR(ksp);
+ kstat_field_t *field = &fields[i];
+ int hint = field->ksf_hint;
+
+ if (field->ksf_name == NULL)
+ continue;
+
+ if (hint < 0 || hint >= ksp->ks_ndata ||
+ strcmp(field->ksf_name, nm[hint].name) != 0) {
+ hint = kstat_field_hint(ksp, field);
+ }
+
+ if (field->ksf_flags & KSTAT_FIELD_STRING)
+ ksi->ksi_data[ksi->ksi_gen][i] =
+ (uint64_t)(uintptr_t)
+ nm[hint].value.str.addr.ptr;
+ else
+ ksi->ksi_data[ksi->ksi_gen][i] =
+ nm[hint].value.ui64;
+ }
+
+ ksi->ksi_snaptime[ksi->ksi_gen] = ksp->ks_snaptime;
+ ksi->ksi_gen ^= 1;
+ }
+}
+
+uint64_t
+kstat_instances_delta(kstat_instance_t *ksi, int i)
+{
+ int gen = ksi->ksi_gen;
+ uint64_t delta = ksi->ksi_data[gen ^ 1][i] - ksi->ksi_data[gen][i];
+ uint64_t tdelta = ksi->ksi_snaptime[gen ^ 1] - ksi->ksi_snaptime[gen];
+
+ return (((delta * (uint64_t)NANOSEC) + (tdelta / 2)) / tdelta);
+}
+
+void
+kstat_instances_print(kstat_instance_t *instances, kstat_field_t *fields,
+ boolean_t header)
+{
+ kstat_instance_t *ksi = instances;
+ int i, nfields;
+
+ for (nfields = 0; fields[nfields].ksf_header != NULL; nfields++)
+ continue;
+
+ if (header) {
+ for (i = 0; i < nfields; i++) {
+ if (fields[i].ksf_flags & KSTAT_FIELD_LJUST) {
+ (void) printf("%s%c", fields[i].ksf_header,
+ i < nfields - 1 ? ' ' : '\n');
+ continue;
+ }
+ (void) printf("%*s%c", fields[i].ksf_width,
+ fields[i].ksf_header, i < nfields - 1 ? ' ' : '\n');
+ }
+ }
+
+ for (ksi = instances; ksi != NULL; ksi = ksi->ksi_next) {
+ if (ksi->ksi_snaptime[1] == 0 || ksi->ksi_ksp == NULL)
+ continue;
+
+ for (i = 0; i < nfields; i++) {
+ char trailer = i < nfields - 1 ? ' ' : '\n';
+
+ if (fields[i].ksf_flags & KSTAT_FIELD_FILLER) {
+ (void) printf("%*s%c", fields[i].ksf_width,
+ fields[i].ksf_header, trailer);
+ continue;
+ }
+
+ if (fields[i].ksf_flags & KSTAT_FIELD_STRING) {
+ (void) printf("%*s%c", fields[i].ksf_width,
+ (char *)(uintptr_t)ksi->ksi_data[
+ ksi->ksi_gen ^ 1][i],
+ trailer);
+ continue;
+ }
+
+ if (fields[i].ksf_flags & KSTAT_FIELD_UNIT) {
+ char buf[128];
+ size_t flen = fields[i].ksf_width + 1;
+ const char *suffix = "";
+
+ if (fields[i].ksf_suffix != NULL) {
+ suffix = fields[i].ksf_suffix;
+ flen -= strlen(fields[i].ksf_suffix);
+ }
+
+ kstat_nicenum(fields[i].ksf_flags &
+ KSTAT_FIELD_NODELTA ?
+ ksi->ksi_data[ksi->ksi_gen ^ 1][i] :
+ kstat_instances_delta(ksi, i), buf,
+ MIN(sizeof (buf), flen));
+ (void) printf("%*s%s%c", flen - 1, buf,
+ suffix, trailer);
+ continue;
+ }
+
+ (void) printf("%*lld%c", fields[i].ksf_width,
+ fields[i].ksf_flags & KSTAT_FIELD_USEINSTANCE ?
+ ksi->ksi_instance :
+ fields[i].ksf_flags & KSTAT_FIELD_NODELTA ?
+ ksi->ksi_data[ksi->ksi_gen ^ 1][i] :
+ kstat_instances_delta(ksi, i), trailer);
+ }
+ }
+}
+
+static boolean_t
+interested(kstat_t *ksp)
+{
+ const char *module = "vnd";
+ const char *class = "net";
+
+ if (strcmp(ksp->ks_module, module) != 0)
+ return (B_FALSE);
+
+ if (strcmp(ksp->ks_class, class) != 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/* BEGIN CSTYLED */
+char *g_usage = "Usage: vndstat [interval [count]]\n"
+ "\n"
+ " Displays statistics for active vnd devices, with one line per device.\n"
+ " All statistics are reported as per-second rates.\n"
+ "\n"
+ " The columns are as follows:\n"
+ "\n"
+ " zone => name of the zone with the device\n"
+ " name => name of the vnd device\n"
+ " rx => bytes received\n"
+ " tx => bytes transmitted\n"
+ " drops => number of dropped packets\n"
+ " txfc => number of transmit flow control events\n"
+ "\n";
+/* END CSTYLED */
+
+void
+usage()
+{
+ (void) fprintf(stderr, "%s", g_usage);
+ exit(EXIT_FAILURE);
+}
+
+/*ARGSUSED*/
+void
+intr(int sig)
+{}
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+ kstat_ctl_t *kcp;
+ kstat_instance_t *instances = NULL;
+ int i = 0;
+ int interval = 1;
+ int count = INT32_MAX;
+ struct itimerval itimer;
+ struct sigaction act;
+ sigset_t set;
+ char *endp;
+
+ kstat_field_t fields[] = {
+ { "name", "linkname", 6, KSTAT_FIELD_STRING },
+ { "|", NULL, 1, KSTAT_FIELD_FILLER },
+ { "rx B/s", "rbytes", 8, KSTAT_FIELD_UNIT, "B/s" },
+ { "|", NULL, 1, KSTAT_FIELD_FILLER },
+ { "tx B/s", "obytes", 8, KSTAT_FIELD_UNIT, "B/s" },
+ { "|", NULL, 1, KSTAT_FIELD_FILLER },
+ { "drops", "total_drops", 5 },
+ { "txfc", "flowcontrol_events", 4 },
+ { "|", NULL, 1, KSTAT_FIELD_FILLER },
+ { "zone", "zonename", 36,
+ KSTAT_FIELD_STRING | KSTAT_FIELD_LJUST },
+ { NULL }
+ };
+
+ if (argc > 1) {
+ interval = strtol(argv[1], &endp, 10);
+
+ if (*endp != '\0' || interval <= 0)
+ usage();
+ }
+
+ if (argc > 2) {
+ count = strtol(argv[2], &endp, 10);
+
+ if (*endp != '\0' || count <= 0)
+ usage();
+ }
+
+ if ((kcp = kstat_open()) == NULL)
+ fatal("could not open /dev/kstat");
+
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = intr;
+ (void) sigaction(SIGALRM, &act, NULL);
+
+ (void) sigemptyset(&set);
+ (void) sigaddset(&set, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &set, NULL);
+
+ bzero(&itimer, sizeof (itimer));
+ itimer.it_value.tv_sec = interval;
+ itimer.it_interval.tv_sec = interval;
+
+ if (setitimer(ITIMER_REAL, &itimer, NULL) != 0) {
+ fatal("could not set timer to %d second%s", interval,
+ interval == 1 ? "" : "s");
+ }
+
+ (void) sigemptyset(&set);
+
+ for (;;) {
+ kstat_instances_update(kcp, &instances, interested);
+ kstat_instances_read(kcp, instances, fields);
+
+ if (i++ > 0) {
+ kstat_instances_print(instances, fields,
+ instances != NULL && instances->ksi_next == NULL ?
+ (((i - 2) % 20) == 0) : B_TRUE);
+ }
+
+ if (i > count)
+ break;
+
+ (void) sigsuspend(&set);
+ }
+
+ /*NOTREACHED*/
+ return (0);
+}
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index 695da7fcbc..c8c7c525ba 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -248,9 +248,9 @@ get_usage(zfs_help_t idx)
return (gettext("\tclone [-p] [-o property=value] ... "
"<snapshot> <filesystem|volume>\n"));
case HELP_CREATE:
- return (gettext("\tcreate [-p] [-o property=value] ... "
+ return (gettext("\tcreate [-Pnpv] [-o property=value] ... "
"<filesystem>\n"
- "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
+ "\tcreate [-Pnpsv] [-b blocksize] [-o property=value] ... "
"-V <size> <volume>\n"));
case HELP_DESTROY:
return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
@@ -258,7 +258,7 @@ get_usage(zfs_help_t idx)
"<filesystem|volume>@<snap>[%<snap>][,...]\n"
"\tdestroy <filesystem|volume>#<bookmark>\n"));
case HELP_GET:
- return (gettext("\tget [-rHp] [-d max] "
+ return (gettext("\tget [-crHp] [-d max] "
"[-o \"all\" | field[,...]]\n"
"\t [-t type[,...]] [-s source[,...]]\n"
"\t <\"all\" | property[,...]> "
@@ -704,7 +704,7 @@ should_auto_mount(zfs_handle_t *zhp)
}
/*
- * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
+ * zfs clone [-Fp] [-o prop=value] ... <snap> <fs | vol>
*
* Given an existing dataset, create a writable copy whose initial contents
* are the same as the source. The newly created dataset maintains a
@@ -712,12 +712,18 @@ should_auto_mount(zfs_handle_t *zhp)
* the clone exists.
*
* The '-p' flag creates all the non-existing ancestors of the target first.
+ *
+ * The '-F' flag retries the zfs_mount() operation as long as zfs_mount() is
+ * still returning EBUSY. Any callers which specify -F should be careful to
+ * ensure that no other process has a persistent hold on the mountpoint's
+ * directory.
*/
static int
zfs_do_clone(int argc, char **argv)
{
zfs_handle_t *zhp = NULL;
boolean_t parents = B_FALSE;
+ boolean_t keeptrying = B_FALSE;
nvlist_t *props;
int ret = 0;
int c;
@@ -726,8 +732,11 @@ zfs_do_clone(int argc, char **argv)
nomem();
/* check options */
- while ((c = getopt(argc, argv, "o:p")) != -1) {
+ while ((c = getopt(argc, argv, "Fo:p")) != -1) {
switch (c) {
+ case 'F':
+ keeptrying = B_TRUE;
+ break;
case 'o':
if (!parseprop(props, optarg)) {
nvlist_free(props);
@@ -796,11 +805,16 @@ zfs_do_clone(int argc, char **argv)
* step.
*/
if (should_auto_mount(clone)) {
- if ((ret = zfs_mount(clone, NULL, 0)) != 0) {
- (void) fprintf(stderr, gettext("clone "
- "successfully created, "
- "but not mounted\n"));
- } else if ((ret = zfs_share(clone)) != 0) {
+ while ((ret = zfs_mount(clone, NULL, 0)) != 0) {
+ if (!keeptrying || errno != EBUSY) {
+ (void) fprintf(stderr,
+ gettext("clone "
+ "successfully created, "
+ "but not mounted\n"));
+ break;
+ }
+ }
+ if (ret == 0 && (ret = zfs_share(clone)) != 0) {
(void) fprintf(stderr, gettext("clone "
"successfully created, "
"but not shared\n"));
@@ -824,8 +838,8 @@ usage:
}
/*
- * zfs create [-p] [-o prop=value] ... fs
- * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size
+ * zfs create [-Pnpv] [-o prop=value] ... fs
+ * zfs create [-Pnpsv] [-b blocksize] [-o prop=value] ... -V vol size
*
* Create a new dataset. This command can be used to create filesystems
* and volumes. Snapshot creation is handled by 'zfs snapshot'.
@@ -837,17 +851,30 @@ usage:
* SPA_VERSION_REFRESERVATION, we set a refreservation instead.
*
* The '-p' flag creates all the non-existing ancestors of the target first.
+ *
+ * The '-n' flag is no-op (dry run) mode. This will perform a user-space sanity
+ * check of arguments and properties, but does not check for permissions,
+ * available space, etc.
+ *
+ * The '-v' flag is for verbose output.
+ *
+ * The '-P' flag is used for parseable output. It implies '-v'.
*/
static int
zfs_do_create(int argc, char **argv)
{
zfs_type_t type = ZFS_TYPE_FILESYSTEM;
zfs_handle_t *zhp = NULL;
+ zpool_handle_t *zpool_handle = NULL;
+ nvlist_t *real_props = NULL;
uint64_t volsize = 0;
int c;
boolean_t noreserve = B_FALSE;
boolean_t bflag = B_FALSE;
boolean_t parents = B_FALSE;
+ boolean_t dryrun = B_FALSE;
+ boolean_t verbose = B_FALSE;
+ boolean_t parseable = B_FALSE;
int ret = 1;
nvlist_t *props;
uint64_t intval;
@@ -856,7 +883,7 @@ zfs_do_create(int argc, char **argv)
nomem();
/* check options */
- while ((c = getopt(argc, argv, ":V:b:so:p")) != -1) {
+ while ((c = getopt(argc, argv, ":PV:b:nso:pv")) != -1) {
switch (c) {
case 'V':
type = ZFS_TYPE_VOLUME;
@@ -872,6 +899,10 @@ zfs_do_create(int argc, char **argv)
nomem();
volsize = intval;
break;
+ case 'P':
+ verbose = B_TRUE;
+ parseable = B_TRUE;
+ break;
case 'p':
parents = B_TRUE;
break;
@@ -889,6 +920,9 @@ zfs_do_create(int argc, char **argv)
intval) != 0)
nomem();
break;
+ case 'n':
+ dryrun = B_TRUE;
+ break;
case 'o':
if (!parseprop(props, optarg))
goto error;
@@ -896,6 +930,9 @@ zfs_do_create(int argc, char **argv)
case 's':
noreserve = B_TRUE;
break;
+ case 'v':
+ verbose = B_TRUE;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing size "
"argument\n"));
@@ -927,14 +964,9 @@ zfs_do_create(int argc, char **argv)
goto badusage;
}
- if (type == ZFS_TYPE_VOLUME && !noreserve) {
- zpool_handle_t *zpool_handle;
- nvlist_t *real_props = NULL;
- uint64_t spa_version;
+ if (dryrun || (type == ZFS_TYPE_VOLUME && !noreserve)) {
+ char msg[ZFS_MAX_DATASET_NAME_LEN * 2];
char *p;
- zfs_prop_t resv_prop;
- char *strval;
- char msg[1024];
if ((p = strchr(argv[0], '/')) != NULL)
*p = '\0';
@@ -943,25 +975,31 @@ zfs_do_create(int argc, char **argv)
*p = '/';
if (zpool_handle == NULL)
goto error;
- spa_version = zpool_get_prop_int(zpool_handle,
- ZPOOL_PROP_VERSION, NULL);
- if (spa_version >= SPA_VERSION_REFRESERVATION)
- resv_prop = ZFS_PROP_REFRESERVATION;
- else
- resv_prop = ZFS_PROP_RESERVATION;
(void) snprintf(msg, sizeof (msg),
+ dryrun ? gettext("cannot verify '%s'") :
gettext("cannot create '%s'"), argv[0]);
if (props && (real_props = zfs_valid_proplist(g_zfs, type,
props, 0, NULL, zpool_handle, B_TRUE, msg)) == NULL) {
zpool_close(zpool_handle);
goto error;
}
+ }
+
+ if (type == ZFS_TYPE_VOLUME && !noreserve) {
+ uint64_t spa_version;
+ zfs_prop_t resv_prop;
+ char *strval;
+
+ spa_version = zpool_get_prop_int(zpool_handle,
+ ZPOOL_PROP_VERSION, NULL);
+ if (spa_version >= SPA_VERSION_REFRESERVATION)
+ resv_prop = ZFS_PROP_REFRESERVATION;
+ else
+ resv_prop = ZFS_PROP_RESERVATION;
volsize = zvol_volsize_to_reservation(zpool_handle, volsize,
real_props);
- nvlist_free(real_props);
- zpool_close(zpool_handle);
if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
&strval) != 0) {
@@ -972,6 +1010,10 @@ zfs_do_create(int argc, char **argv)
}
}
}
+ if (zpool_handle != NULL) {
+ zpool_close(zpool_handle);
+ nvlist_free(real_props);
+ }
if (parents && zfs_name_valid(argv[0], type)) {
/*
@@ -983,8 +1025,50 @@ zfs_do_create(int argc, char **argv)
ret = 0;
goto error;
}
- if (zfs_create_ancestors(g_zfs, argv[0]) != 0)
- goto error;
+ if (verbose) {
+ (void) printf(parseable ? "create_ancestors\t%s\n" :
+ dryrun ? "would create ancestors of %s\n" :
+ "create ancestors of %s\n", argv[0]);
+ }
+ if (!dryrun) {
+ if (zfs_create_ancestors(g_zfs, argv[0]) != 0) {
+ goto error;
+ }
+ }
+ }
+
+ if (verbose) {
+ nvpair_t *nvp = NULL;
+ (void) printf(parseable ? "create\t%s\n" :
+ dryrun ? "would create %s\n" : "create %s\n", argv[0]);
+ while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL) {
+ uint64_t uval;
+ char *sval;
+
+ switch (nvpair_type(nvp)) {
+ case DATA_TYPE_UINT64:
+ VERIFY0(nvpair_value_uint64(nvp, &uval));
+ (void) printf(parseable ?
+ "property\t%s\t%llu\n" : "\t%s=%llu\n",
+ nvpair_name(nvp), (u_longlong_t)uval);
+ break;
+ case DATA_TYPE_STRING:
+ VERIFY0(nvpair_value_string(nvp, &sval));
+ (void) printf(parseable ?
+ "property\t%s\t%s\n" : "\t%s=%s\n",
+ nvpair_name(nvp), sval);
+ break;
+ default:
+ (void) fprintf(stderr, "property '%s' "
+ "has illegal type %d\n",
+ nvpair_name(nvp), nvpair_type(nvp));
+ abort();
+ }
+ }
+ }
+ if (dryrun) {
+ ret = 0;
+ goto error;
}
/* pass to libzfs */
@@ -1027,12 +1111,13 @@ badusage:
}
/*
- * zfs destroy [-rRf] <fs, vol>
+ * zfs destroy [-rRfF] <fs, vol>
* zfs destroy [-rRd] <snap>
*
* -r Recursively destroy all children
* -R Recursively destroy all dependents, including clones
* -f Force unmounting of any dependents
+ * -F Continue retrying on seeing EBUSY
* -d If we can't destroy now, mark for deferred destruction
*
* Destroys the given dataset. By default, it will unmount any filesystems,
@@ -1042,6 +1127,7 @@ badusage:
typedef struct destroy_cbdata {
boolean_t cb_first;
boolean_t cb_force;
+ boolean_t cb_wait;
boolean_t cb_recurse;
boolean_t cb_error;
boolean_t cb_doclones;
@@ -1125,13 +1211,18 @@ out:
static int
destroy_callback(zfs_handle_t *zhp, void *data)
{
- destroy_cbdata_t *cb = data;
+ destroy_cbdata_t *cbp = data;
+ struct timespec ts;
+ int err = 0;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 500 * (NANOSEC / MILLISEC);
const char *name = zfs_get_name(zhp);
- if (cb->cb_verbose) {
- if (cb->cb_parsable) {
+ if (cbp->cb_verbose) {
+ if (cbp->cb_parsable) {
(void) printf("destroy\t%s\n", name);
- } else if (cb->cb_dryrun) {
+ } else if (cbp->cb_dryrun) {
(void) printf(gettext("would destroy %s\n"),
name);
} else {
@@ -1146,13 +1237,10 @@ destroy_callback(zfs_handle_t *zhp, void *data)
*/
if (strchr(zfs_get_name(zhp), '/') == NULL &&
zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
- zfs_close(zhp);
- return (0);
- }
- if (cb->cb_dryrun) {
- zfs_close(zhp);
- return (0);
+ goto out;
}
+ if (cbp->cb_dryrun)
+ goto out;
/*
* We batch up all contiguous snapshots (even of different
@@ -1161,23 +1249,66 @@ destroy_callback(zfs_handle_t *zhp, void *data)
* because we must delete a clone before its origin.
*/
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
- fnvlist_add_boolean(cb->cb_batchedsnaps, name);
- } else {
- int error = zfs_destroy_snaps_nvl(g_zfs,
- cb->cb_batchedsnaps, B_FALSE);
- fnvlist_free(cb->cb_batchedsnaps);
- cb->cb_batchedsnaps = fnvlist_alloc();
-
- if (error != 0 ||
- zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
- zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
- zfs_close(zhp);
- return (-1);
+ fnvlist_add_boolean(cbp->cb_batchedsnaps, name);
+ goto out;
+ }
+
+ if (cbp->cb_wait)
+ libzfs_print_on_error(g_zfs, B_FALSE);
+
+ /*
+ * Unless instructed to retry on EBUSY, bail out on the first error.
+ * When retrying, try every 500ms until either succeeding or seeing a
+ * non-EBUSY error code.
+ */
+ while ((err = zfs_destroy_snaps_nvl(g_zfs,
+ cbp->cb_batchedsnaps, B_FALSE)) != 0) {
+ if (cbp->cb_wait && libzfs_errno(g_zfs) == EZFS_BUSY) {
+ (void) nanosleep(&ts, NULL);
+ continue;
+ }
+ (void) fprintf(stderr, "%s: %s\n",
+ libzfs_error_action(g_zfs),
+ libzfs_error_description(g_zfs));
+ break;
+ }
+
+ fnvlist_free(cbp->cb_batchedsnaps);
+ cbp->cb_batchedsnaps = fnvlist_alloc();
+
+ if (err != 0)
+ goto out;
+
+ while ((err = zfs_unmount(zhp, NULL,
+ cbp->cb_force ? MS_FORCE : 0)) != 0) {
+ if (cbp->cb_wait && libzfs_errno(g_zfs) == EZFS_BUSY) {
+ (void) nanosleep(&ts, NULL);
+ continue;
}
+ (void) fprintf(stderr, "%s: %s\n",
+ libzfs_error_action(g_zfs),
+ libzfs_error_description(g_zfs));
+ break;
}
+ if (err != 0)
+ goto out;
+
+ while ((err = zfs_destroy(zhp, cbp->cb_defer_destroy)) != 0) {
+ if (cbp->cb_wait && libzfs_errno(g_zfs) == EZFS_BUSY) {
+ (void) nanosleep(&ts, NULL);
+ continue;
+ }
+ (void) fprintf(stderr, "%s: %s\n",
+ libzfs_error_action(g_zfs),
+ libzfs_error_description(g_zfs));
+ break;
+ }
+
+out:
+ libzfs_print_on_error(g_zfs, B_TRUE);
zfs_close(zhp);
- return (0);
+ return (err);
}
static int
@@ -1333,7 +1464,7 @@ zfs_do_destroy(int argc, char **argv)
zfs_type_t type = ZFS_TYPE_DATASET;
/* check options */
- while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
+ while ((c = getopt(argc, argv, "vpndfFrR")) != -1) {
switch (c) {
case 'v':
cb.cb_verbose = B_TRUE;
@@ -1352,6 +1483,9 @@ zfs_do_destroy(int argc, char **argv)
case 'f':
cb.cb_force = B_TRUE;
break;
+ case 'F':
+ cb.cb_wait = B_TRUE;
+ break;
case 'r':
cb.cb_recurse = B_TRUE;
break;
@@ -1722,8 +1856,11 @@ zfs_do_get(int argc, char **argv)
cb.cb_type = ZFS_TYPE_DATASET;
/* check options */
- while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) {
+ while ((c = getopt(argc, argv, ":d:o:s:rt:Hcp")) != -1) {
switch (c) {
+ case 'c':
+ libzfs_set_cachedprops(g_zfs, B_TRUE);
+ break;
case 'p':
cb.cb_literal = B_TRUE;
break;
@@ -3244,6 +3381,7 @@ zfs_do_list(int argc, char **argv)
int types = ZFS_TYPE_DATASET;
boolean_t types_specified = B_FALSE;
char *fields = NULL;
+ zprop_list_t *pl;
list_cbdata_t cb = { 0 };
char *value;
int limit = 0;
@@ -3362,6 +3500,18 @@ zfs_do_list(int argc, char **argv)
!= 0)
usage(B_FALSE);
+ /*
+ * The default set of properties contains only properties which can be
+ * retrieved from the set of cached properties. If any user-specfied
+ * properties cannot be retrieved from that set, unset the cachedprops
+ * flags on the ZFS handle.
+ */
+ libzfs_set_cachedprops(g_zfs, B_TRUE);
+ for (pl = cb.cb_proplist; pl != NULL; pl = pl->pl_next) {
+ if (zfs_prop_cacheable(pl->pl_prop))
+ libzfs_set_cachedprops(g_zfs, B_FALSE);
+ }
+
cb.cb_first = B_TRUE;
ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
diff --git a/usr/src/cmd/zlogin/zlogin.c b/usr/src/cmd/zlogin/zlogin.c
index e942e66e71..fb219918c5 100644
--- a/usr/src/cmd/zlogin/zlogin.c
+++ b/usr/src/cmd/zlogin/zlogin.c
@@ -23,12 +23,12 @@
* Copyright 2013 DEY Storage Systems, Inc.
* Copyright (c) 2014 Gary Mills
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/*
- * zlogin provides three types of login which allow users in the global
+ * zlogin provides five types of login which allow users in the global
* zone to access non-global zones.
*
* - "interactive login" is similar to rlogin(1); for example, the user could
@@ -44,12 +44,22 @@
* In this mode, zlogin sets up pipes as the communication channel, and
* 'su' is used to do the login setup work.
*
+ * - "interactive command" is a combination of the above two modes where
+ * a command is provide like the non-interactive case, but the -i option is
+ * also provided to make things interactive. For example, the user could
+ * issue 'zlogin -i my-zone /bin/sh'. In this mode neither 'login -c' nor
+ * 'su root -c' is prepended to the command invocation. Because of this
+ * there will be no wtmpx login record within the zone.
+ *
* - "console login" is the equivalent to accessing the tip line for a
* zone. For example, the user can issue 'zlogin -C my-zone'.
* In this mode, zlogin contacts the zoneadmd process via unix domain
* socket. If zoneadmd is not running, it starts it. This allows the
* console to be available anytime the zone is installed, regardless of
* whether it is running.
+ *
+ * - "standalone-processs interactive" is specified with -I and connects to
+ * the zone's stdin, stdout and stderr zfd(7D) devices.
*/
#include <sys/socket.h>
@@ -94,7 +104,8 @@
#include <auth_attr.h>
#include <secdb.h>
-static int masterfd;
+static int masterfd = -1;
+static int ctlfd = -1;
static struct termios save_termios;
static struct termios effective_termios;
static int save_fd;
@@ -103,12 +114,13 @@ static volatile int dead;
static volatile pid_t child_pid = -1;
static int interactive = 0;
static priv_set_t *dropprivs;
+static unsigned int connect_flags = 0;
static int nocmdchar = 0;
static int failsafe = 0;
-static int disconnect = 0;
static char cmdchar = '~';
static int quiet = 0;
+static char zonebrand[MAXNAMELEN];
static int pollerr = 0;
@@ -125,10 +137,14 @@ static boolean_t forced_login = B_FALSE;
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
#endif
-#define SUPATH "/usr/bin/su"
+#define SUPATH1 "/usr/bin/su"
+#define SUPATH2 "/bin/su"
#define FAILSAFESHELL "/sbin/sh"
#define DEFAULTSHELL "/sbin/sh"
#define DEF_PATH "/usr/sbin:/usr/bin"
+#define LX_DEF_PATH "/bin:/usr/sbin:/usr/bin"
+
+#define MAX_RETRY 30
#define CLUSTER_BRAND_NAME "cluster"
@@ -155,7 +171,7 @@ static boolean_t forced_login = B_FALSE;
static void
usage(void)
{
- (void) fprintf(stderr, gettext("usage: %s [ -dnQCES ] [ -e cmdchar ] "
+ (void) fprintf(stderr, gettext("usage: %s [-dinCEINQS] [-e cmdchar] "
"[-l user] zonename [command [args ...] ]\n"), pname);
exit(2);
}
@@ -250,57 +266,60 @@ postfork_dropprivs()
}
}
-/*
- * Create the unix domain socket and call the zoneadmd server; handshake
- * with it to determine whether it will allow us to connect.
- */
static int
-get_console_master(const char *zname)
+connect_zone_sock(const char *zname, const char *suffix, boolean_t verbose)
{
int sockfd = -1;
struct sockaddr_un servaddr;
- char clientid[MAXPATHLEN];
- char handshake[MAXPATHLEN], c;
- int msglen;
- int i = 0, err = 0;
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
- zperror(gettext("could not create socket"));
+ if (verbose)
+ zperror(gettext("could not create socket"));
return (-1);
}
bzero(&servaddr, sizeof (servaddr));
servaddr.sun_family = AF_UNIX;
(void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
- "%s/%s.console_sock", ZONES_TMPDIR, zname);
-
+ "%s/%s.%s", ZONES_TMPDIR, zname, suffix);
if (connect(sockfd, (struct sockaddr *)&servaddr,
sizeof (servaddr)) == -1) {
- zperror(gettext("Could not connect to zone console"));
- goto bad;
+ if (verbose)
+ zperror(gettext("Could not connect to zone"));
+ close(sockfd);
+ return (-1);
}
- masterfd = sockfd;
+ return (sockfd);
+}
- msglen = snprintf(clientid, sizeof (clientid), "IDENT %lu %s %d\n",
- getpid(), setlocale(LC_MESSAGES, NULL), disconnect);
+
+static int
+handshake_zone_sock(int sockfd, unsigned int flags)
+{
+ char clientid[MAXPATHLEN];
+ char handshake[MAXPATHLEN], c;
+ int msglen;
+ int i = 0, err = 0;
+
+ msglen = snprintf(clientid, sizeof (clientid), "IDENT %s %u\n",
+ setlocale(LC_MESSAGES, NULL), flags);
if (msglen >= sizeof (clientid) || msglen < 0) {
zerror("protocol error");
- goto bad;
+ return (-1);
}
- if (write(masterfd, clientid, msglen) != msglen) {
+ if (write(sockfd, clientid, msglen) != msglen) {
zerror("protocol error");
- goto bad;
+ return (-1);
}
- bzero(handshake, sizeof (handshake));
-
/*
* Take care not to accumulate more than our fill, and leave room for
* the NUL at the end.
*/
- while ((err = read(masterfd, &c, 1)) == 1) {
+ bzero(handshake, sizeof (handshake));
+ while ((err = read(sockfd, &c, 1)) == 1) {
if (i >= (sizeof (handshake) - 1))
break;
if (c == '\n')
@@ -310,26 +329,48 @@ get_console_master(const char *zname)
}
/*
- * If something went wrong during the handshake we bail; perhaps
- * the server died off.
+ * If something went wrong during the handshake we bail.
+ * Perhaps the server died off.
*/
if (err == -1) {
- zperror(gettext("Could not connect to zone console"));
- goto bad;
+ zperror(gettext("Could not connect to zone"));
+ return (-1);
}
- if (strncmp(handshake, "OK", sizeof (handshake)) == 0)
- return (0);
+ if (strncmp(handshake, "OK", sizeof (handshake)) != 0) {
+ zerror(gettext("Zone is already in use by process ID %s."),
+ handshake);
+ return (-1);
+ }
- zerror(gettext("Console is already in use by process ID %s."),
- handshake);
-bad:
- (void) close(sockfd);
- masterfd = -1;
- return (-1);
+ return (0);
}
-
+static int
+send_ctl_sock(const char *buf, size_t len)
+{
+ char rbuf[BUFSIZ];
+ int i;
+ if (ctlfd == -1) {
+ return (-1);
+ }
+ if (write(ctlfd, buf, len) != len) {
+ return (-1);
+ }
+ /* read the response */
+ for (i = 0; i < (BUFSIZ - 1); i++) {
+ char c;
+ if (read(ctlfd, &c, 1) != 1 || c == '\n' || c == '\0') {
+ break;
+ }
+ rbuf[i] = c;
+ }
+ rbuf[i+1] = '\0';
+ if (strncmp("OK", rbuf, BUFSIZ) != 0) {
+ return (-1);
+ }
+ return (0);
+}
/*
* Routines to handle pty creation upon zone entry and to shuttle I/O back
* and forth between the two terminals. We also compute and store the
@@ -518,8 +559,32 @@ sigwinch(int s)
{
struct winsize ws;
- if (ioctl(0, TIOCGWINSZ, &ws) == 0)
- (void) ioctl(masterfd, TIOCSWINSZ, &ws);
+ if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
+ if (ctlfd != -1) {
+ char buf[BUFSIZ];
+ snprintf(buf, sizeof (buf), "TIOCSWINSZ %hu %hu\n",
+ ws.ws_row, ws.ws_col);
+ (void) send_ctl_sock(buf, strlen(buf));
+ } else {
+ (void) ioctl(masterfd, TIOCSWINSZ, &ws);
+ }
+ }
+}
+
+/*
+ * Toggle zfd EOF mode and notify zoneadmd
+ */
+/*ARGSUSED*/
+static void
+sigusr1(int s)
+{
+ connect_flags ^= ZLOGIN_ZFD_EOF;
+ if (ctlfd != -1) {
+ char buf[BUFSIZ];
+ snprintf(buf, sizeof (buf), "SETFLAGS %u\n",
+ connect_flags);
+ (void) send_ctl_sock(buf, strlen(buf));
+ }
}
static volatile int close_on_sig = -1;
@@ -863,28 +928,34 @@ doio(int stdin_fd, int appin_fd, int stdout_fd, int stderr_fd, int sig_fd,
break;
}
- /* event from master side stdout */
- if (pollfds[0].revents) {
- if (pollfds[0].revents &
+ /* event from master side stderr */
+ if (pollfds[1].revents) {
+ if (pollfds[1].revents & POLLHUP)
+ break;
+
+ if (pollfds[1].revents &
(POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
- if (process_output(stdout_fd, STDOUT_FILENO)
+ if (process_output(stderr_fd, STDERR_FILENO)
!= 0)
break;
} else {
- pollerr = pollfds[0].revents;
+ pollerr = pollfds[1].revents;
break;
}
}
- /* event from master side stderr */
- if (pollfds[1].revents) {
- if (pollfds[1].revents &
+ /* event from master side stdout */
+ if (pollfds[0].revents) {
+ if (pollfds[0].revents & POLLHUP)
+ break;
+
+ if (pollfds[0].revents &
(POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
- if (process_output(stderr_fd, STDERR_FILENO)
+ if (process_output(stdout_fd, STDOUT_FILENO)
!= 0)
break;
} else {
- pollerr = pollfds[1].revents;
+ pollerr = pollfds[0].revents;
break;
}
}
@@ -1054,7 +1125,7 @@ zone_login_cmd(brand_handle_t bh, const char *login)
* but we're going to be very simplistic about it and break stuff
* up based on spaces. We're not even going to support any kind
* of quoting or escape characters. It's truly amazing that
- * there is no library function in OpenSolaris to do this for us.
+ * there is no library function in Illumos to do this for us.
*/
/*
@@ -1093,69 +1164,155 @@ zone_login_cmd(brand_handle_t bh, const char *login)
}
/*
- * Prepare argv array for exec'd process; if we're passing commands to the
- * new process, then use su(1M) to do the invocation. Otherwise, use
+ * Prepare argv array for exec'd process. If commands are passed to the new
+ * process and su(1M) is avalable, use it for the invocation. Otherwise, use
* 'login -z <from_zonename> -f' (-z is an undocumented option which tells
* login that we're coming from another zone, and to disregard its CONSOLE
* checks).
*/
static char **
-prep_args(brand_handle_t bh, const char *login, char **argv)
+prep_args(brand_handle_t bh, char *zonename, const char *login, char **argv)
{
- int argc = 0, a = 0, i, n = -1;
- char **new_argv;
+ int argc = 0, i;
+ size_t subshell_len = 1;
+ char *subshell = NULL, *supath = NULL;
+ char **new_argv = NULL;
- if (argv != NULL) {
- size_t subshell_len = 1;
- char *subshell;
+ if (argv == NULL) {
+ if (failsafe) {
+ if ((new_argv = malloc(sizeof (char *) * 2)) == NULL)
+ return (NULL);
+ new_argv[0] = FAILSAFESHELL;
+ new_argv[1] = NULL;
+ } else {
+ new_argv = zone_login_cmd(bh, login);
+ }
+ return (new_argv);
+ }
- while (argv[argc] != NULL)
- argc++;
+ /*
+ * Attempt to locate a 'su' binary if not using the failsafe shell.
+ */
+ if (!failsafe) {
+ struct stat sb;
+ char zonepath[MAXPATHLEN];
+ char supath_check[MAXPATHLEN];
+
+ if (zone_get_zonepath(zonename, zonepath,
+ sizeof (zonepath)) != Z_OK) {
+ zerror(gettext("unable to determine zone "
+ "path"));
+ return (NULL);
+ }
- for (i = 0; i < argc; i++) {
- subshell_len += strlen(argv[i]) + 1;
+ (void) snprintf(supath_check, sizeof (supath), "%s/root/%s",
+ zonepath, SUPATH1);
+ if (stat(supath_check, &sb) == 0) {
+ supath = SUPATH1;
+ } else {
+ (void) snprintf(supath_check, sizeof (supath_check),
+ "%s/root/%s", zonepath, SUPATH2);
+ if (stat(supath_check, &sb) == 0) {
+ supath = SUPATH2;
+ }
}
- if ((subshell = calloc(1, subshell_len)) == NULL)
+ }
+
+ /*
+ * With no failsafe shell or supath to wrap the incoming command, the
+ * arguments are passed straight through.
+ */
+ if (!failsafe && supath == NULL) {
+ /*
+ * Such an outcome is not acceptable, however, if the caller
+ * expressed a desire to switch users.
+ */
+ if (strcmp(login, "root") != 0) {
+ zerror(gettext("unable to find 'su' command"));
return (NULL);
+ }
+ return (argv);
+ }
- for (i = 0; i < argc; i++) {
- (void) strcat(subshell, argv[i]);
+ /*
+ * Inventory arguments and allocate a buffer to escape them for the
+ * subshell.
+ */
+ while (argv[argc] != NULL) {
+ /*
+ * Allocate enough space for the delimiter and 2
+ * quotes which might be needed.
+ */
+ subshell_len += strlen(argv[argc]) + 3;
+ argc++;
+ }
+ if ((subshell = calloc(1, subshell_len)) == NULL) {
+ return (NULL);
+ }
+
+ /*
+ * The handling of quotes in the following block may seem unusual, but
+ * it is done this way for backward compatibility.
+ * When running a command, zlogin is documented as:
+ * zlogin zonename command args
+ * However, some code has come to depend on the following usage:
+ * zlogin zonename 'command args'
+ * This relied on the fact that the single argument would be re-parsed
+ * within the zone and excuted as a command with an argument. To remain
+ * compatible with this (incorrect) usage, if there is only a single
+ * argument, it is not quoted, even if it has embedded spaces.
+ *
+ * Here are two examples which both need to work:
+ * 1) zlogin foo 'echo hello'
+ * This has a single argv member with a space in it but will not be
+ * quoted on the command passed into the zone.
+ * 2) zlogin foo bash -c 'echo hello'
+ * This has 3 argv members. The 3rd arg has a space and must be
+ * quoted on the command passed into the zone.
+ */
+ for (i = 0; i < argc; i++) {
+ if (i > 0)
(void) strcat(subshell, " ");
+
+ if (argc > 1 && (strchr(argv[i], ' ') != NULL ||
+ strchr(argv[i], '\t') != NULL)) {
+ (void) strcat(subshell, "'");
+ (void) strcat(subshell, argv[i]);
+ (void) strcat(subshell, "'");
+ } else {
+ (void) strcat(subshell, argv[i]);
}
+ }
- if (failsafe) {
- n = 4;
- if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
- return (NULL);
+ if (failsafe) {
+ int a = 0, n = 4;
- new_argv[a++] = FAILSAFESHELL;
- } else {
- n = 5;
- if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
- return (NULL);
+ if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
+ return (NULL);
- new_argv[a++] = SUPATH;
- if (strcmp(login, "root") != 0) {
- new_argv[a++] = "-";
- n++;
- }
- new_argv[a++] = (char *)login;
- }
+ new_argv[a++] = FAILSAFESHELL;
new_argv[a++] = "-c";
new_argv[a++] = subshell;
new_argv[a++] = NULL;
assert(a == n);
} else {
- if (failsafe) {
- n = 2;
- if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
- return (NULL);
- new_argv[a++] = FAILSAFESHELL;
- new_argv[a++] = NULL;
- assert(n == a);
+ int a = 0, n = 6;
+
+ assert(supath != NULL);
+ if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
+ return (NULL);
+
+ new_argv[a++] = supath;
+ if (strcmp(login, "root") != 0) {
+ new_argv[a++] = "-";
} else {
- new_argv = zone_login_cmd(bh, login);
+ n--;
}
+ new_argv[a++] = (char *)login;
+ new_argv[a++] = "-c";
+ new_argv[a++] = subshell;
+ new_argv[a++] = NULL;
+ assert(a == n);
}
return (new_argv);
@@ -1186,6 +1343,7 @@ prep_env()
int e = 0, size = 1;
char **new_env, *estr;
char *term = getenv("TERM");
+ char *path;
size++; /* for $PATH */
if (term != NULL)
@@ -1202,7 +1360,12 @@ prep_env()
if ((new_env = malloc(sizeof (char *) * size)) == NULL)
return (NULL);
- if ((estr = add_env("PATH", DEF_PATH)) == NULL)
+ if (strcmp(zonebrand, "lx") == 0)
+ path = LX_DEF_PATH;
+ else
+ path = DEF_PATH;
+
+ if ((estr = add_env("PATH", path)) == NULL)
return (NULL);
new_env[e++] = estr;
@@ -1724,24 +1887,61 @@ get_username()
return (nptr->pw_name);
}
+static boolean_t
+zlog_mode_logging(char *zonename, boolean_t *found)
+{
+ boolean_t lm = B_FALSE;
+ zone_dochandle_t handle;
+ struct zone_attrtab attr;
+
+ *found = B_FALSE;
+ if ((handle = zonecfg_init_handle()) == NULL)
+ return (lm);
+
+ if (zonecfg_get_handle(zonename, handle) != Z_OK)
+ goto done;
+
+ if (zonecfg_setattrent(handle) != Z_OK)
+ goto done;
+ while (zonecfg_getattrent(handle, &attr) == Z_OK) {
+ if (strcmp("zlog-mode", attr.zone_attr_name) == 0) {
+ int len = strlen(attr.zone_attr_value);
+
+ *found = B_TRUE;
+ if (strncmp("log", attr.zone_attr_value, 3) == 0 ||
+ strncmp("nolog", attr.zone_attr_value, 5) == 0 ||
+ (len >= 3 && attr.zone_attr_value[len - 2] == '-'))
+ lm = B_TRUE;
+ break;
+ }
+ }
+ (void) zonecfg_endattrent(handle);
+
+done:
+ zonecfg_fini_handle(handle);
+ return (lm);
+}
+
int
main(int argc, char **argv)
{
- int arg, console = 0;
+ int arg, console = 0, imode = 0;
+ int estatus = 0;
zoneid_t zoneid;
zone_state_t st;
char *login = "root";
+ int iflag = 0;
int lflag = 0;
int nflag = 0;
char *zonename = NULL;
char **proc_args = NULL;
char **new_args, **new_env;
sigset_t block_cld;
+ siginfo_t si;
char devroot[MAXPATHLEN];
char *slavename, slaveshortname[MAXPATHLEN];
priv_set_t *privset;
int tmpl_fd;
- char zonebrand[MAXNAMELEN];
char default_brand[MAXNAMELEN];
struct stat sb;
char kernzone[ZONENAME_MAX];
@@ -1755,7 +1955,7 @@ main(int argc, char **argv)
(void) getpname(argv[0]);
username = get_username();
- while ((arg = getopt(argc, argv, "dnECR:Se:l:Q")) != EOF) {
+ while ((arg = getopt(argc, argv, "diNnECIR:Se:l:Q")) != EOF) {
switch (arg) {
case 'C':
console = 1;
@@ -1763,6 +1963,16 @@ main(int argc, char **argv)
case 'E':
nocmdchar = 1;
break;
+ case 'I':
+ /*
+ * interactive mode is just a slight variation on the
+ * console mode.
+ */
+ console = 1;
+ imode = 1;
+ /* The default is HUP, disconnect on EOF */
+ connect_flags ^= ZLOGIN_ZFD_EOF;
+ break;
case 'R': /* undocumented */
if (*optarg != '/') {
zerror(gettext("root path must be absolute."));
@@ -1782,15 +1992,22 @@ main(int argc, char **argv)
failsafe = 1;
break;
case 'd':
- disconnect = 1;
+ connect_flags |= ZLOGIN_DISCONNECT;
break;
case 'e':
set_cmdchar(optarg);
break;
+ case 'i':
+ iflag = 1;
+ break;
case 'l':
login = optarg;
lflag = 1;
break;
+ case 'N':
+ /* NOHUP - do not send EOF */
+ connect_flags ^= ZLOGIN_ZFD_EOF;
+ break;
case 'n':
nflag = 1;
break;
@@ -1801,6 +2018,12 @@ main(int argc, char **argv)
if (console != 0) {
+ /*
+ * The only connect option in console mode is ZLOGIN_DISCONNECT
+ */
+ if (imode == 0)
+ connect_flags &= ZLOGIN_DISCONNECT;
+
if (lflag != 0) {
zerror(gettext(
"-l may not be specified for console login"));
@@ -1827,17 +2050,27 @@ main(int argc, char **argv)
}
+ if (iflag != 0 && nflag != 0) {
+ zerror(gettext("-i and -n flags are incompatible"));
+ usage();
+ }
+
if (failsafe != 0 && lflag != 0) {
zerror(gettext("-l may not be specified for failsafe login"));
usage();
}
- if (!console && disconnect != 0) {
+ if (!console && (connect_flags & ZLOGIN_DISCONNECT) != 0) {
zerror(gettext(
"-d may only be specified with console login"));
usage();
}
+ if (imode == 0 && (connect_flags & ZLOGIN_ZFD_EOF) != 0) {
+ zerror(gettext("-N may only be specified with -I"));
+ usage();
+ }
+
if (optind == (argc - 1)) {
/*
* zone name, no process name; this should be an interactive
@@ -1860,7 +2093,8 @@ main(int argc, char **argv)
/* zone name and process name, and possibly some args */
zonename = argv[optind];
proc_args = &argv[optind + 1];
- interactive = 0;
+ if (iflag && isatty(STDIN_FILENO))
+ interactive = 1;
} else {
usage();
}
@@ -1946,10 +2180,31 @@ main(int argc, char **argv)
}
/*
- * The console is a separate case from the rest of the code; handle
- * it first.
+ * The console (or standalong interactive mode) is a separate case from
+ * the rest of the code; handle it first.
*/
if (console) {
+ int gz_stderr_fd = -1;
+ int retry;
+ boolean_t set_raw = B_TRUE;
+
+ if (imode) {
+ boolean_t has_zfd_config;
+
+ if (zlog_mode_logging(zonename, &has_zfd_config))
+ set_raw = B_FALSE;
+
+ /*
+ * Asked for standalone interactive mode but the
+ * zlog-mode attribute is not configured on the zone.
+ */
+ if (!has_zfd_config) {
+ zerror(gettext("'%s' is not configured on "
+ "the zone"), "zlog-mode");
+ return (1);
+ }
+ }
+
/*
* Ensure that zoneadmd for this zone is running.
*/
@@ -1958,16 +2213,56 @@ main(int argc, char **argv)
/*
* Make contact with zoneadmd.
+ *
+ * Handshake with the control socket first. We handle retries
+ * here since the relevant thread in zoneadmd might not have
+ * finished setting up yet.
*/
- if (get_console_master(zonename) == -1)
+ for (retry = 0; retry < MAX_RETRY; retry++) {
+ masterfd = connect_zone_sock(zonename,
+ (imode ? "server_ctl" : "console_sock"), B_FALSE);
+ if (masterfd != -1)
+ break;
+ sleep(1);
+ }
+
+ if (retry == MAX_RETRY) {
+ zerror(gettext("unable to connect for %d seconds"),
+ MAX_RETRY);
return (1);
+ }
- if (!quiet)
- (void) printf(
- gettext("[Connected to zone '%s' console]\n"),
- zonename);
+ if (handshake_zone_sock(masterfd, connect_flags) != 0) {
+ (void) close(masterfd);
+ return (1);
+ }
+
+ if (imode) {
+ ctlfd = masterfd;
+
+ /* Now open the io-related sockets */
+ masterfd = connect_zone_sock(zonename, "server_out",
+ B_TRUE);
+ gz_stderr_fd = connect_zone_sock(zonename,
+ "server_err", B_TRUE);
+ if (masterfd == -1 || gz_stderr_fd == -1) {
+ (void) close(ctlfd);
+ (void) close(masterfd);
+ (void) close(gz_stderr_fd);
+ return (1);
+ }
+ }
+
+ if (!quiet) {
+ if (imode)
+ (void) printf(gettext("[Connected to zone '%s' "
+ "interactively]\n"), zonename);
+ else
+ (void) printf(gettext("[Connected to zone '%s' "
+ "console]\n"), zonename);
+ }
- if (set_tty_rawmode(STDIN_FILENO) == -1) {
+ if (set_raw && set_tty_rawmode(STDIN_FILENO) == -1) {
reset_tty();
zperror(gettext("failed to set stdin pty to raw mode"));
return (1);
@@ -1976,15 +2271,25 @@ main(int argc, char **argv)
(void) sigset(SIGWINCH, sigwinch);
(void) sigwinch(0);
+ if (imode) {
+ /* Allow EOF mode toggling via SIGUSR1 */
+ (void) sigset(SIGUSR1, sigusr1);
+ }
+
/*
* Run the I/O loop until we get disconnected.
*/
- doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
+ doio(masterfd, -1, masterfd, gz_stderr_fd, -1, B_FALSE);
reset_tty();
- if (!quiet)
- (void) printf(
- gettext("\n[Connection to zone '%s' console "
- "closed]\n"), zonename);
+ if (!quiet) {
+ if (imode)
+ (void) printf(gettext("\n[Interactive "
+ "connection to zone '%s' closed]\n"),
+ zonename);
+ else
+ (void) printf(gettext("\n[Connection to zone "
+ "'%s' console closed]\n"), zonename);
+ }
return (0);
}
@@ -2052,11 +2357,23 @@ main(int argc, char **argv)
return (1);
}
- if ((new_args = prep_args(bh, login, proc_args)) == NULL) {
- zperror(gettext("could not assemble new arguments"));
- brand_close(bh);
- return (1);
+ /*
+ * The 'interactive' parameter (-i option) indicates that we're running
+ * a command interactively. In this case we skip prep_args so that we
+ * don't prepend the 'su root -c' preamble to the command invocation
+ * since the 'su' command typically will execute a setpgrp which will
+ * disassociate the actual command from the controlling terminal that
+ * we (zlogin) setup.
+ */
+ if (!iflag) {
+ if ((new_args = prep_args(bh, zonename, login, proc_args))
+ == NULL) {
+ zperror(gettext("could not assemble new arguments"));
+ brand_close(bh);
+ return (1);
+ }
}
+
/*
* Get the brand specific user_cmd. This command is used to get
* a passwd(4) entry for login.
@@ -2202,6 +2519,8 @@ main(int argc, char **argv)
return (1);
}
+ /* Note: we're now inside the zone, can't use gettext anymore */
+
if (slavefd != STDERR_FILENO)
(void) close(STDERR_FILENO);
@@ -2243,8 +2562,18 @@ main(int argc, char **argv)
/*
* In failsafe mode, we don't use login(1), so don't try
* setting up a utmpx entry.
+ *
+ * A branded zone may have very different utmpx semantics.
+ * At the moment, we only have two brand types:
+ * Illumos-like (native, sn1) and Linux. In the Illumos
+ * case, we know exactly how to do the necessary utmpx
+ * setup. Fortunately for us, the Linux /bin/login is
+ * prepared to deal with a non-initialized utmpx entry, so
+ * we can simply skip it. If future brands don't fall into
+ * either category, we'll have to add a per-brand utmpx
+ * setup hook.
*/
- if (!failsafe)
+ if (!failsafe && (strcmp(zonebrand, "lx") != 0))
if (setup_utmpx(slaveshortname) == -1)
return (1);
@@ -2253,13 +2582,17 @@ main(int argc, char **argv)
* execute the brand's login program.
*/
if (setuid(0) == -1) {
- zperror(gettext("insufficient privilege"));
+ zperror("insufficient privilege");
return (1);
}
- (void) execve(new_args[0], new_args, new_env);
- zperror(gettext("exec failure"));
- return (1);
+ if (iflag) {
+ (void) execve(proc_args[0], proc_args, new_env);
+ } else {
+ (void) execve(new_args[0], new_args, new_env);
+ }
+ zperror("exec failure");
+ return (ENOEXEC);
}
(void) ct_tmpl_clear(tmpl_fd);
@@ -2284,8 +2617,19 @@ main(int argc, char **argv)
if (pollerr != 0) {
(void) fprintf(stderr, gettext("Error: connection closed due "
"to unexpected pollevents=0x%x.\n"), pollerr);
- return (1);
+ return (EPIPE);
}
- return (0);
+ /* reap child and get its status */
+ if (waitid(P_PID, child_pid, &si, WEXITED | WNOHANG) == -1) {
+ estatus = errno;
+ } else if (si.si_pid == 0) {
+ estatus = ECHILD;
+ } else if (si.si_code == CLD_EXITED) {
+ estatus = si.si_status;
+ } else {
+ estatus = ECONNABORTED;
+ }
+
+ return (estatus);
}
diff --git a/usr/src/cmd/zoneadm/Makefile b/usr/src/cmd/zoneadm/Makefile
index 5dea2ace60..4581c14af9 100644
--- a/usr/src/cmd/zoneadm/Makefile
+++ b/usr/src/cmd/zoneadm/Makefile
@@ -21,14 +21,18 @@
#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
#
PROG= zoneadm
+SCRIPTS=
MANIFEST= zones.xml resource-mgmt.xml
SVCMETHOD= svc-zones svc-resource-mgmt
include ../Makefile.cmd
+include ../Makefile.ctf
+ROOTUSRSBINSCRIPTS= $(SCRIPTS:%=$(ROOTUSRSBIN)/%)
ROOTMANIFESTDIR= $(ROOTSVCSYSTEM)
OBJS= zoneadm.o zfs.o
@@ -44,13 +48,14 @@ CERRWARN += $(CNOWARN_UNINIT)
.KEEP_STATE:
-all: $(PROG)
+all: $(PROG) $(SCRIPTS)
$(PROG): $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
$(POST_PROCESS)
-install: all $(ROOTUSRSBINPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+install: all $(ROOTUSRSBINPROG) $(ROOTUSRSBINSCRIPTS) $(ROOTMANIFEST) \
+ $(ROOTSVCMETHOD)
check: $(PROG).c $(CHKMANIFEST)
$(CSTYLE) -pP $(SRCS:%=%)
@@ -60,7 +65,7 @@ $(POFILE): $(POFILES)
$(CAT) $(POFILES) > $@
clean:
- $(RM) $(OBJS) $(POFILES)
+ $(RM) $(OBJS) $(POFILES) $(SCRIPTS)
lint: lint_SRCS
diff --git a/usr/src/cmd/zoneadm/svc-resource-mgmt b/usr/src/cmd/zoneadm/svc-resource-mgmt
index 762de4c0d8..57fd21c3d9 100644
--- a/usr/src/cmd/zoneadm/svc-resource-mgmt
+++ b/usr/src/cmd/zoneadm/svc-resource-mgmt
@@ -22,25 +22,19 @@
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-
-# ident "%Z%%M% %I% %E% SMI"
-#
+# Copyright 2012 Joyent, Inc. All rights reserved.
. /lib/svc/share/smf_include.sh
-[ ! -f /etc/zones/global.xml ] && exit $SMF_EXIT_OK # No global zone
- # resource mgmt.
- # configuration
-
-[ ! -x /usr/sbin/zoneadm ] && exit $SMF_EXIT_OK # SUNWzoneu not installed
-
# Make sure working directory is / to prevent unmounting problems.
cd /
PATH=/usr/sbin:/usr/bin; export PATH
+smf_is_globalzone || exit $SMF_EXIT_OK
+
case "$1" in
'start')
- zoneadm -z global apply
+ prctl -r -n zone.cpu-shares -v 65535 -t priv -i zone global
if [ $? -ne 0 ]; then
exit $SMF_EXIT_ERR_FATAL
fi
diff --git a/usr/src/cmd/zoneadm/svc-zones b/usr/src/cmd/zoneadm/svc-zones
index 9d307835bd..41f6b3325f 100644
--- a/usr/src/cmd/zoneadm/svc-zones
+++ b/usr/src/cmd/zoneadm/svc-zones
@@ -22,9 +22,128 @@
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright (c) 2012, Joyent Inc. All rights reserved.
+
+set -o xtrace
. /lib/svc/share/smf_include.sh
+ZPOOL=`svcprop -p config/zpool svc:/system/smartdc/init:default 2>/dev/null`
+ZPOOL=${ZPOOL:-zones}
+
+MAN_SRCDIR=/lib/svc/manifest
+MAN_DESTDIR=/$ZPOOL/manifests
+
+MAN_DIRS="\
+ application \
+ milestone \
+ network \
+ network/dns \
+ network/ipsec \
+ network/ldap \
+ network/loadbalancer \
+ network/nfs \
+ network/nis \
+ network/routing \
+ network/rpc \
+ network/security \
+ network/shares \
+ network/smb \
+ network/ssl \
+ site \
+ system \
+ system/device \
+ system/filesystem \
+ system/fm \
+ system/install \
+ system/security \
+ system/svc"
+
+cp_brand_manifests()
+{
+ brand=$1
+
+ # Create the dir hierarchy under the dest dir for SMF manifests.
+ mkdir -m755 $MAN_DESTDIR/$brand
+
+ for dir in $MAN_DIRS
+ do
+ mkdir -m755 $MAN_DESTDIR/$brand/$dir
+ done
+
+ #
+ # Process the SMF SVC configuration list to setup the brand-specific
+ # SMF svcs.
+ #
+ nawk -v base=$MAN_SRCDIR -v dest=$MAN_DESTDIR/$brand '{
+ # Ignore comments and empty lines.
+ if (substr($1, 1, 1) == "#" || length($1) == 0)
+ next
+
+ # entry format is: name status
+ proc_file($1, $2);
+ }
+
+ #
+ # Copy the manifest from the global zone to the brand-specific
+ # manifest area. At the same time, update any manifests whose
+ # status needs to be changed, based on what our configuration
+ # file indicates.
+ #
+ function proc_file(fname, status)
+ {
+ f = base "/" fname
+ of = dest "/" fname
+
+ while (getline <f > 0) {
+ # Fix up the console svc to work with zones.
+ if (fname == "system/console-login.xml")
+ sub("wscons", "console")
+
+ if (($1 == "<instance" &&
+ $2 == "name=\047default\047") ||
+ $1 == "<create_default_instance") {
+ if (status == "enabled")
+ n=sub("\047false\047", "\047true\047")
+ else
+ n=sub("\047true\047", "\047false\047")
+
+ if (n > 0)
+ printf("update svc state: %s %s\n",
+ fname, $0)
+ }
+
+ print $0 >of
+ }
+ close(f)
+ close(of)
+ }' /usr/lib/brand/$brand/manifests
+}
+
+#
+# If we're running off of a live-image, setup a zone-specific collection of
+# manifest files which are mounted in a zone's /lib/svc/manifest directory.
+#
+# Regenerate the manifest data each time this service starts, so that it's
+# always in sync with the running platform (and any fixes included there).
+#
+setup_manifests()
+{
+ echo "Initializing manifest dir."
+
+ rm -rf $MAN_DESTDIR
+ mkdir -m755 -p $MAN_DESTDIR
+
+ for i in /usr/lib/brand/*
+ do
+ brand=`basename $i`
+ [[ ! -f /usr/lib/brand/$brand/manifests ]] && continue
+ # joyent-minimal uses /zones/manifests/joyent too
+ [[ "$brand" == "joyent-minimal" ]] && continue
+ cp_brand_manifests $brand
+ done
+}
+
#
# Return a list of running, non-global zones for which a shutdown via
# "/sbin/init 0" may work (typically only Solaris zones.)
@@ -51,6 +170,16 @@ PATH=/usr/sbin:/usr/bin; export PATH
case "$1" in
'start')
+ #
+ # Generate the manifest, even if no zones, since zones could be
+ # provisioned later.
+ #
+ zfs list -H -o name $ZPOOL >/dev/null 2>&1
+ [ $? -eq 0 ] && setup_manifests
+
+ # Create directory for zone sockets
+ mkdir -m755 -p /var/zonecontrol
+
egrep -vs '^#|^global:' /etc/zones/index || exit 0 # no local zones
#
@@ -68,6 +197,14 @@ case "$1" in
[ -z "$ZONES" ] && echo "Booting zones:\c"
ZONES=yes
echo " $zone\c"
+
+ #
+ # Make sure a site dir exists, it wasn't initially
+ # being created.
+ #
+ zonepath=`zonecfg -z $zone info zonepath | cut -d: -f2`
+ [ ! -d $zonepath/site ] && mkdir -m755 $zonepath/site
+
#
# zoneadmd puts itself into its own contract so
# this service will lose sight of it. We don't
@@ -110,7 +247,7 @@ case "$1" in
for zone in $zonelist; do
echo " $zone\c"
- zoneadm -z $zone shutdown &
+ zlogin -S $zone /sbin/init 0 < /dev/null >&0 2>&0 &
SHUTDOWN=1
done
diff --git a/usr/src/cmd/zoneadm/zfs.c b/usr/src/cmd/zoneadm/zfs.c
index 15be33ddab..214340d0ce 100644
--- a/usr/src/cmd/zoneadm/zfs.c
+++ b/usr/src/cmd/zoneadm/zfs.c
@@ -21,8 +21,8 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 Martin Matuska. All rights reserved.
*/
@@ -968,6 +968,7 @@ create_zfs_zonepath(char *zonepath)
zfs_handle_t *zhp;
char zfs_name[MAXPATHLEN];
nvlist_t *props = NULL;
+ int i;
if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
return;
@@ -1003,9 +1004,20 @@ create_zfs_zonepath(char *zonepath)
nvlist_free(props);
- if (zfs_mount(zhp, NULL, 0) != 0) {
+ /*
+ * A monitoring tool might race with us and touch the mountpoint just
+ * as we're trying to mount, blocking the mount. We wait and retry a
+ * few times to workaround this race.
+ */
+ for (i = 0; i < 5; i++) {
+ if (zfs_mount(zhp, NULL, 0) == 0)
+ break;
(void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
"%s\n"), zfs_name, libzfs_error_description(g_zfs));
+ (void) sleep(1);
+ }
+
+ if (i >= 5) {
(void) zfs_destroy(zhp, B_FALSE);
} else {
if (chmod(zonepath, S_IRWXU) != 0) {
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index e5b1bc4a07..3487dcc7e6 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
* Copyright (c) 2015 by Delphix. All rights reserved.
*/
@@ -101,13 +102,11 @@ typedef struct zone_entry {
char zroot[MAXPATHLEN];
char zuuid[UUID_PRINTABLE_STRING_LENGTH];
zone_iptype_t ziptype;
+ zoneid_t zdid;
} zone_entry_t;
#define CLUSTER_BRAND_NAME "cluster"
-static zone_entry_t *zents;
-static size_t nzents;
-
#define LOOPBACK_IF "lo0"
#define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af))
@@ -406,19 +405,6 @@ zerror(const char *fmt, ...)
va_end(alist);
}
-static void *
-safe_calloc(size_t nelem, size_t elsize)
-{
- void *r = calloc(nelem, elsize);
-
- if (r == NULL) {
- zerror(gettext("failed to allocate %lu bytes: %s"),
- (ulong_t)nelem * elsize, strerror(errno));
- exit(Z_ERR);
- }
- return (r);
-}
-
static void
zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
{
@@ -443,6 +429,7 @@ zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
}
if (!verbose) {
char *cp, *clim;
+ char zdid[80];
if (!parsable) {
(void) printf("%s\n", zent->zname);
@@ -458,8 +445,12 @@ zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
(void) printf("%.*s\\:", clim - cp, cp);
cp = clim + 1;
}
- (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
- ip_type_str);
+ if (zent->zdid == -1)
+ zdid[0] = '\0';
+ else
+ (void) snprintf(zdid, sizeof (zdid), "%d", zent->zdid);
+ (void) printf("%s:%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
+ ip_type_str, zdid);
return;
}
if (zent->zstate_str != NULL) {
@@ -485,6 +476,9 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
(void) strlcpy(zent->zbrand, "???", sizeof (zent->zbrand));
zent->zstate_str = "???";
+ if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
+ zid = zent->zdid = GLOBAL_ZONEID;
+
zent->zid = zid;
if (zonecfg_get_uuid(zone_name, uuid) == Z_OK &&
@@ -529,8 +523,8 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
zent->zstate_str = zone_state_str(zent->zstate_num);
/*
- * A zone's brand is only available in the .xml file describing it,
- * which is only visible to the global zone. This causes
+ * A zone's brand might only be available in the .xml file describing
+ * it, which is only visible to the global zone. This causes
* zone_get_brand() to fail when called from within a non-global
* zone. Fortunately we only do this on labeled systems, where we
* know all zones are native.
@@ -554,6 +548,22 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
return (Z_OK);
}
+ if ((handle = zonecfg_init_handle()) == NULL) {
+ zperror2(zent->zname, gettext("could not init handle"));
+ return (Z_ERR);
+ }
+ if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
+ zperror2(zent->zname, gettext("could not get handle"));
+ zonecfg_fini_handle(handle);
+ return (Z_ERR);
+ }
+
+ if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
+ zperror2(zent->zname, gettext("could not get ip-type"));
+ zonecfg_fini_handle(handle);
+ return (Z_ERR);
+ }
+
/*
* There is a race condition where the zone could boot while
* we're walking the index file. In this case the zone state
@@ -574,193 +584,76 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
zent->ziptype = ZS_EXCLUSIVE;
else
zent->ziptype = ZS_SHARED;
- return (Z_OK);
}
}
- if ((handle = zonecfg_init_handle()) == NULL) {
- zperror2(zent->zname, gettext("could not init handle"));
- return (Z_ERR);
- }
- if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
- zperror2(zent->zname, gettext("could not get handle"));
- zonecfg_fini_handle(handle);
- return (Z_ERR);
- }
+ zent->zdid = zonecfg_get_did(handle);
- if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
- zperror2(zent->zname, gettext("could not get ip-type"));
- zonecfg_fini_handle(handle);
- return (Z_ERR);
- }
zonecfg_fini_handle(handle);
return (Z_OK);
}
-/*
- * fetch_zents() calls zone_list(2) to find out how many zones are running
- * (which is stored in the global nzents), then calls zone_list(2) again
- * to fetch the list of running zones (stored in the global zents). This
- * function may be called multiple times, so if zents is already set, we
- * return immediately to save work.
- *
- * Note that the data about running zones can change while this function
- * is running, so its possible that the list of zones will have empty slots
- * at the end.
- */
-
-static int
-fetch_zents(void)
-{
- zoneid_t *zids = NULL;
- uint_t nzents_saved;
- int i, retv;
- FILE *fp;
- boolean_t inaltroot;
- zone_entry_t *zentp;
- const char *altroot;
-
- if (nzents > 0)
- return (Z_OK);
-
- if (zone_list(NULL, &nzents) != 0) {
- zperror(gettext("failed to get zoneid list"), B_FALSE);
- return (Z_ERR);
- }
-
-again:
- if (nzents == 0)
- return (Z_OK);
-
- zids = safe_calloc(nzents, sizeof (zoneid_t));
- nzents_saved = nzents;
-
- if (zone_list(zids, &nzents) != 0) {
- zperror(gettext("failed to get zone list"), B_FALSE);
- free(zids);
- return (Z_ERR);
- }
- if (nzents != nzents_saved) {
- /* list changed, try again */
- free(zids);
- goto again;
- }
-
- zents = safe_calloc(nzents, sizeof (zone_entry_t));
-
- inaltroot = zonecfg_in_alt_root();
- if (inaltroot) {
- fp = zonecfg_open_scratch("", B_FALSE);
- altroot = zonecfg_get_root();
- } else {
- fp = NULL;
- }
- zentp = zents;
- retv = Z_OK;
- for (i = 0; i < nzents; i++) {
- char name[ZONENAME_MAX];
- char altname[ZONENAME_MAX];
- char rev_altroot[MAXPATHLEN];
-
- if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
- /*
- * There is a race condition where the zone may have
- * shutdown since we retrieved the number of running
- * zones above. This is not an error, there will be
- * an empty slot at the end of the list.
- */
- continue;
- }
- if (zonecfg_is_scratch(name)) {
- /* Ignore scratch zones by default */
- if (!inaltroot)
- continue;
- if (fp == NULL ||
- zonecfg_reverse_scratch(fp, name, altname,
- sizeof (altname), rev_altroot,
- sizeof (rev_altroot)) == -1) {
- zerror(gettext("could not resolve scratch "
- "zone %s"), name);
- retv = Z_ERR;
- continue;
- }
- /* Ignore zones in other alternate roots */
- if (strcmp(rev_altroot, altroot) != 0)
- continue;
- (void) strcpy(name, altname);
- } else {
- /* Ignore non-scratch when in an alternate root */
- if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0)
- continue;
- }
- if (lookup_zone_info(name, zids[i], zentp) != Z_OK) {
- /*
- * There is a race condition where the zone may have
- * shutdown since we retrieved the number of running
- * zones above. This is not an error, there will be
- * an empty slot at the end of the list.
- */
- continue;
- }
- zentp++;
- }
- nzents = zentp - zents;
- if (fp != NULL)
- zonecfg_close_scratch(fp);
-
- free(zids);
- return (retv);
-}
-
static int
zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable,
boolean_t exclude_global)
{
- int i;
zone_entry_t zent;
FILE *cookie;
- char *name;
+ struct zoneent *ze;
/*
- * First get the list of running zones from the kernel and print them.
- * If that is all we need, then return.
- */
- if ((i = fetch_zents()) != Z_OK) {
- /*
- * No need for error messages; fetch_zents() has already taken
- * care of this.
- */
- return (i);
- }
- for (i = 0; i < nzents; i++) {
- if (exclude_global && zents[i].zid == GLOBAL_ZONEID)
- continue;
- zone_print(&zents[i], verbose, parsable);
- }
- if (min_state >= ZONE_STATE_RUNNING)
- return (Z_OK);
- /*
- * Next, get the full list of zones from the configuration, skipping
- * any we have already printed.
+ * Get the full list of zones from the configuration.
*/
cookie = setzoneent();
- while ((name = getzoneent(cookie)) != NULL) {
- for (i = 0; i < nzents; i++) {
- if (strcmp(zents[i].zname, name) == 0)
- break;
- }
- if (i < nzents) {
- free(name);
- continue;
- }
- if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
- free(name);
+ while ((ze = getzoneent_private(cookie)) != NULL) {
+ char *name = ze->zone_name;
+ zoneid_t zid;
+
+ zid = getzoneidbyname(name);
+ if (exclude_global && zid == GLOBAL_ZONEID)
continue;
+
+ if (ze->zone_brand[0] == '\0') {
+ /* old, incomplete index entry */
+ if (lookup_zone_info(name, zid, &zent) != Z_OK) {
+ free(ze);
+ continue;
+ }
+ } else {
+ /* new, full index entry */
+ (void) strlcpy(zent.zname, name, sizeof (zent.zname));
+ (void) strlcpy(zent.zroot, ze->zone_path,
+ sizeof (zent.zroot));
+ uuid_unparse(ze->zone_uuid, zent.zuuid);
+ (void) strlcpy(zent.zbrand, ze->zone_brand,
+ sizeof (zent.zbrand));
+ zent.ziptype = ze->zone_iptype;
+ zent.zdid = ze->zone_did;
+ zent.zid = zid;
+
+ if (zid != -1) {
+ int err;
+
+ err = zone_get_state(name,
+ (zone_state_t *)&ze->zone_state);
+ if (err != Z_OK) {
+ errno = err;
+ zperror2(name, gettext("could not get "
+ "state"));
+ free(ze);
+ continue;
+ }
+ }
+
+ zent.zstate_num = ze->zone_state;
+ zent.zstate_str = zone_state_str(zent.zstate_num);
}
- free(name);
+
if (zent.zstate_num >= min_state)
zone_print(&zent, verbose, parsable);
+
+ free(ze);
}
endzoneent(cookie);
return (Z_OK);
@@ -770,18 +663,22 @@ zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable,
* Retrieve a zone entry by name. Returns NULL if no such zone exists.
*/
static zone_entry_t *
-lookup_running_zone(const char *str)
+lookup_running_zone(const char *name)
{
- int i;
+ zoneid_t zid;
+ zone_entry_t *zent;
+
+ if ((zid = getzoneidbyname(name)) == -1)
+ return (NULL);
- if (fetch_zents() != Z_OK)
+ if ((zent = malloc(sizeof (zone_entry_t))) == NULL)
return (NULL);
- for (i = 0; i < nzents; i++) {
- if (strcmp(str, zents[i].zname) == 0)
- return (&zents[i]);
+ if (lookup_zone_info(name, zid, zent) != Z_OK) {
+ free(zent);
+ return (NULL);
}
- return (NULL);
+ return (zent);
}
/*
@@ -1017,8 +914,12 @@ validate_zonepath(char *path, int cmd_num)
(void) printf(gettext("WARNING: %s is on a temporary "
"file system.\n"), rpath);
}
- if (crosscheck_zonepaths(rpath) != Z_OK)
- return (Z_ERR);
+ if (cmd_num != CMD_BOOT && cmd_num != CMD_REBOOT &&
+ cmd_num != CMD_READY) {
+ /* we checked when we installed, no need to check each boot */
+ if (crosscheck_zonepaths(rpath) != Z_OK)
+ return (Z_ERR);
+ }
/*
* Try to collect and report as many minor errors as possible
* before returning, so the user can learn everything that needs
@@ -1205,6 +1106,7 @@ static int
ready_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
+ boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
@@ -1213,11 +1115,14 @@ ready_func(int argc, char *argv[])
}
optind = 0;
- if ((arg = getopt(argc, argv, "?")) != EOF) {
+ if ((arg = getopt(argc, argv, "?X")) != EOF) {
switch (arg) {
case '?':
sub_usage(SHELP_READY, CMD_READY);
return (optopt == '?' ? Z_OK : Z_USAGE);
+ case 'X':
+ debug = B_TRUE;
+ break;
default:
sub_usage(SHELP_READY, CMD_READY);
return (Z_USAGE);
@@ -1234,6 +1139,7 @@ ready_func(int argc, char *argv[])
return (Z_ERR);
zarg.cmd = Z_READY;
+ zarg.debug = debug;
if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
zerror(gettext("call to %s failed"), "zoneadmd");
return (Z_ERR);
@@ -1246,6 +1152,7 @@ boot_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
boolean_t force = B_FALSE;
+ boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
@@ -1272,7 +1179,7 @@ boot_func(int argc, char *argv[])
* zoneadm -z myzone boot -- -s -v -m verbose.
*/
optind = 0;
- while ((arg = getopt(argc, argv, "?fs")) != EOF) {
+ while ((arg = getopt(argc, argv, "?fsX")) != EOF) {
switch (arg) {
case '?':
sub_usage(SHELP_BOOT, CMD_BOOT);
@@ -1284,6 +1191,9 @@ boot_func(int argc, char *argv[])
case 'f':
force = B_TRUE;
break;
+ case 'X':
+ debug = B_TRUE;
+ break;
default:
sub_usage(SHELP_BOOT, CMD_BOOT);
return (Z_USAGE);
@@ -1309,6 +1219,7 @@ boot_func(int argc, char *argv[])
if (verify_details(CMD_BOOT, argv) != Z_OK)
return (Z_ERR);
zarg.cmd = force ? Z_FORCEBOOT : Z_BOOT;
+ zarg.debug = debug;
if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
zerror(gettext("call to %s failed"), "zoneadmd");
return (Z_ERR);
@@ -1623,10 +1534,10 @@ auth_check(char *user, char *zone, int cmd_num)
* not already running (or ready).
*/
static int
-sanity_check(char *zone, int cmd_num, boolean_t running,
+sanity_check(char *zone, int cmd_num, boolean_t need_running,
boolean_t unsafe_when_running, boolean_t force)
{
- zone_entry_t *zent;
+ boolean_t is_running = B_FALSE;
priv_set_t *privset;
zone_state_t state, min_state;
char kernzone[ZONENAME_MAX];
@@ -1697,51 +1608,54 @@ sanity_check(char *zone, int cmd_num, boolean_t running,
}
if (!zonecfg_in_alt_root()) {
- zent = lookup_running_zone(zone);
- } else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) {
- zent = NULL;
- } else {
- if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(),
- kernzone, sizeof (kernzone)) == 0)
- zent = lookup_running_zone(kernzone);
- else
- zent = NULL;
+ /* Avoid the xml read overhead of lookup_running_zone */
+ if (getzoneidbyname(zone) != -1)
+ is_running = B_TRUE;
+
+ } else if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
+ if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(), kernzone,
+ sizeof (kernzone)) == 0 && getzoneidbyname(kernzone) != -1)
+ is_running = B_TRUE;
+
zonecfg_close_scratch(fp);
}
/*
* Look up from the kernel for 'running' zones.
*/
- if (running && !force) {
- if (zent == NULL) {
+ if (need_running && !force) {
+ if (!is_running) {
zerror(gettext("not running"));
return (Z_ERR);
}
} else {
int err;
- if (unsafe_when_running && zent != NULL) {
+ err = zone_get_state(zone, &state);
+
+ if (unsafe_when_running && is_running) {
/* check whether the zone is ready or running */
- if ((err = zone_get_state(zent->zname,
- &zent->zstate_num)) != Z_OK) {
+ char *zstate_str;
+
+ if (err != Z_OK) {
errno = err;
- zperror2(zent->zname,
- gettext("could not get state"));
+ zperror2(zone, gettext("could not get state"));
/* can't tell, so hedge */
- zent->zstate_str = "ready/running";
+ zstate_str = "ready/running";
} else {
- zent->zstate_str =
- zone_state_str(zent->zstate_num);
+ zstate_str = zone_state_str(state);
}
zerror(gettext("%s operation is invalid for %s zones."),
- cmd_to_str(cmd_num), zent->zstate_str);
+ cmd_to_str(cmd_num), zstate_str);
return (Z_ERR);
}
- if ((err = zone_get_state(zone, &state)) != Z_OK) {
+
+ if (err != Z_OK) {
errno = err;
zperror2(zone, gettext("could not get state"));
return (Z_ERR);
}
+
switch (cmd_num) {
case CMD_UNINSTALL:
if (state == ZONE_STATE_CONFIGURED) {
@@ -1829,6 +1743,7 @@ static int
halt_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
+ boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
@@ -1837,11 +1752,14 @@ halt_func(int argc, char *argv[])
}
optind = 0;
- if ((arg = getopt(argc, argv, "?")) != EOF) {
+ if ((arg = getopt(argc, argv, "?X")) != EOF) {
switch (arg) {
case '?':
sub_usage(SHELP_HALT, CMD_HALT);
return (optopt == '?' ? Z_OK : Z_USAGE);
+ case 'X':
+ debug = B_TRUE;
+ break;
default:
sub_usage(SHELP_HALT, CMD_HALT);
return (Z_USAGE);
@@ -1867,6 +1785,7 @@ halt_func(int argc, char *argv[])
return (Z_ERR);
zarg.cmd = Z_HALT;
+ zarg.debug = debug;
return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale,
B_TRUE) == 0) ? Z_OK : Z_ERR);
}
@@ -1944,6 +1863,7 @@ static int
reboot_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
+ boolean_t debug = B_FALSE;
int arg;
if (zonecfg_in_alt_root()) {
@@ -1952,11 +1872,14 @@ reboot_func(int argc, char *argv[])
}
optind = 0;
- if ((arg = getopt(argc, argv, "?")) != EOF) {
+ if ((arg = getopt(argc, argv, "?X")) != EOF) {
switch (arg) {
case '?':
sub_usage(SHELP_REBOOT, CMD_REBOOT);
return (optopt == '?' ? Z_OK : Z_USAGE);
+ case 'X':
+ debug = B_TRUE;
+ break;
default:
sub_usage(SHELP_REBOOT, CMD_REBOOT);
return (Z_USAGE);
@@ -1991,6 +1914,7 @@ reboot_func(int argc, char *argv[])
return (Z_ERR);
zarg.cmd = Z_REBOOT;
+ zarg.debug = debug;
return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) == 0)
? Z_OK : Z_ERR);
}
@@ -2218,6 +2142,10 @@ verify_fs_special(struct zone_fstab *fstab)
if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
return (verify_fs_zfs(fstab));
+ if (strcmp(fstab->zone_fs_type, MNTTYPE_HYPRLOFS) == 0 &&
+ strcmp(fstab->zone_fs_special, "swap") == 0)
+ return (Z_OK);
+
if (stat64(fstab->zone_fs_special, &st) != 0) {
(void) fprintf(stderr, gettext("could not verify fs "
"%s: could not access %s: %s\n"), fstab->zone_fs_dir,
@@ -2621,7 +2549,6 @@ verify_handle(int cmd_num, zone_dochandle_t handle, char *argv[])
dladm_handle_t dh;
dladm_status_t status;
datalink_id_t linkid;
- char errmsg[DLADM_STRSIZE];
in_alt_root = zonecfg_in_alt_root();
if (in_alt_root)
@@ -2704,11 +2631,6 @@ verify_handle(int cmd_num, zone_dochandle_t handle, char *argv[])
dladm_close(dh);
}
if (status != DLADM_STATUS_OK) {
- (void) fprintf(stderr,
- gettext("WARNING: skipping network "
- "interface '%s': %s\n"),
- nwiftab.zone_nwif_physical,
- dladm_status2str(status, errmsg));
break;
}
dl_owner_zid = ALL_ZONES;
@@ -2792,6 +2714,74 @@ no_net:
return (return_code);
}
+/*
+ * Called when readying or booting a zone. We double check that the zone's
+ * debug ID is set and is unique. This covers the case of pre-existing zones
+ * with no ID. Also, its possible that a zone was migrated to this host
+ * and as a result it has a duplicate ID. In this case we preserve the ID
+ * of the first zone we match on in the index file (since it was there before
+ * the current zone) and we assign a new unique ID to the current zone.
+ * Return true if we assigned a new ID, indicating that the zone configuration
+ * needs to be saved.
+ */
+static boolean_t
+verify_fix_did(zone_dochandle_t handle)
+{
+ zoneid_t mydid;
+ struct zoneent *ze;
+ FILE *cookie;
+ boolean_t fix = B_FALSE;
+
+ mydid = zonecfg_get_did(handle);
+ if (mydid == -1) {
+ zonecfg_set_did(handle);
+ return (B_TRUE);
+ }
+
+ /* Get the full list of zones from the configuration. */
+ cookie = setzoneent();
+ while ((ze = getzoneent_private(cookie)) != NULL) {
+ char *name;
+ zoneid_t did;
+
+ name = ze->zone_name;
+ if (strcmp(name, GLOBAL_ZONENAME) == 0 ||
+ strcmp(name, target_zone) == 0) {
+ free(ze);
+ continue;
+ }
+
+ if (ze->zone_brand[0] == '\0') {
+ /* old, incomplete index entry */
+ zone_entry_t zent;
+
+ if (lookup_zone_info(name, ZONE_ID_UNDEFINED,
+ &zent) != Z_OK) {
+ free(ze);
+ continue;
+ }
+ did = zent.zdid;
+ } else {
+ /* new, full index entry */
+ did = ze->zone_did;
+ }
+ free(ze);
+
+ if (did == mydid) {
+ fix = B_TRUE;
+ break;
+ }
+ }
+ endzoneent(cookie);
+
+ if (fix) {
+ zonecfg_set_did(handle);
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
static int
verify_details(int cmd_num, char *argv[])
{
@@ -2851,6 +2841,18 @@ verify_details(int cmd_num, char *argv[])
if (verify_handle(cmd_num, handle, argv) != Z_OK)
return_code = Z_ERR;
+ if (cmd_num == CMD_READY || cmd_num == CMD_BOOT) {
+ int vcommit = 0, obscommit = 0;
+
+ vcommit = verify_fix_did(handle);
+ obscommit = zonecfg_fix_obsolete(handle);
+
+ if (vcommit || obscommit)
+ if (zonecfg_save(handle) != Z_OK)
+ (void) fprintf(stderr, gettext("Could not save "
+ "updated configuration.\n"));
+ }
+
zonecfg_fini_handle(handle);
if (return_code == Z_ERR)
(void) fprintf(stderr,
@@ -2936,6 +2938,7 @@ install_func(int argc, char *argv[])
int status;
boolean_t do_postinstall = B_FALSE;
boolean_t brand_help = B_FALSE;
+ boolean_t do_dataset = B_TRUE;
char opts[128];
if (target_zone == NULL) {
@@ -3011,6 +3014,12 @@ install_func(int argc, char *argv[])
}
/* Ignore unknown options - may be brand specific. */
break;
+ case 'x':
+ if (strcmp(optarg, "nodataset") == 0) {
+ do_dataset = B_FALSE;
+ continue; /* internal arg, don't pass thru */
+ }
+ break;
default:
/* Ignore unknown options - may be brand specific. */
break;
@@ -3063,7 +3072,8 @@ install_func(int argc, char *argv[])
goto done;
}
- create_zfs_zonepath(zonepath);
+ if (do_dataset)
+ create_zfs_zonepath(zonepath);
}
status = do_subproc(cmdbuf);
@@ -3874,10 +3884,10 @@ cleanup_zonepath(char *zonepath, boolean_t all)
* exist if the zone was force-attached after a
* migration.
*/
- char *std_entries[] = {"dev", "lu", "root",
- "SUNWattached.xml", NULL};
- /* (MAXPATHLEN * 3) is for the 3 std_entries dirs */
- char cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 3) + 64];
+ char *std_entries[] = {"dev", "lastexited", "logs", "lu",
+ "root", "SUNWattached.xml", NULL};
+ /* (MAXPATHLEN * 5) is for the 5 std_entries dirs */
+ char cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 5) + 64];
/*
* We shouldn't need these checks but lets be paranoid since we
@@ -5027,6 +5037,7 @@ uninstall_func(int argc, char *argv[])
if (zonecfg_ping_zoneadmd(target_zone) == Z_OK) {
zone_cmd_arg_t zarg;
zarg.cmd = Z_NOTE_UNINSTALLING;
+ zarg.debug = B_FALSE;
/* we don't care too much if this fails, just plow on */
(void) zonecfg_call_zoneadmd(target_zone, &zarg, locale,
B_TRUE);
@@ -5142,6 +5153,7 @@ mount_func(int argc, char *argv[])
return (Z_ERR);
zarg.cmd = force ? Z_FORCEMOUNT : Z_MOUNT;
+ zarg.debug = B_FALSE;
zarg.bootbuf[0] = '\0';
if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
zerror(gettext("call to %s failed"), "zoneadmd");
@@ -5163,6 +5175,7 @@ unmount_func(int argc, char *argv[])
return (Z_ERR);
zarg.cmd = Z_UNMOUNT;
+ zarg.debug = B_FALSE;
if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
zerror(gettext("call to %s failed"), "zoneadmd");
return (Z_ERR);
@@ -5384,7 +5397,7 @@ apply_func(int argc, char *argv[])
priv_set_t *privset;
zoneid_t zoneid;
zone_dochandle_t handle;
- struct zone_mcaptab mcap;
+ uint64_t mcap;
char pool_err[128];
zoneid = getzoneid();
@@ -5475,19 +5488,12 @@ apply_func(int argc, char *argv[])
}
/*
- * If a memory cap is configured, set the cap in the kernel using
- * zone_setattr() and make sure the rcapd SMF service is enabled.
+ * If a memory cap is configured, make sure the rcapd SMF service is
+ * enabled.
*/
- if (zonecfg_getmcapent(handle, &mcap) == Z_OK) {
- uint64_t num;
+ if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &mcap) == Z_OK) {
char smf_err[128];
- num = (uint64_t)strtoll(mcap.zone_physmem_cap, NULL, 10);
- if (zone_setattr(zoneid, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) {
- zerror(gettext("could not set zone memory cap"));
- res = Z_ERR;
- }
-
if (zonecfg_enable_rcapd(smf_err, sizeof (smf_err)) != Z_OK) {
zerror(gettext("enabling system/rcap service failed: "
"%s"), smf_err);
diff --git a/usr/src/cmd/zoneadm/zones.xml b/usr/src/cmd/zoneadm/zones.xml
index 9c8e305f89..b094bc660b 100644
--- a/usr/src/cmd/zoneadm/zones.xml
+++ b/usr/src/cmd/zoneadm/zones.xml
@@ -54,11 +54,32 @@
<service_fmri value='svc:/milestone/multi-user-server' />
</dependency>
+ <!--
+ Until overlay device creation is moved out of the zone
+ state-change script, zones must be dependent on varpd's
+ successful launch.
+ -->
+ <dependency
+ name='varpd'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/network/varpd' />
+ </dependency>
+
+ <dependency
+ name='metadata'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/smartdc/metadata' />
+ </dependency>
+
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-zones %m'
- timeout_seconds='60'>
+ timeout_seconds='0'>
</exec_method>
<!--
diff --git a/usr/src/cmd/zoneadmd/Makefile b/usr/src/cmd/zoneadmd/Makefile
index 04b3ab3078..aa41acfc8b 100644
--- a/usr/src/cmd/zoneadmd/Makefile
+++ b/usr/src/cmd/zoneadmd/Makefile
@@ -18,57 +18,59 @@
#
# CDDL HEADER END
-
-#
-
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
#
PROG= zoneadmd
include ../Makefile.cmd
+include ../Makefile.ctf
-ROOTCMDDIR= $(ROOTLIB)/zones
+$(64ONLY)SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
-OBJS= zoneadmd.o zcons.o vplat.o
-SRCS = $(OBJS:.o=.c)
-POFILE=zoneadmd_all.po
-POFILES= $(OBJS:%.o=%.po)
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
CFLAGS += $(CCVERBOSE)
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-parentheses
CERRWARN += $(CNOWARN_UNINIT)
-LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
- -lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ltsnet -ltsol \
- -linetutil -lscf
XGETFLAGS += -a -x zoneadmd.xcl
+ROOTUSRLIBZONES = $(ROOT)/usr/lib/zones
+
.KEEP_STATE:
.PARALLEL:
-all: $(PROG)
+all: $(SUBDIRS)
$(PROG): $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
$(POST_PROCESS)
-install: all $(ROOTCMD)
+install: $(SUBDIRS)
+ -$(RM) $(ROOTUSRLIBZONES)/$(PROG)
+ -$(LN) $(ISAEXEC) $(ROOTUSRLIBZONES)/$(PROG)
-$(POFILE): $(POFILES)
- $(RM) $@
- $(CAT) $(POFILES) > $@
+$(POFILE):
-clean:
- $(RM) $(OBJS)
-
-lint: lint_SRCS
+clean clobebr lint: $(SUBDIRS)
check:
- $(CSTYLE) -p -P $(SRCS:%=%)
+ $(CSTYLE) -p -P *.c
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
include ../Makefile.targ
diff --git a/usr/src/cmd/zoneadmd/Makefile.com b/usr/src/cmd/zoneadmd/Makefile.com
new file mode 100644
index 0000000000..aaf21c7f5b
--- /dev/null
+++ b/usr/src/cmd/zoneadmd/Makefile.com
@@ -0,0 +1,72 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2020 Joyent, Inc.
+#
+
+PROG= zoneadmd
+
+include ../../Makefile.cmd
+include ../../Makefile.ctf
+
+ROOTCMDDIR= $(ROOTLIB)/zones
+
+OBJS= zoneadmd.o zcons.o zfd.o vplat.o log.o
+
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
+ -lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ltsnet -ltsol \
+ -linetutil -lscf -lppt -lcustr
+
+CSTD= $(CSTD_GNU99)
+
+.KEEP_STATE:
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+ROOTUSRLIBZONES = $(ROOT)/usr/lib/zones
+ROOTUSRLIBZONES32 = $(ROOTUSRLIBZONES)/$(MACH32)
+ROOTUSRLIBZONES64 = $(ROOTUSRLIBZONES)/$(MACH64)
+ROOTUSRLIBZONESPROG32 = $(ROOTUSRLIBZONES32)/$(PROG)
+ROOTUSRLIBZONESPROG64 = $(ROOTUSRLIBZONES64)/$(PROG)
+$(ROOTUSRLIBZONES32)/%: $(ROOTUSRLIBZONES32) %
+ $(INS.file)
+$(ROOTUSRLIBZONES64)/%: $(ROOTUSRLIBZONES64) %
+ $(INS.file)
+$(ROOTUSRLIBZONES32):
+ $(INS.dir)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+ $(LINT.c) ../*.c $(LDLIBS)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/zoneadmd/amd64/Makefile b/usr/src/cmd/zoneadmd/amd64/Makefile
new file mode 100644
index 0000000000..75ac51db32
--- /dev/null
+++ b/usr/src/cmd/zoneadmd/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+.KEEP_STATE:
+
+include ../Makefile.com
+include ../../Makefile.cmd.64
+
+install: all $(ROOTUSRLIBZONES64) $(ROOTUSRLIBZONESPROG64)
diff --git a/usr/src/cmd/zoneadmd/i386/Makefile b/usr/src/cmd/zoneadmd/i386/Makefile
new file mode 100644
index 0000000000..a8764e0638
--- /dev/null
+++ b/usr/src/cmd/zoneadmd/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2011, Joyent, Inc. All rights reserved.
+#
+
+.KEEP_STATE:
+
+include ../Makefile.com
+
+install: all $(ROOTUSRLIBZONES32) $(ROOTUSRLIBZONESPROG32)
diff --git a/usr/src/cmd/zoneadmd/log.c b/usr/src/cmd/zoneadmd/log.c
new file mode 100644
index 0000000000..a4ecc3e1e8
--- /dev/null
+++ b/usr/src/cmd/zoneadmd/log.c
@@ -0,0 +1,1027 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Joyent, Inc.
+ */
+
+/*
+ * zoneadmd logging
+ *
+ * zoneadmd logs to log files under <zonepath>/logs. Each log entry is a json
+ * structure of the form:
+ *
+ * {
+ * "log": "some message\n",
+ * "stream": "stderr",
+ * "time": "2018-03-28T13:25:02.670423000Z"
+ * }
+ *
+ * Unlike the example above, the entries in the log file are not pretty-printed.
+ * Messages are processed so that they have the proper json escapes for
+ * problematic characters. Excessively long messages may be truncated.
+ *
+ * To use these interfaces:
+ *
+ * int logid;
+ *
+ * logstream_init(zlogp);
+ *
+ * logid = logstream_open("stdio.log", "stdout", flags);
+ * ...
+ * logstream_write(logid, buf, len);
+ * ...
+ * logstream_close(logid);
+ *
+ * logstream_init() needs to be called only once.
+ *
+ * logstream_open() opens a log file (if not already open) and associates the
+ * specified stream with it.
+ *
+ * The following flag is supported:
+ *
+ * LS_LINE_BUFFERED Buffer writes until a newline is encountered or the
+ * buffer fills. This should only be used with streams
+ * that are written to by a single thread. The timestamp
+ * on log messages are the time that the log entry was
+ * written to the log file. This means the timestamp is
+ * the time when the console user hits enter, not the time
+ * that the prompt was printed.
+ *
+ * Line buffering is particularly useful for bhyve console logging because
+ * bhyve's UART emulation causes read() calls in zcons.c to return far fewer
+ * than 10 characters at a time. Without line buffering, a small number of
+ * logged characters are accompanied by about 64 characters of timestamp and
+ * other overhead. Line buffering saves quite a lot of space and makes the log
+ * much easier to read.
+ *
+ *
+ * Log rotation
+ *
+ * Two attributes, zlog-max-size and zlog-keep-rotated are used for automatic
+ * log rotation. zlog-max-size is the approximate maximum size of a log before
+ * it is automatically rotated. Rotated logs are renamed as
+ * <log>.<iso-8601-stamp>. If zlog-keep-rotated is specified and is an integer
+ * greater than zero, only that number of rotated logs will be retained.
+ *
+ * If zlog-max-size is not specified, log rotation will not happen
+ * automatically. An external log rotation program may rename the log file(s),
+ * then send SIGHUP to zoneadmd.
+ *
+ * Log rotation can be forced with SIGUSR1. In this case, the log will be
+ * rotated as though it hit the maximum size and will be subject to retention
+ * rules described above.
+ *
+ *
+ * Locking strategy
+ *
+ * Callers need not worry about locking. In the interest of simplicity, a
+ * single global lock is used to protect the state of the log files and the
+ * associated streams. Locking is necessary because reboots and log rotations
+ * can cause various state changes. Without locking, races could cause log
+ * entries to be directed to the wrong file descriptors.
+ *
+ * The simplistic global lock complicates error reporting within logging
+ * routines. zerror() must not be called while holding logging_lock. Rather,
+ * logstream_err() should be used to log via syslog.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <libcustr.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <strings.h>
+#include <synch.h>
+#include <syslog.h>
+#include <time.h>
+#include <thread.h>
+#include <unistd.h>
+
+#include <sys/debug.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+
+#include "zoneadmd.h"
+
+/*
+ * Currently we only expect stdout, stderr, zoneadmd, and console. Increase
+ * MAX_ZLOG_STREAMS if more streams are added. If the count increases
+ * significantly, logfile_t and logstream_t elements should be dynamically
+ * allocated and the algorithms associated with opening and closing them should
+ * become more efficient.
+ */
+#define MAX_LOG_STREAMS 4
+
+#define ZLOG_MAXSZ "zlog-max-size" /* zonecfg attr */
+#define ZLOG_MAXSZ_MIN (1024 * 1024) /* min size for autorotate */
+#define ZLOG_KEEP "zlog-keep-rotated" /* zonecfg attr */
+#define ZLOG_KEEP_MAX 1000 /* number of log files */
+
+/*
+ * While we could get the numeric value of BUNYAN_LOG_INFO from bunyan.h,
+ * the log version is internal to the library, so we just define the values
+ * we need here.
+ */
+#define BUNYAN_VERSION 0
+#define BUNYAN_LOG_LEVEL 30 /* info */
+
+typedef struct logfile {
+ char lf_path[MAXPATHLEN]; /* log file name (absolute path) */
+ char lf_name[MAXNAMELEN]; /* tail of log file name */
+ char lf_buf[BUFSIZ]; /* Buffer for event messages */
+ custr_t *lf_cus; /* custr_t wrapper for lf_buf */
+ int lf_fd; /* file descriptor */
+ size_t lf_size; /* Current size */
+ boolean_t lf_write_err; /* Avoid spamming console via logsys */
+ boolean_t lf_closing; /* Avoid rotation recursion */
+} logfile_t;
+
+/* Large enough to hold BUFSIZ bytes with some escaping */
+#define LS_BUFSZ (BUFSIZ * 2)
+
+/* Large enough to hold LS_BUF contents + bunyan mandatory properties */
+#define LS_OBUFSZ (LS_BUFSZ + MAXNAMELEN + 128)
+
+typedef struct logstream {
+ char ls_stream[MAXNAMELEN]; /* stdout, stderr, etc. */
+ char ls_buf[LS_BUFSZ]; /* Not-yet written data, json */
+ char ls_obuf[LS_OBUFSZ]; /* Buffer to form output json */
+ custr_t *ls_cusbuf; /* custr_t wrapper to ls_buf */
+ custr_t *ls_cusobuf; /* custr_t wrapper to ls_ofbuf */
+ logstream_flags_t ls_flags;
+ logfile_t *ls_logfile; /* N streams per log file */
+} logstream_t;
+
+typedef struct jsonpair {
+ const char *jp_key;
+ const char *jp_val;
+} jsonpair_t;
+
+boolean_t logging_poisoned = B_FALSE;
+
+/*
+ * MAX_LOG_STREAMS is a small number so we allocate in the simplest way.
+ */
+static logstream_t streams[MAX_LOG_STREAMS];
+static logfile_t logfiles[MAX_LOG_STREAMS];
+
+static char host[MAXHOSTNAMELEN];
+static char pidstr[10];
+
+static boolean_t logging_initialized = B_FALSE;
+static uint64_t logging_rot_size; /* See ZLOG_MAXSZ */
+static uint64_t logging_rot_keep; /* See ZLOG_KEEP */
+static int logging_pending_sig = 0; /* Signal recvd while logging */
+static mutex_t logging_lock = ERRORCHECKMUTEX; /* The global logging lock */
+
+static void logstream_flush_all(logfile_t *);
+static void logstream_sighandler(int);
+static void rotate_log(logfile_t *);
+static size_t make_json(jsonpair_t *, size_t, custr_t *);
+static void logfile_write(logfile_t *, custr_t *);
+
+/*
+ * If errors are encountered while logging_lock is held, we can't use zerror().
+ */
+static void
+logstream_err(boolean_t use_strerror, const char *fmt, ...)
+{
+ va_list alist;
+ char buf[MAXPATHLEN * 2];
+ char *bp;
+ int saved_errno = errno;
+
+ (void) snprintf(buf, sizeof (buf), "[zone %s] ", zone_name);
+
+ bp = &buf[strlen(buf)];
+
+ va_start(alist, fmt);
+ (void) vsnprintf(bp, sizeof (buf) - (bp - buf), fmt, alist);
+ va_end(alist);
+
+ if (use_strerror) {
+ bp = &buf[strlen(buf)];
+ (void) snprintf(bp, sizeof (buf) - (bp - buf), ": %s",
+ strerror(saved_errno));
+ }
+ syslog(LOG_ERR, "%s", buf);
+
+ errno = saved_errno;
+}
+
+static void
+logstream_lock(void)
+{
+ VERIFY(logging_initialized);
+ VERIFY(!logging_poisoned);
+
+ mutex_enter(&logging_lock);
+}
+
+static void
+logstream_unlock(void)
+{
+ int sig = logging_pending_sig;
+
+ logging_pending_sig = 0;
+ mutex_exit(&logging_lock);
+
+ /*
+ * If a signal arrived while this thread was holding the lock, call the
+ * handler.
+ */
+ if (sig != 0) {
+ logstream_sighandler(sig);
+ }
+}
+
+static void
+logfile_write_event(logfile_t *lfp, const char *stream, const char *event)
+{
+ size_t len;
+ jsonpair_t pairs[] = {
+ { "stream", stream },
+ { "msg", event }
+ };
+
+ len = make_json(pairs, ARRAY_SIZE(pairs), lfp->lf_cus);
+ if (len >= sizeof (lfp->lf_buf)) {
+ logstream_err(B_FALSE, "%s: buffer too small. Need %zu bytes, "
+ "have %zu bytes", __func__, len + 1, sizeof (lfp->lf_buf));
+ return;
+ }
+
+ logfile_write(lfp, lfp->lf_cus);
+}
+
+static void
+close_log(logfile_t *lfp, const char *why, boolean_t ign_err)
+{
+ int err;
+
+ VERIFY(MUTEX_HELD(&logging_lock));
+
+ /*
+ * Something may have gone wrong during log rotation, leading to a
+ * zombie log.
+ */
+ if (lfp->lf_fd == -1) {
+ return;
+ }
+
+ lfp->lf_closing = B_TRUE;
+
+ logstream_flush_all(lfp);
+
+ logfile_write_event(lfp, "logfile", why);
+
+ err = close(lfp->lf_fd);
+ if (!ign_err)
+ VERIFY0(err);
+
+ lfp->lf_size = 0;
+ lfp->lf_fd = -1;
+}
+
+static void
+open_log(logfile_t *lfp, const char *why)
+{
+ struct stat64 sb;
+
+ VERIFY(MUTEX_HELD(&logging_lock));
+ VERIFY3S(lfp->lf_fd, ==, -1);
+
+ lfp->lf_fd = open(lfp->lf_path,
+ O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600);
+ if (lfp->lf_fd == -1) {
+ logstream_err(B_TRUE, "Cannot open log file %s",
+ lfp->lf_path);
+ lfp->lf_write_err = B_TRUE;
+ return;
+ }
+
+ VERIFY0(fstat64(lfp->lf_fd, &sb));
+ lfp->lf_size = sb.st_size;
+ lfp->lf_write_err = B_FALSE;
+ lfp->lf_closing = B_FALSE;
+
+ logfile_write_event(lfp, "logfile", why);
+}
+
+static void
+logstream_sighandler(int sig)
+{
+ int i;
+
+ /*
+ * Protect against recursive mutex enters when a signal comes during
+ * logging. This will cause this function to be called again just after
+ * this thread drops the lock.
+ */
+ if (MUTEX_HELD(&logging_lock)) {
+ logging_pending_sig = sig;
+ return;
+ }
+
+ logstream_lock();
+ if (logging_poisoned) {
+ logstream_unlock();
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(logfiles); i++) {
+ /* Inactive logfile slot */
+ if (logfiles[i].lf_name[0] == '\0') {
+ continue;
+ }
+
+ switch (sig) {
+ case SIGHUP:
+ close_log(&logfiles[i], "close-rotate", B_FALSE);
+ open_log(&logfiles[i], "open-rotate");
+ break;
+ case SIGUSR1:
+ rotate_log(&logfiles[i]);
+ break;
+ default:
+ logstream_err(B_FALSE, "unhandled signal %d", sig);
+ }
+ }
+
+ logstream_unlock();
+}
+
+static void
+get_attr_uint64(zlog_t *zlogp, zone_dochandle_t handle, const char *name,
+ uint64_t max, uint64_t *valp)
+{
+ struct zone_attrtab tab = { 0 };
+ char *p;
+ uint64_t val;
+
+ ASSERT(!MUTEX_HELD(&logging_lock));
+
+ (void) strlcpy(tab.zone_attr_name, name, sizeof (tab.zone_attr_name));
+ if (zonecfg_lookup_attr(handle, &tab) != Z_OK) {
+ return;
+ }
+
+ errno = 0;
+ val = strtol(tab.zone_attr_value, &p, 10);
+ if (errno != 0 && *p == '\0') {
+ zerror(zlogp, errno != 0, "Bad value '%s' for 'attr name=%s'",
+ tab.zone_attr_value, tab.zone_attr_name);
+ return;
+ }
+ if (val > max) {
+ zerror(zlogp, B_FALSE, "Value of attr '%s' is too large. "
+ "Reducing to %llu", name, max);
+ val = max;
+ }
+
+ *valp = val;
+}
+
+static void
+logstream_atfork_prepare(void)
+{
+ logstream_lock();
+}
+
+static void
+logstream_atfork_parent(void)
+{
+ logstream_unlock();
+}
+
+/*
+ * logstream_*() should never be called in a child process, so we make sure this
+ * code is never called there.
+ *
+ * zerror() in a child process is still safe: it knows to check for poisoning,
+ * and in such a case will redirect its output to stderr on the presumption it
+ * is a pipe to the parent.
+ */
+static void
+logstream_atfork_child(void)
+{
+ logging_poisoned = B_TRUE;
+ logging_pending_sig = 0;
+ (void) snprintf(pidstr, sizeof (pidstr), "%d", getpid());
+ logstream_unlock();
+}
+
+void
+logstream_init(zlog_t *zlogp)
+{
+ zone_dochandle_t handle;
+ int i;
+
+ VERIFY(!logging_initialized);
+
+ VERIFY0(gethostname(host, sizeof (host)));
+ (void) snprintf(pidstr, sizeof (pidstr), "%d", getpid());
+
+ for (i = 0; i < ARRAY_SIZE(logfiles); i++) {
+ logfile_t *lfp = &logfiles[i];
+
+ lfp->lf_fd = -1;
+ if (custr_alloc_buf(&lfp->lf_cus, lfp->lf_buf,
+ sizeof (lfp->lf_buf)) != 0) {
+ (void) fprintf(stderr, "failed to allocate custr_t for "
+ "log file\n");
+ abort();
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(streams); i++) {
+ logstream_t *lsp = &streams[i];
+
+ if (custr_alloc_buf(&lsp->ls_cusbuf, lsp->ls_buf,
+ sizeof (lsp->ls_buf)) != 0 ||
+ custr_alloc_buf(&lsp->ls_cusobuf, lsp->ls_obuf,
+ sizeof (lsp->ls_obuf)) != 0) {
+ (void) fprintf(stderr, "failed to allocate custr_t for "
+ "log stream\n");
+ abort();
+ }
+ }
+
+ VERIFY0(pthread_atfork(logstream_atfork_prepare,
+ logstream_atfork_parent, logstream_atfork_child));
+
+ logging_initialized = B_TRUE;
+
+ /* Now it is safe to use zlogp */
+
+ if ((handle = zonecfg_init_handle()) == NULL ||
+ zonecfg_get_handle(zone_name, handle) != Z_OK) {
+ zerror(zlogp, B_FALSE, "failed to open zone configuration "
+ "while initializing logging");
+ } else {
+ get_attr_uint64(zlogp, handle, ZLOG_MAXSZ, UINT64_MAX,
+ &logging_rot_size);
+ if (logging_rot_size != 0 &&
+ logging_rot_size < ZLOG_MAXSZ_MIN) {
+ zerror(zlogp, B_FALSE, "%s value %llu is too small. "
+ "Setting to %d", ZLOG_MAXSZ, logging_rot_size,
+ ZLOG_MAXSZ_MIN);
+ logging_rot_size = ZLOG_MAXSZ_MIN;
+ }
+ get_attr_uint64(zlogp, handle, ZLOG_KEEP, ZLOG_KEEP_MAX,
+ &logging_rot_keep);
+ }
+
+ zonecfg_fini_handle(handle);
+
+ /*
+ * This thread should receive SIGHUP so that it can close the log
+ * file and reopen it during log rotation. SIGUSR1 can be used to force
+ * a log rotation.
+ */
+ (void) sigset(SIGHUP, logstream_sighandler);
+ (void) sigset(SIGUSR1, logstream_sighandler);
+}
+
+/*
+ * Rotate a single log file. The global lock must be held while this is called.
+ */
+static void
+rotate_log(logfile_t *lfp)
+{
+ time_t t;
+ struct tm gtm;
+ char path[MAXPATHLEN];
+ int64_t i;
+ size_t len;
+ glob_t glb = { 0 };
+ int err;
+
+ VERIFY(MUTEX_HELD(&logging_lock));
+
+ if (lfp->lf_closing) {
+ return;
+ }
+
+ if ((t = time(NULL)) == (time_t)-1 || gmtime_r(&t, &gtm) == NULL) {
+ logstream_err(B_TRUE, "failed to format time");
+ return;
+ }
+
+ (void) snprintf(path, sizeof (path), "%s.%04d%02d%02dT%02d%02d%02dZ",
+ lfp->lf_path, gtm.tm_year + 1900, gtm.tm_mon + 1, gtm.tm_mday,
+ gtm.tm_hour, gtm.tm_min, gtm.tm_sec);
+
+ if (rename(lfp->lf_path, path) != 0) {
+ logstream_err(B_TRUE, "failed to rotate log file "
+ "'%s' to '%s'", lfp->lf_path, path);
+ }
+
+ close_log(lfp, "close-rotate", B_FALSE);
+ open_log(lfp, "open-rotate");
+
+ if (logging_rot_keep == 0) {
+ return;
+ }
+
+ /*
+ * Remove old logs.
+ */
+ len = snprintf(path, sizeof (path),
+ /* <lf_path>.YYYYmmdd */
+ "%s.[12][0-9][0-9][0-9][01][0-9][0-3][0-9]"
+ /* THHMMSSZ */
+ "T[012][0-9][0-5][0-9][0-6][0-9]Z", lfp->lf_path);
+ if (len >= sizeof (path)) {
+ logstream_err(B_FALSE, "log rotation glob too long");
+ return;
+ }
+
+ if ((err = glob(path, GLOB_LIMIT, NULL, &glb)) != 0) {
+ if (err != GLOB_NOMATCH) {
+ logstream_err(B_TRUE, "glob terminated with error %d",
+ err);
+ }
+ globfree(&glb);
+ return;
+ }
+
+ if (glb.gl_pathc <= logging_rot_keep) {
+ globfree(&glb);
+ return;
+ }
+
+ for (i = glb.gl_pathc - logging_rot_keep - 1; i >= 0; i--) {
+ if (unlink(glb.gl_pathv[i]) != 0) {
+ logstream_err(B_TRUE, "log rotation could not remove "
+ "%s", glb.gl_pathv[i]);
+ }
+ }
+ globfree(&glb);
+}
+
+/*
+ * Modify the input string with json escapes. Since the destination can thus
+ * be larger than the source, multiple calls may be required to fully convert
+ * sbuf to json.
+ *
+ * sbuf, slen Source buffer and the number of bytes in it to process
+ * dest Destination custr_t containing escaped JSON.
+ * scntp On return, *scntp stores number of scnt bytes consumed
+ * flushp If non-NULL, line-buffered mode is enabled. Processing
+ * will stop at the first newline or when dest is full and
+ * *flushp will be set to B_TRUE.
+ *
+ * This function makes no attempt to handle wide characters properly because
+ * the messages that come in may be using any character encoding. Since
+ * characters other than 7-bit ASCII are not directly readable in the log
+ * anyway, it is better to log the raw data and leave it to specialized log
+ * readers to interpret non-ASCII data.
+ */
+static void
+escape_json(const char *sbuf, size_t slen, custr_t *dest, size_t *scntp,
+ boolean_t *flushp)
+{
+ char c;
+ const char *save_sbuf = sbuf;
+ const char *sbuf_end = sbuf + slen - 1;
+ char append_buf[7]; /* "\\u0000\0" */
+ const char *append;
+ int len;
+
+ if (slen == 0) {
+ *scntp = 0;
+ return;
+ }
+
+ if (flushp != NULL) {
+ *flushp = B_FALSE;
+ }
+
+ while (sbuf <= sbuf_end) {
+ c = sbuf[0];
+
+ switch (c) {
+ case '\\':
+ append = "\\\\";
+ break;
+
+ case '"':
+ append = "\\\"";
+ break;
+
+ case '\b':
+ append = "\\b";
+ break;
+
+ case '\f':
+ append = "\\f";
+ break;
+
+ case '\n':
+ append = "\\n";
+ if (flushp != NULL) {
+ *flushp = B_TRUE;
+ }
+ break;
+
+ case '\r':
+ append = "\\r";
+ break;
+
+ case '\t':
+ append = "\\t";
+ break;
+
+ default:
+ if (c >= 0x20 && c < 0x7f) {
+ append_buf[0] = c;
+ append_buf[1] = '\0';
+ } else {
+ len = snprintf(append_buf, sizeof (append_buf),
+ "\\u%04x", (int)(0xff & c));
+ VERIFY3S(len, <, sizeof (append_buf));
+ }
+ append = append_buf;
+ break;
+ }
+
+ if (custr_append(dest, append) != 0) {
+ VERIFY3S(errno, ==, EOVERFLOW);
+ if (flushp != NULL) {
+ *flushp = B_TRUE;
+ }
+ break;
+ }
+
+ sbuf++;
+
+ if (flushp != NULL && *flushp) {
+ break;
+ }
+ }
+
+ *scntp = sbuf - save_sbuf;
+
+ VERIFY3U(*scntp, <=, slen);
+}
+
+/*
+ * Like write(2), but to a logfile_t and with retries on short writes.
+ */
+static void
+logfile_write(logfile_t *lfp, custr_t *cus)
+{
+ const char *buf = custr_cstr(cus);
+ size_t buflen = custr_len(cus);
+ ssize_t wlen;
+ size_t wanted = buflen;
+
+ while (buflen > 0) {
+ wlen = write(lfp->lf_fd, buf, buflen);
+ if (wlen == -1) {
+ if (lfp->lf_write_err) {
+ lfp->lf_write_err = B_TRUE;
+ logstream_err(B_TRUE, "log file fd %d '%s': "
+ "failed to write %llu of %llu bytes",
+ lfp->lf_fd, lfp->lf_path, buflen, wanted);
+ }
+ return;
+ }
+ buf += wlen;
+ buflen -= wlen;
+ lfp->lf_size += wlen;
+
+ lfp->lf_write_err = B_FALSE;
+ }
+
+ if (logging_rot_size != 0 && lfp->lf_size > logging_rot_size) {
+ rotate_log(lfp);
+ }
+}
+
+static void
+add_bunyan_preamble(custr_t *cus)
+{
+ struct tm gtm;
+ struct timeval tv;
+ /* Large enough for YYYY-MM-DDTHH:MM:SS.000000000Z + NUL */
+ char timestr[32] = { 0 };
+ size_t len;
+
+ if (gettimeofday(&tv, NULL) != 0 ||
+ gmtime_r(&tv.tv_sec, &gtm) == NULL) {
+ logstream_err(B_TRUE, "failed to get time of day");
+ abort();
+ }
+
+ len = strftime(timestr, sizeof (timestr) - 1, "%FT%T", &gtm);
+ VERIFY3U(len, >, 0);
+ VERIFY3U(len, <, sizeof (timestr) - 1);
+
+ VERIFY0(custr_append_printf(cus, "\"time\": \"%s.%09ldZ\", ",
+ timestr, tv.tv_usec * 1000));
+ VERIFY0(custr_append_printf(cus, "\"v\": %d, ", BUNYAN_VERSION));
+ VERIFY0(custr_append_printf(cus, "\"hostname\": \"%s\", ", host));
+ VERIFY0(custr_append(cus, "\"name\": \"zoneadmd\","));
+ VERIFY0(custr_append_printf(cus, "\"pid\": %s, ", pidstr));
+ VERIFY0(custr_append_printf(cus, "\"level\": %d", BUNYAN_LOG_LEVEL));
+}
+
+/*
+ * Convert the json pairs into a json object. The properties required for
+ * bunyan-formatted json objects are added to every object.
+ * Returns the number of bytes that would have been written to
+ * buf if bufsz had buf been sufficiently large (excluding the terminating null
+ * byte). Like snprintf().
+ */
+static size_t
+make_json(jsonpair_t *pairs, size_t npairs, custr_t *cus)
+{
+ int i;
+ const char *key, *val;
+ const char *start = ", ";
+
+ VERIFY3S(npairs, >, 0);
+
+ custr_reset(cus);
+
+ VERIFY0(custr_append(cus, "{ "));
+
+ add_bunyan_preamble(cus);
+
+ for (i = 0; i < npairs; i++) {
+ size_t len;
+
+ key = pairs[i].jp_key;
+ val = pairs[i].jp_val;
+
+ /* The total number of bytes we're adding to cus */
+ len = 3 + strlen(key) + 3 + strlen(val) + 1;
+ if (custr_append_printf(cus, "%s\"%s\":\"%s\"",
+ start, key, val) != 0) {
+ VERIFY3S(errno, ==, EOVERFLOW);
+ return (custr_len(cus) + len);
+ }
+ }
+
+ if (custr_append(cus, " }\n") != 0) {
+ return (custr_len(cus) + 3);
+ }
+
+ return (custr_len(cus));
+}
+
+static void
+logstream_write_json(logstream_t *lsp)
+{
+ size_t len;
+ jsonpair_t pairs[] = {
+ { "msg", lsp->ls_buf },
+ { "stream", lsp->ls_stream },
+ };
+
+ if (custr_len(lsp->ls_cusbuf) == 0) {
+ return;
+ }
+
+ len = make_json(pairs, ARRAY_SIZE(pairs), lsp->ls_cusobuf);
+
+ custr_reset(lsp->ls_cusbuf);
+ if (len >= sizeof (lsp->ls_obuf)) {
+ logstream_err(B_FALSE, "%s: buffer too small. Need %llu bytes, "
+ "have %llu bytes", __func__, len + 1,
+ sizeof (lsp->ls_obuf));
+ return;
+ }
+
+ logfile_write(lsp->ls_logfile, lsp->ls_cusobuf);
+}
+
+/*
+ * We output to the log file as json.
+ * ex. for string 'msg\n' on the zone's stdout:
+ * {"log":"msg\n","stream":"stdout","time":"2014-10-24T20:12:11.101973117Z"}
+ *
+ * We use ns in the last field of the timestamp for compatibility.
+ *
+ * We keep track of the size of the log file and rotate it when we exceed
+ * the log size limit (if one is set).
+ */
+void
+logstream_write(int ls, char *buf, int len)
+{
+ logstream_t *lsp;
+ size_t scnt;
+ boolean_t newline;
+ boolean_t buffered;
+
+ if (ls == -1 || len == 0) {
+ return;
+ }
+ VERIFY3S(ls, >=, 0);
+ VERIFY3S(ls, <, ARRAY_SIZE(streams));
+
+ logstream_lock();
+
+ lsp = &streams[ls];
+ if (lsp->ls_stream[0] == '\0' || lsp->ls_logfile == NULL) {
+ logstream_unlock();
+ return;
+ }
+
+ buffered = !!(lsp->ls_flags & LS_LINE_BUFFERED);
+
+ do {
+ escape_json(buf, len, lsp->ls_cusbuf, &scnt,
+ buffered ? &newline : NULL);
+
+ buf += scnt;
+ len -= scnt;
+
+ if (!buffered || newline) {
+ logstream_write_json(lsp);
+ }
+ } while (len > 0 && (!buffered || newline));
+
+ logstream_unlock();
+}
+
+static void
+logstream_flush(int ls)
+{
+ logstream_t *lsp;
+
+ VERIFY(MUTEX_HELD(&logging_lock));
+
+ lsp = &streams[ls];
+ if (lsp->ls_stream[0] == '\0' || lsp->ls_logfile == NULL) {
+ return;
+ }
+ logstream_write_json(lsp);
+}
+
+static void
+logstream_flush_all(logfile_t *lfp)
+{
+ int i;
+
+ VERIFY(MUTEX_HELD(&logging_lock));
+
+ for (i = 0; i < ARRAY_SIZE(streams); i++) {
+ if (streams[i].ls_logfile == lfp) {
+ logstream_flush(i);
+ }
+ }
+}
+
+int
+logstream_open(const char *logname, const char *stream, logstream_flags_t flags)
+{
+ int ls = -1;
+ int i;
+ logstream_t *lsp;
+ logfile_t *lfp = NULL;
+
+ VERIFY3U(strlen(logname), <, sizeof (lfp->lf_name));
+ VERIFY3U(strlen(stream), <, sizeof (lsp->ls_stream));
+
+ logstream_lock();
+
+ /*
+ * Find an empty logstream_t and verify that the stream is not already
+ * open.
+ */
+ for (i = 0; i < ARRAY_SIZE(streams); i++) {
+ if (ls == -1 && streams[i].ls_stream[0] == '\0') {
+ VERIFY3P(streams[i].ls_logfile, ==, NULL);
+ ls = i;
+ continue;
+ }
+ if (strcmp(stream, streams[i].ls_stream) == 0) {
+ logstream_unlock();
+ logstream_err(B_FALSE, "log stream %s already open",
+ stream);
+ return (-1);
+ }
+ }
+ VERIFY3S(ls, !=, -1);
+
+ /* Find an existing or available logfile_t */
+ for (i = 0; i < ARRAY_SIZE(logfiles); i++) {
+ if (lfp == NULL && logfiles[i].lf_name[0] == '\0') {
+ lfp = &logfiles[i];
+ }
+ if (strcmp(logname, logfiles[i].lf_name) == 0) {
+ lfp = &logfiles[i];
+ break;
+ }
+ }
+ if (lfp->lf_name[0] == '\0') {
+ (void) strlcpy(lfp->lf_name, logname, sizeof (lfp->lf_name));
+ (void) snprintf(lfp->lf_path, sizeof (lfp->lf_path), "%s/logs",
+ zonepath);
+ (void) mkdir(lfp->lf_path, 0700);
+
+ (void) snprintf(lfp->lf_path, sizeof (lfp->lf_path),
+ "%s/logs/%s", zonepath, logname);
+
+ open_log(lfp, "open");
+ if (lfp->lf_fd == -1) {
+ logstream_unlock();
+ return (-1);
+ }
+ }
+
+ lsp = &streams[ls];
+ (void) strlcpy(lsp->ls_stream, stream, sizeof (lsp->ls_stream));
+
+ lsp->ls_flags = flags;
+ lsp->ls_logfile = lfp;
+
+ logstream_unlock();
+
+ return (ls);
+}
+
+static void
+logstream_reset(logstream_t *lsp)
+{
+ custr_t *buf = lsp->ls_cusbuf;
+ custr_t *obuf = lsp->ls_cusobuf;
+
+ (void) memset(lsp, 0, sizeof (*lsp));
+ lsp->ls_cusbuf = buf;
+ lsp->ls_cusobuf = obuf;
+
+ custr_reset(buf);
+ custr_reset(obuf);
+}
+
+static void
+logfile_reset(logfile_t *lfp)
+{
+ custr_t *buf = lfp->lf_cus;
+
+ (void) memset(lfp, 0, sizeof (*lfp));
+ lfp->lf_cus = buf;
+ lfp->lf_fd = -1;
+
+ custr_reset(buf);
+}
+
+void
+logstream_close(int ls, boolean_t abrupt)
+{
+ logstream_t *lsp;
+ logfile_t *lfp;
+ int i;
+
+ if (ls == -1) {
+ return;
+ }
+ VERIFY3S(ls, >=, 0);
+ VERIFY3S(ls, <, ARRAY_SIZE(streams));
+
+ logstream_lock();
+ logstream_flush(ls);
+
+ lsp = &streams[ls];
+ lfp = lsp->ls_logfile;
+
+ VERIFY(lsp->ls_stream[0] != '\0');
+ VERIFY3P(lfp, !=, NULL);
+
+ logstream_reset(lsp);
+
+ for (i = 0; i < ARRAY_SIZE(streams); i++) {
+ if (streams[i].ls_logfile == lfp) {
+ logstream_unlock();
+ return;
+ }
+ }
+
+ /* No more streams using this log file so return to initial state */
+
+ close_log(lfp, "close", abrupt);
+
+ logfile_reset(lfp);
+
+ logstream_unlock();
+}
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 4a2d94605b..01332d43e8 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright 2018, Joyent Inc.
* Copyright (c) 2015, 2016 by Delphix. All rights reserved.
* Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -79,10 +79,12 @@
#include <sys/conf.h>
#include <sys/systeminfo.h>
#include <sys/secflags.h>
+#include <sys/vnic.h>
#include <libdlpi.h>
#include <libdllink.h>
#include <libdlvlan.h>
+#include <libdlvnic.h>
#include <inet/tcp.h>
#include <arpa/inet.h>
@@ -138,6 +140,9 @@
#define DFSTYPES "/etc/dfs/fstypes"
#define MAXTNZLEN 2048
+/* Number of times to retry unmounting if it fails */
+#define UMOUNT_RETRIES 30
+
#define ALT_MOUNT(mount_cmd) ((mount_cmd) != Z_MNT_BOOT)
/* a reasonable estimate for the number of lwps per process */
@@ -163,11 +168,25 @@ static priv_set_t *zprivs = NULL;
static const char *DFLT_FS_ALLOWED = "hsfs,smbfs,nfs,nfs3,nfs4,nfsdyn";
+typedef struct zone_proj_rctl_map {
+ char *zpr_zone_rctl;
+ char *zpr_project_rctl;
+} zone_proj_rctl_map_t;
+
+static zone_proj_rctl_map_t zone_proj_rctl_map[] = {
+ {"zone.max-msg-ids", "project.max-msg-ids"},
+ {"zone.max-sem-ids", "project.max-sem-ids"},
+ {"zone.max-shm-ids", "project.max-shm-ids"},
+ {"zone.max-shm-memory", "project.max-shm-memory"},
+ {NULL, NULL}
+};
+
/* from libsocket, not in any header file */
extern int getnetmaskbyaddr(struct in_addr, struct in_addr *);
/* from zoneadmd */
extern char query_hook[];
+extern char post_statechg_hook[];
/*
* For each "net" resource configured in zonecfg, we track a zone_addr_list_t
@@ -204,7 +223,7 @@ autofs_cleanup(zoneid_t zoneid)
/*
* Ask autofs to unmount all trigger nodes in the given zone.
*/
- return (_autofssys(AUTOFS_UNMOUNTALL, (void *)zoneid));
+ return (_autofssys(AUTOFS_UNMOUNTALL, (void *)((uintptr_t)zoneid)));
}
static void
@@ -595,6 +614,24 @@ root_to_lu(zlog_t *zlogp, char *zroot, size_t zrootlen, boolean_t isresolved)
}
/*
+ * Perform brand-specific cleanup if we are unable to unmount a FS.
+ */
+static void
+brand_umount_cleanup(zlog_t *zlogp, char *path)
+{
+ char cmdbuf[2 * MAXPATHLEN];
+
+ if (post_statechg_hook[0] == '\0')
+ return;
+
+ if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %d %d %s", post_statechg_hook,
+ ZONE_STATE_DOWN, Z_UNMOUNT, path) > sizeof (cmdbuf))
+ return;
+
+ (void) do_subproc(zlogp, cmdbuf, NULL, B_FALSE);
+}
+
+/*
* The general strategy for unmounting filesystems is as follows:
*
* - Remote filesystems may be dead, and attempting to contact them as
@@ -627,6 +664,7 @@ static int
unmount_filesystems(zlog_t *zlogp, zoneid_t zoneid, boolean_t unmount_cmd)
{
int error = 0;
+ int fail = 0;
FILE *mnttab;
struct mnttab *mnts;
uint_t nmnt;
@@ -714,18 +752,39 @@ unmount_filesystems(zlog_t *zlogp, zoneid_t zoneid, boolean_t unmount_cmd)
if (umount2(path, MS_FORCE) == 0) {
unmounted = B_TRUE;
stuck = B_FALSE;
+ fail = 0;
} else {
/*
- * The first failure indicates a
- * mount we won't be able to get
- * rid of automatically, so we
- * bail.
+ * We may hit a failure here if there
+ * is an app in the GZ with an open
+ * pipe into the zone (commonly into
+ * the zone's /var/run). This type
+ * of app will notice the closed
+ * connection and cleanup, but it may
+ * take a while and we have no easy
+ * way to notice that. To deal with
+ * this case, we will wait and retry
+ * a few times before we give up.
*/
- error++;
- zerror(zlogp, B_FALSE,
- "unable to unmount '%s'", path);
- free_mnttable(mnts, nmnt);
- goto out;
+ fail++;
+ if (fail < (UMOUNT_RETRIES - 1)) {
+ zerror(zlogp, B_FALSE,
+ "unable to unmount '%s', "
+ "retrying in 2 seconds",
+ path);
+ (void) sleep(2);
+ } else if (fail > UMOUNT_RETRIES) {
+ error++;
+ zerror(zlogp, B_FALSE,
+ "unmount of '%s' failed",
+ path);
+ free_mnttable(mnts, nmnt);
+ goto out;
+ } else {
+ /* Try the hook 2 times */
+ brand_umount_cleanup(zlogp,
+ path);
+ }
}
}
/*
@@ -1063,23 +1122,10 @@ mount_one_dev_symlink_cb(void *arg, const char *source, const char *target)
int
vplat_get_iptype(zlog_t *zlogp, zone_iptype_t *iptypep)
{
- zone_dochandle_t handle;
-
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
- if (zonecfg_get_iptype(handle, iptypep) != Z_OK) {
+ if (zonecfg_get_iptype(snap_hndl, iptypep) != Z_OK) {
zerror(zlogp, B_FALSE, "invalid ip-type configuration");
- zonecfg_fini_handle(handle);
return (-1);
}
- zonecfg_fini_handle(handle);
return (0);
}
@@ -1092,14 +1138,13 @@ static int
mount_one_dev(zlog_t *zlogp, char *devpath, zone_mnt_t mount_cmd)
{
char brand[MAXNAMELEN];
- zone_dochandle_t handle = NULL;
brand_handle_t bh = NULL;
struct zone_devtab ztab;
di_prof_t prof = NULL;
int err;
int retval = -1;
zone_iptype_t iptype;
- const char *curr_iptype;
+ const char *curr_iptype = NULL;
if (di_prof_init(devpath, &prof)) {
zerror(zlogp, B_TRUE, "failed to initialize profile");
@@ -1134,6 +1179,8 @@ mount_one_dev(zlog_t *zlogp, char *devpath, zone_mnt_t mount_cmd)
curr_iptype = "exclusive";
break;
}
+ if (curr_iptype == NULL)
+ abort();
if (brand_platform_iter_devices(bh, zone_name,
mount_one_dev_device_cb, prof, curr_iptype) != 0) {
@@ -1148,28 +1195,25 @@ mount_one_dev(zlog_t *zlogp, char *devpath, zone_mnt_t mount_cmd)
}
/* Add user-specified devices and directories */
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_FALSE, "can't initialize zone handle");
- goto cleanup;
- }
- if (err = zonecfg_get_handle(zone_name, handle)) {
- zerror(zlogp, B_FALSE, "can't get handle for zone "
- "%s: %s", zone_name, zonecfg_strerror(err));
- goto cleanup;
- }
- if (err = zonecfg_setdevent(handle)) {
+ if ((err = zonecfg_setdevent(snap_hndl)) != 0) {
zerror(zlogp, B_FALSE, "%s: %s", zone_name,
zonecfg_strerror(err));
goto cleanup;
}
- while (zonecfg_getdevent(handle, &ztab) == Z_OK) {
- if (di_prof_add_dev(prof, ztab.zone_dev_match)) {
+ while (zonecfg_getdevent(snap_hndl, &ztab) == Z_OK) {
+ char path[MAXPATHLEN];
+
+ if ((err = resolve_device_match(zlogp, &ztab,
+ path, sizeof (path))) != Z_OK)
+ goto cleanup;
+
+ if (di_prof_add_dev(prof, path)) {
zerror(zlogp, B_TRUE, "failed to add "
- "user-specified device");
+ "user-specified device '%s'", path);
goto cleanup;
}
}
- (void) zonecfg_enddevent(handle);
+ (void) zonecfg_enddevent(snap_hndl);
/* Send profile to kernel */
if (di_prof_commit(prof)) {
@@ -1182,8 +1226,6 @@ mount_one_dev(zlog_t *zlogp, char *devpath, zone_mnt_t mount_cmd)
cleanup:
if (bh != NULL)
brand_close(bh);
- if (handle != NULL)
- zonecfg_fini_handle(handle);
if (prof)
di_prof_fini(prof);
return (retval);
@@ -1674,12 +1716,10 @@ static int
mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
{
char rootpath[MAXPATHLEN];
- char zonepath[MAXPATHLEN];
char brand[MAXNAMELEN];
char luroot[MAXPATHLEN];
int i, num_fs = 0;
struct zone_fstab *fs_ptr = NULL;
- zone_dochandle_t handle = NULL;
zone_state_t zstate;
brand_handle_t bh;
plat_gmount_cb_data_t cb;
@@ -1693,22 +1733,12 @@ mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
goto bad;
}
- if (zone_get_zonepath(zone_name, zonepath, sizeof (zonepath)) != Z_OK) {
- zerror(zlogp, B_TRUE, "unable to determine zone path");
- goto bad;
- }
-
if (zone_get_rootpath(zone_name, rootpath, sizeof (rootpath)) != Z_OK) {
zerror(zlogp, B_TRUE, "unable to determine zone root");
goto bad;
}
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- goto bad;
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK ||
- zonecfg_setfsent(handle) != Z_OK) {
+ if (zonecfg_setfsent(snap_hndl) != Z_OK) {
zerror(zlogp, B_FALSE, "invalid configuration");
goto bad;
}
@@ -1726,7 +1756,6 @@ mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
/* Get a handle to the brand info for this zone */
if ((bh = brand_open(brand)) == NULL) {
zerror(zlogp, B_FALSE, "unable to determine zone brand");
- zonecfg_fini_handle(handle);
return (-1);
}
@@ -1741,7 +1770,6 @@ mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
plat_gmount_cb, &cb) != 0) {
zerror(zlogp, B_FALSE, "unable to mount filesystems");
brand_close(bh);
- zonecfg_fini_handle(handle);
return (-1);
}
brand_close(bh);
@@ -1752,13 +1780,10 @@ mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
* higher level directories (e.g., /usr) get mounted before
* any beneath them (e.g., /usr/local).
*/
- if (mount_filesystems_fsent(handle, zlogp, &fs_ptr, &num_fs,
+ if (mount_filesystems_fsent(snap_hndl, zlogp, &fs_ptr, &num_fs,
mount_cmd) != 0)
goto bad;
- zonecfg_fini_handle(handle);
- handle = NULL;
-
/*
* Normally when we mount a zone all the zone filesystems
* get mounted relative to rootpath, which is usually
@@ -1798,23 +1823,40 @@ mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
qsort(fs_ptr, num_fs, sizeof (*fs_ptr), fs_compare);
for (i = 0; i < num_fs; i++) {
- if (ALT_MOUNT(mount_cmd) &&
- strcmp(fs_ptr[i].zone_fs_dir, "/dev") == 0) {
- size_t slen = strlen(rootpath) - 2;
+ if (ALT_MOUNT(mount_cmd)) {
+ if (strcmp(fs_ptr[i].zone_fs_dir, "/dev") == 0) {
+ size_t slen = strlen(rootpath) - 2;
- /*
- * By default we'll try to mount /dev as /a/dev
- * but /dev is special and always goes at the top
- * so strip the trailing '/a' from the rootpath.
- */
- assert(strcmp(&rootpath[slen], "/a") == 0);
- rootpath[slen] = '\0';
- if (mount_one(zlogp, &fs_ptr[i], rootpath, mount_cmd)
- != 0)
- goto bad;
- rootpath[slen] = '/';
- continue;
+ /*
+ * By default we'll try to mount /dev
+ * as /a/dev but /dev is special and
+ * always goes at the top so strip the
+ * trailing '/a' from the rootpath.
+ */
+ assert(strcmp(&rootpath[slen], "/a") == 0);
+ rootpath[slen] = '\0';
+ if (mount_one(zlogp, &fs_ptr[i], rootpath,
+ mount_cmd) != 0)
+ goto bad;
+ rootpath[slen] = '/';
+ continue;
+ } else if (strcmp(brand_name, default_brand) != 0) {
+ /*
+ * If mounting non-native brand, skip
+ * mounting global mounts and
+ * filesystem entries since they are
+ * only needed for native pkg upgrade
+ * tools.
+ *
+ * The only exception right now is
+ * /dev (handled above), which is
+ * needed in the luroot in order to
+ * zlogin -S into the zone.
+ */
+ continue;
+ }
}
+
if (mount_one(zlogp, &fs_ptr[i], rootpath, mount_cmd) != 0)
goto bad;
}
@@ -1837,8 +1879,6 @@ mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
return (0);
bad:
- if (handle != NULL)
- zonecfg_fini_handle(handle);
free_fs_data(fs_ptr, num_fs);
return (-1);
}
@@ -2194,13 +2234,7 @@ configure_one_interface(zlog_t *zlogp, zoneid_t zone_id,
if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
/*
* Here, we know that the interface can't be brought up.
- * A similar warning message was already printed out to
- * the console by zoneadm(1M) so instead we log the
- * message to syslog and continue.
*/
- zerror(&logsys, B_TRUE, "WARNING: skipping network interface "
- "'%s' which may not be present/plumbed in the "
- "global zone.", lifr.lifr_name);
(void) close(s);
return (Z_OK);
}
@@ -2413,7 +2447,6 @@ bad:
static int
configure_shared_network_interfaces(zlog_t *zlogp)
{
- zone_dochandle_t handle;
struct zone_nwiftab nwiftab, loopback_iftab;
zoneid_t zoneid;
@@ -2422,29 +2455,19 @@ configure_shared_network_interfaces(zlog_t *zlogp)
return (-1);
}
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
- if (zonecfg_setnwifent(handle) == Z_OK) {
+ if (zonecfg_setnwifent(snap_hndl) == Z_OK) {
for (;;) {
- if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
+ if (zonecfg_getnwifent(snap_hndl, &nwiftab) != Z_OK)
break;
+ nwifent_free_attrs(&nwiftab);
if (configure_one_interface(zlogp, zoneid, &nwiftab) !=
Z_OK) {
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
+ (void) zonecfg_endnwifent(snap_hndl);
return (-1);
}
}
- (void) zonecfg_endnwifent(handle);
+ (void) zonecfg_endnwifent(snap_hndl);
}
- zonecfg_fini_handle(handle);
if (is_system_labeled()) {
/*
* Labeled zones share the loopback interface
@@ -2898,7 +2921,6 @@ free_ip_interface(zone_addr_list_t *zalist)
static int
configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
{
- zone_dochandle_t handle;
struct zone_nwiftab nwiftab;
char rootpath[MAXPATHLEN];
char path[MAXPATHLEN];
@@ -2907,30 +2929,18 @@ configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
boolean_t added = B_FALSE;
zone_addr_list_t *zalist = NULL, *new;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
-
- if (zonecfg_setnwifent(handle) != Z_OK) {
- zonecfg_fini_handle(handle);
+ if (zonecfg_setnwifent(snap_hndl) != Z_OK)
return (0);
- }
for (;;) {
- if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
+ if (zonecfg_getnwifent(snap_hndl, &nwiftab) != Z_OK)
break;
+ nwifent_free_attrs(&nwiftab);
if (prof == NULL) {
if (zone_get_devroot(zone_name, rootpath,
sizeof (rootpath)) != Z_OK) {
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
+ (void) zonecfg_endnwifent(snap_hndl);
zerror(zlogp, B_TRUE,
"unable to determine dev root");
return (-1);
@@ -2938,8 +2948,7 @@ configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
(void) snprintf(path, sizeof (path), "%s%s", rootpath,
"/dev");
if (di_prof_init(path, &prof) != 0) {
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
+ (void) zonecfg_endnwifent(snap_hndl);
zerror(zlogp, B_TRUE,
"failed to initialize profile");
return (-1);
@@ -2963,17 +2972,17 @@ configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
nwiftab.zone_nwif_physical) == 0) {
added = B_TRUE;
} else {
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
- zerror(zlogp, B_TRUE, "failed to add network device");
- return (-1);
+ /*
+ * Failed to add network device, but the brand hook
+ * might be doing this for us, so keep silent.
+ */
+ continue;
}
/* set up the new IP interface, and add them all later */
new = malloc(sizeof (*new));
if (new == NULL) {
zerror(zlogp, B_TRUE, "no memory for %s",
nwiftab.zone_nwif_physical);
- zonecfg_fini_handle(handle);
free_ip_interface(zalist);
}
bzero(new, sizeof (*new));
@@ -2983,16 +2992,14 @@ configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
}
if (zalist != NULL) {
if ((errno = add_net(zlogp, zoneid, zalist)) != 0) {
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
+ (void) zonecfg_endnwifent(snap_hndl);
zerror(zlogp, B_TRUE, "failed to add address");
free_ip_interface(zalist);
return (-1);
}
free_ip_interface(zalist);
}
- (void) zonecfg_endnwifent(handle);
- zonecfg_fini_handle(handle);
+ (void) zonecfg_endnwifent(snap_hndl);
if (prof != NULL && added) {
if (di_prof_commit(prof) != 0) {
@@ -3128,48 +3135,23 @@ remove_datalink_protect(zlog_t *zlogp, zoneid_t zoneid)
/* datalink does not belong to the GZ */
continue;
}
- if (dlstatus != DLADM_STATUS_OK) {
+ if (dlstatus != DLADM_STATUS_OK)
zerror(zlogp, B_FALSE,
+ "clear 'protection' link property: %s",
dladm_status2str(dlstatus, dlerr));
- free(dllinks);
- return (-1);
- }
+
dlstatus = dladm_set_linkprop(dld_handle, *dllink,
"allowed-ips", NULL, 0, DLADM_OPT_ACTIVE);
- if (dlstatus != DLADM_STATUS_OK) {
+ if (dlstatus != DLADM_STATUS_OK)
zerror(zlogp, B_FALSE,
+ "clear 'allowed-ips' link property: %s",
dladm_status2str(dlstatus, dlerr));
- free(dllinks);
- return (-1);
- }
}
free(dllinks);
return (0);
}
static int
-unconfigure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
-{
- int dlnum = 0;
-
- /*
- * The kernel shutdown callback for the dls module should have removed
- * all datalinks from this zone. If any remain, then there's a
- * problem.
- */
- if (zone_list_datalink(zoneid, &dlnum, NULL) != 0) {
- zerror(zlogp, B_TRUE, "unable to list network interfaces");
- return (-1);
- }
- if (dlnum != 0) {
- zerror(zlogp, B_FALSE,
- "datalinks remain in zone after shutdown");
- return (-1);
- }
- return (0);
-}
-
-static int
tcp_abort_conn(zlog_t *zlogp, zoneid_t zoneid,
const struct sockaddr_storage *local, const struct sockaddr_storage *remote)
{
@@ -3251,26 +3233,14 @@ static int
get_privset(zlog_t *zlogp, priv_set_t *privs, zone_mnt_t mount_cmd)
{
int error = -1;
- zone_dochandle_t handle;
char *privname = NULL;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
-
if (ALT_MOUNT(mount_cmd)) {
zone_iptype_t iptype;
- const char *curr_iptype;
+ const char *curr_iptype = NULL;
- if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
+ if (zonecfg_get_iptype(snap_hndl, &iptype) != Z_OK) {
zerror(zlogp, B_TRUE, "unable to determine ip-type");
- zonecfg_fini_handle(handle);
return (-1);
}
@@ -3283,17 +3253,15 @@ get_privset(zlog_t *zlogp, priv_set_t *privs, zone_mnt_t mount_cmd)
break;
}
- if (zonecfg_default_privset(privs, curr_iptype) == Z_OK) {
- zonecfg_fini_handle(handle);
+ if (zonecfg_default_privset(privs, curr_iptype) == Z_OK)
return (0);
- }
+
zerror(zlogp, B_FALSE,
"failed to determine the zone's default privilege set");
- zonecfg_fini_handle(handle);
return (-1);
}
- switch (zonecfg_get_privset(handle, privs, &privname)) {
+ switch (zonecfg_get_privset(snap_hndl, privs, &privname)) {
case Z_OK:
error = 0;
break;
@@ -3316,10 +3284,22 @@ get_privset(zlog_t *zlogp, priv_set_t *privs, zone_mnt_t mount_cmd)
}
free(privname);
- zonecfg_fini_handle(handle);
return (error);
}
+static char *
+zone_proj_rctl(const char *name)
+{
+ int i;
+
+ for (i = 0; zone_proj_rctl_map[i].zpr_zone_rctl != NULL; i++) {
+ if (strcmp(name, zone_proj_rctl_map[i].zpr_zone_rctl) == 0) {
+ return (zone_proj_rctl_map[i].zpr_project_rctl);
+ }
+ }
+ return (NULL);
+}
+
static int
get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
{
@@ -3329,25 +3309,15 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
nvlist_t **nvlv = NULL;
int rctlcount = 0;
int error = -1;
- zone_dochandle_t handle;
struct zone_rctltab rctltab;
rctlblk_t *rctlblk = NULL;
uint64_t maxlwps;
uint64_t maxprocs;
+ int rproc, rlwp;
*bufp = NULL;
*bufsizep = 0;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
-
rctltab.zone_rctl_valptr = NULL;
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
zerror(zlogp, B_TRUE, "%s failed", "nvlist_alloc");
@@ -3356,22 +3326,31 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
/*
* Allow the administrator to control both the maximum number of
- * process table slots and the maximum number of lwps with just the
- * max-processes property. If only the max-processes property is set,
- * we add a max-lwps property with a limit derived from max-processes.
+ * process table slots, and the maximum number of lwps, with a single
+ * max-processes or max-lwps property. If only the max-processes
+ * property is set, we add a max-lwps property with a limit derived
+ * from max-processes. If only the max-lwps property is set, we add a
+ * max-processes property with the same limit as max-lwps.
*/
- if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXPROCS, &maxprocs)
- == Z_OK &&
- zonecfg_get_aliased_rctl(handle, ALIAS_MAXLWPS, &maxlwps)
- == Z_NO_ENTRY) {
- if (zonecfg_set_aliased_rctl(handle, ALIAS_MAXLWPS,
+ rproc = zonecfg_get_aliased_rctl(snap_hndl, ALIAS_MAXPROCS, &maxprocs);
+ rlwp = zonecfg_get_aliased_rctl(snap_hndl, ALIAS_MAXLWPS, &maxlwps);
+ if (rproc == Z_OK && rlwp == Z_NO_ENTRY) {
+ if (zonecfg_set_aliased_rctl(snap_hndl, ALIAS_MAXLWPS,
maxprocs * LWPS_PER_PROCESS) != Z_OK) {
zerror(zlogp, B_FALSE, "unable to set max-lwps alias");
goto out;
}
+ } else if (rlwp == Z_OK && rproc == Z_NO_ENTRY) {
+ /* no scaling for max-proc value */
+ if (zonecfg_set_aliased_rctl(snap_hndl, ALIAS_MAXPROCS,
+ maxlwps) != Z_OK) {
+ zerror(zlogp, B_FALSE,
+ "unable to set max-processes alias");
+ goto out;
+ }
}
- if (zonecfg_setrctlent(handle) != Z_OK) {
+ if (zonecfg_setrctlent(snap_hndl) != Z_OK) {
zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setrctlent");
goto out;
}
@@ -3380,10 +3359,11 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
zerror(zlogp, B_TRUE, "memory allocation failed");
goto out;
}
- while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
+ while (zonecfg_getrctlent(snap_hndl, &rctltab) == Z_OK) {
struct zone_rctlvaltab *rctlval;
uint_t i, count;
const char *name = rctltab.zone_rctl_name;
+ char *proj_nm;
/* zoneadm should have already warned about unknown rctls. */
if (!zonecfg_is_rctl(name)) {
@@ -3450,6 +3430,26 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
}
zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
rctltab.zone_rctl_valptr = NULL;
+
+ /*
+ * With no action on our part we will start zsched with the
+ * project rctl values for our (zoneadmd) current project. For
+ * brands running a variant of Illumos, that's not a problem
+ * since they will setup their own projects, but for a
+ * non-native brand like lx, where there are no projects, we
+ * want to start things up with the same project rctls as the
+ * corresponding zone rctls, since nothing within the zone will
+ * ever change the project rctls.
+ */
+ if ((proj_nm = zone_proj_rctl(name)) != NULL) {
+ if (nvlist_add_nvlist_array(nvl, proj_nm, nvlv, count)
+ != 0) {
+ zerror(zlogp, B_FALSE,
+ "nvlist_add_nvlist_arrays failed");
+ goto out;
+ }
+ }
+
if (nvlist_add_nvlist_array(nvl, (char *)name, nvlv, count)
!= 0) {
zerror(zlogp, B_FALSE, "%s failed",
@@ -3462,7 +3462,7 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
nvlv = NULL;
rctlcount++;
}
- (void) zonecfg_endrctlent(handle);
+ (void) zonecfg_endrctlent(snap_hndl);
if (rctlcount == 0) {
error = 0;
@@ -3486,8 +3486,6 @@ out:
nvlist_free(nvl);
if (nvlv != NULL)
free(nvlv);
- if (handle != NULL)
- zonecfg_fini_handle(handle);
return (error);
}
@@ -3503,7 +3501,7 @@ get_implicit_datasets(zlog_t *zlogp, char **retstr)
> sizeof (cmdbuf))
return (-1);
- if (do_subproc(zlogp, cmdbuf, retstr) != 0)
+ if (do_subproc(zlogp, cmdbuf, retstr, B_FALSE) != 0)
return (-1);
return (0);
@@ -3512,7 +3510,6 @@ get_implicit_datasets(zlog_t *zlogp, char **retstr)
static int
get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
{
- zone_dochandle_t handle;
struct zone_dstab dstab;
size_t total, offset, len;
int error = -1;
@@ -3523,30 +3520,20 @@ get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
*bufp = NULL;
*bufsizep = 0;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
-
if (get_implicit_datasets(zlogp, &implicit_datasets) != 0) {
zerror(zlogp, B_FALSE, "getting implicit datasets failed");
goto out;
}
- if (zonecfg_setdsent(handle) != Z_OK) {
+ if (zonecfg_setdsent(snap_hndl) != Z_OK) {
zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setdsent");
goto out;
}
total = 0;
- while (zonecfg_getdsent(handle, &dstab) == Z_OK)
+ while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK)
total += strlen(dstab.zone_dataset_name) + 1;
- (void) zonecfg_enddsent(handle);
+ (void) zonecfg_enddsent(snap_hndl);
if (implicit_datasets != NULL)
implicit_len = strlen(implicit_datasets);
@@ -3563,12 +3550,12 @@ get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
goto out;
}
- if (zonecfg_setdsent(handle) != Z_OK) {
+ if (zonecfg_setdsent(snap_hndl) != Z_OK) {
zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setdsent");
goto out;
}
offset = 0;
- while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
+ while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK) {
len = strlen(dstab.zone_dataset_name);
(void) strlcpy(str + offset, dstab.zone_dataset_name,
total - offset);
@@ -3576,7 +3563,7 @@ get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
if (offset < total - 1)
str[offset++] = ',';
}
- (void) zonecfg_enddsent(handle);
+ (void) zonecfg_enddsent(snap_hndl);
if (implicit_len > 0)
(void) strlcpy(str + offset, implicit_datasets, total - offset);
@@ -3588,8 +3575,6 @@ get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
out:
if (error != 0 && str != NULL)
free(str);
- if (handle != NULL)
- zonecfg_fini_handle(handle);
if (implicit_datasets != NULL)
free(implicit_datasets);
@@ -3599,40 +3584,26 @@ out:
static int
validate_datasets(zlog_t *zlogp)
{
- zone_dochandle_t handle;
struct zone_dstab dstab;
zfs_handle_t *zhp;
libzfs_handle_t *hdl;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (-1);
- }
- if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+ if (zonecfg_setdsent(snap_hndl) != Z_OK) {
zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (-1);
- }
-
- if (zonecfg_setdsent(handle) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
return (-1);
}
if ((hdl = libzfs_init()) == NULL) {
zerror(zlogp, B_FALSE, "opening ZFS library");
- zonecfg_fini_handle(handle);
return (-1);
}
- while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
+ while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK) {
if ((zhp = zfs_open(hdl, dstab.zone_dataset_name,
ZFS_TYPE_FILESYSTEM)) == NULL) {
zerror(zlogp, B_FALSE, "cannot open ZFS dataset '%s'",
dstab.zone_dataset_name);
- zonecfg_fini_handle(handle);
libzfs_fini(hdl);
return (-1);
}
@@ -3647,7 +3618,6 @@ validate_datasets(zlog_t *zlogp)
zerror(zlogp, B_FALSE, "cannot set 'zoned' "
"property for ZFS dataset '%s'\n",
dstab.zone_dataset_name);
- zonecfg_fini_handle(handle);
zfs_close(zhp);
libzfs_fini(hdl);
return (-1);
@@ -3655,9 +3625,8 @@ validate_datasets(zlog_t *zlogp)
zfs_close(zhp);
}
- (void) zonecfg_enddsent(handle);
+ (void) zonecfg_enddsent(snap_hndl);
- zonecfg_fini_handle(handle);
libzfs_fini(hdl);
return (0);
@@ -3711,17 +3680,11 @@ validate_rootds_label(zlog_t *zlogp, char *rootpath, m_label_t *zone_sl)
zfs_handle_t *zhp;
libzfs_handle_t *hdl;
m_label_t ds_sl;
- char zonepath[MAXPATHLEN];
char ds_hexsl[MAXNAMELEN];
if (!is_system_labeled())
return (0);
- if (zone_get_zonepath(zone_name, zonepath, sizeof (zonepath)) != Z_OK) {
- zerror(zlogp, B_TRUE, "unable to determine zone path");
- return (-1);
- }
-
if (!is_zonepath_zfs(zonepath))
return (0);
@@ -4392,62 +4355,52 @@ duplicate_reachable_path(zlog_t *zlogp, const char *rootpath)
}
/*
- * Set memory cap and pool info for the zone's resource management
- * configuration.
+ * Set pool info for the zone's resource management configuration.
*/
static int
setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
{
int res;
uint64_t tmp;
- struct zone_mcaptab mcap;
char sched[MAXNAMELEN];
- zone_dochandle_t handle = NULL;
char pool_err[128];
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (Z_BAD_HANDLE);
- }
-
- if ((res = zonecfg_get_snapshot_handle(zone_name, handle)) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- zonecfg_fini_handle(handle);
- return (res);
- }
-
- /*
- * If a memory cap is configured, set the cap in the kernel using
- * zone_setattr() and make sure the rcapd SMF service is enabled.
- */
- if (zonecfg_getmcapent(handle, &mcap) == Z_OK) {
- uint64_t num;
- char smf_err[128];
-
- num = (uint64_t)strtoull(mcap.zone_physmem_cap, NULL, 10);
- if (zone_setattr(zoneid, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) {
- zerror(zlogp, B_TRUE, "could not set zone memory cap");
- zonecfg_fini_handle(handle);
- return (Z_INVAL);
- }
-
- if (zonecfg_enable_rcapd(smf_err, sizeof (smf_err)) != Z_OK) {
- zerror(zlogp, B_FALSE, "enabling system/rcap service "
- "failed: %s", smf_err);
- zonecfg_fini_handle(handle);
- return (Z_INVAL);
- }
- }
-
/* Get the scheduling class set in the zone configuration. */
- if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
+ if (zonecfg_get_sched_class(snap_hndl, sched, sizeof (sched)) == Z_OK &&
strlen(sched) > 0) {
if (zone_setattr(zoneid, ZONE_ATTR_SCHED_CLASS, sched,
strlen(sched)) == -1)
zerror(zlogp, B_TRUE, "WARNING: unable to set the "
"default scheduling class");
- } else if (zonecfg_get_aliased_rctl(handle, ALIAS_SHARES, &tmp)
+ if (strcmp(sched, "FX") == 0) {
+ /*
+ * When FX is specified then by default all processes
+ * will start at the lowest priority level (0) and
+ * stay there. We support an optional attr which
+ * indicates that all the processes should be "high
+ * priority". We set this on the zone so that starting
+ * init will set the priority high.
+ */
+ struct zone_attrtab a;
+
+ bzero(&a, sizeof (a));
+ (void) strlcpy(a.zone_attr_name, "fixed-hi-prio",
+ sizeof (a.zone_attr_name));
+
+ if (zonecfg_lookup_attr(snap_hndl, &a) == Z_OK &&
+ strcmp(a.zone_attr_value, "true") == 0) {
+ boolean_t hi = B_TRUE;
+
+ if (zone_setattr(zoneid,
+ ZONE_ATTR_SCHED_FIXEDHI, (void *)hi,
+ sizeof (hi)) == -1)
+ zerror(zlogp, B_TRUE, "WARNING: unable "
+ "to set high priority");
+ }
+ }
+
+ } else if (zonecfg_get_aliased_rctl(snap_hndl, ALIAS_SHARES, &tmp)
== Z_OK) {
/*
* If the zone has the zone.cpu-shares rctl set then we want to
@@ -4458,7 +4411,7 @@ setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
*/
char class_name[PC_CLNMSZ];
- if (zonecfg_get_dflt_sched_class(handle, class_name,
+ if (zonecfg_get_dflt_sched_class(snap_hndl, class_name,
sizeof (class_name)) != Z_OK) {
zerror(zlogp, B_FALSE, "WARNING: unable to determine "
"the zone's scheduling class");
@@ -4491,7 +4444,7 @@ setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
* right thing in all cases (reuse or create) based on the current
* zonecfg.
*/
- if ((res = zonecfg_bind_tmp_pool(handle, zoneid, pool_err,
+ if ((res = zonecfg_bind_tmp_pool(snap_hndl, zoneid, pool_err,
sizeof (pool_err))) != Z_OK) {
if (res == Z_POOL || res == Z_POOL_CREATE || res == Z_POOL_BIND)
zerror(zlogp, B_FALSE, "%s: %s\ndedicated-cpu setting "
@@ -4500,14 +4453,13 @@ setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
else
zerror(zlogp, B_FALSE, "could not bind zone to "
"temporary pool: %s", zonecfg_strerror(res));
- zonecfg_fini_handle(handle);
return (Z_POOL_BIND);
}
/*
* Check if we need to warn about poold not being enabled.
*/
- if (zonecfg_warn_poold(handle)) {
+ if (zonecfg_warn_poold(snap_hndl)) {
zerror(zlogp, B_FALSE, "WARNING: A range of dedicated-cpus has "
"been specified\nbut the dynamic pool service is not "
"enabled.\nThe system will not dynamically adjust the\n"
@@ -4517,7 +4469,7 @@ setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
}
/* The following is a warning, not an error. */
- if ((res = zonecfg_bind_pool(handle, zoneid, pool_err,
+ if ((res = zonecfg_bind_pool(snap_hndl, zoneid, pool_err,
sizeof (pool_err))) != Z_OK) {
if (res == Z_POOL_BIND)
zerror(zlogp, B_FALSE, "WARNING: unable to bind to "
@@ -4531,10 +4483,9 @@ setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
}
/* Update saved pool name in case it has changed */
- (void) zonecfg_get_poolname(handle, zone_name, pool_name,
+ (void) zonecfg_get_poolname(snap_hndl, zone_name, pool_name,
sizeof (pool_name));
- zonecfg_fini_handle(handle);
return (Z_OK);
}
@@ -4725,36 +4676,31 @@ setup_zone_fs_allowed(zone_dochandle_t handle, zlog_t *zlogp, zoneid_t zoneid)
}
static int
-setup_zone_attrs(zlog_t *zlogp, char *zone_namep, zoneid_t zoneid)
+setup_zone_attrs(zlog_t *zlogp, zoneid_t zoneid)
{
- zone_dochandle_t handle;
int res = Z_OK;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE, "getting zone configuration handle");
- return (Z_BAD_HANDLE);
- }
- if ((res = zonecfg_get_snapshot_handle(zone_namep, handle)) != Z_OK) {
- zerror(zlogp, B_FALSE, "invalid configuration");
- goto out;
- }
-
- if ((res = setup_zone_hostid(handle, zlogp, zoneid)) != Z_OK)
+ if ((res = setup_zone_hostid(snap_hndl, zlogp, zoneid)) != Z_OK)
goto out;
- if ((res = setup_zone_fs_allowed(handle, zlogp, zoneid)) != Z_OK)
+ if ((res = setup_zone_fs_allowed(snap_hndl, zlogp, zoneid)) != Z_OK)
goto out;
- if ((res = setup_zone_secflags(handle, zlogp, zoneid)) != Z_OK)
+ if ((res = setup_zone_secflags(snap_hndl, zlogp, zoneid)) != Z_OK)
goto out;
out:
- zonecfg_fini_handle(handle);
return (res);
}
+/*
+ * The zone_did is a persistent debug ID. Each zone should have a unique ID
+ * in the kernel. This is used for things like DTrace which want to monitor
+ * zones across reboots. They can't use the zoneid since that changes on
+ * each boot.
+ */
zoneid_t
-vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
+vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zone_did)
{
zoneid_t rval = -1;
priv_set_t *privs;
@@ -4770,7 +4716,7 @@ vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
tsol_zcent_t *zcent = NULL;
int match = 0;
int doi = 0;
- int flags;
+ int flags = -1;
zone_iptype_t iptype;
if (zone_get_rootpath(zone_name, rootpath, sizeof (rootpath)) != Z_OK) {
@@ -4792,6 +4738,8 @@ vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
flags = ZCF_NET_EXCL;
break;
}
+ if (flags == -1)
+ abort();
if ((privs = priv_allocset()) == NULL) {
zerror(zlogp, B_TRUE, "%s failed", "priv_allocset");
@@ -4895,7 +4843,7 @@ vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
xerr = 0;
if ((zoneid = zone_create(kzone, rootpath, privs, rctlbuf,
rctlbufsz, zfsbuf, zfsbufsz, &xerr, match, doi, zlabel,
- flags)) == -1) {
+ flags, zone_did)) == -1) {
if (xerr == ZE_AREMOUNTS) {
if (zonecfg_find_mounts(rootpath, NULL, NULL) < 1) {
zerror(zlogp, B_FALSE,
@@ -4941,7 +4889,7 @@ vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
struct brand_attr attr;
char modname[MAXPATHLEN];
- if (setup_zone_attrs(zlogp, zone_name, zoneid) != Z_OK)
+ if (setup_zone_attrs(zlogp, zoneid) != Z_OK)
goto error;
if ((bh = brand_open(brand_name)) == NULL) {
@@ -4999,6 +4947,8 @@ error:
}
if (rctlbuf != NULL)
free(rctlbuf);
+ if (zfsbuf != NULL)
+ free(zfsbuf);
priv_freeset(privs);
if (fp != NULL)
zonecfg_close_scratch(fp);
@@ -5087,7 +5037,7 @@ write_index_file(zoneid_t zoneid)
int
vplat_bringup(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zoneid)
{
- char zonepath[MAXPATHLEN];
+ char zpath[MAXPATHLEN];
if (mount_cmd == Z_MNT_BOOT && validate_datasets(zlogp) != 0) {
lofs_discard_mnttab();
@@ -5098,15 +5048,11 @@ vplat_bringup(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zoneid)
* Before we try to mount filesystems we need to create the
* attribute backing store for /dev
*/
- if (zone_get_zonepath(zone_name, zonepath, sizeof (zonepath)) != Z_OK) {
- lofs_discard_mnttab();
- return (-1);
- }
- resolve_lofs(zlogp, zonepath, sizeof (zonepath));
+ (void) strlcpy(zpath, zonepath, sizeof (zpath));
+ resolve_lofs(zlogp, zpath, sizeof (zpath));
/* Make /dev directory owned by root, grouped sys */
- if (make_one_dir(zlogp, zonepath, "/dev", DEFAULT_DIR_MODE,
- 0, 3) != 0) {
+ if (make_one_dir(zlogp, zpath, "/dev", DEFAULT_DIR_MODE, 0, 3) != 0) {
lofs_discard_mnttab();
return (-1);
}
@@ -5141,6 +5087,8 @@ vplat_bringup(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zoneid)
return (-1);
}
break;
+ default:
+ abort();
}
}
@@ -5215,14 +5163,88 @@ unmounted:
}
}
+/*
+ * Delete all transient VNICs belonging to this zone. A transient VNIC
+ * is one that is created and destroyed along with the lifetime of the
+ * zone. Non-transient VNICs, ones that are assigned from the GZ to a
+ * NGZ, are reassigned to the GZ in zone_shutdown() via the
+ * zone-specific data (zsd) callbacks.
+ */
+static int
+delete_transient_vnics(zlog_t *zlogp, zoneid_t zoneid)
+{
+ dladm_status_t status;
+ int num_links = 0;
+ datalink_id_t *links, link;
+ uint32_t link_flags;
+ datalink_class_t link_class;
+ char link_name[MAXLINKNAMELEN];
+
+ if (zone_list_datalink(zoneid, &num_links, NULL) != 0) {
+ zerror(zlogp, B_TRUE, "unable to determine "
+ "number of network interfaces");
+ return (-1);
+ }
+
+ if (num_links == 0)
+ return (0);
+
+ links = malloc(num_links * sizeof (datalink_id_t));
+
+ if (links == NULL) {
+ zerror(zlogp, B_TRUE, "failed to delete "
+ "network interfaces because of alloc fail");
+ return (-1);
+ }
+
+ if (zone_list_datalink(zoneid, &num_links, links) != 0) {
+ zerror(zlogp, B_TRUE, "failed to delete "
+ "network interfaces because of failure "
+ "to list them");
+ return (-1);
+ }
+
+ for (int i = 0; i < num_links; i++) {
+ char dlerr[DLADM_STRSIZE];
+ link = links[i];
+
+ status = dladm_datalink_id2info(dld_handle, link, &link_flags,
+ &link_class, NULL, link_name, sizeof (link_name));
+
+ if (status != DLADM_STATUS_OK) {
+ zerror(zlogp, B_FALSE, "failed to "
+ "delete network interface (%u)"
+ "due to failure to get link info: %s",
+ link,
+ dladm_status2str(status, dlerr));
+ return (-1);
+ }
+
+ if (link_flags & DLADM_OPT_TRANSIENT) {
+ assert(link_class & DATALINK_CLASS_VNIC);
+ status = dladm_vnic_delete(dld_handle, link,
+ DLADM_OPT_ACTIVE);
+
+ if (status != DLADM_STATUS_OK) {
+ zerror(zlogp, B_TRUE, "failed to delete link "
+ "with id %d: %s", link,
+ dladm_status2str(status, dlerr));
+ return (-1);
+ }
+ }
+ }
+
+ return (0);
+}
+
int
-vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
+vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting,
+ boolean_t debug)
{
char *kzone;
zoneid_t zoneid;
int res;
char pool_err[128];
- char zpath[MAXPATHLEN];
char cmdbuf[MAXPATHLEN];
brand_handle_t bh = NULL;
dladm_status_t status;
@@ -5255,16 +5277,12 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
goto error;
}
- if (remove_datalink_pool(zlogp, zoneid) != 0) {
+ if (remove_datalink_pool(zlogp, zoneid) != 0)
zerror(zlogp, B_FALSE, "unable clear datalink pool property");
- goto error;
- }
- if (remove_datalink_protect(zlogp, zoneid) != 0) {
+ if (remove_datalink_protect(zlogp, zoneid) != 0)
zerror(zlogp, B_FALSE,
"unable clear datalink protect property");
- goto error;
- }
/*
* The datalinks assigned to the zone will be removed from the NGZ as
@@ -5278,12 +5296,6 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
goto error;
}
- /* Get the zonepath of this zone */
- if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
- zerror(zlogp, B_FALSE, "unable to determine zone path");
- goto error;
- }
-
/* Get a handle to the brand info for this zone */
if ((bh = brand_open(brand_name)) == NULL) {
zerror(zlogp, B_FALSE, "unable to determine zone brand");
@@ -5294,7 +5306,7 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
* brand a chance to cleanup any custom configuration.
*/
(void) strcpy(cmdbuf, EXEC_PREFIX);
- if (brand_get_halt(bh, zone_name, zpath, cmdbuf + EXEC_LEN,
+ if (brand_get_halt(bh, zone_name, zonepath, cmdbuf + EXEC_LEN,
sizeof (cmdbuf) - EXEC_LEN) < 0) {
brand_close(bh);
zerror(zlogp, B_FALSE, "unable to determine branded zone's "
@@ -5304,7 +5316,7 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
brand_close(bh);
if ((strlen(cmdbuf) > EXEC_LEN) &&
- (do_subproc(zlogp, cmdbuf, NULL) != Z_OK)) {
+ (do_subproc(zlogp, cmdbuf, NULL, debug) != Z_OK)) {
zerror(zlogp, B_FALSE, "%s failed", cmdbuf);
goto error;
}
@@ -5336,17 +5348,18 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
}
break;
case ZS_EXCLUSIVE:
- if (unconfigure_exclusive_network_interfaces(zlogp,
- zoneid) != 0) {
- zerror(zlogp, B_FALSE, "unable to unconfigure "
- "network interfaces in zone");
+ if (delete_transient_vnics(zlogp, zoneid) != 0) {
+ zerror(zlogp, B_FALSE, "unable to delete "
+ "transient vnics in zone");
goto error;
}
+
status = dladm_zone_halt(dld_handle, zoneid);
if (status != DLADM_STATUS_OK) {
zerror(zlogp, B_FALSE, "unable to notify "
"dlmgmtd of zone halt: %s",
dladm_status2str(status, errmsg));
+ goto error;
}
break;
}
@@ -5378,14 +5391,9 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
if (rebooting) {
struct zone_psettab pset_tab;
- zone_dochandle_t handle;
- if ((handle = zonecfg_init_handle()) != NULL &&
- zonecfg_get_handle(zone_name, handle) == Z_OK &&
- zonecfg_lookup_pset(handle, &pset_tab) == Z_OK)
+ if (zonecfg_lookup_pset(snap_hndl, &pset_tab) == Z_OK)
destroy_tmp_pool = B_FALSE;
-
- zonecfg_fini_handle(handle);
}
if (destroy_tmp_pool) {
diff --git a/usr/src/cmd/zoneadmd/zcons.c b/usr/src/cmd/zoneadmd/zcons.c
index 5f6fc4973c..5f415b0210 100644
--- a/usr/src/cmd/zoneadmd/zcons.c
+++ b/usr/src/cmd/zoneadmd/zcons.c
@@ -22,7 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2012 Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
@@ -40,10 +40,10 @@
*
* Global Zone | Non-Global Zone
* .--------------. |
- * .-----------. | zoneadmd -z | | .--------. .---------.
- * | zlogin -C | | myzone | | | ttymon | | syslogd |
- * `-----------' `--------------' | `--------' `---------'
- * | | | | | | |
+ * .-----------. | zoneadmd -z |--. | .--------. .---------.
+ * | zlogin -C | | myzone | | | | ttymon | | syslogd |
+ * `-----------' `--------------' V | `--------' `---------'
+ * | | | | console.log | | |
* User | | | | | V V
* - - - - - - - - -|- - - -|- - - -|-|- - - - - - -|- - /dev/zconsole - - -
* Kernel V V | | |
@@ -81,6 +81,8 @@
* functions as a two-way proxy for console I/O, relaying user input
* to the master side of the console, and relaying output from the
* zone to the user.
+ *
+ * - Logging output to <zonepath>/logs/console.log.
*/
#include <sys/types.h>
@@ -118,9 +120,10 @@
#define CONSOLE_SOCKPATH ZONES_TMPDIR "/%s.console_sock"
+#define ZCONS_RETRY 10
+
static int serverfd = -1; /* console server unix domain socket fd */
char boot_args[BOOTARGS_MAX];
-char bad_boot_arg[BOOTARGS_MAX];
/*
* The eventstream is a simple one-directional flow of messages from the
@@ -130,7 +133,10 @@ char bad_boot_arg[BOOTARGS_MAX];
*/
static int eventstream[2];
-
+/* flag used to cope with race creating master zcons devlink */
+static boolean_t master_zcons_failed = B_FALSE;
+/* flag to track if we've seen a state change when there is no master zcons */
+static boolean_t state_changed = B_FALSE;
int
eventstream_init()
@@ -322,7 +328,7 @@ destroy_console_devs(zlog_t *zlogp)
* interfaces to instantiate a new zone console node. We do a lot of
* sanity checking, and are careful to reuse a console if one exists.
*
- * Once the device is in the device tree, we kick devfsadm via di_init_devs()
+ * Once the device is in the device tree, we kick devfsadm via di_devlink_init()
* to ensure that the appropriate symlinks (to the master and slave console
* devices) are placed in /dev in the global zone.
*/
@@ -408,43 +414,63 @@ devlinks:
* Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
* which will cause the master to retain a reference to the slave.
* This prevents ttymon from blowing through the slave's STREAMS anchor.
+ *
+ * In very rare cases the open returns ENOENT if devfs doesn't have
+ * everything setup yet due to heavy zone startup load. Wait for
+ * 1 sec. and retry a few times. Even if we can't setup the zone's
+ * console, we still go ahead and boot the zone.
*/
(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
zone_name, ZCONS_MASTER_NAME);
- if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
+ for (i = 0; i < ZCONS_RETRY; i++) {
+ masterfd = open(conspath, O_RDWR | O_NOCTTY);
+ if (masterfd >= 0 || errno != ENOENT)
+ break;
+ (void) sleep(1);
+ }
+ if (masterfd == -1) {
zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
"zone console for %s to acquire slave handle", zone_name);
- goto error;
+ master_zcons_failed = B_TRUE;
}
+
(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
zone_name, ZCONS_SLAVE_NAME);
- if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
+ for (i = 0; i < ZCONS_RETRY; i++) {
+ slavefd = open(conspath, O_RDWR | O_NOCTTY);
+ if (slavefd >= 0 || errno != ENOENT)
+ break;
+ (void) sleep(1);
+ }
+ if (slavefd == -1)
zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
" console for %s to acquire slave handle", zone_name);
- (void) close(masterfd);
- goto error;
- }
+
/*
* This ioctl can occasionally return ENXIO if devfs doesn't have
* everything plumbed up yet due to heavy zone startup load. Wait for
* 1 sec. and retry a few times before we fail to boot the zone.
*/
- for (i = 0; i < 5; i++) {
- if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd)
- == 0) {
- rv = 0;
- break;
- } else if (errno != ENXIO) {
- break;
+ if (masterfd != -1 && slavefd != -1) {
+ for (i = 0; i < ZCONS_RETRY; i++) {
+ if (ioctl(masterfd, ZC_HOLDSLAVE,
+ (caddr_t)(intptr_t)slavefd) == 0) {
+ rv = 0;
+ break;
+ } else if (errno != ENXIO) {
+ break;
+ }
+ (void) sleep(1);
}
- (void) sleep(1);
+ if (rv != 0)
+ zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
+ "slave handle of zone console for %s", zone_name);
}
- if (rv != 0)
- zerror(zlogp, B_TRUE, "ERROR: error while acquiring slave "
- "handle of zone console for %s", zone_name);
- (void) close(slavefd);
- (void) close(masterfd);
+ if (slavefd != -1)
+ (void) close(slavefd);
+ if (masterfd != -1)
+ (void) close(masterfd);
error:
if (ddef_hdl)
@@ -517,6 +543,7 @@ get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
size_t buflen = sizeof (buf);
char c = '\0';
int i = 0, r;
+ ucred_t *cred = NULL;
/* "eat up the ident string" case, for simplicity */
if (pid == NULL) {
@@ -550,18 +577,22 @@ get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
break;
}
+ if (getpeerucred(clifd, &cred) == 0) {
+ *pid = ucred_getpid((const ucred_t *)cred);
+ ucred_free(cred);
+ } else {
+ return (-1);
+ }
+
/*
* Parse buffer for message of the form:
- * IDENT <pid> <locale> <disconnect flag>
+ * IDENT <locale> <disconnect flag>
*/
bufp = buf;
if (strncmp(bufp, "IDENT ", 6) != 0)
return (-1);
bufp += 6;
errno = 0;
- *pid = strtoll(bufp, &bufp, 10);
- if (errno != 0)
- return (-1);
while (*bufp != '\0' && isspace(*bufp))
bufp++;
@@ -667,14 +698,6 @@ event_message(int clifd, char *clilocale, zone_evt_t evt, int dflag)
else
str = "NOTICE: Zone boot failed";
break;
- case Z_EVT_ZONE_BADARGS:
- /*LINTED*/
- (void) snprintf(lmsg, sizeof (lmsg),
- localize_msg(clilocale,
- "WARNING: Ignoring invalid boot arguments: %s"),
- bad_boot_arg);
- lstr = lmsg;
- break;
default:
return;
}
@@ -713,7 +736,7 @@ test_client(int clifd)
* messages) can be output in the user's locale.
*/
static void
-do_console_io(zlog_t *zlogp, int consfd, int servfd)
+do_console_io(zlog_t *zlogp, int consfd, int servfd, int conslog)
{
struct pollfd pollfds[4];
char ibuf[BUFSIZ];
@@ -759,14 +782,21 @@ do_console_io(zlog_t *zlogp, int consfd, int servfd)
(POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
errno = 0;
cc = read(consfd, ibuf, BUFSIZ);
- if (cc <= 0 && (errno != EINTR) &&
- (errno != EAGAIN))
- break;
- /*
- * Lose I/O if no one is listening
- */
- if (clifd != -1 && cc > 0)
- (void) write(clifd, ibuf, cc);
+ if (cc <= 0) {
+ if (errno != EINTR &&
+ errno != EAGAIN) {
+ break;
+ }
+ } else {
+ logstream_write(conslog, ibuf, cc);
+
+ /*
+ * Lose I/O if no one is listening
+ */
+ if (clifd != -1) {
+ (void) write(clifd, ibuf, cc);
+ }
+ }
} else {
pollerr = pollfds[0].revents;
zerror(zlogp, B_FALSE,
@@ -878,7 +908,6 @@ init_console(zlog_t *zlogp)
if (init_console_dev(zlogp) == -1) {
zerror(zlogp, B_FALSE,
"console setup: device initialization failed");
- return (-1);
}
if ((serverfd = init_console_sock(zlogp)) == -1) {
@@ -890,6 +919,17 @@ init_console(zlog_t *zlogp)
}
/*
+ * Maintain a simple flag that tracks if we have seen at least one state
+ * change. This is currently only used to handle the special case where we are
+ * running without a console device, which is what normally drives shutdown.
+ */
+void
+zcons_statechanged()
+{
+ state_changed = B_TRUE;
+}
+
+/*
* serve_console() is the master loop for driving console I/O. It is also the
* routine which is ultimately responsible for "pulling the plug" on zoneadmd
* when it realizes that the daemon should shut down.
@@ -907,6 +947,10 @@ serve_console(zlog_t *zlogp)
int masterfd;
zone_state_t zstate;
char conspath[MAXPATHLEN];
+ static boolean_t cons_warned = B_FALSE;
+ int conslog;
+
+ conslog = logstream_open("console.log", "console", LS_LINE_BUFFERED);
(void) snprintf(conspath, sizeof (conspath),
"/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
@@ -914,6 +958,46 @@ serve_console(zlog_t *zlogp)
for (;;) {
masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
if (masterfd == -1) {
+ if (master_zcons_failed) {
+ /*
+ * If we don't have a console and the zone is
+ * not shutting down, there may have been a
+ * race/failure with devfs while creating the
+ * console. In this case we want to leave the
+ * zone up, even without a console, so
+ * periodically recheck.
+ */
+ int i;
+
+ /*
+ * In the normal flow of this loop, we use
+ * do_console_io to give things a chance to get
+ * going first. However, in this case we can't
+ * use that, so we have to wait for at least
+ * one state change before checking the state.
+ */
+ for (i = 0; i < 60; i++) {
+ if (state_changed)
+ break;
+ (void) sleep(1);
+ }
+
+ if (i < 60 && zone_get_state(zone_name,
+ &zstate) == Z_OK &&
+ (zstate == ZONE_STATE_READY ||
+ zstate == ZONE_STATE_RUNNING)) {
+ if (!cons_warned) {
+ zerror(zlogp, B_FALSE,
+ "WARNING: missing zone "
+ "console for %s",
+ zone_name);
+ cons_warned = B_TRUE;
+ }
+ (void) sleep(ZCONS_RETRY);
+ continue;
+ }
+ }
+
zerror(zlogp, B_TRUE, "failed to open console master");
(void) mutex_lock(&lock);
goto death;
@@ -933,7 +1017,7 @@ serve_console(zlog_t *zlogp)
goto death;
}
- do_console_io(zlogp, masterfd, serverfd);
+ do_console_io(zlogp, masterfd, serverfd, conslog);
/*
* We would prefer not to do this, but hostile zone processes
@@ -974,4 +1058,6 @@ death:
destroy_console_sock(serverfd);
(void) destroy_console_devs(zlogp);
+
+ logstream_close(conslog, B_FALSE);
}
diff --git a/usr/src/cmd/zoneadmd/zfd.c b/usr/src/cmd/zoneadmd/zfd.c
new file mode 100644
index 0000000000..307d916154
--- /dev/null
+++ b/usr/src/cmd/zoneadmd/zfd.c
@@ -0,0 +1,1237 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Zone file descriptor support is used as a mechanism for a process inside the
+ * zone to log messages to the GZ zoneadmd and also as a way to interact
+ * directly with the process (via zlogin -I). The zfd thread is modeled on
+ * the zcons thread so see the comment header in zcons.c for a general overview.
+ * Unlike with zcons, which has a single endpoint within the zone and a single
+ * endpoint used by zoneadmd, we setup multiple endpoints within the zone.
+ *
+ * The mode, which is controlled by the zone attribute "zlog-mode" is somewhat
+ * of a misnomer since its purpose has evolved. The attribute currently
+ * can have six values which are used to control:
+ * - how the zfd devices are used inside the zone
+ * - if the output on the device(s) is also teed into another stream within
+ * the zone
+ * - if we do logging in the GZ
+ * See the comment on get_mode_logmax() in this file, and the comment in
+ * uts/common/io/zfd.c for more details.
+ *
+ * Internally the zfd_mode_t struct holds the number of stdio devs (1 or 3),
+ * the number of additional devs corresponding to the zone attr value and the
+ * GZ logging flag.
+ *
+ * Note that although the mode indicates the number of devices needed, we always
+ * create all possible zfd devices for simplicity.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/termios.h>
+#include <sys/zfd.h>
+#include <sys/mkdev.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stropts.h>
+#include <thread.h>
+#include <ucred.h>
+#include <unistd.h>
+#include <zone.h>
+#include <signal.h>
+#include <wchar.h>
+
+#include <libdevinfo.h>
+#include <libdevice.h>
+#include <libzonecfg.h>
+
+#include <syslog.h>
+#include <sys/modctl.h>
+
+#include "zoneadmd.h"
+
+static int shutting_down = 0;
+static thread_t logger_tid;
+static char log_name[MAXNAMELEN] = "stdio.log";
+
+/*
+ * The eventstream is a simple one-directional flow of messages implemented
+ * with a pipe. It is used to wake up the poller when it needs to shutdown.
+ */
+static int eventstream[2] = {-1, -1};
+
+#define ZLOG_MODE "zlog-mode"
+#define ZLOG_NAME "zlog-name"
+#define ZFDNEX_DEVTREEPATH "/pseudo/zfdnex@2"
+#define ZFDNEX_FILEPATH "/devices/pseudo/zfdnex@2"
+#define SERVER_SOCKPATH ZONES_TMPDIR "/%s.server_%s"
+#define ZTTY_RETRY 5
+
+#define NUM_ZFD_DEVS 5
+
+typedef struct zfd_mode {
+ uint_t zmode_n_stddevs;
+ uint_t zmode_n_addl_devs;
+ boolean_t zmode_gzlogging;
+} zfd_mode_t;
+static zfd_mode_t mode;
+
+/*
+ * cb_data is only used by destroy_cb.
+ */
+struct cb_data {
+ zlog_t *zlogp;
+ int killed;
+};
+
+/*
+ * destroy_zfd_devs() and its helper destroy_cb() tears down any zfd instances
+ * associated with this zone. If things went very wrong, we might have an
+ * incorrect number of instances hanging around. This routine hunts down and
+ * tries to remove all of them. Of course, if the fd is open, the instance will
+ * not detach, which is a potential issue.
+ */
+static int
+destroy_cb(di_node_t node, void *arg)
+{
+ struct cb_data *cb = (struct cb_data *)arg;
+ char *prop_data;
+ char *tmp;
+ char devpath[MAXPATHLEN];
+ devctl_hdl_t hdl;
+
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zfd_zname",
+ &prop_data) == -1)
+ return (DI_WALK_CONTINUE);
+
+ assert(prop_data != NULL);
+ if (strcmp(prop_data, zone_name) != 0) {
+ /* this is a zfd for a different zone */
+ return (DI_WALK_CONTINUE);
+ }
+
+ tmp = di_devfs_path(node);
+ (void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp);
+ di_devfs_path_free(tmp);
+
+ if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) {
+ zerror(cb->zlogp, B_TRUE, "WARNING: zfd %s found, "
+ "but it could not be controlled.", devpath);
+ return (DI_WALK_CONTINUE);
+ }
+ if (devctl_device_remove(hdl) == 0) {
+ cb->killed++;
+ } else {
+ zerror(cb->zlogp, B_TRUE, "WARNING: zfd %s found, "
+ "but it could not be removed.", devpath);
+ }
+ devctl_release(hdl);
+ return (DI_WALK_CONTINUE);
+}
+
+static int
+destroy_zfd_devs(zlog_t *zlogp)
+{
+ di_node_t root;
+ struct cb_data cb;
+
+ bzero(&cb, sizeof (cb));
+ cb.zlogp = zlogp;
+
+ if ((root = di_init(ZFDNEX_DEVTREEPATH, DINFOCPYALL)) == DI_NODE_NIL) {
+ zerror(zlogp, B_TRUE, "di_init failed");
+ return (-1);
+ }
+
+ (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
+
+ di_fini(root);
+ return (0);
+}
+
+static void
+make_tty(zlog_t *zlogp, int id)
+{
+ int i;
+ int fd = -1;
+ char stdpath[MAXPATHLEN];
+
+ /*
+ * Open the master side of the dev and issue the ZFD_MAKETTY ioctl,
+ * which will cause the the various tty-related streams modules to be
+ * pushed when the slave opens the device.
+ *
+ * In very rare cases the open returns ENOENT if devfs doesn't have
+ * everything setup yet due to heavy zone startup load. Wait for
+ * 1 sec. and retry a few times. Even if we can't setup tty mode
+ * we still move on.
+ */
+ (void) snprintf(stdpath, sizeof (stdpath), "/dev/zfd/%s/master/%d",
+ zone_name, id);
+
+ for (i = 0; !shutting_down && i < ZTTY_RETRY; i++) {
+ fd = open(stdpath, O_RDWR | O_NOCTTY);
+ if (fd >= 0 || errno != ENOENT)
+ break;
+ (void) sleep(1);
+ }
+ if (fd == -1) {
+ zerror(zlogp, B_TRUE, "ERROR: could not open zfd %d for "
+ "zone %s to set tty mode", id, zone_name);
+ } else {
+ /*
+ * This ioctl can occasionally return ENXIO if devfs doesn't
+ * have everything plumbed up yet due to heavy zone startup
+ * load. Wait for 1 sec. and retry a few times before we give
+ * up.
+ */
+ for (i = 0; !shutting_down && i < ZTTY_RETRY; i++) {
+ if (ioctl(fd, ZFD_MAKETTY) == 0) {
+ break;
+ } else if (errno != ENXIO) {
+ break;
+ }
+ (void) sleep(1);
+ }
+ }
+
+ if (fd != -1)
+ (void) close(fd);
+}
+
+/*
+ * init_zfd_devs() drives the device-tree configuration of the zone fd devices.
+ * The general strategy is to use the libdevice (devctl) interfaces to
+ * instantiate all of new zone fd nodes. We do a lot of sanity checking, and
+ * are careful to reuse a dev if one exists.
+ *
+ * Once the devices are in the device tree, we kick devfsadm via
+ * di_devlink_init() to ensure that the appropriate symlinks (to the master and
+ * slave fd devices) are placed in /dev in the global zone.
+ */
+static int
+init_zfd_dev(zlog_t *zlogp, devctl_hdl_t bus_hdl, int id)
+{
+ int rv = -1;
+ devctl_ddef_t ddef_hdl = NULL;
+ devctl_hdl_t dev_hdl = NULL;
+
+ if ((ddef_hdl = devctl_ddef_alloc("zfd", 0)) == NULL) {
+ zerror(zlogp, B_TRUE, "failed to allocate ddef handle");
+ goto error;
+ }
+
+ /*
+ * Set four properties on this node; the name of the zone, the dev name
+ * seen inside the zone, a flag which lets pseudo know that it is OK to
+ * automatically allocate an instance # for this device, and the last
+ * one tells the device framework not to auto-detach this node - we
+ * need the node to still be there when we ask devfsadmd to make links,
+ * and when we need to open it.
+ */
+ if (devctl_ddef_string(ddef_hdl, "zfd_zname", zone_name) == -1) {
+ zerror(zlogp, B_TRUE, "failed to create zfd_zname property");
+ goto error;
+ }
+ if (devctl_ddef_int(ddef_hdl, "zfd_id", id) == -1) {
+ zerror(zlogp, B_TRUE, "failed to create zfd_id property");
+ goto error;
+ }
+ if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) {
+ zerror(zlogp, B_TRUE, "failed to create auto-assign-instance "
+ "property");
+ goto error;
+ }
+ if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
+ zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
+ "property");
+ goto error;
+ }
+ if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
+ zerror(zlogp, B_TRUE, "failed to create zfd node");
+ goto error;
+ }
+ rv = 0;
+
+error:
+ if (ddef_hdl)
+ devctl_ddef_free(ddef_hdl);
+ if (dev_hdl)
+ devctl_release(dev_hdl);
+ return (rv);
+}
+
+static int
+init_zfd_devs(zlog_t *zlogp, zfd_mode_t *mode)
+{
+ devctl_hdl_t bus_hdl = NULL;
+ di_devlink_handle_t dl = NULL;
+ int rv = -1;
+ int i;
+
+ /*
+ * Time to make the devices.
+ */
+ if ((bus_hdl = devctl_bus_acquire(ZFDNEX_FILEPATH, 0)) == NULL) {
+ zerror(zlogp, B_TRUE, "devctl_bus_acquire failed");
+ goto error;
+ }
+
+ for (i = 0; i < NUM_ZFD_DEVS; i++) {
+ if (init_zfd_dev(zlogp, bus_hdl, i) != 0)
+ goto error;
+ }
+
+ if ((dl = di_devlink_init("zfd", DI_MAKE_LINK)) == NULL) {
+ zerror(zlogp, B_TRUE, "failed to create devlinks");
+ goto error;
+ }
+
+ (void) di_devlink_fini(&dl);
+ rv = 0;
+
+ if (mode->zmode_n_stddevs == 1) {
+ /* We want the primary stream to look like a tty. */
+ make_tty(zlogp, 0);
+ }
+
+error:
+ if (bus_hdl)
+ devctl_release(bus_hdl);
+ return (rv);
+}
+
+static int
+init_server_sock(int *servfd, char *nm)
+{
+ int resfd = -1;
+ struct sockaddr_un servaddr;
+
+ bzero(&servaddr, sizeof (servaddr));
+ servaddr.sun_family = AF_UNIX;
+ (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
+ SERVER_SOCKPATH, zone_name, nm);
+
+ if ((resfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ zerror(&logplat, B_TRUE,
+ "server setup: could not create socket");
+ goto err;
+ }
+ (void) unlink(servaddr.sun_path);
+
+ if (bind(resfd, (struct sockaddr *)&servaddr, sizeof (servaddr))
+ == -1) {
+ zerror(&logplat, B_TRUE,
+ "server setup: could not bind to socket");
+ goto err;
+ }
+
+ if (listen(resfd, 4) == -1) {
+ zerror(&logplat, B_TRUE,
+ "server setup: could not listen on socket");
+ goto err;
+ }
+
+ *servfd = resfd;
+ return (0);
+
+err:
+ (void) unlink(servaddr.sun_path);
+ if (resfd != -1)
+ (void) close(resfd);
+ return (-1);
+}
+
+static void
+destroy_server_sock(int servfd, char *nm)
+{
+ char path[MAXPATHLEN];
+
+ (void) snprintf(path, sizeof (path), SERVER_SOCKPATH, zone_name, nm);
+ (void) unlink(path);
+ (void) shutdown(servfd, SHUT_RDWR);
+ (void) close(servfd);
+}
+
+/*
+ * Read the "ident" string from the client's descriptor; this routine also
+ * tolerates being called with pid=NULL, for times when you want to "eat"
+ * the ident string from a client without saving it.
+ */
+static int
+get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
+ uint_t *flagsp)
+{
+ char buf[BUFSIZ], *bufp;
+ size_t buflen = sizeof (buf);
+ char c = '\0';
+ int i = 0, r;
+ ucred_t *cred = NULL;
+
+ /* "eat up the ident string" case, for simplicity */
+ if (pid == NULL) {
+ assert(locale == NULL && locale_len == 0);
+ while (read(clifd, &c, 1) == 1) {
+ if (c == '\n')
+ return (0);
+ }
+ }
+
+ bzero(buf, sizeof (buf));
+ while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
+ buflen--;
+ if (c == '\n')
+ break;
+
+ buf[i] = c;
+ i++;
+ }
+ if (r == -1)
+ return (-1);
+
+ /*
+ * We've filled the buffer, but still haven't seen \n. Keep eating
+ * until we find it; we don't expect this to happen, but this is
+ * defensive.
+ */
+ if (c != '\n') {
+ while ((r = read(clifd, &c, sizeof (c))) > 0)
+ if (c == '\n')
+ break;
+ }
+
+ /*
+ * Parse buffer for message of the form:
+ * IDENT <locale> <flags>
+ */
+ bufp = buf;
+ if (strncmp(bufp, "IDENT ", 6) != 0)
+ return (-1);
+ bufp += 6;
+
+ if (getpeerucred(clifd, &cred) == 0) {
+ *pid = ucred_getpid((const ucred_t *)cred);
+ ucred_free(cred);
+ } else {
+ return (-1);
+ }
+
+ while (*bufp != '\0' && isspace(*bufp))
+ bufp++;
+ buflen = strlen(bufp) - 1;
+ bufp[buflen - 1] = '\0';
+ (void) strlcpy(locale, bufp, locale_len);
+
+ *flagsp = atoi(&bufp[buflen]);
+
+ return (0);
+}
+
+static int
+accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
+ uint_t *flagsp)
+{
+ int connfd;
+ struct sockaddr_un cliaddr;
+ socklen_t clilen;
+ int flags;
+
+ clilen = sizeof (cliaddr);
+ connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
+ if (connfd == -1)
+ return (-1);
+ if (pid != NULL) {
+ if (get_client_ident(connfd, pid, locale, locale_len, flagsp)
+ == -1) {
+ (void) shutdown(connfd, SHUT_RDWR);
+ (void) close(connfd);
+ return (-1);
+ }
+ (void) write(connfd, "OK\n", 3);
+ }
+
+ flags = fcntl(connfd, F_GETFL, 0);
+ if (flags != -1)
+ (void) fcntl(connfd, F_SETFL, flags | O_NONBLOCK | FD_CLOEXEC);
+
+ return (connfd);
+}
+
+static void
+reject_client(int servfd, pid_t clientpid)
+{
+ int connfd;
+ struct sockaddr_un cliaddr;
+ socklen_t clilen;
+ char nak[MAXPATHLEN];
+
+ clilen = sizeof (cliaddr);
+ connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
+
+ /*
+ * After getting its ident string, tell client to get lost.
+ */
+ if (get_client_ident(connfd, NULL, NULL, 0, NULL) == 0) {
+ (void) snprintf(nak, sizeof (nak), "%lu\n",
+ clientpid);
+ (void) write(connfd, nak, strlen(nak));
+ }
+ (void) shutdown(connfd, SHUT_RDWR);
+ (void) close(connfd);
+}
+
+static int
+accept_socket(int servfd, pid_t verpid)
+{
+ int connfd;
+ struct sockaddr_un cliaddr;
+ socklen_t clilen = sizeof (cliaddr);
+ ucred_t *cred = NULL;
+ pid_t rpid = -1;
+ int flags;
+
+ connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
+ if (connfd == -1)
+ return (-1);
+
+ /* Confirm connecting process is who we expect */
+ if (getpeerucred(connfd, &cred) == 0) {
+ rpid = ucred_getpid((const ucred_t *)cred);
+ ucred_free(cred);
+ }
+ if (rpid == -1 || rpid != verpid) {
+ (void) shutdown(connfd, SHUT_RDWR);
+ (void) close(connfd);
+ return (-1);
+ }
+
+ flags = fcntl(connfd, F_GETFL, 0);
+ if (flags != -1)
+ (void) fcntl(connfd, F_SETFL, flags | O_NONBLOCK | FD_CLOEXEC);
+
+ return (connfd);
+}
+
+static void
+ctlcmd_process(int sockfd, int stdoutfd, unsigned int *flags)
+{
+ char buf[BUFSIZ];
+ int i;
+ for (i = 0; i < BUFSIZ-1; i++) {
+ char c;
+ if (read(sockfd, &c, 1) != 1 ||
+ c == '\n' || c == '\0') {
+ break;
+ }
+ buf[i] = c;
+ }
+ if (i == 0) {
+ goto fail;
+ }
+ buf[i] = '\0';
+
+ if (strncmp(buf, "TIOCSWINSZ ", 11) == 0) {
+ char *next = buf + 11;
+ struct winsize ws;
+ errno = 0;
+ ws.ws_row = strtol(next, &next, 10);
+ if (errno == EINVAL) {
+ goto fail;
+ }
+ ws.ws_col = strtol(next + 1, &next, 10);
+ if (errno == EINVAL) {
+ goto fail;
+ }
+ if (ioctl(stdoutfd, TIOCSWINSZ, &ws) == 0) {
+ (void) write(sockfd, "OK\n", 3);
+ return;
+ }
+ }
+ if (strncmp(buf, "SETFLAGS ", 9) == 0) {
+ char *next = buf + 9;
+ unsigned int result;
+ errno = 0;
+ result = strtoul(next, &next, 10);
+ if (errno == EINVAL) {
+ goto fail;
+ }
+ *flags = result;
+ (void) write(sockfd, "OK\n", 3);
+ return;
+ }
+fail:
+ (void) write(sockfd, "FAIL\n", 5);
+}
+
+/*
+ * Check to see if the client at the other end of the socket is still alive; we
+ * know it is not if it throws EPIPE at us when we try to write an otherwise
+ * harmless 0-length message to it.
+ */
+static int
+test_client(int clifd)
+{
+ if ((write(clifd, "", 0) == -1) && errno == EPIPE)
+ return (-1);
+ return (0);
+}
+
+/*
+ * We want to sleep for a little while but need to be responsive if the zone is
+ * halting. We poll/sleep on the event stream so we can notice if we're halting.
+ * Return true if halting, otherwise false.
+ */
+static boolean_t
+halt_sleep(int slptime)
+{
+ struct pollfd evfd[1];
+
+ evfd[0].fd = eventstream[1];
+ evfd[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
+
+ if (poll(evfd, 1, slptime) > 0) {
+ /* zone halting */
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * This routine drives the logging and interactive I/O loop. It polls for
+ * input from the zone side of the fd (output to stdout/stderr), and from the
+ * client (input to the zone's stdin). Additionally, it polls on the server
+ * fd, and disconnects any clients that might try to hook up with the zone
+ * while the fd's are in use.
+ *
+ * Data from the zone's stdout and stderr is formatted in json and written to
+ * the log file whether an interactive client is connected or not.
+ *
+ * When the client first calls us up, it is expected to send a line giving its
+ * "identity"; this consists of the string 'IDENT <pid> <locale>'. This is so
+ * that we can report that the fd's are busy, along with some diagnostics
+ * about who has them busy; the locale is ignore here but kept for compatability
+ * with the zlogin code when running on the zone's console.
+ *
+ * We need to handle the case where there is no server within the zone (or
+ * the server gets stuck) and data that we're writing to the zone server's
+ * stdin fills the pipe. Because of the way the zfd device works writes can
+ * flow into the stream and simply be dropped, if there is no server, or writes
+ * could return -1 with EAGAIN if the server is stuck. Since we ignore errors
+ * on the write to stdin, we won't get blocked in that case but we'd like to
+ * avoid dropping initial input if the server within the zone hasn't started
+ * yet. To handle this we wait to read initial input until we detect that there
+ * is a server inside the zone. We have to poll for this so that we can
+ * re-run the ioctl to notice when a server shows up. This poll/wait is handled
+ * by halt_sleep() so that we can be responsive if the zone wants to halt.
+ * We only do this check to avoid dropping initial input so it is possible for
+ * the server within the zone to go away later. At that point zfd will just
+ * drop any new input flowing into the stream.
+ */
+static void
+do_zfd_io(int gzctlfd, int gzservfd, int gzerrfd, int stdinfd, int stdoutfd,
+ int stderrfd, int logout, int logerr)
+{
+ struct pollfd pollfds[8];
+ char ibuf[BUFSIZ + 1];
+ int cc, ret;
+ int ctlfd = -1;
+ int clifd = -1;
+ int clierrfd = -1;
+ int pollerr = 0;
+ char clilocale[MAXPATHLEN];
+ pid_t clipid = 0;
+ uint_t flags = 0;
+ boolean_t stdin_ready = B_FALSE;
+ int slptime = 250; /* initial poll sleep time in ms */
+
+ /* client control socket, watch for read events */
+ pollfds[0].fd = ctlfd;
+ pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
+ POLLPRI | POLLERR | POLLHUP | POLLNVAL;
+
+ /* client socket, watch for read events */
+ pollfds[1].fd = clifd;
+ pollfds[1].events = pollfds[0].events;
+
+ /* stdout, watch for read events */
+ pollfds[2].fd = stdoutfd;
+ pollfds[2].events = pollfds[0].events;
+
+ /* stderr, watch for read events */
+ pollfds[3].fd = stderrfd;
+ pollfds[3].events = pollfds[0].events;
+
+ /* the server control socket; watch for new connections */
+ pollfds[4].fd = gzctlfd;
+ pollfds[4].events = POLLIN | POLLRDNORM;
+
+ /* the server stdin/out socket; watch for new connections */
+ pollfds[5].fd = gzservfd;
+ pollfds[5].events = POLLIN | POLLRDNORM;
+
+ /* the server stderr socket; watch for new connections */
+ pollfds[6].fd = gzerrfd;
+ pollfds[6].events = POLLIN | POLLRDNORM;
+
+ /* the eventstream; any input means the zone is halting */
+ pollfds[7].fd = eventstream[1];
+ pollfds[7].events = pollfds[0].events;
+
+ while (!shutting_down) {
+ pollfds[0].revents = pollfds[1].revents = 0;
+ pollfds[2].revents = pollfds[3].revents = 0;
+ pollfds[4].revents = pollfds[5].revents = 0;
+ pollfds[6].revents = pollfds[7].revents = 0;
+
+ ret = poll(pollfds, 8, -1);
+ if (ret == -1 && errno != EINTR) {
+ zerror(&logplat, B_TRUE, "poll failed");
+ /* we are hosed, close connection */
+ break;
+ }
+
+ /* control events from client */
+ if (pollfds[0].revents &
+ (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
+ /* process control message */
+ ctlcmd_process(ctlfd, stdoutfd, &flags);
+ } else if (pollfds[0].revents) {
+ /* bail if any error occurs */
+ pollerr = pollfds[0].revents;
+ zerror(&logplat, B_FALSE, "closing connection "
+ "with control channel, pollerr %d\n", pollerr);
+ break;
+ }
+
+ /* event from client side */
+ if (pollfds[1].revents) {
+ if (stdin_ready) {
+ if (pollfds[1].revents & (POLLIN |
+ POLLRDNORM | POLLRDBAND | POLLPRI)) {
+ errno = 0;
+ cc = read(clifd, ibuf, BUFSIZ);
+ if (cc > 0) {
+ /*
+ * See comment for this
+ * function on what happens if
+ * there is no reader in the
+ * zone. EOF is handled below.
+ */
+ (void) write(stdinfd, ibuf, cc);
+ }
+ } else if (pollfds[1].revents & (POLLERR |
+ POLLNVAL)) {
+ pollerr = pollfds[1].revents;
+ zerror(&logplat, B_FALSE,
+ "closing connection "
+ "with client, pollerr %d\n",
+ pollerr);
+ break;
+ }
+
+ if (pollfds[1].revents & POLLHUP) {
+ if (flags & ZLOGIN_ZFD_EOF) {
+ /*
+ * Let the client know. We've
+ * already serviced any pending
+ * regular input. Let the
+ * stream clear since the EOF
+ * ioctl jumps to the head.
+ */
+ (void) ioctl(stdinfd, I_FLUSH);
+ if (halt_sleep(250))
+ break;
+ (void) ioctl(stdinfd, ZFD_EOF);
+ }
+ break;
+ }
+ } else {
+ if (ioctl(stdinfd, ZFD_HAS_SLAVE) == 0) {
+ stdin_ready = B_TRUE;
+ } else {
+ /*
+ * There is nothing in the zone to read
+ * our input. Presumably the user
+ * providing input expects something to
+ * show up, but that is no guarantee.
+ * Since we haven't serviced the pending
+ * input poll yet, we don't want to
+ * immediately loop around but we also
+ * need to be responsive if the zone is
+ * halting.
+ */
+ if (halt_sleep(slptime))
+ break;
+
+ if (slptime < 5000)
+ slptime += 250;
+ }
+ }
+ }
+
+ /* event from the zone's stdout */
+ if (pollfds[2].revents) {
+ if (pollfds[2].revents &
+ (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
+ errno = 0;
+ cc = read(stdoutfd, ibuf, BUFSIZ);
+ /* zfd is a stream, so ignore 0 length read */
+ if (cc < 0 && (errno != EINTR) &&
+ (errno != EAGAIN))
+ break;
+ if (cc > 0) {
+ logstream_write(logout, ibuf, cc);
+
+ /*
+ * Lose output if no one is listening,
+ * otherwise pass it on.
+ */
+ if (clifd != -1)
+ (void) write(clifd, ibuf, cc);
+ }
+ } else {
+ pollerr = pollfds[2].revents;
+ zerror(&logplat, B_FALSE,
+ "closing connection with stdout zfd, "
+ "pollerr %d\n", pollerr);
+ break;
+ }
+ }
+
+ /* event from the zone's stderr */
+ if (pollfds[3].revents) {
+ if (pollfds[3].revents &
+ (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
+ errno = 0;
+ cc = read(stderrfd, ibuf, BUFSIZ);
+ /* zfd is a stream, so ignore 0 length read */
+ if (cc < 0 && (errno != EINTR) &&
+ (errno != EAGAIN))
+ break;
+ if (cc > 0) {
+ logstream_write(logerr, ibuf, cc);
+
+ /*
+ * Lose output if no one is listening,
+ * otherwise pass it on.
+ */
+ if (clierrfd != -1)
+ (void) write(clierrfd, ibuf,
+ cc);
+ }
+ } else {
+ pollerr = pollfds[3].revents;
+ zerror(&logplat, B_FALSE,
+ "closing connection with stderr zfd, "
+ "pollerr %d\n", pollerr);
+ break;
+ }
+ }
+
+ /* connect event from server control socket */
+ if (pollfds[4].revents) {
+ if (ctlfd != -1) {
+ /*
+ * Test the client to see if it is really
+ * still alive. If it has died but we
+ * haven't yet detected that, we might
+ * deny a legitimate connect attempt. If it
+ * is dead, we break out; once we tear down
+ * the old connection, the new connection
+ * will happen.
+ */
+ if (test_client(ctlfd) == -1) {
+ break;
+ }
+ /* we're already handling a client */
+ reject_client(gzctlfd, clipid);
+ } else {
+ ctlfd = accept_client(gzctlfd, &clipid,
+ clilocale, sizeof (clilocale), &flags);
+ if (ctlfd != -1) {
+ pollfds[0].fd = ctlfd;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* connect event from server stdin/out socket */
+ if (pollfds[5].revents) {
+ if (ctlfd == -1) {
+ /*
+ * This shouldn't happen since the client is
+ * expected to connect on the control socket
+ * first. If we see this, tear everything down
+ * and start over.
+ */
+ zerror(&logplat, B_FALSE, "GZ zfd stdin/stdout "
+ "connection attempt with no GZ control\n");
+ break;
+ }
+ assert(clifd == -1);
+ if ((clifd = accept_socket(gzservfd, clipid)) != -1) {
+ /* No need to watch for other new connections */
+ pollfds[5].fd = -1;
+ /* Client input is of interest, though */
+ pollfds[1].fd = clifd;
+ } else {
+ break;
+ }
+ }
+
+ /* connection event from server stderr socket */
+ if (pollfds[6].revents) {
+ if (ctlfd == -1) {
+ /*
+ * Same conditions apply to stderr as stdin/out.
+ */
+ zerror(&logplat, B_FALSE, "GZ zfd stderr "
+ "connection attempt with no GZ control\n");
+ break;
+ }
+ assert(clierrfd == -1);
+ if ((clierrfd = accept_socket(gzerrfd, clipid)) != -1) {
+ /* No need to watch for other new connections */
+ pollfds[6].fd = -1;
+ } else {
+ break;
+ }
+ }
+
+ /*
+ * Watch for events on the eventstream. This is how we get
+ * notified of the zone halting, etc. It provides us a
+ * "wakeup" from poll when important things happen, which
+ * is good.
+ */
+ if (pollfds[7].revents) {
+ break;
+ }
+ }
+
+ if (clifd != -1) {
+ (void) shutdown(clifd, SHUT_RDWR);
+ (void) close(clifd);
+ }
+
+ if (clierrfd != -1) {
+ (void) shutdown(clierrfd, SHUT_RDWR);
+ (void) close(clierrfd);
+ }
+}
+
+static int
+open_fd(int id, int rw)
+{
+ int fd;
+ int flag = O_NONBLOCK | O_NOCTTY | O_CLOEXEC;
+ int retried = 0;
+ char stdpath[MAXPATHLEN];
+
+ (void) snprintf(stdpath, sizeof (stdpath), "/dev/zfd/%s/master/%d",
+ zone_name, id);
+ flag |= rw;
+
+ while (!shutting_down) {
+ if ((fd = open(stdpath, flag)) != -1) {
+ /*
+ * Setting RPROTDIS on the stream means that the
+ * control portion of messages received (which we don't
+ * care about) will be discarded by the stream head. If
+ * we allowed such messages, we wouldn't be able to use
+ * read(2), as it fails (EBADMSG) when a message with a
+ * control element is received.
+ */
+ if (ioctl(fd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
+ zerror(&logplat, B_TRUE,
+ "failed to set options on zfd");
+ return (-1);
+ }
+ return (fd);
+ }
+
+ if (retried++ > 60)
+ break;
+
+ (void) sleep(1);
+ }
+
+ zerror(&logplat, B_TRUE, "failed to open zfd");
+ return (-1);
+}
+
+/*
+ * Body of the worker thread to log the zfd's stdout and stderr to a log file
+ * and to perform interactive IO to the stdin, stdout and stderr zfd's.
+ *
+ * The stdin, stdout and stderr are from the perspective of the process inside
+ * the zone, so the zoneadmd view is opposite (i.e. we write to the stdin fd
+ * and read from the stdout/stderr fds).
+ */
+static void
+srvr(void *modearg)
+{
+ zfd_mode_t *mode = (zfd_mode_t *)modearg;
+ int gzctlfd = -1;
+ int gzoutfd = -1;
+ int stdinfd = -1;
+ int stdoutfd = -1;
+ int gzerrfd = -1;
+ int stderrfd = -1;
+ int flags;
+ int len;
+ char ibuf[BUFSIZ + 1];
+ int logout = -1;
+ int logerr = -1;
+
+ if (!shutting_down && mode->zmode_gzlogging) {
+ logout = logstream_open(log_name, "stdout", 0);
+ logerr = logstream_open(log_name, "stderr", 0);
+ }
+
+ if (!shutting_down) {
+ if (pipe(eventstream) != 0) {
+ zerror(&logplat, B_TRUE, "failed to open logger "
+ "control pipe");
+ return;
+ }
+ }
+
+ while (!shutting_down) {
+ if (init_server_sock(&gzctlfd, "ctl") == -1) {
+ zerror(&logplat, B_FALSE,
+ "server setup: control socket init failed");
+ goto death;
+ }
+ if (init_server_sock(&gzoutfd, "out") == -1) {
+ zerror(&logplat, B_FALSE,
+ "server setup: stdout socket init failed");
+ goto death;
+ }
+ if (init_server_sock(&gzerrfd, "err") == -1) {
+ zerror(&logplat, B_FALSE,
+ "server setup: stderr socket init failed");
+ goto death;
+ }
+
+ if (mode->zmode_n_stddevs == 1) {
+ if ((stdinfd = open_fd(0, O_RDWR)) == -1) {
+ goto death;
+ }
+ stdoutfd = stdinfd;
+ } else {
+ if ((stdinfd = open_fd(0, O_WRONLY)) == -1 ||
+ (stdoutfd = open_fd(1, O_RDONLY)) == -1 ||
+ (stderrfd = open_fd(2, O_RDONLY)) == -1) {
+ goto death;
+ }
+ }
+
+ do_zfd_io(gzctlfd, gzoutfd, gzerrfd, stdinfd, stdoutfd,
+ stderrfd, logout, logerr);
+death:
+ destroy_server_sock(gzctlfd, "ctl");
+ destroy_server_sock(gzoutfd, "out");
+ destroy_server_sock(gzerrfd, "err");
+
+ /* when shutting down, leave open until drained */
+ if (!shutting_down) {
+ (void) close(stdinfd);
+ if (mode->zmode_n_stddevs == 3) {
+ (void) close(stdoutfd);
+ (void) close(stderrfd);
+ }
+ }
+ }
+
+ /*
+ * Attempt to drain remaining log output from the zone prior to closing
+ * the file descriptors. This helps ensure that complete logs are
+ * captured during shutdown.
+ */
+ flags = fcntl(stdoutfd, F_GETFL, 0);
+ if (fcntl(stdoutfd, F_SETFL, flags | O_NONBLOCK) != -1) {
+ while ((len = read(stdoutfd, ibuf, BUFSIZ)) > 0) {
+ logstream_write(logout, ibuf, len);
+ }
+ }
+ (void) close(stdoutfd);
+
+ if (mode->zmode_n_stddevs > 1) {
+ (void) close(stdinfd);
+ flags = fcntl(stderrfd, F_GETFL, 0);
+ if (fcntl(stderrfd, F_SETFL, flags | O_NONBLOCK) != -1) {
+ while ((len = read(stderrfd, ibuf, BUFSIZ)) > 0) {
+ logstream_write(logerr, ibuf, len);
+ }
+ }
+ (void) close(stderrfd);
+ }
+
+
+ (void) close(eventstream[0]);
+ eventstream[0] = -1;
+ (void) close(eventstream[1]);
+ eventstream[1] = -1;
+ logstream_close(logout, B_FALSE);
+ logstream_close(logerr, B_FALSE);
+}
+
+/*
+ * The meaning of the original legacy values for the zlog-mode evolved over
+ * time, to the point where the old names no longer made sense. The current
+ * values are simply positional letters used to indicate various capabilities.
+ * The following table shows the meaning of the mode values, along with the
+ * legacy name which we continue to support for compatability. Any future
+ * capability can add a letter to the left and '-' is implied for existing
+ * strings.
+ *
+ * zlog-mode gz log - tty - ngz log
+ * --------- ------ --- -------
+ * gt- (int) y y n
+ * g-- (log) y n n
+ * gtn (nlint) y y y
+ * g-n (nolog) y n y
+ * -t- n y n
+ * --- n n n
+ *
+ * This function also obtains any custom name for stdio.log while it is reading
+ * the zone configuration.
+ */
+static void
+get_mode_logmax(zfd_mode_t *mode)
+{
+ zone_dochandle_t handle;
+ struct zone_attrtab attr;
+
+ bzero(mode, sizeof (zfd_mode_t));
+
+ if ((handle = zonecfg_init_handle()) == NULL)
+ return;
+
+ if (zonecfg_get_handle(zone_name, handle) != Z_OK)
+ goto done;
+
+ if (zonecfg_setattrent(handle) != Z_OK)
+ goto done;
+ while (zonecfg_getattrent(handle, &attr) == Z_OK) {
+ if (strcmp(ZLOG_MODE, attr.zone_attr_name) == 0) {
+ if (strcmp("g--", attr.zone_attr_value) == 0 ||
+ strncmp("log", attr.zone_attr_value, 3) == 0) {
+ mode->zmode_gzlogging = B_TRUE;
+ mode->zmode_n_stddevs = 3;
+ mode->zmode_n_addl_devs = 0;
+ } else if (strcmp("g-n", attr.zone_attr_value) == 0 ||
+ strncmp("nolog", attr.zone_attr_value, 5) == 0) {
+ mode->zmode_gzlogging = B_TRUE;
+ mode->zmode_n_stddevs = 3;
+ mode->zmode_n_addl_devs = 2;
+ } else if (strcmp("gt-", attr.zone_attr_value) == 0 ||
+ strncmp("int", attr.zone_attr_value, 3) == 0) {
+ mode->zmode_gzlogging = B_TRUE;
+ mode->zmode_n_stddevs = 1;
+ mode->zmode_n_addl_devs = 0;
+ } else if (strcmp("gtn", attr.zone_attr_value) == 0 ||
+ strncmp("nlint", attr.zone_attr_value, 5) == 0) {
+ mode->zmode_gzlogging = B_TRUE;
+ mode->zmode_n_stddevs = 1;
+ mode->zmode_n_addl_devs = 1;
+ } else if (strcmp("-t-", attr.zone_attr_value) == 0) {
+ mode->zmode_gzlogging = B_FALSE;
+ mode->zmode_n_stddevs = 1;
+ mode->zmode_n_addl_devs = 0;
+ } else if (strcmp("---", attr.zone_attr_value) == 0) {
+ mode->zmode_gzlogging = B_FALSE;
+ mode->zmode_n_stddevs = 3;
+ mode->zmode_n_addl_devs = 0;
+ }
+ continue;
+ }
+
+ if (strcmp(ZLOG_NAME, attr.zone_attr_name) == 0) {
+ (void) strlcpy(log_name, attr.zone_attr_value,
+ sizeof (log_name));
+ continue;
+ }
+ }
+ (void) zonecfg_endattrent(handle);
+
+done:
+ zonecfg_fini_handle(handle);
+}
+
+void
+create_log_thread(zlog_t *zlogp)
+{
+ int res;
+
+ shutting_down = 0;
+
+ get_mode_logmax(&mode);
+ if (mode.zmode_n_stddevs == 0)
+ return;
+
+ if (init_zfd_devs(zlogp, &mode) == -1) {
+ zerror(zlogp, B_FALSE,
+ "zfd setup: device initialization failed");
+ return;
+ }
+
+ res = thr_create(NULL, 0, (void * (*)(void *))srvr, (void *)&mode, 0,
+ &logger_tid);
+ if (res != 0) {
+ zerror(zlogp, B_FALSE, "error %d creating logger thread", res);
+ logger_tid = 0;
+ }
+}
+
+void
+destroy_log_thread(zlog_t *zlogp)
+{
+ if (logger_tid != 0) {
+ int stop = 1;
+
+ shutting_down = 1;
+ /* break out of poll to shutdown */
+ if (eventstream[0] != -1)
+ (void) write(eventstream[0], &stop, sizeof (stop));
+ (void) thr_join(logger_tid, NULL, NULL);
+ logger_tid = 0;
+ }
+
+ (void) destroy_zfd_devs(zlogp);
+}
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.c b/usr/src/cmd/zoneadmd/zoneadmd.c
index b901d6055f..7c8d2a2bbc 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.c
+++ b/usr/src/cmd/zoneadmd/zoneadmd.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -69,6 +70,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
+#include <sys/time.h>
#include <bsm/adt.h>
#include <bsm/adt_event.h>
@@ -102,6 +104,8 @@
#include <libdladm.h>
#include <sys/dls_mgmt.h>
#include <libscf.h>
+#include <uuid/uuid.h>
+#include <libppt.h>
#include <libzonecfg.h>
#include <zonestat_impl.h>
@@ -109,6 +113,8 @@
static char *progname;
char *zone_name; /* zone which we are managing */
+zone_dochandle_t snap_hndl; /* handle for snapshot created when ready */
+char zonepath[MAXNAMELEN];
char pool_name[MAXNAMELEN];
char default_brand[MAXNAMELEN];
char brand_name[MAXNAMELEN];
@@ -117,13 +123,15 @@ boolean_t zone_iscluster;
boolean_t zone_islabeled;
boolean_t shutdown_in_progress;
static zoneid_t zone_id;
+static zoneid_t zone_did = 0;
dladm_handle_t dld_handle = NULL;
-static char pre_statechg_hook[2 * MAXPATHLEN];
-static char post_statechg_hook[2 * MAXPATHLEN];
+char pre_statechg_hook[2 * MAXPATHLEN];
+char post_statechg_hook[2 * MAXPATHLEN];
char query_hook[2 * MAXPATHLEN];
-zlog_t logsys;
+zlog_t logsys; /* log to syslog */
+zlog_t logplat; /* log to platform.log */
mutex_t lock = DEFAULTMUTEX; /* to serialize stuff */
mutex_t msglock = DEFAULTMUTEX; /* for calling setlocale() */
@@ -136,12 +144,17 @@ static int zone_door = -1;
boolean_t in_death_throes = B_FALSE; /* daemon is dying */
boolean_t bringup_failure_recovery = B_FALSE; /* ignore certain failures */
+static int platloghdl = -1; /* Handle for <zonepath>/logs/platform.log */
+
#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
#endif
#define DEFAULT_LOCALE "C"
+#define RSRC_NET "net"
+#define RSRC_DEV "device"
+
static const char *
z_cmd_name(zone_cmd_t zcmd)
{
@@ -215,17 +228,14 @@ zerror(zlog_t *zlogp, boolean_t use_strerror, const char *fmt, ...)
{
va_list alist;
char buf[MAXPATHLEN * 2]; /* enough space for err msg with a path */
- char *bp;
+ char *bp, *bp_nozone;
int saved_errno = errno;
- if (zlogp == NULL)
- return;
if (zlogp == &logsys)
- (void) snprintf(buf, sizeof (buf), "[zone '%s'] ",
- zone_name);
+ (void) snprintf(buf, sizeof (buf), "[zone '%s'] ", zone_name);
else
buf[0] = '\0';
- bp = &(buf[strlen(buf)]);
+ bp = bp_nozone = &(buf[strlen(buf)]);
/*
* In theory, the locale pointer should be set to either "C" or a
@@ -242,15 +252,38 @@ zerror(zlog_t *zlogp, boolean_t use_strerror, const char *fmt, ...)
if (use_strerror)
(void) snprintf(bp, sizeof (buf) - (bp - buf), ": %s",
strerror(saved_errno));
+
+ (void) strlcat(buf, "\n", sizeof (buf));
+
+ /*
+ * If we don't have the platform log, we are in a child process, and
+ * should log to stderr (which is a pipe) instead of the file.
+ */
+ if (logging_poisoned) {
+ (void) fprintf(stderr, "%s", buf);
+
+ if (zlogp != &logsys && zlogp->logfile == stderr)
+ return;
+ } else {
+ logstream_write(platloghdl, bp_nozone, strlen(bp_nozone));
+
+ if (zlogp == &logplat)
+ return;
+ }
+
if (zlogp == &logsys) {
+ bp = strrchr(buf, '\n');
+ if (bp != NULL && bp[1] == '\0') {
+ *bp = '\0';
+ }
(void) syslog(LOG_ERR, "%s", buf);
} else if (zlogp->logfile != NULL) {
- (void) fprintf(zlogp->logfile, "%s\n", buf);
+ (void) fprintf(zlogp->logfile, "%s", buf);
} else {
size_t buflen;
size_t copylen;
- buflen = snprintf(zlogp->log, zlogp->loglen, "%s\n", buf);
+ buflen = snprintf(zlogp->log, zlogp->loglen, "%s", buf);
copylen = MIN(buflen, zlogp->loglen);
zlogp->log += copylen;
zlogp->loglen -= copylen;
@@ -258,34 +291,43 @@ zerror(zlog_t *zlogp, boolean_t use_strerror, const char *fmt, ...)
}
/*
- * Emit a warning for any boot arguments which are unrecognized. Since
- * Solaris boot arguments are getopt(3c) compatible (see kernel(1m)), we
+ * Append src to dest, modifying dest in the process. Prefix src with
+ * a space character if dest is a non-empty string.
+ */
+static void
+strnappend(char *dest, size_t n, const char *src)
+{
+ (void) snprintf(dest, n, "%s%s%s", dest,
+ dest[0] == '\0' ? "" : " ", src);
+}
+
+/*
+ * Since illumos boot arguments are getopt(3c) compatible (see kernel(1m)), we
* put the arguments into an argv style array, use getopt to process them,
- * and put the resultant argument string back into outargs.
+ * and put the resultant argument string back into outargs. Non-native brands
+ * may support alternate forms of boot arguments so we must handle that as well.
*
* During the filtering, we pull out any arguments which are truly "boot"
* arguments, leaving only those which are to be passed intact to the
* progenitor process. The one we support at the moment is -i, which
* indicates to the kernel which program should be launched as 'init'.
*
- * A return of Z_INVAL indicates specifically that the arguments are
- * not valid; this is a non-fatal error. Except for Z_OK, all other return
- * values are treated as fatal.
+ * Except for Z_OK, all other return values are treated as fatal.
*/
static int
filter_bootargs(zlog_t *zlogp, const char *inargs, char *outargs,
- char *init_file, char *badarg)
+ char *init_file)
{
int argc = 0, argc_save;
int i;
- int err;
+ int err = Z_OK;
char *arg, *lasts, **argv = NULL, **argv_save;
char zonecfg_args[BOOTARGS_MAX];
char scratchargs[BOOTARGS_MAX], *sargs;
+ char scratchopt[3];
char c;
bzero(outargs, BOOTARGS_MAX);
- bzero(badarg, BOOTARGS_MAX);
/*
* If the user didn't specify transient boot arguments, check
@@ -293,25 +335,10 @@ filter_bootargs(zlog_t *zlogp, const char *inargs, char *outargs,
* and use them if applicable.
*/
if (inargs == NULL || inargs[0] == '\0') {
- zone_dochandle_t handle;
- if ((handle = zonecfg_init_handle()) == NULL) {
- zerror(zlogp, B_TRUE,
- "getting zone configuration handle");
- return (Z_BAD_HANDLE);
- }
- err = zonecfg_get_snapshot_handle(zone_name, handle);
- if (err != Z_OK) {
- zerror(zlogp, B_FALSE,
- "invalid configuration snapshot");
- zonecfg_fini_handle(handle);
- return (Z_BAD_HANDLE);
- }
-
bzero(zonecfg_args, sizeof (zonecfg_args));
- (void) zonecfg_get_bootargs(handle, zonecfg_args,
+ (void) zonecfg_get_bootargs(snap_hndl, zonecfg_args,
sizeof (zonecfg_args));
inargs = zonecfg_args;
- zonecfg_fini_handle(handle);
}
if (strlen(inargs) >= BOOTARGS_MAX) {
@@ -348,14 +375,22 @@ filter_bootargs(zlog_t *zlogp, const char *inargs, char *outargs,
}
/*
- * We preserve compatibility with the Solaris system boot behavior,
+ * We preserve compatibility with the illumos system boot behavior,
* which allows:
*
* # reboot kernel/unix -s -m verbose
*
- * In this example, kernel/unix tells the booter what file to
- * boot. We don't want reboot in a zone to be gratuitously different,
- * so we silently ignore the boot file, if necessary.
+ * In this example, kernel/unix tells the booter what file to boot. The
+ * original intent of this was that we didn't want reboot in a zone to
+ * be gratuitously different, so we would silently ignore the boot
+ * file, if necessary. However, this usage is archaic and has never
+ * been common, since it is impossible to boot a zone onto a different
+ * kernel. Ignoring the first argument breaks for non-native brands
+ * which pass boot arguments in a different style. e.g.
+ * systemd.log_level=debug
+ * Thus, for backward compatibility we only ignore the first argument
+ * if it appears to be in the illumos form and attempting to specify a
+ * kernel.
*/
if (argv[0] == NULL)
goto done;
@@ -363,7 +398,7 @@ filter_bootargs(zlog_t *zlogp, const char *inargs, char *outargs,
assert(argv[0][0] != ' ');
assert(argv[0][0] != '\t');
- if (argv[0][0] != '-' && argv[0][0] != '\0') {
+ if (strncmp(argv[0], "kernel/", 7) == 0) {
argv = &argv[1];
argc--;
}
@@ -386,41 +421,35 @@ filter_bootargs(zlog_t *zlogp, const char *inargs, char *outargs,
case 'm':
case 's':
/* These pass through unmolested */
- (void) snprintf(outargs, BOOTARGS_MAX,
- "%s -%c %s ", outargs, c, optarg ? optarg : "");
+ (void) snprintf(scratchopt, sizeof (scratchopt),
+ "-%c", c);
+ strnappend(outargs, BOOTARGS_MAX, scratchopt);
+ if (optarg != NULL)
+ strnappend(outargs, BOOTARGS_MAX, optarg);
break;
case '?':
/*
- * We warn about unknown arguments but pass them
- * along anyway-- if someone wants to develop their
- * own init replacement, they can pass it whatever
- * args they want.
+ * If a brand has its own init, we need to pass along
+ * whatever the user provides. We use the entire
+ * unknown string here so that we correctly handle
+ * unknown long options (e.g. --debug).
*/
- err = Z_INVAL;
- (void) snprintf(outargs, BOOTARGS_MAX,
- "%s -%c", outargs, optopt);
- (void) snprintf(badarg, BOOTARGS_MAX,
- "%s -%c", badarg, optopt);
+ strnappend(outargs, BOOTARGS_MAX, argv[optind - 1]);
break;
}
}
/*
- * For Solaris Zones we warn about and discard non-option arguments.
- * Hence 'boot foo bar baz gub' --> 'boot'. However, to be similar
- * to the kernel, we concat up all the other remaining boot args.
- * and warn on them as a group.
+ * We need to pass along everything else since we don't know what
+ * the brand's init is expecting. For example, an argument list like:
+ * --confdir /foo --debug
+ * will cause the getopt parsing to stop at '/foo' but we need to pass
+ * that on, along with the '--debug'. This does mean that we require
+ * any of our known options (-ifms) to preceed the brand-specific ones.
*/
- if (optind < argc) {
- err = Z_INVAL;
- while (optind < argc) {
- (void) snprintf(badarg, BOOTARGS_MAX, "%s%s%s",
- badarg, strlen(badarg) > 0 ? " " : "",
- argv[optind]);
- optind++;
- }
- zerror(zlogp, B_FALSE, "WARNING: Unused or invalid boot "
- "arguments `%s'.", badarg);
+ while (optind < argc) {
+ strnappend(outargs, BOOTARGS_MAX, argv[optind]);
+ optind++;
}
done:
@@ -459,7 +488,7 @@ mkzonedir(zlog_t *zlogp)
* Run the brand's pre-state change callback, if it exists.
*/
static int
-brand_prestatechg(zlog_t *zlogp, int state, int cmd)
+brand_prestatechg(zlog_t *zlogp, int state, int cmd, boolean_t debug)
{
char cmdbuf[2 * MAXPATHLEN];
const char *altroot;
@@ -472,7 +501,7 @@ brand_prestatechg(zlog_t *zlogp, int state, int cmd)
state, cmd, altroot) > sizeof (cmdbuf))
return (-1);
- if (do_subproc(zlogp, cmdbuf, NULL) != 0)
+ if (do_subproc(zlogp, cmdbuf, NULL, debug) != 0)
return (-1);
return (0);
@@ -482,7 +511,7 @@ brand_prestatechg(zlog_t *zlogp, int state, int cmd)
* Run the brand's post-state change callback, if it exists.
*/
static int
-brand_poststatechg(zlog_t *zlogp, int state, int cmd)
+brand_poststatechg(zlog_t *zlogp, int state, int cmd, boolean_t debug)
{
char cmdbuf[2 * MAXPATHLEN];
const char *altroot;
@@ -495,7 +524,7 @@ brand_poststatechg(zlog_t *zlogp, int state, int cmd)
state, cmd, altroot) > sizeof (cmdbuf))
return (-1);
- if (do_subproc(zlogp, cmdbuf, NULL) != 0)
+ if (do_subproc(zlogp, cmdbuf, NULL, debug) != 0)
return (-1);
return (0);
@@ -532,37 +561,51 @@ notify_zonestatd(zoneid_t zoneid)
* Bring a zone up to the pre-boot "ready" stage. The mount_cmd argument is
* 'true' if this is being invoked as part of the processing for the "mount"
* subcommand.
+ *
+ * If a scratch zone mount (ALT_MOUNT) is being performed then do not
+ * call the state change hooks.
*/
static int
-zone_ready(zlog_t *zlogp, zone_mnt_t mount_cmd, int zstate)
+zone_ready(zlog_t *zlogp, zone_mnt_t mount_cmd, int zstate, boolean_t debug)
{
int err;
+ boolean_t snapped = B_FALSE;
- if (brand_prestatechg(zlogp, zstate, Z_READY) != 0)
- return (-1);
-
+ if ((snap_hndl = zonecfg_init_handle()) == NULL) {
+ zerror(zlogp, B_TRUE, "getting zone configuration handle");
+ goto bad;
+ }
if ((err = zonecfg_create_snapshot(zone_name)) != Z_OK) {
zerror(zlogp, B_FALSE, "unable to create snapshot: %s",
zonecfg_strerror(err));
goto bad;
}
+ snapped = B_TRUE;
- if ((zone_id = vplat_create(zlogp, mount_cmd)) == -1) {
- if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
- zerror(zlogp, B_FALSE, "destroying snapshot: %s",
- zonecfg_strerror(err));
+ if (zonecfg_get_snapshot_handle(zone_name, snap_hndl) != Z_OK) {
+ zerror(zlogp, B_FALSE, "invalid configuration snapshot");
goto bad;
}
+
+ if (zone_did == 0)
+ zone_did = zone_get_did(zone_name);
+
+ if (!ALT_MOUNT(mount_cmd) &&
+ brand_prestatechg(zlogp, zstate, Z_READY, debug) != 0)
+ goto bad;
+
+ if ((zone_id = vplat_create(zlogp, mount_cmd, zone_did)) == -1)
+ goto bad;
+
if (vplat_bringup(zlogp, mount_cmd, zone_id) != 0) {
bringup_failure_recovery = B_TRUE;
- (void) vplat_teardown(NULL, (mount_cmd != Z_MNT_BOOT), B_FALSE);
- if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
- zerror(zlogp, B_FALSE, "destroying snapshot: %s",
- zonecfg_strerror(err));
+ (void) vplat_teardown(NULL, (mount_cmd != Z_MNT_BOOT), B_FALSE,
+ debug);
goto bad;
}
- if (brand_poststatechg(zlogp, zstate, Z_READY) != 0)
+ if (!ALT_MOUNT(mount_cmd) &&
+ brand_poststatechg(zlogp, zstate, Z_READY, debug) != 0)
goto bad;
return (0);
@@ -572,7 +615,16 @@ bad:
* If something goes wrong, we up the zones's state to the target
* state, READY, and then invoke the hook as if we're halting.
*/
- (void) brand_poststatechg(zlogp, ZONE_STATE_READY, Z_HALT);
+ if (!ALT_MOUNT(mount_cmd))
+ (void) brand_poststatechg(zlogp, ZONE_STATE_READY, Z_HALT,
+ debug);
+
+ if (snapped)
+ if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
+ zerror(zlogp, B_FALSE, "destroying snapshot: %s",
+ zonecfg_strerror(err));
+ zonecfg_fini_handle(snap_hndl);
+ snap_hndl = NULL;
return (-1);
}
@@ -624,15 +676,8 @@ mount_early_fs(void *data, const char *spec, const char *dir,
/* determine the zone rootpath */
if (mount_cmd) {
- char zonepath[MAXPATHLEN];
char luroot[MAXPATHLEN];
- if (zone_get_zonepath(zone_name,
- zonepath, sizeof (zonepath)) != Z_OK) {
- zerror(zlogp, B_FALSE, "unable to determine zone path");
- return (-1);
- }
-
(void) snprintf(luroot, sizeof (luroot), "%s/lu", zonepath);
resolve_lofs(zlogp, luroot, sizeof (luroot));
(void) strlcpy(rootpath, luroot, sizeof (rootpath));
@@ -687,6 +732,8 @@ mount_early_fs(void *data, const char *spec, const char *dir,
char opt_buf[MAX_MNTOPT_STR];
int optlen = 0;
int mflag = MS_DATA;
+ int i;
+ int ret;
(void) ct_tmpl_clear(tmpl_fd);
/*
@@ -714,9 +761,26 @@ mount_early_fs(void *data, const char *spec, const char *dir,
optlen = MAX_MNTOPT_STR;
mflag = MS_OPTIONSTR;
}
- if (mount(spec, dir, mflag, fstype, NULL, 0, opt, optlen) != 0)
- _exit(errno);
- _exit(0);
+
+ /*
+ * There is an obscure race condition which can cause mount
+ * to return EBUSY. This happens for example on the mount
+ * of the zone's /etc/svc/volatile file system if there is
+ * a GZ process running svcs -Z, which will touch the
+ * mountpoint, just as we're trying to do the mount. To cope
+ * with this, we retry up to 3 times to let this transient
+ * process get out of the way.
+ */
+ for (i = 0; i < 3; i++) {
+ ret = 0;
+ if (mount(spec, dir, mflag, fstype, NULL, 0, opt,
+ optlen) != 0)
+ ret = errno;
+ if (ret != EBUSY)
+ break;
+ (void) sleep(1);
+ }
+ _exit(ret);
}
/* parent */
@@ -740,18 +804,275 @@ mount_early_fs(void *data, const char *spec, const char *dir,
}
/*
+ * Replace characters other than [A-Za-z0-9_] with '_' so that the string is a
+ * valid environment variable name.
+ */
+static void
+sanitize_env_var_name(char *var)
+{
+ for (char *p = var; *p != '\0'; p++) {
+ if (!isalnum(*p)) {
+ *p = '_';
+ }
+ }
+}
+
+/*
+ * env variable name format
+ * _ZONECFG_{resource name}_{identifying attr. name}_{property name}
+ * Any dashes (-) in the property names are replaced with underscore (_).
+ */
+static void
+set_zonecfg_env(char *rsrc, char *attr, char *name, char *val)
+{
+ /* Enough for maximal name, rsrc + attr, & slop for ZONECFG & _'s */
+ char nm[2 * MAXNAMELEN + 32];
+
+ if (attr == NULL)
+ (void) snprintf(nm, sizeof (nm), "_ZONECFG_%s_%s", rsrc,
+ name);
+ else
+ (void) snprintf(nm, sizeof (nm), "_ZONECFG_%s_%s_%s", rsrc,
+ attr, name);
+
+ sanitize_env_var_name(nm);
+
+ (void) setenv(nm, val, 1);
+}
+
+/*
+ * Resolve a device:match value to a path. This is only different for PPT
+ * devices, where we expect the match property to be a /devices/... path, and
+ * configured for PPT already.
+ */
+int
+resolve_device_match(zlog_t *zlogp, struct zone_devtab *dtab,
+ char *path, size_t len)
+{
+ struct zone_res_attrtab *rap;
+
+ for (rap = dtab->zone_dev_attrp; rap != NULL;
+ rap = rap->zone_res_attr_next) {
+ if (strcmp(rap->zone_res_attr_name, "model") == 0 &&
+ strcmp(rap->zone_res_attr_value, "passthru") == 0)
+ break;
+ }
+
+ if (rap == NULL) {
+ if (strlcpy(path, dtab->zone_dev_match, len) >= len)
+ return (Z_INVAL);
+ return (Z_OK);
+ }
+
+ if (strncmp(dtab->zone_dev_match, "/devices",
+ strlen("/devices")) != 0) {
+ zerror(zlogp, B_FALSE, "invalid passthru match value '%s'",
+ dtab->zone_dev_match);
+ return (Z_INVAL);
+ }
+
+ if (ppt_devpath_to_dev(dtab->zone_dev_match, path, len) != 0) {
+ zerror(zlogp, B_TRUE, "failed to resolve passthru device %s",
+ dtab->zone_dev_match);
+ return (Z_INVAL);
+ }
+
+ return (Z_OK);
+}
+
+/*
+ * Export various zonecfg properties into environment for the boot and state
+ * change hooks.
+ *
+ * If debug is true, _ZONEADMD_brand_debug is set to 1, else it is set to an
+ * empty string. Brand hooks consider any non-empty string as an indication
+ * that debug output is requested.
+ *
+ * We could export more of the config in the future, as necessary. A better
+ * solution would be to make it so brand-specific behavior is handled by
+ * brand-specific callbacks written in C. Then the normal libzonecfg interfaces
+ * can be used for accessing any parts of the configuration that are needed.
+ *
+ * All of the environment variables set by this function are specific to
+ * SmartOS.
+ */
+static int
+setup_subproc_env(zlog_t *zlogp, boolean_t debug)
+{
+ int res;
+ struct zone_nwiftab ntab;
+ struct zone_devtab dtab;
+ struct zone_attrtab atab;
+ char net_resources[MAXNAMELEN * 2];
+ char dev_resources[MAXNAMELEN * 2];
+ char didstr[16];
+ char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
+ uuid_t uuid;
+
+ /* snap_hndl is null when called through the set_brand_env code path */
+ if (snap_hndl == NULL)
+ return (Z_OK);
+
+ if ((res = zonecfg_get_uuid(zone_name, uuid)) != Z_OK)
+ return (res);
+
+ uuid_unparse(uuid, uuidstr);
+ (void) setenv("_ZONECFG_uuid", uuidstr, 1);
+
+ (void) snprintf(didstr, sizeof (didstr), "%d", zone_did);
+ (void) setenv("_ZONECFG_did", didstr, 1);
+
+ /*
+ * "net" resources are exported because zoneadmd does not handle
+ * automatic configuration of vnics and so that the bhyve boot hook
+ * can generate the argument list for the brand's init program. At such
+ * a time as vnic creation is handled in zoneadmd and brand callbacks
+ * can be executed as part of the zoneadmd process this should be
+ * removed.
+ */
+ net_resources[0] = '\0';
+ if ((res = zonecfg_setnwifent(snap_hndl)) != Z_OK)
+ goto done;
+
+ while (zonecfg_getnwifent(snap_hndl, &ntab) == Z_OK) {
+ struct zone_res_attrtab *rap;
+ char *phys;
+
+ phys = ntab.zone_nwif_physical;
+
+ (void) strlcat(net_resources, phys, sizeof (net_resources));
+ (void) strlcat(net_resources, " ", sizeof (net_resources));
+
+ set_zonecfg_env(RSRC_NET, phys, "physical", phys);
+
+ set_zonecfg_env(RSRC_NET, phys, "address",
+ ntab.zone_nwif_address);
+ set_zonecfg_env(RSRC_NET, phys, "allowed-address",
+ ntab.zone_nwif_allowed_address);
+ set_zonecfg_env(RSRC_NET, phys, "defrouter",
+ ntab.zone_nwif_defrouter);
+ set_zonecfg_env(RSRC_NET, phys, "global-nic",
+ ntab.zone_nwif_gnic);
+ set_zonecfg_env(RSRC_NET, phys, "mac-addr", ntab.zone_nwif_mac);
+ set_zonecfg_env(RSRC_NET, phys, "vlan-id",
+ ntab.zone_nwif_vlan_id);
+
+ for (rap = ntab.zone_nwif_attrp; rap != NULL;
+ rap = rap->zone_res_attr_next)
+ set_zonecfg_env(RSRC_NET, phys, rap->zone_res_attr_name,
+ rap->zone_res_attr_value);
+ nwifent_free_attrs(&ntab);
+ }
+
+ (void) setenv("_ZONECFG_net_resources", net_resources, 1);
+
+ (void) zonecfg_endnwifent(snap_hndl);
+
+ /*
+ * "device" resources are exported because the bhyve boot brand callback
+ * needs them to generate the argument list for the brand's init
+ * program. At such a time as brand callbacks can be executed as part
+ * of the zoneadmd process, this should be removed.
+ *
+ * The bhyve brand only supports disk-like and ppt devices and does not
+ * support regular expressions.
+ */
+ if ((res = zonecfg_setdevent(snap_hndl)) != Z_OK)
+ goto done;
+
+ dev_resources[0] = '\0';
+ while (zonecfg_getdevent(snap_hndl, &dtab) == Z_OK) {
+ char *match = dtab.zone_dev_match;
+ struct zone_res_attrtab *rap;
+ char path[MAXPATHLEN];
+
+ res = resolve_device_match(zlogp, &dtab, path, sizeof (path));
+ if (res != Z_OK)
+ goto done;
+
+ /*
+ * Even if not modified, the match path will be mangled in the
+ * environment variable name, so we always store the value here.
+ */
+ set_zonecfg_env(RSRC_DEV, match, "path", path);
+
+ for (rap = dtab.zone_dev_attrp; rap != NULL;
+ rap = rap->zone_res_attr_next) {
+ set_zonecfg_env(RSRC_DEV, match,
+ rap->zone_res_attr_name, rap->zone_res_attr_value);
+ }
+
+ /*
+ * _ZONECFG_device_resources will contain a space separated list
+ * of devices that have _ZONECFG_device_<device>* environment
+ * variables. So that each element of the list matches up with
+ * <device>, each list item needs to be sanitized in the same
+ * way that environment variable names are sanitized.
+ */
+ sanitize_env_var_name(match);
+ (void) strlcat(dev_resources, match, sizeof (dev_resources));
+ (void) strlcat(dev_resources, " ", sizeof (dev_resources));
+ }
+ (void) zonecfg_enddevent(snap_hndl);
+
+ (void) setenv("_ZONECFG_device_resources", dev_resources, 1);
+
+ /*
+ * "attr" resources are exported because the bhyve brand's boot hook
+ * needs access to the "ram", "cpu", "bootrom", etc. to form the
+ * argument list for the brand's init program. Once the bhyve brand is
+ * configured via proper resources and properties, this should be
+ * removed.
+ */
+ if ((res = zonecfg_setattrent(snap_hndl)) != Z_OK)
+ goto done;
+
+ while (zonecfg_getattrent(snap_hndl, &atab) == Z_OK) {
+ set_zonecfg_env("attr", NULL, atab.zone_attr_name,
+ atab.zone_attr_value);
+ }
+
+ (void) zonecfg_endattrent(snap_hndl);
+
+ if (debug)
+ (void) setenv("_ZONEADMD_brand_debug", "1", 1);
+ else
+ (void) setenv("_ZONEADMD_brand_debug", "", 1);
+
+ res = Z_OK;
+
+done:
+ return (res);
+}
+
+void
+nwifent_free_attrs(struct zone_nwiftab *np)
+{
+ struct zone_res_attrtab *rap;
+
+ for (rap = np->zone_nwif_attrp; rap != NULL; ) {
+ struct zone_res_attrtab *tp = rap;
+
+ rap = rap->zone_res_attr_next;
+ free(tp);
+ }
+}
+
+/*
* If retstr is not NULL, the output of the subproc is returned in the str,
* otherwise it is output using zerror(). Any memory allocated for retstr
* should be freed by the caller.
*/
int
-do_subproc(zlog_t *zlogp, char *cmdbuf, char **retstr)
+do_subproc(zlog_t *zlogp, char *cmdbuf, char **retstr, boolean_t debug)
{
char buf[1024]; /* arbitrary large amount */
char *inbuf;
FILE *file;
int status;
int rd_cnt;
+ int fds[2];
+ pid_t child;
if (retstr != NULL) {
if ((*retstr = malloc(1024)) == NULL) {
@@ -764,31 +1085,104 @@ do_subproc(zlog_t *zlogp, char *cmdbuf, char **retstr)
inbuf = buf;
}
- file = popen(cmdbuf, "r");
- if (file == NULL) {
- zerror(zlogp, B_TRUE, "could not launch: %s", cmdbuf);
+ if (pipe(fds) != 0) {
+ zerror(zlogp, B_TRUE, "failed to create pipe for subprocess");
+ return (-1);
+ }
+
+ if ((child = fork()) == 0) {
+ int in;
+
+ /*
+ * SIGINT is currently ignored. It probably shouldn't be so
+ * hard to kill errant children, so we revert to SIG_DFL.
+ * SIGHUP and SIGUSR1 are used to perform log rotation. We
+ * leave those as-is because we don't want a 'pkill -HUP
+ * zoneadmd' to kill this child process before exec(). On
+ * exec(), SIGHUP and SIGUSR1 will become SIG_DFL.
+ */
+ (void) sigset(SIGINT, SIG_DFL);
+
+ /*
+ * Set up a pipe for the child to log to.
+ */
+ if (dup2(fds[1], STDERR_FILENO) == -1) {
+ (void) snprintf(buf, sizeof (buf),
+ "subprocess failed to dup2(STDERR_FILENO): %s\n",
+ strerror(errno));
+ (void) write(fds[1], buf, strlen(buf));
+ _exit(127);
+ }
+ if (dup2(fds[1], STDOUT_FILENO) == -1) {
+ perror("subprocess failed to dup2(STDOUT_FILENO)");
+ _exit(127);
+ }
+ /*
+ * Some naughty children may try to read from stdin. Be sure
+ * that the first file that a child opens doesn't get stdin's
+ * file descriptor.
+ */
+ if ((in = open("/dev/null", O_RDONLY)) == -1 ||
+ dup2(in, STDIN_FILENO) == -1) {
+ zerror(zlogp, B_TRUE,
+ "subprocess failed to set up STDIN_FILENO");
+ _exit(127);
+ }
+ closefrom(STDERR_FILENO + 1);
+
+ if (setup_subproc_env(zlogp, debug) != Z_OK) {
+ zerror(zlogp, B_FALSE, "failed to setup environment");
+ _exit(127);
+ }
+
+ (void) execl("/bin/sh", "sh", "-c", cmdbuf, NULL);
+
+ zerror(zlogp, B_TRUE, "subprocess execl failed");
+ _exit(127);
+ } else if (child == -1) {
+ zerror(zlogp, B_TRUE, "failed to create subprocess for '%s'",
+ cmdbuf);
+ (void) close(fds[0]);
+ (void) close(fds[1]);
return (-1);
}
+ (void) close(fds[1]);
+
+ file = fdopen(fds[0], "r");
while (fgets(inbuf, 1024, file) != NULL) {
if (retstr == NULL) {
- if (zlogp != &logsys)
+ if (zlogp != &logsys) {
+ int last = strlen(inbuf) - 1;
+
+ if (inbuf[last] == '\n')
+ inbuf[last] = '\0';
zerror(zlogp, B_FALSE, "%s", inbuf);
+ }
} else {
char *p;
rd_cnt += 1024 - 1;
if ((p = realloc(*retstr, rd_cnt + 1024)) == NULL) {
zerror(zlogp, B_FALSE, "out of memory");
- (void) pclose(file);
- return (-1);
+ break;
}
*retstr = p;
inbuf = *retstr + rd_cnt;
}
}
- status = pclose(file);
+
+ while (fclose(file) != 0) {
+ assert(errno == EINTR);
+ }
+ while (waitpid(child, &status, 0) == -1) {
+ if (errno != EINTR) {
+ zerror(zlogp, B_TRUE,
+ "failed to get exit status of '%s'", cmdbuf);
+ return (-1);
+ }
+ }
if (WIFSIGNALED(status)) {
zerror(zlogp, B_FALSE, "%s unexpectedly terminated due to "
@@ -803,24 +1197,91 @@ do_subproc(zlog_t *zlogp, char *cmdbuf, char **retstr)
return (WEXITSTATUS(status));
}
+/*
+ * Get the path for this zone's init(1M) (or equivalent) process. First look
+ * for a zone-specific init-name attr, then get it from the brand.
+ */
+static int
+get_initname(brand_handle_t bh, char *initname, int len)
+{
+ struct zone_attrtab a;
+
+ bzero(&a, sizeof (a));
+ (void) strlcpy(a.zone_attr_name, "init-name",
+ sizeof (a.zone_attr_name));
+
+ if (zonecfg_lookup_attr(snap_hndl, &a) == Z_OK) {
+ (void) strlcpy(initname, a.zone_attr_value, len);
+ return (0);
+ }
+
+ return (brand_get_initname(bh, initname, len));
+}
+
+/*
+ * Get the restart-init flag for this zone's init(1M) (or equivalent) process.
+ * First look for a zone-specific restart-init attr, then get it from the brand.
+ */
+static boolean_t
+restartinit(brand_handle_t bh)
+{
+ struct zone_attrtab a;
+
+ bzero(&a, sizeof (a));
+ (void) strlcpy(a.zone_attr_name, "restart-init",
+ sizeof (a.zone_attr_name));
+
+ if (zonecfg_lookup_attr(snap_hndl, &a) == Z_OK) {
+ if (strcmp(a.zone_attr_value, "false") == 0)
+ return (B_FALSE);
+ return (B_TRUE);
+ }
+
+ return (brand_restartinit(bh));
+}
+
+/*
+ * Get the app-svc-dependent flag for this zone's init process. This is a
+ * zone-specific attr which controls the type of contract we create for the
+ * zone's init. When true, the contract will include CT_PR_EV_EXIT in the fatal
+ * set, so that when any service which is in the same contract exits, the init
+ * application will be terminated.
+ */
+static boolean_t
+is_app_svc_dep(void)
+{
+ struct zone_attrtab a;
+
+ bzero(&a, sizeof (a));
+ (void) strlcpy(a.zone_attr_name, "app-svc-dependent",
+ sizeof (a.zone_attr_name));
+
+ if (zonecfg_lookup_attr(snap_hndl, &a) == Z_OK &&
+ strcmp(a.zone_attr_value, "true") == 0) {
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
static int
-zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate)
+zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate, boolean_t debug)
{
zoneid_t zoneid;
struct stat st;
- char zpath[MAXPATHLEN], initpath[MAXPATHLEN], init_file[MAXPATHLEN];
+ char rpath[MAXPATHLEN], initpath[MAXPATHLEN], init_file[MAXPATHLEN];
char nbootargs[BOOTARGS_MAX];
char cmdbuf[MAXPATHLEN];
fs_callback_t cb;
brand_handle_t bh;
zone_iptype_t iptype;
- boolean_t links_loaded = B_FALSE;
dladm_status_t status;
char errmsg[DLADM_STRSIZE];
int err;
boolean_t restart_init;
+ boolean_t app_svc_dep;
- if (brand_prestatechg(zlogp, zstate, Z_BOOT) != 0)
+ if (brand_prestatechg(zlogp, zstate, Z_BOOT, debug) != 0)
return (-1);
if ((zoneid = getzoneidbyname(zone_name)) == -1) {
@@ -853,13 +1314,8 @@ zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate)
/*
* Get the brand's boot callback if it exists.
*/
- if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
- zerror(zlogp, B_FALSE, "unable to determine zone path");
- brand_close(bh);
- goto bad;
- }
(void) strcpy(cmdbuf, EXEC_PREFIX);
- if (brand_get_boot(bh, zone_name, zpath, cmdbuf + EXEC_LEN,
+ if (brand_get_boot(bh, zone_name, zonepath, cmdbuf + EXEC_LEN,
sizeof (cmdbuf) - EXEC_LEN) != 0) {
zerror(zlogp, B_FALSE,
"unable to determine branded zone's boot callback");
@@ -868,41 +1324,50 @@ zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate)
}
/* Get the path for this zone's init(1M) (or equivalent) process. */
- if (brand_get_initname(bh, init_file, MAXPATHLEN) != 0) {
+ if (get_initname(bh, init_file, MAXPATHLEN) != 0) {
zerror(zlogp, B_FALSE,
"unable to determine zone's init(1M) location");
brand_close(bh);
goto bad;
}
- /* See if this zone's brand should restart init if it dies. */
- restart_init = brand_restartinit(bh);
+ /* See if we should restart init if it dies. */
+ restart_init = restartinit(bh);
+
+ /*
+ * See if we need to setup contract dependencies between the zone's
+ * primary application and any of its services.
+ */
+ app_svc_dep = is_app_svc_dep();
brand_close(bh);
- err = filter_bootargs(zlogp, bootargs, nbootargs, init_file,
- bad_boot_arg);
- if (err == Z_INVAL)
- eventstream_write(Z_EVT_ZONE_BADARGS);
- else if (err != Z_OK)
+ err = filter_bootargs(zlogp, bootargs, nbootargs, init_file);
+ if (err != Z_OK)
goto bad;
assert(init_file[0] != '\0');
- /* Try to anticipate possible problems: Make sure init is executable. */
- if (zone_get_rootpath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
+ /*
+ * Try to anticipate possible problems: If possible, make sure init is
+ * executable.
+ */
+ if (zone_get_rootpath(zone_name, rpath, sizeof (rpath)) != Z_OK) {
zerror(zlogp, B_FALSE, "unable to determine zone root");
goto bad;
}
- (void) snprintf(initpath, sizeof (initpath), "%s%s", zpath, init_file);
+ (void) snprintf(initpath, sizeof (initpath), "%s%s", rpath, init_file);
- if (stat(initpath, &st) == -1) {
+ if (lstat(initpath, &st) == -1) {
zerror(zlogp, B_TRUE, "could not stat %s", initpath);
goto bad;
}
- if ((st.st_mode & S_IXUSR) == 0) {
+ /* LINTED: E_NOP_IF_STMT */
+ if ((st.st_mode & S_IFMT) == S_IFLNK) {
+ /* symlink, we'll have to wait and resolve when we boot */
+ } else if ((st.st_mode & S_IXUSR) == 0) {
zerror(zlogp, B_FALSE, "%s is not executable", initpath);
goto bad;
}
@@ -920,7 +1385,6 @@ zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate)
" %s", dladm_status2str(status, errmsg));
goto bad;
}
- links_loaded = B_TRUE;
}
/*
@@ -929,7 +1393,7 @@ zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate)
* is booted.
*/
if ((strlen(cmdbuf) > EXEC_LEN) &&
- (do_subproc(zlogp, cmdbuf, NULL) != Z_OK)) {
+ (do_subproc(zlogp, cmdbuf, NULL, debug) != Z_OK)) {
zerror(zlogp, B_FALSE, "%s failed", cmdbuf);
goto bad;
}
@@ -950,19 +1414,31 @@ zone_bootup(zlog_t *zlogp, const char *bootargs, int zstate)
goto bad;
}
+ if (app_svc_dep && zone_setattr(zoneid, ZONE_ATTR_APP_SVC_CT,
+ (void *)B_TRUE, sizeof (boolean_t)) == -1) {
+ zerror(zlogp, B_TRUE, "could not set zone app-die");
+ goto bad;
+ }
+
/*
* Inform zonestatd of a new zone so that it can install a door for
* the zone to contact it.
*/
notify_zonestatd(zone_id);
+ /* Startup a thread to perform zfd logging/tty svc for the zone. */
+ create_log_thread(zlogp);
+
if (zone_boot(zoneid) == -1) {
zerror(zlogp, B_TRUE, "unable to boot zone");
+ destroy_log_thread(zlogp);
goto bad;
}
- if (brand_poststatechg(zlogp, zstate, Z_BOOT) != 0)
+ if (brand_poststatechg(zlogp, zstate, Z_BOOT, debug) != 0) {
+ destroy_log_thread(zlogp);
goto bad;
+ }
return (0);
@@ -971,32 +1447,45 @@ bad:
* If something goes wrong, we up the zones's state to the target
* state, RUNNING, and then invoke the hook as if we're halting.
*/
- (void) brand_poststatechg(zlogp, ZONE_STATE_RUNNING, Z_HALT);
- if (links_loaded)
- (void) dladm_zone_halt(dld_handle, zoneid);
+ (void) brand_poststatechg(zlogp, ZONE_STATE_RUNNING, Z_HALT, debug);
+
return (-1);
}
static int
-zone_halt(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting, int zstate)
+zone_halt(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting, int zstate,
+ boolean_t debug)
{
int err;
- if (brand_prestatechg(zlogp, zstate, Z_HALT) != 0)
+ /*
+ * If performing a scratch zone unmount then do not call the
+ * state change hooks.
+ */
+ if (unmount_cmd == B_FALSE &&
+ brand_prestatechg(zlogp, zstate, Z_HALT, debug) != 0)
return (-1);
- if (vplat_teardown(zlogp, unmount_cmd, rebooting) != 0) {
+ if (vplat_teardown(zlogp, unmount_cmd, rebooting, debug) != 0) {
if (!bringup_failure_recovery)
zerror(zlogp, B_FALSE, "unable to destroy zone");
+ destroy_log_thread(zlogp);
return (-1);
}
+ /* Shut down is done, stop the log thread */
+ destroy_log_thread(zlogp);
+
+ if (unmount_cmd == B_FALSE &&
+ brand_poststatechg(zlogp, zstate, Z_HALT, debug) != 0)
+ return (-1);
+
if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
zerror(zlogp, B_FALSE, "destroying snapshot: %s",
zonecfg_strerror(err));
- if (brand_poststatechg(zlogp, zstate, Z_HALT) != 0)
- return (-1);
+ zonecfg_fini_handle(snap_hndl);
+ snap_hndl = NULL;
return (0);
}
@@ -1008,7 +1497,6 @@ zone_graceful_shutdown(zlog_t *zlogp)
pid_t child;
char cmdbuf[MAXPATHLEN];
brand_handle_t bh = NULL;
- char zpath[MAXPATHLEN];
ctid_t ct;
int tmpl_fd;
int child_status;
@@ -1029,18 +1517,12 @@ zone_graceful_shutdown(zlog_t *zlogp)
return (-1);
}
- if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
- zerror(zlogp, B_FALSE, "unable to determine zone path");
- brand_close(bh);
- return (-1);
- }
-
/*
* If there is a brand 'shutdown' callback, execute it now to give the
* brand a chance to cleanup any custom configuration.
*/
(void) strcpy(cmdbuf, EXEC_PREFIX);
- if (brand_get_shutdown(bh, zone_name, zpath, cmdbuf + EXEC_LEN,
+ if (brand_get_shutdown(bh, zone_name, zonepath, cmdbuf + EXEC_LEN,
sizeof (cmdbuf) - EXEC_LEN) != 0 || strlen(cmdbuf) <= EXEC_LEN) {
(void) strcat(cmdbuf, SHUTDOWN_DEFAULT);
}
@@ -1178,6 +1660,36 @@ audit_put_record(zlog_t *zlogp, ucred_t *uc, int return_val,
}
/*
+ * Log the exit time and status of the zone's init process into
+ * {zonepath}/lastexited. If the zone shutdown normally, the exit status will
+ * be -1, otherwise it will be the exit status as described in wait.3c.
+ * If the zone is configured to restart init, then nothing will be logged if
+ * init exits unexpectedly (the kernel will never upcall in this case).
+ */
+static void
+log_init_exit(int status)
+{
+ char p[MAXPATHLEN];
+ char buf[128];
+ struct timeval t;
+ int fd;
+
+ if (snprintf(p, sizeof (p), "%s/lastexited", zonepath) > sizeof (p))
+ return;
+ if (gettimeofday(&t, NULL) != 0)
+ return;
+ if (snprintf(buf, sizeof (buf), "%ld.%ld %d\n", t.tv_sec, t.tv_usec,
+ status) > sizeof (buf))
+ return;
+ if ((fd = open(p, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0)
+ return;
+
+ (void) write(fd, buf, strlen(buf));
+
+ (void) close(fd);
+}
+
+/*
* The main routine for the door server that deals with zone state transitions.
*/
/* ARGSUSED */
@@ -1190,9 +1702,11 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
zone_state_t zstate;
zone_cmd_t cmd;
+ boolean_t debug;
+ int init_status;
zone_cmd_arg_t *zargp;
- boolean_t kernelcall;
+ boolean_t kernelcall = B_TRUE;
int rval = -1;
uint64_t uniqid;
@@ -1213,6 +1727,8 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
* it is time for us to shut down zoneadmd.
*/
if (zargp == DOOR_UNREF_DATA) {
+ logstream_close(platloghdl, B_TRUE);
+
/*
* See comment at end of main() for info on the last rites.
*/
@@ -1242,6 +1758,8 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
goto out;
}
cmd = zargp->cmd;
+ debug = zargp->debug;
+ init_status = zargp->status;
if (door_ucred(&uc) != 0) {
zerror(&logsys, B_TRUE, "door_ucred");
@@ -1322,7 +1840,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
rval = -1;
goto out;
}
- zlogp = &logsys; /* Log errors to syslog */
+ zlogp = &logplat; /* Log errors to platform.log */
}
/*
@@ -1348,23 +1866,25 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
case ZONE_STATE_INSTALLED:
switch (cmd) {
case Z_READY:
- rval = zone_ready(zlogp, Z_MNT_BOOT, zstate);
+ rval = zone_ready(zlogp, Z_MNT_BOOT, zstate, debug);
if (rval == 0)
eventstream_write(Z_EVT_ZONE_READIED);
+ zcons_statechanged();
break;
case Z_BOOT:
case Z_FORCEBOOT:
eventstream_write(Z_EVT_ZONE_BOOTING);
- if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate))
- == 0) {
+ if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate,
+ debug)) == 0) {
rval = zone_bootup(zlogp, zargp->bootbuf,
- zstate);
+ zstate, debug);
}
audit_put_record(zlogp, uc, rval, "boot");
+ zcons_statechanged();
if (rval != 0) {
bringup_failure_recovery = B_TRUE;
(void) zone_halt(zlogp, B_FALSE, B_FALSE,
- zstate);
+ zstate, debug);
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
}
break;
@@ -1416,7 +1936,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
rval = zone_ready(zlogp,
strcmp(zargp->bootbuf, "-U") == 0 ?
- Z_MNT_UPDATE : Z_MNT_SCRATCH, zstate);
+ Z_MNT_UPDATE : Z_MNT_SCRATCH, zstate, debug);
if (rval != 0)
break;
@@ -1478,15 +1998,18 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
rval = 0;
break;
case Z_BOOT:
+ case Z_FORCEBOOT:
(void) strlcpy(boot_args, zargp->bootbuf,
sizeof (boot_args));
eventstream_write(Z_EVT_ZONE_BOOTING);
- rval = zone_bootup(zlogp, zargp->bootbuf, zstate);
+ rval = zone_bootup(zlogp, zargp->bootbuf, zstate,
+ debug);
audit_put_record(zlogp, uc, rval, "boot");
+ zcons_statechanged();
if (rval != 0) {
bringup_failure_recovery = B_TRUE;
(void) zone_halt(zlogp, B_FALSE, B_TRUE,
- zstate);
+ zstate, debug);
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
}
boot_args[0] = '\0';
@@ -1494,15 +2017,17 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
case Z_HALT:
if (kernelcall) /* Invalid; can't happen */
abort();
- if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate))
- != 0)
+ if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate,
+ debug)) != 0)
break;
+ zcons_statechanged();
eventstream_write(Z_EVT_ZONE_HALTED);
break;
case Z_SHUTDOWN:
case Z_REBOOT:
case Z_NOTE_UNINSTALLING:
case Z_MOUNT:
+ case Z_FORCEMOUNT:
case Z_UNMOUNT:
if (kernelcall) /* Invalid; can't happen */
abort();
@@ -1519,7 +2044,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
case Z_UNMOUNT:
if (kernelcall) /* Invalid; can't happen */
abort();
- rval = zone_halt(zlogp, B_TRUE, B_FALSE, zstate);
+ rval = zone_halt(zlogp, B_TRUE, B_FALSE, zstate, debug);
if (rval == 0) {
eventstream_write(Z_EVT_ZONE_HALTED);
(void) sema_post(&scratch_sem);
@@ -1541,15 +2066,18 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
case ZONE_STATE_DOWN:
switch (cmd) {
case Z_READY:
- if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate))
- != 0)
+ if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate,
+ debug)) != 0)
break;
- if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) == 0)
+ zcons_statechanged();
+ if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate,
+ debug)) == 0)
eventstream_write(Z_EVT_ZONE_READIED);
else
eventstream_write(Z_EVT_ZONE_HALTED);
break;
case Z_BOOT:
+ case Z_FORCEBOOT:
/*
* We could have two clients racing to boot this
* zone; the second client loses, but its request
@@ -1560,32 +2088,40 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
rval = 0;
break;
case Z_HALT:
- if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate))
- != 0)
+ if (kernelcall) {
+ log_init_exit(init_status);
+ } else {
+ log_init_exit(-1);
+ }
+ if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate,
+ debug)) != 0)
break;
eventstream_write(Z_EVT_ZONE_HALTED);
+ zcons_statechanged();
break;
case Z_REBOOT:
(void) strlcpy(boot_args, zargp->bootbuf,
sizeof (boot_args));
eventstream_write(Z_EVT_ZONE_REBOOTING);
- if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate))
- != 0) {
+ if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate,
+ debug)) != 0) {
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
boot_args[0] = '\0';
break;
}
- if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate))
- != 0) {
+ zcons_statechanged();
+ if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate,
+ debug)) != 0) {
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
boot_args[0] = '\0';
break;
}
- rval = zone_bootup(zlogp, zargp->bootbuf, zstate);
+ rval = zone_bootup(zlogp, zargp->bootbuf, zstate,
+ debug);
audit_put_record(zlogp, uc, rval, "reboot");
if (rval != 0) {
(void) zone_halt(zlogp, B_FALSE, B_TRUE,
- zstate);
+ zstate, debug);
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
}
boot_args[0] = '\0';
@@ -1597,6 +2133,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
break;
case Z_NOTE_UNINSTALLING:
case Z_MOUNT:
+ case Z_FORCEMOUNT:
case Z_UNMOUNT:
zerror(zlogp, B_FALSE, "%s operation is invalid "
"for zones in state '%s'", z_cmd_name(cmd),
@@ -1765,6 +2302,29 @@ top:
"zoneadmd does not appear to be available; "
"restarted zoneadmd to recover.",
zone_name, zone_state_str(zstate));
+
+ /*
+ * Startup a thread to perform the zfd logging/tty svc
+ * for the zone. zlogp won't be valid for much longer
+ * so use logplat.
+ */
+ if (getzoneidbyname(zone_name) != -1) {
+ create_log_thread(&logplat);
+ }
+
+ /* recover the global configuration snapshot */
+ if (snap_hndl == NULL) {
+ if ((snap_hndl = zonecfg_init_handle())
+ == NULL ||
+ zonecfg_create_snapshot(zone_name)
+ != Z_OK ||
+ zonecfg_get_snapshot_handle(zone_name,
+ snap_hndl) != Z_OK) {
+ zerror(zlogp, B_FALSE, "recovering "
+ "zone configuration handle");
+ goto out;
+ }
+ }
}
(void) fdetach(zone_door_path);
@@ -1778,21 +2338,62 @@ out:
}
/*
- * Setup the brand's pre and post state change callbacks, as well as the
- * query callback, if any of these exist.
+ * Run the query hook with the 'env' parameter. It should return a
+ * string of tab-delimited key-value pairs, each of which should be set
+ * in the environment.
+ *
+ * Because the env_vars string values become part of the environment, the
+ * string is static and we don't free it.
+ *
+ * This function is always called before zoneadmd forks and makes itself
+ * exclusive, so it is possible there could more than one instance of zoneadmd
+ * running in parallel at this point. Thus, we have no zonecfg snapshot and
+ * shouldn't take one yet (i.e. snap_hndl is NULL). Thats ok, since we don't
+ * need any zonecfg info to query for a brand-specific env value.
*/
static int
-brand_callback_init(brand_handle_t bh, char *zone_name)
+set_brand_env(zlog_t *zlogp)
{
- char zpath[MAXPATHLEN];
+ int ret = 0;
+ static char *env_vars = NULL;
+ char buf[2 * MAXPATHLEN];
+
+ if (query_hook[0] == '\0' || env_vars != NULL)
+ return (0);
+
+ if (snprintf(buf, sizeof (buf), "%s env", query_hook) > sizeof (buf))
+ return (-1);
- if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK)
+ if (do_subproc(zlogp, buf, &env_vars, B_FALSE) != 0)
return (-1);
+ if (env_vars != NULL) {
+ char *sp;
+
+ sp = strtok(env_vars, "\t");
+ while (sp != NULL) {
+ if (putenv(sp) != 0) {
+ ret = -1;
+ break;
+ }
+ sp = strtok(NULL, "\t");
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * Setup the brand's pre and post state change callbacks, as well as the
+ * query callback, if any of these exist.
+ */
+static int
+brand_callback_init(brand_handle_t bh, char *zone_name)
+{
(void) strlcpy(pre_statechg_hook, EXEC_PREFIX,
sizeof (pre_statechg_hook));
- if (brand_get_prestatechange(bh, zone_name, zpath,
+ if (brand_get_prestatechange(bh, zone_name, zonepath,
pre_statechg_hook + EXEC_LEN,
sizeof (pre_statechg_hook) - EXEC_LEN) != 0)
return (-1);
@@ -1803,7 +2404,7 @@ brand_callback_init(brand_handle_t bh, char *zone_name)
(void) strlcpy(post_statechg_hook, EXEC_PREFIX,
sizeof (post_statechg_hook));
- if (brand_get_poststatechange(bh, zone_name, zpath,
+ if (brand_get_poststatechange(bh, zone_name, zonepath,
post_statechg_hook + EXEC_LEN,
sizeof (post_statechg_hook) - EXEC_LEN) != 0)
return (-1);
@@ -1814,7 +2415,7 @@ brand_callback_init(brand_handle_t bh, char *zone_name)
(void) strlcpy(query_hook, EXEC_PREFIX,
sizeof (query_hook));
- if (brand_get_query(bh, zone_name, zpath, query_hook + EXEC_LEN,
+ if (brand_get_query(bh, zone_name, zonepath, query_hook + EXEC_LEN,
sizeof (query_hook) - EXEC_LEN) != 0)
return (-1);
@@ -1942,6 +2543,11 @@ main(int argc, char *argv[])
return (1);
}
+ if (zone_get_zonepath(zone_name, zonepath, sizeof (zonepath)) != Z_OK) {
+ zerror(zlogp, B_FALSE, "unable to determine zone path");
+ return (-1);
+ }
+
if (zonecfg_default_brand(default_brand,
sizeof (default_brand)) != Z_OK) {
zerror(zlogp, B_FALSE, "unable to determine default brand");
@@ -2013,6 +2619,11 @@ main(int argc, char *argv[])
}
priv_freeset(privset);
+ if (set_brand_env(zlogp) != 0) {
+ zerror(zlogp, B_FALSE, "Unable to setup brand's environment");
+ return (1);
+ }
+
if (mkzonedir(zlogp) != 0)
return (1);
@@ -2139,6 +2750,15 @@ main(int argc, char *argv[])
openlog("zoneadmd", LOG_PID, LOG_DAEMON);
/*
+ * Allow logging to <zonepath>/logs/<file>.
+ */
+ logstream_init(zlogp);
+ platloghdl = logstream_open("platform.log", "zoneadmd", 0);
+
+ /* logplat looks the same as logsys, but logs to platform.log */
+ logplat = logsys;
+
+ /*
* The eventstream is used to publish state changes in the zone
* from the door threads to the console I/O poller.
*/
@@ -2157,7 +2777,6 @@ main(int argc, char *argv[])
if (make_daemon_exclusive(zlogp) == -1)
goto child_out;
-
/*
* Create/join a new session; we need to be careful of what we do with
* the console from now on so we don't end up being the session leader
@@ -2167,9 +2786,13 @@ main(int argc, char *argv[])
/*
* This thread shouldn't be receiving any signals; in particular,
- * SIGCHLD should be received by the thread doing the fork().
+ * SIGCHLD should be received by the thread doing the fork(). The
+ * exceptions are SIGHUP and SIGUSR1 for log rotation, set up by
+ * logstream_init().
*/
(void) sigfillset(&blockset);
+ (void) sigdelset(&blockset, SIGHUP);
+ (void) sigdelset(&blockset, SIGUSR1);
(void) thr_sigsetmask(SIG_BLOCK, &blockset, NULL);
/*
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.h b/usr/src/cmd/zoneadmd/zoneadmd.h
index d784a303b3..06353cbe61 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.h
+++ b/usr/src/cmd/zoneadmd/zoneadmd.h
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _ZONEADMD_H
@@ -32,6 +33,9 @@ extern "C" {
#endif
#include <libdladm.h>
+#include <libzonecfg.h>
+#include <thread.h>
+#include <synch.h>
/*
* Multi-threaded programs should avoid MT-unsafe library calls (i.e., any-
@@ -69,6 +73,7 @@ extern "C" {
#define DEFAULT_DIR_USER -1 /* user ID for chown: -1 means don't change */
#define DEFAULT_DIR_GROUP -1 /* grp ID for chown: -1 means don't change */
+#define ALT_MOUNT(mount_cmd) ((mount_cmd) != Z_MNT_BOOT)
typedef struct zlog {
FILE *logfile; /* file to log to */
@@ -83,24 +88,27 @@ typedef struct zlog {
char *locale; /* locale to use for gettext() */
} zlog_t;
-extern zlog_t logsys;
+extern zlog_t logsys; /* syslog */
+extern zlog_t logplat; /* platform.log */
extern mutex_t lock;
extern mutex_t msglock;
extern boolean_t in_death_throes;
extern boolean_t bringup_failure_recovery;
extern char *zone_name;
+extern char zonepath[MAXNAMELEN];
+extern zone_dochandle_t snap_hndl;
extern char pool_name[MAXNAMELEN];
extern char brand_name[MAXNAMELEN];
extern char default_brand[MAXNAMELEN];
extern char boot_args[BOOTARGS_MAX];
-extern char bad_boot_arg[BOOTARGS_MAX];
extern boolean_t zone_isnative;
extern boolean_t zone_iscluster;
extern dladm_handle_t dld_handle;
extern void zerror(zlog_t *, boolean_t, const char *, ...);
extern char *localize_msg(char *locale, const char *msg);
+extern void nwifent_free_attrs(struct zone_nwiftab *);
/*
* Eventstream interfaces.
@@ -112,8 +120,7 @@ typedef enum {
Z_EVT_ZONE_HALTED,
Z_EVT_ZONE_READIED,
Z_EVT_ZONE_UNINSTALLING,
- Z_EVT_ZONE_BOOTFAILED,
- Z_EVT_ZONE_BADARGS
+ Z_EVT_ZONE_BOOTFAILED
} zone_evt_t;
extern int eventstream_init();
@@ -135,9 +142,9 @@ typedef enum {
/*
* Virtual platform interfaces.
*/
-extern zoneid_t vplat_create(zlog_t *, zone_mnt_t);
+extern zoneid_t vplat_create(zlog_t *, zone_mnt_t, zoneid_t);
extern int vplat_bringup(zlog_t *, zone_mnt_t, zoneid_t);
-extern int vplat_teardown(zlog_t *, boolean_t, boolean_t);
+extern int vplat_teardown(zlog_t *, boolean_t, boolean_t, boolean_t);
extern int vplat_get_iptype(zlog_t *, zone_iptype_t *);
/*
@@ -154,6 +161,23 @@ extern void resolve_lofs(zlog_t *zlogp, char *path, size_t pathlen);
*/
extern int init_console(zlog_t *);
extern void serve_console(zlog_t *);
+extern void zcons_statechanged();
+
+/*
+ * Logging routines
+ */
+typedef enum {
+ LS_LINE_BUFFERED = 0x1 /* Write when \n found or full buffer */
+} logstream_flags_t;
+
+extern boolean_t logging_poisoned;
+
+extern void create_log_thread(zlog_t *);
+extern void destroy_log_thread(zlog_t *);
+extern void logstream_init(zlog_t *);
+extern int logstream_open(const char *, const char *, logstream_flags_t);
+extern void logstream_write(int, char *, int);
+extern void logstream_close(int, boolean_t);
/*
* Contract handling.
@@ -163,7 +187,13 @@ extern int init_template(void);
/*
* Routine to manage child processes.
*/
-extern int do_subproc(zlog_t *, char *, char **);
+extern int do_subproc(zlog_t *, char *, char **, boolean_t);
+
+/*
+ * Resource handling.
+ */
+extern int resolve_device_match(zlog_t *, struct zone_devtab *,
+ char *, size_t);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/zonecfg/Makefile b/usr/src/cmd/zonecfg/Makefile
index c5d042f48f..c551d7073a 100644
--- a/usr/src/cmd/zonecfg/Makefile
+++ b/usr/src/cmd/zonecfg/Makefile
@@ -29,6 +29,7 @@ PROG= zonecfg
OBJS= zonecfg.o zonecfg_lex.o zonecfg_grammar.tab.o
include ../Makefile.cmd
+include ../Makefile.ctf
# zonecfg has a name clash with main() and libl.so.1. However, zonecfg must
# still export a number of "yy*" (libl) interfaces. Reduce all other symbols
@@ -38,7 +39,8 @@ MAPOPTS = $(MAPFILES:%=-M%)
LFLAGS = -t
YFLAGS = -d -b zonecfg_grammar
-LDLIBS += -lzonecfg -ll -lnsl -ltecla -lzfs -lbrand -ldladm -linetutil
+LDLIBS += -lzonecfg -ll -lnsl -ltecla -lzfs -lbrand -ldladm -linetutil -luuid
+CFLAGS += -DYYLMAX=2048
CPPFLAGS += -I.
LDFLAGS += $(MAPOPTS)
CLEANFILES += zonecfg_lex.c zonecfg_grammar.tab.c zonecfg_grammar.tab.h
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c
index d1aaec81db..20f30e6e0c 100644
--- a/usr/src/cmd/zonecfg/zonecfg.c
+++ b/usr/src/cmd/zonecfg/zonecfg.c
@@ -81,6 +81,7 @@
#include <libinetutil.h>
#include <pwd.h>
#include <inet/ip.h>
+#include <uuid/uuid.h>
#include <libzonecfg.h>
#include "zonecfg.h"
@@ -128,7 +129,7 @@ extern int lex_lineno;
#define SHELP_REMOVE "remove [-F] <resource-type> " \
"[ <property-name>=<property-value> ]*\n" \
"\t(global scope)\n" \
- "remove <property-name> <property-value>\n" \
+ "remove [-F] <property-name> <property-value>\n" \
"\t(resource scope)"
#define SHELP_REVERT "revert [-F]"
#define SHELP_SELECT "select <resource-type> { <property-name>=" \
@@ -189,6 +190,8 @@ char *res_types[] = {
"admin",
"fs-allowed",
ALIAS_MAXPROCS,
+ ALIAS_ZFSPRI,
+ "uuid",
"security-flags",
NULL
};
@@ -237,6 +240,12 @@ char *prop_types[] = {
"fs-allowed",
ALIAS_MAXPROCS,
"allowed-address",
+ ALIAS_ZFSPRI,
+ "mac-addr",
+ "vlan-id",
+ "global-nic",
+ "property",
+ "uuid",
"default",
"lower",
"upper",
@@ -306,6 +315,7 @@ static const char *clear_cmds[] = {
"clear " ALIAS_MAXSEMIDS,
"clear " ALIAS_SHARES,
"clear " ALIAS_MAXPROCS,
+ "clear " ALIAS_ZFSPRI,
NULL
};
@@ -358,6 +368,8 @@ static const char *set_cmds[] = {
"set hostid=",
"set fs-allowed=",
"set " ALIAS_MAXPROCS "=",
+ "set " ALIAS_ZFSPRI "=",
+ "set uuid=",
NULL
};
@@ -391,6 +403,7 @@ static const char *info_cmds[] = {
"info admin",
"info fs-allowed",
"info max-processes",
+ "info uuid",
NULL
};
@@ -416,10 +429,20 @@ static const char *net_res_scope_cmds[] = {
"exit",
"help",
"info",
+ "add property ",
+ "clear allowed-address",
+ "clear defrouter",
+ "clear global-nic",
+ "clear mac-addr",
+ "clear vlan-id",
+ "remove property ",
"set address=",
"set allowed-address=",
- "set physical=",
"set defrouter=",
+ "set global-nic=",
+ "set mac-addr=",
+ "set physical=",
+ "set vlan-id=",
NULL
};
@@ -429,6 +452,7 @@ static const char *device_res_scope_cmds[] = {
"exit",
"help",
"info",
+ "add property ",
"set match=",
NULL
};
@@ -546,12 +570,14 @@ static zone_dochandle_t handle;
/* used all over the place */
static char zone[ZONENAME_MAX];
static char revert_zone[ZONENAME_MAX];
+static char new_uuid[UUID_PRINTABLE_STRING_LENGTH];
/* global brand operations */
static brand_handle_t brand;
/* set in modifying functions, checked in read_input() */
static boolean_t need_to_commit = B_FALSE;
+static boolean_t is_create = B_FALSE;
boolean_t saw_error;
/* set in yacc parser, checked in read_input() */
@@ -600,7 +626,6 @@ static struct zone_rctltab old_rctltab, in_progress_rctltab;
static struct zone_attrtab old_attrtab, in_progress_attrtab;
static struct zone_dstab old_dstab, in_progress_dstab;
static struct zone_psettab old_psettab, in_progress_psettab;
-static struct zone_mcaptab old_mcaptab, in_progress_mcaptab;
static struct zone_admintab old_admintab, in_progress_admintab;
static struct zone_secflagstab old_secflagstab, in_progress_secflagstab;
@@ -1106,11 +1131,20 @@ usage(boolean_t verbose, uint_t flags)
(void) fprintf(fp, gettext("Valid commands:\n"));
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
+ (void) fprintf(fp, "\t%s %s (%s=<value>,%s=<value>)\n",
+ cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+ pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_ALLOWED_ADDRESS),
gettext("<IP-address>"));
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_PHYSICAL), gettext("<interface>"));
+ (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_MAC), gettext("<mac-address>"));
+ (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_GNIC), gettext("<global zone NIC>"));
+ (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_VLANID), gettext("<vlan ID>"));
(void) fprintf(fp, gettext("See ifconfig(1M) for "
"details of the <interface> string.\n"));
(void) fprintf(fp, gettext("%s %s is valid "
@@ -1118,10 +1152,12 @@ usage(boolean_t verbose, uint_t flags)
"must not be set.\n"),
cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
pt_to_str(PT_IPTYPE), gettext("shared"));
- (void) fprintf(fp, gettext("%s %s is valid "
- "if the %s property is set to %s, otherwise it "
- "must not be set.\n"),
- cmd_to_str(CMD_SET), pt_to_str(PT_ALLOWED_ADDRESS),
+ (void) fprintf(fp, gettext("%s (%s, %s, %s, %s) are "
+ "valid if the %s property is set to %s, otherwise "
+ "they must not be set.\n"),
+ cmd_to_str(CMD_SET),
+ pt_to_str(PT_ALLOWED_ADDRESS), pt_to_str(PT_MAC),
+ pt_to_str(PT_VLANID), pt_to_str(PT_GNIC),
pt_to_str(PT_IPTYPE), gettext("exclusive"));
(void) fprintf(fp, gettext("\t%s %s=%s\n%s %s "
"is valid if the %s or %s property is set, "
@@ -1137,6 +1173,9 @@ usage(boolean_t verbose, uint_t flags)
"used to configure a device node.\n"),
rt_to_str(resource_scope));
(void) fprintf(fp, gettext("Valid commands:\n"));
+ (void) fprintf(fp, "\t%s %s (%s=<value>,%s=<value>)\n",
+ cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+ pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_MATCH), gettext("<device-path>"));
break;
@@ -1283,10 +1322,12 @@ usage(boolean_t verbose, uint_t flags)
if (flags & HELP_USAGE) {
(void) fprintf(fp, "%s:\t%s %s\n", gettext("usage"),
execname, cmd_to_str(CMD_HELP));
- (void) fprintf(fp, "\t%s -z <zone>\t\t\t(%s)\n",
+ (void) fprintf(fp, "\t%s {-z <zone>|-u <uuid>}\t\t\t(%s)\n",
execname, gettext("interactive"));
- (void) fprintf(fp, "\t%s -z <zone> <command>\n", execname);
- (void) fprintf(fp, "\t%s -z <zone> -f <command-file>\n",
+ (void) fprintf(fp, "\t%s {-z <zone>|-u <uuid>} <command>\n",
+ execname);
+ (void) fprintf(fp,
+ "\t%s {-z <zone>|-u <uuid>} -f <command-file>\n",
execname);
}
if (flags & HELP_SUBCMDS) {
@@ -1375,15 +1416,22 @@ usage(boolean_t verbose, uint_t flags)
pt_to_str(PT_MAXSEMIDS));
(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
pt_to_str(PT_SHARES));
+ (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+ pt_to_str(PT_UUID));
+ (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+ pt_to_str(PT_ZFSPRI));
(void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
rt_to_str(RT_FS), pt_to_str(PT_DIR),
pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
- (void) fprintf(fp, "\t%s\t\t%s, %s, %s|%s\n", rt_to_str(RT_NET),
+ (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s, %s, %s %s\n",
+ rt_to_str(RT_NET),
pt_to_str(PT_ADDRESS), pt_to_str(PT_ALLOWED_ADDRESS),
- pt_to_str(PT_PHYSICAL), pt_to_str(PT_DEFROUTER));
- (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
- pt_to_str(PT_MATCH));
+ pt_to_str(PT_GNIC), pt_to_str(PT_MAC),
+ pt_to_str(PT_PHYSICAL), pt_to_str(PT_NPROP),
+ pt_to_str(PT_VLANID), pt_to_str(PT_DEFROUTER));
+ (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_DEVICE),
+ pt_to_str(PT_MATCH), pt_to_str(PT_NPROP));
(void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
(void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
@@ -1441,6 +1489,9 @@ initialize(boolean_t handle_expected)
if (zonecfg_check_handle(handle) != Z_OK) {
if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
got_handle = B_TRUE;
+
+ (void) zonecfg_fix_obsolete(handle);
+
if (zonecfg_get_brand(handle, brandname,
sizeof (brandname)) != Z_OK) {
zerr("Zone %s is inconsistent: missing "
@@ -1708,6 +1759,7 @@ create_func(cmd_t *cmd)
boolean_t force = B_FALSE;
boolean_t attach = B_FALSE;
boolean_t arg_err = B_FALSE;
+ uuid_t uuid;
assert(cmd != NULL);
@@ -1715,7 +1767,7 @@ create_func(cmd_t *cmd)
(void) strlcpy(zone_template, "SUNWdefault", sizeof (zone_template));
optind = 0;
- while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:"))
+ while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?a:bFt:X"))
!= EOF) {
switch (arg) {
case '?':
@@ -1741,6 +1793,17 @@ create_func(cmd_t *cmd)
(void) strlcpy(zone_template, optarg,
sizeof (zone_template));
break;
+ case 'X':
+ (void) snprintf(zone_template, sizeof (zone_template),
+ "%s/%s.xml", ZONE_CONFIG_ROOT, zone);
+ err = zonecfg_get_xml_handle(zone_template, handle);
+ if (err != Z_OK) {
+ zone_perror(execname, err, B_TRUE);
+ exit(Z_ERR);
+ }
+ got_handle = B_TRUE;
+ need_to_commit = B_TRUE;
+ return;
default:
short_usage(CMD_CREATE);
arg_err = B_TRUE;
@@ -1794,9 +1857,14 @@ create_func(cmd_t *cmd)
}
need_to_commit = B_TRUE;
+ is_create = B_TRUE;
zonecfg_fini_handle(handle);
handle = tmphandle;
got_handle = B_TRUE;
+
+ /* Allocate a new uuid for this new zone */
+ uuid_generate(uuid);
+ uuid_unparse(uuid, new_uuid);
}
/*
@@ -1845,8 +1913,8 @@ export_func(cmd_t *cmd)
struct zone_rctltab rctltab;
struct zone_dstab dstab;
struct zone_psettab psettab;
- struct zone_mcaptab mcaptab;
struct zone_rctlvaltab *valptr;
+ struct zone_res_attrtab *rap;
struct zone_admintab admintab;
struct zone_secflagstab secflagstab;
int err, arg;
@@ -1860,6 +1928,7 @@ export_func(cmd_t *cmd)
FILE *of;
boolean_t autoboot;
zone_iptype_t iptype;
+ uuid_t uuid;
boolean_t need_to_close = B_FALSE;
boolean_t arg_err = B_FALSE;
@@ -1970,6 +2039,14 @@ export_func(cmd_t *cmd)
pt_to_str(PT_FS_ALLOWED), fsallowedp);
}
+ if (zonecfg_get_uuid(zone, uuid) == Z_OK && !uuid_is_null(uuid)) {
+ char suuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ uuid_unparse(uuid, suuid);
+ (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_UUID), suuid);
+ }
+
if ((err = zonecfg_setfsent(handle)) != Z_OK) {
zone_perror(zone, err, B_FALSE);
goto done;
@@ -2017,7 +2094,17 @@ export_func(cmd_t *cmd)
export_prop(of, PT_ALLOWED_ADDRESS,
nwiftab.zone_nwif_allowed_address);
export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
+ export_prop(of, PT_MAC, nwiftab.zone_nwif_mac);
+ export_prop(of, PT_VLANID, nwiftab.zone_nwif_vlan_id);
+ export_prop(of, PT_GNIC, nwiftab.zone_nwif_gnic);
export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
+ for (rap = nwiftab.zone_nwif_attrp; rap != NULL;
+ rap = rap->zone_res_attr_next) {
+ fprintf(of, "%s %s (%s=%s,%s=\"%s\")\n",
+ cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+ pt_to_str(PT_NAME), rap->zone_res_attr_name,
+ pt_to_str(PT_VALUE), rap->zone_res_attr_value);
+ }
(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
}
(void) zonecfg_endnwifent(handle);
@@ -2030,21 +2117,17 @@ export_func(cmd_t *cmd)
(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
rt_to_str(RT_DEVICE));
export_prop(of, PT_MATCH, devtab.zone_dev_match);
+ for (rap = devtab.zone_dev_attrp; rap != NULL;
+ rap = rap->zone_res_attr_next) {
+ fprintf(of, "%s %s (%s=%s,%s=\"%s\")\n",
+ cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+ pt_to_str(PT_NAME), rap->zone_res_attr_name,
+ pt_to_str(PT_VALUE), rap->zone_res_attr_value);
+ }
(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
}
(void) zonecfg_enddevent(handle);
- if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
- char buf[128];
-
- (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
- rt_to_str(RT_MCAP));
- bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
- (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
- pt_to_str(PT_PHYSICAL), buf);
- (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
- }
-
if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
zone_perror(zone, err, B_FALSE);
goto done;
@@ -2208,7 +2291,6 @@ add_resource(cmd_t *cmd)
{
int type;
struct zone_psettab tmp_psettab;
- struct zone_mcaptab tmp_mcaptab;
struct zone_secflagstab tmp_secflagstab;
uint64_t tmp;
uint64_t tmp_mcap;
@@ -2301,9 +2383,10 @@ add_resource(cmd_t *cmd)
* Make sure there isn't already a mem-cap entry or max-swap
* or max-locked rctl.
*/
- if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
- zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
- == Z_OK ||
+ if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
+ &tmp_mcap) == Z_OK ||
+ zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM,
+ &tmp_mcap) == Z_OK ||
zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
&tmp_mcap) == Z_OK) {
zerr(gettext("The %s resource or a related resource "
@@ -2316,7 +2399,6 @@ add_resource(cmd_t *cmd)
"to even the root user; "
"this could render the system impossible\n"
"to administer. Please use caution."));
- bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
return;
case RT_ADMIN:
bzero(&in_progress_admintab, sizeof (in_progress_admintab));
@@ -2427,6 +2509,79 @@ bad:
zonecfg_free_rctl_value_list(rctlvaltab);
}
+/*
+ * Resource attribute ("property" resource embedded on net or dev resource)
+ */
+static void
+do_res_attr(struct zone_res_attrtab **headp, complex_property_ptr_t cpp)
+{
+ complex_property_ptr_t cp;
+ struct zone_res_attrtab *np;
+ int err;
+ boolean_t seen_name = B_FALSE, seen_value = B_FALSE;
+
+ if ((np = calloc(1, sizeof (struct zone_res_attrtab))) == NULL) {
+ zone_perror(zone, Z_NOMEM, B_TRUE);
+ exit(Z_ERR);
+ }
+
+ for (cp = cpp; cp != NULL; cp = cp->cp_next) {
+ switch (cp->cp_type) {
+ case PT_NAME:
+ if (seen_name) {
+ zerr(gettext("%s already specified"),
+ pt_to_str(PT_NAME));
+ goto bad;
+ }
+ if (strlcpy(np->zone_res_attr_name, cp->cp_value,
+ sizeof (np->zone_res_attr_name)) >=
+ sizeof (np->zone_res_attr_name)) {
+ zerr(gettext("Input for %s is too long"),
+ pt_to_str(PT_NAME));
+ goto bad;
+ }
+ seen_name = B_TRUE;
+ break;
+ case PT_VALUE:
+ if (seen_value) {
+ zerr(gettext("%s already specified"),
+ pt_to_str(PT_VALUE));
+ goto bad;
+ }
+ if (strlcpy(np->zone_res_attr_value, cp->cp_value,
+ sizeof (np->zone_res_attr_value)) >=
+ sizeof (np->zone_res_attr_value)) {
+ zerr(gettext("Input for %s is too long"),
+ pt_to_str(PT_VALUE));
+ goto bad;
+ }
+
+ seen_value = B_TRUE;
+ break;
+ default:
+ zone_perror(pt_to_str(PT_NPROP), Z_NO_PROPERTY_TYPE,
+ B_TRUE);
+ long_usage(CMD_ADD, B_TRUE);
+ usage(B_FALSE, HELP_PROPS);
+ zonecfg_free_res_attr_list(np);
+ return;
+ }
+ }
+
+ if (!seen_name)
+ zerr(gettext("%s not specified"), pt_to_str(PT_NAME));
+ if (!seen_value)
+ zerr(gettext("%s not specified"), pt_to_str(PT_VALUE));
+
+ err = zonecfg_add_res_attr(headp, np);
+ if (err != Z_OK)
+ zone_perror(pt_to_str(PT_NPROP), err, B_TRUE);
+ return;
+
+bad:
+ zonecfg_free_res_attr_list(np);
+}
+
static void
add_property(cmd_t *cmd)
{
@@ -2494,6 +2649,44 @@ add_property(cmd_t *cmd)
}
}
return;
+ case RT_NET:
+ if (prop_type != PT_NPROP) {
+ zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+ B_TRUE);
+ long_usage(CMD_ADD, B_TRUE);
+ usage(B_FALSE, HELP_PROPS);
+ return;
+ }
+ pp = cmd->cmd_property_ptr[0];
+ if (pp->pv_type != PROP_VAL_COMPLEX) {
+ zerr(gettext("A %s value was expected here."),
+ pvt_to_str(PROP_VAL_COMPLEX));
+ saw_error = B_TRUE;
+ return;
+ }
+
+ do_res_attr(&(in_progress_nwiftab.zone_nwif_attrp),
+ pp->pv_complex);
+ return;
+ case RT_DEVICE:
+ if (prop_type != PT_NPROP) {
+ zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+ B_TRUE);
+ long_usage(CMD_ADD, B_TRUE);
+ usage(B_FALSE, HELP_PROPS);
+ return;
+ }
+ pp = cmd->cmd_property_ptr[0];
+ if (pp->pv_type != PROP_VAL_COMPLEX) {
+ zerr(gettext("A %s value was expected here."),
+ pvt_to_str(PROP_VAL_COMPLEX));
+ saw_error = B_TRUE;
+ return;
+ }
+
+ do_res_attr(&(in_progress_devtab.zone_dev_attrp),
+ pp->pv_complex);
+ return;
case RT_RCTL:
if (prop_type != PT_VALUE) {
zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
@@ -2538,7 +2731,7 @@ static boolean_t
gz_invalid_rt_property(int type)
{
return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
- type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
+ type == RT_AUTOBOOT || type == RT_LIMITPRIV || type == RT_UUID ||
type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
}
@@ -2547,7 +2740,7 @@ static boolean_t
gz_invalid_property(int type)
{
return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
- type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
+ type == PT_AUTOBOOT || type == PT_LIMITPRIV || type == PT_UUID ||
type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
}
@@ -2598,8 +2791,9 @@ add_func(cmd_t *cmd)
resource_scope = cmd->cmd_res_type;
end_op = CMD_ADD;
add_resource(cmd);
- } else
+ } else {
add_property(cmd);
+ }
}
/*
@@ -2764,6 +2958,32 @@ fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
return (zonecfg_lookup_filesystem(handle, fstab));
}
+/*
+ * Turn an addr that looks like f:2:0:44:5:6C into 0f:02:00:44:05:6c
+ * We're expecting a dst of at least MAXMACADDRLEN size here.
+ */
+static void
+normalize_mac_addr(char *dst, const char *src, int len)
+{
+ char *p, *e, *sep = "";
+ long n;
+ char buf[MAXMACADDRLEN], tmp[4];
+
+ *dst = '\0';
+ (void) strlcpy(buf, src, sizeof (buf));
+ p = strtok(buf, ":");
+ while (p != NULL) {
+ n = strtol(p, &e, 16);
+ if (*e != '\0' || n > 0xff)
+ return;
+ (void) snprintf(tmp, sizeof (tmp), "%s%02x", sep, n);
+ (void) strlcat(dst, tmp, len);
+
+ sep = ":";
+ p = strtok(NULL, ":");
+ }
+}
+
static int
fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
boolean_t fill_in_only)
@@ -2797,6 +3017,21 @@ fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
pp->pv_simple,
sizeof (nwiftab->zone_nwif_physical));
break;
+ case PT_MAC:
+ normalize_mac_addr(nwiftab->zone_nwif_mac,
+ pp->pv_simple,
+ sizeof (nwiftab->zone_nwif_mac));
+ break;
+ case PT_VLANID:
+ (void) strlcpy(nwiftab->zone_nwif_vlan_id,
+ pp->pv_simple,
+ sizeof (nwiftab->zone_nwif_vlan_id));
+ break;
+ case PT_GNIC:
+ (void) strlcpy(nwiftab->zone_nwif_gnic,
+ pp->pv_simple,
+ sizeof (nwiftab->zone_nwif_gnic));
+ break;
case PT_DEFROUTER:
(void) strlcpy(nwiftab->zone_nwif_defrouter,
pp->pv_simple,
@@ -3095,6 +3330,8 @@ prompt_remove_resource(cmd_t *cmd, char *rsrc)
num = zonecfg_num_resources(handle, rsrc);
if (num == 0) {
+ if (force)
+ return (B_TRUE);
z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
B_TRUE);
return (B_FALSE);
@@ -3123,7 +3360,7 @@ prompt_remove_resource(cmd_t *cmd, char *rsrc)
}
static void
-remove_fs(cmd_t *cmd)
+remove_fs(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3132,13 +3369,16 @@ remove_fs(cmd_t *cmd)
struct zone_fstab fstab;
if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
return;
}
- if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
zonecfg_free_fs_option_list(fstab.zone_fs_options);
return;
}
@@ -3157,7 +3397,7 @@ remove_fs(cmd_t *cmd)
}
static void
-remove_net(cmd_t *cmd)
+remove_net(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3166,13 +3406,18 @@ remove_net(cmd_t *cmd)
struct zone_nwiftab nwiftab;
if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_NET, err,
+ B_TRUE);
return;
}
- if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_NET, err,
+ B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
return;
}
@@ -3190,7 +3435,7 @@ remove_net(cmd_t *cmd)
}
static void
-remove_device(cmd_t *cmd)
+remove_device(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3199,13 +3444,18 @@ remove_device(cmd_t *cmd)
struct zone_devtab devtab;
if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err,
+ B_TRUE);
return;
}
- if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err,
+ B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
return;
}
@@ -3223,7 +3473,7 @@ remove_device(cmd_t *cmd)
}
static void
-remove_attr(cmd_t *cmd)
+remove_attr(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3232,13 +3482,18 @@ remove_attr(cmd_t *cmd)
struct zone_attrtab attrtab;
if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err,
+ B_TRUE);
return;
}
- if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err,
+ B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
return;
}
@@ -3256,7 +3511,7 @@ remove_attr(cmd_t *cmd)
}
static void
-remove_dataset(cmd_t *cmd)
+remove_dataset(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3265,13 +3520,18 @@ remove_dataset(cmd_t *cmd)
struct zone_dstab dstab;
if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err,
+ B_TRUE);
return;
}
- if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err,
+ B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
return;
}
@@ -3289,7 +3549,7 @@ remove_dataset(cmd_t *cmd)
}
static void
-remove_rctl(cmd_t *cmd)
+remove_rctl(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3298,13 +3558,18 @@ remove_rctl(cmd_t *cmd)
struct zone_rctltab rctltab;
if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err,
+ B_TRUE);
return;
}
- if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err,
+ B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
return;
}
@@ -3323,72 +3588,90 @@ remove_rctl(cmd_t *cmd)
}
static void
-remove_pset()
+remove_pset(boolean_t force)
{
int err;
struct zone_psettab psettab;
if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
return;
}
- if ((err = zonecfg_delete_pset(handle)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
- else
+ if ((err = zonecfg_delete_pset(handle)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
}
static void
-remove_pcap()
+remove_pcap(boolean_t force)
{
int err;
uint64_t tmp;
if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
- zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
- zonecfg_strerror(Z_NO_RESOURCE_TYPE));
- saw_error = B_TRUE;
+ if (!force) {
+ zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
+ rt_to_str(RT_PCAP),
+ zonecfg_strerror(Z_NO_RESOURCE_TYPE));
+ saw_error = B_TRUE;
+ }
return;
}
- if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
- else
+ if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
}
static void
-remove_mcap()
+remove_mcap(boolean_t force)
{
int err, res1, res2, res3;
uint64_t tmp;
- struct zone_mcaptab mcaptab;
boolean_t revert = B_FALSE;
- res1 = zonecfg_lookup_mcap(handle, &mcaptab);
+ res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &tmp);
res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
/* if none of these exist, there is no resource to remove */
if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
- zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
- zonecfg_strerror(Z_NO_RESOURCE_TYPE));
- saw_error = B_TRUE;
+ if (!force) {
+ zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
+ rt_to_str(RT_MCAP),
+ zonecfg_strerror(Z_NO_RESOURCE_TYPE));
+ saw_error = B_TRUE;
+ }
return;
}
if (res1 == Z_OK) {
- if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
- revert = B_TRUE;
+ if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXPHYSMEM))
+ != Z_OK) {
+ if (!force) {
+ z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err,
+ B_TRUE);
+ revert = B_TRUE;
+ }
} else {
need_to_commit = B_TRUE;
}
}
+
if (res2 == Z_OK) {
if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
!= Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
- revert = B_TRUE;
+ if (!force) {
+ z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err,
+ B_TRUE);
+ revert = B_TRUE;
+ }
} else {
need_to_commit = B_TRUE;
}
@@ -3396,8 +3679,11 @@ remove_mcap()
if (res3 == Z_OK) {
if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
!= Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
- revert = B_TRUE;
+ if (!force) {
+ z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err,
+ B_TRUE);
+ revert = B_TRUE;
+ }
} else {
need_to_commit = B_TRUE;
}
@@ -3408,7 +3694,7 @@ remove_mcap()
}
static void
-remove_admin(cmd_t *cmd)
+remove_admin(cmd_t *cmd, boolean_t force)
{
int err;
@@ -3417,34 +3703,33 @@ remove_admin(cmd_t *cmd)
struct zone_admintab admintab;
if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
- z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
- err, B_TRUE);
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, err,
+ B_TRUE);
return;
}
if ((err = zonecfg_delete_admin(handle, &admintab,
- zone))
- != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
- err, B_TRUE);
- else
+ zone)) != Z_OK) {
+ if (!force)
+ z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, err,
+ B_TRUE);
+ } else {
need_to_commit = B_TRUE;
+ }
return;
- } else {
- /*
- * unqualified admin removal.
- * remove all admins but prompt if more
- * than one.
- */
- if (!prompt_remove_resource(cmd, "admin"))
- return;
-
- if ((err = zonecfg_delete_admins(handle, zone))
- != Z_OK)
- z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
- err, B_TRUE);
- else
- need_to_commit = B_TRUE;
}
+
+ /*
+ * unqualified admin removal.
+ * remove all admins but prompt if more than one.
+ */
+ if (!prompt_remove_resource(cmd, "admin"))
+ return;
+
+ if ((err = zonecfg_delete_admins(handle, zone)) != Z_OK)
+ z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN, err, B_TRUE);
+ else
+ need_to_commit = B_TRUE;
}
static void
@@ -3474,6 +3759,7 @@ remove_resource(cmd_t *cmd)
int type;
int arg;
boolean_t arg_err = B_FALSE;
+ boolean_t force = B_FALSE;
if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
long_usage(CMD_REMOVE, B_TRUE);
@@ -3488,6 +3774,7 @@ remove_resource(cmd_t *cmd)
arg_err = B_TRUE;
break;
case 'F':
+ force = B_TRUE;
break;
default:
short_usage(CMD_REMOVE);
@@ -3503,34 +3790,34 @@ remove_resource(cmd_t *cmd)
switch (type) {
case RT_FS:
- remove_fs(cmd);
+ remove_fs(cmd, force);
return;
case RT_NET:
- remove_net(cmd);
+ remove_net(cmd, force);
return;
case RT_DEVICE:
- remove_device(cmd);
+ remove_device(cmd, force);
return;
case RT_RCTL:
- remove_rctl(cmd);
+ remove_rctl(cmd, force);
return;
case RT_ATTR:
- remove_attr(cmd);
+ remove_attr(cmd, force);
return;
case RT_DATASET:
- remove_dataset(cmd);
+ remove_dataset(cmd, force);
return;
case RT_DCPU:
- remove_pset();
+ remove_pset(force);
return;
case RT_PCAP:
- remove_pcap();
+ remove_pcap(force);
return;
case RT_MCAP:
- remove_mcap();
+ remove_mcap(force);
return;
case RT_ADMIN:
- remove_admin(cmd);
+ remove_admin(cmd, force);
return;
case RT_SECFLAGS:
remove_secflags();
@@ -3550,7 +3837,27 @@ remove_property(cmd_t *cmd)
int err, res_type, prop_type;
property_value_ptr_t pp;
struct zone_rctlvaltab *rctlvaltab;
+ struct zone_res_attrtab *np;
complex_property_ptr_t cx;
+ int arg;
+ boolean_t force = B_FALSE;
+ boolean_t arg_err = B_FALSE;
+
+ optind = 0;
+ while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
+ switch (arg) {
+ case 'F':
+ force = B_TRUE;
+ break;
+ default:
+ arg_err = B_TRUE;
+ break;
+ }
+ }
+ if (arg_err) {
+ saw_error = B_TRUE;
+ return;
+ }
res_type = resource_scope;
prop_type = cmd->cmd_prop_name[0];
@@ -3592,7 +3899,7 @@ remove_property(cmd_t *cmd)
prop_id = pp->pv_simple;
err = zonecfg_remove_fs_option(&in_progress_fstab,
prop_id);
- if (err != Z_OK)
+ if (err != Z_OK && !force)
zone_perror(pt_to_str(prop_type), err, B_TRUE);
} else {
list_property_ptr_t list;
@@ -3604,12 +3911,62 @@ remove_property(cmd_t *cmd)
break;
err = zonecfg_remove_fs_option(
&in_progress_fstab, prop_id);
- if (err != Z_OK)
+ if (err != Z_OK && !force)
zone_perror(pt_to_str(prop_type), err,
B_TRUE);
}
}
return;
+ case RT_NET: /* FALLTHRU */
+ case RT_DEVICE:
+ if (prop_type != PT_NPROP) {
+ zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+ B_TRUE);
+ long_usage(CMD_REMOVE, B_TRUE);
+ usage(B_FALSE, HELP_PROPS);
+ return;
+ }
+ pp = cmd->cmd_property_ptr[0];
+ if (pp->pv_type != PROP_VAL_COMPLEX) {
+ zerr(gettext("A %s value was expected here."),
+ pvt_to_str(PROP_VAL_COMPLEX));
+ saw_error = B_TRUE;
+ return;
+ }
+
+ np = alloca(sizeof (struct zone_res_attrtab));
+ for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
+ switch (cx->cp_type) {
+ case PT_NAME:
+ (void) strlcpy(np->zone_res_attr_name,
+ cx->cp_value,
+ sizeof (np->zone_res_attr_name));
+ break;
+ case PT_VALUE:
+ (void) strlcpy(np->zone_res_attr_value,
+ cx->cp_value,
+ sizeof (np->zone_res_attr_value));
+ break;
+ default:
+ zone_perror(pt_to_str(prop_type),
+ Z_NO_PROPERTY_TYPE, B_TRUE);
+ long_usage(CMD_REMOVE, B_TRUE);
+ usage(B_FALSE, HELP_PROPS);
+ return;
+ }
+ }
+ np->zone_res_attr_next = NULL;
+
+ if (res_type == RT_NET) {
+ err = zonecfg_remove_res_attr(
+ &(in_progress_nwiftab.zone_nwif_attrp), np);
+ } else { /* RT_DEVICE */
+ err = zonecfg_remove_res_attr(
+ &(in_progress_devtab.zone_dev_attrp), np);
+ }
+ if (err != Z_OK && !force)
+ zone_perror(pt_to_str(prop_type), err, B_TRUE);
+ return;
case RT_RCTL:
if (prop_type != PT_VALUE) {
zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
@@ -3658,22 +4015,10 @@ remove_property(cmd_t *cmd)
rctlvaltab->zone_rctlval_next = NULL;
err = zonecfg_remove_rctl_value(&in_progress_rctltab,
rctlvaltab);
- if (err != Z_OK)
+ if (err != Z_OK && !force)
zone_perror(pt_to_str(prop_type), err, B_TRUE);
zonecfg_free_rctl_value_list(rctlvaltab);
return;
- case RT_NET:
- if (prop_type != PT_DEFROUTER) {
- zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
- B_TRUE);
- long_usage(CMD_REMOVE, B_TRUE);
- usage(B_FALSE, HELP_PROPS);
- return;
- } else {
- bzero(&in_progress_nwiftab.zone_nwif_defrouter,
- sizeof (in_progress_nwiftab.zone_nwif_defrouter));
- return;
- }
default:
zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
long_usage(CMD_REMOVE, B_TRUE);
@@ -3736,8 +4081,7 @@ clear_property(cmd_t *cmd)
case RT_MCAP:
switch (prop_type) {
case PT_PHYSICAL:
- in_progress_mcaptab.zone_physmem_cap[0] = '\0';
- need_to_commit = B_TRUE;
+ remove_aliased_rctl(PT_PHYSICAL, ALIAS_MAXPHYSMEM);
return;
case PT_SWAP:
remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
@@ -3747,6 +4091,30 @@ clear_property(cmd_t *cmd)
return;
}
break;
+ case RT_NET:
+ switch (prop_type) {
+ case PT_ALLOWED_ADDRESS:
+ in_progress_nwiftab.zone_nwif_allowed_address[0] = '\0';
+ need_to_commit = B_TRUE;
+ return;
+ case PT_DEFROUTER:
+ in_progress_nwiftab.zone_nwif_defrouter[0] = '\0';
+ need_to_commit = B_TRUE;
+ return;
+ case PT_GNIC:
+ in_progress_nwiftab.zone_nwif_gnic[0] = '\0';
+ need_to_commit = B_TRUE;
+ return;
+ case PT_MAC:
+ in_progress_nwiftab.zone_nwif_mac[0] = '\0';
+ need_to_commit = B_TRUE;
+ return;
+ case PT_VLANID:
+ in_progress_nwiftab.zone_nwif_vlan_id[0] = '\0';
+ need_to_commit = B_TRUE;
+ return;
+ }
+ break;
case RT_SECFLAGS:
switch (prop_type) {
case PT_LOWER:
@@ -3788,6 +4156,8 @@ clear_global(cmd_t *cmd)
/* FALLTHRU */
case PT_ZONEPATH:
/* FALLTHRU */
+ case PT_UUID:
+ /* FALLTHRU */
case PT_BRAND:
zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
return;
@@ -3850,6 +4220,9 @@ clear_global(cmd_t *cmd)
case PT_SHARES:
remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
return;
+ case PT_ZFSPRI:
+ remove_aliased_rctl(PT_ZFSPRI, ALIAS_ZFSPRI);
+ return;
case PT_HOSTID:
if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
@@ -3895,7 +4268,7 @@ clear_func(cmd_t *cmd)
void
select_func(cmd_t *cmd)
{
- int type, err, res;
+ int type, err;
uint64_t limit;
uint64_t tmp;
@@ -3990,7 +4363,8 @@ select_func(cmd_t *cmd)
return;
case RT_MCAP:
/* if none of these exist, there is no resource to select */
- if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
+ if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &limit)
+ != Z_OK &&
zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
!= Z_OK &&
zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
@@ -3999,12 +4373,6 @@ select_func(cmd_t *cmd)
B_TRUE);
global_scope = B_TRUE;
}
- if (res == Z_OK)
- bcopy(&old_mcaptab, &in_progress_mcaptab,
- sizeof (struct zone_mcaptab));
- else
- bzero(&in_progress_mcaptab,
- sizeof (in_progress_mcaptab));
return;
case RT_ADMIN:
if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
@@ -4281,9 +4649,8 @@ set_func(cmd_t *cmd)
boolean_t autoboot;
zone_iptype_t iptype;
boolean_t force_set = B_FALSE;
- size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
uint64_t mem_cap, mem_limit;
- float cap;
+ double cap;
char *unitp;
struct zone_psettab tmp_psettab;
boolean_t arg_err = B_FALSE;
@@ -4356,6 +4723,10 @@ set_func(cmd_t *cmd)
res_type = RT_HOSTID;
} else if (prop_type == PT_FS_ALLOWED) {
res_type = RT_FS_ALLOWED;
+ } else if (prop_type == PT_ZFSPRI) {
+ res_type = RT_ZFSPRI;
+ } else if (prop_type == PT_UUID) {
+ res_type = RT_UUID;
} else {
zerr(gettext("Cannot set a resource-specific property "
"from the global scope."));
@@ -4385,10 +4756,12 @@ set_func(cmd_t *cmd)
* A nasty expression but not that complicated:
* 1. fs options are simple or list (tested below)
* 2. rctl value's are complex or list (tested below)
+ * 3. net attr's are complex (tested below)
* Anything else should be simple.
*/
if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
!(res_type == RT_RCTL && prop_type == PT_VALUE) &&
+ !(res_type == RT_NET && prop_type == PT_NPROP) &&
(pp->pv_type != PROP_VAL_SIMPLE ||
(prop_id = pp->pv_simple) == NULL)) {
zerr(gettext("A %s value was expected here."),
@@ -4561,6 +4934,9 @@ set_func(cmd_t *cmd)
case RT_SHARES:
set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
return;
+ case RT_ZFSPRI:
+ set_aliased_rctl(ALIAS_ZFSPRI, prop_type, prop_id);
+ return;
case RT_HOSTID:
if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
if (err == Z_TOO_BIG) {
@@ -4574,6 +4950,15 @@ set_func(cmd_t *cmd)
}
need_to_commit = B_TRUE;
return;
+ case RT_UUID:
+ /*
+ * We can't set here. We have to wait until commit since the
+ * uuid will be updating the index file and we may not have
+ * created the zone yet.
+ */
+ (void) strlcpy(new_uuid, prop_id, sizeof (new_uuid));
+ need_to_commit = B_TRUE;
+ return;
case RT_FS_ALLOWED:
if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
zone_perror(zone, err, B_TRUE);
@@ -4648,6 +5033,21 @@ set_func(cmd_t *cmd)
prop_id,
sizeof (in_progress_nwiftab.zone_nwif_physical));
break;
+ case PT_MAC:
+ normalize_mac_addr(in_progress_nwiftab.zone_nwif_mac,
+ prop_id,
+ sizeof (in_progress_nwiftab.zone_nwif_mac));
+ break;
+ case PT_VLANID:
+ (void) strlcpy(in_progress_nwiftab.zone_nwif_vlan_id,
+ prop_id,
+ sizeof (in_progress_nwiftab.zone_nwif_vlan_id));
+ break;
+ case PT_GNIC:
+ (void) strlcpy(in_progress_nwiftab.zone_nwif_gnic,
+ prop_id,
+ sizeof (in_progress_nwiftab.zone_nwif_gnic));
+ break;
case PT_DEFROUTER:
if (validate_net_address_syntax(prop_id, B_TRUE)
!= Z_OK) {
@@ -4658,6 +5058,20 @@ set_func(cmd_t *cmd)
prop_id,
sizeof (in_progress_nwiftab.zone_nwif_defrouter));
break;
+ case PT_NPROP:
+ if (pp->pv_type != PROP_VAL_COMPLEX) {
+ zerr(gettext("A %s value was expected here."),
+ pvt_to_str(PROP_VAL_COMPLEX));
+ saw_error = B_TRUE;
+ return;
+ }
+ zonecfg_free_res_attr_list(
+ in_progress_nwiftab.zone_nwif_attrp);
+ in_progress_nwiftab.zone_nwif_attrp = NULL;
+ if (!(pp->pv_type == PROP_VAL_LIST &&
+ pp->pv_list == NULL))
+ add_property(cmd);
+ break;
default:
zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
B_TRUE);
@@ -4673,6 +5087,20 @@ set_func(cmd_t *cmd)
prop_id,
sizeof (in_progress_devtab.zone_dev_match));
break;
+ case PT_NPROP:
+ if (pp->pv_type != PROP_VAL_COMPLEX) {
+ zerr(gettext("A %s value was expected here."),
+ pvt_to_str(PROP_VAL_COMPLEX));
+ saw_error = B_TRUE;
+ return;
+ }
+ zonecfg_free_res_attr_list(
+ in_progress_devtab.zone_dev_attrp);
+ in_progress_devtab.zone_dev_attrp = NULL;
+ if (!(pp->pv_type == PROP_VAL_LIST &&
+ pp->pv_list == NULL))
+ add_property(cmd);
+ break;
default:
zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
B_TRUE);
@@ -4816,35 +5244,50 @@ set_func(cmd_t *cmd)
* the add_resource() function.
*/
- if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
- (int)(cap * 100) < 1) {
+ if ((cap = strtod(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
+ (cap * 100.0) < 1) {
zerr(gettext("%s property is out of range."),
pt_to_str(PT_NCPUS));
saw_error = B_TRUE;
return;
}
+ cap *= 100.0;
+ /* To avoid rounding issues add .5 to force correct value. */
if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
- (int)(cap * 100))) != Z_OK)
+ (uint_t)(cap + 0.5))) != Z_OK) {
zone_perror(zone, err, B_TRUE);
- else
+ } else {
need_to_commit = B_TRUE;
+ }
return;
case RT_MCAP:
switch (prop_type) {
case PT_PHYSICAL:
+ /*
+ * We have to check if an rctl is allowed here since
+ * there might already be a rctl defined that blocks
+ * the alias.
+ */
+ if (!zonecfg_aliased_rctl_ok(handle,
+ ALIAS_MAXPHYSMEM)) {
+ zone_perror(pt_to_str(PT_LOCKED),
+ Z_ALIAS_DISALLOW, B_FALSE);
+ saw_error = B_TRUE;
+ return;
+ }
+
if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
- zerr(gettext("A positive number with a "
+ zerr(gettext("A non-negative number with a "
"required scale suffix (K, M, G or T) was "
- "expected here."));
- saw_error = B_TRUE;
- } else if (mem_cap < ONE_MB) {
- zerr(gettext("%s value is too small. It must "
- "be at least 1M."), pt_to_str(PT_PHYSICAL));
+ "expected\nhere."));
saw_error = B_TRUE;
} else {
- snprintf(in_progress_mcaptab.zone_physmem_cap,
- physmem_size, "%llu", mem_cap);
+ if ((err = zonecfg_set_aliased_rctl(handle,
+ ALIAS_MAXPHYSMEM, mem_cap)) != Z_OK)
+ zone_perror(zone, err, B_TRUE);
+ else
+ need_to_commit = B_TRUE;
}
break;
case PT_SWAP:
@@ -5139,6 +5582,23 @@ info_hostid(zone_dochandle_t handle, FILE *fp)
}
static void
+info_uuid(FILE *fp)
+{
+ uuid_t uuid;
+ char suuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ if (new_uuid[0] != '\0') {
+ (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_UUID), new_uuid);
+ } else if (zonecfg_get_uuid(zone, uuid) == Z_OK &&
+ !uuid_is_null(uuid)) {
+ uuid_unparse(uuid, suuid);
+ (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_UUID), suuid);
+ } else {
+ (void) fprintf(fp, "%s:\n", pt_to_str(PT_UUID));
+ }
+}
+
+static void
info_fs_allowed(zone_dochandle_t handle, FILE *fp)
{
char fsallowedp[ZONE_FS_ALLOWED_MAX];
@@ -5220,12 +5680,25 @@ loopend:
static void
output_net(FILE *fp, struct zone_nwiftab *nwiftab)
{
+ struct zone_res_attrtab *np;
+
(void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
output_prop(fp, PT_ALLOWED_ADDRESS,
nwiftab->zone_nwif_allowed_address, B_TRUE);
- output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
+ output_prop(fp, PT_GNIC, nwiftab->zone_nwif_gnic, B_TRUE);
+ output_prop(fp, PT_MAC, nwiftab->zone_nwif_mac, B_TRUE);
+ output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
+ output_prop(fp, PT_VLANID, nwiftab->zone_nwif_vlan_id, B_TRUE);
+
+ for (np = nwiftab->zone_nwif_attrp; np != NULL;
+ np = np->zone_res_attr_next) {
+ fprintf(fp, "\t%s: (%s=%s,%s=\"%s\")\n",
+ pt_to_str(PT_NPROP),
+ pt_to_str(PT_NAME), np->zone_res_attr_name,
+ pt_to_str(PT_VALUE), np->zone_res_attr_value);
+ }
}
static void
@@ -5268,8 +5741,18 @@ info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
static void
output_dev(FILE *fp, struct zone_devtab *devtab)
{
+ struct zone_res_attrtab *np;
+
(void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
+
+ for (np = devtab->zone_dev_attrp; np != NULL;
+ np = np->zone_res_attr_next) {
+ fprintf(fp, "\t%s: (%s=%s,%s=\"%s\")\n",
+ pt_to_str(PT_NPROP),
+ pt_to_str(PT_NAME), np->zone_res_attr_name,
+ pt_to_str(PT_VALUE), np->zone_res_attr_value);
+ }
}
static void
@@ -5528,15 +6011,18 @@ bytes_to_units(char *str, char *buf, int bufsize)
}
static void
-output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
+output_mcap(FILE *fp, int showphys, uint64_t maxphys, int showswap,
uint64_t maxswap, int showlocked, uint64_t maxlocked)
{
char buf[128];
(void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
- if (mcaptab->zone_physmem_cap[0] != '\0') {
- bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
- output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
+
+ if (showphys == Z_OK) {
+ (void) snprintf(buf, sizeof (buf), "%llu", maxphys);
+ bytes_to_units(buf, buf, sizeof (buf));
+ /* Print directly since "physical" also is a net property. */
+ (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(PT_PHYSICAL), buf);
}
if (showswap == Z_OK) {
@@ -5558,16 +6044,16 @@ info_mcap(zone_dochandle_t handle, FILE *fp)
int res1, res2, res3;
uint64_t swap_limit;
uint64_t locked_limit;
- struct zone_mcaptab lookup;
+ uint64_t phys_limit;
- bzero(&lookup, sizeof (lookup));
- res1 = zonecfg_getmcapent(handle, &lookup);
+ res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &phys_limit);
res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
&locked_limit);
if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
- output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
+ output_mcap(fp, res1, phys_limit, res2, swap_limit,
+ res3, locked_limit);
}
static void
@@ -5637,9 +6123,11 @@ info_func(cmd_t *cmd)
FILE *fp = stdout;
boolean_t need_to_close = B_FALSE;
int type;
- int res1, res2;
+ int res1, res2, res3;
uint64_t swap_limit;
uint64_t locked_limit;
+ uint64_t phys_limit;
+ struct stat statbuf;
assert(cmd != NULL);
@@ -5687,7 +6175,9 @@ info_func(cmd_t *cmd)
&swap_limit);
res2 = zonecfg_get_aliased_rctl(handle,
ALIAS_MAXLOCKEDMEM, &locked_limit);
- output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
+ res3 = zonecfg_get_aliased_rctl(handle,
+ ALIAS_MAXPHYSMEM, &phys_limit);
+ output_mcap(fp, res3, phys_limit, res1, swap_limit,
res2, locked_limit);
break;
case RT_ADMIN:
@@ -5730,6 +6220,7 @@ info_func(cmd_t *cmd)
info_iptype(handle, fp);
info_hostid(handle, fp);
info_fs_allowed(handle, fp);
+ info_uuid(fp);
}
info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
@@ -5738,6 +6229,7 @@ info_func(cmd_t *cmd)
info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
info_aliased_rctl(handle, fp, ALIAS_SHARES);
+ info_aliased_rctl(handle, fp, ALIAS_ZFSPRI);
if (!global_zone) {
info_fs(handle, fp, cmd);
info_net(handle, fp, cmd);
@@ -5802,6 +6294,9 @@ info_func(cmd_t *cmd)
case RT_SHARES:
info_aliased_rctl(handle, fp, ALIAS_SHARES);
break;
+ case RT_ZFSPRI:
+ info_aliased_rctl(handle, fp, ALIAS_ZFSPRI);
+ break;
case RT_FS:
info_fs(handle, fp, cmd);
break;
@@ -5832,6 +6327,9 @@ info_func(cmd_t *cmd)
case RT_HOSTID:
info_hostid(handle, fp);
break;
+ case RT_UUID:
+ info_uuid(fp);
+ break;
case RT_ADMIN:
info_auth(handle, fp, cmd);
break;
@@ -6410,10 +6908,33 @@ verify_func(cmd_t *cmd)
if (save) {
if (ret_val == Z_OK) {
+ /*
+ * If the zone doesn't yet have a debug ID, set one now.
+ */
+ if (zonecfg_get_did(handle) == -1)
+ zonecfg_set_did(handle);
+
if ((ret_val = zonecfg_save(handle)) == Z_OK) {
need_to_commit = B_FALSE;
(void) strlcpy(revert_zone, zone,
sizeof (revert_zone));
+
+ if (is_create) {
+ zonecfg_notify_create(handle);
+ is_create = B_FALSE;
+ }
+ }
+
+ /*
+ * Commit a new uuid at this point since we now know the
+ * zone index entry will exist.
+ */
+ if (new_uuid[0] != '\0') {
+ if ((err = zonecfg_set_uuid(zone, zonepath,
+ new_uuid)) != Z_OK)
+ zone_perror(zone, err, B_FALSE);
+ else
+ new_uuid[0] = '\0';
}
} else {
zerr(gettext("Zone %s failed to verify"), zone);
@@ -6584,6 +7105,7 @@ end_func(cmd_t *cmd)
int err, arg, res1, res2, res3;
uint64_t swap_limit;
uint64_t locked_limit;
+ uint64_t phys_limit;
uint64_t proc_cap;
assert(cmd != NULL);
@@ -6887,8 +7409,8 @@ end_func(cmd_t *cmd)
break;
case RT_MCAP:
/* Make sure everything was filled in. */
- res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
- Z_ERR : Z_OK;
+ res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM,
+ &phys_limit);
res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
&swap_limit);
res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
@@ -6904,11 +7426,6 @@ end_func(cmd_t *cmd)
/* if phys & locked are both set, verify locked <= phys */
if (res1 == Z_OK && res3 == Z_OK) {
- uint64_t phys_limit;
- char *endp;
-
- phys_limit = strtoull(
- in_progress_mcaptab.zone_physmem_cap, &endp, 10);
if (phys_limit < locked_limit) {
zerr(gettext("The %s cap must be less than or "
"equal to the %s cap."),
@@ -6920,23 +7437,6 @@ end_func(cmd_t *cmd)
}
err = Z_OK;
- if (res1 == Z_OK) {
- /*
- * We could be ending from either an add operation
- * or a select operation. Since all of the properties
- * within this resource are optional, we always use
- * modify on the mcap entry. zonecfg_modify_mcap()
- * will handle both adding and modifying a memory cap.
- */
- err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
- } else if (end_op == CMD_SELECT) {
- /*
- * If we're ending from a select and the physical
- * memory cap is empty then the user could have cleared
- * the physical cap value, so try to delete the entry.
- */
- (void) zonecfg_delete_mcap(handle);
- }
break;
case RT_ADMIN:
/* First make sure everything was filled in. */
@@ -7499,8 +7999,10 @@ get_execbasename(char *execfullname)
int
main(int argc, char *argv[])
{
- int err, arg;
+ int err, arg, uflag = 0, zflag = 0;
struct stat st;
+ uuid_t uuidin;
+ char zonename[ZONENAME_MAX + 1];
/* This must be before anything goes to stdout. */
setbuf(stdout, NULL);
@@ -7527,7 +8029,7 @@ main(int argc, char *argv[])
exit(Z_OK);
}
- while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
+ while ((arg = getopt(argc, argv, "?f:R:z:u:")) != EOF) {
switch (arg) {
case '?':
if (optopt == '?')
@@ -7554,6 +8056,21 @@ main(int argc, char *argv[])
}
zonecfg_set_root(optarg);
break;
+ case 'u':
+ if (uuid_parse((char *)optarg, uuidin) == -1)
+ return (Z_INVALID_PROPERTY);
+
+ if (zonecfg_get_name_by_uuid(uuidin, zonename,
+ ZONENAME_MAX) != Z_OK) {
+ zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
+ usage(B_FALSE, HELP_SYNTAX);
+ exit(Z_USAGE);
+ }
+
+ (void) strlcpy(zone, zonename, sizeof (zone));
+ (void) strlcpy(revert_zone, zonename, sizeof (zone));
+ uflag = 1;
+ break;
case 'z':
if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
global_zone = B_TRUE;
@@ -7564,6 +8081,7 @@ main(int argc, char *argv[])
}
(void) strlcpy(zone, optarg, sizeof (zone));
(void) strlcpy(revert_zone, optarg, sizeof (zone));
+ zflag = 1;
break;
default:
usage(B_FALSE, HELP_USAGE);
@@ -7571,7 +8089,7 @@ main(int argc, char *argv[])
}
}
- if (optind > argc || strcmp(zone, "") == 0) {
+ if (optind > argc || strcmp(zone, "") == 0 || (uflag && zflag)) {
usage(B_FALSE, HELP_USAGE);
exit(Z_USAGE);
}
diff --git a/usr/src/cmd/zonecfg/zonecfg.h b/usr/src/cmd/zonecfg/zonecfg.h
index 108d0ce507..e4ae4d4d61 100644
--- a/usr/src/cmd/zonecfg/zonecfg.h
+++ b/usr/src/cmd/zonecfg/zonecfg.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#ifndef _ZONECFG_H
@@ -90,7 +91,9 @@ extern "C" {
#define RT_ADMIN 26
#define RT_FS_ALLOWED 27
#define RT_MAXPROCS 28 /* really a rctl alias property, but for info */
-#define RT_SECFLAGS 29
+#define RT_ZFSPRI 29 /* really a rctl alias property, but for info */
+#define RT_UUID 30 /* really a property, but for info */
+#define RT_SECFLAGS 31
#define RT_MIN RT_UNKNOWN
#define RT_MAX RT_SECFLAGS
@@ -138,9 +141,15 @@ extern "C" {
#define PT_FS_ALLOWED 39
#define PT_MAXPROCS 40
#define PT_ALLOWED_ADDRESS 41
-#define PT_DEFAULT 42
-#define PT_LOWER 43
-#define PT_UPPER 44
+#define PT_ZFSPRI 42
+#define PT_MAC 43
+#define PT_VLANID 44
+#define PT_GNIC 45
+#define PT_NPROP 46
+#define PT_UUID 47
+#define PT_DEFAULT 48
+#define PT_LOWER 49
+#define PT_UPPER 50
#define PT_MIN PT_UNKNOWN
#define PT_MAX PT_UPPER
diff --git a/usr/src/cmd/zonecfg/zonecfg_grammar.y b/usr/src/cmd/zonecfg/zonecfg_grammar.y
index 2e950512ec..d8b2fadb2f 100644
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Joyent Inc. All rights reserved.
*/
/*
@@ -135,7 +136,8 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
%token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET PCAP
%token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
-%token MAXSEMIDS LOCKED SWAP SCHED CLEAR DEFROUTER ADMIN SECFLAGS USER AUTHS MAXPROCS
+%token MAXSEMIDS LOCKED SWAP SCHED CLEAR DEFROUTER ADMIN USER AUTHS MAXPROCS
+%token ZFSPRI MAC VLANID GNIC NPROP UUID SECFLAGS
%token DEFAULT UPPER LOWER
%type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
@@ -146,7 +148,7 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID USER AUTHS FS_ALLOWED
- ALLOWED_ADDRESS DEFAULT UPPER LOWER
+ ALLOWED_ADDRESS MAC VLANID GNIC NPROP UUID DEFAULT UPPER LOWER
%type <cmd> command
%type <cmd> add_command ADD
%type <cmd> cancel_command CANCEL
@@ -651,6 +653,24 @@ info_command: INFO
$$->cmd_res_type = RT_FS_ALLOWED;
$$->cmd_prop_nv_pairs = 0;
}
+ | INFO UUID
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &info_func;
+ $$->cmd_res_type = RT_UUID;
+ $$->cmd_prop_nv_pairs = 0;
+ }
+ | INFO ZFSPRI
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &info_func;
+ $$->cmd_res_type = RT_ZFSPRI;
+ $$->cmd_prop_nv_pairs = 0;
+ }
| INFO resource_type property_name EQUAL property_value
{
if (($$ = alloc_cmd()) == NULL)
@@ -735,6 +755,19 @@ remove_command: REMOVE
$$->cmd_prop_name[0] = $2;
$$->cmd_property_ptr[0] = &property[0];
}
+ | REMOVE TOKEN property_name property_value
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &remove_func;
+ $$->cmd_argc = 1;
+ $$->cmd_argv[0] = claim_token($2);
+ $$->cmd_argv[1] = NULL;
+ $$->cmd_prop_nv_pairs = 1;
+ $$->cmd_prop_name[0] = $3;
+ $$->cmd_property_ptr[0] = &property[0];
+ }
| REMOVE resource_type property_name EQUAL property_value
{
if (($$ = alloc_cmd()) == NULL)
@@ -746,6 +779,20 @@ remove_command: REMOVE
$$->cmd_prop_name[0] = $3;
$$->cmd_property_ptr[0] = &property[0];
}
+ | REMOVE TOKEN resource_type property_name EQUAL property_value
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &remove_func;
+ $$->cmd_res_type = $3;
+ $$->cmd_argc = 1;
+ $$->cmd_argv[0] = claim_token($2);
+ $$->cmd_argv[1] = NULL;
+ $$->cmd_prop_nv_pairs = 1;
+ $$->cmd_prop_name[0] = $4;
+ $$->cmd_property_ptr[0] = &property[0];
+ }
| REMOVE resource_type property_name EQUAL property_value property_name EQUAL property_value
{
if (($$ = alloc_cmd()) == NULL)
@@ -759,6 +806,22 @@ remove_command: REMOVE
$$->cmd_prop_name[1] = $6;
$$->cmd_property_ptr[1] = &property[1];
}
+ | REMOVE TOKEN resource_type property_name EQUAL property_value property_name EQUAL property_value
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &remove_func;
+ $$->cmd_res_type = $3;
+ $$->cmd_argc = 1;
+ $$->cmd_argv[0] = claim_token($2);
+ $$->cmd_argv[1] = NULL;
+ $$->cmd_prop_nv_pairs = 2;
+ $$->cmd_prop_name[0] = $4;
+ $$->cmd_property_ptr[0] = &property[0];
+ $$->cmd_prop_name[1] = $7;
+ $$->cmd_property_ptr[1] = &property[1];
+ }
| REMOVE resource_type property_name EQUAL property_value property_name EQUAL property_value property_name EQUAL property_value
{
if (($$ = alloc_cmd()) == NULL)
@@ -774,6 +837,24 @@ remove_command: REMOVE
$$->cmd_prop_name[2] = $9;
$$->cmd_property_ptr[2] = &property[2];
}
+ | REMOVE TOKEN resource_type property_name EQUAL property_value property_name EQUAL property_value property_name EQUAL property_value
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &remove_func;
+ $$->cmd_res_type = $3;
+ $$->cmd_argc = 1;
+ $$->cmd_argv[0] = claim_token($2);
+ $$->cmd_argv[1] = NULL;
+ $$->cmd_prop_nv_pairs = 3;
+ $$->cmd_prop_name[0] = $4;
+ $$->cmd_property_ptr[0] = &property[0];
+ $$->cmd_prop_name[1] = $7;
+ $$->cmd_property_ptr[1] = &property[1];
+ $$->cmd_prop_name[2] = $10;
+ $$->cmd_property_ptr[2] = &property[2];
+ }
revert_command: REVERT
{
@@ -978,6 +1059,10 @@ property_name: SPECIAL { $$ = PT_SPECIAL; }
| ALLOWED_ADDRESS { $$ = PT_ALLOWED_ADDRESS; }
| PHYSICAL { $$ = PT_PHYSICAL; }
| DEFROUTER { $$ = PT_DEFROUTER; }
+ | MAC { $$ = PT_MAC; }
+ | VLANID { $$ = PT_VLANID; }
+ | GNIC { $$ = PT_GNIC; }
+ | NPROP { $$ = PT_NPROP; }
| NAME { $$ = PT_NAME; }
| VALUE { $$ = PT_VALUE; }
| MATCH { $$ = PT_MATCH; }
@@ -1001,6 +1086,8 @@ property_name: SPECIAL { $$ = PT_SPECIAL; }
| USER { $$ = PT_USER; }
| AUTHS { $$ = PT_AUTHS; }
| FS_ALLOWED { $$ = PT_FS_ALLOWED; }
+ | UUID { $$ = PT_UUID; }
+ | ZFSPRI { $$ = PT_ZFSPRI; }
| DEFAULT { $$ = PT_DEFAULT; }
| UPPER { $$ = PT_UPPER; }
| LOWER { $$ = PT_LOWER; }
diff --git a/usr/src/cmd/zonecfg/zonecfg_lex.l b/usr/src/cmd/zonecfg/zonecfg_lex.l
index 8714c55499..05b41df48b 100644
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#include <assert.h>
@@ -57,10 +58,11 @@ extern void yyerror(char *s);
static char *create_token(char *s);
%}
-%a 7000
-%p 5000
+%a 8000
+%p 5500
%e 2000
%n 1000
+%o 14000
%{
/*
@@ -238,6 +240,18 @@ static char *create_token(char *s);
<TSTATE>defrouter { return DEFROUTER; }
<CSTATE>defrouter { return DEFROUTER; }
+<TSTATE>mac-addr { return MAC; }
+<CSTATE>mac-addr { return MAC; }
+
+<TSTATE>vlan-id { return VLANID; }
+<CSTATE>vlan-id { return VLANID; }
+
+<TSTATE>global-nic { return GNIC; }
+<CSTATE>global-nic { return GNIC; }
+
+<TSTATE>property { return NPROP; }
+<CSTATE>property { return NPROP; }
+
<TSTATE>dir { return DIR; }
<CSTATE>dir { return DIR; }
@@ -310,6 +324,12 @@ static char *create_token(char *s);
<TSTATE>fs-allowed { return FS_ALLOWED; }
<CSTATE>fs-allowed { return FS_ALLOWED; }
+<TSTATE>uuid { return UUID; }
+<CSTATE>uuid { return UUID; }
+
+<TSTATE>zfs-io-priority { return ZFSPRI; }
+<CSTATE>zfs-io-priority { return ZFSPRI; }
+
<TSTATE>default { return DEFAULT; }
<CSTATE>default { return DEFAULT; }
@@ -368,6 +388,13 @@ static char *create_token(char *s);
return TOKEN;
}
+<CSTATE>\"[^\"\n]*[\"\n] {
+ yylval.strval = create_token(yytext + 1);
+ if (yylval.strval[yyleng - 2] == '"')
+ yylval.strval[yyleng - 2] = 0;
+ return TOKEN;
+ }
+
<TSTATE>\"[^\"\n]*[\"\n] {
yylval.strval = create_token(yytext + 1);
if (yylval.strval[yyleng - 2] == '"')
diff --git a/usr/src/cmd/zonename/Makefile b/usr/src/cmd/zonename/Makefile
index 566e893a67..3a51952455 100644
--- a/usr/src/cmd/zonename/Makefile
+++ b/usr/src/cmd/zonename/Makefile
@@ -28,8 +28,10 @@
#
PROG= zonename
+OBJS= zonename.o
include ../Makefile.cmd
+include ../Makefile.ctf
LDLIBS += -lzonecfg
@@ -37,6 +39,10 @@ LDLIBS += -lzonecfg
all: $(PROG)
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
install: all $(ROOTSBINPROG)
$(RM) $(ROOTPROG)
$(SYMLINK) ../../sbin/$(PROG) $(ROOTPROG)
@@ -44,6 +50,10 @@ install: all $(ROOTSBINPROG)
check: $(PROG).c
$(CSTYLE) -pP $(PROG).c
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
clean:
lint: lint_PROG
diff --git a/usr/src/cmd/zonestat/zonestatd/zonestatd.c b/usr/src/cmd/zonestat/zonestatd/zonestatd.c
index 026d188fda..10b73fd26e 100644
--- a/usr/src/cmd/zonestat/zonestatd/zonestatd.c
+++ b/usr/src/cmd/zonestat/zonestatd/zonestatd.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#include <alloca.h>
#include <assert.h>
@@ -2190,7 +2191,7 @@ zsd_get_zone_rctl_usage(char *name)
return (rctlblk_get_value(rblk));
}
-#define ZSD_NUM_RCTL_VALS 19
+#define ZSD_NUM_RCTL_VALS 20
/*
* Fetch the limit information for a zone. This uses zone_enter() as the
@@ -2237,12 +2238,6 @@ zsd_get_zone_caps(zsd_ctl_t *ctl, zsd_zone_t *zone, uint64_t *cpu_shares,
*msgids = 0;
*lofi = 0;
- /* Get the ram cap first since it is a zone attr */
- ret = zone_getattr(zone->zsz_id, ZONE_ATTR_PHYS_MCAP,
- ram_cap, sizeof (*ram_cap));
- if (ret < 0 || *ram_cap == 0)
- *ram_cap = ZS_LIMIT_NONE;
-
/* Get the zone's default scheduling class */
ret = zone_getattr(zone->zsz_id, ZONE_ATTR_SCHED_CLASS,
class, sizeof (class));
@@ -2298,6 +2293,7 @@ zsd_get_zone_caps(zsd_ctl_t *ctl, zsd_zone_t *zone, uint64_t *cpu_shares,
vals[i++] = zsd_get_zone_rctl_usage("zone.max-msg-ids");
vals[i++] = zsd_get_zone_rctl_limit("zone.max-lofi");
vals[i++] = zsd_get_zone_rctl_usage("zone.max-lofi");
+ vals[i++] = zsd_get_zone_rctl_usage("zone.max-physical-memory");
if (write(p[1], vals, ZSD_NUM_RCTL_VALS * sizeof (uint64_t)) !=
ZSD_NUM_RCTL_VALS * sizeof (uint64_t)) {
@@ -2342,6 +2338,7 @@ zsd_get_zone_caps(zsd_ctl_t *ctl, zsd_zone_t *zone, uint64_t *cpu_shares,
*msgids = vals[i++];
*lofi_cap = vals[i++];
*lofi = vals[i++];
+ *ram_cap = vals[i++];
/* Interpret maximum values as no cap */
if (*cpu_cap == UINT32_MAX || *cpu_cap == 0)
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index 39cdf276c8..cb13102874 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -24,6 +24,7 @@
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
* Copyright 2016 Nexenta Systems, Inc.
* Copyright (c) 2017 Datto Inc.
@@ -2790,6 +2791,8 @@ zpool_do_checkpoint(int argc, char **argv)
*
* -F Attempt rewind if necessary.
*
+ * -m Allow import with a missing log device.
+ *
* -n See if rewind would work, but don't actually rewind.
*
* -N Import the pool but don't mount datasets.