aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/gen/pw_scan.c122
-rw-r--r--lib/libc/gen/pw_scan.h36
-rw-r--r--lib/libutil/pw_util.c204
-rw-r--r--sbin/sysctl/Makefile6
-rw-r--r--sbin/sysctl/pathconf.c229
-rw-r--r--sbin/sysctl/sysctl.8208
-rw-r--r--sbin/sysctl/sysctl.c572
-rw-r--r--secure/usr.sbin/sendmail/Makefile24
-rw-r--r--share/examples/sliplogin/slip.hosts11
-rw-r--r--share/examples/sliplogin/slip.login12
-rw-r--r--usr.sbin/Makefile26
-rw-r--r--usr.sbin/Makefile.inc3
-rw-r--r--usr.sbin/ac/ac.8107
-rw-r--r--usr.sbin/accton/Makefile6
-rw-r--r--usr.sbin/accton/accton.c95
-rw-r--r--usr.sbin/amd/Makefile5
-rw-r--r--usr.sbin/amd/amd/ChangeLog1169
-rw-r--r--usr.sbin/amd/amd/Makefile33
-rw-r--r--usr.sbin/amd/amd/afs_ops.c1816
-rw-r--r--usr.sbin/amd/amd/am_ops.c181
-rw-r--r--usr.sbin/amd/amd/amd.8232
-rw-r--r--usr.sbin/amd/amd/amd.c344
-rw-r--r--usr.sbin/amd/amd/amq_subr.c464
-rw-r--r--usr.sbin/amd/amd/clock.c241
-rw-r--r--usr.sbin/amd/amd/efs_ops.c135
-rw-r--r--usr.sbin/amd/amd/get_args.c336
-rw-r--r--usr.sbin/amd/amd/host_ops.c681
-rw-r--r--usr.sbin/amd/amd/ifs_ops.c195
-rw-r--r--usr.sbin/amd/amd/info_file.c276
-rw-r--r--usr.sbin/amd/amd/info_hes.c697
-rw-r--r--usr.sbin/amd/amd/info_ndbm.c123
-rw-r--r--usr.sbin/amd/amd/info_nis.c247
-rw-r--r--usr.sbin/amd/amd/info_passwd.c162
-rw-r--r--usr.sbin/amd/amd/info_union.c153
-rw-r--r--usr.sbin/amd/amd/map.c1140
-rw-r--r--usr.sbin/amd/amd/mapc.c914
-rw-r--r--usr.sbin/amd/amd/misc_rpc.c333
-rw-r--r--usr.sbin/amd/amd/mntfs.c367
-rw-r--r--usr.sbin/amd/amd/mount_fs.c273
-rw-r--r--usr.sbin/amd/amd/mtab.c108
-rw-r--r--usr.sbin/amd/amd/nfs_ops.c809
-rw-r--r--usr.sbin/amd/amd/nfs_start.c435
-rw-r--r--usr.sbin/amd/amd/nfs_subr.c552
-rw-r--r--usr.sbin/amd/amd/nfsx_ops.c516
-rw-r--r--usr.sbin/amd/amd/opts.c835
-rw-r--r--usr.sbin/amd/amd/pfs_ops.c169
-rw-r--r--usr.sbin/amd/amd/restart.c181
-rw-r--r--usr.sbin/amd/amd/rpc_fwd.c430
-rw-r--r--usr.sbin/amd/amd/sched.c325
-rw-r--r--usr.sbin/amd/amd/sfs_ops.c208
-rw-r--r--usr.sbin/amd/amd/srvr_afs.c205
-rw-r--r--usr.sbin/amd/amd/srvr_nfs.c719
-rw-r--r--usr.sbin/amd/amd/ufs_ops.c178
-rw-r--r--usr.sbin/amd/amd/umount_fs.c225
-rw-r--r--usr.sbin/amd/amd/util.c648
-rw-r--r--usr.sbin/amd/amd/wire.c281
-rw-r--r--usr.sbin/amd/amd/xutil.c491
-rw-r--r--usr.sbin/amd/amq/Makefile15
-rw-r--r--usr.sbin/amd/amq/amq.8130
-rw-r--r--usr.sbin/amd/amq/amq.c666
-rw-r--r--usr.sbin/amd/config/Configure60
-rw-r--r--usr.sbin/amd/config/Makefile.aix35
-rw-r--r--usr.sbin/amd/config/Makefile.bsd448
-rw-r--r--usr.sbin/amd/config/Makefile.config91
-rw-r--r--usr.sbin/amd/config/Makefile.hpux13
-rw-r--r--usr.sbin/amd/config/Makefile.irix10
-rw-r--r--usr.sbin/amd/config/Makefile.irix313
-rw-r--r--usr.sbin/amd/config/Makefile.irix414
-rw-r--r--usr.sbin/amd/config/Makefile.stellix10
-rw-r--r--usr.sbin/amd/config/RELEASE1
-rw-r--r--usr.sbin/amd/config/arch126
-rw-r--r--usr.sbin/amd/config/misc-aix3.h96
-rw-r--r--usr.sbin/amd/config/misc-hpux.h79
-rw-r--r--usr.sbin/amd/config/misc-irix.h50
-rw-r--r--usr.sbin/amd/config/misc-next.h44
-rw-r--r--usr.sbin/amd/config/misc-stellix.h65
-rw-r--r--usr.sbin/amd/config/misc-ultrix.h55
-rw-r--r--usr.sbin/amd/config/mount_aix.c153
-rw-r--r--usr.sbin/amd/config/mount_irix.c83
-rw-r--r--usr.sbin/amd/config/mount_stellix.c76
-rw-r--r--usr.sbin/amd/config/mtab_aix.c137
-rw-r--r--usr.sbin/amd/config/mtab_bsd.c114
-rw-r--r--usr.sbin/amd/config/mtab_file.c472
-rw-r--r--usr.sbin/amd/config/mtab_ultrix.c115
-rw-r--r--usr.sbin/amd/config/newvers.sh88
-rw-r--r--usr.sbin/amd/config/os-acis43.h83
-rw-r--r--usr.sbin/amd/config/os-aix3.h181
-rw-r--r--usr.sbin/amd/config/os-aux.h117
-rw-r--r--usr.sbin/amd/config/os-bsd44.h191
-rw-r--r--usr.sbin/amd/config/os-concentrix.h79
-rw-r--r--usr.sbin/amd/config/os-convex.h80
-rw-r--r--usr.sbin/amd/config/os-defaults.h143
-rw-r--r--usr.sbin/amd/config/os-dgux.h114
-rw-r--r--usr.sbin/amd/config/os-fpx4.h92
-rw-r--r--usr.sbin/amd/config/os-hcx.h81
-rw-r--r--usr.sbin/amd/config/os-hlh42.h89
-rw-r--r--usr.sbin/amd/config/os-hpux.h150
-rw-r--r--usr.sbin/amd/config/os-irix.h133
-rw-r--r--usr.sbin/amd/config/os-irix3.h133
-rw-r--r--usr.sbin/amd/config/os-irix4.h150
-rw-r--r--usr.sbin/amd/config/os-next.h79
-rw-r--r--usr.sbin/amd/config/os-pyrOSx.h80
-rw-r--r--usr.sbin/amd/config/os-riscix.h88
-rw-r--r--usr.sbin/amd/config/os-sos3.h79
-rw-r--r--usr.sbin/amd/config/os-sos4.h116
-rw-r--r--usr.sbin/amd/config/os-stellix.h108
-rw-r--r--usr.sbin/amd/config/os-type128
-rw-r--r--usr.sbin/amd/config/os-u2_2.h161
-rw-r--r--usr.sbin/amd/config/os-u3_0.h154
-rw-r--r--usr.sbin/amd/config/os-u4_0.h158
-rw-r--r--usr.sbin/amd/config/os-u4_2.h153
-rw-r--r--usr.sbin/amd/config/os-umax43.h79
-rw-r--r--usr.sbin/amd/config/os-utek.h49
-rw-r--r--usr.sbin/amd/config/os-utx32.h85
-rw-r--r--usr.sbin/amd/config/os-xinu43.h112
-rw-r--r--usr.sbin/amd/doc/Makefile53
-rw-r--r--usr.sbin/amd/doc/amdref.cps381
-rw-r--r--usr.sbin/amd/doc/amdref.ps6429
-rw-r--r--usr.sbin/amd/doc/amdref.texinfo4554
-rw-r--r--usr.sbin/amd/doc/texinfo.tex2192
-rw-r--r--usr.sbin/amd/fsinfo/Makefile30
-rw-r--r--usr.sbin/amd/fsinfo/conf/automounts48
-rw-r--r--usr.sbin/amd/fsinfo/conf/csg_sun318
-rw-r--r--usr.sbin/amd/fsinfo/conf/csg_vax67
-rw-r--r--usr.sbin/amd/fsinfo/conf/diskless_sun3_sos49
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/achilles.doc.ic.ac.uk116
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/bigears.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/dylan.doc.ic.ac.uk68
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/flamingo.doc.ic.ac.uk104
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/ganymede.doc.ic.ac.uk33
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/gould.doc.ic.ac.uk477
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/gummo.doc.ic.ac.uk12
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/ivax.doc.ic.ac.uk84
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/obsidian.doc.ic.ac.uk28
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/pelican.doc.ic.ac.uk208
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/rvax.doc.ic.ac.uk66
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/sky.doc.ic.ac.uk79
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/svax.doc.ic.ac.uk66
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun1.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun2.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun3.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun4.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun5.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/toytown.doc.ic.ac.uk116
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/truth.doc.ic.ac.uk9
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun1.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun10.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun11.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun12.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun13.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun14.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun15.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun16.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun17.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun18.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun19.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun2.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun3.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun4.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun5.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun6.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun7.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun8.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun9.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsunfs.doc.ic.ac.uk211
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/whoops.doc.ic.ac.uk21
-rw-r--r--usr.sbin/amd/fsinfo/conf/users106
-rw-r--r--usr.sbin/amd/fsinfo/fsi_analyze.c645
-rw-r--r--usr.sbin/amd/fsinfo/fsi_data.h236
-rw-r--r--usr.sbin/amd/fsinfo/fsi_dict.c125
-rw-r--r--usr.sbin/amd/fsinfo/fsi_gram.y394
-rw-r--r--usr.sbin/amd/fsinfo/fsi_lex.l403
-rw-r--r--usr.sbin/amd/fsinfo/fsi_util.c573
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.877
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.c275
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.h159
-rw-r--r--usr.sbin/amd/fsinfo/wr_atab.c284
-rw-r--r--usr.sbin/amd/fsinfo/wr_bparam.c101
-rw-r--r--usr.sbin/amd/fsinfo/wr_dumpset.c88
-rw-r--r--usr.sbin/amd/fsinfo/wr_exportfs.c100
-rw-r--r--usr.sbin/amd/fsinfo/wr_fstab.c303
-rw-r--r--usr.sbin/amd/include/am.h567
-rw-r--r--usr.sbin/amd/include/config.h142
-rw-r--r--usr.sbin/amd/include/fstype.h148
-rw-r--r--usr.sbin/amd/include/re.h21
-rw-r--r--usr.sbin/amd/include/remagic.h5
-rw-r--r--usr.sbin/amd/include/uwait.h83
-rw-r--r--usr.sbin/amd/maps/a_master79
-rw-r--r--usr.sbin/amd/maps/a_net3
-rw-r--r--usr.sbin/amd/mk-amd-map/Makefile11
-rw-r--r--usr.sbin/amd/mk-amd-map/mk-amd-map.859
-rw-r--r--usr.sbin/amd/mk-amd-map/mk-amd-map.c384
-rw-r--r--usr.sbin/amd/rpcx/amq.h153
-rw-r--r--usr.sbin/amd/rpcx/amq.x185
-rw-r--r--usr.sbin/amd/rpcx/amq_clnt.c181
-rw-r--r--usr.sbin/amd/rpcx/amq_svc.c136
-rw-r--r--usr.sbin/amd/rpcx/amq_xdr.c251
-rw-r--r--usr.sbin/amd/rpcx/mount.h124
-rw-r--r--usr.sbin/amd/rpcx/mount_xdr.c206
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot.h389
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot_svc.c198
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot_xdr.c627
-rw-r--r--usr.sbin/amd/text/COPYRIGHT3
-rw-r--r--usr.sbin/amd/text/INSTALL194
-rw-r--r--usr.sbin/amd/text/README37
-rw-r--r--usr.sbin/amd/text/amd.start.ex87
-rw-r--r--usr.sbin/arp/Makefile13
-rw-r--r--usr.sbin/arp/arp.8127
-rw-r--r--usr.sbin/arp/arp.c514
-rw-r--r--usr.sbin/arp/arp4.4124
-rw-r--r--usr.sbin/bad144/Makefile7
-rw-r--r--usr.sbin/bad144/bad144.8186
-rw-r--r--usr.sbin/bad144/bad144.c662
-rw-r--r--usr.sbin/chown/Makefile9
-rw-r--r--usr.sbin/chown/chgrp.1136
-rw-r--r--usr.sbin/chown/chown.8149
-rw-r--r--usr.sbin/chown/chown.c273
-rw-r--r--usr.sbin/chroot/Makefile6
-rw-r--r--usr.sbin/chroot/chroot.879
-rw-r--r--usr.sbin/chroot/chroot.c96
-rw-r--r--usr.sbin/config.new/Makefile14
-rw-r--r--usr.sbin/config.new/config.h281
-rw-r--r--usr.sbin/config.new/config.new.8167
-rw-r--r--usr.sbin/config.new/files.c262
-rw-r--r--usr.sbin/config.new/gram.y392
-rw-r--r--usr.sbin/config.new/hash.c279
-rw-r--r--usr.sbin/config.new/main.c466
-rw-r--r--usr.sbin/config.new/mkheaders.c148
-rw-r--r--usr.sbin/config.new/mkioconf.c395
-rw-r--r--usr.sbin/config.new/mkmakefile.c364
-rw-r--r--usr.sbin/config.new/mkswap.c118
-rw-r--r--usr.sbin/config.new/pack.c520
-rw-r--r--usr.sbin/config.new/scan.l238
-rw-r--r--usr.sbin/config.new/sem.c974
-rw-r--r--usr.sbin/config.new/sem.h61
-rw-r--r--usr.sbin/config.new/util.c262
-rw-r--r--usr.sbin/config/Makefile12
-rw-r--r--usr.sbin/config/SMM.doc/0.t88
-rw-r--r--usr.sbin/config/SMM.doc/1.t61
-rw-r--r--usr.sbin/config/SMM.doc/2.t188
-rw-r--r--usr.sbin/config/SMM.doc/3.t299
-rw-r--r--usr.sbin/config/SMM.doc/4.t442
-rw-r--r--usr.sbin/config/SMM.doc/5.t271
-rw-r--r--usr.sbin/config/SMM.doc/6.t239
-rw-r--r--usr.sbin/config/SMM.doc/Makefile10
-rw-r--r--usr.sbin/config/SMM.doc/a.t162
-rw-r--r--usr.sbin/config/SMM.doc/b.t137
-rw-r--r--usr.sbin/config/SMM.doc/c.t109
-rw-r--r--usr.sbin/config/SMM.doc/d.t272
-rw-r--r--usr.sbin/config/SMM.doc/e.t114
-rw-r--r--usr.sbin/config/SMM.doc/spell.ok306
-rw-r--r--usr.sbin/config/config.8174
-rw-r--r--usr.sbin/config/config.h212
-rw-r--r--usr.sbin/config/config.y1109
-rw-r--r--usr.sbin/config/lang.l215
-rw-r--r--usr.sbin/config/main.c268
-rw-r--r--usr.sbin/config/mkglue.c400
-rw-r--r--usr.sbin/config/mkheaders.c207
-rw-r--r--usr.sbin/config/mkioconf.c1085
-rw-r--r--usr.sbin/config/mkmakefile.c623
-rw-r--r--usr.sbin/config/mkswapconf.c216
-rw-r--r--usr.sbin/config/mkubglue.c196
-rw-r--r--usr.sbin/dev_mkdb/Makefile6
-rw-r--r--usr.sbin/dev_mkdb/dev_mkdb.881
-rw-r--r--usr.sbin/dev_mkdb/dev_mkdb.c181
-rw-r--r--usr.sbin/diskpart/Makefile6
-rw-r--r--usr.sbin/diskpart/diskpart.8143
-rw-r--r--usr.sbin/diskpart/diskpart.c474
-rw-r--r--usr.sbin/edquota/Makefile6
-rw-r--r--usr.sbin/edquota/edquota.8150
-rw-r--r--usr.sbin/edquota/edquota.c722
-rw-r--r--usr.sbin/edquota/pathnames.h39
-rw-r--r--usr.sbin/eeprom/Makefile6
-rw-r--r--usr.sbin/eeprom/eeprom.869
-rw-r--r--usr.sbin/eeprom/eeprom.c204
-rw-r--r--usr.sbin/eeprom/pathnames.h45
-rw-r--r--usr.sbin/inetd/Makefile7
-rw-r--r--usr.sbin/inetd/inetd.8375
-rw-r--r--usr.sbin/inetd/inetd.c1255
-rw-r--r--usr.sbin/inetd/pathnames.h38
-rw-r--r--usr.sbin/iostat/Makefile11
-rw-r--r--usr.sbin/iostat/iostat.8142
-rw-r--r--usr.sbin/iostat/iostat.c391
-rw-r--r--usr.sbin/kgmon/Makefile14
-rw-r--r--usr.sbin/kgmon/kgmon.8122
-rw-r--r--usr.sbin/kgmon/kgmon.c520
-rw-r--r--usr.sbin/kvm_mkdb/Makefile7
-rw-r--r--usr.sbin/kvm_mkdb/extern.h38
-rw-r--r--usr.sbin/kvm_mkdb/kvm_mkdb.869
-rw-r--r--usr.sbin/kvm_mkdb/kvm_mkdb.c111
-rw-r--r--usr.sbin/kvm_mkdb/nlist.c186
-rw-r--r--usr.sbin/kvm_mkdb/testdb.c113
-rw-r--r--usr.sbin/lpr/Makefile6
-rw-r--r--usr.sbin/lpr/SMM.doc/0.t68
-rw-r--r--usr.sbin/lpr/SMM.doc/1.t77
-rw-r--r--usr.sbin/lpr/SMM.doc/2.t141
-rw-r--r--usr.sbin/lpr/SMM.doc/3.t73
-rw-r--r--usr.sbin/lpr/SMM.doc/4.t206
-rw-r--r--usr.sbin/lpr/SMM.doc/5.t116
-rw-r--r--usr.sbin/lpr/SMM.doc/6.t94
-rw-r--r--usr.sbin/lpr/SMM.doc/7.t226
-rw-r--r--usr.sbin/lpr/SMM.doc/Makefile10
-rw-r--r--usr.sbin/lpr/SMM.doc/spell.ok70
-rw-r--r--usr.sbin/lpr/common_source/common.c352
-rw-r--r--usr.sbin/lpr/common_source/displayq.c449
-rw-r--r--usr.sbin/lpr/common_source/lp.h126
-rw-r--r--usr.sbin/lpr/common_source/lp.local.h80
-rw-r--r--usr.sbin/lpr/common_source/pathnames.h50
-rw-r--r--usr.sbin/lpr/common_source/printcap.c458
-rw-r--r--usr.sbin/lpr/common_source/recvjob.c358
-rw-r--r--usr.sbin/lpr/common_source/rmjob.c339
-rw-r--r--usr.sbin/lpr/common_source/startdaemon.c108
-rw-r--r--usr.sbin/lpr/filters/Makefile7
-rw-r--r--usr.sbin/lpr/filters/lpf.c217
-rw-r--r--usr.sbin/lpr/lpc/Makefile12
-rw-r--r--usr.sbin/lpr/lpc/cmds.c1107
-rw-r--r--usr.sbin/lpr/lpc/cmdtab.c79
-rw-r--r--usr.sbin/lpr/lpc/extern.h58
-rw-r--r--usr.sbin/lpr/lpc/lpc.8174
-rw-r--r--usr.sbin/lpr/lpc/lpc.c277
-rw-r--r--usr.sbin/lpr/lpc/lpc.h45
-rw-r--r--usr.sbin/lpr/lpd/Makefile11
-rw-r--r--usr.sbin/lpr/lpd/extern.h39
-rw-r--r--usr.sbin/lpr/lpd/lpd.8249
-rw-r--r--usr.sbin/lpr/lpd/lpd.c507
-rw-r--r--usr.sbin/lpr/lpd/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/lpd/printjob.c1377
-rw-r--r--usr.sbin/lpr/lpd/recvjob.c358
-rw-r--r--usr.sbin/lpr/lpq/Makefile12
-rw-r--r--usr.sbin/lpr/lpq/lpq.1134
-rw-r--r--usr.sbin/lpr/lpq/lpq.c126
-rw-r--r--usr.sbin/lpr/lpr/Makefile12
-rw-r--r--usr.sbin/lpr/lpr/lpr.1256
-rw-r--r--usr.sbin/lpr/lpr/lpr.c744
-rw-r--r--usr.sbin/lpr/lprm/Makefile12
-rw-r--r--usr.sbin/lpr/lprm/lprm.1145
-rw-r--r--usr.sbin/lpr/lprm/lprm.c144
-rw-r--r--usr.sbin/lpr/lptest/Makefile6
-rw-r--r--usr.sbin/lpr/lptest/lptest.174
-rw-r--r--usr.sbin/lpr/lptest/lptest.c83
-rw-r--r--usr.sbin/lpr/pac/Makefile10
-rw-r--r--usr.sbin/lpr/pac/pac.8106
-rw-r--r--usr.sbin/lpr/pac/pac.c444
-rw-r--r--usr.sbin/lpr/runqueue/extern.h39
-rw-r--r--usr.sbin/lpr/runqueue/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/runqueue/printjob.c1377
-rw-r--r--usr.sbin/mtree/Makefile8
-rw-r--r--usr.sbin/mtree/compare.c271
-rw-r--r--usr.sbin/mtree/create.c290
-rw-r--r--usr.sbin/mtree/extern.h44
-rw-r--r--usr.sbin/mtree/misc.c125
-rw-r--r--usr.sbin/mtree/mtree.8249
-rw-r--r--usr.sbin/mtree/mtree.c146
-rw-r--r--usr.sbin/mtree/mtree.h88
-rw-r--r--usr.sbin/mtree/spec.c280
-rw-r--r--usr.sbin/mtree/verify.c202
-rw-r--r--usr.sbin/portmap/Makefile8
-rw-r--r--usr.sbin/portmap/portmap.8110
-rw-r--r--usr.sbin/portmap/portmap.c541
-rw-r--r--usr.sbin/pstat/Makefile10
-rw-r--r--usr.sbin/pstat/pstat.8321
-rw-r--r--usr.sbin/pstat/pstat.c1110
-rw-r--r--usr.sbin/pwd_mkdb/Makefile7
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.c122
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.h36
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.8128
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c387
-rw-r--r--usr.sbin/quot/quot.884
-rw-r--r--usr.sbin/quotaon/Makefile8
-rw-r--r--usr.sbin/quotaon/quotaon.8139
-rw-r--r--usr.sbin/quotaon/quotaon.c251
-rw-r--r--usr.sbin/repquota/Makefile6
-rw-r--r--usr.sbin/repquota/repquota.8103
-rw-r--r--usr.sbin/repquota/repquota.c379
-rw-r--r--usr.sbin/rmt/Makefile6
-rw-r--r--usr.sbin/rmt/rmt.8217
-rw-r--r--usr.sbin/rmt/rmt.c244
-rw-r--r--usr.sbin/rwhod/Makefile6
-rw-r--r--usr.sbin/rwhod/rwhod.8146
-rw-r--r--usr.sbin/rwhod/rwhod.c539
-rw-r--r--usr.sbin/sendmail/FAQ343
-rw-r--r--usr.sbin/sendmail/KNOWNBUGS131
-rw-r--r--usr.sbin/sendmail/Makefile24
-rw-r--r--usr.sbin/sendmail/READ_ME239
-rw-r--r--usr.sbin/sendmail/RELEASE_NOTES2556
-rw-r--r--usr.sbin/sendmail/cf/README1232
-rw-r--r--usr.sbin/sendmail/cf/cf/Makefile86
-rw-r--r--usr.sbin/sendmail/cf/cf/Makefile.dist85
-rw-r--r--usr.sbin/sendmail/cf/cf/alpha.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/auspex.mc42
-rw-r--r--usr.sbin/sendmail/cf/cf/chez.mc44
-rw-r--r--usr.sbin/sendmail/cf/cf/clientproto.mc49
-rw-r--r--usr.sbin/sendmail/cf/cf/cogsci.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/cs-exposed.mc40
-rw-r--r--usr.sbin/sendmail/cf/cf/cs-hidden.mc40
-rw-r--r--usr.sbin/sendmail/cf/cf/hpux-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/hpux-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/knecht.mc44
-rw-r--r--usr.sbin/sendmail/cf/cf/mail.cs.mc55
-rw-r--r--usr.sbin/sendmail/cf/cf/mail.eecs.mc54
-rw-r--r--usr.sbin/sendmail/cf/cf/osf1-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/osf1-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/python.mc52
-rw-r--r--usr.sbin/sendmail/cf/cf/riscos-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/s2k.mc42
-rw-r--r--usr.sbin/sendmail/cf/cf/sample.mc40
-rw-r--r--usr.sbin/sendmail/cf/cf/sleepy.mc43
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos3.5-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos3.5-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos4.1-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos4.1-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/tcpproto.mc50
-rw-r--r--usr.sbin/sendmail/cf/cf/ucbarpa.mc43
-rw-r--r--usr.sbin/sendmail/cf/cf/ucbvax.mc101
-rw-r--r--usr.sbin/sendmail/cf/cf/udb.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/ultrix4.1-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/ultrix4.1-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/uucpproto.mc49
-rw-r--r--usr.sbin/sendmail/cf/cf/vangogh.mc44
-rw-r--r--usr.sbin/sendmail/cf/domain/Berkeley.m442
-rw-r--r--usr.sbin/sendmail/cf/domain/cs.exposed.m440
-rw-r--r--usr.sbin/sendmail/cf/domain/cs.hidden.m438
-rw-r--r--usr.sbin/sendmail/cf/domain/eecs.hidden.m438
-rw-r--r--usr.sbin/sendmail/cf/domain/s2k.m438
-rw-r--r--usr.sbin/sendmail/cf/feature/allmasquerade.m441
-rw-r--r--usr.sbin/sendmail/cf/feature/always_add_domain.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/bitdomain.m449
-rw-r--r--usr.sbin/sendmail/cf/feature/domaintable.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/mailertable.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nocanonify.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nodns.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/notsticky.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nouucp.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nullclient.m461
-rw-r--r--usr.sbin/sendmail/cf/feature/redirect.m448
-rw-r--r--usr.sbin/sendmail/cf/feature/use_cw_file.m446
-rw-r--r--usr.sbin/sendmail/cf/feature/uucpdomain.m449
-rw-r--r--usr.sbin/sendmail/cf/hack/cssubdomain.m444
-rw-r--r--usr.sbin/sendmail/cf/m4/cf.m4149
-rw-r--r--usr.sbin/sendmail/cf/m4/nullrelay.m4302
-rw-r--r--usr.sbin/sendmail/cf/m4/proto.m4689
-rw-r--r--usr.sbin/sendmail/cf/m4/version.m439
-rw-r--r--usr.sbin/sendmail/cf/mailer/fax.m450
-rw-r--r--usr.sbin/sendmail/cf/mailer/local.m466
-rw-r--r--usr.sbin/sendmail/cf/mailer/pop.m453
-rw-r--r--usr.sbin/sendmail/cf/mailer/smtp.m4126
-rw-r--r--usr.sbin/sendmail/cf/mailer/usenet.m447
-rw-r--r--usr.sbin/sendmail/cf/mailer/uucp.m4172
-rw-r--r--usr.sbin/sendmail/cf/ostype/aix3.m440
-rw-r--r--usr.sbin/sendmail/cf/ostype/aux.m443
-rw-r--r--usr.sbin/sendmail/cf/ostype/bsd4.3.m439
-rw-r--r--usr.sbin/sendmail/cf/ostype/bsd4.4.m442
-rw-r--r--usr.sbin/sendmail/cf/ostype/bsdi1.0.m438
-rw-r--r--usr.sbin/sendmail/cf/ostype/dgux.m439
-rw-r--r--usr.sbin/sendmail/cf/ostype/domainos.m442
-rw-r--r--usr.sbin/sendmail/cf/ostype/dynix3.2.m439
-rw-r--r--usr.sbin/sendmail/cf/ostype/hpux.m444
-rw-r--r--usr.sbin/sendmail/cf/ostype/irix.m441
-rw-r--r--usr.sbin/sendmail/cf/ostype/linux.m438
-rw-r--r--usr.sbin/sendmail/cf/ostype/nextstep.m444
-rw-r--r--usr.sbin/sendmail/cf/ostype/osf1.m441
-rw-r--r--usr.sbin/sendmail/cf/ostype/riscos4.5.m442
-rw-r--r--usr.sbin/sendmail/cf/ostype/sco3.2.m445
-rw-r--r--usr.sbin/sendmail/cf/ostype/solaris2.m443
-rw-r--r--usr.sbin/sendmail/cf/ostype/sunos3.5.m437
-rw-r--r--usr.sbin/sendmail/cf/ostype/sunos4.1.m437
-rw-r--r--usr.sbin/sendmail/cf/ostype/svr4.m445
-rw-r--r--usr.sbin/sendmail/cf/ostype/ultrix4.1.m438
-rw-r--r--usr.sbin/sendmail/cf/sh/makeinfo.sh77
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.cogsci.m46
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.old.arpa.m44
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.ucbarpa.m41
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.ucbvax.m473
-rw-r--r--usr.sbin/sendmail/contrib/README10
-rw-r--r--usr.sbin/sendmail/contrib/bitdomain.c409
-rw-r--r--usr.sbin/sendmail/contrib/converting.sun.configs446
-rwxr-xr-xusr.sbin/sendmail/contrib/expn.pl1365
-rw-r--r--usr.sbin/sendmail/contrib/mail.local.linux205
-rw-r--r--usr.sbin/sendmail/contrib/mh.patch193
-rw-r--r--usr.sbin/sendmail/contrib/mmuegel2079
-rw-r--r--usr.sbin/sendmail/contrib/oldbind.compat.c79
-rw-r--r--usr.sbin/sendmail/contrib/rcpt-streaming305
-rw-r--r--usr.sbin/sendmail/contrib/xla/README207
-rw-r--r--usr.sbin/sendmail/contrib/xla/xla.c532
-rw-r--r--usr.sbin/sendmail/doc/Makefile5
-rw-r--r--usr.sbin/sendmail/doc/changes/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/changes/changes.me997
-rw-r--r--usr.sbin/sendmail/doc/changes/changes.ps1088
-rw-r--r--usr.sbin/sendmail/doc/intro/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/intro/intro.me1478
-rw-r--r--usr.sbin/sendmail/doc/intro/intro.ps1295
-rw-r--r--usr.sbin/sendmail/doc/op/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/op/op.me6921
-rw-r--r--usr.sbin/sendmail/doc/op/op.ps5477
-rw-r--r--usr.sbin/sendmail/doc/op/spell.ok324
-rw-r--r--usr.sbin/sendmail/doc/rfc/rfc819.txt1044
-rw-r--r--usr.sbin/sendmail/doc/rfc/rfc821.txt4050
-rw-r--r--usr.sbin/sendmail/doc/rfc/rfc822.txt2901
-rw-r--r--usr.sbin/sendmail/doc/usenix/Makefile12
-rw-r--r--usr.sbin/sendmail/doc/usenix/usenix.me1076
-rw-r--r--usr.sbin/sendmail/doc/usenix/usenix.ps1004
-rw-r--r--usr.sbin/sendmail/mailstats/Makefile8
-rw-r--r--usr.sbin/sendmail/mailstats/mailstats.c209
-rw-r--r--usr.sbin/sendmail/makemap/Makefile8
-rw-r--r--usr.sbin/sendmail/makemap/Makefile.dist81
-rw-r--r--usr.sbin/sendmail/makemap/makemap.8128
-rw-r--r--usr.sbin/sendmail/makemap/makemap.c373
-rw-r--r--usr.sbin/sendmail/praliases/Makefile9
-rw-r--r--usr.sbin/sendmail/praliases/Makefile.dist81
-rw-r--r--usr.sbin/sendmail/praliases/praliases.c132
-rw-r--r--usr.sbin/sendmail/src/Makefile42
-rw-r--r--usr.sbin/sendmail/src/Makefile.386BSD42
-rw-r--r--usr.sbin/sendmail/src/Makefile.AIX113
-rw-r--r--usr.sbin/sendmail/src/Makefile.AUX105
-rw-r--r--usr.sbin/sendmail/src/Makefile.BSD43123
-rw-r--r--usr.sbin/sendmail/src/Makefile.BSDI32
-rw-r--r--usr.sbin/sendmail/src/Makefile.CLIX115
-rw-r--r--usr.sbin/sendmail/src/Makefile.ConvexOS105
-rw-r--r--usr.sbin/sendmail/src/Makefile.DGUX101
-rw-r--r--usr.sbin/sendmail/src/Makefile.Dell113
-rw-r--r--usr.sbin/sendmail/src/Makefile.DomainOS123
-rw-r--r--usr.sbin/sendmail/src/Makefile.Dynix113
-rw-r--r--usr.sbin/sendmail/src/Makefile.FreeBSD50
-rw-r--r--usr.sbin/sendmail/src/Makefile.HP-UX105
-rw-r--r--usr.sbin/sendmail/src/Makefile.IRIX109
-rw-r--r--usr.sbin/sendmail/src/Makefile.Linux120
-rw-r--r--usr.sbin/sendmail/src/Makefile.Mach386107
-rw-r--r--usr.sbin/sendmail/src/Makefile.NCR3000109
-rw-r--r--usr.sbin/sendmail/src/Makefile.NeXT114
-rw-r--r--usr.sbin/sendmail/src/Makefile.NetBSD46
-rw-r--r--usr.sbin/sendmail/src/Makefile.OSF1109
-rw-r--r--usr.sbin/sendmail/src/Makefile.PTX114
-rw-r--r--usr.sbin/sendmail/src/Makefile.RISCos117
-rw-r--r--usr.sbin/sendmail/src/Makefile.SCO104
-rw-r--r--usr.sbin/sendmail/src/Makefile.SVR4113
-rw-r--r--usr.sbin/sendmail/src/Makefile.Solaris115
-rw-r--r--usr.sbin/sendmail/src/Makefile.SunOS111
-rw-r--r--usr.sbin/sendmail/src/Makefile.SunOS.4.0.3113
-rw-r--r--usr.sbin/sendmail/src/Makefile.SunOS.5.x115
-rw-r--r--usr.sbin/sendmail/src/Makefile.Titan114
-rw-r--r--usr.sbin/sendmail/src/Makefile.ULTRIX107
-rw-r--r--usr.sbin/sendmail/src/Makefile.UMAX114
-rw-r--r--usr.sbin/sendmail/src/Makefile.Utah40
-rw-r--r--usr.sbin/sendmail/src/Makefile.dist107
-rw-r--r--usr.sbin/sendmail/src/READ_ME872
-rw-r--r--usr.sbin/sendmail/src/TODO287
-rw-r--r--usr.sbin/sendmail/src/TRACEFLAGS64
-rw-r--r--usr.sbin/sendmail/src/alias.c770
-rw-r--r--usr.sbin/sendmail/src/aliases.5106
-rw-r--r--usr.sbin/sendmail/src/arpadate.c173
-rw-r--r--usr.sbin/sendmail/src/clock.c276
-rw-r--r--usr.sbin/sendmail/src/collect.c579
-rw-r--r--usr.sbin/sendmail/src/conf.c2377
-rw-r--r--usr.sbin/sendmail/src/conf.h1191
-rw-r--r--usr.sbin/sendmail/src/convtime.c197
-rw-r--r--usr.sbin/sendmail/src/daemon.c1547
-rw-r--r--usr.sbin/sendmail/src/deliver.c2409
-rw-r--r--usr.sbin/sendmail/src/domain.c769
-rw-r--r--usr.sbin/sendmail/src/envelope.c777
-rw-r--r--usr.sbin/sendmail/src/err.c561
-rw-r--r--usr.sbin/sendmail/src/headers.c1192
-rw-r--r--usr.sbin/sendmail/src/macro.c279
-rw-r--r--usr.sbin/sendmail/src/mailq.188
-rw-r--r--usr.sbin/sendmail/src/mailstats.h49
-rw-r--r--usr.sbin/sendmail/src/main.c1479
-rw-r--r--usr.sbin/sendmail/src/makesendmail113
-rw-r--r--usr.sbin/sendmail/src/map.c1339
-rw-r--r--usr.sbin/sendmail/src/mci.c398
-rw-r--r--usr.sbin/sendmail/src/newaliases.168
-rw-r--r--usr.sbin/sendmail/src/parseaddr.c1964
-rw-r--r--usr.sbin/sendmail/src/pathnames.h46
-rw-r--r--usr.sbin/sendmail/src/queue.c1571
-rw-r--r--usr.sbin/sendmail/src/readcf.c1681
-rw-r--r--usr.sbin/sendmail/src/recipient.c1059
-rw-r--r--usr.sbin/sendmail/src/savemail.c833
-rw-r--r--usr.sbin/sendmail/src/sendmail.8501
-rw-r--r--usr.sbin/sendmail/src/sendmail.h973
-rw-r--r--usr.sbin/sendmail/src/sendmail.hf58
-rw-r--r--usr.sbin/sendmail/src/srvrsmtp.c1032
-rw-r--r--usr.sbin/sendmail/src/stab.c166
-rw-r--r--usr.sbin/sendmail/src/stats.c130
-rw-r--r--usr.sbin/sendmail/src/sysexits.c67
-rw-r--r--usr.sbin/sendmail/src/trace.c131
-rw-r--r--usr.sbin/sendmail/src/udb.c985
-rw-r--r--usr.sbin/sendmail/src/useful.h77
-rw-r--r--usr.sbin/sendmail/src/usersmtp.c905
-rw-r--r--usr.sbin/sendmail/src/util.c1467
-rw-r--r--usr.sbin/sendmail/src/version.c39
-rw-r--r--usr.sbin/sliplogin/Makefile9
-rw-r--r--usr.sbin/sliplogin/pathnames.h46
-rw-r--r--usr.sbin/sliplogin/slip.hosts11
-rw-r--r--usr.sbin/sliplogin/slip.login12
-rw-r--r--usr.sbin/sliplogin/sliplogin.8220
-rw-r--r--usr.sbin/sliplogin/sliplogin.c381
-rw-r--r--usr.sbin/sysctl/Makefile6
-rw-r--r--usr.sbin/sysctl/pathconf.c229
-rw-r--r--usr.sbin/sysctl/sysctl.8208
-rw-r--r--usr.sbin/sysctl/sysctl.c572
-rw-r--r--usr.sbin/syslogd/Makefile9
-rw-r--r--usr.sbin/syslogd/pathnames.h40
-rw-r--r--usr.sbin/syslogd/syslog.conf.5224
-rw-r--r--usr.sbin/syslogd/syslogd.8122
-rw-r--r--usr.sbin/syslogd/syslogd.c1131
-rw-r--r--usr.sbin/timed/Makefile5
-rw-r--r--usr.sbin/timed/SMM.doc/timed/Makefile11
-rw-r--r--usr.sbin/timed/SMM.doc/timed/date53
-rw-r--r--usr.sbin/timed/SMM.doc/timed/loop54
-rw-r--r--usr.sbin/timed/SMM.doc/timed/spell.ok34
-rw-r--r--usr.sbin/timed/SMM.doc/timed/time53
-rw-r--r--usr.sbin/timed/SMM.doc/timed/timed.ms504
-rw-r--r--usr.sbin/timed/SMM.doc/timed/unused53
-rw-r--r--usr.sbin/timed/SMM.doc/timedop/Makefile7
-rw-r--r--usr.sbin/timed/SMM.doc/timedop/timed.ms279
-rw-r--r--usr.sbin/timed/timed/CHANGES144
-rw-r--r--usr.sbin/timed/timed/Makefile13
-rw-r--r--usr.sbin/timed/timed/acksend.c132
-rw-r--r--usr.sbin/timed/timed/byteorder.c86
-rw-r--r--usr.sbin/timed/timed/candidate.c167
-rw-r--r--usr.sbin/timed/timed/cksum.c87
-rw-r--r--usr.sbin/timed/timed/correct.c294
-rw-r--r--usr.sbin/timed/timed/extern.h89
-rw-r--r--usr.sbin/timed/timed/globals.h186
-rw-r--r--usr.sbin/timed/timed/master.c907
-rw-r--r--usr.sbin/timed/timed/measure.c353
-rw-r--r--usr.sbin/timed/timed/networkdelta.c264
-rw-r--r--usr.sbin/timed/timed/pathnames.h44
-rw-r--r--usr.sbin/timed/timed/readmsg.c488
-rw-r--r--usr.sbin/timed/timed/slave.c715
-rw-r--r--usr.sbin/timed/timed/timed.8219
-rw-r--r--usr.sbin/timed/timed/timed.c980
-rw-r--r--usr.sbin/timed/timedc/Makefile11
-rw-r--r--usr.sbin/timed/timedc/cmds.c526
-rw-r--r--usr.sbin/timed/timedc/cmdtab.c57
-rw-r--r--usr.sbin/timed/timedc/extern.h52
-rw-r--r--usr.sbin/timed/timedc/timedc.8145
-rw-r--r--usr.sbin/timed/timedc/timedc.c261
-rw-r--r--usr.sbin/timed/timedc/timedc.h66
-rw-r--r--usr.sbin/traceroute/Makefile8
-rw-r--r--usr.sbin/traceroute/README126
-rw-r--r--usr.sbin/traceroute/mean.awk50
-rw-r--r--usr.sbin/traceroute/median.awk67
-rw-r--r--usr.sbin/traceroute/traceroute.8336
-rw-r--r--usr.sbin/traceroute/traceroute.c835
-rw-r--r--usr.sbin/trpt/Makefile8
-rw-r--r--usr.sbin/trpt/trpt.8151
-rw-r--r--usr.sbin/trpt/trpt.c414
-rw-r--r--usr.sbin/trsp/Makefile9
-rw-r--r--usr.sbin/trsp/trsp.8141
-rw-r--r--usr.sbin/trsp/trsp.c433
-rw-r--r--usr.sbin/update/Makefile6
-rw-r--r--usr.sbin/update/update.874
-rw-r--r--usr.sbin/update/update.c75
-rw-r--r--usr.sbin/vipw/Makefile7
-rw-r--r--usr.sbin/vipw/pw_util.c204
-rw-r--r--usr.sbin/vipw/pw_util.h42
-rw-r--r--usr.sbin/vipw/vipw.893
-rw-r--r--usr.sbin/vipw/vipw.c127
657 files changed, 183029 insertions, 0 deletions
diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c
new file mode 100644
index 000000000000..3093ac257e5b
--- /dev/null
+++ b/lib/libc/gen/pw_scan.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1990, 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.
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pw_scan.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+/*
+ * This module is used to "verify" password entries by chpass(1) and
+ * pwd_mkdb(8).
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pw_scan.h"
+
+int
+pw_scan(bp, pw)
+ char *bp;
+ struct passwd *pw;
+{
+ long id;
+ int root;
+ char *p, *sh;
+
+ if (!(pw->pw_name = strsep(&bp, ":"))) /* login */
+ goto fmt;
+ root = !strcmp(pw->pw_name, "root");
+
+ if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */
+ goto fmt;
+
+ if (!(p = strsep(&bp, ":"))) /* uid */
+ goto fmt;
+ id = atol(p);
+ if (root && id) {
+ warnx("root uid should be 0");
+ return (0);
+ }
+ if (id > USHRT_MAX) {
+ warnx("%s > max uid value (%d)", p, USHRT_MAX);
+ return (0);
+ }
+ pw->pw_uid = id;
+
+ if (!(p = strsep(&bp, ":"))) /* gid */
+ goto fmt;
+ id = atol(p);
+ if (id > USHRT_MAX) {
+ warnx("%s > max gid value (%d)", p, USHRT_MAX);
+ return (0);
+ }
+ pw->pw_gid = id;
+
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ pw->pw_change = atol(p);
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ pw->pw_expire = atol(p);
+ pw->pw_gecos = strsep(&bp, ":"); /* gecos */
+ pw->pw_dir = strsep(&bp, ":"); /* directory */
+ if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */
+ goto fmt;
+
+ p = pw->pw_shell;
+ if (root && *p) /* empty == /bin/sh */
+ for (setusershell();;) {
+ if (!(sh = getusershell())) {
+ warnx("warning, unknown root shell");
+ break;
+ }
+ if (!strcmp(p, sh))
+ break;
+ }
+
+ if (p = strsep(&bp, ":")) { /* too many */
+fmt: warnx("corrupted entry");
+ return (0);
+ }
+ return (1);
+}
diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h
new file mode 100644
index 000000000000..d1d4bc1ef631
--- /dev/null
+++ b/lib/libc/gen/pw_scan.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 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.
+ * 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.
+ *
+ * @(#)pw_scan.h 8.1 (Berkeley) 4/1/94
+ */
+
+extern int pw_scan __P((char *, struct passwd *));
diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c
new file mode 100644
index 000000000000..9873f74c3a31
--- /dev/null
+++ b/lib/libutil/pw_util.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 1990, 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.
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+/*
+ * This file is used by all the "password" programs; vipw(8), chpass(1),
+ * and passwd(1).
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+extern char *tempname;
+
+void
+pw_init()
+{
+ struct rlimit rlim;
+
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &rlim);
+ (void)setrlimit(RLIMIT_FSIZE, &rlim);
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ (void)setrlimit(RLIMIT_RSS, &rlim);
+
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ /* Turn off signals. */
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGTSTP, SIG_IGN);
+ (void)signal(SIGTTOU, SIG_IGN);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+}
+
+static int lockfd;
+
+int
+pw_lock()
+{
+ /*
+ * If the master password file doesn't exist, the system is hosed.
+ * Might as well try to build one. Set the close-on-exec bit so
+ * that users can't get at the encrypted passwords while editing.
+ * Open should allow flock'ing the file; see 4.4BSD. XXX
+ */
+ lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
+ if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
+ err(1, "%s", _PATH_MASTERPASSWD);
+ if (flock(lockfd, LOCK_EX|LOCK_NB))
+ errx(1, "the password db file is busy");
+ return (lockfd);
+}
+
+int
+pw_tmp()
+{
+ static char path[MAXPATHLEN] = _PATH_MASTERPASSWD;
+ int fd;
+ char *p;
+
+ if (p = strrchr(path, '/'))
+ ++p;
+ else
+ p = path;
+ strcpy(p, "pw.XXXXXX");
+ if ((fd = mkstemp(path)) == -1)
+ err(1, "%s", path);
+ tempname = path;
+ return (fd);
+}
+
+int
+pw_mkdb()
+{
+ int pstat;
+ pid_t pid;
+
+ warnx("rebuilding the database...");
+ (void)fflush(stderr);
+ if (!(pid = vfork())) {
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL);
+ pw_error(_PATH_PWD_MKDB, 1, 1);
+ }
+ pid = waitpid(pid, &pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ return (0);
+ warnx("done");
+ return (1);
+}
+
+void
+pw_edit(notsetuid)
+ int notsetuid;
+{
+ int pstat;
+ pid_t pid;
+ char *p, *editor;
+
+ if (!(editor = getenv("EDITOR")))
+ editor = _PATH_VI;
+ if (p = strrchr(editor, '/'))
+ ++p;
+ else
+ p = editor;
+
+ if (!(pid = vfork())) {
+ if (notsetuid) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tempname, NULL);
+ _exit(1);
+ }
+ pid = waitpid(pid, (int *)&pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ pw_error(editor, 1, 1);
+}
+
+void
+pw_prompt()
+{
+ int c;
+
+ (void)printf("re-edit the password file? [y]: ");
+ (void)fflush(stdout);
+ c = getchar();
+ if (c != EOF && c != '\n')
+ while (getchar() != '\n');
+ if (c == 'n')
+ pw_error(NULL, 0, 0);
+}
+
+void
+pw_error(name, err, eval)
+ char *name;
+ int err, eval;
+{
+ if (err)
+ warn(name);
+
+ warnx("%s: unchanged", _PATH_MASTERPASSWD);
+ (void)unlink(tempname);
+ exit(eval);
+}
diff --git a/sbin/sysctl/Makefile b/sbin/sysctl/Makefile
new file mode 100644
index 000000000000..40d12d2fede4
--- /dev/null
+++ b/sbin/sysctl/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= sysctl
+MAN8= sysctl.0
+
+.include <bsd.prog.mk>
diff --git a/sbin/sysctl/pathconf.c b/sbin/sysctl/pathconf.c
new file mode 100644
index 000000000000..4b60ccfb1c09
--- /dev/null
+++ b/sbin/sysctl/pathconf.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1993
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pathconf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PC_NAMES { \
+ { 0, 0 }, \
+ { "link_max", CTLTYPE_INT }, \
+ { "max_canon", CTLTYPE_INT }, \
+ { "max_input", CTLTYPE_INT }, \
+ { "name_max", CTLTYPE_INT }, \
+ { "path_max", CTLTYPE_INT }, \
+ { "pipe_buf", CTLTYPE_INT }, \
+ { "chown_restricted", CTLTYPE_INT }, \
+ { "no_trunc", CTLTYPE_INT }, \
+ { "vdisable", CTLTYPE_INT }, \
+}
+#define PC_MAXID 10
+
+struct ctlname pcnames[] = PC_NAMES;
+char names[BUFSIZ];
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list pclist = { pcnames, PC_MAXID };
+
+int Aflag, aflag, nflag, wflag, stdinflag;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ char *path;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "Aan")) != EOF) {
+ switch (ch) {
+
+ case 'A':
+ Aflag = 1;
+ break;
+
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+ path = *argv++;
+ if (strcmp(path, "-") == 0)
+ stdinflag = 1;
+ argc--;
+ if (Aflag || aflag) {
+ listall(path, &pclist);
+ exit(0);
+ }
+ if (argc == 0)
+ usage();
+ while (argc-- > 0)
+ parse(path, *argv, 1);
+ exit(0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+listall(path, lp)
+ char *path;
+ struct list *lp;
+{
+ int lvl2;
+
+ if (lp->list == 0)
+ return;
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ parse(path, lp->list[lvl2].ctl_name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into an index.
+ * Lookup and print out the attribute if it exists.
+ */
+parse(pathname, string, flags)
+ char *pathname;
+ char *string;
+ int flags;
+{
+ int indx, value;
+ char *bufp, buf[BUFSIZ];
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((indx = findname(string, "top", &bufp, &pclist)) == -1)
+ return;
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
+ return;
+ }
+ if (stdinflag)
+ value = fpathconf(0, indx);
+ else
+ value = pathconf(pathname, indx);
+ if (value == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case EOPNOTSUPP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%d\n", value);
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ return (-1);
+ }
+ return (i);
+}
+
+usage()
+{
+
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n",
+ "pathname [-n] variable ...",
+ "pathname [-n] -a", "pathname [-n] -A");
+ exit(1);
+}
diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8
new file mode 100644
index 000000000000..9def5093a221
--- /dev/null
+++ b/sbin/sysctl/sysctl.8
@@ -0,0 +1,208 @@
+.\" Copyright (c) 1993
+.\" 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.
+.\"
+.\" @(#)sysctl.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd "June 6, 1993"
+.Dt SYSCTL 8
+.Os
+.Sh NAME
+.Nm sysctl
+.Nd get or set kernel state
+.Sh SYNOPSIS
+.Nm sysctl
+.Op Fl n
+.Ar name ...
+.Nm sysctl
+.Op Fl n
+.Fl w
+.Ar name=value ...
+.Nm sysctl
+.Op Fl n
+.Fl aA
+.Sh DESCRIPTION
+The
+.Nm sysctl
+utility retrieves kernel state and allows processes with
+appropriate privilege to set kernel state.
+The state to be retrieved or set is described using a
+``Management Information Base'' (``MIB'') style name,
+described as a dotted set of components.
+The
+.Fl a
+flag can be used to list all the currently available string or integer values.
+The
+.Fl A
+flag will list all the known MIB names including tables.
+Those with string or integer values will be printed as with the
+.Fl a
+flag; for the table values,
+the name of the utility to retrieve them is given.
+.Pp
+The
+.Fl n
+flag specifies that the printing of the field name should be
+suppressed and that only its value should be output.
+This flag is useful for setting shell variables.
+For example, to save the pagesize in variable psize, use:
+.Bd -literal -offset indent -compact
+set psize=`sysctl -n hw.pagesize`
+.Ed
+.Pp
+If just a MIB style name is given,
+the corresponding value is retrieved.
+If a value is to be set, the
+.Fl w
+flag must be specified and the MIB name followed
+by an equal sign and the new value to be used.
+.Pp
+The information available from
+.Nm sysctl
+consists of integers, strings, and tables.
+The tabular information can only be retrieved by special
+purpose programs such as
+.Nm ps ,
+.Nm systat ,
+and
+.Nm netstat .
+The string and integer information is summaried below.
+For a detailed description of these variable see
+.Xr sysctl 3 .
+The changeable column indicates whether a process with appropriate
+privilege can change the value.
+.Bl -column net.inet.ip.forwardingxxxxxx integerxxx
+.It Sy Name Type Changeable
+.It kern.ostype string no
+.It kern.osrelease string no
+.It kern.osrevision integer no
+.It kern.version string no
+.It kern.maxvnodes integer yes
+.It kern.maxproc integer yes
+.It kern.maxfiles integer yes
+.It kern.argmax integer no
+.It kern.securelevel integer raise only
+.It kern.hostname string yes
+.It kern.hostid integer yes
+.It kern.clockrate struct no
+.It kern.posix1version integer no
+.It kern.ngroups integer no
+.It kern.job_control integer no
+.It kern.saved_ids integer no
+.It kern.link_max integer no
+.It kern.max_canon integer no
+.It kern.max_input integer no
+.It kern.name_max integer no
+.It kern.path_max integer no
+.It kern.pipe_buf integer no
+.It kern.chown_restricted integer no
+.It kern.no_trunc integer no
+.It kern.vdisable integer no
+.It kern.boottime struct no
+.It vm.loadavg struct no
+.It machdep.console_device dev_t no
+.It net.inet.ip.forwarding integer yes
+.It net.inet.ip.redirect integer yes
+.It net.inet.ip.ttl integer yes
+.It net.inet.icmp.maskrepl integer yes
+.It net.inet.udp.checksum integer yes
+.It hw.machine string no
+.It hw.model string no
+.It hw.ncpu integer no
+.It hw.byteorder integer no
+.It hw.physmem integer no
+.It hw.usermem integer no
+.It hw.pagesize integer no
+.It user.cs_path string no
+.It user.bc_base_max integer no
+.It user.bc_dim_max integer no
+.It user.bc_scale_max integer no
+.It user.bc_string_max integer no
+.It user.coll_weights_max integer no
+.It user.expr_nest_max integer no
+.It user.line_max integer no
+.It user.re_dup_max integer no
+.It user.posix2_version integer no
+.It user.posix2_c_bind integer no
+.It user.posix2_c_dev integer no
+.It user.posix2_char_term integer no
+.It user.posix2_fort_dev integer no
+.It user.posix2_fort_run integer no
+.It user.posix2_localedef integer no
+.It user.posix2_sw_dev integer no
+.It user.posix2_upe integer no
+.El
+.Sh EXAMPLES
+.Pp
+For example, to retrieve the maximum number of processes allowed
+in the system, one would use the follow request:
+.Bd -literal -offset indent -compact
+sysctl kern.maxproc
+.Ed
+.Pp
+To set the maximum number of processes allowed
+in the system to 1000, one would use the follow request:
+.Bd -literal -offset indent -compact
+sysctl -w kern.maxproc=1000
+.Ed
+.Pp
+Information about the system clock rate may be obtained with:
+.Bd -literal -offset indent -compact
+sysctl kern.clockrate
+.Ed
+.Pp
+Information about the load average history may be obtained with
+.Bd -literal -offset indent -compact
+sysctl vm.loadavg
+.Ed
+.Sh FILES
+.Bl -tag -width <netinet/icmpXvar.h> -compact
+.It Pa <sys/sysctl.h>
+definitions for top level identifiers, second level kernel and hardware
+identifiers, and user level identifiers
+.It Pa <sys/socket.h>
+definitions for second level network identifiers
+.It Pa <sys/gmon.h>
+definitions for third level profiling identifiers
+.It Pa <vm/vm_param.h>
+definitions for second level virtual memory identifiers
+.It Pa <netinet/in.h>
+definitions for third level Internet identifiers and
+fourth level IP identifiers
+.It Pa <netinet/icmp_var.h>
+definitions for fourth level ICMP identifiers
+.It Pa <netinet/udp_var.h>
+definitions for fourth level UDP identifiers
+.El
+.Sh SEE ALSO
+.Xr sysctl 3
+.Sh HISTORY
+.Nm sysctl
+first appeared in 4.4BSD.
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c
new file mode 100644
index 000000000000..a3426868b4f2
--- /dev/null
+++ b/sbin/sysctl/sysctl.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 1993
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/gmon.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <vm/vm_param.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct ctlname topname[] = CTL_NAMES;
+struct ctlname kernname[] = CTL_KERN_NAMES;
+struct ctlname vmname[] = CTL_VM_NAMES;
+struct ctlname netname[] = CTL_NET_NAMES;
+struct ctlname hwname[] = CTL_HW_NAMES;
+struct ctlname username[] = CTL_USER_NAMES;
+struct ctlname debugname[CTL_DEBUG_MAXID];
+#ifdef CTL_MACHDEP_NAMES
+struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
+#endif
+char names[BUFSIZ];
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list toplist = { topname, CTL_MAXID };
+struct list secondlevel[] = {
+ { 0, 0 }, /* CTL_UNSPEC */
+ { kernname, KERN_MAXID }, /* CTL_KERN */
+ { vmname, VM_MAXID }, /* CTL_VM */
+ { 0, 0 }, /* CTL_FS */
+ { netname, NET_MAXID }, /* CTL_NET */
+ { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
+ { hwname, HW_MAXID }, /* CTL_HW */
+#ifdef CTL_MACHDEP_NAMES
+ { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
+#else
+ { 0, 0 }, /* CTL_MACHDEP */
+#endif
+ { username, USER_MAXID }, /* CTL_USER_NAMES */
+};
+
+int Aflag, aflag, nflag, wflag;
+
+/*
+ * Variables requiring special processing.
+ */
+#define CLOCK 0x00000001
+#define BOOTTIME 0x00000002
+#define CONSDEV 0x00000004
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, lvl1;
+
+ while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
+ switch (ch) {
+
+ case 'A':
+ Aflag = 1;
+ break;
+
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ case 'w':
+ wflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (Aflag || aflag) {
+ debuginit();
+ for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
+ listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
+ exit(0);
+ }
+ if (argc == 0)
+ usage();
+ while (argc-- > 0)
+ parse(*argv, 1);
+ exit(0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+listall(prefix, lp)
+ char *prefix;
+ struct list *lp;
+{
+ int lvl2;
+ char *cp, name[BUFSIZ];
+
+ if (lp->list == 0)
+ return;
+ strcpy(name, prefix);
+ cp = &name[strlen(name)];
+ *cp++ = '.';
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ strcpy(cp, lp->list[lvl2].ctl_name);
+ parse(name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+parse(string, flags)
+ char *string;
+ int flags;
+{
+ int indx, type, state, size, len;
+ int special = 0;
+ void *newval = 0;
+ int intval, newsize = 0;
+ quad_t quadval;
+ struct list *lp;
+ int mib[CTL_MAXNAME];
+ char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((cp = strchr(string, '=')) != NULL) {
+ if (!wflag) {
+ fprintf(stderr, "Must specify -w to set variables\n");
+ exit(2);
+ }
+ *strchr(buf, '=') = '\0';
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ newval = cp;
+ newsize = strlen(cp);
+ }
+ if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
+ return;
+ mib[0] = indx;
+ if (indx == CTL_DEBUG)
+ debuginit();
+ lp = &secondlevel[indx];
+ if (lp->list == 0) {
+ fprintf(stderr, "%s: class is not implemented\n",
+ topname[indx]);
+ return;
+ }
+ if (bufp == NULL) {
+ listall(topname[indx].ctl_name, lp);
+ return;
+ }
+ if ((indx = findname(string, "second", &bufp, lp)) == -1)
+ return;
+ mib[1] = indx;
+ type = lp->list[indx].ctl_type;
+ len = 2;
+ switch (mib[0]) {
+
+ case CTL_KERN:
+ switch (mib[1]) {
+ case KERN_PROF:
+ mib[2] = GPROF_STATE;
+ size = sizeof state;
+ if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
+ if (flags == 0)
+ return;
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stderr,
+ "kernel is not compiled for profiling\n");
+ return;
+ }
+ if (!nflag)
+ fprintf(stdout, "%s: %s\n", string,
+ state == GMON_PROF_OFF ? "off" : "running");
+ return;
+ case KERN_VNODE:
+ case KERN_FILE:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use pstat to view %s information\n", string);
+ return;
+ case KERN_PROC:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use ps to view %s information\n", string);
+ return;
+ case KERN_CLOCKRATE:
+ special |= CLOCK;
+ break;
+ case KERN_BOOTTIME:
+ special |= BOOTTIME;
+ break;
+ }
+ break;
+
+ case CTL_HW:
+ break;
+
+ case CTL_VM:
+ if (mib[1] == VM_LOADAVG) {
+ double loads[3];
+
+ getloadavg(loads, 3);
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout, "%.2f %.2f %.2f\n",
+ loads[0], loads[1], loads[2]);
+ return;
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use vmstat or systat to view %s information\n", string);
+ return;
+
+ case CTL_NET:
+ if (mib[1] == PF_INET) {
+ len = sysctl_inet(string, &bufp, mib, flags, &type);
+ if (len >= 0)
+ break;
+ return;
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr, "Use netstat to view %s information\n", string);
+ return;
+
+ case CTL_DEBUG:
+ mib[2] = CTL_DEBUG_VALUE;
+ len = 3;
+ break;
+
+ case CTL_MACHDEP:
+#ifdef CPU_CONSDEV
+ if (mib[1] == CPU_CONSDEV)
+ special |= CONSDEV;
+#endif
+ break;
+
+ case CTL_FS:
+ case CTL_USER:
+ break;
+
+ default:
+ fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
+ return;
+
+ }
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
+ return;
+ }
+ if (newsize > 0) {
+ switch (type) {
+ case CTLTYPE_INT:
+ intval = atoi(newval);
+ newval = &intval;
+ newsize = sizeof intval;
+ break;
+
+ case CTLTYPE_QUAD:
+ sscanf(newval, "%qd", &quadval);
+ newval = &quadval;
+ newsize = sizeof quadval;
+ break;
+ }
+ }
+ size = BUFSIZ;
+ if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case EOPNOTSUPP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (special & CLOCK) {
+ struct clockinfo *clkp = (struct clockinfo *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout,
+ "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
+ clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
+ return;
+ }
+ if (special & BOOTTIME) {
+ struct timeval *btp = (struct timeval *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ ctime(&btp->tv_sec));
+ else
+ fprintf(stdout, "%d\n", btp->tv_sec);
+ return;
+ }
+ if (special & CONSDEV) {
+ dev_t dev = *(dev_t *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ devname(dev, S_IFCHR));
+ else
+ fprintf(stdout, "0x%x\n", dev);
+ return;
+ }
+ switch (type) {
+ case CTLTYPE_INT:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%d\n", *(int *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %d -> ", string,
+ *(int *)buf);
+ fprintf(stdout, "%d\n", *(int *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRING:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%s\n", buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %s -> ", string, buf);
+ fprintf(stdout, "%s\n", newval);
+ }
+ return;
+
+ case CTLTYPE_QUAD:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%qd\n", *(quad_t *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %qd -> ", string,
+ *(quad_t *)buf);
+ fprintf(stdout, "%qd\n", *(quad_t *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRUCT:
+ fprintf(stderr, "%s: unknown structure returned\n",
+ string);
+ return;
+
+ default:
+ case CTLTYPE_NODE:
+ fprintf(stderr, "%s: unknown type returned\n",
+ string);
+ return;
+ }
+}
+
+/*
+ * Initialize the set of debugging names
+ */
+debuginit()
+{
+ int mib[3], size, loc, i;
+
+ if (secondlevel[CTL_DEBUG].list != 0)
+ return;
+ secondlevel[CTL_DEBUG].list = debugname;
+ mib[0] = CTL_DEBUG;
+ mib[2] = CTL_DEBUG_NAME;
+ for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
+ mib[1] = i;
+ size = BUFSIZ - loc;
+ if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
+ continue;
+ debugname[i].ctl_name = &names[loc];
+ debugname[i].ctl_type = CTLTYPE_INT;
+ loc += size;
+ }
+}
+
+struct ctlname inetname[] = CTL_IPPROTO_NAMES;
+struct ctlname ipname[] = IPCTL_NAMES;
+struct ctlname icmpname[] = ICMPCTL_NAMES;
+struct ctlname udpname[] = UDPCTL_NAMES;
+struct list inetlist = { inetname, IPPROTO_MAXID };
+struct list inetvars[] = {
+ { ipname, IPCTL_MAXID }, /* ip */
+ { icmpname, ICMPCTL_MAXID }, /* icmp */
+ { 0, 0 }, /* igmp */
+ { 0, 0 }, /* ggmp */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }, /* tcp */
+ { 0, 0 },
+ { 0, 0 }, /* egp */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }, /* pup */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { udpname, UDPCTL_MAXID }, /* udp */
+};
+
+/*
+ * handle internet requests
+ */
+sysctl_inet(string, bufpp, mib, flags, typep)
+ char *string;
+ char **bufpp;
+ int mib[];
+ int flags;
+ int *typep;
+{
+ struct list *lp;
+ int indx;
+
+ if (*bufpp == NULL) {
+ listall(string, &inetlist);
+ return (-1);
+ }
+ if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
+ return (-1);
+ mib[2] = indx;
+ if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
+ lp = &inetvars[indx];
+ else if (!flags)
+ return (-1);
+ else {
+ fprintf(stderr, "%s: no variables defined for this protocol\n",
+ string);
+ return (-1);
+ }
+ if (*bufpp == NULL) {
+ listall(string, lp);
+ return (-1);
+ }
+ if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
+ return (-1);
+ mib[3] = indx;
+ *typep = lp->list[indx].ctl_type;
+ return (4);
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ return (-1);
+ }
+ return (i);
+}
+
+usage()
+{
+
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
+ "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
+ "sysctl [-n] -a", "sysctl [-n] -A");
+ exit(1);
+}
diff --git a/secure/usr.sbin/sendmail/Makefile b/secure/usr.sbin/sendmail/Makefile
new file mode 100644
index 000000000000..3b21e37d6324
--- /dev/null
+++ b/secure/usr.sbin/sendmail/Makefile
@@ -0,0 +1,24 @@
+# @(#)Makefile 8.4 (Berkeley) 4/22/94
+
+SUBDIR= src mailstats makemap praliases cf/cf
+FTPDIR= barad-dur:/disks/barad-dur/ftp/sendmail/.
+VER= XX
+
+tar: Files.base Files.cf Files.misc Files.xdoc
+ (cd src; ${MAKE})
+ (cd doc; PRINTER=ps ${MAKE})
+ (cd doc; chmod 444 op/op.ps intro/intro.ps usenix/usenix.ps)
+ (cd cf/cf; ${MAKE})
+ pax -w -x tar -L -f sendmail.${VER}.base.tar `grep -v ^# Files.base`
+ compress sendmail.${VER}.base.tar
+ pax -w -x tar -L -f sendmail.${VER}.cf.tar `grep -v ^# Files.cf`
+ compress sendmail.${VER}.cf.tar
+ pax -w -x tar -L -f sendmail.${VER}.misc.tar `grep -v ^# Files.misc`
+ compress sendmail.${VER}.misc.tar
+ pax -w -x tar -L -f sendmail.${VER}.xdoc.tar `grep -v ^# Files.xdoc`
+ compress sendmail.${VER}.xdoc.tar
+
+ftp: sendmail.${VER}.base.tar.Z sendmail.${VER}.cf.tar.Z sendmail.${VER}.misc.tar.Z sendmail.${VER}.xdoc.tar.Z
+ rcp sendmail.${VER}.*.tar.Z RELEASE_NOTES FAQ KNOWNBUGS ${FTPDIR}
+
+.include <bsd.subdir.mk>
diff --git a/share/examples/sliplogin/slip.hosts b/share/examples/sliplogin/slip.hosts
new file mode 100644
index 000000000000..f6ebf4095605
--- /dev/null
+++ b/share/examples/sliplogin/slip.hosts
@@ -0,0 +1,11 @@
+# @(#)slip.hosts 8.1 (Berkeley) 6/6/93
+#
+# login local-addr remote-addr mask opt1 opt2
+# (normal,compress,noicmp)
+#
+Schez vangogh chez 0xffffff00 compress
+Sjun vangogh 128.32.130.36 0xffffff00 normal
+Sleconte vangogh leconte 0xffffff00 compress
+Sleeb vangogh leeb 0xffffff00 compress
+Smjk vangogh pissaro-sl 0xffffff00 compress
+Soxford vangogh oxford 0xffffff00 compress
diff --git a/share/examples/sliplogin/slip.login b/share/examples/sliplogin/slip.login
new file mode 100644
index 000000000000..3c70095a2fcc
--- /dev/null
+++ b/share/examples/sliplogin/slip.login
@@ -0,0 +1,12 @@
+#!/bin/sh -
+#
+# @(#)slip.login 8.1 (Berkeley) 6/6/93
+
+#
+# generic login file for a slip line. sliplogin invokes this with
+# the parameters:
+# 1 2 3 4 5 6 7-n
+# slipunit ttyspeed loginname local-addr remote-addr mask opt-args
+#
+/sbin/ifconfig sl$1 inet $4 $5 netmask $6
+exit
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
new file mode 100644
index 000000000000..84676086deb5
--- /dev/null
+++ b/usr.sbin/Makefile
@@ -0,0 +1,26 @@
+# @(#)Makefile 5.20 (Berkeley) 6/12/93
+
+SUBDIR= ac accton amd arp chown chroot cron dev_mkdb diskpart edquota \
+ inetd kgmon kvm_mkdb lpr mkproto mtree portmap pstat pwd_mkdb \
+ quot quotaon repquota rmt rwhod sa sendmail sliplogin sysctl \
+ syslogd traceroute trpt trsp update vipw
+
+.if make(clean) || make(cleandir)
+SUBDIR+=bad144 config config.new eeprom iostat timed
+.elif ${MACHINE} == "hp300"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "i386"
+SUBDIR+=bad144 config iostat
+.elif ${MACHINE} == "luna68k"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "mips"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "sparc"
+SUBDIR+=config.new eeprom timed
+.elif ${MACHINE} == "tahoe"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "vax"
+SUBDIR+=bad144 config iostat timed
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/Makefile.inc b/usr.sbin/Makefile.inc
new file mode 100644
index 000000000000..fd9286474425
--- /dev/null
+++ b/usr.sbin/Makefile.inc
@@ -0,0 +1,3 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/6/93
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/ac/ac.8 b/usr.sbin/ac/ac.8
new file mode 100644
index 000000000000..0c834a7a991e
--- /dev/null
+++ b/usr.sbin/ac/ac.8
@@ -0,0 +1,107 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" 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.
+.\"
+.\" @(#)ac.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt AC 8
+.Os BSD 4
+.Sh NAME
+.Nm ac
+.Nd display connect time accounting
+.Sh SYNOPSIS
+.Nm ac
+.Op Fl d
+.Op Fl p
+.Op Fl w Ar file
+.Op Ar users ...
+.Sh DESCRIPTION
+If the file
+.Pa /var/log/wtmp
+exists,
+a record of individual
+login and logout times are written to it by
+.Xr init 8
+and
+.Xr login 8
+respectively.
+The program
+.Nm ac
+examines these
+records and writes the accumulated connect time for all logins to the
+standard output.
+.Pp
+Options available:
+.Bl -tag -width people
+.It Fl d
+Display the connect times in 24 hour chunks.
+.It Fl p
+Display individual user totals.
+.It Fl w Ar file
+Read raw connect time data from
+.Ar file
+instead of the default file
+.Pa /var/log/wtmp .
+.It Ar users ...
+Display totals for the given individuals
+only.
+.El
+.Pp
+If no arguments are given,
+.Nm
+displays the total amount of login time for all active accounts on the
+system.
+.Pp
+The default
+.Pa wtmp
+file is an infinitely increasing file
+unless frequently truncated. This is normally
+done by the daily daemon scripts scheduled by
+.Xr cron 8
+which rename and rotate the
+.Pa wtmp
+files before truncating them (and keeping about a weeks worth on hand).
+No login times are collected however, if the file does not exist.
+.Sh FILES
+.Bl -tag -width /var/log/wtmp.[0-7] -compact
+.It Pa /var/log/wtmp
+.It Pa /var/log/wtmp.[0-7]
+rotated files
+.El
+.Sh SEE ALSO
+.Xr init 8 ,
+.Xr sa 8 ,
+.Xr login 1 ,
+.Xr utmp 5 .
+.Sh HISTORY
+A
+.Nm
+command appeared in Version 6 AT&T UNIX.
diff --git a/usr.sbin/accton/Makefile b/usr.sbin/accton/Makefile
new file mode 100644
index 000000000000..15152a63765b
--- /dev/null
+++ b/usr.sbin/accton/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= accton
+NOMAN= noman
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/accton/accton.c b/usr.sbin/accton/accton.c
new file mode 100644
index 000000000000..c65ef680afc4
--- /dev/null
+++ b/usr.sbin/accton/accton.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1988, 1993
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)accton.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ if (acct(NULL)) {
+ (void)fprintf(stderr,
+ "accton: %s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 1:
+ if (acct(*argv)) {
+ (void)fprintf(stderr,
+ "accton: %s: %s\n", *argv, strerror(errno));
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: accton [file]\n");
+ exit(1);
+}
diff --git a/usr.sbin/amd/Makefile b/usr.sbin/amd/Makefile
new file mode 100644
index 000000000000..96405b8fe90c
--- /dev/null
+++ b/usr.sbin/amd/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+SUBDIR= amd amq fsinfo mk-amd-map
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/amd/amd/ChangeLog b/usr.sbin/amd/amd/ChangeLog
new file mode 100644
index 000000000000..2cd1807260d4
--- /dev/null
+++ b/usr.sbin/amd/amd/ChangeLog
@@ -0,0 +1,1169 @@
+Sun Jun 7 19:01:37 1992 Jan-Simon Pendry (jsp at achilles)
+
+ * Code cut for BSD 4.4 alpha.
+
+Sun May 31 17:28:52 1992 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) make sure error code is returned to user if there
+ is an immediate error in afs_lookuppn.
+
+ * (nfs_ops.c) clear out mountd port number after use.
+
+ * (nfs_ops.c) optionally (KICK_KERNEL) run lstat over the old
+ mount point. This should go somewhere else more appropriate.
+
+Sun Mar 29 16:22:01 1992 Jan-Simon Pendry (jsp at achilles)
+
+ * (mount_fs.c) FASCIST_DF_COMMAND is now defined as the fstype
+ you want df to see.
+
+ * (opts.c) fix buffer overrun in slash munging.
+
+ * (host_ops.c) add support for INFORM_MOUNTD.
+
+Sat Mar 7 10:23:04 1992 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfsx_ops.c) fix buffer overrun problem by allocating sufficient
+ memory.
+
+ * (afs_ops.c) fix dereference of free'ed memory when calling
+ assign_error_mntfs.
+
+ * (xutil.c) fix xmalloc and xrealloc to allow zero sized
+ allocation.
+
+ * (os-type) make it recognise aix3.2
+
+Sun Feb 9 13:14:54 1992 Jan-Simon Pendry (jsp at achilles)
+
+ * Release 5.3 Beta
+
+ * hpux 8 support is still missing.
+
+ * (os-bsd44.h) merged in changes for new bsd nfs code. still need
+ to add in lease and kerberos support.
+
+Sun Dec 1 16:20:21 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * (info_nis.c) changed so that it remembers if the NIS domainname
+ is set and doesn't repeatedly complain. Message changed from an
+ Error to a Warning.
+
+ * (sfs_ops.c) added linkx fstype. linkx is the same as link but
+ it also checks that the target exists. This makes it useful for
+ wildcard map entries.
+
+ * (wire.c) applied changes from Dirk Grunwald. Now stands a
+ better chance of correctly determining the network name.
+
+ * (map.c) changes in timeout_mp to cause second and subsequent
+ backgrounded unmount attempts to backoff and so reduce the chance
+ of running more than one backgrounded unmount at a time.
+
+ * (misc_rpc.c) bug fix from Martyn Johnson to avoid xdr_free'ing
+ the wrong piece of memory. This was causing random core dumps,
+ often with a stack trace through pickup_rpc_reply.
+
+Sun Sep 15 21:16:38 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * Release 5.3 alpha 14.
+
+ * (os-osf1.h) merged in OSF/1 support.
+
+Sun Aug 4 18:25:04 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * (os-stellix.h) merged in Stellix support.
+
+ * (os-u4_2.h) merged in Ultrix 4.2 support.
+
+ * (host_ops.c) made TCP the default transport protocol. Define
+ HOST_RPC_UDP somewhere to get UDP transport.
+
+ * (many) added support for ${remopts}. Suggested by Steve
+ Heimlich. remopts is the same as opts, but is used when the
+ remote server is not on the local network. If it is not set it
+ defaults to whatever value ${opts} has.
+
+Tue May 7 22:30:00 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * Checkpoint for Berkeley network tape II.
+
+Sat May 4 22:06:24 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * New Berkeley Copyright.
+
+ * (mntfs.c) more short-circuiting in realloc_mntfs().
+
+ * (host_ops.c) increase RPC timeout to 20 seconds.
+
+ * (info_hes.c) now supports lookup in other domains.
+
+ * (srvr_nfs.c) call map_flush_srvr whenever a server comes up.
+
+ * (map.c) added hook to flush hung file servers.
+
+ * (wire.c) make loop step more portable.
+
+ * (util.c) fix for compiling on rios.
+
+Sun Apr 21 21:54:52 1991 Jan-Simon Pendry (jsp at forest)
+
+ * (util.c) ignore EINVAL returned by rmdir().
+
+ * (am_ops.c, afs_ops.c) remove SunOS4 map compat code.
+
+ * (nfsx_ops.c) don't clear MFF_MOUNTING until finished mount attempts.
+
+ * (nfsx_ops.c) don't call sched_task more than once.
+
+ * (afs_ops.c) don't call afs_bgmount if a mount is in progress.
+
+ * (info_file.c) handle case where map ends with \
+
+Fri Apr 5 19:23:50 1991 Jan-Simon Pendry (jsp at forest)
+
+ * Release 5.3 Alpha 12.
+
+ * (util.c) don't clear MFF_MOUNTING flag if mount is still in progress.
+
+ * (srvr_nfs.c) calls make_nfs_auth() as required.
+
+ * (host_ops.c) calls make_nfs_auth() as required.
+
+ * (afs_ops.c) allow foreground mounts to return pending. This is
+ used by nfsx_ops.c.
+
+ * (mapc.c) uses new RE_HDR abstraction coping with systems which
+ already have the re package installed.
+
+ * (nfsx_ops.c) automatically generates a suitable sublink to make
+ things work. Remounts now work correctly, but are done in the
+ foreground so there is a possibility that things may hang. This is
+ too hard to do differently.
+
+Wed Apr 3 17:49:05 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_ops.c) HAS_NFS_QUALIFIED_NAME is a new compile time switch
+ which puts a qualified domain name into the RPC authentication
+ instead of using the default value. Abstracted this out into new
+ routine called make_nfs_auth().
+
+ * (afs_ops.c) fixed bug which caused spurious ENOENTs to appear.
+ this was caused by some code motion which also got slightly
+ altered int the process. moral: don't make two changes at once.
+
+Sun Mar 17 12:05:27 1991 Jan-Simon Pendry (jsp at forest)
+
+ * Release 5.3 Alpha 11.
+
+ * (amq.8) Updated.
+
+ * (amq.c) Added new -v option which displays the version number of
+ the target Amd. Also added support to Amd and reworked newvers
+ script. Got rid of rcs_info.c.
+
+ * (mk-amd-map.c) Changed name of remove function to avoid clash
+ with ANSI C.
+
+ * (wire.c) Fixed to work with new 4.4BSD sockaddr's.
+
+ * Changed const to Const everywhere and added new define in config.h.
+
+ * (mk-amd-map.c) New -p option which just writes the output to
+ stdout. Useful for making NIS or Hesiod maps.
+
+ * (amdref) Small updates and clarifications.
+
+Sat Mar 16 20:35:17 1991 Jan-Simon Pendry (jsp at forest)
+
+ * (amq_subr.c) Flush request now flushes all internal caches.
+
+ * (amq_subr.c) Changed xdr_amq_mount_tree to return only the
+ required sub-tree.
+
+ * (ifs_ops.c) Added missing return 0; to ifs_mount.
+
+Sat Mar 9 19:31:25 1991 Jan-Simon Pendry (jsp at forest)
+
+ * (get_args.c) Output the primary network interface information
+ with the -v option.
+
+ * (mapc.c) Fixed spurious warning about "root" map not supporting
+ cache mode "all". Added new (unnamed) cache mode MAPC_ROOT.
+
+ * (info_nis.c) Fixed order number testing which was the cause of a
+ loop.
+
+Sun Mar 3 17:57:03 1991 Jan-Simon Pendry (jsp at forest)
+
+ * Release 5.3 Alpha 10.
+
+ * Introduced new inet_dquad routine which prints IP addresses in
+ dotted quad format. The C library routine is not used because it
+ uses a static buffer and it takes a structure argument on some
+ machines and unsigned longs on others. This confuses the hell out
+ of some compilers and causes SEGVs.
+
+ * task_notify becomes do_task_notify to avoid clash with Mach.
+
+ * (mntfs.c) In realloc_mntfs, the private data field wasn't being
+ cleared out when the mntfs object was being re-used. This meant
+ that the data might be used for the wrong mount, so causing
+ various obscure errors.
+
+ * (info_file.c) Reworked to provide support for map cache "sync"
+ option.
+
+ * (mapc.c) Added new "sync" option to map cache. This ensures
+ that the cached data doesn't become stale wrt the source.
+ Currently this isn't implemented for passwd and hesiod maps.
+
+Wed Feb 27 11:38:07 1991 Jan-Simon Pendry (jsp at forest)
+
+ * (afs_ops.c) Fixed pid put in fs_hostname for toplvl mount.
+
+Sun Feb 24 19:37:55 1991 Jan-Simon Pendry (jsp at forest)
+
+ * (wire.c) New module which determines the name of the primary
+ attached network. This could be used to determine which
+ server to use.
+
+ * (srvr_nfs.c) Changed mount daemon port mapping caching. This is
+ now much more eager to recompute the mapping than before. Will
+ also now work even if pinging is switched off (for example "tcp").
+
+ * (info_nis.c) Added back old NIS reload code to allow NIS maps to
+ support "regexp" caching.
+
+ * (mapc.c) Added support for "regexp" caching. This is a type of
+ map cache where the entries are all REs to be matched against the
+ requested key. This implies "all" since all the keys must be
+ loaded for the search to work.
+
+Sat Feb 23 15:32:43 1991 Jan-Simon Pendry (jsp at forest)
+
+ * (afs_ops.c) Avoid spurious error messages about discarding a
+ retry mntfs.
+
+ * (amq_subr.c) Removed inet_ntoa call due to disagreement between
+ gcc and libc about 4 byte structure passing.
+
+ * (xutil.c) Changed way initial logging is done to make command
+ line more usable. Default logging flags are set statically and
+ can then be modified by -x options. At the end an additional call
+ to switch_option is made to initialise xlog_level_init.
+
+ * (umount_fs.c) ENOENT now treated the same as EINVAL. If the
+ filesystem gets removed and the mountpoint deleted then just
+ assume the filesystem isn't there - which it isn't.
+
+ * (host_ops.c) Now copes with unmount failures by attempting to
+ remount the filesystems which had been unmounted.
+
+ * (host_ops.c) Added check during fhandle collection to detect
+ duplicate entries in the export list (from Stefan Petri).
+
+ * (nfsx_ops.c) Reworked to correctly keep track of what is and
+ isn't mounted.
+
+Sun Jan 27 16:58:02 1991 Jan-Simon Pendry (jsp at achilles)
+
+ * (misc-next.h) Added missing NeXT config file.
+
+ * Merged Harris HCX/UX support from Chris Metcalf.
+
+ * (ifs_ops.c) added ifs_fmount entry point to keep nfsx_ops happy.
+
+Sun Jan 13 18:19:19 1991 Jan-Simon Pendry (jsp at beauty)
+
+ * (nfsx_ops.c) play with opt_fs field to make sure it is unique.
+
+Fri Dec 21 15:35:45 1990 Jan-Simon Pendry (jsp at forest)
+
+ * Release 5.3 Alpha 9. This is still not Beta!
+
+ * (host_ops.c) use normalized hostname in mtab entries, from
+ Chris Metcalf.
+
+ * (map.c) enum ftype -> ftype, from Andrew Findlay.
+
+Mon Dec 17 01:11:25 1990 Jan-Simon Pendry (jsp at beauty)
+
+ * (amdref.texinfo) merged in fsinfo documentation from Nick.
+
+Sat Dec 15 15:39:07 1990 Jan-Simon Pendry (jsp at beauty)
+
+ * (clock.c) minor tweaks to messages.
+
+ * (sfs_ops.c) make the opt_fs field unique, rather than always
+ ".", but make sure it still begins with a "." to avoid a clash
+ with any other existing mounts.
+
+ * (amd.c) changed way local IP address is obtained to avoid using
+ a call to the name server. It was observed that if the power to
+ the building goes and everything reboots simultaneously then there
+ would be a good chance that the nameserver would not recover
+ before Amd on another machine required it. This happened :-) Now
+ use the RPC get_myaddress call.
+
+ * (info_hes.c) added hesiod_reload code from Bruce Cole.
+ Optionally compiled when HAS_HESIOD_RELOAD is defined.
+
+ * (amq_subr.c) fix "security" check.
+
+ * (amq.c) make sure a privileged port is allocated. In fact
+ RPC3.9 and newer make this guarentee but older versions don't so
+ we do it here.
+
+Sun Dec 2 21:30:07 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) fixed problem with pointer pre-increment.
+
+Mon Nov 19 00:31:28 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_ops.c) saved filehandle with mntfs structure. this allows
+ nfsx unmounts to be undone even if the filehandle cache has lost
+ the entry. all of this is bogus and deserves a rewrite...
+
+Sun Nov 18 22:55:43 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfsx_ops.c) now handles mounts of root filesystem correctly.
+
+ * (afs_ops.c) fixed dfs_ops definition to call toplvl_mounted when
+ done, so making sure that a map cache reference is set up.
+
+Sun Nov 11 21:09:34 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (fsinfo/wr_fstab.c) has per-ostype fstab rules.
+
+ * (fsinfo/fsi_lex.l) now works correctly with flex.
+
+Mon Nov 5 00:08:30 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * Release 5.3 Alpha 8. No more new features from now to 5.3Rel.
+ Call next one Beta.
+
+ * (amdref.texinfo) more updates.
+
+ * (info_union.c) reload routine now adds a wildcard pointing to
+ the last named directory so that new files get created correctly.
+
+Sun Nov 4 22:02:50 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (os-u4_0.h) Ultrix 4.0 support merged.
+
+ * (os-utek.h) Utek 4.0 support merged.
+
+ * (amdref.texinfo) fixed & updated.
+
+ * (nfsx_ops.c) reworked string munging to prevent ..//.. strings
+ from occuring.
+
+ * (util.c) am_mounted now correctly updates the am_node for
+ duplicate mounts.
+
+ * (afs_ops.c) added union fstype. derived from "toplvl" except it
+ causes all the filesystems to be mounted. cannot be used for
+ filesystem types whose mounts may be defered (eg nfs) since it
+ doesn't retry the mounts.
+
+ * (info_union.c) map type for union fstype support. currently
+ can't handle being given automounted filesystems - causes a
+ deadlock.
+
+Sun Oct 21 22:56:16 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (fsinfo/*) finally integrated the fsinfo package. currently no
+ documentation or man page. this is a pre-req to getting mmd up.
+
+Sun Oct 14 20:02:11 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (amdref.texinfo) reworking of documentation continues.
+
+ * (clock.c) reschedule_timeouts() now called in the event that the
+ system clock goes backwards. this is possible during the average
+ bootstrap juggling act with timed/xntpd etc. especially useful if
+ your machines TOY clock gets way ahead of time.
+
+Sat Oct 6 19:57:55 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (map.c) when expanding the filehandle for a server which is
+ down, don't update the ttl on the original node unless a new node
+ gets allocated. this should give the original mount a chance to
+ go away as soon as the server comes back.
+
+ * (arch, os-type) Updated.
+
+ * (nfs_ops.c) Added "noconn", "spongy" and "compress" mount
+ options for 4.4 BSD.
+
+Sun Sep 30 18:37:54 1990 Jan-Simon Pendry (jsp at beauty)
+
+ * Release 5.3 Alpha 6.
+
+ * (util.c) domain_strip now doesn't leave partial domains behind.
+ if it can't strip the complete domain it leaves the string untouched.
+
+ * (restart.c) remember to initialise opt_opts field from mtab.
+
+ * (nfs_ops.c) supports "nocto" option for SunOS4.1.
+
+ * (os-irix.h) new SGI Iris port.
+
+ * (os-next.h) new NeXT port.
+
+ * (os-dgux.h) new DG/UX port.
+
+ * (many) fixed problem where mf_opts was being used for two
+ different purposes. Now have two fields.
+
+ * (mapc.c) error map prints error message whenever used.
+
+ * (mapc.c) wildcard code rewritten.
+
+ * (util.c) slpit into two parts - some code now in xutil.c. This
+ is used by mmd (not yet shipped).
+
+Sun Aug 19 19:58:16 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (srvr_nfs.c) reduce verbosity of "nfs server yoyo is ok" messages.
+
+ * (opts.c) fix deslashification in expand.
+
+ * (nfs_start.c) amq registering done just before the server kicks
+ in. running amd with nothing to do leaves the portmapper in peace.
+
+ * (mapc.c) bootstrap code abstracted to allow AMQ_MOUNT entry point.
+
+ * (nfsx_ops.c) new filesystem type, supporting groups of nfs
+ mounts. needs abstracting to allow groups of (*) mounts.
+
+ * (am.h, *_ops.c) am_ops structure changed; corresponding changes
+ in the filesystem implemention source. Change was to allow nfsx
+ filesystem implementation.
+
+ * (amd.c) hostname defaults to "localhost" startup code re-ordered
+ so that logging still works in case things go wrong early.
+
+ * (am_ops.c) new routine to print list of available fs types; used
+ by the -v option.
+
+ * (info_file.c) bug fix to make reloads work correctly.
+
+ * (mtab_file.c) does locking on single write, to avoid trashing
+ mount table when a mount and unmount are done at the same time.
+
+ * (mount_fs.c) automount hack removed since afs_ops no longer
+ needs it.
+
+ * (afs_ops.c) split "auto" into several other filesystem types.
+ Now much cleaner.
+
+ * (amq.c) new -M option.
+
+ * (amq_subr.c) support for AMQ_MOUNT added.
+
+ * (amq.x) new AMQ_MOUNT RPC call allows mount map entries to be
+ passed in at run-time. Automount points can now be added
+ dynamically, but not yet deleted.
+
+Sat Jun 23 22:12:48 1990 Jan-Simon Pendry (jsp at beauty)
+
+ * Release 5.2 for Berkeley.
+
+ * (*) Re-organised source code layout. Now much more complicated.
+
+ * (map.c) code which flushed the kernel name cache is not really
+ needed now that the modify times on the automount directories are
+ correctly updated so ifdef the whole lot. Remove later...
+
+ * (map.c) make sure that the automount directories modify times
+ are updated when a change occurs so that the nfs client code can
+ decide when to update its name cache.
+
+ * (srvr_nfs.c) fixed bug which caused mounted filesystems to
+ appear down when they were up.
+
+ * YP becomes NIS.
+
+Mon May 28 19:50:34 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (amd.tex) substantially updated with more explanation of the
+ theory and more examples.
+
+ * (nfs_stubs.c) statfs now claims to have a single used block.
+ Avoids ambiguity between 100% and 0% full.
+
+ * (nfs_stubs.c) changed to allow the size of symlinks optionally
+ to be accurate wrt the length of the string returned. Optional
+ because it is cheaper to ignore the length when doing a getattr
+ and just send any length for the readlink. However, this breaks
+ on some systems (e.g. Ultrix).
+
+ * (mount_fs.c) automount points get marked type "nfs" instead of
+ "ignore". This is to fix an interaction with getwd(). Can go
+ away when getwd() gets re-written. Really only applies to SunOS4
+ but change applies to everything to keep consistent across platforms.
+
+ * (mount_fs.c) abstracted out mount options into a table and
+ corresponding loop.
+
+ * (srvr_nfs.c) make sure portmap information is available when
+ needed, not just after a ping has succeeded. This needed changing
+ after the ping algorithm got changed.
+
+ * (mntfs.c) fixed incorrect reference to mf_error instead of mf_flags.
+
+ * (nfs_start.c) keep track of number of fds in use, so don't run
+ select on system maximum (which is bad news if you have a large
+ system maximum).
+
+ * (host_ops.c) new NFS tree mount filesystem type (ala Sun -hosts).
+
+ * (nfs_ops.c) abstracted out NFS mount code to support host_ops.
+
+ * (afs_ops.c) dfs_readlink now returns the am_node, instead of the
+ link. This allows getattr to return the correct set of attributes
+ so keeping Ultrix happy.
+
+ * (afs_ops.c) Make certain the hostname field given to mount()
+ does not get too long - otherwise random EINVAL errors occur.
+
+ * Putting closing comments on all #endif's
+
+Sun May 13 16:07:21 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (srvr_nfs.c) second rewrite of NFS ping algorithm.
+
+Sun Apr 29 21:12:33 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_stubs.c) re-arranged readlink code to avoid need to
+ pre-mount a direct filesystem whenever possible.
+
+ * (host_ops.c) finally incorporated new module to support /net
+ mount point.
+
+Sat Mar 24 13:18:47 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_stubs.c) workaround added to rename entry point to avoid
+ arguments with NFS client code.
+
+ * (srvr_nfs.c) changed the way NFS pings are done and cleaned up
+ the process for deciding when a server is up or down. Now there
+ is just a simple time limit on a reply from the server. The limit
+ is adjusted depending on whether the state of the server is known.
+
+ * (opts.c) fixed bug with ${var/} expansion et al. Added ${varN}
+ N = 0..7 for use as scratch variables.
+
+ * (mntfs.c) fixed bug in dup_mntfs().
+
+Thu Jan 11 16:56:41 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * Release 5.1c.
+
+ * (amq*) has new options. -f flushes the map cache and -m prints
+ information about mounted filesystem and fileservers.
+
+Tue Jan 2 14:44:21 1990 Jan-Simon Pendry (jsp at achilles)
+
+ * (util.c) am_mounted() patches the path for "direct" mounted
+ filesystems - cosmetic.
+
+ * (afs_ops.c) when possible sets a small kernel attribute cache
+ timeout on the automount points.
+
+ * (nfs_stubs.c) delete() and rmdir() operations implemented. Used
+ when a mount point is timed out so the kernel name cache gets to
+ know about the changes. Fixes most ESTALE errors.
+
+ * (nfs_stubs.c) New do_readlink() function added. This is used to
+ make sure that a filesystem is mounted at the time a link is read
+ in the case of "direct" mounts. Done so that the length of the
+ link is available when the initial getattr is done on the mountpoint.
+
+ * (sfs_ops.c) Changed implementation to avoid race conditions.
+ The link target is re-arranged so that sublink points to the
+ target and fs always points at ".".
+
+ * Fixed mount flag bug on Ultrix.
+
+ * Added support from Sjoerd Mullender for Alliant FX/4 and Encore
+ Multimax.
+
+Thu Dec 7 17:55:29 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) dfs_readlink now does a new_ttl on the node it
+ returns.
+
+ * (afs_ops.c) next_nonerror_node now implements the task after
+ which it is named.
+
+Tue Nov 28 17:20:52 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Release 5.1b.
+
+ * (restart.c) Generates link nodes for any unrecognised filesystem
+ types and then marks them so that they are never deleted (since
+ they could never be automounted later).
+
+ * (os-*.h) Irrelevant #undef's deleted.
+
+ * (arch) Now knows about AIX on RTs.
+
+ * (amq.c) Rationalised the output. Now only gives you what you
+ asked for.
+
+ * (am.h) New macro: FSRV_ISDOWN(fs), which checks whether a
+ fileserver is down.
+
+ * (afs_ops.c) When a mount fails due to a timeout the underlying
+ filesystem is ripped away and replaced with an error fs. This
+ avoids the possibility of being left with a single error reference
+ to a valid mounted filesystem.
+
+Thu Nov 23 18:04:29 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_start.c) Re-order bootstrap sequence to avoid potential
+ deadlock if restart() ends up accessing one of the automount points.
+
+ * (amq.c) Don't produce default mount output if one of the -l, -x
+ or -D options was used.
+
+ * (umount_fs.c) Add alternative unmount routine for 4.4 BSD.
+
+Mon Nov 20 16:22:50 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (os-bsd44.h) Fixed redefinition of UMOUNT_FS.
+
+ * (info_ndbm.c) Added missing #include <sys/stat.h>.
+
+ * (mapc.c) Fixed typo in ifdef around gdbm config entry.
+
+Sat Nov 18 16:39:13 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (util.c) If "/" is automounted, make sure it is never timed out.
+
+ * (mtab.c) Missing clock invalidation added in read_mtab (from a file).
+
+ * (mntfs.c) realloc_mntfs simplified.
+
+ * (map.c) Closed a race condition during shutdown when second and
+ subsequent duplicate mounts were deleted prematurely.
+
+ * (afs_ops.c) Duplicate mounts are now given the correct return
+ code.
+
+Fri Nov 17 18:58:18 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.1 Release.
+
+Thu Nov 16 17:57:02 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (mntfs.c) Make sure inherit mntfs structures are not cached
+ after last reference; otherwise a second reference to the
+ inherited filesystem will get stuck on the inherit rather than the
+ (now) fully mounted filesystem.
+
+ * (am.c, nfs_start.c) After forking the server, make sure the
+ parent does not exit until the automount points are mounted. This
+ allows a clean sequence during system startup.
+
+ * Initial port to 4.4 BSD. Several new configuration abstractions
+ were added to make this port possible.
+
+Thu Nov 9 21:42:14 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c, opts.c) Added map logging to facilitate mount map
+ debugging without needing a -DDEBUG version of Amd.
+
+ * (afs_ops.c) Make sure the length of the fs_hostname mount
+ parameter does not exceed MAXHOSTNAMESZ.
+
+Wed Nov 8 13:44:02 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Change the message log format to indicate the severity of the
+ message to allow simpler analysis of the log file.
+
+Tue Nov 7 14:11:36 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 11.
+
+ * (os-bsd44.h) Initial guess at 4.4 BSD definitions.
+
+ * (os-aux.h) Port for Macintosh II from Julian Onions.
+
+ * (amq.c) Output formats cleaned up. AMQ_MNTTREE is still broken
+ in amq_subr.c though.
+
+ * (afs_ops.c) If a mount timed out, for example an NFS server was
+ down at the time, it was possible for the error code to remain
+ unset thus jamming that mount node in a state from which it could
+ not recover. Just make sure that the mf_error field gets filled
+ in when an error occurs.
+
+ * (afs_ops.c) strsplit is run over /defaults to avoid problems
+ with whitespace creeping in.
+
+Sun Nov 5 11:50:51 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (util.c) am_mounted: Added missing initialisation of stats.s_mtime.
+
+Fri Nov 3 17:33:02 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 10.
+
+ * Changed the copyright.
+
+Thu Nov 2 17:07:53 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 9.
+
+ * (opts.c) new option syntax: == != :=
+
+ * (nfs_ops.c) Less caching of filehandles. Now cached errors are
+ discarded after use.
+
+ * (mtab.c) now attempts to deal with a lack of open file slots (ENFILE).
+
+ * (mount_fs.c) automount entries in the mount table now have a
+ dev= entry in the same way as NFS and UFS.
+
+ * (mntfs.c) mntfs nodes are now cached after the last reference
+ and discarded <ALLOWED_MOUNT_TIME> seconds later. This avoids
+ thrashing during a mount.
+
+ * (mapc.c) map default cache mode is now selected with
+ "mapdefault", not "default"
+
+ * (amd.tex) numerous clarifications. Still more work required...
+
+ * (amq_subr.c) now allows the -x option of amq to operate.
+
+ * (afs_ops.c) afs_bgmount now keeps track of which filesystem
+ needed retrying and ensures that the mount node in the
+ continuation correctly points at an unmounted filesystem. This
+ fixes a problem whereby a valid mounted filesystem could appear to
+ have failed to mount.
+
+ * Configure now gives more of a running commentary and checks
+ whether os-type and arch actually worked.
+
+ * Allow spurious ';'s in a mount location.
+
+Fri Oct 27 14:03:31 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * foo=blah changed to foo:=blah, foo==blah and foo!=blah.
+
+ * -l stderr changed to -l /dev/stderr.
+
+Thu Oct 19 15:34:28 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 6.
+
+ * LOG_INFO messages have been rationalised so that some
+ statistics, graphs and so on can be generated.
+
+ * Transaction ID's for RPC calls are now allocated by the
+ individual callers, rather than from a central pool. This
+ decreases the load on mount daemons and NFS servers since the
+ same XID is used for retries when needed.
+
+ * Many fine details of the new data structures have been changed.
+ Some areas have been optimized.
+
+Fri Oct 13 12:31:26 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Restart code re-implemented to work with the new data structures.
+
+ * Fine tuning applied to new NFS server modeling code.
+
+Thu Oct 12 15:57:24 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Added ${/var} and ${var/} variable expansions. The first gives
+ the "basename" component of the variable, the latter gives the
+ "dirname" component. Additionally, spurious /'s are deleted after
+ the variable expansions is complete.
+
+ * Added new -C option to allow the machine's cluster name to be
+ given to amd. ${cluster} fetches the value and can be used as
+ another selector.
+
+ * Broken the major data struct (am_node) into three layers:
+ am_node (one for each automount node), mntfs (one for each mounted
+ filesystem) and fserver (one for each file server). Machine
+ up/down state is maintained in the fserver layer. Filesystem
+ mount/unmount state is maintained in the mntfs layer. This change
+ fixes the last known major problem caused by the lack of a central
+ focus for filesystem and fileserver status. There is a dummy file
+ server layer for local filesystems (ufs, link, program, error).
+
+Tue Oct 10 11:15:42 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 5.
+
+ * (nfs_ops.c) the filehandle cache is now flushed when a
+ filesystem is unmounted. This avoids ending up with stale
+ information if a server bounces.
+
+ * (clock.c) new module to implement callouts. Many other
+ routines changed to use callouts instead of messing with ttl
+ fields.
+
+Sun Oct 1 17:08:20 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 3 & 4.
+
+ * Numerous cleanups.
+
+Wed Sep 13 14:30:05 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 2.
+
+ * (nfs_ops.c) portmap information is not remembered beyond the
+ basic filehandle cache interval. That avoids problems when a new
+ portmap and/or rpc.mountd is started and the bound port changes.
+
+ * (mapc.c) cache reloads are automatically done every hour.
+
+ * Removed xlog macro in favour of plog() so that the log level
+ can be reflected through to syslog(). log() routine renamed to
+ plog() which takes an extra parameter indicating the log level.
+
+Tue Sep 5 20:00:19 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_ops.c) when a server is known to be down, any cached file
+ handles and port mapping informaton is flushed since that may have
+ changed when it comes back up.
+
+ * (map.c) timeout no longer attempts to unmount a hung mount point.
+
+Mon Sep 4 14:49:18 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) a mount node which timed out during mount is now
+ retained for the normal timeout interval rather than for a short
+ period. This avoids wasting time retrying mounts from a server
+ which is down.
+
+ * (afs_ops.c) hung mounts are now detected and not used as a
+ duplicate mount - something which defeated the replacement fs
+ scheme.
+
+ * (nfs_ops.c) keepalive's now back-off when a server has gone
+ down.
+
+Thu Aug 31 21:18:35 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * 5.0 Patchlevel 1.
+
+ * Fixed several bugs which showed up in the keepalive
+ implementation when a gateway went down causing
+ a different sequence of errors than usual.
+
+Wed Aug 30 11:29:21 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (amq.x) now uses a Sun assigned program number.
+
+ * Revision 5.0 - can now start using metaconfig.
+
+Tue Aug 29 14:36:48 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (os-u3_0.h, os-type) now knows about DECstations (mips).
+
+ * (nfs_stubs.c) Added hooks to readlink entry point to call
+ per-fs readlink routine if it exists, otherwise old behaviour.
+
+ * (afs_ops.c) Added implementation of "type=direct". This is
+ the same as "type=auto" but is itself the link to the
+ mount point, rather than being a directory containing a list
+ of links to mount points.
+
+Mon Aug 28 17:48:15 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) Changed readdir to workaround a problem on
+ ultrix 3 where it seems to forget that eof has been reached.
+
+Thu Aug 24 15:17:55 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Created "beta16".
+
+ * (afs_ops.c) /defaults is located along with every key.
+ this makes it possible to update the /defaults in
+ a map and get to use it.
+
+ * (mapc.c) added map cache synchronization support. if
+ a file or ndbm map is updated the cache is junked so avoiding
+ things getting out of sync.
+
+Wed Aug 23 19:17:52 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (os-u3_0.h) new file to support Ultrix 3.0
+
+ * (opts.c) allow environment variables to be accessed via
+ the same ${env} syntax used for options & selectors.
+
+Tue Aug 22 13:19:49 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (opts.c, get_args.c) added support for kernel architecture
+ type to allow /usr/kvm to be automounted under SunOS 4.x.
+
+ * (os-xinu43.h) updated for june '89 release of MORE/bsd.
+
+ * (opts.c) fixed memory allocation problems where some strings
+ may not have been strdup'ed before they were free'ed so causing
+ the malloc arena to get into a twist. This caused core dumps on
+ some machines and infinite loops on others.
+
+ * (*.c) clock handling is now done by a macro. Global variable
+ clock_valid is > 0 (ie the time) when valid, 0 if invalid.
+
+ * (map.c) timeout code survived a complete rewrite and is now
+ O(n) rather than O(n^2).
+
+ * (info_hes.c) new database hooks for Hesiod nameserver.
+
+ * (get_args.c) the local sub-domain is picked up from the
+ hostname if it is not specifed with -d. The subdomain is
+ then stripped from the hostname.
+
+ * (am.c) when a SIGTERM is received, an immediate abort
+ occurs - only the top-level automounts are unmounted; all
+ other mounts stay -- use amd -r to restart.
+
+ * (afs_ops.c) cleaned up key prefix handling. Again updated
+ the "hostname" string passed to the kernel so that includes
+ the hostname, pid and mount point.
+
+Tue Aug 8 16:05:23 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_ops.c) changed the way the file handle cache is managed.
+ No longer gets a race condition between something entering the
+ cache and being used and discard.
+
+Tue Jul 25 20:40:51 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (map.c) changed fh_to_mp2 so that it does not return
+ ESTALE during shutdown. it returns ENOENT instead which
+ avoids thrashing with the kernel.
+
+Sun Jul 23 15:06:10 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) make sure the incoming key from the kernel
+ does not contain any characters which could cause trouble
+ during macro expansion (such as `"! etc).
+
+ * (afs_ops.c) fixed contruction of "mtab" entry.
+
+Fri Jul 21 11:01:05 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) some changes to support the new startup
+ shutdown scheme.
+
+ * (map.c) startup and shutdown are now done using the
+ standard interfaces. Startup is done by creating a
+ private cache map ";root;" and then doing lookups
+ on all the names in it. Shutdown is done by forcibly
+ timing out all the mount points including the automount
+ points.
+
+ * (info_*.c) modified to provide interface required by
+ mapc.c module.
+
+ * (mapc.c) new module to implement map caching. Caching
+ can be controlled by an fs option. "all" means cache
+ the entire map (if possible). "inc" means cache things
+ incrementally. "none" means never cache things. Each
+ map type has a default caching mode which is used if
+ cache option "default" is used.
+
+Wed Jul 19 16:14:52 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (sched.c) implements a general sleep/wakeup scheme and uses
+ it for sub-process handling.
+
+ * (nfs_start.c) task_notify() called from where it used to
+ be called.
+
+ * (nfs_ops.c) now implements a non-blocking rpc library.
+ Everything in nfs_ops was changed to use it. This should
+ not be in this file and will be moved later.
+
+ * (map.c) if a mount point times out and it is deferred then
+ issue a wakeup so that it can be retried.
+
+ * (map.c) when creating a new mount point fetches the entry
+ "/defaults" from the associated map if no other options are
+ specified.
+
+ * (am.c) implements the -p (print process id) option.
+
+ * (afs_ops.c) a mount attempt now has a time-to-live of twenty
+ seconds. if only deferred attempts are waiting after that
+ interval the kernel gets sent ETIMEDOUT.
+
+ * (afs_ops.c) the name by which the kernel knows the filesystem
+ has changed from pid%d@host to /mountpoint@host. That looks
+ better to users who get hit by it.
+
+Fri Jul 14 18:46:16 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) now knows about defered mounts - mounts which
+ are not in progress, not completed, and not failed.
+
+ * (sched.c) added new entry point sched_ast(). This simulates
+ a completed job. The basic idea is to let something else return
+ to the main scheduling loop with a guarentee that it will be
+ called back when some other action has taken place.
+
+ * (nfs_ops.c) implemented a file handle cache. The nfs_init
+ routine starts up a request for the filehandle and the mount
+ routine uses it when it arrives.
+
+Thu Jul 13 18:07:58 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (afs_ops.c) found a race condition between an error occuring
+ and the am_node being timed out. Fixed by updating the
+ time-to-live and keepalive counters in the node whenever
+ AMF_MOUNTING is cleared. Also changed afs_lookuppn() so that
+ it doesn't destroy the node when it returns the error code.
+ This stops thrashing and the node is eventually timed out.
+ Now the only way a node gets deleted is by the timeout code
+ which seems more elegant.
+
+Tue Jul 11 15:36:44 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Created "beta15".
+
+ * Fixed *all* references to "u2.2". Some where missed in
+ the original change. They are now u2_2.
+
+ * (mk-amd-map.c) new command. Converts plain files into
+ ndbm databases for use by the info_ndbm module. Hooks
+ included for future support for gdbm just as soon as I
+ can get a copy.
+
+Sun Jul 9 19:00:22 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Created "beta14".
+
+ * (get_info.c) code to handle yp and files now split into
+ new files info_yp.c and info_file.c New support for ndbm
+ databases is in info_ndbm.c. A table in get_info.c controls
+ what and in which order things are searched.
+
+ * (map.c, nfs_stubs.c) better handling for hung mount points.
+ if a filehandle is passed in by the kernel which references
+ a hung node, then try to find a replacement, possibly by calling
+ lookup explicitly.
+
+ * (*.c) use new xlog(level)(message) interface
+
+Thu Jun 8 20:28:55 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (nfs_ops.c, ufs_ops.c) when compiled with DEBUG, display
+ the fs options being used.
+
+ * (am.c) make test for root a little more polite.
+
+ * (get_args.c) update Usage message to include -r option.
+
+Wed Jun 7 16:28:51 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (rpc_fwd.c) fwd_reply: if the recvfrom call fails because it
+ is interrupted then try again.
+
+Tue Jun 6 16:39:15 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Created "beta12".
+
+ * (afs_ops.c) inheriting mount option list from command line
+ is now cumulative. A -foo on the command line is prepended
+ to the default option list taken from the map. This can be
+ used to override the ``default default'' options in opts.c.
+
+ * (get_args.c, am.c) added new -r (restart) option. Restart of
+ mounted filesystems is only done if this option is specified.
+ [Should *not* be specified in /etc/rc.local of course. - wrong]
+
+ * (yp_master.c) make the enumeration error message more verbose
+ when debugging is enabled.
+
+ * (rpc_fwd.c) rearranged some declarations at the top. Removed
+ a spurious call to free which was causing grief on some systems,
+ but not on Sun's. [This problem was the reason for implementing
+ the -D mem option.]
+
+ * (opts.c) make sure opt_key and opt_path are set to a zero
+ length string unless otherwise specified. Previously they
+ were a source of dangling pointers.
+
+ * (nfs_ops.c) make sure that the allocated nfs_private identifiers
+ are unique even when some filesystem are being restarted. This mean
+ starting the basic allocation from 1, not zero.
+
+ * (am.h, get_args.c, util.c) added definition and implmentation of
+ a simple memory allocation trace (D_MEM).
+
+ * (afs_ops.c) afs_lookuppn: tightened up memory allocation and
+ delay string copying until last possible moment.
+
+Mon Jun 5 18:01:18 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * (Makefile.com) diffs: added new rule to generate diffs
+ between versions.
+
+ * (get_info.c) search_file: added a new dlog() to note when
+ wildcards are returned.
+
+ * (afs_ops.c) afs_lookuppn: call to init_map specifies efs as
+ the default ops structure. If the location list only contained
+ defaults and no real mounts then this previously caused a null
+ pointer dereference.
+
+ * (map.c) last_used_map: Added new variable. Keeps track of the
+ last used map, which may be wildly different from first_free_map.
+ This fixes bugs in several routines in this file.
+
+ * (util.c) mkdirs, rmdirs: Changed directory make/unmake. It is
+ not possible to quickly determine how many directories need to
+ be created or deleted, so we try to make as many as possible.
+
+ * (opts.c) Added default values for rfs, rhost and fs.
+ The new defaults guarentee unique names to allow the NFS
+ keepalive stuff to work.
+
+Sun Jun 4 16:12:15 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * First draft of documentation included in the next release.
+
+ * Hooks for TFS added, though this still requires a lot of work.
+
+ * Re-implemented option handling. Options are now allocated
+ dynamically on a per-mount basis in the continuation structure.
+
+ * Changed os type u2.2 to u2_2 to allow for regular expression
+ matching in selectors.
+
+ * Format of mount maps is now entirely different. Instead of
+ guessing which filesystem type is being used, it is now explicitly
+ stated along with the required options. Variable expansion is
+ done on the options and selectors are also implemented. The
+ requested name can also contain any of the selectors.
+
+Wed May 24 15:21:39 1989 Jan-Simon Pendry (jsp at achilles)
+
+ * Re-implemented NFS ping algorithm to use the new RPC forwarding
+ system. This allowed a large amount of nfs_ops specific code
+ to be removed from nfs_start.c and moved to nfs_ops.c.
+ There is still no strategy for hung file systems. At the moment
+ it will merely try to mount an alternative (or the same again)
+ to the same place in the file system.
+
+ * Added RPC forwarding package. This supports general RPC gatewaying
+ over a UDP transport. The idea is to put a packet identifier into
+ each outgoing RPC packet and then match that up in a database when
+ a reply comes in. The database records the original packet identifier
+ (so that it can be replaced), the source address for the packet and
+ a function to call to do the forwarding.
+
+ * ChangeLog added between beta8 and beta9. Should have done this sooner.
diff --git a/usr.sbin/amd/amd/Makefile b/usr.sbin/amd/amd/Makefile
new file mode 100644
index 000000000000..328fd8064a86
--- /dev/null
+++ b/usr.sbin/amd/amd/Makefile
@@ -0,0 +1,33 @@
+# @(#)Makefile 8.2 (Berkeley) 4/22/94
+
+PROG= amd
+MAN8= amd.0
+OS= bsd44
+SRCS= afs_ops.c am_ops.c clock.c util.c xutil.c \
+ efs_ops.c mapc.c info_file.c info_hes.c \
+ info_ndbm.c info_passwd.c info_nis.c \
+ info_union.c map.c srvr_afs.c srvr_nfs.c \
+ mntfs.c misc_rpc.c mount_fs.c mount_xdr.c \
+ mtab.c mtab_bsd.c nfs_ops.c nfs_prot_svc.c \
+ nfs_start.c nfs_subr.c nfs_prot_xdr.c opts.c \
+ pfs_ops.c rpc_fwd.c sched.c sfs_ops.c amq_svc.c \
+ amq_subr.c umount_fs.c host_ops.c nfsx_ops.c \
+ ufs_ops.c ifs_ops.c amd.c get_args.c restart.c wire.c
+OBJS+= vers.${PROG}.o
+LDADD+= -lrpc
+CFLAGS+=-I${.CURDIR}/../rpcx
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-DARCH_REP=\"${MACHINE}\"
+CFLAGS+=-DOS_REP=\"${OS}\"
+CFLAGS+=-DOS_HDR=\"os-${OS}.h\"
+CFLAGS+=${CONFIG}
+CLEANFILES+=vers.${PROG}.c vers.${PROG}.o version.amd
+
+vers.${PROG}.c: ${SRCS:.c=.o}
+ @d=${.CURDIR}/ sh ${.CURDIR}/../config/newvers.sh ${PROG} ${MACHINE} ${OS}
+
+.PATH: ${.CURDIR}/../rpcx ${.CURDIR}/../config
+.include "Makefile.config"
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/amd/afs_ops.c b/usr.sbin/amd/amd/afs_ops.c
new file mode 100644
index 000000000000..6dfdc1401bcb
--- /dev/null
+++ b/usr.sbin/amd/amd/afs_ops.c
@@ -0,0 +1,1816 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)afs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: afs_ops.c,v 5.2.2.4 1992/05/31 16:36:36 jsp Exp $
+ *
+ */
+
+#include "am.h"
+
+#define NFS
+#define NFSCLIENT
+
+#include <sys/stat.h>
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#ifdef NFS_HDR
+#include NFS_HDR
+#endif /* NFS_HDR */
+#include <sys/mount.h>
+#include "mount.h"
+
+/*
+ * Automount file system
+ * Direct file system
+ * Root file system
+ * Top-level file system
+ */
+
+/*
+ * Interval between forced retries of a mount.
+ */
+#define RETRY_INTERVAL 2
+
+/*
+ * AFS needs nothing in particular.
+ */
+static char *afs_match P((am_opts *fo));
+static char *afs_match(fo)
+am_opts *fo;
+{
+ char *p = fo->opt_rfs;
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "auto: no mount point named (rfs:=)");
+ return 0;
+ }
+ if (!fo->opt_fs) {
+ plog(XLOG_USER, "auto: no map named (fs:=)");
+ return 0;
+ }
+ /*
+ * Swap round fs:= and rfs:= options
+ * ... historical (jsp)
+ */
+ fo->opt_rfs = fo->opt_fs;
+ fo->opt_fs = p;
+ /*
+ * mtab entry turns out to be the name of the mount map
+ */
+ return strdup(fo->opt_rfs ? fo->opt_rfs : ".");
+}
+
+/*
+ * Mount an automounter directory.
+ * The automounter is connected into the system
+ * as a user-level NFS server. mount_toplvl constructs
+ * the necessary NFS parameters to be given to the
+ * kernel so that it will talk back to us.
+ */
+static int mount_toplvl P((char *dir, char *opts));
+static int mount_toplvl(dir, opts)
+char *dir;
+char *opts;
+{
+ struct nfs_args nfs_args;
+ struct mntent mnt;
+ int retry;
+ struct sockaddr_in sin;
+ unsigned short port;
+ int flags;
+ extern nfs_fh *root_fh();
+ nfs_fh *fhp;
+ char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];
+
+ MTYPE_TYPE type = MOUNT_TYPE_NFS;
+
+ bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */
+
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = pid_fsname;
+ mnt.mnt_type = MNTTYPE_AUTO;
+ mnt.mnt_opts = opts;
+ mnt.mnt_freq = 0;
+ mnt.mnt_passno = 0;
+
+ retry = hasmntval(&mnt, "retry");
+ if (retry <= 0)
+ retry = 2; /* XXX */
+
+ /*
+ * get fhandle of remote path for automount point
+ */
+
+ fhp = root_fh(dir);
+ if (!fhp) {
+ plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
+ return EINVAL;
+ }
+
+ NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp);
+
+ /*
+ * Create sockaddr to point to the local machine. 127.0.0.1
+ * is not used since that will not work in HP-UX clusters and
+ * this is no more expensive.
+ */
+ bzero((voidp) &sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr = myipaddr;
+ if (port = hasmntval(&mnt, "port")) {
+ sin.sin_port = htons(port);
+ } else {
+ plog(XLOG_ERROR, "no port number specified for %s", dir);
+ return EINVAL;
+ }
+
+ /*
+ * set mount args
+ */
+ NFS_SA_DREF(nfs_args, &sin);
+
+ /*
+ * Make a ``hostname'' string for the kernel
+ */
+#ifndef HOSTNAMESZ
+#define SHORT_MOUNT_NAME
+#endif /* HOSTNAMESZ */
+#ifdef SHORT_MOUNT_NAME
+ sprintf(fs_hostname, "amd:%d", foreground ? mypid : getppid());
+#else
+ sprintf(fs_hostname, "pid%d@%s:%s", foreground ? mypid : getppid(), hostname, dir);
+#endif /* SHORT_MOUNT_NAME */
+ nfs_args.hostname = fs_hostname;
+ nfs_args.flags |= NFSMNT_HOSTNAME;
+#ifdef HOSTNAMESZ
+ /*
+ * Most kernels have a name length restriction.
+ */
+ if (strlen(fs_hostname) >= HOSTNAMESZ)
+ strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
+#endif /* HOSTNAMESZ */
+
+#ifdef NFSMNT_DUMBTIMR
+ nfs_args.flags |= NFSMNT_DUMBTIMR;
+ plog(XLOG_INFO, "defeating nfs window computation");
+#endif
+
+ /*
+ * Parse a subset of the standard nfs options. The
+ * others are probably irrelevant for this application
+ */
+ if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
+ nfs_args.flags |= NFSMNT_TIMEO;
+
+ if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
+ nfs_args.flags |= NFSMNT_RETRANS;
+
+#ifdef NFSMNT_BIODS
+ if (nfs_args.biods = hasmntval(&mnt, "biods"))
+ nfs_args.flags |= NFSMNT_BIODS;
+
+#endif /* NFSMNT_BIODS */
+
+#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
+ /*
+ * Don't cache attributes - they are changing under
+ * the kernel's feet...
+ */
+ nfs_args.acregmin = nfs_args.acregmax = 1;
+ nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;
+#endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */
+ /*
+ * These two are constructed internally by the calling routine
+ */
+ if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
+ nfs_args.flags |= NFSMNT_SOFT;
+
+#ifdef MNTOPT_INTR
+ if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
+ nfs_args.flags |= NFSMNT_INT;
+#endif /* MNTOPT_INTR */
+
+ flags = compute_mount_flags(&mnt);
+#ifdef ULTRIX_HACK
+ nfs_args.gfs_flags = flags;
+ flags &= M_RDONLY;
+ if (flags & M_RDONLY)
+ nfs_args.flags |= NFSMNT_RONLY;
+#endif /* ULTRIX_HACK */
+ return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
+}
+
+static void afs_mkcacheref P((mntfs *mf));
+static void afs_mkcacheref(mf)
+mntfs *mf;
+{
+ /*
+ * Build a new map cache for this node, or re-use
+ * an existing cache for the same map.
+ */
+ char *cache;
+ if (mf->mf_fo && mf->mf_fo->opt_cache)
+ cache = mf->mf_fo->opt_cache;
+ else
+ cache = "none";
+ mf->mf_private = (voidp) mapc_find(mf->mf_info, cache);
+ mf->mf_prfree = mapc_free;
+}
+
+/*
+ * Mount the root...
+ */
+static int root_mount P((am_node *mp));
+static int root_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ mf->mf_mount = strealloc(mf->mf_mount, pid_fsname);
+ mf->mf_private = (voidp) mapc_find(mf->mf_info, "");
+ mf->mf_prfree = mapc_free;
+
+ return 0;
+}
+
+/*
+ * Mount a sub-mount
+ */
+static int afs_mount P((am_node *mp));
+static int afs_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * Pseudo-directories are used to provide some structure
+ * to the automounted directories instead
+ * of putting them all in the top-level automount directory.
+ *
+ * Here, just increment the parent's link count.
+ */
+ mp->am_parent->am_fattr.nlink++;
+ /*
+ * Info field of . means use parent's info field.
+ * Historical - not documented.
+ */
+ if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')
+ mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);
+ /*
+ * Compute prefix:
+ *
+ * If there is an option prefix then use that else
+ * If the parent had a prefix then use that with name
+ * of this node appended else
+ * Use the name of this node.
+ *
+ * That means if you want no prefix you must say so
+ * in the map.
+ */
+ if (mf->mf_fo->opt_pref) {
+ /*
+ * the prefix specified as an option
+ */
+ mp->am_pref = strdup(mf->mf_fo->opt_pref);
+ } else {
+ /*
+ * else the parent's prefix
+ * followed by the name
+ * followed by /
+ */
+ char *ppref = mp->am_parent->am_pref;
+ if (ppref == 0)
+ ppref = "";
+ mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
+ }
+
+ /*
+ * Attach a map cache
+ */
+ afs_mkcacheref(mf);
+
+ return 0;
+}
+
+/*
+ * Mount the top-level
+ */
+static int toplvl_mount P((am_node *mp));
+static int toplvl_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ struct stat stb;
+ char opts[256];
+ int error;
+ char *mnttype;
+
+ /*
+ * Mounting the automounter.
+ * Make sure the mount directory exists, construct
+ * the mount options and call the mount_toplvl routine.
+ */
+
+ if (stat(mp->am_path, &stb) < 0) {
+ return errno;
+ } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
+ return ENOTDIR;
+ }
+
+ if (mf->mf_ops == &toplvl_ops) mnttype = "indirect";
+ else if (mf->mf_ops == &dfs_ops) mnttype = "direct";
+#ifdef HAS_UNION_FS
+ else if (mf->mf_ops == &union_ops) mnttype = "union";
+#endif
+ else mnttype = "auto";
+
+ /*
+ * Construct some mount options
+ */
+ sprintf(opts,
+#ifdef MNTOPT_INTR
+ "%s,%s,%s=%d,%s=%d,%s=%d,%s",
+ MNTOPT_INTR,
+#else
+ "%s,%s=%d,%s=%d,%s=%d,%s",
+#endif /* MNTOPT_INTR */
+ "rw",
+ "port", nfs_port,
+ "timeo", afs_timeo,
+ "retrans", afs_retrans,
+ mnttype);
+
+ error = mount_toplvl(mf->mf_mount, opts);
+ if (error) {
+ errno = error;
+ plog(XLOG_FATAL, "mount_toplvl: %m");
+ return error;
+ }
+
+ return 0;
+}
+
+static void toplvl_mounted P((mntfs *mf));
+static void toplvl_mounted(mf)
+mntfs *mf;
+{
+ afs_mkcacheref(mf);
+}
+
+#ifdef HAS_UNION_FS
+/*
+ * Create a reference to a union'ed entry
+ */
+static int create_union_node P((char *dir, voidp arg));
+static int create_union_node(dir, arg)
+char *dir;
+voidp arg;
+{
+ if (strcmp(dir, "/defaults") != 0) {
+ int error = 0;
+ (void) toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE);
+ if (error > 0) {
+ errno = error; /* XXX */
+ plog(XLOG_ERROR, "Could not mount %s: %m", dir);
+ }
+ return error;
+ }
+ return 0;
+}
+
+static void union_mounted P((mntfs *mf));
+static void union_mounted(mf)
+mntfs *mf;
+{
+ int i;
+
+ afs_mkcacheref(mf);
+
+ /*
+ * Having made the union mount point,
+ * populate all the entries...
+ */
+ for (i = 0; i <= last_used_map; i++) {
+ am_node *mp = exported_ap[i];
+ if (mp && mp->am_mnt == mf) {
+ /* return value from create_union_node is ignored by mapc_keyiter */
+ (void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private,
+ (void (*)P((char*,void*))) create_union_node, mp);
+ break;
+ }
+ }
+
+#ifdef notdef
+ /*
+ * would be nice to flush most of the cache, but we need to
+ * keep the wildcard and /defaults entries...
+ */
+ mapc_free(mf->mf_private);
+ mf->mf_private = (voidp) mapc_find(mf->mf_info, "inc");
+/* mapc_add_kv(mf->mf_private, strdup("/defaults"),
+ strdup("type:=link;opts:=nounmount;sublink:=${key}")); */
+#endif
+}
+#endif /* HAS_UNION_FS */
+
+/*
+ * Unmount an automount sub-node
+ */
+static int afs_umount P((am_node *mp));
+static int afs_umount(mp)
+am_node *mp;
+{
+ return 0;
+}
+
+/*
+ * Unmount a top-level automount node
+ */
+static int toplvl_umount P((am_node *mp));
+static int toplvl_umount(mp)
+am_node *mp;
+{
+ int error;
+
+ struct stat stb;
+again:
+ /*
+ * The lstat is needed if this mount is type=direct.
+ * When that happens, the kernel cache gets confused
+ * between the underlying type (dir) and the mounted
+ * type (link) and so needs to be re-synced before
+ * the unmount. This is all because the unmount system
+ * call follows links and so can't actually unmount
+ * a link (stupid!). It was noted that doing an ls -ld
+ * of the mount point to see why things were not working
+ * actually fixed the problem - so simulate an ls -ld here.
+ */
+ if (lstat(mp->am_path, &stb) < 0) {
+#ifdef DEBUG
+ dlog("lstat(%s): %m", mp->am_path);
+#endif /* DEBUG */
+ }
+ error = UMOUNT_FS(mp->am_path);
+ if (error == EBUSY) {
+ plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);
+ sleep(1); /* XXX */
+ goto again;
+ }
+
+ return error;
+}
+
+/*
+ * Unmount an automount node
+ */
+static void afs_umounted P((am_node *mp));
+static void afs_umounted(mp)
+am_node *mp;
+{
+ /*
+ * If this is a pseudo-directory then just adjust the link count
+ * in the parent, otherwise call the generic unmount routine
+ */
+ if (mp->am_parent && mp->am_parent->am_parent)
+ --mp->am_parent->am_fattr.nlink;
+}
+
+/*
+ * Mounting a file system may take a significant period of time. The
+ * problem is that if this is done in the main process thread then
+ * the entire automounter could be blocked, possibly hanging lots of
+ * processes on the system. Instead we use a continuation scheme to
+ * allow mounts to be attempted in a sub-process. When the sub-process
+ * exits we pick up the exit status (by convention a UN*X error number)
+ * and continue in a notifier. The notifier gets handed a data structure
+ * and can then determine whether the mount was successful or not. If
+ * not, it updates the data structure and tries again until there are no
+ * more ways to try the mount, or some other permanent error occurs.
+ * In the mean time no RPC reply is sent, even after the mount is succesful.
+ * We rely on the RPC retry mechanism to resend the lookup request which
+ * can then be handled.
+ */
+
+
+struct continuation {
+ char **ivec; /* Current mount info */
+ am_node *mp; /* Node we are trying to mount */
+ char *key; /* Map key */
+ char *info; /* Info string */
+ char **xivec; /* Saved strsplit vector */
+ char *auto_opts; /* Automount options */
+ am_opts fs_opts; /* Filesystem options */
+ char *def_opts; /* Default automount options */
+ int retry; /* Try again? */
+ int tried; /* Have we tried any yet? */
+ time_t start; /* Time we started this mount */
+ int callout; /* Callout identifier */
+};
+
+#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING)
+
+/*
+ * Discard an old continuation
+ */
+static void free_continuation P((struct continuation *cp));
+static void free_continuation(cp)
+struct continuation *cp;
+{
+ if (cp->callout)
+ untimeout(cp->callout);
+ free((voidp) cp->key);
+ free((voidp) cp->xivec);
+ free((voidp) cp->info);
+ free((voidp) cp->auto_opts);
+ free((voidp) cp->def_opts);
+ free_opts(&cp->fs_opts);
+ free((voidp) cp);
+}
+
+static int afs_bgmount P((struct continuation*, int));
+
+/*
+ * Discard the underlying mount point and replace
+ * with a reference to an error filesystem.
+ */
+static void assign_error_mntfs P((am_node *mp));
+static void assign_error_mntfs(mp)
+am_node *mp;
+{
+ if (mp->am_error > 0) {
+ /*
+ * Save the old error code
+ */
+ int error = mp->am_error;
+ if (error <= 0)
+ error = mp->am_mnt->mf_error;
+ /*
+ * Discard the old filesystem
+ */
+ free_mntfs(mp->am_mnt);
+ /*
+ * Allocate a new error reference
+ */
+ mp->am_mnt = new_mntfs();
+ /*
+ * Put back the error code
+ */
+ mp->am_mnt->mf_error = error;
+ mp->am_mnt->mf_flags |= MFF_ERROR;
+ /*
+ * Zero the error in the mount point
+ */
+ mp->am_error = 0;
+ }
+}
+
+/*
+ * The continuation function. This is called by
+ * the task notifier when a background mount attempt
+ * completes.
+ */
+static void afs_cont P((int rc, int term, voidp closure));
+static void afs_cont(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ struct continuation *cp = (struct continuation *) closure;
+ mntfs *mf = cp->mp->am_mnt;
+
+ /*
+ * Definitely not trying to mount at the moment
+ */
+ mf->mf_flags &= ~MFF_MOUNTING;
+ /*
+ * While we are mounting - try to avoid race conditions
+ */
+ new_ttl(cp->mp);
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) mf);
+
+ /*
+ * Check for termination signal or exit status...
+ */
+ if (rc || term) {
+ am_node *xmp;
+
+ if (term) {
+ /*
+ * Not sure what to do for an error code.
+ */
+ mf->mf_error = EIO; /* XXX ? */
+ mf->mf_flags |= MFF_ERROR;
+ plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
+ } else {
+ /*
+ * Check for exit status...
+ */
+ mf->mf_error = rc;
+ mf->mf_flags |= MFF_ERROR;
+ errno = rc; /* XXX */
+ plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
+ }
+
+ /*
+ * If we get here then that attempt didn't work, so
+ * move the info vector pointer along by one and
+ * call the background mount routine again
+ */
+ amd_stats.d_merr++;
+ cp->ivec++;
+ xmp = cp->mp;
+ (void) afs_bgmount(cp, 0);
+ assign_error_mntfs(xmp);
+ } else {
+ /*
+ * The mount worked.
+ */
+ am_mounted(cp->mp);
+ free_continuation(cp);
+ }
+
+ reschedule_timeout_mp();
+}
+
+/*
+ * Retry a mount
+ */
+/*ARGSUSED*/
+static void afs_retry P((int rc, int term, voidp closure));
+static void afs_retry(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ struct continuation *cp = (struct continuation *) closure;
+ int error = 0;
+
+#ifdef DEBUG
+ dlog("Commencing retry for mount of %s", cp->mp->am_path);
+#endif /* DEBUG */
+
+ new_ttl(cp->mp);
+
+ if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
+ /*
+ * The entire mount has timed out.
+ * Set the error code and skip past
+ * all the info vectors so that
+ * afs_bgmount will not have any more
+ * ways to try the mount, so causing
+ * an error.
+ */
+ plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
+ error = ETIMEDOUT;
+ while (*cp->ivec)
+ cp->ivec++;
+ }
+
+ if (error || !IN_PROGRESS(cp)) {
+ (void) afs_bgmount(cp, error);
+ }
+ reschedule_timeout_mp();
+}
+
+/*
+ * Try to mount a file system. Can be called
+ * directly or in a sub-process by run_task
+ */
+static int try_mount P((voidp mvp));
+static int try_mount(mvp)
+voidp mvp;
+{
+ /*
+ * Mount it!
+ */
+ int error;
+ am_node *mp = (am_node *) mvp;
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * If the directory is not yet made and
+ * it needs to be made, then make it!
+ * This may be run in a backgroun process
+ * in which case the flag setting won't be
+ * noticed later - but it is set anyway
+ * just after run_task is called. It
+ * should probably go away totally...
+ */
+ if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) {
+ error = mkdirs(mf->mf_mount, 0555);
+ if (!error)
+ mf->mf_flags |= MFF_MKMNT;
+ }
+
+ error = mount_node(mp);
+#ifdef DEBUG
+ if (error > 0) {
+ errno = error;
+ dlog("afs call to mount_node failed: %m");
+ }
+#endif /* DEBUG */
+ return error;
+}
+
+/*
+ * Pick a file system to try mounting and
+ * do that in the background if necessary
+ *
+For each location:
+ if it is new -defaults then
+ extract and process
+ continue;
+ fi
+ if it is a cut then
+ if a location has been tried then
+ break;
+ fi
+ continue;
+ fi
+ parse mount location
+ discard previous mount location if required
+ find matching mounted filesystem
+ if not applicable then
+ this_error = No such file or directory
+ continue
+ fi
+ if the filesystem failed to be mounted then
+ this_error = error from filesystem
+ elif the filesystem is mounting or unmounting then
+ this_error = -1
+ elif the fileserver is down then
+ this_error = -1
+ elif the filesystem is already mounted
+ this_error = 0
+ break
+ fi
+ if no error on this mount then
+ this_error = initialise mount point
+ fi
+ if no error on this mount and mount is delayed then
+ this_error = -1
+ fi
+ if this_error < 0 then
+ retry = true
+ fi
+ if no error on this mount then
+ make mount point if required
+ fi
+ if no error on this mount then
+ if mount in background then
+ run mount in background
+ return -1
+ else
+ this_error = mount in foreground
+ fi
+ fi
+ if an error occured on this mount then
+ update stats
+ save error in mount point
+ fi
+endfor
+ */
+
+static int afs_bgmount P((struct continuation *cp, int mpe));
+static int afs_bgmount(cp, mpe)
+struct continuation *cp;
+int mpe;
+{
+ mntfs *mf = cp->mp->am_mnt; /* Current mntfs */
+ mntfs *mf_retry = 0; /* First mntfs which needed retrying */
+ int this_error = -1; /* Per-mount error */
+ int hard_error = -1;
+ int mp_error = mpe;
+
+ /*
+ * Try to mount each location.
+ * At the end:
+ * hard_error == 0 indicates something was mounted.
+ * hard_error > 0 indicates everything failed with a hard error
+ * hard_error < 0 indicates nothing could be mounted now
+ */
+ for (; this_error && *cp->ivec; cp->ivec++) {
+ am_ops *p;
+ am_node *mp = cp->mp;
+ char *link_dir;
+ int dont_retry;
+
+ if (hard_error < 0)
+ hard_error = this_error;
+
+ this_error = -1;
+
+ if (**cp->ivec == '-') {
+ /*
+ * Pick up new defaults
+ */
+ if (cp->auto_opts && *cp->auto_opts)
+ cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec+1);
+ else
+ cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1);
+#ifdef DEBUG
+ dlog("Setting def_opts to \"%s\"", cp->def_opts);
+#endif /* DEBUG */
+ continue;
+ }
+
+ /*
+ * If a mount has been attempted, and we find
+ * a cut then don't try any more locations.
+ */
+ if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
+ if (cp->tried) {
+#ifdef DEBUG
+ dlog("Cut: not trying any more locations for %s",
+ mp->am_path);
+#endif /* DEBUG */
+ break;
+ }
+ continue;
+ }
+
+#ifdef SUNOS4_COMPAT
+#ifdef nomore
+ /*
+ * By default, you only get this bit on SunOS4.
+ * If you want this anyway, then define SUNOS4_COMPAT
+ * in the relevant "os-blah.h" file.
+ *
+ * We make the observation that if the local key line contains
+ * no '=' signs then either it is sick, or it is a SunOS4-style
+ * "host:fs[:link]" line. In the latter case the am_opts field
+ * is also assumed to be in old-style, so you can't mix & match.
+ * You can use ${} expansions for the fs and link bits though...
+ *
+ * Actually, this doesn't really cover all the possibilities for
+ * the latest SunOS automounter and it is debatable whether there
+ * is any point bothering.
+ */
+ if (strchr(*cp->ivec, '=') == 0)
+ p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
+ else
+#endif
+#endif /* SUNOS4_COMPAT */
+ p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
+
+ /*
+ * Find a mounted filesystem for this node.
+ */
+ mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs,
+ cp->fs_opts.fs_mtab, cp->auto_opts, cp->fs_opts.opt_opts, cp->fs_opts.opt_remopts);
+
+ p = mf->mf_ops;
+#ifdef DEBUG
+ dlog("Got a hit with %s", p->fs_type);
+#endif /* DEBUG */
+ /*
+ * Note whether this is a real mount attempt
+ */
+ if (p == &efs_ops) {
+ plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path);
+ if (this_error <= 0)
+ this_error = ENOENT;
+ continue;
+ } else {
+ if (cp->fs_opts.fs_mtab) {
+ plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
+ cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
+ }
+ cp->tried = TRUE;
+ }
+
+ this_error = 0;
+ dont_retry = FALSE;
+
+ if (mp->am_link) {
+ free(mp->am_link);
+ mp->am_link = 0;
+ }
+
+ link_dir = mf->mf_fo->opt_sublink;
+
+ if (link_dir && *link_dir) {
+ if (*link_dir == '/') {
+ mp->am_link = strdup(link_dir);
+ } else {
+ mp->am_link = str3cat((char *) 0,
+ mf->mf_fo->opt_fs, "/", link_dir);
+ normalize_slash(mp->am_link);
+ }
+ }
+
+ if (mf->mf_error > 0) {
+ this_error = mf->mf_error;
+ } else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) {
+ /*
+ * Still mounting - retry later
+ */
+#ifdef DEBUG
+ dlog("Duplicate pending mount fstype %s", p->fs_type);
+#endif /* DEBUG */
+ this_error = -1;
+ } else if (FSRV_ISDOWN(mf->mf_server)) {
+ /*
+ * Would just mount from the same place
+ * as a hung mount - so give up
+ */
+#ifdef DEBUG
+ dlog("%s is already hung - giving up", mf->mf_mount);
+#endif /* DEBUG */
+ mp_error = EWOULDBLOCK;
+ dont_retry = TRUE;
+ this_error = -1;
+ } else if (mf->mf_flags & MFF_MOUNTED) {
+#ifdef DEBUG
+ dlog("duplicate mount of \"%s\" ...", mf->mf_info);
+#endif /* DEBUG */
+ /*
+ * Just call mounted()
+ */
+ am_mounted(mp);
+
+ this_error = 0;
+ break;
+ }
+
+ /*
+ * Will usually need to play around with the mount nodes
+ * file attribute structure. This must be done here.
+ * Try and get things initialised, even if the fileserver
+ * is not known to be up. In the common case this will
+ * progress things faster.
+ */
+ if (!this_error) {
+ /*
+ * Fill in attribute fields.
+ */
+ if (mf->mf_ops->fs_flags & FS_DIRECTORY)
+ mk_fattr(mp, NFDIR);
+ else
+ mk_fattr(mp, NFLNK);
+
+ mp->am_fattr.fileid = mp->am_gen;
+
+ if (p->fs_init)
+ this_error = (*p->fs_init)(mf);
+ }
+
+ /*
+ * Make sure the fileserver is UP before doing any more work
+ */
+ if (!FSRV_ISUP(mf->mf_server)) {
+#ifdef DEBUG
+ dlog("waiting for server %s to become available", mf->mf_server->fs_host);
+#endif
+ this_error = -1;
+ }
+
+ if (!this_error && mf->mf_fo->opt_delay) {
+ /*
+ * If there is a delay timer on the mount
+ * then don't try to mount if the timer
+ * has not expired.
+ */
+ int i = atoi(mf->mf_fo->opt_delay);
+ if (i > 0 && clocktime() < (cp->start + i)) {
+#ifdef DEBUG
+ dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start);
+#endif /* DEBUG */
+ this_error = -1;
+ }
+ }
+
+ if (this_error < 0 && !dont_retry) {
+ if (!mf_retry)
+ mf_retry = dup_mntfs(mf);
+ cp->retry = TRUE;
+ }
+
+ if (!this_error)
+ if (p->fs_flags & FS_MBACKGROUND) {
+ mf->mf_flags |= MFF_MOUNTING; /*XXX*/
+#ifdef DEBUG
+ dlog("backgrounding mount of \"%s\"", mf->mf_mount);
+#endif /* DEBUG */
+ if (cp->callout) {
+ untimeout(cp->callout);
+ cp->callout = 0;
+ }
+ run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
+ mf->mf_flags |= MFF_MKMNT; /* XXX */
+ if (mf_retry) free_mntfs(mf_retry);
+ return -1;
+ } else {
+#ifdef DEBUG
+ dlog("foreground mount of \"%s\" ...", mf->mf_info);
+#endif /* DEBUG */
+ this_error = try_mount((voidp) mp);
+ if (this_error < 0) {
+ if (!mf_retry)
+ mf_retry = dup_mntfs(mf);
+ cp->retry = TRUE;
+ }
+ }
+
+ if (this_error >= 0) {
+ if (this_error > 0) {
+ amd_stats.d_merr++;
+ if (mf != mf_retry) {
+ mf->mf_error = this_error;
+ mf->mf_flags |= MFF_ERROR;
+ }
+ }
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) mf);
+ }
+ }
+
+ if (this_error && cp->retry) {
+ free_mntfs(mf);
+ mf = cp->mp->am_mnt = mf_retry;
+ /*
+ * Not retrying again (so far)
+ */
+ cp->retry = FALSE;
+ cp->tried = FALSE;
+ /*
+ * Start at the beginning.
+ * Rewind the location vector and
+ * reset the default options.
+ */
+ cp->ivec = cp->xivec;
+ cp->def_opts = strealloc(cp->def_opts, cp->auto_opts);
+ /*
+ * Arrange that afs_bgmount is called
+ * after anything else happens.
+ */
+#ifdef DEBUG
+ dlog("Arranging to retry mount of %s", cp->mp->am_path);
+#endif /* DEBUG */
+ sched_task(afs_retry, (voidp) cp, (voidp) mf);
+ if (cp->callout)
+ untimeout(cp->callout);
+ cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
+
+ cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
+
+ /*
+ * Not done yet - so don't return anything
+ */
+ return -1;
+ }
+
+ if (hard_error < 0 || this_error == 0)
+ hard_error = this_error;
+
+ /*
+ * Discard handle on duff filesystem.
+ * This should never happen since it
+ * should be caught by the case above.
+ */
+ if (mf_retry) {
+ if (hard_error)
+ plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
+ free_mntfs(mf_retry);
+ }
+
+ /*
+ * If we get here, then either the mount succeeded or
+ * there is no more mount information available.
+ */
+ if (hard_error < 0 && mp_error)
+ hard_error = cp->mp->am_error = mp_error;
+ if (hard_error > 0) {
+ /*
+ * Set a small(ish) timeout on an error node if
+ * the error was not a time out.
+ */
+ switch (hard_error) {
+ case ETIMEDOUT:
+ case EWOULDBLOCK:
+ cp->mp->am_timeo = 5;
+ break;
+ default:
+ cp->mp->am_timeo = 17;
+ break;
+ }
+ new_ttl(cp->mp);
+ }
+
+ /*
+ * Make sure that the error value in the mntfs has a
+ * reasonable value.
+ */
+ if (mf->mf_error < 0) {
+ mf->mf_error = hard_error;
+ if (hard_error)
+ mf->mf_flags |= MFF_ERROR;
+ }
+
+ /*
+ * In any case we don't need the continuation any more
+ */
+ free_continuation(cp);
+
+ return hard_error;
+}
+
+/*
+ * Automount interface to RPC lookup routine
+ */
+static am_node *afs_lookuppn P((am_node *mp, char *fname, int *error_return, int op));
+static am_node *afs_lookuppn(mp, fname, error_return, op)
+am_node *mp;
+char *fname;
+int *error_return;
+int op;
+{
+#define ereturn(x) { *error_return = x; return 0; }
+
+ /*
+ * Find the corresponding entry and return
+ * the file handle for it.
+ */
+ am_node *ap, *new_mp, *ap_hung;
+ char *info; /* Mount info - where to get the file system */
+ char **ivec, **xivec; /* Split version of info */
+ char *auto_opts; /* Automount options */
+ int error = 0; /* Error so far */
+ char path_name[MAXPATHLEN]; /* General path name buffer */
+ char *pfname; /* Path for database lookup */
+ struct continuation *cp; /* Continuation structure if we need to mount */
+ int in_progress = 0; /* # of (un)mount in progress */
+ char *dflts;
+ mntfs *mf;
+
+#ifdef DEBUG
+ dlog("in afs_lookuppn");
+#endif /* DEBUG */
+
+ /*
+ * If the server is shutting down
+ * then don't return information
+ * about the mount point.
+ */
+ if (amd_state == Finishing) {
+#ifdef DEBUG
+ if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &dfs_ops)
+ dlog("%s mount ignored - going down", fname);
+ else
+ dlog("%s/%s mount ignored - going down", mp->am_path, fname);
+#endif /* DEBUG */
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Handle special case of "." and ".."
+ */
+ if (fname[0] == '.') {
+ if (fname[1] == '\0')
+ return mp; /* "." is the current node */
+ if (fname[1] == '.' && fname[2] == '\0') {
+ if (mp->am_parent) {
+#ifdef DEBUG
+ dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
+#endif /* DEBUG */
+ return mp->am_parent; /* ".." is the parent node */
+ }
+ ereturn(ESTALE);
+ }
+ }
+
+ /*
+ * Check for valid key name.
+ * If it is invalid then pretend it doesn't exist.
+ */
+ if (!valid_key(fname)) {
+ plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Expand key name.
+ * fname is now a private copy.
+ */
+ fname = expand_key(fname);
+
+ for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
+ /*
+ * Otherwise search children of this node
+ */
+ if (FSTREQ(ap->am_name, fname)) {
+ mf = ap->am_mnt;
+ if (ap->am_error) {
+ error = ap->am_error;
+ continue;
+ }
+
+ /*
+ * If the error code is undefined then it must be
+ * in progress.
+ */
+ if (mf->mf_error < 0)
+ goto in_progrss;
+
+ /*
+ * Check for a hung node
+ */
+ if (FSRV_ISDOWN(mf->mf_server)) {
+#ifdef DEBUG
+ dlog("server hung");
+#endif /* DEBUG */
+ error = ap->am_error;
+ ap_hung = ap;
+ continue;
+ }
+
+ /*
+ * If there was a previous error with this node
+ * then return that error code.
+ */
+ if (mf->mf_flags & MFF_ERROR) {
+ error = mf->mf_error;
+ continue;
+ }
+
+ if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
+in_progrss:
+ /*
+ * If the fs is not mounted or it is unmounting then there
+ * is a background (un)mount in progress. In this case
+ * we just drop the RPC request (return nil) and
+ * wait for a retry, by which time the (un)mount may
+ * have completed.
+ */
+#ifdef DEBUG
+ dlog("ignoring mount of %s in %s -- in progress",
+ fname, mf->mf_mount);
+#endif /* DEBUG */
+ in_progress++;
+ continue;
+ }
+
+ /*
+ * Otherwise we have a hit: return the current mount point.
+ */
+#ifdef DEBUG
+ dlog("matched %s in %s", fname, ap->am_path);
+#endif /* DEBUG */
+ free(fname);
+ return ap;
+ }
+ }
+
+ if (in_progress) {
+#ifdef DEBUG
+ dlog("Waiting while %d mount(s) in progress", in_progress);
+#endif /* DEBUG */
+ free(fname);
+ ereturn(-1);
+ }
+
+ /*
+ * If an error occured then return it.
+ */
+ if (error) {
+#ifdef DEBUG
+ errno = error; /* XXX */
+ dlog("Returning error: %m", error);
+#endif /* DEBUG */
+ free(fname);
+ ereturn(error);
+ }
+
+ /*
+ * If doing a delete then don't create again!
+ */
+ switch (op) {
+ case VLOOK_DELETE:
+ ereturn(ENOENT);
+ break;
+
+ case VLOOK_CREATE:
+ break;
+
+ default:
+ plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
+ ereturn(EINVAL);
+ break;
+ }
+
+ /*
+ * If the server is going down then just return,
+ * don't try to mount any more file systems
+ */
+ if ((int)amd_state >= (int)Finishing) {
+#ifdef DEBUG
+ dlog("not found - server going down anyway");
+#endif /* DEBUG */
+ free(fname);
+ ereturn(ENOENT);
+ }
+
+ /*
+ * If we get there then this is a reference to an,
+ * as yet, unknown name so we need to search the mount
+ * map for it.
+ */
+ if (mp->am_pref) {
+ sprintf(path_name, "%s%s", mp->am_pref, fname);
+ pfname = path_name;
+ } else {
+ pfname = fname;
+ }
+
+ mf = mp->am_mnt;
+
+#ifdef DEBUG
+ dlog("will search map info in %s to find %s", mf->mf_info, pfname);
+#endif /* DEBUG */
+ /*
+ * Consult the oracle for some mount information.
+ * info is malloc'ed and belongs to this routine.
+ * It ends up being free'd in free_continuation().
+ *
+ * Note that this may return -1 indicating that information
+ * is not yet available.
+ */
+ error = mapc_search((mnt_map*) mf->mf_private, pfname, &info);
+ if (error) {
+ if (error > 0)
+ plog(XLOG_MAP, "No map entry for %s", pfname);
+ else
+ plog(XLOG_MAP, "Waiting on map entry for %s", pfname);
+ free(fname);
+ ereturn(error);
+ }
+
+#ifdef DEBUG
+ dlog("mount info is %s", info);
+#endif /* DEBUG */
+
+ /*
+ * Split info into an argument vector.
+ * The vector is malloc'ed and belongs to
+ * this routine. It is free'd in free_continuation()
+ */
+ xivec = ivec = strsplit(info, ' ', '\"');
+
+ /*
+ * Default error code...
+ */
+ if (ap_hung)
+ error = EWOULDBLOCK;
+ else
+ error = ENOENT;
+
+ /*
+ * Allocate a new map
+ */
+ new_mp = exported_ap_alloc();
+ if (new_mp == 0) {
+ free((voidp) xivec);
+ free((voidp) info);
+ free((voidp) fname);
+ ereturn(ENOSPC);
+ }
+
+ if (mf->mf_auto)
+ auto_opts = mf->mf_auto;
+ else
+ auto_opts = "";
+
+ auto_opts = strdup(auto_opts);
+
+#ifdef DEBUG
+ dlog("searching for /defaults entry");
+#endif /* DEBUG */
+ if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) {
+ char *dfl;
+ char **rvec;
+#ifdef DEBUG
+ dlog("/defaults gave %s", dflts);
+#endif /* DEBUG */
+ if (*dflts == '-')
+ dfl = dflts+1;
+ else
+ dfl = dflts;
+
+ /*
+ * Chop the defaults up
+ */
+ rvec = strsplit(dfl, ' ', '\"');
+ /*
+ * Extract first value
+ */
+ dfl = rvec[0];
+
+ /*
+ * If there were any values at all...
+ */
+ if (dfl) {
+ /*
+ * Log error if there were other values
+ */
+ if (rvec[1]) {
+#ifdef DEBUG
+ dlog("/defaults chopped into %s", dfl);
+#endif /* DEBUG */
+ plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
+ }
+
+ /*
+ * Prepend to existing defaults if they exist,
+ * otherwise just use these defaults.
+ */
+ if (*auto_opts && *dfl) {
+ char *nopts = (char *) xmalloc(strlen(auto_opts)+strlen(dfl)+2);
+ sprintf(nopts, "%s;%s", dfl, auto_opts);
+ free(auto_opts);
+ auto_opts = nopts;
+ } else if (*dfl) {
+ auto_opts = strealloc(auto_opts, dfl);
+ }
+ }
+ free(dflts);
+ /*
+ * Don't need info vector any more
+ */
+ free((voidp) rvec);
+ }
+
+ /*
+ * Fill it in
+ */
+ init_map(new_mp, fname);
+
+ /*
+ * Put it in the table
+ */
+ insert_am(new_mp, mp);
+
+ /*
+ * Fill in some other fields,
+ * path and mount point.
+ *
+ * bugfix: do not prepend old am_path if direct map
+ * <wls@astro.umd.edu> William Sebok
+ */
+ new_mp->am_path = str3cat(new_mp->am_path,
+ mf->mf_ops == &dfs_ops ? "" : mp->am_path,
+ *fname == '/' ? "" : "/", fname);
+
+#ifdef DEBUG
+ dlog("setting path to %s", new_mp->am_path);
+#endif /* DEBUG */
+
+ /*
+ * Take private copy of pfname
+ */
+ pfname = strdup(pfname);
+
+ /*
+ * Construct a continuation
+ */
+ cp = ALLOC(continuation);
+ cp->mp = new_mp;
+ cp->xivec = xivec;
+ cp->ivec = ivec;
+ cp->info = info;
+ cp->key = pfname;
+ cp->auto_opts = auto_opts;
+ cp->retry = FALSE;
+ cp->tried = FALSE;
+ cp->start = clocktime();
+ cp->def_opts = strdup(auto_opts);
+ bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts));
+
+ /*
+ * Try and mount the file system
+ * If this succeeds immediately (possible
+ * for a ufs file system) then return
+ * the attributes, otherwise just
+ * return an error.
+ */
+ error = afs_bgmount(cp, error);
+ reschedule_timeout_mp();
+ if (!error) {
+ free(fname);
+ return new_mp;
+ }
+
+ if (error && (cp->mp->am_mnt->mf_ops == &efs_ops))
+ cp->mp->am_error = error;
+
+ assign_error_mntfs(new_mp);
+
+ free(fname);
+
+ ereturn(error);
+#undef ereturn
+}
+
+/*
+ * Locate next node in sibling list which is mounted
+ * and is not an error node.
+ */
+static am_node *next_nonerror_node P((am_node *xp));
+static am_node *next_nonerror_node(xp)
+am_node *xp;
+{
+ mntfs *mf;
+
+ /*
+ * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
+ * Fixes a race condition when mounting direct automounts.
+ * Also fixes a problem when doing a readdir on a directory
+ * containing hung automounts.
+ */
+ while (xp &&
+ (!(mf = xp->am_mnt) || /* No mounted filesystem */
+ mf->mf_error != 0 || /* There was a mntfs error */
+ xp->am_error != 0 || /* There was a mount error */
+ !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
+ (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
+ )
+ xp = xp->am_osib;
+
+ return xp;
+}
+
+static int afs_readdir P((am_node *mp, nfscookie cookie, struct dirlist *dp, struct entry *ep, int count));
+static int afs_readdir(mp, cookie, dp, ep, count)
+am_node *mp;
+nfscookie cookie;
+struct dirlist *dp;
+struct entry *ep;
+int count;
+{
+ unsigned int gen = *(unsigned int*) cookie;
+ am_node *xp;
+
+ dp->eof = FALSE;
+
+ if (gen == 0) {
+ /*
+ * In the default instance (which is used to
+ * start a search) we return "." and "..".
+ *
+ * This assumes that the count is big enough
+ * to allow both "." and ".." to be returned in
+ * a single packet. If it isn't (which would
+ * be fairly unbelievable) then tough.
+ */
+#ifdef DEBUG
+ dlog("default search");
+#endif /* DEBUG */
+ /*
+ * Check for enough room. This is extremely
+ * approximate but is more than enough space.
+ * Really need 2 times:
+ * 4byte fileid
+ * 4byte cookie
+ * 4byte name length
+ * 4byte name
+ * plus the dirlist structure
+ */
+ if (count <
+ (2 * (2 * (sizeof(*ep) + sizeof("..") + 4)
+ + sizeof(*dp))))
+ return EINVAL;
+
+ xp = next_nonerror_node(mp->am_child);
+ dp->entries = ep;
+
+ /* construct "." */
+ ep[0].fileid = mp->am_gen;
+ ep[0].name = ".";
+ ep[0].nextentry = &ep[1];
+ *(unsigned int *) ep[0].cookie = 0;
+
+ /* construct ".." */
+ if (mp->am_parent)
+ ep[1].fileid = mp->am_parent->am_gen;
+ else
+ ep[1].fileid = mp->am_gen;
+ ep[1].name = "..";
+ ep[1].nextentry = 0;
+ *(unsigned int *) ep[1].cookie =
+ xp ? xp->am_gen : ~(unsigned int)0;
+
+ if (!xp) dp->eof = TRUE;
+ return 0;
+ }
+
+#ifdef DEBUG
+ dlog("real child");
+#endif /* DEBUG */
+
+ if (gen == ~(unsigned int)0) {
+#ifdef DEBUG
+ dlog("End of readdir in %s", mp->am_path);
+#endif /* DEBUG */
+ dp->eof = TRUE;
+ dp->entries = 0;
+ return 0;
+ }
+
+ xp = mp->am_child;
+ while (xp && xp->am_gen != gen)
+ xp = xp->am_osib;
+
+ if (xp) {
+ int nbytes = count / 2; /* conservative */
+ int todo = MAX_READDIR_ENTRIES;
+ dp->entries = ep;
+ do {
+ am_node *xp_next = next_nonerror_node(xp->am_osib);
+
+ if (xp_next) {
+ *(unsigned int *) ep->cookie = xp_next->am_gen;
+ } else {
+ *(unsigned int *) ep->cookie = ~(unsigned int)0;
+ dp->eof = TRUE;
+ }
+
+ ep->fileid = xp->am_gen;
+ ep->name = xp->am_name;
+ nbytes -= sizeof(*ep) + strlen(xp->am_name) + 1;
+
+ xp = xp_next;
+
+ if (nbytes > 0 && !dp->eof && todo > 1) {
+ ep->nextentry = ep + 1;
+ ep++;
+ --todo;
+ } else {
+ todo = 0;
+ }
+ } while (todo > 0);
+
+ ep->nextentry = 0;
+
+ return 0;
+ }
+
+ return ESTALE;
+
+}
+
+static am_node *dfs_readlink P((am_node *mp, int *error_return));
+static am_node *dfs_readlink(mp, error_return)
+am_node *mp;
+int *error_return;
+{
+ am_node *xp;
+ int rc = 0;
+
+ xp = next_nonerror_node(mp->am_child);
+ if (!xp) {
+ if (!mp->am_mnt->mf_private)
+ afs_mkcacheref(mp->am_mnt); /* XXX */
+ xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
+ }
+
+ if (xp) {
+ new_ttl(xp); /* (7/12/89) from Rein Tollevik */
+ return xp;
+ }
+ if (amd_state == Finishing)
+ rc = ENOENT;
+ *error_return = rc;
+ return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops root_ops = {
+ "root",
+ 0, /* root_match */
+ 0, /* root_init */
+ root_mount,
+ 0,
+ afs_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* root_readlink */
+ 0, /* root_mounted */
+ 0, /* root_umounted */
+ find_afs_srvr,
+ FS_NOTIMEOUT|FS_AMQINFO|FS_DIRECTORY
+};
+
+am_ops afs_ops = {
+ "auto",
+ afs_match,
+ 0, /* afs_init */
+ afs_mount,
+ 0,
+ afs_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* afs_readlink */
+ 0, /* afs_mounted */
+ afs_umounted,
+ find_afs_srvr,
+ FS_AMQINFO|FS_DIRECTORY
+};
+
+am_ops toplvl_ops = {
+ "toplvl",
+ afs_match,
+ 0, /* afs_init */
+ toplvl_mount,
+ 0,
+ toplvl_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* toplvl_readlink */
+ toplvl_mounted,
+ 0, /* toplvl_umounted */
+ find_afs_srvr,
+ FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
+};
+
+am_ops dfs_ops = {
+ "direct",
+ afs_match,
+ 0, /* dfs_init */
+ toplvl_mount,
+ 0,
+ toplvl_umount,
+ 0,
+ efs_lookuppn,
+ efs_readdir,
+ dfs_readlink,
+ toplvl_mounted,
+ 0, /* afs_umounted */
+ find_afs_srvr,
+ FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#ifdef HAS_UNION_FS
+am_ops union_ops = {
+ "union",
+ afs_match,
+ 0, /* afs_init */
+ toplvl_mount,
+ 0,
+ toplvl_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* toplvl_readlink */
+ union_mounted,
+ 0, /* toplvl_umounted */
+ find_afs_srvr,
+ FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
+};
+#endif /* HAS_UNION_FS */
diff --git a/usr.sbin/amd/amd/am_ops.c b/usr.sbin/amd/amd/am_ops.c
new file mode 100644
index 000000000000..436011010fef
--- /dev/null
+++ b/usr.sbin/amd/amd/am_ops.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)am_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: am_ops.c,v 5.2.2.1 1992/02/09 15:08:17 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+static am_ops *vops[] = {
+#ifdef HAS_UFS
+ &ufs_ops,
+#endif
+#ifdef HAS_NFS
+ &nfs_ops,
+#endif
+#ifdef HAS_NFSX
+ &nfsx_ops,
+#endif
+#ifdef HAS_HOST
+ &host_ops,
+#endif
+#ifdef HAS_SFS
+ &sfs_ops,
+#endif
+#ifdef HAS_SFSX
+ &sfsx_ops,
+#endif
+#ifdef HAS_LOFS
+ &lofs_ops,
+#endif
+#ifdef HAS_PFS
+ &pfs_ops,
+#endif
+#ifdef HAS_UNION_FS
+ &union_ops,
+#endif
+ &afs_ops, /* These four should be last ... */
+ &dfs_ops, /* ... */
+ &toplvl_ops, /* ... */
+ &efs_ops, /* ... in the order afs; dfs; toplvl; efs */
+ 0
+};
+
+void ops_showfstypes P((FILE *fp));
+void ops_showfstypes(fp)
+FILE *fp;
+{
+ struct am_ops **ap;
+ int l = 0;
+
+ for (ap = vops; *ap; ap++) {
+ fputs((*ap)->fs_type, fp);
+ if (ap[1]) fputs(", ", fp);
+ l += strlen((*ap)->fs_type) + 2;
+ if (l > 60) { l = 0; fputs("\n ", fp); }
+ }
+}
+
+#ifdef SUNOS4_COMPAT
+#ifdef nomore
+/*
+ * Crack a SunOS4-style host:fs:sub-link line
+ * Construct an amd-style line and call the
+ * normal amd matcher.
+ */
+am_ops *sunos4_match(fo, key, g_key, path, keym, map)
+am_opts *fo;
+char *key;
+char *g_key;
+char *path;
+char *keym;
+char *map;
+{
+ char *host = key;
+ char *fs = strchr(host, ':');
+ char *sublink = fs ? strchr(fs+1, ':') : 0;
+ char keybuf[MAXPATHLEN];
+
+ sprintf(keybuf, "type:=nfs;rhost:=%s;rfs:=%s;sublink:=%s;opts:=%s", host,
+ fs ? fs+1 : "",
+ sublink ? sublink+1 : "",
+ g_key);
+ return ops_match(fo, keybuf, "", path, keym, map);
+}
+#endif
+#endif /* SUNOS4_COMPAT */
+
+am_ops *ops_match(fo, key, g_key, path, keym, map)
+am_opts *fo;
+char *key;
+char *g_key;
+char *path;
+char *keym;
+char *map;
+{
+ am_ops **vp;
+ am_ops *rop = 0;
+
+ /*
+ * First crack the global opts and the local opts
+ */
+ if (!eval_fs_opts(fo, key, g_key, path, keym, map)) {
+ rop = &efs_ops;
+ } else if (fo->opt_type == 0) {
+ plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map);
+ rop = &efs_ops;
+ } else {
+ /*
+ * Next find the correct filesystem type
+ */
+ for (vp = vops; rop = *vp; vp++)
+ if (strcmp(rop->fs_type, fo->opt_type) == 0)
+ break;
+
+ if (!rop) {
+ plog(XLOG_USER, "fs type \"%s\" not recognised", fo->opt_type);
+ rop = &efs_ops;
+ }
+ }
+
+ /*
+ * Make sure we have a default mount option.
+ * Otherwise skip past any leading '-'.
+ */
+ if (fo->opt_opts == 0)
+ fo->opt_opts = "rw,defaults";
+ else if (*fo->opt_opts == '-')
+ fo->opt_opts++;
+
+ /*
+ * Check the filesystem is happy
+ */
+ if (fo->fs_mtab)
+ free((voidp) fo->fs_mtab);
+
+ if (fo->fs_mtab = (*rop->fs_match)(fo))
+ return rop;
+
+ /*
+ * Return error file system
+ */
+ fo->fs_mtab = (*efs_ops.fs_match)(fo);
+ return &efs_ops;
+}
diff --git a/usr.sbin/amd/amd/amd.8 b/usr.sbin/amd/amd/amd.8
new file mode 100644
index 000000000000..9fa01a2b469d
--- /dev/null
+++ b/usr.sbin/amd/amd/amd.8
@@ -0,0 +1,232 @@
+.\"
+.\" Copyright (c) 1989 Jan-Simon Pendry
+.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jan-Simon Pendry at Imperial College, London.
+.\"
+.\" 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.
+.\"
+.\" @(#)amd.8 5.10 (Berkeley) 4/19/94
+.\"
+.\" $Id: amd.8,v 5.2.2.1 1992/02/09 15:11:39 jsp beta $
+.\"
+.Dd "April 19, 1994"
+.Dt AMD 8
+.Os
+.Sh NAME
+.Nm amd
+.Nd automatically mount file systems
+.Sh SYNOPSIS
+.Nm amd
+.Op Fl nprv
+.Op Fl a Ar mount_point
+.Op Fl c Ar duration
+.Op Fl d Ar domain
+.Bk -words
+.Op Fl k Ar kernel-arch
+.Ek
+.Op Fl l Ar logfile
+.Op Fl t Ar interval.interval
+.Bk -words
+.Op Fl w Ar interval
+.Ek
+.Op Fl x Ar log-option
+.Op Fl y Ar YP-domain
+.Bk -words
+.Op Fl C Ar cluster-name
+.Ek
+.Op Fl D Ar option
+.Oo
+.Ar directory mapname
+.Op Fl map-options
+.Oc
+.Ar ...
+.Sh DESCRIPTION
+.Nm Amd
+is a daemon that automatically mounts filesystems
+whenever a file or directory
+within that filesystem is accessed.
+Filesystems are automatically unmounted when they
+appear to be quiescent.
+.Pp
+.Nm Amd
+operates by attaching itself as an
+.Tn NFS
+server to each of the specified
+.Ar directories .
+Lookups within the specified directories
+are handled by
+.Nm amd ,
+which uses the map defined by
+.Ar mapname
+to determine how to resolve the lookup.
+Generally, this will be a host name, some filesystem information
+and some mount options for the given filesystem.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl a Ar temporary-directory
+Specify an alternative location for the real mount points.
+The default is
+.Pa /a .
+.It Fl c Ar duration
+Specify a
+.Ar duration ,
+in seconds, that a looked up name remains
+cached when not in use. The default is 5 minutes.
+.It Fl d Ar domain
+Specify the local domain name. If this option is not
+given the domain name is determined from the hostname.
+.It Fl k Ar kernel-arch
+Specifies the kernel architecture. This is used solely
+to set the ${karch} selector.
+.It Fl l Ar logfile
+Specify a logfile in which to record mount and unmount events.
+If
+.Ar logfile
+is the string
+.Em syslog ,
+the log messages will be sent to the system log daemon by
+.Xr syslog 3 .
+.It Fl n
+Normalize hostnames.
+The name referred to by ${rhost} is normalized relative to the
+host database before being used. The effect is to translate
+aliases into ``official'' names.
+.It Fl p
+Print
+.Em PID .
+Outputs the process-id of
+.Nm amd
+to standard output where it can be saved into a file.
+.It Fl r
+Restart existing mounts.
+.Nm Amd
+will scan the mount file table to determine which filesystems
+are currently mounted. Whenever one of these would have
+been auto-mounted,
+.Nm amd
+.Em inherits
+it.
+.It Fl t Ar interval.interval
+Specify the
+.Ar interval ,
+in tenths of a second, between
+.Tn NFS/RPC/UDP
+retries.
+The default is 0.8 seconds.
+The second values alters the retransmit counter.
+Useful defaults are supplied if either or both
+values are missing.
+.It Fl v
+Version. Displays version and configuration information on standard error.
+.It Fl w Ar interval
+Specify an
+.Ar interval ,
+in seconds, between attempts to dismount
+filesystems that have exceeded their cached times.
+The default is 2 minutes.
+.It Fl y Ar domain
+Specify an alternative
+.Tn NIS
+domain from which to fetch the
+.Tn NIS
+maps.
+The default is the system domain name.
+This option is ignored if
+.Tn NIS
+support is not available.
+.It Fl x Ar options
+Specify run-time logging options. The options are a comma separated
+list chosen from: fatal, error, user, warn, info, map, stats, all.
+.It Fl D Ar option
+Select from a variety of debug options. Prefixing an
+option with the string
+.Em no
+reverses the effect of that option. Options are cumulative.
+The most useful option is
+.Ar all .
+.El
+.Pp
+Since
+.Fl D
+is only used for debugging other options are not documented here:
+the current supported set of options is listed by the
+.Fl v
+option
+and a fuller description is available in the program source.
+.Sh FILES
+.Bl -tag -width /axx
+.It Pa /a
+directory under which filesystems are dynamically mounted
+.El
+.Sh CAVEATS
+Some care may be required when creating a mount map.
+.Pp
+Symbolic links on an
+.Tn NFS
+filesystem can be incredibly inefficient.
+In most implementations of
+.Tn NFS ,
+their interpolations are not cached by
+the kernel and each time a symbolic link is
+encountered during a
+.Em lookuppn
+translation it costs an
+.Tn RPC
+call to the
+.Tn NFS
+server.
+A large improvement in real-time
+performance could be gained by adding a cache somewhere.
+Replacing
+.Xr symlinks 2
+with a suitable incarnation of the auto-mounter
+results in a large real-time speedup, but also causes a large
+number of process context switches.
+.Pp
+A weird imagination is most useful to gain full advantage of all
+the features.
+.Sh SEE ALSO
+.Xr amq 8 ,
+.Xr hostname 1 ,
+.Xr mount 8 ,
+.Xr umount 8 ,
+.Rs
+.%T Amd \- The 4.4 BSD Automounter
+.Re
+.Sh AUTHOR
+.An Jan-Simon Pendry
+<jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK.
+.Sh HISTORY
+The
+.Nm amd
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/amd/amd/amd.c b/usr.sbin/amd/amd/amd.c
new file mode 100644
index 000000000000..c3b2b61f3ed2
--- /dev/null
+++ b/usr.sbin/amd/amd/amd.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)amd.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amd.c,v 5.2.2.1 1992/02/09 15:08:15 jsp beta $
+ *
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Automounter
+ */
+
+#include "am.h"
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <setjmp.h>
+
+char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */
+char *progname; /* "amd" */
+#ifdef HAS_HOST
+#ifdef HOST_EXEC
+char *host_helper;
+#endif /* HOST_EXEC */
+#endif /* HAS_HOST */
+char *auto_dir = "/a";
+char *hostdomain = "unknown.domain";
+char hostname[MAXHOSTNAMELEN] = "localhost"; /* Hostname */
+char hostd[2*MAXHOSTNAMELEN]; /* Host+domain */
+char *op_sys = OS_REP; /* Name of current op_sys */
+char *arch = ARCH_REP; /* Name of current architecture */
+char *endian = ARCH_ENDIAN; /* Big or Little endian */
+char *wire;
+int foreground = 1; /* This is the top-level server */
+int mypid; /* Current process id */
+int immediate_abort; /* Should close-down unmounts be retried */
+struct in_addr myipaddr; /* (An) IP address of this host */
+serv_state amd_state;
+struct amd_stats amd_stats; /* Server statistics */
+time_t do_mapc_reload = 0; /* mapc_reload() call required? */
+jmp_buf select_intr;
+int select_intr_valid;
+int orig_umask;
+
+/*
+ * Signal handler:
+ * SIGINT - tells amd to do a full shutdown, including unmounting all filesystem.
+ * SIGTERM - tells amd to shutdown now. Just unmounts the automount nodes.
+ */
+static void sigterm(sig)
+int sig;
+{
+#ifdef SYS5_SIGNALS
+ signal(sig, sigterm);
+#endif /* SYS5_SIGNALS */
+
+ switch (sig) {
+ case SIGINT:
+ immediate_abort = 15;
+ break;
+
+ case SIGTERM:
+ immediate_abort = -1;
+ /* fall through... */
+
+ default:
+ plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
+ break;
+ }
+ if (select_intr_valid)
+ longjmp(select_intr, sig);
+}
+
+/*
+ * Hook for cache reload.
+ * When a SIGHUP arrives it schedules a call to mapc_reload
+ */
+/*ARGSUSED*/
+static void sighup(sig)
+int sig;
+{
+#ifdef SYS5_SIGNALS
+ signal(sig, sighup);
+#endif /* SYS5_SIGNALS */
+
+#ifdef DEBUG
+ if (sig != SIGHUP)
+ dlog("spurious call to sighup");
+#endif /* DEBUG */
+ /*
+ * Force a reload by zero'ing the timer
+ */
+ if (amd_state == Run)
+ do_mapc_reload = 0;
+}
+
+/*ARGSUSED*/
+static void parent_exit(sig)
+int sig;
+{
+ exit(0);
+}
+
+static int daemon_mode(P_void)
+{
+ int bgpid;
+
+ signal(SIGQUIT, parent_exit);
+ bgpid = background();
+
+ if (bgpid != 0) {
+ if (print_pid) {
+ printf("%d\n", bgpid);
+ fflush(stdout);
+ }
+ /*
+ * Now wait for the automount points to
+ * complete.
+ */
+ for (;;)
+ pause();
+ }
+
+ signal(SIGQUIT, SIG_DFL);
+
+ /*
+ * Pretend we are in the foreground again
+ */
+ foreground = 1;
+
+#ifdef TIOCNOTTY
+ {
+ int t = open("/dev/tty", O_RDWR);
+ if (t < 0) {
+ if (errno != ENXIO) /* not an error if already no controlling tty */
+ plog(XLOG_WARNING, "Could not open controlling tty: %m");
+ } else {
+ if (ioctl(t, TIOCNOTTY, 0) < 0 && errno != ENOTTY)
+ plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m");
+ (void) close(t);
+ }
+ }
+#else
+ (void) setpgrp();
+#endif /* TIOCNOTTY */
+
+ return getppid();
+}
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *domdot;
+ int ppid = 0;
+ int error;
+
+ /*
+ * Make sure some built-in assumptions are true before we start
+ */
+ assert(sizeof(nfscookie) >= sizeof (unsigned int));
+ assert(sizeof(int) >= 4);
+
+ /*
+ * Set processing status.
+ */
+ amd_state = Start;
+
+ /*
+ * Determine program name
+ */
+ if (argv[0]) {
+ progname = strrchr(argv[0], '/');
+ if (progname && progname[1])
+ progname++;
+ else
+ progname = argv[0];
+ }
+
+ if (!progname)
+ progname = "amd";
+
+ /*
+ * Initialise process id. This is kept
+ * cached since it is used for generating
+ * and using file handles.
+ */
+ mypid = getpid();
+
+ /*
+ * Get local machine name
+ */
+ if (gethostname(hostname, sizeof(hostname)) < 0) {
+ plog(XLOG_FATAL, "gethostname: %m");
+ going_down(1);
+ }
+ /*
+ * Check it makes sense
+ */
+ if (!*hostname) {
+ plog(XLOG_FATAL, "host name is not set");
+ going_down(1);
+ }
+ /*
+ * Partially initialise hostd[]. This
+ * is completed in get_args().
+ */
+ if (domdot = strchr(hostname, '.')) {
+ /*
+ * Hostname already contains domainname.
+ * Split out hostname and domainname
+ * components
+ */
+ *domdot++ = '\0';
+ hostdomain = domdot;
+ }
+ strcpy(hostd, hostname);
+
+ /*
+ * Trap interrupts for shutdowns.
+ */
+ (void) signal(SIGINT, sigterm);
+
+ /*
+ * Hangups tell us to reload the cache
+ */
+ (void) signal(SIGHUP, sighup);
+
+ /*
+ * Trap Terminate so that we can shutdown gracefully (some chance)
+ */
+ (void) signal(SIGTERM, sigterm);
+ /*
+ * Trap Death-of-a-child. These allow us to
+ * pick up the exit status of backgrounded mounts.
+ * See "sched.c".
+ */
+ (void) signal(SIGCHLD, sigchld);
+
+ /*
+ * Fix-up any umask problems. Most systems default
+ * to 002 which is not too convenient for our purposes
+ */
+ orig_umask = umask(0);
+
+ /*
+ * Figure out primary network name
+ */
+ wire = getwire();
+
+ /*
+ * Determine command-line arguments
+ */
+ get_args(argc, argv);
+
+ /*
+ * Get our own IP address so that we
+ * can mount the automounter.
+ */
+ { struct sockaddr_in sin;
+ get_myaddress(&sin);
+ myipaddr.s_addr = sin.sin_addr.s_addr;
+ }
+
+ /*
+ * Now check we are root.
+ */
+ if (geteuid() != 0) {
+ plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %d)", geteuid());
+ going_down(1);
+ }
+
+#ifdef HAS_NIS_MAPS
+ /*
+ * If the domain was specified then bind it here
+ * to circumvent any default bindings that may
+ * be done in the C library.
+ */
+ if (domain && yp_bind(domain)) {
+ plog(XLOG_FATAL, "Can't bind to domain \"%s\"", domain);
+ going_down(1);
+ }
+#endif /* HAS_NIS_MAPS */
+
+#ifdef DEBUG
+ Debug(D_DAEMON)
+#endif /* DEBUG */
+ ppid = daemon_mode();
+
+ sprintf(pid_fsname, "%s:(pid%d)", hostname, mypid);
+
+ do_mapc_reload = clocktime() + ONE_HOUR;
+
+ /*
+ * Register automounter with system
+ */
+ error = mount_automounter(ppid);
+ if (error && ppid)
+ kill(SIGALRM, ppid);
+ going_down(error);
+
+ abort();
+}
diff --git a/usr.sbin/amd/amd/amq_subr.c b/usr.sbin/amd/amd/amq_subr.c
new file mode 100644
index 000000000000..cf04d9d4160b
--- /dev/null
+++ b/usr.sbin/amd/amd/amq_subr.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)amq_subr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq_subr.c,v 5.2.2.1 1992/02/09 15:08:18 jsp beta $
+ *
+ */
+/*
+ * Auxilliary routines for amq tool
+ */
+
+#include "am.h"
+#include "amq.h"
+#include <ctype.h>
+
+/*ARGSUSED*/
+voidp
+amqproc_null_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp) &res;
+}
+
+/*
+ * Return a sub-tree of mounts
+ */
+/*ARGSUSED*/
+amq_mount_tree_p *
+amqproc_mnttree_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static am_node *mp;
+ mp = find_ap(*(char **) argp);
+ return (amq_mount_tree_p *) &mp;
+}
+
+/*
+ * Unmount a single node
+ */
+/*ARGSUSED*/
+voidp
+amqproc_umnt_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+ am_node *mp = find_ap(*(char **) argp);
+ if (mp)
+ forcibly_timeout_mp(mp);
+
+ return (voidp) &res;
+}
+
+/*
+ * Return global statistics
+ */
+/*ARGSUSED*/
+amq_mount_stats *
+amqproc_stats_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ return (amq_mount_stats *) &amd_stats;
+}
+
+/*
+ * Return the entire tree of mount nodes
+ */
+/*ARGSUSED*/
+amq_mount_tree_list *
+amqproc_export_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static amq_mount_tree_list aml;
+
+ aml.amq_mount_tree_list_val = (amq_mount_tree_p *) &exported_ap[0];
+ aml.amq_mount_tree_list_len = 1; /* XXX */
+
+ return &aml;
+}
+
+int *
+amqproc_setopt_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static int rc;
+
+ amq_setopt *opt = (amq_setopt *) argp;
+
+ rc = 0;
+ switch (opt->as_opt) {
+ case AMOPT_DEBUG:
+#ifdef DEBUG
+ if (debug_option(opt->as_str))
+ rc = EINVAL;
+#else
+ rc = EINVAL;
+#endif /* DEBUG */
+ break;
+
+ case AMOPT_LOGFILE:
+#ifdef not_yet
+ if (switch_to_logfile(opt->as_str))
+ rc = EINVAL;
+#else
+ rc = EACCES;
+#endif /* not_yet */
+ break;
+
+ case AMOPT_XLOG:
+ if (switch_option(opt->as_str))
+ rc = EINVAL;
+ break;
+
+ case AMOPT_FLUSHMAPC:
+ if (amd_state == Run) {
+ plog(XLOG_INFO, "amq says flush cache");
+ do_mapc_reload = 0;
+ flush_nfs_fhandle_cache((fserver *) 0);
+ flush_srvr_nfs_cache();
+ }
+ break;
+ }
+ return &rc;
+}
+
+amq_mount_info_list *
+amqproc_getmntfs_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+extern qelem mfhead;
+ return (amq_mount_info_list *) &mfhead; /* XXX */
+}
+
+static int ok_security(rqstp)
+struct svc_req *rqstp;
+{
+ struct sockaddr_in *sin;
+
+ sin = svc_getcaller(rqstp->rq_xprt);
+ if (ntohs(sin->sin_port) >= 1024 ||
+ !(sin->sin_addr.s_addr == htonl(0x7f000001) ||
+ sin->sin_addr.s_addr == myipaddr.s_addr)) {
+ char dq[20];
+ plog(XLOG_INFO, "AMQ request from %s.%d DENIED",
+ inet_dquad(dq, sin->sin_addr.s_addr),
+ ntohs(sin->sin_port));
+ return(0);
+ }
+ return(1);
+}
+
+int *
+amqproc_mount_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static int rc;
+ char *s = *(amq_string *) argp;
+ char *cp;
+
+ plog(XLOG_INFO, "amq requested mount of %s", s);
+ /*
+ * Minimalist security check.
+ */
+ if (!ok_security(rqstp)) {
+ rc = EACCES;
+ return &rc;
+ }
+
+ /*
+ * Find end of key
+ */
+ for (cp = (char *) s; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
+ ;
+
+ if (!*cp) {
+ plog(XLOG_INFO, "amqproc_mount: Invalid arguments");
+ rc = EINVAL;
+ return &rc;
+ }
+ *cp++ = '\0';
+
+ /*
+ * Find start of value
+ */
+ while (*cp && isascii(*cp) && isspace(*cp))
+ cp++;
+
+ root_newmap(s, cp, (char *) 0);
+ rc = mount_auto_node(s, (voidp) root_node);
+ if (rc < 0)
+ return 0;
+ return &rc;
+}
+
+amq_string *
+amqproc_getvers_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+static amq_string res;
+ res = version;
+ return &res;
+}
+
+/*
+ * XDR routines.
+ */
+bool_t
+xdr_amq_string(xdrs, objp)
+ XDR *xdrs;
+ amq_string *objp;
+{
+ if (!xdr_string(xdrs, objp, AMQ_STRLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_setopt(xdrs, objp)
+ XDR *xdrs;
+ amq_setopt *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)&objp->as_opt)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * More XDR routines - Should be used for OUTPUT ONLY.
+ */
+bool_t
+xdr_amq_mount_tree_node(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ am_node *mp = (am_node *) objp;
+
+ if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_info)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mp->am_path)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, mp->am_link ? &mp->am_link : &mp->am_mnt->mf_mount)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_ops->fs_type)) {
+ return (FALSE);
+ }
+ if (!xdr_long(xdrs, &mp->am_stats.s_mtime)) {
+ return (FALSE);
+ }
+ if (!xdr_u_short(xdrs, &mp->am_stats.s_uid)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_getattr)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_lookup)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_readdir)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_readlink)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_statfs)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_subtree(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ am_node *mp = (am_node *) objp;
+
+ if (!xdr_amq_mount_tree_node(xdrs, objp)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mp->am_osib, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_tree(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ am_node *mp = (am_node *) objp;
+ am_node *mnil = 0;
+
+ if (!xdr_amq_mount_tree_node(xdrs, objp)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mnil, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_tree_p(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree_p *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+bool_t
+xdr_amq_mount_stats(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_stats *objp;
+{
+ if (!xdr_int(xdrs, &objp->as_drops)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_stale)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_mok)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_merr)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_uerr)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+bool_t
+xdr_amq_mount_tree_list(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree_list *objp;
+{
+ if (!xdr_array(xdrs, (char **)&objp->amq_mount_tree_list_val, (u_int *)&objp->amq_mount_tree_list_len, ~0, sizeof(amq_mount_tree_p), xdr_amq_mount_tree_p)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_info_qelem(xdrs, qhead)
+ XDR *xdrs;
+ qelem *qhead;
+{
+ /*
+ * Compute length of list
+ */
+ mntfs *mf;
+ u_int len = 0;
+ for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
+ if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+ continue;
+ len++;
+ }
+ xdr_u_int(xdrs, &len);
+
+ /*
+ * Send individual data items
+ */
+ for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
+ int up;
+ if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+ continue;
+
+ if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mf->mf_mount)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mf->mf_info)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mf->mf_server->fs_host)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mf->mf_error)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mf->mf_refc)) {
+ return (FALSE);
+ }
+ if (mf->mf_server->fs_flags & FSF_ERROR)
+ up = 0;
+ else switch (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) {
+ case FSF_DOWN|FSF_VALID: up = 0; break;
+ case FSF_VALID: up = 1; break;
+ default: up = -1; break;
+ }
+ if (!xdr_int(xdrs, &up)) {
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
diff --git a/usr.sbin/amd/amd/clock.c b/usr.sbin/amd/amd/clock.c
new file mode 100644
index 000000000000..91e11eec4962
--- /dev/null
+++ b/usr.sbin/amd/amd/clock.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)clock.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: clock.c,v 5.2.2.1 1992/02/09 15:08:20 jsp beta $
+ *
+ */
+
+/*
+ * Callouts.
+ *
+ * Modelled on kernel object of the same name.
+ * See usual references.
+ *
+ * Use of a heap-based mechanism was rejected:
+ * 1. more complex implementation needed.
+ * 2. not obvious that a list is too slow for Amd.
+ */
+
+#include "am.h"
+
+typedef struct callout callout;
+struct callout {
+ callout *c_next; /* List of callouts */
+ void (*c_fn)(); /* Function to call */
+ voidp c_closure; /* Closure to pass to call */
+ time_t c_time; /* Time of call */
+ int c_id; /* Unique identifier */
+};
+
+static callout callouts; /* List of pending callouts */
+static callout *free_callouts; /* Cache of free callouts */
+static int nfree_callouts; /* Number on free list */
+static int callout_id; /* Next free callout identifier */
+time_t next_softclock; /* Time of next call to softclock() */
+
+/*
+ * Number of callout slots we keep on the free list
+ */
+#define CALLOUT_FREE_SLOP 10
+
+/*
+ * Global assumption: valid id's are non-zero.
+ */
+#define CID_ALLOC() (++callout_id)
+#define CID_UNDEF (0)
+
+static callout *alloc_callout(P_void);
+static callout *alloc_callout()
+{
+ callout *cp = free_callouts;
+ if (cp) {
+ --nfree_callouts;
+ free_callouts = free_callouts->c_next;
+ return cp;
+ }
+ return ALLOC(callout);
+}
+
+static void free_callout P((callout *cp));
+static void free_callout(cp)
+callout *cp;
+{
+ if (nfree_callouts > CALLOUT_FREE_SLOP) {
+ free((voidp) cp);
+ } else {
+ cp->c_next = free_callouts;
+ free_callouts = cp;
+ nfree_callouts++;
+ }
+}
+
+/*
+ * Schedule a callout.
+ *
+ * (*fn)(closure) will be called at clocktime() + secs
+ */
+int timeout P((unsigned int secs, void (*fn)(), voidp closure));
+int timeout(secs, fn, closure)
+unsigned int secs;
+void (*fn)();
+voidp closure;
+{
+ callout *cp, *cp2;
+ time_t t = clocktime() + secs;
+
+ /*
+ * Allocate and fill in a new callout structure
+ */
+ callout *cpnew = alloc_callout();
+ cpnew->c_closure = closure;
+ cpnew->c_fn = fn;
+ cpnew->c_time = t;
+ cpnew->c_id = CID_ALLOC();
+
+ if (t < next_softclock)
+ next_softclock = t;
+
+ /*
+ * Find the correct place in the list
+ */
+ for (cp = &callouts; cp2 = cp->c_next; cp = cp2)
+ if (cp2->c_time >= t)
+ break;
+
+ /*
+ * And link it in
+ */
+ cp->c_next = cpnew;
+ cpnew->c_next = cp2;
+
+ /*
+ * Return callout identifier
+ */
+ return cpnew->c_id;
+}
+
+/*
+ * De-schedule a callout
+ */
+void untimeout P((int id));
+void untimeout(id)
+int id;
+{
+ callout *cp, *cp2;
+ for (cp = &callouts; cp2 = cp->c_next; cp = cp2) {
+ if (cp2->c_id == id) {
+ cp->c_next = cp2->c_next;
+ free_callout(cp2);
+ break;
+ }
+ }
+}
+
+/*
+ * Reschedule after clock changed
+ */
+void reschedule_timeouts P((time_t now, time_t then));
+void reschedule_timeouts(now, then)
+time_t now;
+time_t then;
+{
+ callout *cp;
+
+ for (cp = callouts.c_next; cp; cp = cp->c_next) {
+ if (cp->c_time >= now && cp->c_time <= then) {
+ plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id);
+#ifdef DEBUG
+ dlog("rescheduling job %d back %d seconds",
+ cp->c_id, cp->c_time - now);
+#endif
+ next_softclock = cp->c_time = now;
+ }
+ }
+}
+
+/*
+ * Clock handler
+ */
+int softclock(P_void);
+int softclock()
+{
+ time_t now;
+ callout *cp;
+
+ do {
+ if (task_notify_todo)
+ do_task_notify();
+
+ now = clocktime();
+
+ /*
+ * While there are more callouts waiting...
+ */
+ while ((cp = callouts.c_next) && cp->c_time <= now) {
+ /*
+ * Extract first from list, save fn & closure and
+ * unlink callout from list and free.
+ * Finally call function.
+ *
+ * The free is done first because
+ * it is quite common that the
+ * function will call timeout()
+ * and try to allocate a callout
+ */
+ void (*fn)() = cp->c_fn;
+ voidp closure = cp->c_closure;
+
+ callouts.c_next = cp->c_next;
+ free_callout(cp);
+#ifdef DEBUG
+ /*dlog("Calling %#x(%#x)", fn, closure);*/
+#endif /* DEBUG */
+ (*fn)(closure);
+ }
+
+ } while (task_notify_todo);
+
+ /*
+ * Return number of seconds to next event,
+ * or 0 if there is no event.
+ */
+ if (cp = callouts.c_next)
+ return cp->c_time - now;
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/efs_ops.c b/usr.sbin/amd/amd/efs_ops.c
new file mode 100644
index 000000000000..6630277eab4c
--- /dev/null
+++ b/usr.sbin/amd/amd/efs_ops.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)efs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: efs_ops.c,v 5.2.2.1 1992/02/09 15:08:21 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_EFS
+
+/*
+ * Error file system.
+ * This is used as a last resort catchall if
+ * nothing else worked. EFS just returns lots
+ * of error codes, except for unmount which
+ * always works of course.
+ */
+
+/*
+ * EFS file system always matches
+ */
+static char *efs_match(fo)
+am_opts *fo;
+{
+ return strdup("(error-hook)");
+}
+
+/*ARGSUSED*/
+static int efs_fmount(mf)
+mntfs *mf;
+{
+ return ENOENT;
+}
+
+/*ARGSUSED*/
+static int efs_fumount(mf)
+mntfs *mf;
+{
+ /*
+ * Always succeed
+ */
+
+ return 0;
+}
+
+/*
+ * EFS interface to RPC lookup() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
+ */
+/*ARGSUSED*/
+am_node *efs_lookuppn(mp, fname, error_return, op)
+am_node *mp;
+char *fname;
+int *error_return;
+int op;
+{
+ *error_return = ESTALE;
+ return 0;
+}
+
+/*
+ * EFS interface to RPC readdir() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
+ */
+/*ARGSUSED*/
+int efs_readdir(mp, cookie, dp, ep, count)
+am_node *mp;
+nfscookie cookie;
+dirlist *dp;
+entry *ep;
+int count;
+{
+ return ESTALE;
+}
+
+/*
+ * Ops structure
+ */
+am_ops efs_ops = {
+ "error",
+ efs_match,
+ 0, /* efs_init */
+ auto_fmount,
+ efs_fmount,
+ auto_fumount,
+ efs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* efs_readlink */
+ 0, /* efs_mounted */
+ 0, /* efs_umounted */
+ find_afs_srvr,
+ FS_DISCARD
+};
+
+#endif /* HAS_EFS */
diff --git a/usr.sbin/amd/amd/get_args.c b/usr.sbin/amd/amd/get_args.c
new file mode 100644
index 000000000000..0567d5dd5ea3
--- /dev/null
+++ b/usr.sbin/amd/amd/get_args.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)get_args.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: get_args.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $
+ *
+ */
+
+/*
+ * Argument decode
+ */
+
+#include "am.h"
+#ifdef HAS_SYSLOG
+#include <syslog.h>
+#endif /* HAS_SYSLOG */
+#include <sys/stat.h>
+
+extern int optind;
+extern char *optarg;
+
+#if defined(DEBUG) && defined(PARANOID)
+char **gargv;
+#endif /* defined(DEBUG) && defined(PARANOID) */
+int restart_existing_mounts;
+int print_pid;
+int normalize_hosts;
+char *karch; /* Kernel architecture */
+char *cluster; /* Cluster name */
+#ifdef HAS_NIS_MAPS
+char *domain; /* YP domain */
+#endif /* HAS_NIS_MAPS */
+#ifdef UPDATE_MTAB
+char *mtab;
+#endif /* UPDATE_MTAB */
+int afs_timeo = -1;
+int afs_retrans = -1;
+int am_timeo = AM_TTL;
+int am_timeo_w = AM_TTL_W;
+
+#ifdef DEBUG
+/*
+ * List of debug options.
+ */
+static struct opt_tab dbg_opt[] = {
+ { "all", D_ALL }, /* All */
+ { "amq", D_AMQ }, /* Register for AMQ program */
+ { "daemon", D_DAEMON }, /* Enter daemon mode */
+ { "full", D_FULL }, /* Program trace */
+ { "mem", D_MEM }, /* Trace memory allocations */
+ { "mtab", D_MTAB }, /* Use local mtab file */
+ { "str", D_STR }, /* Debug string munging */
+ { "test", D_TEST }, /* Full debug - but no daemon */
+ { "trace", D_TRACE }, /* Protocol trace */
+ { 0, 0 }
+};
+
+int debug_flags = D_AMQ /* Register AMQ */
+ |D_DAEMON /* Enter daemon mode */
+ ;
+
+/*
+ * Switch on/off debug options
+ */
+int debug_option(opt)
+char *opt;
+{
+ return cmdoption(opt, dbg_opt, &debug_flags);
+}
+#endif /* DEBUG */
+
+void get_args(c, v)
+int c;
+char *v[];
+{
+ int opt_ch;
+ int usage = 0;
+ char *logfile = 0;
+ char *sub_domain = 0;
+
+ while ((opt_ch = getopt(c, v, "mnprva:c:d:h:k:l:t:w:x:y:C:D:")) != EOF)
+ switch (opt_ch) {
+ case 'a':
+ if (*optarg != '/') {
+ fprintf(stderr, "%s: -a option must begin with a '/'\n",
+ progname);
+ exit(1);
+ }
+ auto_dir = optarg;
+ break;
+
+ case 'c':
+ am_timeo = atoi(optarg);
+ if (am_timeo <= 0)
+ am_timeo = AM_TTL;
+ break;
+
+ case 'd':
+ sub_domain = optarg;
+ break;
+
+ case 'h':
+#if defined(HAS_HOST) && defined(HOST_EXEC)
+ host_helper = optarg;
+#else
+ plog(XLOG_USER, "-h: option ignored. HOST_EXEC is not enabled.");
+ break;
+#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */
+
+ case 'k':
+ karch = optarg;
+ break;
+
+ case 'l':
+ logfile = optarg;
+ break;
+
+ case 'm':
+ plog(XLOG_USER, "The -m option is no longer supported.");
+ plog(XLOG_USER, "... Use `ypcat -k am.master` on the command line instead");
+ break;
+
+ case 'n':
+ normalize_hosts = 1;
+ break;
+
+ case 'p':
+ print_pid = 1;
+ break;
+
+ case 'r':
+ restart_existing_mounts = 1;
+ break;
+
+ case 't':
+ /* timeo.retrans */
+ { char *dot = strchr(optarg, '.');
+ if (dot) *dot = '\0';
+ if (*optarg) {
+ afs_timeo = atoi(optarg);
+ }
+ if (dot) {
+ afs_retrans = atoi(dot+1);
+ *dot = '.';
+ }
+ }
+ break;
+
+ case 'v':
+ fprintf(stderr, "%s%s (%s-endian).\n", copyright, version, endian);
+ fputs("Map support for: ", stderr);
+ mapc_showtypes(stderr);
+ fputs(".\nFS: ", stderr);
+ ops_showfstypes(stderr);
+ fputs(".\n", stderr);
+ fprintf(stderr, "Primary network is %s.\n", wire);
+ exit(0);
+ break;
+
+ case 'w':
+ am_timeo_w = atoi(optarg);
+ if (am_timeo_w <= 0)
+ am_timeo_w = AM_TTL_W;
+ break;
+
+ case 'x':
+ usage += switch_option(optarg);
+ break;
+
+ case 'y':
+#ifdef HAS_NIS_MAPS
+ domain = optarg;
+#else
+ plog(XLOG_USER, "-y: option ignored. No NIS support available.");
+#endif /* HAS_NIS_MAPS */
+ break;
+
+ case 'C':
+ cluster = optarg;
+ break;
+
+ case 'D':
+#ifdef DEBUG
+ usage += debug_option(optarg);
+#else
+ fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", progname);
+#endif /* DEBUG */
+ break;
+
+ default:
+ usage = 1;
+ break;
+ }
+
+ if (xlog_level_init == ~0) {
+ (void) switch_option("");
+#ifdef DEBUG
+ usage += switch_option("debug");
+#endif /* DEBUG */
+ } else {
+#ifdef DEBUG
+ usage += switch_option("debug");
+#endif /* DEBUG */
+ }
+
+ if (usage)
+ goto show_usage;
+
+ while (optind <= c-2) {
+ char *dir = v[optind++];
+ char *map = v[optind++];
+ char *opts = "";
+ if (v[optind] && *v[optind] == '-')
+ opts = &v[optind++][1];
+
+ root_newmap(dir, opts, map);
+ }
+
+ if (optind == c) {
+#ifdef hpux
+ /*
+ * HP-UX can't handle ./mtab
+ * That system is sick - really.
+ */
+#ifdef DEBUG
+ debug_option("nomtab");
+#endif /* DEBUG */
+#endif /* hpux */
+
+ /*
+ * Append domain name to hostname.
+ * sub_domain overrides hostdomain
+ * if given.
+ */
+ if (sub_domain)
+ hostdomain = sub_domain;
+ if (*hostdomain == '.')
+ hostdomain++;
+ strcat(hostd, ".");
+ strcat(hostd, hostdomain);
+
+#ifdef UPDATE_MTAB
+#ifdef DEBUG
+ if (debug_flags & D_MTAB)
+ mtab = DEBUG_MTAB;
+ else
+#endif /* DEBUG */
+ mtab = MOUNTED;
+#else
+#ifdef DEBUG
+ { if (debug_flags & D_MTAB) {
+ dlog("-D mtab option ignored");
+ } }
+#endif /* DEBUG */
+#endif /* UPDATE_MTAB */
+
+ if (switch_to_logfile(logfile) != 0)
+ plog(XLOG_USER, "Cannot switch logfile");
+
+ /*
+ * If the kernel architecture was not specified
+ * then use the machine architecture.
+ */
+ if (karch == 0)
+ karch = arch;
+
+ if (cluster == 0)
+ cluster = hostdomain;
+
+ if (afs_timeo <= 0)
+ afs_timeo = AFS_TIMEO;
+ if (afs_retrans <= 0)
+ afs_retrans = AFS_RETRANS;
+ if (afs_retrans <= 0)
+ afs_retrans = 3; /* XXX */
+ return;
+ }
+
+show_usage:
+ fprintf(stderr,
+"Usage: %s [-mnprv] [-a mnt_point] [-c cache_time] [-d domain]\n\
+\t[-k kernel_arch] [-l logfile|\"syslog\"] [-t afs_timeout]\n\
+\t[-w wait_timeout] [-C cluster_name]", progname);
+
+#if defined(HAS_HOST) && defined(HOST_EXEC)
+ fputs(" [-h host_helper]\n", stderr);
+#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */
+
+#ifdef HAS_NIS_MAPS
+ fputs(" [-y nis-domain]\n", stderr);
+#else
+ fputc('\n', stderr);
+#endif /* HAS_NIS_MAPS */
+
+ show_opts('x', xlog_opt);
+#ifdef DEBUG
+ show_opts('D', dbg_opt);
+#endif /* DEBUG */
+ fprintf(stderr, "\t{directory mapname [-map_options]} ...\n");
+ exit(1);
+}
diff --git a/usr.sbin/amd/amd/host_ops.c b/usr.sbin/amd/amd/host_ops.c
new file mode 100644
index 000000000000..ba0dedb43154
--- /dev/null
+++ b/usr.sbin/amd/amd/host_ops.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)host_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: host_ops.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_HOST
+
+#include "mount.h"
+#include <sys/stat.h>
+
+/*
+ * NFS host file system.
+ * Mounts all exported filesystems from a given host.
+ * This has now degenerated into a mess but will not
+ * be rewritten. Amd 6 will support the abstractions
+ * needed to make this work correctly.
+ */
+
+/*
+ * Define HOST_RPC_UDP to use dgram instead of stream RPC.
+ * Datagrams are generally much faster.
+ */
+/*#define HOST_RPC_UDP*/
+
+/*
+ * Define HOST_MKDIRS to make Amd automatically try
+ * to create the mount points.
+ */
+#define HOST_MKDIRS
+
+/*
+ * Determine the mount point
+ */
+#define MAKE_MNTPT(mntpt, ex, mf) { \
+ if (strcmp((ex)->ex_dir, "/") == 0) \
+ strcpy((mntpt), (mf)->mf_mount); \
+ else \
+ sprintf((mntpt), "%s%s", (mf)->mf_mount, (ex)->ex_dir); \
+}
+
+/*
+ * Execute needs the same as NFS plus a helper command
+ */
+static char *host_match P((am_opts *fo));
+static char *host_match(fo)
+am_opts *fo;
+{
+#ifdef HOST_EXEC
+ if (!host_helper) {
+ plog(XLOG_USER, "No host helper command given");
+ return FALSE;
+ }
+#endif /* HOST_EXEC */
+
+ /*
+ * Make sure rfs is specified to keep nfs_match happy...
+ */
+ if (!fo->opt_rfs)
+ fo->opt_rfs = "/";
+
+
+ return (*nfs_ops.fs_match)(fo);
+}
+
+static int host_init(mf)
+mntfs *mf;
+{
+ if (strchr(mf->mf_info, ':') == 0)
+ return ENOENT;
+ return 0;
+}
+
+/*
+ * Two implementations:
+ * HOST_EXEC gets you the external version. The program specified with
+ * the -h option is called. The external program is not published...
+ * roll your own.
+ *
+ * Otherwise you get the native version. Faster but makes the program
+ * bigger.
+ */
+
+#ifndef HOST_EXEC
+
+static bool_t
+xdr_pri_free(xdr_args, args_ptr)
+xdrproc_t xdr_args;
+caddr_t args_ptr;
+{
+ XDR xdr;
+ xdr.x_op = XDR_FREE;
+ return ((*xdr_args)(&xdr, args_ptr));
+}
+
+static int do_mount P((fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
+static int do_mount(fhp, dir, fs_name, opts, mf)
+fhstatus *fhp;
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+ struct stat stb;
+#ifdef DEBUG
+ dlog("host: mounting fs %s on %s\n", fs_name, dir);
+#endif /* DEBUG */
+#ifdef HOST_MKDIRS
+ (void) mkdirs(dir, 0555);
+#endif /* HOST_MKDIRS */
+ if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_ERROR, "No mount point for %s - skipping", dir);
+ return ENOENT;
+ }
+
+ return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
+}
+
+static int sortfun P((exports *a, exports *b));
+static int sortfun(a, b)
+exports *a,*b;
+{
+ return strcmp((*a)->ex_dir, (*b)->ex_dir);
+}
+
+/*
+ * Get filehandle
+ */
+static int fetch_fhandle P((CLIENT *client, char *dir, fhstatus *fhp));
+static int fetch_fhandle(client, dir, fhp)
+CLIENT *client;
+char *dir;
+fhstatus *fhp;
+{
+ struct timeval tv;
+ enum clnt_stat clnt_stat;
+
+ /*
+ * Pick a number, any number...
+ */
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+
+#ifdef DEBUG
+ dlog("Fetching fhandle for %s", dir);
+#endif /* DEBUG */
+ /*
+ * Call the mount daemon on the remote host to
+ * get the filehandle.
+ */
+ clnt_stat = clnt_call(client, MOUNTPROC_MNT, xdr_dirpath, &dir, xdr_fhstatus, fhp, tv);
+ if (clnt_stat != RPC_SUCCESS) {
+ extern char *clnt_sperrno();
+ char *msg = clnt_sperrno(clnt_stat);
+ plog(XLOG_ERROR, "mountd rpc failed: %s", msg);
+ return EIO;
+ }
+ /*
+ * Check status of filehandle
+ */
+ if (fhp->fhs_status) {
+#ifdef DEBUG
+ errno = fhp->fhs_status;
+ dlog("fhandle fetch failed: %m");
+#endif /* DEBUG */
+ return fhp->fhs_status;
+ }
+ return 0;
+}
+
+/*
+ * Scan mount table to see if something already mounted
+ */
+static int already_mounted P((mntlist *mlist, char*dir));
+static int already_mounted(mlist, dir)
+mntlist *mlist;
+char *dir;
+{
+ mntlist *ml;
+
+ for (ml = mlist; ml; ml = ml->mnext)
+ if (strcmp(ml->mnt->mnt_dir, dir) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * Mount the export tree from a host
+ */
+static int host_fmount P((mntfs *mf));
+static int host_fmount(mf)
+mntfs *mf;
+{
+ struct timeval tv2;
+ CLIENT *client;
+ enum clnt_stat clnt_stat;
+ int n_export;
+ int j, k;
+ exports exlist = 0, ex;
+ exports *ep = 0;
+ fhstatus *fp = 0;
+ char *host = mf->mf_server->fs_host;
+ int error = 0;
+ struct sockaddr_in sin;
+ int sock = RPC_ANYSOCK;
+ int ok = FALSE;
+ mntlist *mlist;
+ char fs_name[MAXPATHLEN], *rfs_dir;
+ char mntpt[MAXPATHLEN];
+ struct timeval tv;
+ tv.tv_sec = 10; tv.tv_usec = 0;
+
+ /*
+ * Read the mount list
+ */
+ mlist = read_mtab(mf->mf_mount);
+
+ /*
+ * Unlock the mount list
+ */
+ unlock_mntlist();
+
+ /*
+ * Take a copy of the server address
+ */
+ sin = *mf->mf_server->fs_ip;
+
+ /*
+ * Zero out the port - make sure we recompute
+ */
+ sin.sin_port = 0;
+ /*
+ * Make a client end-point.
+ * Try TCP first
+ */
+ if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL &&
+ (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) {
+ plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
+ error = EIO;
+ goto out;
+ }
+
+ if (!nfs_auth) {
+ error = make_nfs_auth();
+ if (error)
+ goto out;
+ }
+
+ client->cl_auth = nfs_auth;
+
+#ifdef DEBUG
+ dlog("Fetching export list from %s", host);
+#endif /* DEBUG */
+
+ /*
+ * Fetch the export list
+ */
+ tv2.tv_sec = 10; tv2.tv_usec = 0;
+ clnt_stat = clnt_call(client, MOUNTPROC_EXPORT, xdr_void, 0, xdr_exports, &exlist, tv2);
+ if (clnt_stat != RPC_SUCCESS) {
+ /*clnt_perror(client, "rpc");*/
+ error = EIO;
+ goto out;
+ }
+
+ /*
+ * Figure out how many exports were returned
+ */
+ for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) {
+ /*printf("export %s\n", ex->ex_dir);*/
+ n_export++;
+ }
+#ifdef DEBUG
+ /*dlog("%d exports returned\n", n_export);*/
+#endif /* DEBUG */
+
+ /*
+ * Allocate an array of pointers into the list
+ * so that they can be sorted. If the filesystem
+ * is already mounted then ignore it.
+ */
+ ep = (exports *) xmalloc(n_export * sizeof(exports));
+ for (j = 0, ex = exlist; ex; ex = ex->ex_next) {
+ MAKE_MNTPT(mntpt, ex, mf);
+ if (!already_mounted(mlist, mntpt))
+ ep[j++] = ex;
+ }
+ n_export = j;
+
+ /*
+ * Sort into order.
+ * This way the mounts are done in order down the tree,
+ * instead of any random order returned by the mount
+ * daemon (the protocol doesn't specify...).
+ */
+ qsort(ep, n_export, sizeof(exports), sortfun);
+
+ /*
+ * Allocate an array of filehandles
+ */
+ fp = (fhstatus *) xmalloc(n_export * sizeof(fhstatus));
+
+ /*
+ * Try to obtain filehandles for each directory.
+ * If a fetch fails then just zero out the array
+ * reference but discard the error.
+ */
+ for (j = k = 0; j < n_export; j++) {
+ /* Check and avoid a duplicated export entry */
+ if (j > k && ep[k] && strcmp(ep[j]->ex_dir, ep[k]->ex_dir) == 0) {
+#ifdef DEBUG
+ dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir);
+#endif
+ ep[j] = 0;
+ } else {
+ k = j;
+ if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j]))
+ ep[j] = 0;
+ }
+ }
+
+ /*
+ * Mount each filesystem for which we have a filehandle.
+ * If any of the mounts succeed then mark "ok" and return
+ * error code 0 at the end. If they all fail then return
+ * the last error code.
+ */
+ strncpy(fs_name, mf->mf_info, sizeof(fs_name));
+ if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) {
+ plog(XLOG_FATAL, "host_fmount: mf_info has no colon");
+ error = EINVAL;
+ goto out;
+ }
+ ++rfs_dir;
+ for (j = 0; j < n_export; j++) {
+ ex = ep[j];
+ if (ex) {
+ strcpy(rfs_dir, ex->ex_dir);
+ MAKE_MNTPT(mntpt, ex, mf);
+ if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0)
+ ok = TRUE;
+ }
+ }
+
+ /*
+ * Clean up and exit
+ */
+out:
+ discard_mntlist(mlist);
+ if (ep)
+ free(ep);
+ if (fp)
+ free(fp);
+ if (client)
+ clnt_destroy(client);
+ if (exlist)
+ xdr_pri_free(xdr_exports, &exlist);
+ if (ok)
+ return 0;
+ return error;
+}
+
+/*
+ * Return true if pref is a directory prefix of dir.
+ *
+ * TODO:
+ * Does not work if pref is "/".
+ */
+static int directory_prefix P((char *pref, char *dir));
+static int directory_prefix(pref, dir)
+char *pref;
+char *dir;
+{
+ int len = strlen(pref);
+ if (strncmp(pref, dir, len) != 0)
+ return FALSE;
+ if (dir[len] == '/' || dir[len] == '\0')
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Unmount a mount tree
+ */
+static int host_fumount P((mntfs *mf));
+static int host_fumount(mf)
+mntfs *mf;
+{
+ mntlist *ml, *mprev;
+ int xerror = 0;
+
+ /*
+ * Read the mount list
+ */
+ mntlist *mlist = read_mtab(mf->mf_mount);
+
+ /*
+ * Unlock the mount list
+ */
+ unlock_mntlist();
+
+ /*
+ * Reverse list...
+ */
+ ml = mlist;
+ mprev = 0;
+ while (ml) {
+ mntlist *ml2 = ml->mnext;
+ ml->mnext = mprev;
+ mprev = ml;
+ ml = ml2;
+ }
+ mlist = mprev;
+
+ /*
+ * Unmount all filesystems...
+ */
+ for (ml = mlist; ml && !xerror; ml = ml->mnext) {
+ char *dir = ml->mnt->mnt_dir;
+ if (directory_prefix(mf->mf_mount, dir)) {
+ int error;
+#ifdef DEBUG
+ dlog("host: unmounts %s", dir);
+#endif /* DEBUG */
+ /*
+ * Unmount "dir"
+ */
+ error = UMOUNT_FS(dir);
+ /*
+ * Keep track of errors
+ */
+ if (error) {
+ if (!xerror)
+ xerror = error;
+ if (error != EBUSY) {
+ errno = error;
+ plog("Tree unmount of %s failed: %m", ml->mnt->mnt_dir);
+ }
+ } else {
+#ifdef HOST_MKDIRS
+ (void) rmdirs(dir);
+#endif /* HOST_MKDIRS */
+ }
+ }
+ }
+
+ /*
+ * Throw away mount list
+ */
+ discard_mntlist(mlist);
+
+ /*
+ * Try to remount, except when we are shutting down.
+ */
+ if (xerror && amd_state != Finishing) {
+ xerror = host_fmount(mf);
+ if (!xerror) {
+ /*
+ * Don't log this - it's usually too verbose
+ plog(XLOG_INFO, "Remounted host %s", mf->mf_info);
+ */
+ xerror = EBUSY;
+ }
+ }
+ return xerror;
+}
+
+/*
+ * Tell mountd we're done.
+ * This is not quite right, because we may still
+ * have other filesystems mounted, but the existing
+ * mountd protocol is badly broken anyway.
+ */
+static void host_umounted(mp)
+am_node *mp;
+{
+#ifdef INFORM_MOUNTD
+ mntfs *mf = mp->am_mnt;
+ char *host;
+ CLIENT *client;
+ enum clnt_stat clnt_stat;
+ struct sockaddr_in sin;
+ int sock = RPC_ANYSOCK;
+ struct timeval tv;
+ tv.tv_sec = 10; tv.tv_usec = 0;
+
+ if (mf->mf_error || mf->mf_refc > 1 || ! mf->mf_server)
+ return;
+
+ host = mf->mf_server->fs_host;
+ sin = *mf->mf_server->fs_ip;
+
+ /*
+ * Zero out the port - make sure we recompute
+ */
+ sin.sin_port = 0;
+ /*
+ * Make a client end-point.
+ * Try TCP first
+ */
+ if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL &&
+ (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) {
+ plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
+ goto out;
+ }
+
+ if (!nfs_auth) {
+ if (make_nfs_auth())
+ goto out;
+ }
+
+ client->cl_auth = nfs_auth;
+
+#ifdef DEBUG
+ dlog("Unmounting all from %s", host);
+#endif /* DEBUG */
+
+ clnt_stat = clnt_call(client, MOUNTPROC_UMNTALL, xdr_void, 0, xdr_void, 0, tv);
+ if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) {
+ /* RPC_SYSTEMERROR seems to be returned for no good reason ...*/
+ extern char *clnt_sperrno();
+ char *msg = clnt_sperrno(clnt_stat);
+ plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat);
+ goto out;
+ }
+
+out:
+ if (client)
+ clnt_destroy(client);
+
+#endif /* INFORM_MOUNTD */
+}
+
+
+#else /* HOST_EXEC */
+
+static int host_exec P((char*op, char*host, char*fs, char*opts));
+static int host_exec(op, host, fs, opts)
+char *op;
+char *host;
+char *fs;
+char *opts;
+{
+ int error;
+ char *argv[7];
+
+ /*
+ * Build arg vector
+ */
+ argv[0] = host_helper;
+ argv[1] = host_helper;
+ argv[2] = op;
+ argv[3] = host;
+ argv[4] = fs;
+ argv[5] = opts && *opts ? opts : "rw,default";
+ argv[6] = 0;
+
+ /*
+ * Put stdout to stderr
+ */
+ (void) fclose(stdout);
+ (void) dup(fileno(logfp));
+ if (fileno(logfp) != fileno(stderr)) {
+ (void) fclose(stderr);
+ (void) dup(fileno(logfp));
+ }
+ /*
+ * Try the exec
+ */
+#ifdef DEBUG
+ Debug(D_FULL) {
+ char **cp = argv;
+ plog(XLOG_DEBUG, "executing (un)mount command...");
+ while (*cp) {
+ plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-argv, *cp);
+ cp++;
+ }
+ }
+#endif /* DEBUG */
+ if (argv[0] == 0 || argv[1] == 0) {
+ errno = EINVAL;
+ plog(XLOG_USER, "1st/2nd args missing to (un)mount program");
+ } else {
+ (void) execv(argv[0], argv+1);
+ }
+ /*
+ * Save error number
+ */
+ error = errno;
+ plog(XLOG_ERROR, "exec %s failed: %m", argv[0]);
+
+ /*
+ * Return error
+ */
+ return error;
+}
+
+static int host_mount P((am_node *mp));
+static int host_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_opts);
+}
+
+static int host_umount P((am_node *mp));
+static int host_umount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ return host_exec("unmount", mf->mf_server->fs_host, mf->mf_mount, "xxx");
+}
+
+#endif /* HOST_EXEC */
+
+/*
+ * Ops structure
+ */
+am_ops host_ops = {
+ "host",
+ host_match,
+ host_init,
+ auto_fmount,
+ host_fmount,
+ auto_fumount,
+ host_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* host_readlink */
+ 0, /* host_mounted */
+#ifdef HOST_EXEC
+ 0, /* host_umounted */
+#else
+ host_umounted,
+#endif
+ find_nfs_srvr,
+ FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_HOST */
diff --git a/usr.sbin/amd/amd/ifs_ops.c b/usr.sbin/amd/amd/ifs_ops.c
new file mode 100644
index 000000000000..14df832b24c6
--- /dev/null
+++ b/usr.sbin/amd/amd/ifs_ops.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)ifs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: ifs_ops.c,v 5.2.2.1 1992/02/09 15:08:26 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_IFS
+
+/*
+ * Inheritance file system.
+ * This implements a filesystem restart.
+ *
+ * This is a *gross* hack - it knows far too
+ * much about the way other parts of the
+ * sytem work. See restart.c too.
+ */
+static char not_a_filesystem[] = "Attempting to inherit not-a-filesystem";
+/*
+ * This should never be called.
+ */
+/*ARGSUSED*/
+static char *ifs_match P((am_opts *fo));
+static char *ifs_match(fo)
+am_opts *fo;
+{
+ plog(XLOG_FATAL, "ifs_match called!");
+ return 0;
+}
+
+static int ifs_init P((mntfs *mf));
+static int ifs_init(mf)
+mntfs *mf;
+{
+ mntfs *mf_link = (mntfs *) mf->mf_private;
+ if (mf_link == 0) {
+ plog(XLOG_FATAL, not_a_filesystem);
+ return EINVAL;
+ }
+#ifdef notdef
+ /*
+ * Fill in attribute fields
+ */
+ mf_link->mf_fattr.type = NFLNK;
+ mf_link->mf_fattr.mode = NFSMODE_LNK | 0777;
+ mf_link->mf_fattr.nlink = 1;
+ mf_link->mf_fattr.size = MAXPATHLEN / 4;
+#endif
+ if (mf_link->mf_ops->fs_init)
+ return (*mf_link->mf_ops->fs_init)(mf_link);
+ return 0;
+}
+
+static mntfs *ifs_inherit P((mntfs *mf));
+static mntfs *ifs_inherit(mf)
+mntfs *mf;
+{
+ /*
+ * Take the linked mount point and
+ * propogate.
+ */
+ mntfs *mf_link = (mntfs *) mf->mf_private;
+ if (mf_link == 0) {
+ plog(XLOG_FATAL, not_a_filesystem);
+ return 0; /*XXX*/
+ }
+
+ mf_link->mf_fo = mf->mf_fo;
+#ifdef notdef
+ mf_link->mf_fattr.fileid = mf->mf_fattr.fileid;
+#endif /* notdef */
+
+ /*
+ * Discard the old map.
+ * Don't call am_unmounted since this
+ * node was never really mounted in the
+ * first place.
+ */
+ mf->mf_private = 0;
+ free_mntfs(mf);
+ /*
+ * Free the dangling reference
+ * to the mount link.
+ */
+ free_mntfs(mf_link);
+ /*
+ * Get a hold of the other entry
+ */
+ mf_link->mf_flags &= ~MFF_RESTART;
+
+ /* Say what happened */
+ plog(XLOG_INFO, "restarting %s on %s", mf_link->mf_info, mf_link->mf_mount);
+
+ return mf_link;
+}
+
+static int ifs_mount P((am_node *mp));
+static int ifs_mount(mp)
+am_node *mp;
+{
+ mntfs *newmf = ifs_inherit(mp->am_mnt);
+ if (newmf) {
+ mp->am_mnt = newmf;
+ /*
+ * XXX - must do the am_mounted call here
+ */
+ if (newmf->mf_ops->fs_flags & FS_MBACKGROUND)
+ am_mounted(mp);
+
+ new_ttl(mp);
+ return 0;
+ }
+ return EINVAL;
+}
+
+static int ifs_fmount P((mntfs *mf));
+static int ifs_fmount(mf)
+mntfs *mf;
+{
+ am_node *mp = find_mf(mf);
+ if (mp)
+ return ifs_mount(mp);
+ return ifs_inherit(mf) ? 0 : EINVAL;
+}
+
+/*ARGSUSED*/
+static int ifs_fumount P((mntfs *mf));
+static int ifs_fumount(mf)
+mntfs *mf;
+{
+ /*
+ * Always succeed
+ */
+ return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops ifs_ops = {
+ "inherit",
+ ifs_match,
+ ifs_init,
+ ifs_mount,
+ ifs_fmount,
+ auto_fumount,
+ ifs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* ifs_readlink */
+ 0, /* ifs_mounted */
+ 0, /* ifs_umounted */
+ find_afs_srvr,
+ FS_DISCARD
+};
+
+#endif /* HAS_IFS */
diff --git a/usr.sbin/amd/amd/info_file.c b/usr.sbin/amd/amd/info_file.c
new file mode 100644
index 000000000000..c43b2a7b07c2
--- /dev/null
+++ b/usr.sbin/amd/amd/info_file.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)info_file.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_file.c,v 5.2.2.1 1992/02/09 15:08:28 jsp beta $
+ *
+ */
+
+/*
+ * Get info from file
+ */
+
+#include "am.h"
+
+#ifdef HAS_FILE_MAPS
+#include <ctype.h>
+#include <sys/stat.h>
+
+#define MAX_LINE_LEN 2048
+
+static int read_line P((char *buf, int size, FILE *fp));
+static int read_line(buf, size, fp)
+char *buf;
+int size;
+FILE *fp;
+{
+ int done = 0;
+
+ do {
+ while (fgets(buf, size, fp)) {
+ int len = strlen(buf);
+ done += len;
+ if (len > 1 && buf[len-2] == '\\' &&
+ buf[len-1] == '\n') {
+ int ch;
+ buf += len - 2;
+ size -= len - 2;
+ *buf = '\n'; buf[1] = '\0';
+ /*
+ * Skip leading white space on next line
+ */
+ while ((ch = getc(fp)) != EOF &&
+ isascii(ch) && isspace(ch))
+ ;
+ (void) ungetc(ch, fp);
+ } else {
+ return done;
+ }
+ }
+ } while (size > 0 && !feof(fp));
+
+ return done;
+}
+
+/*
+ * Try to locate a key in a file
+ */
+static int search_or_reload_file P((FILE *fp, char *map, char *key, char **val, mnt_map *m, void (*fn)(mnt_map *m, char*, char*)));
+static int search_or_reload_file(fp, map, key, val, m, fn)
+FILE *fp;
+char *map;
+char *key;
+char **val;
+mnt_map *m;
+void (*fn) P((mnt_map*, char*, char*));
+{
+ char key_val[MAX_LINE_LEN];
+ int chuck = 0;
+ int line_no = 0;
+
+ while (read_line(key_val, sizeof(key_val), fp)) {
+ char *kp;
+ char *cp;
+ char *hash;
+ int len = strlen(key_val);
+ line_no++;
+
+ /*
+ * Make sure we got the whole line
+ */
+ if (key_val[len-1] != '\n') {
+ plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
+ chuck = 1;
+ } else {
+ key_val[len-1] = '\0';
+ }
+
+ /*
+ * Strip comments
+ */
+ hash = strchr(key_val, '#');
+ if (hash)
+ *hash = '\0';
+
+ /*
+ * Find start of key
+ */
+ for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++)
+ ;
+
+ /*
+ * Ignore blank lines
+ */
+ if (!*kp)
+ goto again;
+
+ /*
+ * Find end of key
+ */
+ for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
+ ;
+
+ /*
+ * Check whether key matches
+ */
+ if (*cp)
+ *cp++ = '\0';
+
+ if (fn || (*key == *kp && strcmp(key, kp) == 0)) {
+ while (*cp && isascii(*cp) && isspace(*cp))
+ cp++;
+ if (*cp) {
+ /*
+ * Return a copy of the data
+ */
+ char *dc = strdup(cp);
+ if (fn) {
+ (*fn)(m, strdup(kp), dc);
+ } else {
+ *val = dc;
+#ifdef DEBUG
+ dlog("%s returns %s", key, dc);
+#endif /* DEBUG */
+ }
+ if (!fn)
+ return 0;
+ } else {
+ plog(XLOG_USER, "%s: line %d has no value field", map, line_no);
+ }
+ }
+
+again:
+ /*
+ * If the last read didn't get a whole line then
+ * throw away the remainder before continuing...
+ */
+ if (chuck) {
+ while (fgets(key_val, sizeof(key_val), fp) &&
+ !strchr(key_val, '\n'))
+ ;
+ chuck = 0;
+ }
+ }
+
+ return fn ? 0 : ENOENT;
+}
+
+static FILE *file_open P((char *map, time_t *tp));
+static FILE *file_open(map, tp)
+char *map;
+time_t *tp;
+{
+ FILE *mapf = fopen(map, "r");
+ if (mapf && tp) {
+ struct stat stb;
+ if (fstat(fileno(mapf), &stb) < 0)
+ *tp = clocktime();
+ else
+ *tp = stb.st_mtime;
+ }
+ return mapf;
+}
+
+int file_init P((char *map, time_t *tp));
+int file_init(map, tp)
+char *map;
+time_t *tp;
+{
+ FILE *mapf = file_open(map, tp);
+ if (mapf) {
+ (void) fclose(mapf);
+ return 0;
+ }
+ return errno;
+}
+
+int file_reload P((mnt_map *m, char *map, void (*fn)()));
+int file_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ FILE *mapf = file_open(map, (time_t *) 0);
+ if (mapf) {
+ int error = search_or_reload_file(mapf, map, 0, 0, m, fn);
+ (void) fclose(mapf);
+ return error;
+ }
+
+ return errno;
+}
+
+int file_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int file_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ time_t t;
+ FILE *mapf = file_open(map, &t);
+ if (mapf) {
+ int error;
+ if (*tp < t) {
+ *tp = t;
+ error = -1;
+ } else {
+ error = search_or_reload_file(mapf, map, key, pval, 0, 0);
+ }
+ (void) fclose(mapf);
+ return error;
+ }
+
+ return errno;
+}
+
+int file_mtime P((char *map, time_t *tp));
+int file_mtime(map, tp)
+char *map;
+time_t *tp;
+{
+ FILE *mapf = file_open(map, tp);
+ if (mapf) {
+ (void) fclose(mapf);
+ return 0;
+ }
+
+ return errno;
+}
+#endif /* HAS_FILE_MAPS */
diff --git a/usr.sbin/amd/amd/info_hes.c b/usr.sbin/amd/amd/info_hes.c
new file mode 100644
index 000000000000..875cfe7257b8
--- /dev/null
+++ b/usr.sbin/amd/amd/info_hes.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)info_hes.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_hes.c,v 5.2.2.1 1992/02/09 15:08:29 jsp beta $
+ *
+ */
+
+/*
+ * Get info from Hesiod
+ *
+ * Zone transfer code from Bruce Cole <cole@cs.wisc.edu>
+ */
+
+#include "am.h"
+
+#ifdef HAS_HESIOD_MAPS
+#include <hesiod.h>
+
+#define HES_PREFIX "hesiod."
+#define HES_PREFLEN 7
+
+#ifdef HAS_HESIOD_RELOAD
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <sys/uio.h>
+#include <netdb.h>
+
+/*
+ * Patch up broken system include files
+ */
+#ifndef C_HS
+#define C_HS 4
+#endif
+#ifndef T_TXT
+#define T_TXT 16
+#endif
+
+static int soacnt;
+static struct timeval hs_timeout;
+static int servernum;
+#endif /* HAS_HESIOD_RELOAD */
+
+/*
+ * No easy way to probe the server - check the map name begins with "hesiod."
+ */
+int hesiod_init P((char *map, time_t *tp));
+int hesiod_init(map, tp)
+char *map;
+time_t *tp;
+{
+#ifdef DEBUG
+ dlog("hesiod_init(%s)", map);
+#endif
+ *tp = 0;
+ return strncmp(map, HES_PREFIX, HES_PREFLEN) == 0 ? 0 : ENOENT;
+}
+
+
+/*
+ * Make Hesiod name. Skip past the "hesiod."
+ * at the start of the map name and append
+ * ".automount". The net effect is that a lookup
+ * of /defaults in hesiod.home will result in a
+ * call to hes_resolve("/defaults", "home.automount");
+ */
+#ifdef notdef
+#define MAKE_HES_NAME(dest, src) sprintf(dest, "%s%s", src + HES_PREFLEN, ".automount")
+#endif
+
+/*
+ * Do a Hesiod nameserver call.
+ * Modify time is ignored by Hesiod - XXX
+ */
+int hesiod_search P((mnt_map *m, char *map, char **pval, time_t *tp));
+int hesiod_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ int error;
+ char hes_key[MAXPATHLEN];
+ char **rvec;
+#ifdef DEBUG
+ dlog("hesiod_search(m=%x, map=%s, key=%s, pval=%x tp=%x)", m, map, key, pval, tp);
+#endif
+ /*MAKE_HES_NAME(hes_map, map);*/
+ sprintf(hes_key, "%s.%s", key, map+HES_PREFLEN);
+
+ /*
+ * Call the resolver
+ */
+#ifdef DEBUG
+ dlog("hesiod_search: hes_resolve(%s, %s)", hes_key, "automount");
+#ifdef HAS_HESIOD_RELOAD
+ if (debug_flags & D_FULL)
+ _res.options |= RES_DEBUG;
+#endif
+#endif
+ rvec = hes_resolve(hes_key, "automount");
+ /*
+ * If a reply was forthcoming then return
+ * it (and free subsequent replies)
+ */
+ if (rvec && *rvec) {
+ *pval = *rvec;
+ while (*++rvec)
+ free(*rvec);
+ return 0;
+ }
+
+ /*
+ * Otherwise reflect the hesiod error into a Un*x error
+ */
+#ifdef DEBUG
+ dlog("hesiod_search: Error: %d", hes_error());
+#endif
+ switch (hes_error()) {
+ case HES_ER_NOTFOUND: error = ENOENT; break;
+ case HES_ER_CONFIG: error = EIO; break;
+ case HES_ER_NET: error = ETIMEDOUT; break;
+ default: error = EINVAL; break;
+ }
+#ifdef DEBUG
+ dlog("hesiod_search: Returning: %d", error);
+#endif
+ return error;
+}
+
+#ifdef HAS_HESIOD_RELOAD
+/*
+ * Zone transfer...
+ */
+
+#define MAXHSNS 8
+#define MAX_NSADDR 16
+
+static char *hs_domain;
+static mnt_map *hs_map;
+static int hs_nscount;
+static char nsaddr_list[MAX_NSADDR][sizeof(struct in_addr)];
+
+int hesiod_reload P((mnt_map *m, char *map, void (*fn)()));
+int hesiod_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ char *zone_name, *cp;
+ short domainlen;
+ int status;
+
+#ifdef DEBUG
+ dlog("hesiod_reload (%x %s %x)", m, map, fn);
+#endif DEBUG
+ if (status = res_init()) {
+#ifdef DEBUG
+ dlog("hesiod_reload: res_init failed with %d", status);
+#endif
+ return(status);
+ }
+ _res.retrans = 90;
+ hs_map = m;
+ domainlen = strlen(hostdomain);
+ zone_name = hes_to_bind(map+HES_PREFLEN, "automount");
+ if (*zone_name == '.')
+ zone_name++;
+ hs_domain = zone_name;
+ /* Traverse the DNS tree until we find an SOA we can transfer from.
+ (Our initial zone_name is likely to just be a subtree of a
+ real zone). */
+ do {
+ /* If we can't find any NS records, go up a level in the
+ DNS tree */
+ if (hs_get_ns_list(zone_name) == 0 &&
+ hs_zone_transfer(zone_name) == 0)
+ return(0);
+ /* Move up DNS tree by one component */
+ if (cp = strchr(zone_name, '.'))
+ zone_name = ++cp;
+ else
+ break;
+ } while (strlen(zone_name) >= domainlen);
+#ifdef DEBUG
+ dlog("hesiod_reload: Giving up on %s", hs_domain);
+#endif
+ return(-1);
+}
+
+hs_zone_transfer(domain)
+char *domain;
+{
+ int status, len;
+ char buf[PACKETSZ];
+ /* Want to make sure ansbuf is well alligned */
+ long ansbuf[PACKETSZ/sizeof(long)];
+
+#ifdef DEBUG
+ dlog("hs_zone_transfer (%s)", domain);
+#endif
+ if ((len = res_mkquery(QUERY, domain, C_HS, T_AXFR,
+ (char *)NULL, 0, NULL, buf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_zone_transfer: res_mkquery failed");
+#endif
+ errno = 0;
+ return(-1);
+ }
+ if ((status = hs_res_send(buf, len, (char *)ansbuf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_zone_transfer: hs_res_send failed. status %d errno %d",
+ status, errno);
+#endif
+ errno = 0;
+ return(-1);
+ }
+ return(0);
+}
+
+#define hs_server_addr(ns) ((struct in_addr *) nsaddr_list[ns])
+
+hs_res_send(buf, buflen, answer, anslen)
+char *buf;
+int buflen;
+char *answer;
+int anslen;
+{
+ int retry, ns;
+ u_short id, len;
+ HEADER *hp = (HEADER *) buf;
+ struct iovec iov[2];
+ static int s = -1;
+ int status;
+ struct sockaddr_in server;
+
+ soacnt = 0;
+ id = hp->id;
+ /*
+ * Send request, RETRY times, or until successful
+ */
+ for (retry = _res.retry; retry > 0; retry--) {
+ for (ns = 0; ns < hs_nscount; ns++) {
+ hs_timeout.tv_sec =
+ (_res.retrans << (_res.retry - retry))
+ / hs_nscount;
+ if (hs_timeout.tv_sec <= 0)
+ hs_timeout.tv_sec = 1;
+ hs_timeout.tv_usec = 0;
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ continue;
+ }
+ servernum = ns;
+ bcopy(hs_server_addr(ns), &server.sin_addr,
+ sizeof(struct in_addr));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(NAMESERVER_PORT);
+
+ if (connect(s, &server,
+ sizeof(struct sockaddr)) < 0) {
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ }
+ /*
+ * Send length & message
+ */
+ len = htons((u_short)buflen);
+ iov[0].iov_base = (caddr_t)&len;
+ iov[0].iov_len = sizeof(len);
+ iov[1].iov_base = buf;
+ iov[1].iov_len = buflen;
+ if (writev(s, iov, 2) != sizeof(len) + buflen) {
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ status = 0;
+ while (s != -1 && soacnt < 2 && status != -2) {
+ if ((status =
+ hs_readresp(s, answer, anslen)) == -1) {
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ }
+ if (status == -2) {
+ /* There was a permanent error transfering this
+ zone. Give up. */
+ if (s != -1) {
+ (void) close(s);
+ s = -1;
+ }
+ return(-1);
+ }
+ if (s == -1)
+ continue;
+ return (0);
+ }
+ }
+ if (errno == 0)
+ errno = ETIMEDOUT;
+ return (-1);
+}
+
+/* Returns:
+ 0: Success
+ -1: Error
+ -2: Permanent failure
+*/
+hs_readresp(s, answer, anslen)
+int s;
+char *answer;
+int anslen;
+{
+ register int len, n;
+ char *cp;
+
+ cp = answer;
+ len = sizeof(short);
+ while (len != 0 &&
+ (n = hs_res_vcread(s, (char *)cp, (int)len, &hs_timeout)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0)
+ return(-1);
+ cp = answer;
+ if ((len = _getshort(cp)) > anslen) {
+#ifdef DEBUG
+ dlog("hs_readresp: response too long: %d", len);
+#endif
+ return(-1);
+ }
+ while (len != 0 &&
+ (n = hs_res_vcread(s, (char *)cp, (int)len, &hs_timeout)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0)
+ return(-1);
+ return(hs_parse(answer, answer+PACKETSZ));
+}
+
+hs_res_vcread(sock, buf, buflen, timeout)
+int sock, buflen;
+char *buf;
+struct timeval *timeout;
+{
+ register int n;
+
+ if ((n = hs_res_selwait(sock, timeout)) > 0)
+ return(read(sock, buf, buflen));
+ else
+ return(n);
+}
+
+hs_res_selwait(sock, timeout)
+int sock;
+struct timeval *timeout;
+{
+ fd_set dsmask;
+ register int n;
+
+ /*
+ * Wait for reply
+ */
+ FD_ZERO(&dsmask);
+ FD_SET(sock, &dsmask);
+ n = select(sock+1, &dsmask, (fd_set *)NULL,
+ (fd_set *)NULL, timeout);
+ return(n);
+}
+
+/* Returns:
+ 0: Success
+ -1: Error
+ -2: Permanent failure
+*/
+hs_parse(msg, eom)
+char *msg, *eom;
+{
+ register char *cp;
+ register HEADER *hp;
+ register int n, len;
+ int qdcount, ancount;
+ char key[PACKETSZ];
+ char *key_cpy, *value, *hs_make_value();
+ short type;
+
+ hp = (HEADER *)msg;
+ if (hp->rcode != NOERROR || hp->opcode != QUERY) {
+ char dq[20];
+#ifdef DEBUG
+ dlog("Bad response (%d) from nameserver %s", hp->rcode, inet_dquad(dq, hs_server_addr(servernum)->s_addr));
+#endif DEBUG
+ return(-1);
+ }
+ cp = msg + sizeof(HEADER);
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0)
+ cp += dn_skipname(cp, eom) + QFIXEDSZ;
+ if (soacnt == 0 && ancount == 0) {
+ /* XXX We should look for NS records to find SOA */
+#ifdef DEBUG
+ dlog("No SOA found");
+#endif
+ return(-2);
+ }
+ while (ancount-- > 0 && cp < eom) {
+ if ((n = dn_expand(msg, eom, cp, key, PACKETSZ)) < 0)
+ break;
+ cp += n;
+ if ((type = _getshort(cp)) == T_SOA) {
+ soacnt++;
+ }
+ cp += 2*sizeof(u_short) + sizeof(u_long);
+ len = _getshort(cp);
+ cp += sizeof(u_short);
+ /* Check to see if key is in our domain */
+ if (type == T_TXT && hs_strip_our_domain(key)) {
+ value = hs_make_value(cp, len);
+ if (value == NULL)
+ return(-1);
+ key_cpy = strdup(key);
+#ifdef DEBUG
+ dlog("hs_parse: Parsed key: %s, value: %s", key,
+ value);
+#endif
+ mapc_add_kv(hs_map, key_cpy, value);
+ }
+ cp += len;
+ errno = 0;
+ }
+ return(0);
+}
+
+/* Check to see if the domain name in the supplied argument matches
+ hs_domain. Strip hs_domain from supplied argument if so. */
+hs_strip_our_domain(name)
+char *name;
+{
+ char *end_pos;
+ short targ_len, cur_len;
+
+ targ_len = strlen(hs_domain);
+ cur_len = strlen(name);
+ if (cur_len <= targ_len)
+ return(0);
+ end_pos = &name[cur_len - targ_len];
+ if (strcmp(end_pos, hs_domain) != 0)
+ return(0);
+ if (*--end_pos != '.')
+ return(0);
+ *end_pos = '\0';
+ return(1);
+}
+
+#define MAXDATA 8*1024
+
+char *
+hs_make_value(cp, len)
+char *cp;
+int len;
+{
+ char *value, *cpcpy, *valuep;
+ int cnt, nextcnt, totalcnt, lencpy;
+#ifdef DEBUG
+ char *dbgname;
+
+ dbgname = &cp[1];
+#endif DEBUG
+
+ lencpy = len;
+ cpcpy = cp;
+ totalcnt = 0;
+ cnt = *cpcpy++;
+ while (cnt) {
+ totalcnt += cnt;
+ lencpy -= cnt+1;
+ if (lencpy == 0)
+ break;
+ nextcnt = cpcpy[cnt];
+ cpcpy = &cpcpy[cnt+1];
+ cnt = nextcnt;
+ }
+ if (totalcnt < 1 || totalcnt > MAXDATA || totalcnt > len) {
+#ifdef DEBUG
+ dlog("TXT RR not of expected length (%d %d): %s", totalcnt,
+ len, dbgname);
+#endif DEBUG
+ return(NULL);
+ }
+ /* Allocate null terminated string */
+ value = (char *) xmalloc(totalcnt+1);
+ value[totalcnt] = '\0';
+ cnt = *cp++;
+ valuep = value;
+ while (cnt) {
+ bcopy(cp, valuep, cnt);
+ len -= cnt+1;
+ if (len == 0)
+ break;
+ valuep = &valuep[cnt];
+ nextcnt = cp[cnt];
+ cp = &cp[cnt+1];
+ cnt = nextcnt;
+ }
+ return(value);
+}
+
+hs_make_ns_query(domain, ansbuf)
+char *domain;
+char *ansbuf;
+{
+ int status, len;
+ char buf[PACKETSZ];
+
+ if ((len = res_mkquery(QUERY, domain, C_HS, T_NS,
+ (char *)NULL, 0, NULL, buf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_get_ns_list: res_mkquery failed");
+#endif
+ errno = 0;
+ return(-1);
+ }
+ if ((status = res_send(buf, len, (char *)ansbuf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_get_ns_list: res_send failed. status %d errno %d",
+ status, errno);
+#endif
+ errno = 0;
+ return(-1);
+ }
+ return(0);
+}
+
+static void
+add_address(addr)
+struct in_addr *addr;
+{
+ char dq[20];
+ bcopy((char *)addr, nsaddr_list[hs_nscount++], sizeof(struct in_addr));
+#ifdef DEBUG
+ dlog("Adding NS address %s", inet_dquad(dq, addr->s_addr));
+#endif DEBUG
+}
+
+hs_get_ns_list(domain)
+char *domain;
+{
+ register HEADER *hp;
+ int qdcount, nscount;
+ register char *cp;
+ register int n, len;
+ char key[PACKETSZ], name[PACKETSZ], msg[PACKETSZ], *eom;
+ register long **hptr;
+ struct hostent *ghp;
+ int numns;
+ char nsname[MAXHSNS][MAXDATA];
+ int nshaveaddr[MAXHSNS], i;
+ short type;
+
+ if (hs_make_ns_query(domain, msg) == -1)
+ return(-1);
+ numns = hs_nscount = 0;
+ eom = &msg[PACKETSZ];
+ bzero(nsname, sizeof(nsname));
+ hp = (HEADER *)msg;
+ if (hp->rcode != NOERROR || hp->opcode != QUERY) {
+#ifdef DEBUG
+ dlog("Bad response (%d) from nameserver %#x", hp->rcode,
+ hs_server_addr(servernum)->s_addr);
+#endif DEBUG
+ return(-1);
+ }
+ cp = msg + sizeof(HEADER);
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0)
+ cp += dn_skipname(cp, eom) + QFIXEDSZ;
+ nscount = ntohs(hp->ancount) + ntohs(hp->nscount) + ntohs(hp->arcount);
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Processing %d response records", nscount);
+#endif
+ for (;nscount; nscount--) {
+ if ((n = dn_expand(msg, eom, cp, key, PACKETSZ)) < 0)
+ break;
+ cp += n;
+ type = _getshort(cp);
+ cp += 2*sizeof(u_short) + sizeof(u_long);
+ len = _getshort(cp);
+ cp += sizeof(u_short);
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Record type: %d", type);
+#endif
+ switch (type) {
+ case T_NS:
+ if (numns >= MAXHSNS || strcasecmp(domain, key) != 0)
+ break;
+ if ((n = dn_expand(msg, eom, cp, name, PACKETSZ)) < 0)
+ break;
+#ifdef DEBUG
+ dlog("hs_get_ns_list: NS name: %s", name);
+#endif
+ for (i = 0; i < numns; i++)
+ if (strcasecmp(nsname[i], name) == 0)
+ break;
+ if (i == numns) {
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Saving name %s", name);
+#endif
+ strncpy(nsname[numns], name, MAXDATA);
+ nshaveaddr[numns] = 0;
+ numns++;
+ }
+ break;
+ case T_A:
+ if (hs_nscount == MAX_NSADDR)
+ break;
+ for (i = 0; i < numns; i++) {
+ if (strcasecmp(nsname[i], domain) == 0) {
+ nshaveaddr[i]++;
+ add_address((struct in_addr *) cp);
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if (hs_nscount == MAX_NSADDR)
+ break;
+ cp += len;
+ errno = 0;
+ }
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Found %d NS records", numns);
+#endif
+ for (i = 0; i < numns; i++) {
+ if (nshaveaddr[i])
+ continue;
+ if ((ghp = gethostbyname(nsname[i])) == 0)
+ continue;
+ for (hptr = (long **)ghp->h_addr_list;
+ *hptr && hs_nscount < MAX_NSADDR; hptr++) {
+ add_address((struct in_addr *) *hptr);
+ }
+ }
+ if (hs_nscount)
+ return(0);
+#ifdef DEBUG
+ dlog("No NS records found for %s", domain);
+ return(-1);
+#endif DEBUG
+}
+#endif /* HAS_HESIOD_RELOAD */
+#endif /* HAS_HESIOD_MAPS */
diff --git a/usr.sbin/amd/amd/info_ndbm.c b/usr.sbin/amd/amd/info_ndbm.c
new file mode 100644
index 000000000000..d3deaa187f9f
--- /dev/null
+++ b/usr.sbin/amd/amd/info_ndbm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)info_ndbm.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_ndbm.c,v 5.2.2.1 1992/02/09 15:08:31 jsp beta $
+ *
+ */
+
+/*
+ * Get info from NDBM map
+ */
+
+#include "am.h"
+
+#ifdef HAS_NDBM_MAPS
+
+#include <ndbm.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+static int search_ndbm P((DBM *db, char *key, char **val));
+static int search_ndbm(db, key, val)
+DBM *db;
+char *key;
+char **val;
+{
+ datum k, v;
+ k.dptr = key;
+ k.dsize = strlen(key) + 1;
+ v = dbm_fetch(db, k);
+ if (v.dptr) {
+ *val = strdup(v.dptr);
+ return 0;
+ }
+ return ENOENT;
+}
+
+int ndbm_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int ndbm_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ DBM *db;
+
+ db = dbm_open(map, O_RDONLY, 0);
+ if (db) {
+ struct stat stb;
+ int error;
+ error = fstat(dbm_pagfno(db), &stb);
+ if (!error && *tp < stb.st_mtime) {
+ *tp = stb.st_mtime;
+ error = -1;
+ } else {
+ error = search_ndbm(db, key, pval);
+ }
+ (void) dbm_close(db);
+ return error;
+ }
+
+ return errno;
+}
+
+int ndbm_init P((char *map, time_t *tp));
+int ndbm_init(map, tp)
+char *map;
+time_t *tp;
+{
+ DBM *db;
+
+ db = dbm_open(map, O_RDONLY, 0);
+ if (db) {
+ struct stat stb;
+
+ if (fstat(dbm_pagfno(db), &stb) < 0)
+ *tp = clocktime();
+ else
+ *tp = stb.st_mtime;
+ dbm_close(db);
+ return 0;
+ }
+
+ return errno;
+}
+
+#endif /* HAS_NDBM_MAPS */
diff --git a/usr.sbin/amd/amd/info_nis.c b/usr.sbin/amd/amd/info_nis.c
new file mode 100644
index 000000000000..ac80f5f975dd
--- /dev/null
+++ b/usr.sbin/amd/amd/info_nis.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)info_nis.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_nis.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $
+ *
+ */
+
+/*
+ * Get info from NIS map
+ */
+
+#include "am.h"
+
+#ifdef HAS_NIS_MAPS
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+/*
+ * Figure out the nis domain name
+ */
+static int determine_nis_domain(P_void)
+{
+static int nis_not_running = 0;
+
+ char default_domain[YPMAXDOMAIN];
+
+ if (nis_not_running)
+ return ENOENT;
+
+ if (getdomainname(default_domain, sizeof(default_domain)) < 0) {
+ nis_not_running = 1;
+ plog(XLOG_ERROR, "getdomainname: %m");
+ return EIO;
+ }
+
+ if (!*default_domain) {
+ nis_not_running = 1;
+ plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored.");
+ return ENOENT;
+ }
+
+ domain = strdup(default_domain);
+
+ return 0;
+}
+
+
+#ifdef HAS_NIS_RELOAD
+struct nis_callback_data {
+ mnt_map *ncd_m;
+ char *ncd_map;
+ void (*ncd_fn)();
+};
+
+/*
+ * Callback from yp_all
+ */
+static int callback(status, key, kl, val, vl, data)
+int status;
+char *key;
+int kl;
+char *val;
+int vl;
+struct nis_callback_data *data;
+{
+ if (status == YP_TRUE) {
+ /*
+ * Add to list of maps
+ */
+ char *kp = strnsave(key, kl);
+ char *vp = strnsave(val, vl);
+ (*data->ncd_fn)(data->ncd_m, kp, vp);
+
+ /*
+ * We want more ...
+ */
+ return FALSE;
+ } else {
+ /*
+ * NOMORE means end of map - otherwise log error
+ */
+ if (status != YP_NOMORE) {
+ /*
+ * Check what went wrong
+ */
+ int e = ypprot_err(status);
+
+#ifdef DEBUG
+ plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d",
+ data->ncd_map, yperr_string(e), status, e);
+#else
+ plog(XLOG_ERROR, "yp enumeration of %s: %s", data->ncd_map, yperr_string(e));
+#endif
+ }
+
+ return TRUE;
+ }
+}
+
+int nis_reload P((mnt_map *m, char *map, void (*fn)()));
+int nis_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ struct ypall_callback cbinfo;
+ int error;
+ struct nis_callback_data data;
+
+ if (!domain) {
+ error = determine_nis_domain();
+ if (error)
+ return error;
+ }
+
+ data.ncd_m = m;
+ data.ncd_map = map;
+ data.ncd_fn = fn;
+ cbinfo.data = (voidp) &data;
+ cbinfo.foreach = callback;
+
+ error = yp_all(domain, map, &cbinfo);
+
+ if (error)
+ plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error)));
+
+ return error;
+}
+#endif /* HAS_NIS_RELOAD */
+
+/*
+ * Try to locate a key using NIS.
+ */
+int nis_search P((mnt_map *m, char *map, char *key, char **val, time_t *tp));
+int nis_search(m, map, key, val, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **val;
+time_t *tp;
+{
+ int outlen;
+ int res;
+ int order;
+
+ /*
+ * Make sure domain initialised
+ */
+ if (!domain) {
+ int error = determine_nis_domain();
+ if (error)
+ return error;
+ }
+
+ /*
+ * Check if map has changed
+ */
+ if (yp_order(domain, map, &order))
+ return EIO;
+ if ((time_t) order > *tp) {
+ *tp = (time_t) order;
+ return -1;
+ }
+
+ /*
+ * Lookup key
+ */
+ res = yp_match(domain, map, key, strlen(key), val, &outlen);
+
+ /*
+ * Do something interesting with the return code
+ */
+ switch (res) {
+ case 0:
+ return 0;
+
+ case YPERR_KEY:
+ return ENOENT;
+
+ default:
+ plog(XLOG_ERROR, "%s: %s", map, yperr_string(res));
+ return EIO;
+ }
+}
+
+int nis_init P((char *map, time_t *tp));
+int nis_init(map, tp)
+char *map;
+time_t *tp;
+{
+ int order;
+
+ if (!domain) {
+ int error = determine_nis_domain();
+ if (error)
+ return error;
+ }
+
+ /*
+ * To see if the map exists, try to find
+ * a master for it.
+ */
+ if (yp_order(domain, map, &order))
+ return ENOENT;
+ *tp = (time_t) order;
+#ifdef DEBUG
+ dlog("NIS master for %s@%s has order %d", map, domain, order);
+#endif
+ return 0;
+}
+#endif /* HAS_NIS_MAPS */
diff --git a/usr.sbin/amd/amd/info_passwd.c b/usr.sbin/amd/amd/info_passwd.c
new file mode 100644
index 000000000000..3123e38c8d96
--- /dev/null
+++ b/usr.sbin/amd/amd/info_passwd.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)info_passwd.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_passwd.c,v 5.2.2.1 1992/02/09 15:08:33 jsp beta $
+ *
+ */
+
+/*
+ * Get info from password "file"
+ *
+ * This is experimental and probably doesn't
+ * do what you expect.
+ */
+
+#include "am.h"
+
+#ifdef HAS_PASSWD_MAPS
+#include <pwd.h>
+
+#define PASSWD_MAP "/etc/passwd"
+
+/*
+ * Nothing to probe - check the map name is PASSWD_MAP.
+ */
+int passwd_init P((char *map, time_t *tp));
+int passwd_init(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = 0;
+ return strcmp(map, PASSWD_MAP) == 0 ? 0 : ENOENT;
+}
+
+
+/*
+ * Grab the entry via the getpwname routine
+ * Modify time is ignored by passwd - XXX
+ */
+int passwd_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int passwd_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ char *dir = 0;
+ struct passwd *pw;
+ if (strcmp(key, "/defaults") == 0) {
+ *pval = strdup("type:=nfs");
+ return 0;
+ }
+
+ pw = getpwnam(key);
+ if (pw) {
+ /*
+ * We chop the home directory up as follows:
+ * /anydir/dom1/dom2/dom3/user
+ *
+ * and return
+ * rfs:=/anydir/dom3;rhost:=dom3.dom2.dom1;sublink:=user
+ *
+ * This allows cross-domain entries in your passwd file.
+ * ... but forget about security!
+ */
+ char *user;
+ char *p, *q;
+ char val[MAXPATHLEN];
+ char rhost[MAXHOSTNAMELEN];
+ dir = strdup(pw->pw_dir);
+ /*
+ * Find user name. If no / then Invalid...
+ */
+ user = strrchr(dir, '/');
+ if (!user)
+ goto enoent;
+ *user++ = '\0';
+ /*
+ * Find start of host "path". If no / then Invalid...
+ */
+ p = strchr(dir+1, '/');
+ if (!p)
+ goto enoent;
+ *p++ = '\0';
+ /*
+ * At this point, p is dom1/dom2/dom3
+ * Copy, backwards, into rhost replacing
+ * / with .
+ */
+ rhost[0] = '\0';
+ do {
+ q = strrchr(p, '/');
+ if (q) {
+ strcat(rhost, q + 1);
+ strcat(rhost, ".");
+ *q = '\0';
+ } else {
+ strcat(rhost, p);
+ }
+ } while (q);
+ /*
+ * Sanity check
+ */
+ if (*rhost == '\0' || *user == '\0' || *dir == '\0')
+ goto enoent;
+ /*
+ * Make up return string
+ */
+ q = strchr(rhost, '.');
+ if (q)
+ *q = '\0';
+ sprintf(val, "rfs:=%s/%s;rhost:=%s;sublink:=%s;fs:=${autodir}%s",
+ dir, rhost, rhost, user, pw->pw_dir);
+ if (q)
+ *q = '.';
+ *pval = strdup(val);
+ return 0;
+ }
+
+enoent:
+ if (dir)
+ free(dir);
+
+ return ENOENT;
+}
+#endif /* HAS_PASSWD_MAPS */
diff --git a/usr.sbin/amd/amd/info_union.c b/usr.sbin/amd/amd/info_union.c
new file mode 100644
index 000000000000..e3062adaa5a3
--- /dev/null
+++ b/usr.sbin/amd/amd/info_union.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)info_union.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_union.c,v 5.2.2.1 1992/02/09 15:08:34 jsp beta $
+ *
+ */
+
+/*
+ * Get info from the system namespace
+ *
+ * NOTE: Cannot handle reads back through the automounter.
+ * THIS WILL CAUSE A DEADLOCK!
+ */
+
+#include "am.h"
+
+#ifdef HAS_UNION_MAPS
+
+#ifdef _POSIX_SOURCE
+#include <dirent.h>
+#define DIRENT struct dirent
+#else
+#include <sys/dir.h>
+#define DIRENT struct direct
+#endif
+
+#define UNION_PREFIX "union:"
+#define UNION_PREFLEN 6
+
+/*
+ * No way to probe - check the map name begins with "union:"
+ */
+int union_init P((char *map, time_t *tp));
+int union_init(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = 0;
+ return strncmp(map, UNION_PREFIX, UNION_PREFLEN) == 0 ? 0 : ENOENT;
+}
+
+int union_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int union_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ char *mapd = strdup(map + UNION_PREFLEN);
+ char **v = strsplit(mapd, ':', '\"');
+ char **p;
+ for (p = v; p[1]; p++)
+ ;
+ *pval = xmalloc(strlen(*p) + 5);
+ sprintf(*pval, "fs:=%s", *p);
+ free(mapd);
+ free(v);
+ return 0;
+}
+
+int union_reload P((mnt_map *m, char *map, void (*fn)()));
+int union_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ char *mapd = strdup(map + UNION_PREFLEN);
+ char **v = strsplit(mapd, ':', '\"');
+ char **dir;
+
+ /*
+ * Add fake /defaults entry
+ */
+ (*fn)(m, strdup("/defaults"), strdup("type:=link;opts:=nounmount;sublink:=${key}"));
+
+ for (dir = v; *dir; dir++) {
+ int dlen;
+ DIRENT *dp;
+ DIR *dirp = opendir(*dir);
+ if (!dirp) {
+ plog(XLOG_USER, "Cannot read directory %s: %m", *dir);
+ continue;
+ }
+ dlen = strlen(*dir);
+#ifdef DEBUG
+ dlog("Reading directory %s...", *dir);
+#endif
+ while (dp = readdir(dirp)) {
+ char *val;
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+ continue;
+
+#ifdef DEBUG
+ dlog("... gives %s", dp->d_name);
+#endif
+ val = xmalloc(dlen + 5);
+ sprintf(val, "fs:=%s", *dir);
+ (*fn)(m, strdup(dp->d_name), val);
+ }
+ closedir(dirp);
+ }
+ /*
+ * Add wildcard entry
+ */
+ { char *val = xmalloc(strlen(dir[-1]) + 5);
+ sprintf(val, "fs:=%s", dir[-1]);
+ (*fn)(m, strdup("*"), val);
+ }
+ free(mapd);
+ free(v);
+ return 0;
+}
+
+#endif /* HAS_UNION_MAPS */
diff --git a/usr.sbin/amd/amd/map.c b/usr.sbin/amd/amd/map.c
new file mode 100644
index 000000000000..6f2acb383907
--- /dev/null
+++ b/usr.sbin/amd/amd/map.c
@@ -0,0 +1,1140 @@
+/*-
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * $Id: map.c,v 5.2.2.1 1992/02/09 15:08:36 jsp beta $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "am.h"
+
+/*
+ * Generation Numbers.
+ *
+ * Generation numbers are allocated to every node created
+ * by amd. When a filehandle is computed and sent to the
+ * kernel, the generation number makes sure that it is safe
+ * to reallocate a node slot even when the kernel has a cached
+ * reference to its old incarnation.
+ * No garbage collection is done, since it is assumed that
+ * there is no way that 2^32 generation numbers could ever
+ * be allocated by a single run of amd - there is simply
+ * not enough cpu time available.
+ */
+static unsigned int am_gen = 2; /* Initial generation number */
+#define new_gen() (am_gen++)
+
+am_node **exported_ap = (am_node **) 0;
+int exported_ap_size = 0;
+int first_free_map = 0; /* First available free slot */
+int last_used_map = -1; /* Last unavailable used slot */
+static int timeout_mp_id; /* Id from last call to timeout */
+
+/*
+ * This is the default attributes field which
+ * is copied into every new node to be created.
+ * The individual filesystem fs_init() routines
+ * patch the copy to represent the particular
+ * details for the relevant filesystem type
+ */
+static struct fattr gen_fattr = {
+ NFLNK, /* type */
+ NFSMODE_LNK | 0777, /* mode */
+ 1, /* nlink */
+ 0, /* uid */
+ 0, /* gid */
+ 0, /* size */
+ 4096, /* blocksize */
+ 0, /* rdev */
+ 1, /* blocks */
+ 0, /* fsid */
+ 0, /* fileid */
+ { 0, 0 }, /* atime */
+ { 0, 0 }, /* mtime */
+ { 0, 0 }, /* ctime */
+};
+
+/*
+ * Resize exported_ap map
+ */
+static int exported_ap_realloc_map P((int nsize));
+static int exported_ap_realloc_map(nsize)
+int nsize;
+{
+#ifdef notdef
+ /*
+ * If a second realloc occasionally causes Amd to die
+ * in then include this check.
+ */
+ if (exported_ap_size != 0) /* XXX */
+ return 0;
+#endif
+
+ /*
+ * this shouldn't happen, but...
+ */
+ if (nsize < 0 || nsize == exported_ap_size)
+ return 0;
+
+ exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node*));
+
+ if (nsize > exported_ap_size)
+ bzero((char*) (exported_ap+exported_ap_size),
+ (nsize - exported_ap_size) * sizeof(am_node*));
+ exported_ap_size = nsize;
+
+ return 1;
+}
+
+
+/*
+ * The root of the mount tree.
+ */
+am_node *root_node;
+
+/*
+ * Allocate a new mount slot and create
+ * a new node.
+ * Fills in the map number of the node,
+ * but leaves everything else uninitialised.
+ */
+am_node *exported_ap_alloc(P_void)
+{
+ am_node *mp, **mpp;
+
+ /*
+ * First check if there are any slots left, realloc if needed
+ */
+ if (first_free_map >= exported_ap_size)
+ if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP))
+ return 0;
+
+ /*
+ * Grab the next free slot
+ */
+ mpp = exported_ap + first_free_map;
+ mp = *mpp = ALLOC(am_node);
+ bzero((char *) mp, sizeof(*mp));
+
+ mp->am_mapno = first_free_map++;
+
+ /*
+ * Update free pointer
+ */
+ while (first_free_map < exported_ap_size && exported_ap[first_free_map])
+ first_free_map++;
+
+ if (first_free_map > last_used_map)
+ last_used_map = first_free_map - 1;
+
+ /*
+ * Shrink exported_ap if reasonable
+ */
+ if (last_used_map < exported_ap_size - (NEXP_AP + NEXP_AP_MARGIN))
+ exported_ap_realloc_map(exported_ap_size - NEXP_AP);
+
+#ifdef DEBUG
+ /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n",
+ last_used_map, first_free_map);*/
+#endif /* DEBUG */
+
+ return mp;
+}
+
+/*
+ * Free a mount slot
+ */
+void exported_ap_free P((am_node *mp));
+void exported_ap_free(mp)
+am_node *mp;
+{
+ /*
+ * Sanity check
+ */
+ if (!mp)
+ return;
+
+ /*
+ * Zero the slot pointer to avoid double free's
+ */
+ exported_ap[mp->am_mapno] = 0;
+
+ /*
+ * Update the free and last_used indices
+ */
+ if (mp->am_mapno == last_used_map)
+ while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
+ --last_used_map;
+
+ if (first_free_map > mp->am_mapno)
+ first_free_map = mp->am_mapno;
+
+#ifdef DEBUG
+ /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n",
+ last_used_map, first_free_map);*/
+#endif /* DEBUG */
+
+ /*
+ * Free the mount node
+ */
+ free((voidp) mp);
+}
+
+/*
+ * Insert mp into the correct place,
+ * where p_mp is its parent node.
+ * A new node gets placed as the youngest sibling
+ * of any other children, and the parent's child
+ * pointer is adjusted to point to the new child node.
+ */
+void insert_am(mp, p_mp)
+am_node *mp;
+am_node *p_mp;
+{
+ /*
+ * If this is going in at the root then flag it
+ * so that it cannot be unmounted by amq.
+ */
+ if (p_mp == root_node)
+ mp->am_flags |= AMF_ROOT;
+ /*
+ * Fill in n-way links
+ */
+ mp->am_parent = p_mp;
+ mp->am_osib = p_mp->am_child;
+ if (mp->am_osib)
+ mp->am_osib->am_ysib = mp;
+ p_mp->am_child = mp;
+}
+
+/*
+ * Remove am from its place in the mount tree
+ */
+void remove_am(mp)
+am_node *mp;
+{
+ /*
+ * 1. Consistency check
+ */
+ if (mp->am_child && mp->am_parent) {
+ plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
+ }
+
+ /*
+ * 2. Update parent's child pointer
+ */
+ if (mp->am_parent && mp->am_parent->am_child == mp)
+ mp->am_parent->am_child = mp->am_osib;
+
+ /*
+ * 3. Unlink from sibling chain
+ */
+ if (mp->am_ysib)
+ mp->am_ysib->am_osib = mp->am_osib;
+ if (mp->am_osib)
+ mp->am_osib->am_ysib = mp->am_ysib;
+}
+
+/*
+ * Compute a new time to live value for a node.
+ */
+void new_ttl(mp)
+am_node *mp;
+{
+ mp->am_timeo_w = 0;
+
+ mp->am_ttl = clocktime();
+ mp->am_fattr.atime.seconds = mp->am_ttl;
+ mp->am_ttl += mp->am_timeo; /* sun's -tl option */
+}
+
+void mk_fattr P((am_node *mp, ftype vntype));
+void mk_fattr(mp, vntype)
+am_node *mp;
+ftype vntype;
+{
+ switch (vntype) {
+ case NFDIR:
+ mp->am_fattr.type = NFDIR;
+ mp->am_fattr.mode = NFSMODE_DIR | 0555;
+ mp->am_fattr.nlink = 2;
+ mp->am_fattr.size = 512;
+ break;
+ case NFLNK:
+ mp->am_fattr.type = NFLNK;
+ mp->am_fattr.mode = NFSMODE_LNK | 0777;
+ mp->am_fattr.nlink = 1;
+ mp->am_fattr.size = 0;
+ break;
+ default:
+ plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype);
+ break;
+ }
+}
+
+/*
+ * Initialise an allocated mount node.
+ * It is assumed that the mount node was bzero'd
+ * before getting here so anything that would
+ * be set to zero isn't done here.
+ */
+void init_map(mp, dir)
+am_node *mp;
+char *dir;
+{
+ /* mp->am_mapno initalised by exported_ap_alloc */
+ mp->am_mnt = new_mntfs();
+ mp->am_name = strdup(dir);
+ mp->am_path = strdup(dir);
+ /*mp->am_link = 0;*/
+ /*mp->am_parent = 0;*/
+ /*mp->am_ysib = 0;*/
+ /*mp->am_osib = 0;*/
+ /*mp->am_child = 0;*/
+ /*mp->am_flags = 0;*/
+ /*mp->am_error = 0;*/
+ mp->am_gen = new_gen();
+ /*mp->am_pref = 0;*/
+
+ mp->am_timeo = am_timeo;
+ mp->am_attr.status = NFS_OK;
+ mp->am_fattr = gen_fattr;
+ mp->am_fattr.fsid = 42;
+ mp->am_fattr.fileid = 0;
+ mp->am_fattr.atime.seconds = clocktime();
+ mp->am_fattr.atime.useconds = 0;
+ mp->am_fattr.mtime = mp->am_fattr.ctime = mp->am_fattr.atime;
+
+ new_ttl(mp);
+ mp->am_stats.s_mtime = mp->am_fattr.atime.seconds;
+ /*mp->am_private = 0;*/
+}
+
+/*
+ * Free a mount node.
+ * The node must be already unmounted.
+ */
+void free_map(mp)
+am_node *mp;
+{
+ remove_am(mp);
+
+ if (mp->am_link)
+ free(mp->am_link);
+ if (mp->am_name)
+ free(mp->am_name);
+ if (mp->am_path)
+ free(mp->am_path);
+ if (mp->am_pref)
+ free(mp->am_pref);
+
+ if (mp->am_mnt)
+ free_mntfs(mp->am_mnt);
+
+ exported_ap_free(mp);
+}
+
+/*
+ * Convert from file handle to
+ * automount node.
+ */
+am_node *fh_to_mp3(fhp, rp, c_or_d)
+nfs_fh *fhp;
+int *rp;
+int c_or_d;
+{
+ struct am_fh *fp = (struct am_fh *) fhp;
+ am_node *ap = 0;
+
+ /*
+ * Check process id matches
+ * If it doesn't then it is probably
+ * from an old kernel cached filehandle
+ * which is now out of date.
+ */
+ if (fp->fhh_pid != mypid)
+ goto drop;
+
+ /*
+ * Make sure the index is valid before
+ * exported_ap is referenced.
+ */
+ if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size)
+ goto drop;
+
+ /*
+ * Get hold of the supposed mount node
+ */
+ ap = exported_ap[fp->fhh_id];
+
+ /*
+ * If it exists then maybe...
+ */
+ if (ap) {
+ /*
+ * Check the generation number in the node
+ * matches the one from the kernel. If not
+ * then the old node has been timed out and
+ * a new one allocated.
+ */
+ if (ap->am_gen != fp->fhh_gen) {
+ ap = 0;
+ goto drop;
+ }
+
+ /*
+ * If the node is hung then locate a new node
+ * for it. This implements the replicated filesystem
+ * retries.
+ */
+ if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
+ int error;
+ am_node *orig_ap = ap;
+#ifdef DEBUG
+ dlog("fh_to_mp3: %s (%s) is hung:- call lookup",
+ orig_ap->am_path, orig_ap->am_mnt->mf_info);
+#endif /* DEBUG */
+ /*
+ * Update modify time of parent node.
+ * With any luck the kernel will re-stat
+ * the child node and get new information.
+ */
+ orig_ap->am_fattr.mtime.seconds = clocktime();
+
+ /*
+ * Call the parent's lookup routine for an object
+ * with the same name. This may return -1 in error
+ * if a mount is in progress. In any case, if no
+ * mount node is returned the error code is propagated
+ * to the caller.
+ */
+ if (c_or_d == VLOOK_CREATE) {
+ ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn)(orig_ap->am_parent,
+ orig_ap->am_name, &error, c_or_d);
+ } else {
+ ap = 0;
+ error = ESTALE;
+ }
+ if (ap == 0) {
+ if (error < 0 && amd_state == Finishing)
+ error = ENOENT;
+ *rp = error;
+ return 0;
+ }
+ /*
+ * Update last access to original node. This
+ * avoids timing it out and so sending ESTALE
+ * back to the kernel.
+ * XXX - Not sure we need this anymore (jsp, 90/10/6).
+ */
+ new_ttl(orig_ap);
+
+ }
+ /*
+ * Disallow references to objects being unmounted, unless
+ * they are automount points.
+ */
+ if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
+ !(ap->am_flags & AMF_ROOT)) {
+ if (amd_state == Finishing)
+ *rp = ENOENT;
+ else
+ *rp = -1;
+ return 0;
+ }
+ new_ttl(ap);
+ }
+
+drop:
+ if (!ap || !ap->am_mnt) {
+ /*
+ * If we are shutting down then it is likely
+ * that this node has disappeared because of
+ * a fast timeout. To avoid things thrashing
+ * just pretend it doesn't exist at all. If
+ * ESTALE is returned, some NFS clients just
+ * keep retrying (stupid or what - if it's
+ * stale now, what's it going to be in 5 minutes?)
+ */
+ if (amd_state == Finishing)
+ *rp = ENOENT;
+ else
+ *rp = ESTALE;
+ amd_stats.d_stale++;
+ }
+
+ return ap;
+}
+
+am_node *fh_to_mp(fhp)
+nfs_fh *fhp;
+{
+ int dummy;
+ return fh_to_mp2(fhp, &dummy);
+}
+
+/*
+ * Convert from automount node to
+ * file handle.
+ */
+void mp_to_fh(mp, fhp)
+am_node *mp;
+struct nfs_fh *fhp;
+{
+ struct am_fh *fp = (struct am_fh *) fhp;
+
+ /*
+ * Take the process id
+ */
+ fp->fhh_pid = mypid;
+ /*
+ * .. the map number
+ */
+ fp->fhh_id = mp->am_mapno;
+ /*
+ * .. and the generation number
+ */
+ fp->fhh_gen = mp->am_gen;
+ /*
+ * .. to make a "unique" triple that will never
+ * be reallocated except across reboots (which doesn't matter)
+ * or if we are unlucky enough to be given the same
+ * pid as a previous amd (very unlikely).
+ */
+}
+
+static am_node *find_ap2 P((char *dir, am_node *mp));
+static am_node *find_ap2(dir, mp)
+char *dir;
+am_node *mp;
+{
+ if (mp) {
+ am_node *mp2;
+ if (strcmp(mp->am_path, dir) == 0)
+ return mp;
+
+ if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
+ strcmp(mp->am_mnt->mf_mount, dir) == 0)
+ return mp;
+
+ mp2 = find_ap2(dir, mp->am_osib);
+ if (mp2)
+ return mp2;
+ return find_ap2(dir, mp->am_child);
+ }
+
+ return 0;
+}
+
+/*
+ * Find the mount node corresponding
+ * to dir. dir can match either the
+ * automount path or, if the node is
+ * mounted, the mount location.
+ */
+am_node *find_ap P((char *dir));
+am_node *find_ap(dir)
+char *dir;
+{
+ int i;
+
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp && (mp->am_flags & AMF_ROOT)) {
+ mp = find_ap2(dir, exported_ap[i]);
+ if (mp)
+ return mp;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Find the mount node corresponding
+ * to the mntfs structure.
+ */
+am_node *find_mf P((mntfs *mf));
+am_node *find_mf(mf)
+mntfs *mf;
+{
+ int i;
+
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp && mp->am_mnt == mf)
+ return mp;
+ }
+ return 0;
+}
+
+/*
+ * Get the filehandle for a particular named directory.
+ * This is used during the bootstrap to tell the kernel
+ * the filehandles of the initial automount points.
+ */
+nfs_fh *root_fh(dir)
+char *dir;
+{
+ static nfs_fh nfh;
+ am_node *mp = root_ap(dir, TRUE);
+ if (mp) {
+ mp_to_fh(mp, &nfh);
+ /*
+ * Patch up PID to match main server...
+ */
+ if (!foreground) {
+ long pid = getppid();
+ ((struct am_fh *) &nfh)->fhh_pid = pid;
+#ifdef DEBUG
+ dlog("root_fh substitutes pid %d", pid);
+#endif
+ }
+ return &nfh;
+ }
+
+ /*
+ * Should never get here...
+ */
+ plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
+ return 0;
+}
+
+am_node *root_ap(dir, path)
+char *dir;
+int path;
+{
+ am_node *mp = find_ap(dir);
+ if (mp && mp->am_parent == root_node)
+ return mp;
+
+ return 0;
+}
+
+/*
+ * Timeout all nodes waiting on
+ * a given Fserver.
+ */
+void map_flush_srvr P((fserver *fs));
+void map_flush_srvr(fs)
+fserver *fs;
+{
+ int i;
+ int done = 0;
+
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) {
+ plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host);
+ mp->am_ttl = clocktime();
+ done = 1;
+ }
+ }
+ if (done)
+ reschedule_timeout_mp();
+}
+
+/*
+ * Mount a top level automount node
+ * by calling lookup in the parent
+ * (root) node which will cause the
+ * automount node to be automounted.
+ */
+int mount_auto_node P((char *dir, voidp arg));
+int mount_auto_node(dir, arg)
+char *dir;
+voidp arg;
+{
+ int error = 0;
+ (void) afs_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE);
+ if (error > 0) {
+ errno = error; /* XXX */
+ plog(XLOG_ERROR, "Could not mount %s: %m", dir);
+ }
+ return error;
+}
+
+/*
+ * Cause all the top-level mount nodes
+ * to be automounted
+ */
+int mount_exported P((void));
+int mount_exported()
+{
+ /*
+ * Iterate over all the nodes to be started
+ */
+ return root_keyiter((void (*)P((char*,void*))) mount_auto_node, root_node);
+}
+
+/*
+ * Construct top-level node
+ */
+void make_root_node P((void));
+void make_root_node()
+{
+ mntfs *root_mnt;
+ char *rootmap = ROOT_MAP;
+ root_node = exported_ap_alloc();
+
+ /*
+ * Allocate a new map
+ */
+ init_map(root_node, "");
+ /*
+ * Allocate a new mounted filesystem
+ */
+ root_mnt = find_mntfs(&root_ops, (am_opts *) 0, "", rootmap, "", "", "");
+ /*
+ * Replace the initial null reference
+ */
+ free_mntfs(root_node->am_mnt);
+ root_node->am_mnt = root_mnt;
+
+ /*
+ * Initialise the root
+ */
+ if (root_mnt->mf_ops->fs_init)
+ (*root_mnt->mf_ops->fs_init)(root_mnt);
+
+ /*
+ * Mount the root
+ */
+ root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs)(root_node);
+}
+
+/*
+ * Cause all the nodes to be unmounted by timing
+ * them out.
+ */
+void umount_exported(P_void)
+{
+ int i;
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp) {
+ mntfs *mf = mp->am_mnt;
+ if (mf->mf_flags & MFF_UNMOUNTING) {
+ /*
+ * If this node is being unmounted then
+ * just ignore it. However, this could
+ * prevent amd from finishing if the
+ * unmount gets blocked since the am_node
+ * will never be free'd. am_unmounted needs
+ * telling about this possibility. - XXX
+ */
+ continue;
+ }
+ if (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) {
+ /*
+ * When shutting down this had better
+ * look like a directory, otherwise it
+ * can't be unmounted!
+ */
+ mk_fattr(mp, NFDIR);
+ }
+ if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
+ (mf->mf_flags & MFF_RESTART)) {
+ /*
+ * Just throw this node away without
+ * bothering to unmount it. If the
+ * server is not known to be up then
+ * don't discard the mounted on directory
+ * or Amd might hang...
+ */
+ if (mf->mf_server &&
+ (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID)
+ mf->mf_flags &= ~MFF_MKMNT;
+ am_unmounted(mp);
+ } else {
+ /*
+ * Any other node gets forcibly
+ * timed out
+ */
+ mp->am_flags &= ~AMF_NOTIMEOUT;
+ mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
+ mp->am_ttl = 0;
+ mp->am_timeo = 1;
+ mp->am_timeo_w = 0;
+ }
+ }
+ }
+}
+
+static int unmount_node P((am_node *mp));
+static int unmount_node(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ int error;
+
+ if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
+ /*
+ * Just unlink
+ */
+#ifdef DEBUG
+ if (mf->mf_flags & MFF_ERROR)
+ dlog("No-op unmount of error node %s", mf->mf_info);
+#endif /* DEBUG */
+ error = 0;
+ } else {
+#ifdef DEBUG
+ dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
+#endif /* DEBUG */
+ error = (*mf->mf_ops->umount_fs)(mp);
+ }
+
+ if (error) {
+#ifdef DEBUG
+ errno = error; /* XXX */
+ dlog("%s: unmount: %m", mf->mf_mount);
+#endif /* DEBUG */
+ }
+
+ return error;
+}
+
+#ifdef FLUSH_KERNEL_NAME_CACHE
+static void flush_kernel_name_cache P((am_node*));
+static void flush_kernel_name_cache(mp)
+am_node *mp;
+{
+ int islink = (mp->am_mnt->mf_fattr.type == NFLNK);
+ int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);
+ int elog = 0;
+ if (islink) {
+ if (unlink(mp->am_path) < 0)
+ elog = 1;
+ } else if (isdir) {
+ if (rmdir(mp->am_path) < 0)
+ elog = 1;
+ }
+ if (elog)
+ plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path);
+}
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+
+static int unmount_node_wrap P((voidp vp));
+static int unmount_node_wrap(vp)
+voidp vp;
+{
+#ifndef FLUSH_KERNEL_NAME_CACHE
+ return unmount_node((am_node*) vp);
+#else /* FLUSH_KERNEL_NAME_CACHE */
+ /*
+ * This code should just say:
+ * return unmount_node((am_node *) vp);
+ *
+ * However...
+ * The kernel keeps a cached copy of filehandles,
+ * and doesn't ever uncache them (apparently). So
+ * when Amd times out a node the kernel will have a
+ * stale filehandle. When the kernel next uses the
+ * filehandle it gets ESTALE.
+ *
+ * The workaround:
+ * Arrange that when a node is removed an unlink or
+ * rmdir is done on that path so that the kernel
+ * cache is done. Yes - yuck.
+ *
+ * This can all be removed (and the background
+ * unmount flag in sfs_ops) if/when the kernel does
+ * something smarter.
+ *
+ * If the unlink or rmdir failed then just log a warning,
+ * don't fail the unmount. This can occur if the kernel
+ * client code decides that the object is still referenced
+ * and should be renamed rather than discarded.
+ *
+ * There is still a race condition here...
+ * if another process is trying to access the same
+ * filesystem at the time we get here, then
+ * it will block, since the MF_UNMOUNTING flag will
+ * be set. That may, or may not, cause the entire
+ * system to deadlock. Hmmm...
+ */
+ am_node *mp = (am_node *) vp;
+ int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);
+ int error = unmount_node(mp);
+ if (error)
+ return error;
+ if (isauto && (int)amd_state < (int)Finishing)
+ flush_kernel_name_cache(mp);
+
+ return 0;
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+}
+
+static void free_map_if_success(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ am_node *mp = (am_node *) closure;
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * Not unmounting any more
+ */
+ mf->mf_flags &= ~MFF_UNMOUNTING;
+
+ /*
+ * If a timeout was defered because the underlying filesystem
+ * was busy then arrange for a timeout as soon as possible.
+ */
+ if (mf->mf_flags & MFF_WANTTIMO) {
+ mf->mf_flags &= ~MFF_WANTTIMO;
+ reschedule_timeout_mp();
+ }
+
+ if (term) {
+ plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
+#if defined(DEBUG) && defined(SIGTRAP)
+ /*
+ * dbx likes to put a trap on exit().
+ * Pretend it succeeded for now...
+ */
+ if (term == SIGTRAP) {
+ am_unmounted(mp);
+ }
+#endif /* DEBUG */
+ amd_stats.d_uerr++;
+ } else if (rc) {
+ if (rc == EBUSY) {
+ plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
+ } else {
+ errno = rc; /* XXX */
+ plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);
+ }
+ amd_stats.d_uerr++;
+ } else {
+ am_unmounted(mp);
+ }
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) mf);
+}
+
+static int unmount_mp(mp)
+am_node *mp;
+{
+ int was_backgrounded = 0;
+ mntfs *mf = mp->am_mnt;
+
+#ifdef notdef
+ plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+#endif /* notdef */
+
+ if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&
+ (mf->mf_flags & MFF_MOUNTED)) {
+ if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
+ /*
+ * Don't try to unmount from a server that is known to be down
+ */
+ if (!(mf->mf_flags & MFF_LOGDOWN)) {
+ /* Only log this once, otherwise gets a bit boring */
+ plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
+ mf->mf_flags |= MFF_LOGDOWN;
+ }
+ } else {
+ /* Clear logdown flag - since the server must be up */
+ mf->mf_flags &= ~MFF_LOGDOWN;
+#ifdef DEBUG
+ dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+ /*dlog("Will background the unmount attempt");*/
+#endif /* DEBUG */
+ /*
+ * Note that we are unmounting this node
+ */
+ mf->mf_flags |= MFF_UNMOUNTING;
+ run_task(unmount_node_wrap, (voidp) mp,
+ free_map_if_success, (voidp) mp);
+ was_backgrounded = 1;
+#ifdef DEBUG
+ dlog("unmount attempt backgrounded");
+#endif /* DEBUG */
+ }
+ } else {
+#ifdef DEBUG
+ dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+ dlog("Trying unmount in foreground");
+#endif
+ mf->mf_flags |= MFF_UNMOUNTING;
+ free_map_if_success(unmount_node(mp), 0, (voidp) mp);
+#ifdef DEBUG
+ dlog("unmount attempt done");
+#endif /* DEBUG */
+ }
+
+ return was_backgrounded;
+}
+
+void timeout_mp()
+{
+#define NEVER (time_t) 0
+#define smallest_t(t1, t2) \
+ (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
+#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
+
+ int i;
+ time_t t = NEVER;
+ time_t now = clocktime();
+ int backoff = 0;
+
+#ifdef DEBUG
+ dlog("Timing out automount points...");
+#endif /* DEBUG */
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ mntfs *mf;
+ /*
+ * Just continue if nothing mounted, or can't be timed out.
+ */
+ if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
+ continue;
+ /*
+ * Pick up mounted filesystem
+ */
+ mf = mp->am_mnt;
+ if (!mf)
+ continue;
+ /*
+ * Don't delete last reference to a restarted filesystem.
+ */
+ if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
+ continue;
+ /*
+ * If there is action on this filesystem then ignore it
+ */
+ if (!(mf->mf_flags & IGNORE_FLAGS)) {
+ int expired = 0;
+ mf->mf_flags &= ~MFF_WANTTIMO;
+#ifdef DEBUG
+ /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/
+#endif /* DEBUG */
+ if (now >= mp->am_ttl) {
+ if (!backoff) {
+ expired = 1;
+ /*
+ * Move the ttl forward to avoid thrashing effects
+ * on the next call to timeout!
+ */
+ /* sun's -tw option */
+ if (mp->am_timeo_w < 4 * am_timeo_w)
+ mp->am_timeo_w += am_timeo_w;
+ mp->am_ttl = now + mp->am_timeo_w;
+ } else {
+ /*
+ * Just backoff this unmount for
+ * a couple of seconds to avoid
+ * many multiple unmounts being
+ * started in parallel.
+ */
+ mp->am_ttl = now + backoff + 1;
+ }
+ }
+ /*
+ * If the next ttl is smallest, use that
+ */
+ t = smallest_t(t, mp->am_ttl);
+
+#ifdef DEBUG
+ /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/
+#endif /* DEBUG */
+
+ if (!mp->am_child && mf->mf_error >= 0 && expired) {
+ /*
+ * If the unmount was backgrounded then
+ * bump the backoff counter.
+ */
+ if (unmount_mp(mp)) {
+ backoff = 2;
+#ifdef DEBUG
+ /*dlog("backing off subsequent unmounts by at least %d seconds", backoff);*/
+#endif
+ }
+ }
+ } else if (mf->mf_flags & MFF_UNMOUNTING) {
+ mf->mf_flags |= MFF_WANTTIMO;
+ }
+ }
+
+ if (t == NEVER) {
+#ifdef DEBUG
+ dlog("No further timeouts");
+#endif /* DEBUG */
+ t = now + ONE_HOUR;
+ }
+
+ /*
+ * Sanity check to avoid runaways.
+ * Absolutely should never get this but
+ * if you do without this trap amd will thrash.
+ */
+ if (t <= now) {
+ t = now + 6; /* XXX */
+ plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
+ }
+ /*
+ * XXX - when shutting down, make things happen faster
+ */
+ if ((int)amd_state >= (int)Finishing)
+ t = now + 1;
+#ifdef DEBUG
+ dlog("Next mount timeout in %ds", t - now);
+#endif /* DEBUG */
+
+ timeout_mp_id = timeout(t - now, timeout_mp, 0);
+
+#undef NEVER
+#undef smallest_t
+#undef IGNORE_FLAGS
+}
+
+/*
+ * Cause timeout_mp to be called soonest
+ */
+void reschedule_timeout_mp()
+{
+ if (timeout_mp_id)
+ untimeout(timeout_mp_id);
+ timeout_mp_id = timeout(0, timeout_mp, 0);
+}
diff --git a/usr.sbin/amd/amd/mapc.c b/usr.sbin/amd/amd/mapc.c
new file mode 100644
index 000000000000..2155f19cfa4b
--- /dev/null
+++ b/usr.sbin/amd/amd/mapc.c
@@ -0,0 +1,914 @@
+/*-
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * $Id: mapc.c,v 5.2.2.1 1992/02/09 15:08:38 jsp beta $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)mapc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Mount map cache
+ */
+
+#include "am.h"
+#ifdef HAS_REGEXP
+#include RE_HDR
+#endif
+
+/*
+ * Hash table size
+ */
+#define NKVHASH (1 << 2) /* Power of two */
+
+/*
+ * Wildcard key
+ */
+static char wildcard[] = "*";
+
+/*
+ * Map cache types
+ * default, none, incremental, all, regexp
+ * MAPC_RE implies MAPC_ALL and must be numerically
+ * greater.
+ */
+#define MAPC_DFLT 0x000
+#define MAPC_NONE 0x001
+#define MAPC_INC 0x002
+#define MAPC_ROOT 0x004
+#define MAPC_ALL 0x010
+#ifdef HAS_REGEXP
+#define MAPC_RE 0x020
+#define MAPC_ISRE(m) ((m)->alloc == MAPC_RE)
+#else
+#define MAPC_ISRE(m) FALSE
+#endif
+#define MAPC_CACHE_MASK 0x0ff
+#define MAPC_SYNC 0x100
+
+static struct opt_tab mapc_opt[] = {
+ { "all", MAPC_ALL },
+ { "default", MAPC_DFLT },
+ { "inc", MAPC_INC },
+ { "mapdefault", MAPC_DFLT },
+ { "none", MAPC_NONE },
+#ifdef HAS_REGEXP
+ { "re", MAPC_RE },
+ { "regexp", MAPC_RE },
+#endif
+ { "sync", MAPC_SYNC },
+ { 0, 0 }
+};
+
+/*
+ * Lookup recursion
+ */
+#define MREC_FULL 2
+#define MREC_PART 1
+#define MREC_NONE 0
+
+/*
+ * Cache map operations
+ */
+typedef void add_fn P((mnt_map*, char*, char*));
+typedef int init_fn P((char*, time_t*));
+typedef int search_fn P((mnt_map*, char*, char*, char**, time_t*));
+typedef int reload_fn P((mnt_map*, char*, add_fn*));
+typedef int mtime_fn P((char*, time_t*));
+
+static void mapc_sync P((mnt_map*));
+
+/*
+ * Map type
+ */
+typedef struct map_type map_type;
+struct map_type {
+ char *name; /* Name of this map type */
+ init_fn *init; /* Initialisation */
+ reload_fn *reload; /* Reload or fill */
+ search_fn *search; /* Search for new entry */
+ mtime_fn *mtime; /* Find modify time */
+ int def_alloc; /* Default allocation mode */
+};
+
+/*
+ * Key-value pair
+ */
+typedef struct kv kv;
+struct kv {
+ kv *next;
+ char *key;
+ char *val;
+};
+
+struct mnt_map {
+ qelem hdr;
+ int refc; /* Reference count */
+ short flags; /* Allocation flags */
+ short alloc; /* Allocation mode */
+ time_t modify; /* Modify time of map */
+ char *map_name; /* Name of this map */
+ char *wildcard; /* Wildcard value */
+ reload_fn *reload; /* Function to be used for reloads */
+ search_fn *search; /* Function to be used for searching */
+ mtime_fn *mtime; /* Modify time function */
+ kv *kvhash[NKVHASH]; /* Cached data */
+};
+
+/*
+ * Map for root node
+ */
+static mnt_map *root_map;
+
+/*
+ * List of known maps
+ */
+extern qelem map_list_head;
+qelem map_list_head = { &map_list_head, &map_list_head };
+
+/*
+ * Configuration
+ */
+
+/* ROOT MAP */
+static int root_init P((char*, time_t*));
+
+/* FILE MAPS */
+#ifdef HAS_FILE_MAPS
+extern int file_init P((char*, time_t*));
+extern int file_reload P((mnt_map*, char*, add_fn*));
+extern int file_search P((mnt_map*, char*, char*, char**, time_t*));
+extern int file_mtime P((char*, time_t*));
+#endif /* HAS_FILE_MAPS */
+
+/* Network Information Service (NIS) MAPS */
+#ifdef HAS_NIS_MAPS
+extern int nis_init P((char*, time_t*));
+#ifdef HAS_NIS_RELOAD
+extern int nis_reload P((mnt_map*, char*, add_fn*));
+#else
+#define nis_reload error_reload
+#endif
+extern int nis_search P((mnt_map*, char*, char*, char**, time_t*));
+#define nis_mtime nis_init
+#endif /* HAS_NIS_MAPS */
+
+/* NDBM MAPS */
+#ifdef HAS_NDBM_MAPS
+#ifdef OS_HAS_NDBM
+extern int ndbm_init P((char*, time_t*));
+extern int ndbm_search P((mnt_map*, char*, char*, char**, time_t*));
+#define ndbm_mtime ndbm_init
+#endif /* OS_HAS_NDBM */
+#endif /* HAS_NDBM_MAPS */
+
+/* PASSWD MAPS */
+#ifdef HAS_PASSWD_MAPS
+extern int passwd_init P((char*, time_t*));
+extern int passwd_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_PASSWD_MAPS */
+
+/* HESIOD MAPS */
+#ifdef HAS_HESIOD_MAPS
+extern int hesiod_init P((char*, time_t*));
+#ifdef HAS_HESIOD_RELOAD
+extern int hesiod_reload P((mnt_map*, char*, add_fn*));
+#else
+#define hesiod_reload error_reload
+#endif
+extern int hesiod_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_HESIOD_MAPS */
+
+/* UNION MAPS */
+#ifdef HAS_UNION_MAPS
+extern int union_init P((char*, time_t*));
+extern int union_search P((mnt_map*, char*, char*, char**, time_t*));
+extern int union_reload P((mnt_map*, char*, add_fn*));
+#endif /* HAS_UNION_MAPS */
+
+/* ERROR MAP */
+static int error_init P((char*, time_t*));
+static int error_reload P((mnt_map*, char*, add_fn*));
+static int error_search P((mnt_map*, char*, char*, char**, time_t*));
+static int error_mtime P((char*, time_t*));
+
+static map_type maptypes[] = {
+ { "root", root_init, error_reload, error_search, error_mtime, MAPC_ROOT },
+
+#ifdef HAS_PASSWD_MAPS
+ { "passwd", passwd_init, error_reload, passwd_search, error_mtime, MAPC_INC },
+#endif
+
+#ifdef HAS_HESIOD_MAPS
+ { "hesiod", hesiod_init, hesiod_reload, hesiod_search, error_mtime, MAPC_ALL },
+#endif
+
+#ifdef HAS_UNION_MAPS
+ { "union", union_init, union_reload, union_search, error_mtime, MAPC_ALL },
+#endif
+
+#ifdef HAS_NIS_MAPS
+ { "nis", nis_init, nis_reload, nis_search, nis_mtime, MAPC_INC },
+#endif
+
+#ifdef HAS_NDBM_MAPS
+ { "ndbm", ndbm_init, error_reload, ndbm_search, ndbm_mtime, MAPC_INC },
+#endif
+
+#ifdef HAS_FILE_MAPS
+ { "file", file_init, file_reload, file_search, file_mtime, MAPC_ALL },
+#endif
+
+ { "error", error_init, error_reload, error_search, error_mtime, MAPC_NONE },
+};
+
+/*
+ * Hash function
+ */
+static unsigned int kvhash_of P((char *key));
+static unsigned int kvhash_of(key)
+char *key;
+{
+ unsigned int i, j;
+
+ for (i = 0; j = *key++; i += j)
+ ;
+
+ return i % NKVHASH;
+}
+
+void mapc_showtypes P((FILE *fp));
+void mapc_showtypes(fp)
+FILE *fp;
+{
+ map_type *mt;
+ char *sep = "";
+ for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) {
+ fprintf(fp, "%s%s", sep, mt->name);
+ sep = ", ";
+ }
+}
+
+static Const char *reg_error = "?";
+void regerror P((Const char *m));
+void regerror(m)
+Const char *m;
+{
+ reg_error = m;
+}
+
+/*
+ * Add key and val to the map m.
+ * key and val are assumed to be safe copies
+ */
+void mapc_add_kv P((mnt_map *m, char *key, char *val));
+void mapc_add_kv(m, key, val)
+mnt_map *m;
+char *key;
+char *val;
+{
+ kv **h;
+ kv *n;
+ int hash = kvhash_of(key);
+
+#ifdef DEBUG
+ dlog("add_kv: %s -> %s", key, val);
+#endif
+
+#ifdef HAS_REGEXP
+ if (MAPC_ISRE(m)) {
+ char keyb[MAXPATHLEN];
+ regexp *re;
+ /*
+ * Make sure the string is bound to the start and end
+ */
+ sprintf(keyb, "^%s$", key);
+ re = regcomp(keyb);
+ if (re == 0) {
+ plog(XLOG_USER, "error compiling RE \"%s\": %s", keyb, reg_error);
+ return;
+ } else {
+ free(key);
+ key = (char *) re;
+ }
+ }
+#endif
+
+ h = &m->kvhash[hash];
+ n = ALLOC(kv);
+ n->key = key;
+ n->val = val;
+ n->next = *h;
+ *h = n;
+}
+
+void mapc_repl_kv P((mnt_map *m, char *key, char *val));
+void mapc_repl_kv(m, key, val)
+mnt_map *m;
+char *key;
+char *val;
+{
+ kv *k;
+
+ /*
+ * Compute the hash table offset
+ */
+ k = m->kvhash[kvhash_of(key)];
+
+ /*
+ * Scan the linked list for the key
+ */
+ while (k && !FSTREQ(k->key, key))
+ k = k->next;
+
+ if (k) {
+ free(k->val);
+ k->val = val;
+ } else {
+ mapc_add_kv(m, key, val);
+ }
+
+}
+
+/*
+ * Search a map for a key.
+ * Calls map specific search routine.
+ * While map is out of date, keep re-syncing.
+ */
+static int search_map P((mnt_map *m, char *key, char **valp));
+static int search_map(m, key, valp)
+mnt_map *m;
+char *key;
+char **valp;
+{
+ int rc;
+ do {
+ rc = (*m->search)(m, m->map_name, key, valp, &m->modify);
+ if (rc < 0) {
+ plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
+ mapc_sync(m);
+ }
+ } while (rc < 0);
+
+ return rc;
+}
+
+/*
+ * Do a wildcard lookup in the map and
+ * save the result.
+ */
+static void mapc_find_wildcard P((mnt_map *m));
+static void mapc_find_wildcard(m)
+mnt_map *m;
+{
+ /*
+ * Attempt to find the wildcard entry
+ */
+ int rc = search_map(m, wildcard, &m->wildcard);
+
+ if (rc != 0)
+ m->wildcard = 0;
+}
+
+/*
+ * Make a duplicate reference to an existing map
+ */
+#define mapc_dup(m) ((m)->refc++, (m))
+
+/*
+ * Do a map reload
+ */
+static int mapc_reload_map(m)
+mnt_map *m;
+{
+ int error;
+#ifdef DEBUG
+ dlog("calling map reload on %s", m->map_name);
+#endif
+ error = (*m->reload)(m, m->map_name, mapc_add_kv);
+ if (error)
+ return error;
+ m->wildcard = 0;
+#ifdef DEBUG
+ dlog("calling mapc_search for wildcard");
+#endif
+ error = mapc_search(m, wildcard, &m->wildcard);
+ if (error)
+ m->wildcard = 0;
+ return 0;
+}
+
+/*
+ * Create a new map
+ */
+static mnt_map *mapc_create P((char *map, char *opt));
+static mnt_map *mapc_create(map, opt)
+char *map;
+char *opt;
+{
+ mnt_map *m = ALLOC(mnt_map);
+ map_type *mt;
+ time_t modify;
+ int alloc = 0;
+
+ (void) cmdoption(opt, mapc_opt, &alloc);
+
+ for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++)
+ if ((*mt->init)(map, &modify) == 0)
+ break;
+ /* assert: mt in maptypes */
+
+ m->flags = alloc & ~MAPC_CACHE_MASK;
+ alloc &= MAPC_CACHE_MASK;
+
+ if (alloc == MAPC_DFLT)
+ alloc = mt->def_alloc;
+ switch (alloc) {
+ default:
+ plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
+ alloc = MAPC_INC;
+ /* fallthrough... */
+ case MAPC_NONE:
+ case MAPC_INC:
+ case MAPC_ROOT:
+ break;
+ case MAPC_ALL:
+ /*
+ * If there is no support for reload and it was requested
+ * then back off to incremental instead.
+ */
+ if (mt->reload == error_reload) {
+ plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
+ alloc = MAPC_INC;
+ }
+ break;
+#ifdef HAS_REGEXP
+ case MAPC_RE:
+ if (mt->reload == error_reload) {
+ plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name);
+ mt = &maptypes[sizeof(maptypes)/sizeof(maptypes[0]) - 1];
+ /* assert: mt->name == "error" */
+ }
+ break;
+#endif
+ }
+
+#ifdef DEBUG
+ dlog("Map for %s coming from maptype %s", map, mt->name);
+#endif
+
+ m->alloc = alloc;
+ m->reload = mt->reload;
+ m->modify = modify;
+ m->search = alloc >= MAPC_ALL ? error_search : mt->search;
+ m->mtime = mt->mtime;
+ bzero((voidp) m->kvhash, sizeof(m->kvhash));
+ m->map_name = strdup(map);
+ m->refc = 1;
+ m->wildcard = 0;
+
+ /*
+ * synchronize cache with reality
+ */
+ mapc_sync(m);
+
+ return m;
+}
+
+/*
+ * Free the cached data in a map
+ */
+static void mapc_clear P((mnt_map *m));
+static void mapc_clear(m)
+mnt_map *m;
+{
+ int i;
+
+ /*
+ * For each of the hash slots, chain
+ * along free'ing the data.
+ */
+ for (i = 0; i < NKVHASH; i++) {
+ kv *k = m->kvhash[i];
+ while (k) {
+ kv *n = k->next;
+ free((voidp) k->key);
+ if (k->val)
+ free((voidp) k->val);
+ free((voidp) k);
+ k = n;
+ }
+ }
+ /*
+ * Zero the hash slots
+ */
+ bzero((voidp) m->kvhash, sizeof(m->kvhash));
+ /*
+ * Free the wildcard if it exists
+ */
+ if (m->wildcard) {
+ free(m->wildcard);
+ m->wildcard = 0;
+ }
+}
+
+/*
+ * Find a map, or create one if it does not exist
+ */
+mnt_map *mapc_find P((char *map, char *opt));
+mnt_map *mapc_find(map, opt)
+char *map;
+char *opt;
+{
+ mnt_map *m;
+
+ /*
+ * Search the list of known maps to see if
+ * it has already been loaded. If it is found
+ * then return a duplicate reference to it.
+ * Otherwise make a new map as required and
+ * add it to the list of maps
+ */
+ ITER(m, mnt_map, &map_list_head)
+ if (STREQ(m->map_name, map))
+ return mapc_dup(m);
+
+ m = mapc_create(map, opt);
+ ins_que(&m->hdr, &map_list_head);
+ return m;
+}
+
+/*
+ * Free a map.
+ */
+void mapc_free P((mnt_map *m));
+void mapc_free(m)
+mnt_map *m;
+{
+ /*
+ * Decrement the reference count.
+ * If the reference count hits zero
+ * then throw the map away.
+ */
+ if (m && --m->refc == 0) {
+ mapc_clear(m);
+ free((voidp) m->map_name);
+ rem_que(&m->hdr);
+ free((voidp) m);
+ }
+}
+
+/*
+ * Search the map for the key.
+ * Put a safe copy in *pval or return
+ * an error code
+ */
+int mapc_meta_search P((mnt_map *m, char *key, char **pval, int recurse));
+int mapc_meta_search(m, key, pval, recurse)
+mnt_map *m;
+char *key;
+char **pval;
+int recurse;
+{
+ int error = 0;
+ kv *k = 0;
+
+ /*
+ * Firewall
+ */
+ if (!m) {
+ plog(XLOG_ERROR, "Null map request for %s", key);
+ return ENOENT;
+ }
+
+ if (m->flags & MAPC_SYNC) {
+ /*
+ * Get modify time...
+ */
+ time_t t;
+ error = (*m->mtime)(m->map_name, &t);
+ if (error || t > m->modify) {
+ m->modify = t;
+ plog(XLOG_INFO, "Map %s is out of date", m->map_name);
+ mapc_sync(m);
+ }
+ }
+
+ if (!MAPC_ISRE(m)) {
+ /*
+ * Compute the hash table offset
+ */
+ k = m->kvhash[kvhash_of(key)];
+
+ /*
+ * Scan the linked list for the key
+ */
+ while (k && !FSTREQ(k->key, key)) k = k->next;
+
+ }
+#ifdef HAS_REGEXP
+ else if (recurse == MREC_FULL) {
+ /*
+ * Try for an RE match against the entire map.
+ * Note that this will be done in a "random"
+ * order.
+ */
+
+ int i;
+
+ for (i = 0; i < NKVHASH; i++) {
+ k = m->kvhash[i];
+ while (k) {
+ if (regexec((regexp *) k->key, key))
+ break;
+ k = k->next;
+ }
+ if (k)
+ break;
+ }
+ }
+#endif
+
+ /*
+ * If found then take a copy
+ */
+ if (k) {
+ if (k->val)
+ *pval = strdup(k->val);
+ else
+ error = ENOENT;
+ } else if (m->alloc >= MAPC_ALL) {
+ /*
+ * If the entire map is cached then this
+ * key does not exist.
+ */
+ error = ENOENT;
+ } else {
+ /*
+ * Otherwise search the map. If we are
+ * in incremental mode then add the key
+ * to the cache.
+ */
+ error = search_map(m, key, pval);
+ if (!error && m->alloc == MAPC_INC)
+ mapc_add_kv(m, strdup(key), strdup(*pval));
+ }
+
+ /*
+ * If an error, and a wildcard exists,
+ * and the key is not internal then
+ * return a copy of the wildcard.
+ */
+ if (error > 0) {
+ if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
+ char wildname[MAXPATHLEN];
+ char *subp;
+ if (*key == '/')
+ return error;
+ /*
+ * Keep chopping sub-directories from the RHS
+ * and replacing with "/ *" and repeat the lookup.
+ * For example:
+ * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
+ */
+ strcpy(wildname, key);
+ while (error && (subp = strrchr(wildname, '/'))) {
+ strcpy(subp, "/*");
+#ifdef DEBUG
+ dlog("mapc recurses on %s", wildname);
+#endif
+ error = mapc_meta_search(m, wildname, pval, MREC_PART);
+ if (error)
+ *subp = 0;
+ }
+ if (error > 0 && m->wildcard) {
+ *pval = strdup(m->wildcard);
+ error = 0;
+ }
+ }
+ }
+
+ return error;
+}
+
+int mapc_search P((mnt_map *m, char *key, char **pval));
+int mapc_search(m, key, pval)
+mnt_map *m;
+char *key;
+char **pval;
+{
+ return mapc_meta_search(m, key, pval, MREC_FULL);
+}
+
+/*
+ * Get map cache in sync with physical representation
+ */
+static void mapc_sync P((mnt_map *m));
+static void mapc_sync(m)
+mnt_map *m;
+{
+ if (m->alloc != MAPC_ROOT) {
+ mapc_clear(m);
+
+ if (m->alloc >= MAPC_ALL)
+ if (mapc_reload_map(m))
+ m->alloc = MAPC_INC;
+ /*
+ * Attempt to find the wildcard entry
+ */
+ if (m->alloc < MAPC_ALL)
+ mapc_find_wildcard(m);
+ }
+}
+
+/*
+ * Reload all the maps
+ * Called when Amd gets hit by a SIGHUP.
+ */
+void mapc_reload(P_void);
+void mapc_reload()
+{
+ mnt_map *m;
+
+ /*
+ * For all the maps,
+ * Throw away the existing information.
+ * Do a reload
+ * Find the wildcard
+ */
+ ITER(m, mnt_map, &map_list_head)
+ mapc_sync(m);
+}
+
+/*
+ * Root map.
+ * The root map is used to bootstrap amd.
+ * All the require top-level mounts are added
+ * into the root map and then the map is iterated
+ * and a lookup is done on all the mount points.
+ * This causes the top level mounts to be automounted.
+ */
+
+static int root_init P((char *map, time_t *tp));
+static int root_init(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = clocktime();
+ return strcmp(map, ROOT_MAP) == 0 ? 0 : ENOENT;
+}
+
+/*
+ * Add a new entry to the root map
+ *
+ * dir - directory (key)
+ * opts - mount options
+ * map - map name
+ */
+void root_newmap P((char *dir, char *opts, char *map));
+void root_newmap(dir, opts, map)
+char *dir;
+char *opts;
+char *map;
+{
+ char str[MAXPATHLEN];
+
+ /*
+ * First make sure we have a root map to talk about...
+ */
+ if (!root_map)
+ root_map = mapc_find(ROOT_MAP, "mapdefault");
+
+ /*
+ * Then add the entry...
+ */
+ dir = strdup(dir);
+ if (map)
+ sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
+ map, opts ? opts : "");
+ else
+ strcpy(str, opts);
+ mapc_repl_kv(root_map, dir, strdup(str));
+}
+
+int mapc_keyiter P((mnt_map *m, void (*fn)(char*,voidp), voidp arg));
+int mapc_keyiter(m, fn, arg)
+mnt_map *m;
+void (*fn)P((char*, voidp));
+voidp arg;
+{
+ int i;
+ int c = 0;
+
+ for (i = 0; i < NKVHASH; i++) {
+ kv *k = m->kvhash[i];
+ while (k) {
+ (*fn)(k->key, arg);
+ k = k->next;
+ c++;
+ }
+ }
+
+ return c;
+}
+
+/*
+ * Iterate of the the root map
+ * and call (*fn)() on the key
+ * of all the nodes.
+ * Finally throw away the root map.
+ */
+int root_keyiter P((void (*fn)(char*,voidp), voidp arg));
+int root_keyiter(fn, arg)
+void (*fn)P((char*,voidp));
+voidp arg;
+{
+ if (root_map) {
+ int c = mapc_keyiter(root_map, fn, arg);
+#ifdef notdef
+ mapc_free(root_map);
+ root_map = 0;
+#endif
+ return c;
+ }
+ return 0;
+}
+
+/*
+ * Error map
+ */
+static int error_init P((char *map, time_t *tp));
+static int error_init(map, tp)
+char *map;
+time_t *tp;
+{
+ plog(XLOG_USER, "No source data for map %s", map);
+ *tp = 0;
+ return 0;
+}
+
+/*ARGSUSED*/
+static int error_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+static int error_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ return ENOENT;
+}
+
+/*ARGSUSED*/
+static int error_reload P((mnt_map *m, char *map, add_fn *fn));
+static int error_reload(m, map, fn)
+mnt_map *m;
+char *map;
+add_fn *fn;
+{
+ return ENOENT;
+}
+
+static int error_mtime P((char *map, time_t *tp));
+static int error_mtime(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = 0;
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/misc_rpc.c b/usr.sbin/amd/amd/misc_rpc.c
new file mode 100644
index 000000000000..0fb10c8ad741
--- /dev/null
+++ b/usr.sbin/amd/amd/misc_rpc.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)misc_rpc.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc_rpc.c,v 5.2.2.1 1992/02/09 15:08:40 jsp beta $
+ *
+ */
+
+/*
+ * Additions to Sun RPC.
+ */
+
+#include "am.h"
+
+void rpc_msg_init P((struct rpc_msg *mp, u_long prog, u_long vers, u_long proc));
+void rpc_msg_init(mp, prog, vers, proc)
+struct rpc_msg *mp;
+unsigned long prog, vers, proc;
+{
+ /*
+ * Initialise the message
+ */
+ bzero((voidp) mp, sizeof(*mp));
+ mp->rm_xid = 0;
+ mp->rm_direction = CALL;
+ mp->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ mp->rm_call.cb_prog = prog;
+ mp->rm_call.cb_vers = vers;
+ mp->rm_call.cb_proc = proc;
+}
+
+/*
+ * Field reply to call to mountd
+ */
+int pickup_rpc_reply P((voidp pkt, int len, voidp where, xdrproc_t where_xdr));
+int pickup_rpc_reply(pkt, len, where, where_xdr)
+voidp pkt;
+int len;
+voidp where;
+xdrproc_t where_xdr;
+{
+ XDR reply_xdr;
+ int ok;
+ struct rpc_err err;
+ struct rpc_msg reply_msg;
+ int error = 0;
+
+ /*bzero((voidp) &err, sizeof(err));*/
+ bzero((voidp) &reply_msg, sizeof(reply_msg));
+
+ reply_msg.acpted_rply.ar_results.where = (caddr_t) where;
+ reply_msg.acpted_rply.ar_results.proc = where_xdr;
+
+ xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE);
+
+ ok = xdr_replymsg(&reply_xdr, &reply_msg);
+ if (!ok) {
+ error = EIO;
+ goto drop;
+ }
+ _seterr_reply(&reply_msg, &err);
+ if (err.re_status != RPC_SUCCESS) {
+ error = EIO;
+ goto drop;
+ }
+
+drop:
+ if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED &&
+ reply_msg.acpted_rply.ar_verf.oa_base) {
+ reply_xdr.x_op = XDR_FREE;
+ (void)xdr_opaque_auth(&reply_xdr,
+ &reply_msg.acpted_rply.ar_verf);
+ }
+ xdr_destroy(&reply_xdr);
+
+ return error;
+}
+
+int make_rpc_packet P((char *buf, int buflen, unsigned long proc,
+ struct rpc_msg *mp, voidp arg, xdrproc_t arg_xdr, AUTH *auth));
+int make_rpc_packet(buf, buflen, proc, mp, arg, arg_xdr, auth)
+char *buf;
+int buflen;
+unsigned long proc;
+struct rpc_msg *mp;
+voidp arg;
+xdrproc_t arg_xdr;
+AUTH *auth;
+{
+ XDR msg_xdr;
+ int len;
+
+ xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE);
+ /*
+ * Basic protocol header
+ */
+ if (!xdr_callhdr(&msg_xdr, mp))
+ return -EIO;
+ /*
+ * Called procedure number
+ */
+ if (!xdr_enum(&msg_xdr, &proc))
+ return -EIO;
+ /*
+ * Authorization
+ */
+ if (!AUTH_MARSHALL(auth, &msg_xdr))
+ return -EIO;
+ /*
+ * Arguments
+ */
+ if (!(*arg_xdr)(&msg_xdr, arg))
+ return -EIO;
+ /*
+ * Determine length
+ */
+ len = xdr_getpos(&msg_xdr);
+ /*
+ * Throw away xdr
+ */
+ xdr_destroy(&msg_xdr);
+ return len;
+}
+
+
+/*
+ * Early RPC seems to be missing these..
+ * Extracted from the RPC 3.9 sources as indicated
+ */
+
+#ifdef NEED_XDR_POINTER
+/* @(#)xdr_reference.c 1.1 87/11/04 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ * What's sent is actually a union:
+ *
+ * union object_pointer switch (boolean b) {
+ * case TRUE: object_data data;
+ * case FALSE: void nothing;
+ * }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(xdrs,objpp,obj_size,xdr_obj)
+ register XDR *xdrs;
+ char **objpp;
+ u_int obj_size;
+ xdrproc_t xdr_obj;
+{
+
+ bool_t more_data;
+
+ more_data = (*objpp != NULL);
+ if (! xdr_bool(xdrs,&more_data)) {
+ return (FALSE);
+ }
+ if (! more_data) {
+ *objpp = NULL;
+ return (TRUE);
+ }
+ return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
+#endif /* NEED_XDR_POINTER */
+
+#ifdef NEED_CLNT_SPERRNO
+/* @(#)clnt_perror.c 1.1 87/11/04 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+struct rpc_errtab {
+ enum clnt_stat status;
+ char *message;
+};
+
+static struct rpc_errtab rpc_errlist[] = {
+ { RPC_SUCCESS,
+ "RPC: Success" },
+ { RPC_CANTENCODEARGS,
+ "RPC: Can't encode arguments" },
+ { RPC_CANTDECODERES,
+ "RPC: Can't decode result" },
+ { RPC_CANTSEND,
+ "RPC: Unable to send" },
+ { RPC_CANTRECV,
+ "RPC: Unable to receive" },
+ { RPC_TIMEDOUT,
+ "RPC: Timed out" },
+ { RPC_VERSMISMATCH,
+ "RPC: Incompatible versions of RPC" },
+ { RPC_AUTHERROR,
+ "RPC: Authentication error" },
+ { RPC_PROGUNAVAIL,
+ "RPC: Program unavailable" },
+ { RPC_PROGVERSMISMATCH,
+ "RPC: Program/version mismatch" },
+ { RPC_PROCUNAVAIL,
+ "RPC: Procedure unavailable" },
+ { RPC_CANTDECODEARGS,
+ "RPC: Server can't decode arguments" },
+ { RPC_SYSTEMERROR,
+ "RPC: Remote system error" },
+ { RPC_UNKNOWNHOST,
+ "RPC: Unknown host" },
+/* { RPC_UNKNOWNPROTO,
+ "RPC: Unknown protocol" },*/
+ { RPC_PMAPFAILURE,
+ "RPC: Port mapper failure" },
+ { RPC_PROGNOTREGISTERED,
+ "RPC: Program not registered"},
+ { RPC_FAILED,
+ "RPC: Failed (unspecified error)"}
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno(stat)
+ enum clnt_stat stat;
+{
+ int i;
+
+ for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) {
+ if (rpc_errlist[i].status == stat) {
+ return (rpc_errlist[i].message);
+ }
+ }
+ return ("RPC: (unknown error code)");
+}
+
+#endif /* NEED_CLNT_SPERRNO */
+
diff --git a/usr.sbin/amd/amd/mntfs.c b/usr.sbin/amd/amd/mntfs.c
new file mode 100644
index 000000000000..ef8f17f2cbf1
--- /dev/null
+++ b/usr.sbin/amd/amd/mntfs.c
@@ -0,0 +1,367 @@
+/*-
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * $Id: mntfs.c,v 5.2.2.1 1992/02/09 15:08:42 jsp beta $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)mntfs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+
+#include "am.h"
+
+extern qelem mfhead;
+qelem mfhead = { &mfhead, &mfhead };
+
+int mntfs_allocated;
+
+#ifdef notdef
+/*
+ * This is the default attributes field which
+ * is copied into every new node to be created.
+ * The individual filesystem fs_init() routines
+ * patch the copy to represent the particular
+ * details for the relevant filesystem type
+ */
+static struct fattr gen_fattr = {
+ NFDIR, /* type */
+ NFSMODE_DIR | 0555, /* mode */
+ 2, /* nlink */
+ 0, /* uid */
+ 0, /* gid */
+ 512, /* size */
+ 4096, /* blocksize */
+ 0, /* rdev */
+ 1, /* blocks */
+ 0, /* fsid */
+ 0, /* fileid */
+ { 0, 0 }, /* atime */
+ { 0, 0 }, /* mtime */
+ { 0, 0 }, /* ctime */
+};
+#endif /* notdef */
+
+mntfs *dup_mntfs(mf)
+mntfs *mf;
+{
+ if (mf->mf_refc == 0) {
+ if (mf->mf_cid)
+ untimeout(mf->mf_cid);
+ mf->mf_cid = 0;
+#ifdef notdef
+ mf->mf_error = -1;
+ mf->mf_flags &= ~MFF_ERROR;
+#endif
+ }
+ mf->mf_refc++;
+ return mf;
+}
+
+static void init_mntfs P((mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+static void init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts)
+mntfs *mf;
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mf->mf_ops = ops;
+ mf->mf_fo = mo;
+ mf->mf_mount = strdup(mp);
+ mf->mf_info = strdup(info);
+ mf->mf_auto = strdup(auto_opts);
+ mf->mf_mopts = strdup(mopts);
+ mf->mf_remopts = strdup(remopts);
+ mf->mf_refc = 1;
+ mf->mf_flags = 0;
+ mf->mf_error = -1;
+ mf->mf_cid = 0;
+ mf->mf_private = 0;
+ mf->mf_prfree = 0;
+#ifdef notdef
+ mf->mf_attr.status = NFS_OK;
+ mf->mf_fattr = gen_fattr;
+ mf->mf_fattr.fsid = 42;
+ mf->mf_fattr.fileid = 0;
+ mf->mf_fattr.atime.seconds = clocktime();
+ mf->mf_fattr.atime.useconds = 0;
+ mf->mf_fattr.mtime = mf->mf_fattr.ctime = mf->mf_fattr.atime;
+#endif
+
+ if (ops->ffserver)
+ mf->mf_server = (*ops->ffserver)(mf);
+ else
+ mf->mf_server = 0;
+}
+
+static mntfs *alloc_mntfs P((am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+static mntfs *alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts)
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mntfs *mf = ALLOC(mntfs);
+ init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts);
+ ins_que(&mf->mf_q, &mfhead);
+ mntfs_allocated++;
+
+ return mf;
+}
+
+mntfs *find_mntfs P((am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+mntfs *find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts)
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mntfs *mf;
+
+#ifdef DEBUG
+ dlog("Locating mntfs reference to %s", mp);
+#endif /* DEBUG */
+ ITER(mf, mntfs, &mfhead) {
+ if (STREQ(mf->mf_mount, mp)) {
+ /*
+ * Handle cases where error ops are involved
+ */
+ if (ops == &efs_ops) {
+ /*
+ * If the existing ops are not efs_ops
+ * then continue...
+ */
+ if (mf->mf_ops != &efs_ops)
+ continue;
+ } else /* ops != &efs_ops */ {
+ /*
+ * If the existing ops are efs_ops
+ * then continue...
+ */
+ if (mf->mf_ops == &efs_ops)
+ continue;
+ }
+
+ if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) {
+ /*
+ * Restart a previously mounted filesystem.
+ */
+ mntfs *mf2 = alloc_mntfs(&ifs_ops, mo, mp, info, auto_opts, mopts, remopts);
+#ifdef DEBUG
+ dlog("Restarting filesystem %s", mf->mf_mount);
+#endif /* DEBUG */
+ /*
+ * Remember who we are restarting
+ */
+ mf2->mf_private = (voidp) dup_mntfs(mf);
+ mf2->mf_prfree = free_mntfs;
+ return mf2;
+ }
+ mf->mf_fo = mo;
+ if (!(mf->mf_flags & (MFF_MOUNTED|MFF_MOUNTING|MFF_UNMOUNTING))) {
+ fserver *fs;
+ mf->mf_flags &= ~MFF_ERROR;
+ mf->mf_error = -1;
+ mf->mf_auto = strealloc(mf->mf_auto, auto_opts);
+ mf->mf_mopts = strealloc(mf->mf_mopts, mopts);
+ mf->mf_remopts = strealloc(mf->mf_remopts, remopts);
+ mf->mf_info = strealloc(mf->mf_info, info);
+ if (mf->mf_private && mf->mf_prfree) {
+ (*mf->mf_prfree)(mf->mf_private);
+ mf->mf_private = 0;
+ }
+ fs = ops->ffserver ? (*ops->ffserver)(mf) : (fserver *) 0;
+ if (mf->mf_server)
+ free_srvr(mf->mf_server);
+ mf->mf_server = fs;
+ }
+ return dup_mntfs(mf);
+ }
+ }
+
+ return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
+}
+
+mntfs *new_mntfs()
+{
+ return alloc_mntfs(&efs_ops, (am_opts *) 0, "//nil//", ".", "", "", "");
+}
+
+static void uninit_mntfs(mf, rmd)
+mntfs *mf;
+int rmd;
+{
+ if (mf->mf_mount) free((voidp) mf->mf_mount);
+ if (mf->mf_auto) free((voidp) mf->mf_auto);
+ if (mf->mf_mopts) free((voidp) mf->mf_mopts);
+ if (mf->mf_remopts) free((voidp) mf->mf_remopts);
+ if (mf->mf_info) free((voidp) mf->mf_info);
+ if (mf->mf_private && mf->mf_prfree)
+ (*mf->mf_prfree)(mf->mf_private);
+ /*
+ * Clean up any directories that were made
+ */
+ if (rmd && (mf->mf_flags & MFF_MKMNT))
+ rmdirs(mf->mf_mount);
+
+ /*
+ * Clean up the file server
+ */
+ if (mf->mf_server)
+ free_srvr(mf->mf_server);
+
+ /*
+ * Don't do a callback on this mount
+ */
+ if (mf->mf_cid) {
+ untimeout(mf->mf_cid);
+ mf->mf_cid = 0;
+ }
+}
+
+static void discard_mntfs(mf)
+mntfs *mf;
+{
+ rem_que(&mf->mf_q);
+ /*
+ * Free memory
+ */
+ uninit_mntfs(mf, TRUE);
+ free((voidp) mf);
+
+ --mntfs_allocated;
+}
+
+void flush_mntfs()
+{
+ mntfs *mf;
+
+ mf = FIRST(mntfs, &mfhead);
+ while (mf != HEAD(mntfs, &mfhead)) {
+ mntfs *mf2 = mf;
+ mf = NEXT(mntfs, mf);
+ if (mf2->mf_refc == 0 && mf2->mf_cid)
+ discard_mntfs(mf2);
+ }
+}
+
+void free_mntfs(mf)
+mntfs *mf;
+{
+ if (--mf->mf_refc == 0) {
+ if (mf->mf_flags & MFF_MOUNTED) {
+ int quoted;
+ mf->mf_flags &= ~MFF_MOUNTED;
+
+ /*
+ * Record for posterity
+ */
+ quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */
+ plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s",
+ quoted ? "\"" : "",
+ mf->mf_info,
+ quoted ? "\"" : "",
+ mf->mf_error ? "discard" : "unmount",
+ mf->mf_ops->fs_type, mf->mf_mount);
+ }
+
+ if (mf->mf_ops->fs_flags & FS_DISCARD) {
+#ifdef DEBUG
+ dlog("Immediately discarding mntfs for %s", mf->mf_mount);
+#endif /* DEBUG */
+ discard_mntfs(mf);
+ } else {
+#ifdef DEBUG
+ if (mf->mf_flags & MFF_RESTART) {
+ dlog("Discarding remount hook for %s", mf->mf_mount);
+ } else {
+ dlog("Discarding last mntfs reference to %s fstype %s",
+ mf->mf_mount, mf->mf_ops->fs_type);
+ }
+ if (mf->mf_flags & (MFF_MOUNTED|MFF_MOUNTING|MFF_UNMOUNTING))
+ dlog("mntfs reference for %s still active", mf->mf_mount);
+#endif /* DEBUG */
+ mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf);
+ }
+ }
+}
+
+mntfs *realloc_mntfs P((mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+mntfs *realloc_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts)
+mntfs *mf;
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mntfs *mf2;
+ if (mf->mf_refc == 1 && mf->mf_ops == &ifs_ops && STREQ(mf->mf_mount, mp)) {
+ /*
+ * If we are inheriting then just return
+ * the same node...
+ */
+ return mf;
+ }
+
+ /*
+ * Re-use the existing mntfs if it is mounted.
+ * This traps a race in nfsx.
+ */
+ if (mf->mf_ops != &efs_ops &&
+ (mf->mf_flags & MFF_MOUNTED) &&
+ !FSRV_ISDOWN(mf->mf_server)) {
+ mf->mf_fo = mo;
+ return mf;
+ }
+
+ mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
+ free_mntfs(mf);
+ return mf2;
+}
diff --git a/usr.sbin/amd/amd/mount_fs.c b/usr.sbin/amd/amd/mount_fs.c
new file mode 100644
index 000000000000..43a06251ddc4
--- /dev/null
+++ b/usr.sbin/amd/amd/mount_fs.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)mount_fs.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mount_fs.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $
+ *
+ */
+
+#include "am.h"
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#include <sys/mount.h>
+
+#include <sys/stat.h>
+
+/*
+ * Standard mount flags
+ */
+#ifdef hpux
+/*
+ * HP-UX has an annoying feature of printing
+ * error msgs on /dev/console
+ */
+#undef M_NOSUID
+#endif /* hpux */
+
+struct opt_tab mnt_flags[] = {
+ { "ro", M_RDONLY },
+#ifdef M_CACHE
+ { "nocache", M_NOCACHE },
+#endif /* M_CACHE */
+#ifdef M_GRPID
+ { "grpid", M_GRPID },
+#endif /* M_GRPID */
+#ifdef M_MULTI
+ { "multi", M_MULTI },
+#endif /* M_MULTI */
+#ifdef M_NODEV
+ { "nodev", M_NODEV },
+#endif /* M_NODEV */
+#ifdef M_NOEXEC
+ { "noexec", M_NOEXEC },
+#endif /* M_NOEXEC */
+#ifdef M_NOSUB
+ { "nosub", M_NOSUB },
+#endif /* M_NOSUB */
+#ifdef M_NOSUID
+ { "nosuid", M_NOSUID },
+#endif /* M_NOSUID */
+#ifdef M_SYNC
+ { "sync", M_SYNC },
+#endif /* M_SYNC */
+ { 0, 0 }
+};
+
+int compute_mount_flags(mnt)
+struct mntent *mnt;
+{
+ struct opt_tab *opt;
+ int flags;
+#ifdef NFS_4
+ flags = M_NEWTYPE;
+#else
+ flags = 0;
+#endif /* NFS_4 */
+
+ /*
+ * Crack basic mount options
+ */
+ for (opt = mnt_flags; opt->opt; opt++)
+ flags |= hasmntopt(mnt, opt->opt) ? opt->flag : 0;
+
+ return flags;
+}
+
+int mount_fs P((struct mntent *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type));
+int mount_fs(mnt, flags, mnt_data, retry, type)
+struct mntent *mnt;
+int flags;
+caddr_t mnt_data;
+int retry;
+MTYPE_TYPE type;
+{
+ int error = 0;
+#ifdef MNTINFO_DEV
+ struct stat stb;
+ char *xopts = 0;
+#endif /* MNTINFO_DEV */
+
+#ifdef DEBUG
+#ifdef NFS_4
+ dlog("%s fstype %s (%s) flags %#x (%s)",
+ mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
+#else
+ dlog("%s fstype %d (%s) flags %#x (%s)",
+ mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
+#endif /* NFS_4 */
+#endif /* DEBUG */
+
+ /*
+ * Fake some mount table entries for the automounter
+ */
+#ifdef FASCIST_DF_COMMAND
+ /*
+ * Some systems have a df command which blows up when
+ * presented with an unknown mount type.
+ */
+ if (STREQ(mnt->mnt_type, MNTTYPE_AUTO)) {
+ /*
+ * Try it with the normal name
+ */
+ mnt->mnt_type = FASCIST_DF_COMMAND;
+ }
+#endif /* FASCIST_DF_COMMAND */
+
+again:
+ clock_valid = 0;
+ error = MOUNT_TRAP(type, mnt, flags, mnt_data);
+ if (error < 0)
+ plog(XLOG_ERROR, "%s: mount: %m", mnt->mnt_dir);
+ if (error < 0 && --retry > 0) {
+ sleep(1);
+ goto again;
+ }
+ if (error < 0) {
+#ifdef notdef
+ if (automount)
+ going_down(errno);
+#endif
+ return errno;
+ }
+
+#ifdef UPDATE_MTAB
+#ifdef MNTINFO_DEV
+ /*
+ * Add the extra dev= field to the mount table.
+ */
+ if (lstat(mnt->mnt_dir, &stb) == 0) {
+ char *zopts = (char *) xmalloc(strlen(mnt->mnt_opts) + 32);
+ xopts = mnt->mnt_opts;
+ if (sizeof(stb.st_dev) == 2) {
+ /* e.g. SunOS 4.1 */
+ sprintf(zopts, "%s,%s=%s%04lx", xopts, MNTINFO_DEV,
+ MNTINFO_PREF, (u_long) stb.st_dev & 0xffff);
+ } else {
+ /* e.g. System Vr4 */
+ sprintf(zopts, "%s,%s=%s%08lx", xopts, MNTINFO_DEV,
+ MNTINFO_PREF, (u_long) stb.st_dev);
+ }
+ mnt->mnt_opts = zopts;
+ }
+#endif /* MNTINFO_DEV */
+
+#ifdef FIXUP_MNTENT
+ /*
+ * Additional fields in struct mntent
+ * are fixed up here
+ */
+ FIXUP_MNTENT(mnt);
+#endif
+
+ write_mntent(mnt);
+#ifdef MNTINFO_DEV
+ if (xopts) {
+ free(mnt->mnt_opts);
+ mnt->mnt_opts = xopts;
+ }
+#endif /* MNTINFO_DEV */
+#endif /* UPDATE_MTAB */
+
+ return 0;
+}
+
+#ifdef NEED_MNTOPT_PARSER
+/*
+ * Some systems don't provide these to the user,
+ * but amd needs them, so...
+ *
+ * From: Piete Brooks <pb@cl.cam.ac.uk>
+ */
+
+#include <ctype.h>
+
+static char *nextmntopt(p)
+char **p;
+{
+ char *cp = *p;
+ char *rp;
+ /*
+ * Skip past white space
+ */
+ while (*cp && isspace(*cp))
+ cp++;
+ /*
+ * Word starts here
+ */
+ rp = cp;
+ /*
+ * Scan to send of string or separator
+ */
+ while (*cp && *cp != ',')
+ cp++;
+ /*
+ * If separator found the overwrite with nul char.
+ */
+ if (*cp) {
+ *cp = '\0';
+ cp++;
+ }
+ /*
+ * Return value for next call
+ */
+ *p = cp;
+ return rp;
+}
+
+char *hasmntopt(mnt, opt)
+struct mntent *mnt;
+char *opt;
+{
+ char t[MNTMAXSTR];
+ char *f;
+ char *o = t;
+ int l = strlen(opt);
+ strcpy(t, mnt->mnt_opts);
+
+ while (*(f = nextmntopt(&o)))
+ if (strncmp(opt, f, l) == 0)
+ return f - t + mnt->mnt_opts;
+
+ return 0;
+}
+#endif /* NEED_MNTOPT_PARSER */
+
+#ifdef MOUNT_HELPER_SOURCE
+#include MOUNT_HELPER_SOURCE
+#endif /* MOUNT_HELPER_SOURCE */
diff --git a/usr.sbin/amd/amd/mtab.c b/usr.sbin/amd/amd/mtab.c
new file mode 100644
index 000000000000..43b3a26e9a7f
--- /dev/null
+++ b/usr.sbin/amd/amd/mtab.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)mtab.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab.c,v 5.2.2.1 1992/02/09 15:08:45 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+/*
+ * Firewall /etc/mtab entries
+ */
+void mnt_free P((struct mntent *mp));
+void mnt_free(mp)
+struct mntent *mp;
+{
+ free(mp->mnt_fsname);
+ free(mp->mnt_dir);
+ free(mp->mnt_type);
+ free(mp->mnt_opts);
+ free((voidp) mp);
+}
+
+/*
+ * Discard memory allocated for mount list
+ */
+void discard_mntlist P((mntlist *mp));
+void discard_mntlist(mp)
+mntlist *mp;
+{
+ mntlist *mp2;
+
+ while (mp2 = mp) {
+ mp = mp->mnext;
+ if (mp2->mnt)
+ mnt_free(mp2->mnt);
+ free((voidp) mp2);
+ }
+}
+
+/*
+ * Throw away a mount list
+ */
+void free_mntlist P((mntlist *mp));
+void free_mntlist(mp)
+mntlist *mp;
+{
+ discard_mntlist(mp);
+ unlock_mntlist();
+}
+
+/*
+ * Utility routine which determines the value of a
+ * numeric option in the mount options (such as port=%d).
+ * Returns 0 if the option is not specified.
+ */
+int hasmntval P((struct mntent *mnt, char *opt));
+int hasmntval(mnt, opt)
+struct mntent *mnt;
+char *opt;
+{
+ char *str = hasmntopt(mnt, opt);
+ if (str) {
+ char *eq = strchr(str, '=');
+ if (eq)
+ return atoi(eq+1);
+ else
+ plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
+ }
+
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/nfs_ops.c b/usr.sbin/amd/amd/nfs_ops.c
new file mode 100644
index 000000000000..bcfd7a598fe1
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_ops.c
@@ -0,0 +1,809 @@
+/*-
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * $Id: nfs_ops.c,v 5.2.2.2 1992/05/31 16:35:05 jsp Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)nfs_ops.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "am.h"
+#include <sys/stat.h>
+
+#ifdef HAS_NFS
+
+#define NFS
+#define NFSCLIENT
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#ifdef NFS_HDR
+#include NFS_HDR
+#endif /* NFS_HDR */
+#include <sys/mount.h>
+#include "mount.h"
+
+/*
+ * Network file system
+ */
+
+/*
+ * Convert from nfsstat to UN*X error code
+ */
+#define unx_error(e) ((int)(e))
+
+/*
+ * The NFS layer maintains a cache of file handles.
+ * This is *fundamental* to the implementation and
+ * also allows quick remounting when a filesystem
+ * is accessed soon after timing out.
+ *
+ * The NFS server layer knows to flush this cache
+ * when a server goes down so avoiding stale handles.
+ *
+ * Each cache entry keeps a hard reference to
+ * the corresponding server. This ensures that
+ * the server keepalive information is maintained.
+ *
+ * The copy of the sockaddr_in here is taken so
+ * that the port can be twiddled to talk to mountd
+ * instead of portmap or the NFS server as used
+ * elsewhere.
+ * The port# is flushed if a server goes down.
+ * The IP address is never flushed - we assume
+ * that the address of a mounted machine never
+ * changes. If it does, then you have other
+ * problems...
+ */
+typedef struct fh_cache fh_cache;
+struct fh_cache {
+ qelem fh_q; /* List header */
+ voidp fh_wchan; /* Wait channel */
+ int fh_error; /* Valid data? */
+ int fh_id; /* Unique id */
+ int fh_cid; /* Callout id */
+ struct fhstatus fh_handle; /* Handle on filesystem */
+ struct sockaddr_in fh_sin; /* Address of mountd */
+ fserver *fh_fs; /* Server holding filesystem */
+ char *fh_path; /* Filesystem on host */
+};
+
+/*
+ * FH_TTL is the time a file handle will remain in the cache since
+ * last being used. If the file handle becomes invalid, then it
+ * will be flushed anyway.
+ */
+#define FH_TTL (5 * 60) /* five minutes */
+#define FH_TTL_ERROR (30) /* 30 seconds */
+
+static int fh_id = 0;
+#define FHID_ALLOC() (++fh_id)
+extern qelem fh_head;
+qelem fh_head = { &fh_head, &fh_head };
+
+static int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp));
+
+AUTH *nfs_auth;
+
+static fh_cache *find_nfs_fhandle_cache P((voidp idv, int done));
+static fh_cache *find_nfs_fhandle_cache(idv, done)
+voidp idv;
+int done;
+{
+ fh_cache *fp, *fp2 = 0;
+ int id = (int) idv;
+
+ ITER(fp, fh_cache, &fh_head) {
+ if (fp->fh_id == id) {
+ fp2 = fp;
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (fp2) {
+ dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path);
+ } else {
+ dlog("fh cache search failed");
+ }
+#endif /* DEBUG */
+
+ if (fp2 && !done) {
+ fp2->fh_error = ETIMEDOUT;
+ return 0;
+ }
+
+ return fp2;
+}
+
+/*
+ * Called when a filehandle appears
+ */
+static void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa,
+ struct sockaddr_in *ia, voidp idv, int done));
+static void got_nfs_fh(pkt, len, sa, ia, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sa, *ia;
+voidp idv;
+int done;
+{
+ fh_cache *fp = find_nfs_fhandle_cache(idv, done);
+ if (fp) {
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus);
+ if (!fp->fh_error) {
+#ifdef DEBUG
+ dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+#endif /* DEBUG */
+ /*
+ * Wakeup anything sleeping on this filehandle
+ */
+ if (fp->fh_wchan) {
+#ifdef DEBUG
+ dlog("Calling wakeup on %#x", fp->fh_wchan);
+#endif /* DEBUG */
+ wakeup(fp->fh_wchan);
+ }
+ }
+ }
+}
+
+void flush_nfs_fhandle_cache P((fserver *fs));
+void flush_nfs_fhandle_cache(fs)
+fserver *fs;
+{
+ fh_cache *fp;
+ ITER(fp, fh_cache, &fh_head) {
+ if (fp->fh_fs == fs || fs == 0) {
+ fp->fh_sin.sin_port = (u_short) 0;
+ fp->fh_error = -1;
+ }
+ }
+}
+
+static void discard_fh P((fh_cache *fp));
+static void discard_fh(fp)
+fh_cache *fp;
+{
+ rem_que(&fp->fh_q);
+#ifdef DEBUG
+ dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+#endif /* DEBUG */
+ free_srvr(fp->fh_fs);
+ free((voidp) fp->fh_path);
+ free((voidp) fp);
+}
+
+/*
+ * Determine the file handle for a node
+ */
+static int prime_nfs_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan));
+static int prime_nfs_fhandle_cache(path, fs, fhbuf, wchan)
+char *path;
+fserver *fs;
+struct fhstatus *fhbuf;
+voidp wchan;
+{
+ fh_cache *fp, *fp_save = 0;
+ int error;
+ int reuse_id = FALSE;
+
+#ifdef DEBUG
+ dlog("Searching cache for %s:%s", fs->fs_host, path);
+#endif /* DEBUG */
+
+ /*
+ * First search the cache
+ */
+ ITER(fp, fh_cache, &fh_head) {
+ if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) {
+ switch (fp->fh_error) {
+ case 0:
+ error = fp->fh_error = unx_error(fp->fh_handle.fhs_status);
+ if (error == 0) {
+ if (fhbuf)
+ bcopy((voidp) &fp->fh_handle, (voidp) fhbuf,
+ sizeof(fp->fh_handle));
+ if (fp->fh_cid)
+ untimeout(fp->fh_cid);
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+ } else if (error == EACCES) {
+ /*
+ * Now decode the file handle return code.
+ */
+ plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
+ fs->fs_host, path);
+ } else {
+ errno = error; /* XXX */
+ plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
+ fs->fs_host, path);
+ }
+
+ /*
+ * The error was returned from the remote mount daemon.
+ * Policy: this error will be cached for now...
+ */
+ return error;
+
+ case -1:
+ /*
+ * Still thinking about it, but we can re-use.
+ */
+ fp_save = fp;
+ reuse_id = TRUE;
+ break;
+
+ default:
+ /*
+ * Return the error.
+ * Policy: make sure we recompute if required again
+ * in case this was caused by a network failure.
+ * This can thrash mountd's though... If you find
+ * your mountd going slowly then:
+ * 1. Add a fork() loop to main.
+ * 2. Remove the call to innetgr() and don't use
+ * netgroups, especially if you don't use YP.
+ */
+ error = fp->fh_error;
+ fp->fh_error = -1;
+ return error;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Not in cache
+ */
+ if (fp_save) {
+ fp = fp_save;
+ /*
+ * Re-use existing slot
+ */
+ untimeout(fp->fh_cid);
+ free_srvr(fp->fh_fs);
+ free(fp->fh_path);
+ } else {
+ fp = ALLOC(fh_cache);
+ bzero((voidp) fp, sizeof(*fp));
+ ins_que(&fp->fh_q, &fh_head);
+ }
+ if (!reuse_id)
+ fp->fh_id = FHID_ALLOC();
+ fp->fh_wchan = wchan;
+ fp->fh_error = -1;
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+
+ /*
+ * If the address has changed then don't try to re-use the
+ * port information
+ */
+ if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
+ fp->fh_sin = *fs->fs_ip;
+ fp->fh_sin.sin_port = 0;
+ }
+ fp->fh_fs = dup_srvr(fs);
+ fp->fh_path = strdup(path);
+
+ error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
+ if (error) {
+ /*
+ * Local error - cache for a short period
+ * just to prevent thrashing.
+ */
+ untimeout(fp->fh_cid);
+ fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
+ discard_fh, (voidp) fp);
+ fp->fh_error = error;
+ } else {
+ error = fp->fh_error;
+ }
+ return error;
+}
+
+int make_nfs_auth P((void))
+{
+#ifdef HAS_NFS_QUALIFIED_NAMES
+ /*
+ * From: Chris Metcalf <metcalf@masala.lcs.mit.edu>
+ * Use hostd, not just hostname. Note that uids
+ * and gids and the gidlist are type *int* and not the
+ * system uid_t and gid_t types.
+ */
+ static int group_wheel = 0;
+ nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel);
+#else
+ nfs_auth = authunix_create_default();
+#endif
+ if (!nfs_auth)
+ return ENOBUFS;
+ return 0;
+}
+
+static int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan));
+static int call_mountd(fp, proc, f, wchan)
+fh_cache *fp;
+u_long proc;
+fwd_fun f;
+voidp wchan;
+{
+ struct rpc_msg mnt_msg;
+ int len;
+ char iobuf[8192];
+ int error;
+
+ if (!nfs_auth) {
+ error = make_nfs_auth();
+ if (error)
+ return error;
+ }
+
+ if (fp->fh_sin.sin_port == 0) {
+ u_short port;
+ error = nfs_srvr_port(fp->fh_fs, &port, wchan);
+ if (error)
+ return error;
+ fp->fh_sin.sin_port = port;
+ }
+
+ rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0);
+ len = make_rpc_packet(iobuf, sizeof(iobuf), proc,
+ &mnt_msg, (voidp) &fp->fh_path, xdr_nfspath, nfs_auth);
+
+ if (len > 0) {
+ error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
+ (voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f);
+ } else {
+ error = -len;
+ }
+/*
+ * It may be the case that we're sending to the wrong MOUNTD port. This
+ * occurs if mountd is restarted on the server after the port has been
+ * looked up and stored in the filehandle cache somewhere. The correct
+ * solution, if we're going to cache port numbers is to catch the ICMP
+ * port unreachable reply from the server and cause the portmap request
+ * to be redone. The quick solution here is to invalidate the MOUNTD
+ * port.
+ */
+ fp->fh_sin.sin_port = 0;
+
+ return error;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * NFS needs the local filesystem, remote filesystem
+ * remote hostname.
+ * Local filesystem defaults to remote and vice-versa.
+ */
+static char *nfs_match(fo)
+am_opts *fo;
+{
+ char *xmtab;
+ if (fo->opt_fs && !fo->opt_rfs)
+ fo->opt_rfs = fo->opt_fs;
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "nfs: no remote filesystem specified");
+ return FALSE;
+ }
+ if (!fo->opt_rhost) {
+ plog(XLOG_USER, "nfs: no remote host specified");
+ return FALSE;
+ }
+ /*
+ * Determine magic cookie to put in mtab
+ */
+ xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
+ sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
+#ifdef DEBUG
+ dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
+ fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
+#endif /* DEBUG */
+
+ return xmtab;
+}
+
+/*
+ * Initialise am structure for nfs
+ */
+static int nfs_init(mf)
+mntfs *mf;
+{
+ if (!mf->mf_private) {
+ int error;
+ struct fhstatus fhs;
+
+ char *colon = strchr(mf->mf_info, ':');
+ if (colon == 0)
+ return ENOENT;
+
+ error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) mf);
+ if (!error) {
+ mf->mf_private = (voidp) ALLOC(fhstatus);
+ mf->mf_prfree = (void (*)()) free;
+ bcopy((voidp) &fhs, mf->mf_private, sizeof(fhs));
+ }
+ return error;
+ }
+
+ return 0;
+}
+
+int mount_nfs_fh P((struct fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
+int mount_nfs_fh(fhp, dir, fs_name, opts, mf)
+struct fhstatus *fhp;
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+ struct nfs_args nfs_args;
+ struct mntent mnt;
+ int retry;
+ char *colon;
+ /*char *path;*/
+ char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
+ fserver *fs = mf->mf_server;
+ int flags;
+ char *xopts;
+ int error;
+#ifdef notdef
+ unsigned short port;
+#endif /* notdef */
+
+ MTYPE_TYPE type = MOUNT_TYPE_NFS;
+
+ bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */
+
+ /*
+ * Extract host name to give to kernel
+ */
+ if (!(colon = strchr(fs_name, ':')))
+ return ENOENT;
+#ifndef NFS_ARGS_NEEDS_PATH
+ *colon = '\0';
+#endif
+ strncpy(host, fs_name, sizeof(host));
+#ifndef NFS_ARGS_NEEDS_PATH
+ *colon = ':';
+#endif /* NFS_ARGS_NEEDS_PATH */
+ /*path = colon + 1;*/
+
+ if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr))
+ xopts = strdup(mf->mf_remopts);
+ else
+ xopts = strdup(opts);
+
+ bzero((voidp) &nfs_args, sizeof(nfs_args));
+
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = fs_name;
+ mnt.mnt_type = MTAB_TYPE_NFS;
+ mnt.mnt_opts = xopts;
+ mnt.mnt_freq = 0;
+ mnt.mnt_passno = 0;
+
+ retry = hasmntval(&mnt, "retry");
+ if (retry <= 0)
+ retry = 1; /* XXX */
+
+/*again:*/
+
+ /*
+ * set mount args
+ */
+ NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp->fhstatus_u.fhs_fhandle);
+
+#ifdef ULTRIX_HACK
+ nfs_args.optstr = mnt.mnt_opts;
+#endif /* ULTRIX_HACK */
+
+ nfs_args.hostname = host;
+ nfs_args.flags |= NFSMNT_HOSTNAME;
+#ifdef HOSTNAMESZ
+ /*
+ * Most kernels have a name length restriction.
+ */
+ if (strlen(host) >= HOSTNAMESZ)
+ strcpy(host + HOSTNAMESZ - 3, "..");
+#endif /* HOSTNAMESZ */
+
+ if (nfs_args.rsize = hasmntval(&mnt, "rsize"))
+ nfs_args.flags |= NFSMNT_RSIZE;
+
+ if (nfs_args.wsize = hasmntval(&mnt, "wsize"))
+ nfs_args.flags |= NFSMNT_WSIZE;
+
+ if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
+ nfs_args.flags |= NFSMNT_TIMEO;
+
+ if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
+ nfs_args.flags |= NFSMNT_RETRANS;
+
+#ifdef NFSMNT_BIODS
+ if (nfs_args.biods = hasmntval(&mnt, "biods"))
+ nfs_args.flags |= NFSMNT_BIODS;
+
+#endif /* NFSMNT_BIODS */
+
+#ifdef NFSMNT_MAXGRPS
+ if (nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups"))
+ nfs_args.flags |= NFSMNT_MAXGRPS;
+#endif /* NFSMNT_MAXGRPS */
+
+#ifdef notdef
+/*
+ * This isn't supported by the ping algorithm yet.
+ * In any case, it is all done in nfs_init().
+ */
+ if (port = hasmntval(&mnt, "port"))
+ sin.sin_port = htons(port);
+ else
+ sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */
+#endif /* notdef */
+
+ if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
+ nfs_args.flags |= NFSMNT_SOFT;
+
+#ifdef NFSMNT_SPONGY
+ if (hasmntopt(&mnt, "spongy") != NULL) {
+ nfs_args.flags |= NFSMNT_SPONGY;
+ if (nfs_args.flags & NFSMNT_SOFT) {
+ plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored");
+ nfs_args.flags &= ~NFSMNT_SOFT;
+ }
+ }
+#endif /* MNTOPT_SPONGY */
+
+#ifdef MNTOPT_INTR
+ if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
+ nfs_args.flags |= NFSMNT_INT;
+#endif /* MNTOPT_INTR */
+
+#ifdef MNTOPT_NODEVS
+ if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL)
+ nfs_args.flags |= NFSMNT_NODEVS;
+#endif /* MNTOPT_NODEVS */
+
+#ifdef MNTOPT_COMPRESS
+ if (hasmntopt(&mnt, "compress") != NULL)
+ nfs_args.flags |= NFSMNT_COMPRESS;
+#endif /* MNTOPT_COMPRESS */
+
+#ifdef MNTOPT_NOCONN
+ if (hasmntopt(&mnt, "noconn") != NULL)
+ nfs_args.flags |= NFSMNT_NOCONN;
+#endif /* MNTOPT_NOCONN */
+
+#ifdef NFSMNT_PGTHRESH
+ if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))
+ nfs_args.flags |= NFSMNT_PGTHRESH;
+#endif /* NFSMNT_PGTHRESH */
+
+ NFS_SA_DREF(nfs_args, fs->fs_ip);
+
+ flags = compute_mount_flags(&mnt);
+
+#ifdef NFSMNT_NOCTO
+ if (hasmntopt(&mnt, "nocto") != NULL)
+ nfs_args.flags |= NFSMNT_NOCTO;
+#endif /* NFSMNT_NOCTO */
+
+#ifdef HAS_TCP_NFS
+ if (hasmntopt(&mnt, "tcp") != NULL)
+ nfs_args.sotype = SOCK_STREAM;
+#endif /* HAS_TCP_NFS */
+
+
+#ifdef ULTRIX_HACK
+ /*
+ * Ultrix passes the flags argument as part of the
+ * mount data structure, rather than using the
+ * flags argument to the system call. This is
+ * confusing...
+ */
+ if (!(nfs_args.flags & NFSMNT_PGTHRESH)) {
+ nfs_args.pg_thresh = 64; /* 64k - XXX */
+ nfs_args.flags |= NFSMNT_PGTHRESH;
+ }
+ nfs_args.gfs_flags = flags;
+ flags &= M_RDONLY;
+ if (flags & M_RDONLY)
+ nfs_args.flags |= NFSMNT_RONLY;
+#endif /* ULTRIX_HACK */
+
+ error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
+ free(xopts);
+ return error;
+}
+
+static int mount_nfs(dir, fs_name, opts, mf)
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+#ifdef notdef
+ int error;
+ struct fhstatus fhs;
+ char *colon;
+
+ if (!(colon = strchr(fs_name, ':')))
+ return ENOENT;
+
+#ifdef DEBUG
+ dlog("locating fhandle for %s", fs_name);
+#endif /* DEBUG */
+ error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) 0);
+
+ if (error)
+ return error;
+
+ return mount_nfs_fh(&fhs, dir, fs_name, opts, mf);
+#endif
+ if (!mf->mf_private) {
+ plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
+ return EINVAL;
+ }
+
+ return mount_nfs_fh((struct fhstatus *) mf->mf_private, dir, fs_name, opts, mf);
+}
+
+static int nfs_fmount(mf)
+mntfs *mf;
+{
+ int error;
+
+ error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
+
+#ifdef DEBUG
+ if (error) {
+ errno = error;
+ dlog("mount_nfs: %m");
+ }
+#endif /* DEBUG */
+ return error;
+}
+
+static int nfs_fumount(mf)
+mntfs *mf;
+{
+ int error = UMOUNT_FS(mf->mf_mount);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void nfs_umounted(mp)
+am_node *mp;
+{
+#ifdef INFORM_MOUNTD
+ /*
+ * Don't bother to inform remote mountd
+ * that we are finished. Until a full
+ * track of filehandles is maintained
+ * the mountd unmount callback cannot
+ * be done correctly anyway...
+ */
+
+ mntfs *mf = mp->am_mnt;
+ fserver *fs;
+ char *colon, *path;
+
+ if (mf->mf_error || mf->mf_refc > 1)
+ return;
+
+ fs = mf->mf_server;
+
+ /*
+ * Call the mount daemon on the server to
+ * announce that we are not using the fs any more.
+ *
+ * This is *wrong*. The mountd should be called
+ * when the fhandle is flushed from the cache, and
+ * a reference held to the cached entry while the
+ * fs is mounted...
+ */
+ colon = path = strchr(mf->mf_info, ':');
+ if (fs && colon) {
+ fh_cache f;
+#ifdef DEBUG
+ dlog("calling mountd for %s", mf->mf_info);
+#endif /* DEBUG */
+ *path++ = '\0';
+ f.fh_path = path;
+ f.fh_sin = *fs->fs_ip;
+ f.fh_sin.sin_port = (u_short) 0;
+ f.fh_fs = fs;
+ f.fh_id = 0;
+ f.fh_error = 0;
+ (void) prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf);
+ (void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
+ *colon = ':';
+ }
+#endif /* INFORM_MOUNTD */
+
+#ifdef KICK_KERNEL
+ /* This should go into the mainline code, not in nfs_ops... */
+
+ /*
+ * Run lstat over the underlying directory in
+ * case this was a direct mount. This will
+ * get the kernel back in sync with reality.
+ */
+ if (mp->am_parent && mp->am_parent->am_path &&
+ STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")) {
+ struct stat stb;
+ int pid;
+ if ((pid = background()) == 0) {
+ if (lstat(mp->am_parent->am_path, &stb) < 0) {
+ plog(XLOG_ERROR, "lstat(%s) after unmount: %m", mp->am_parent->am_path);
+#ifdef DEBUG
+ } else {
+ dlog("hack lstat(%s): ok", mp->am_parent->am_path);
+#endif /* DEBUG */
+ }
+ _exit(0);
+ }
+ }
+#endif /* KICK_KERNEL */
+}
+
+/*
+ * Network file system
+ */
+am_ops nfs_ops = {
+ "nfs",
+ nfs_match,
+ nfs_init,
+ auto_fmount,
+ nfs_fmount,
+ auto_fumount,
+ nfs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* nfs_readlink */
+ 0, /* nfs_mounted */
+ nfs_umounted,
+ find_nfs_srvr,
+ FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_NFS */
diff --git a/usr.sbin/amd/amd/nfs_start.c b/usr.sbin/amd/amd/nfs_start.c
new file mode 100644
index 000000000000..13d36a14ee8b
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_start.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)nfs_start.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_start.c,v 5.2.2.1 1992/02/09 15:08:51 jsp beta $
+ *
+ */
+
+#include "am.h"
+#include "amq.h"
+#include <sys/signal.h>
+#include <setjmp.h>
+extern jmp_buf select_intr;
+extern int select_intr_valid;
+
+#ifdef HAS_TFS
+/*
+ * Use replacement for RPC/UDP transport
+ * so that we do NFS gatewaying.
+ */
+#define svcudp_create svcudp2_create
+extern SVCXPRT *svcudp2_create P((int));
+#endif /* HAS_TFS */
+
+extern void nfs_program_2();
+extern void amq_program_1();
+
+unsigned short nfs_port;
+SVCXPRT *nfsxprt;
+
+extern int fwd_sock;
+int max_fds = -1;
+
+#define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
+
+#ifdef DEBUG
+/*
+ * Check that we are not burning resources
+ */
+static void checkup(P_void)
+{
+
+static int max_fd = 0;
+static char *max_mem = 0;
+
+ int next_fd = dup(0);
+ extern caddr_t sbrk P((int));
+ caddr_t next_mem = sbrk(0);
+ close(next_fd);
+
+ /*if (max_fd < 0) {
+ max_fd = next_fd;
+ } else*/ if (max_fd < next_fd) {
+ dlog("%d new fds allocated; total is %d",
+ next_fd - max_fd, next_fd);
+ max_fd = next_fd;
+ }
+
+ /*if (max_mem == 0) {
+ max_mem = next_mem;
+ } else*/ if (max_mem < next_mem) {
+ dlog("%#x bytes of memory allocated; total is %#x (%d pages)",
+ next_mem - max_mem,
+ next_mem,
+ ((int)next_mem+getpagesize()-1)/getpagesize());
+ max_mem = next_mem;
+ }
+}
+#endif /* DEBUG */
+
+static int do_select(smask, fds, fdp, tvp)
+int smask;
+int fds;
+int *fdp;
+struct timeval *tvp;
+{
+ int sig;
+ int nsel;
+ if (sig = setjmp(select_intr)) {
+ select_intr_valid = 0;
+ /* Got a signal */
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ amd_state = Finishing;
+ reschedule_timeout_mp();
+ break;
+ }
+ nsel = -1;
+ errno = EINTR;
+ } else {
+ select_intr_valid = 1;
+ /*
+ * Invalidate the current clock value
+ */
+ clock_valid = 0;
+ /*
+ * Allow interrupts. If a signal
+ * occurs, then it will cause a longjmp
+ * up above.
+ */
+ (void) sigsetmask(smask);
+ /*
+ * Wait for input
+ */
+ nsel = select(fds, fdp, (int *) 0, (int *) 0,
+ tvp->tv_sec ? tvp : (struct timeval *) 0);
+
+ }
+
+ (void) sigblock(MASKED_SIGS);
+
+ /*
+ * Perhaps reload the cache?
+ */
+ if (do_mapc_reload < clocktime()) {
+ mapc_reload();
+ do_mapc_reload = clocktime() + ONE_HOUR;
+ }
+ return nsel;
+}
+
+/*
+ * Determine whether anything is left in
+ * the RPC input queue.
+ */
+static int rpc_pending_now()
+{
+ struct timeval tvv;
+ int nsel;
+#ifdef FD_SET
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ FD_SET(fwd_sock, &readfds);
+#else
+ int readfds = (1 << fwd_sock);
+#endif /* FD_SET */
+
+ tvv.tv_sec = tvv.tv_usec = 0;
+ nsel = select(max_fds+1, &readfds, (int *) 0, (int *) 0, &tvv);
+ if (nsel < 1)
+ return(0);
+#ifdef FD_SET
+ if (FD_ISSET(fwd_sock, &readfds))
+ return(1);
+#else
+ if (readfds & (1 << fwd_sock))
+ return(1);
+#endif
+ return(0);
+}
+
+static serv_state run_rpc(P_void)
+{
+ int dtbsz = max_fds + 1;
+ int smask = sigblock(MASKED_SIGS);
+
+ next_softclock = clocktime();
+
+ amd_state = Run;
+
+ /*
+ * Keep on trucking while we are in Run mode. This state
+ * is switched to Quit after all the file systems have
+ * been unmounted.
+ */
+ while ((int)amd_state <= (int)Finishing) {
+ struct timeval tvv;
+ int nsel;
+ time_t now;
+#ifdef RPC_4
+ fd_set readfds;
+ readfds = svc_fdset;
+ FD_SET(fwd_sock, &readfds);
+#else
+#ifdef FD_SET
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ readfds.fds_bits[0] = svc_fds;
+ FD_SET(fwd_sock, &readfds);
+#else
+ int readfds = svc_fds | (1 << fwd_sock);
+#endif /* FD_SET */
+#endif /* RPC_4 */
+
+#ifdef DEBUG
+ checkup();
+#endif /* DEBUG */
+
+ /*
+ * If the full timeout code is not called,
+ * then recompute the time delta manually.
+ */
+ now = clocktime();
+
+ if (next_softclock <= now) {
+ if (amd_state == Finishing)
+ umount_exported();
+ tvv.tv_sec = softclock();
+ } else {
+ tvv.tv_sec = next_softclock - now;
+ }
+ tvv.tv_usec = 0;
+
+ if (amd_state == Finishing && last_used_map < 0) {
+ flush_mntfs();
+ amd_state = Quit;
+ break;
+ }
+
+#ifdef DEBUG
+ if (tvv.tv_sec)
+ dlog("Select waits for %ds", tvv.tv_sec);
+ else
+ dlog("Select waits for Godot");
+#endif /* DEBUG */
+
+ nsel = do_select(smask, dtbsz, &readfds, &tvv);
+
+
+ switch (nsel) {
+ case -1:
+ if (errno == EINTR) {
+#ifdef DEBUG
+ dlog("select interrupted");
+#endif /* DEBUG */
+ continue;
+ }
+ perror("select");
+ break;
+
+ case 0:
+#ifdef DEBUG
+ /*dlog("select returned 0");*/
+#endif /* DEBUG */
+ break;
+
+ default:
+ /* Read all pending NFS responses at once to avoid
+ having responses queue up as a consequence of
+ retransmissions. */
+#ifdef FD_SET
+ if (FD_ISSET(fwd_sock, &readfds)) {
+ FD_CLR(fwd_sock, &readfds);
+#else
+ if (readfds & (1 << fwd_sock)) {
+ readfds &= ~(1 << fwd_sock);
+#endif
+ --nsel;
+ do {
+ fwd_reply();
+ } while (rpc_pending_now() > 0);
+ }
+
+ if (nsel) {
+ /*
+ * Anything left must be a normal
+ * RPC request.
+ */
+#ifdef RPC_4
+ svc_getreqset(&readfds);
+#else
+#ifdef FD_SET
+ svc_getreq(readfds.fds_bits[0]);
+#else
+ svc_getreq(readfds);
+#endif /* FD_SET */
+#endif /* RPC_4 */
+ }
+ break;
+ }
+ }
+
+ (void) sigsetmask(smask);
+
+ if (amd_state == Quit)
+ amd_state = Done;
+
+ return amd_state;
+}
+
+static int bindnfs_port(so)
+int so;
+{
+ unsigned short port;
+ int error = bind_resv_port(so, &port);
+ if (error == 0)
+ nfs_port = port;
+ return error;
+}
+
+void unregister_amq(P_void)
+{
+#ifdef DEBUG
+ Debug(D_AMQ)
+#endif /* DEBUG */
+ (void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION);
+}
+
+int mount_automounter(ppid)
+int ppid;
+{
+ int so = socket(AF_INET, SOCK_DGRAM, 0);
+ SVCXPRT *amqp;
+ int nmount;
+
+ if (so < 0 || bindnfs_port(so) < 0) {
+ perror("Can't create privileged nfs port");
+ return 1;
+ }
+
+ if ((nfsxprt = svcudp_create(so)) == NULL ||
+ (amqp = svcudp_create(so)) == NULL) {
+ plog(XLOG_FATAL, "cannot create rpc/udp service");
+ return 2;
+ }
+
+ if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) {
+ plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
+ return 3;
+ }
+
+ /*
+ * Start RPC forwarding
+ */
+ if (fwd_init() != 0)
+ return 3;
+
+ /*
+ * One or other of so, fwd_sock
+ * must be the highest fd on
+ * which to select.
+ */
+ if (so > max_fds)
+ max_fds = so;
+ if (fwd_sock > max_fds)
+ max_fds = fwd_sock;
+
+ /*
+ * Construct the root automount node
+ */
+ make_root_node();
+
+ /*
+ * Pick up the pieces from a previous run
+ * This is likely to (indirectly) need the rpc_fwd package
+ * so it *must* come after the call to fwd_init().
+ */
+ if (restart_existing_mounts)
+ restart();
+
+ /*
+ * Mount the top-level auto-mountpoints
+ */
+ nmount = mount_exported();
+
+ /*
+ * Now safe to tell parent that we are up and running
+ */
+ if (ppid)
+ kill(ppid, SIGQUIT);
+
+ if (nmount == 0) {
+ plog(XLOG_FATAL, "No work to do - quitting");
+ amd_state = Done;
+ return 0;
+ }
+
+#ifdef DEBUG
+ Debug(D_AMQ) {
+#endif /* DEBUG */
+ /*
+ * Register with amq
+ */
+ unregister_amq();
+
+ if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) {
+ plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)");
+ return 3;
+ }
+#ifdef DEBUG
+ }
+#endif /* DEBUG */
+
+ /*
+ * Start timeout_mp rolling
+ */
+ reschedule_timeout_mp();
+
+ /*
+ * Start the server
+ */
+ if (run_rpc() != Done) {
+ plog(XLOG_FATAL, "run_rpc failed");
+ amd_state = Done;
+ }
+
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/nfs_subr.c b/usr.sbin/amd/amd/nfs_subr.c
new file mode 100644
index 000000000000..297cf9330617
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_subr.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)nfs_subr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_subr.c,v 5.2.2.1 1992/02/09 15:08:53 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+/*
+ * Convert from UN*X to NFS error code
+ */
+#ifdef NFS_ERROR_MAPPING
+NFS_ERROR_MAPPING
+#define nfs_error(e) \
+ ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \
+ nfs_errormap[(e) - NFS_LOMAP] : (e)))
+#else
+#define nfs_error(e) ((nfsstat)(e))
+#endif /* NFS_ERROR_MAPPING */
+
+static char *do_readlink P((am_node *mp, int *error_return, struct attrstat **attrpp));
+static char *do_readlink(mp, error_return, attrpp)
+am_node *mp;
+int *error_return;
+struct attrstat **attrpp;
+{
+ char *ln;
+
+ /*
+ * If there is a readlink method, then use
+ * that, otherwise if a link exists use
+ * that, otherwise use the mount point.
+ */
+ if (mp->am_mnt->mf_ops->readlink) {
+ int retry = 0;
+ mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry);
+ if (mp == 0) {
+ *error_return = retry;
+ return 0;
+ }
+ /*reschedule_timeout_mp();*/
+ }
+ if (mp->am_link) {
+ ln = mp->am_link;
+ } else {
+ ln = mp->am_mnt->mf_mount;
+ }
+ if (attrpp)
+ *attrpp = &mp->am_attr;
+ return ln;
+}
+
+/*ARGSUSED*/
+voidp
+nfsproc_null_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp) &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_getattr_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+ static struct attrstat res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "gettattr:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(argp, &retry);
+ if (mp == 0) {
+#ifdef PRECISE_SYMLINKS
+getattr_retry:
+#endif /* PRECISE_SYMLINKS */
+
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ struct attrstat *attrp = &mp->am_attr;
+#ifdef PRECISE_SYMLINKS
+ if (mp->am_fattr.type == NFLNK) {
+ /*
+ * Make sure we can read the link,
+ * and then determine the length.
+ */
+ char *ln = do_readlink(mp, &retry, &attrp);
+ if (ln == 0)
+ goto getattr_retry;
+ }
+#endif /* PRECISE_SYMLINKS */
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size);
+#endif /* DEBUG */
+ mp->am_stats.s_getattr++;
+ return attrp;
+ }
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_setattr_2(argp, rqstp)
+struct sattrargs *argp;
+struct svc_req *rqstp;
+{
+ static struct attrstat res;
+
+ if (!fh_to_mp(&argp->file))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+voidp
+nfsproc_root_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp)&res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_lookup_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+ static struct diropres res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "lookup:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(&argp->dir, &retry);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ int error;
+ am_node *ap;
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name);
+#endif /* DEBUG */
+ ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE);
+ if (ap == 0) {
+ if (error < 0) {
+#ifdef DEBUG
+ dlog("Not sending RPC reply");
+#endif /* DEBUG */
+ amd_stats.d_drops++;
+ return 0;
+ }
+ res.status = nfs_error(error);
+ } else {
+ mp_to_fh(ap, &res.diropres_u.diropres.file);
+ res.diropres_u.diropres.attributes = ap->am_fattr;
+ res.status = NFS_OK;
+ }
+ mp->am_stats.s_lookup++;
+ /*reschedule_timeout_mp();*/
+ }
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct readlinkres *
+nfsproc_readlink_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+ static struct readlinkres res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "readlink:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(argp, &retry);
+ if (mp == 0) {
+readlink_retry:
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ char *ln = do_readlink(mp, &retry, (struct attrstat **) 0);
+ if (ln == 0)
+ goto readlink_retry;
+ res.status = NFS_OK;
+#ifdef DEBUG
+ Debug(D_TRACE)
+ if (ln)
+ plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
+#endif /* DEBUG */
+ res.readlinkres_u.data = ln;
+ mp->am_stats.s_readlink++;
+ }
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct readres *
+nfsproc_read_2(argp, rqstp)
+struct readargs *argp;
+struct svc_req *rqstp;
+{
+ static struct readres res;
+
+ bzero((char *)&res, sizeof(res));
+
+ res.status = nfs_error(EACCES);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+voidp
+nfsproc_writecache_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp) &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_write_2(argp, rqstp)
+writeargs *argp;
+struct svc_req *rqstp;
+{
+ static struct attrstat res;
+
+ if (!fh_to_mp(&argp->file))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_create_2(argp, rqstp)
+createargs *argp;
+struct svc_req *rqstp;
+{
+ static struct diropres res;
+
+ if (!fh_to_mp(&argp->where.dir))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+static nfsstat *
+unlink_or_rmdir(argp, rqstp, unlinkp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+int unlinkp;
+{
+ static nfsstat res;
+ int retry;
+ /*mntfs *mf;*/
+ am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res = nfs_error(retry);
+ goto out;
+ }
+ /*mf = mp->am_mnt;*/
+ if (mp->am_fattr.type != NFDIR) {
+ res = nfs_error(ENOTDIR);
+ goto out;
+ }
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name);
+#endif /* DEBUG */
+ mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE);
+ if (mp == 0) {
+ /*
+ * Ignore retries...
+ */
+ if (retry < 0)
+ retry = 0;
+ /*
+ * Usual NFS workaround...
+ */
+ else if (retry == ENOENT)
+ retry = 0;
+ res = nfs_error(retry);
+ } else {
+ forcibly_timeout_mp(mp);
+ res = NFS_OK;
+ }
+
+out:
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_remove_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+ return unlink_or_rmdir(argp, rqstp, TRUE);
+}
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_rename_2(argp, rqstp)
+renameargs *argp;
+struct svc_req *rqstp;
+{
+ static nfsstat res;
+ if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir))
+ res = nfs_error(ESTALE);
+ /*
+ * If the kernel is doing clever things with referenced files
+ * then let it pretend...
+ */
+ else if (strncmp(argp->to.name, ".nfs", 4) == 0)
+ res = NFS_OK;
+ /*
+ * otherwise a failure
+ */
+ else
+ res = nfs_error(EROFS);
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_link_2(argp, rqstp)
+linkargs *argp;
+struct svc_req *rqstp;
+{
+ static nfsstat res;
+ if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir))
+ res = nfs_error(ESTALE);
+ else
+ res = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_symlink_2(argp, rqstp)
+symlinkargs *argp;
+struct svc_req *rqstp;
+{
+ static nfsstat res;
+ if (!fh_to_mp(&argp->from.dir))
+ res = nfs_error(ESTALE);
+ else
+ res = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_mkdir_2(argp, rqstp)
+createargs *argp;
+struct svc_req *rqstp;
+{
+ static struct diropres res;
+ if (!fh_to_mp(&argp->where.dir))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_rmdir_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+ return unlink_or_rmdir(argp, rqstp, FALSE);
+}
+
+
+/*ARGSUSED*/
+struct readdirres *
+nfsproc_readdir_2(argp, rqstp)
+readdirargs *argp;
+struct svc_req *rqstp;
+{
+ static readdirres res;
+ static entry e_res[MAX_READDIR_ENTRIES];
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "readdir:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(&argp->dir, &retry);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
+#endif /* DEBUG */
+ res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie,
+ &res.readdirres_u.reply, e_res, argp->count));
+ mp->am_stats.s_readdir++;
+ }
+
+ return &res;
+}
+
+/*ARGSUSED*/
+struct statfsres *
+nfsproc_statfs_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+ static statfsres res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "statfs:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(argp, &retry);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ statfsokres *fp;
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
+#endif /* DEBUG */
+ /*
+ * just return faked up file system information
+ */
+
+ fp = &res.statfsres_u.reply;
+
+ fp->tsize = 1024;
+ fp->bsize = 4096;
+#ifdef HAS_EMPTY_AUTOMOUNTS
+ fp->blocks = 0;
+#else
+ fp->blocks = 1;
+#endif
+ fp->bfree = 0;
+ fp->bavail = 0;
+
+ res.status = NFS_OK;
+ mp->am_stats.s_statfs++;
+ }
+
+ return &res;
+}
diff --git a/usr.sbin/amd/amd/nfsx_ops.c b/usr.sbin/amd/amd/nfsx_ops.c
new file mode 100644
index 000000000000..ba18cdcfebe8
--- /dev/null
+++ b/usr.sbin/amd/amd/nfsx_ops.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * @(#)nfsx_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfsx_ops.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_NFSX
+
+/*
+ * NFS hierarchical mounts
+ *
+ * TODO: Re-implement.
+ */
+
+/*
+ * The rfs field contains a list of mounts to be done from
+ * the remote host.
+ */
+typedef struct nfsx_mnt {
+ mntfs *n_mnt;
+ int n_error;
+} nfsx_mnt;
+
+struct nfsx {
+ int nx_c; /* Number of elements in nx_v */
+ nfsx_mnt *nx_v; /* Underlying mounts */
+ nfsx_mnt *nx_try;
+};
+
+static int nfsx_fmount P((mntfs*));
+
+static char *nfsx_match(fo)
+am_opts *fo;
+{
+ char *xmtab;
+ char *ptr;
+ int len;
+
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "nfsx: no remote filesystem specified");
+ return FALSE;
+ }
+ if (!fo->opt_rhost) {
+ plog(XLOG_USER, "nfsx: no remote host specified");
+ return FALSE;
+ }
+
+#ifdef notdef
+ /* fiddle sublink, must be last... */
+ if (fo->opt_sublink) {
+ plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink);
+ free((voidp) fo->opt_sublink);
+ fo->opt_sublink = 0;
+ }
+#endif
+
+ /* set default sublink */
+ if (fo->opt_sublink == 0) {
+ ptr = strchr(fo->opt_rfs, ',');
+ if (ptr && ptr != (fo->opt_rfs + 1))
+ fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1);
+ }
+
+ /*
+ * Remove trailing ",..." from ${fs}
+ * After deslashifying, overwrite the end of ${fs} with "/"
+ * to make sure it is unique.
+ */
+ if (ptr = strchr(fo->opt_fs, ','))
+ *ptr = '\0';
+ deslashify(fo->opt_fs);
+ /*
+ * Bump string length to allow trailing /
+ */
+ len = strlen(fo->opt_fs);
+ fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1);
+ ptr = fo->opt_fs + len;
+ /*
+ * Make unique...
+ */
+ *ptr++ = '/';
+ *ptr = '\0';
+
+ /*
+ * Determine magic cookie to put in mtab
+ */
+ xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs);
+#ifdef DEBUG
+ dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
+ fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
+#endif /* DEBUG */
+
+ return xmtab;
+}
+
+static void nfsx_prfree P((voidp vp));
+static void nfsx_prfree(vp)
+voidp vp;
+{
+ struct nfsx *nx = (struct nfsx *) vp;
+ int i;
+
+ for (i = 0; i < nx->nx_c; i++) {
+ mntfs *m = nx->nx_v[i].n_mnt;
+ if (m)
+ free_mntfs(m);
+ }
+
+ free((voidp) nx->nx_v);
+ free((voidp) nx);
+}
+
+static int nfsx_init(mf)
+mntfs *mf;
+{
+ /*
+ * mf_info has the form:
+ * host:/prefix/path,sub,sub,sub
+ */
+ int i;
+ int glob_error;
+ struct nfsx *nx;
+ int asked_for_wakeup = 0;
+
+ nx = (struct nfsx *) mf->mf_private;
+
+ if (nx == 0) {
+ char **ivec;
+ char *info = 0;
+ char *host;
+ char *pref;
+ int error = 0;
+
+ info = strdup(mf->mf_info);
+ host = strchr(info, ':');
+ if (!host) {
+ error = EINVAL;
+ goto errexit;
+ }
+
+ pref = host+1;
+ host = info;
+
+ /*
+ * Split the prefix off from the suffices
+ */
+ ivec = strsplit(pref, ',', '\'');
+
+ /*
+ * Count array size
+ */
+ for (i = 0; ivec[i]; i++)
+ ;
+
+ nx = ALLOC(nfsx);
+ mf->mf_private = (voidp) nx;
+ mf->mf_prfree = nfsx_prfree;
+
+ nx->nx_c = i - 1; /* i-1 because we don't want the prefix */
+ nx->nx_v = (nfsx_mnt *) xmalloc(nx->nx_c * sizeof(nfsx_mnt));
+ { char *mp = 0;
+ char *xinfo = 0;
+ char *fs = mf->mf_fo->opt_fs;
+ char *rfs = 0;
+ for (i = 0; i < nx->nx_c; i++) {
+ char *path = ivec[i+1];
+ rfs = str3cat(rfs, pref, "/", path);
+ /*
+ * Determine the mount point.
+ * If this is the root, then don't remove
+ * the trailing slash to avoid mntfs name clashes.
+ */
+ mp = str3cat(mp, fs, "/", rfs);
+ normalize_slash(mp);
+ deslashify(mp);
+ /*
+ * Determine the mount info
+ */
+ xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path);
+ normalize_slash(xinfo);
+ if (pref[1] != '\0')
+ deslashify(xinfo);
+#ifdef DEBUG
+ dlog("nfsx: init mount for %s on %s", xinfo, mp);
+#endif
+ nx->nx_v[i].n_error = -1;
+ nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts);
+ }
+ if (rfs) free(rfs);
+ if (mp) free(mp);
+ if (xinfo) free(xinfo);
+ }
+
+ free((voidp) ivec);
+errexit:
+ if (info)
+ free(info);
+ if (error)
+ return error;
+ }
+
+ /*
+ * Iterate through the mntfs's and call
+ * the underlying init routine on each
+ */
+ glob_error = 0;
+ for (i = 0; i < nx->nx_c; i++) {
+ nfsx_mnt *n = &nx->nx_v[i];
+ mntfs *m = n->n_mnt;
+ int error = (*m->mf_ops->fs_init)(m);
+ /*
+ * If HARD_NFSX_ERRORS is defined, make any
+ * initialisation failure a hard error and
+ * fail the entire group. Otherwise only fail
+ * if none of the group is mountable (see nfsx_fmount).
+ */
+#ifdef HARD_NFSX_ERRORS
+ if (error > 0)
+ return error;
+#else
+ if (error > 0)
+ n->n_error = error;
+#endif
+ else if (error < 0) {
+ glob_error = -1;
+ if (!asked_for_wakeup) {
+ asked_for_wakeup = 1;
+ sched_task(wakeup_task, (voidp) mf, (voidp) m);
+ }
+ }
+ }
+
+ return glob_error;
+}
+
+static void nfsx_cont P((int rc, int term, voidp closure));
+static void nfsx_cont(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ mntfs *mf = (mntfs *) closure;
+ struct nfsx *nx = (struct nfsx *) mf->mf_private;
+ nfsx_mnt *n = nx->nx_try;
+
+ n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING);
+ mf->mf_flags &= ~MFF_ERROR;
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) n->n_mnt);
+
+ if (rc || term) {
+ if (term) {
+ /*
+ * Not sure what to do for an error code.
+ */
+ plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term);
+ n->n_error = EIO;
+ } else {
+ /*
+ * Check for exit status
+ */
+ errno = rc; /* XXX */
+ plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount);
+ n->n_error = rc;
+ }
+ free_mntfs(n->n_mnt);
+ n->n_mnt = new_mntfs();
+ n->n_mnt->mf_error = n->n_error;
+ n->n_mnt->mf_flags |= MFF_ERROR;
+ } else {
+ /*
+ * The mount worked.
+ */
+ mf_mounted(n->n_mnt);
+ n->n_error = 0;
+ }
+
+ /*
+ * Do the remaining bits
+ */
+ if (nfsx_fmount(mf) >= 0) {
+ wakeup((voidp) mf);
+ mf->mf_flags &= ~MFF_MOUNTING;
+ mf_mounted(mf);
+ }
+}
+
+static int try_nfsx_mount P((voidp mv));
+static int try_nfsx_mount(mv)
+voidp mv;
+{
+ mntfs *mf = (mntfs *) mv;
+ int error;
+
+ mf->mf_flags |= MFF_MOUNTING;
+ error = (*mf->mf_ops->fmount_fs)(mf);
+ mf->mf_flags &= ~MFF_MOUNTING;
+ return error;
+}
+
+static int nfsx_remount P((mntfs *mf, int fg));
+static int nfsx_remount(mf, fg)
+mntfs *mf;
+int fg;
+{
+ struct nfsx *nx = (struct nfsx *) mf->mf_private;
+ nfsx_mnt *n;
+ int glob_error = -1;
+
+ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
+ mntfs *m = n->n_mnt;
+ if (n->n_error < 0) {
+ if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) {
+ int error = mkdirs(m->mf_mount, 0555);
+ if (!error)
+ m->mf_flags |= MFF_MKMNT;
+ }
+ }
+ }
+
+ /*
+ * Iterate through the mntfs's and mount each filesystem
+ * which is not yet mounted.
+ */
+ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
+ mntfs *m = n->n_mnt;
+ if (n->n_error < 0) {
+ /*
+ * Check fmount entry pt. exists
+ * and then mount...
+ */
+ if (!m->mf_ops->fmount_fs) {
+ n->n_error = EINVAL;
+ } else {
+#ifdef DEBUG
+ dlog("calling underlying fmount on %s", m->mf_mount);
+#endif
+ if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) {
+ m->mf_flags |= MFF_MOUNTING; /* XXX */
+#ifdef DEBUG
+ dlog("backgrounding mount of \"%s\"", m->mf_info);
+#endif
+ nx->nx_try = n;
+ run_task(try_nfsx_mount, (voidp) m, nfsx_cont, (voidp) mf);
+ n->n_error = -1;
+ return -1;
+ } else {
+#ifdef DEBUG
+ dlog("foreground mount of \"%s\" ...", mf->mf_info);
+#endif
+ n->n_error = (*m->mf_ops->fmount_fs)(m);
+ }
+ }
+#ifdef DEBUG
+ if (n->n_error > 0) {
+ errno = n->n_error; /* XXX */
+ dlog("underlying fmount of %s failed: %m", m->mf_mount);
+ }
+#endif
+ if (n->n_error == 0) {
+ glob_error = 0;
+ } else if (glob_error < 0) {
+ glob_error = n->n_error;
+ }
+ }
+ }
+
+ return glob_error < 0 ? 0 : glob_error;
+}
+
+static int nfsx_fmount P((mntfs *mf));
+static int nfsx_fmount(mf)
+mntfs *mf;
+{
+ return nfsx_remount(mf, FALSE);
+}
+
+/*
+ * Unmount an NFS hierarchy.
+ * Note that this is called in the foreground
+ * and so may hang under extremely rare conditions.
+ */
+static int nfsx_fumount(mf)
+mntfs *mf;
+{
+ struct nfsx *nx = (struct nfsx *) mf->mf_private;
+ nfsx_mnt *n;
+ int glob_error = 0;
+
+ /*
+ * Iterate in reverse through the mntfs's and unmount each filesystem
+ * which is mounted.
+ */
+ for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) {
+ mntfs *m = n->n_mnt;
+ /*
+ * If this node has not been messed with
+ * and there has been no error so far
+ * then try and unmount.
+ * If an error had occured then zero
+ * the error code so that the remount
+ * only tries to unmount those nodes
+ * which had been successfully unmounted.
+ */
+ if (n->n_error == 0) {
+#ifdef DEBUG
+ dlog("calling underlying fumount on %s", m->mf_mount);
+#endif
+ n->n_error = (*m->mf_ops->fumount_fs)(m);
+ if (n->n_error) {
+ glob_error = n->n_error;
+ n->n_error = 0;
+ } else {
+ /*
+ * Make sure remount gets this node
+ */
+ n->n_error = -1;
+ }
+ }
+ }
+
+ /*
+ * If any unmounts failed then remount the
+ * whole lot...
+ */
+ if (glob_error) {
+ glob_error = nfsx_remount(mf, TRUE);
+ if (glob_error) {
+ errno = glob_error; /* XXX */
+ plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount);
+ }
+ glob_error = EBUSY;
+ } else {
+ /*
+ * Remove all the mount points
+ */
+ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
+ mntfs *m = n->n_mnt;
+ if (n->n_error < 0) {
+ if (m->mf_ops->fs_flags & FS_MKMNT) {
+ (void) rmdirs(m->mf_mount);
+ m->mf_flags &= ~MFF_MKMNT;
+ }
+ }
+ free_mntfs(m);
+ n->n_mnt = 0;
+ n->n_error = -1;
+ }
+ }
+
+ return glob_error;
+}
+
+/*
+ * Ops structure
+ */
+am_ops nfsx_ops = {
+ "nfsx",
+ nfsx_match,
+ nfsx_init,
+ auto_fmount,
+ nfsx_fmount,
+ auto_fumount,
+ nfsx_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* nfsx_readlink */
+ 0, /* nfsx_mounted */
+ 0, /* nfsx_umounted */
+ find_nfs_srvr, /* XXX */
+ /*FS_UBACKGROUND|*/FS_AMQINFO
+};
+
+#endif /* HAS_NFSX */
diff --git a/usr.sbin/amd/amd/opts.c b/usr.sbin/amd/amd/opts.c
new file mode 100644
index 000000000000..54c967528c44
--- /dev/null
+++ b/usr.sbin/amd/amd/opts.c
@@ -0,0 +1,835 @@
+/*-
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ *
+ * $Id: opts.c,v 5.2.2.3 1992/05/31 16:34:13 jsp Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)opts.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "am.h"
+
+extern char *getenv P((const char *));
+
+/*
+ * static copy of the options with
+ * which to play
+ */
+static struct am_opts fs_static;
+
+static char *opt_host = hostname;
+static char *opt_hostd = hostd;
+static char nullstr[] = "";
+static char *opt_key = nullstr;
+static char *opt_map = nullstr;
+static char *opt_path = nullstr;
+
+static char *vars[8];
+
+/*
+ * Length of longest option name
+ */
+#define NLEN 16 /* conservative */
+#define S(x) (x) , (sizeof(x)-1)
+static struct opt {
+ char *name; /* Name of the option */
+ int nlen; /* Length of option name */
+ char **optp; /* Pointer to option value string */
+ char **sel_p; /* Pointer to selector value string */
+} opt_fields[] = {
+ /* Options in something corresponding to frequency of use */
+ { S("opts"), &fs_static.opt_opts, 0 },
+ { S("host"), 0, &opt_host },
+ { S("hostd"), 0, &opt_hostd },
+ { S("type"), &fs_static.opt_type, 0 },
+ { S("rhost"), &fs_static.opt_rhost, 0 },
+ { S("rfs"), &fs_static.opt_rfs, 0 },
+ { S("fs"), &fs_static.opt_fs, 0 },
+ { S("key"), 0, &opt_key },
+ { S("map"), 0, &opt_map },
+ { S("sublink"), &fs_static.opt_sublink, 0 },
+ { S("arch"), 0, &arch },
+ { S("dev"), &fs_static.opt_dev, 0 },
+ { S("pref"), &fs_static.opt_pref, 0 },
+ { S("path"), 0, &opt_path },
+ { S("autodir"), 0, &auto_dir },
+ { S("delay"), &fs_static.opt_delay, 0 },
+ { S("domain"), 0, &hostdomain },
+ { S("karch"), 0, &karch },
+ { S("cluster"), 0, &cluster },
+ { S("wire"), 0, &wire },
+ { S("byte"), 0, &endian },
+ { S("os"), 0, &op_sys },
+ { S("remopts"), &fs_static.opt_remopts, 0 },
+ { S("mount"), &fs_static.opt_mount, 0 },
+ { S("unmount"), &fs_static.opt_unmount, 0 },
+ { S("cache"), &fs_static.opt_cache, 0 },
+ { S("user"), &fs_static.opt_user, 0 },
+ { S("group"), &fs_static.opt_group, 0 },
+ { S("var0"), &vars[0], 0 },
+ { S("var1"), &vars[1], 0 },
+ { S("var2"), &vars[2], 0 },
+ { S("var3"), &vars[3], 0 },
+ { S("var4"), &vars[4], 0 },
+ { S("var5"), &vars[5], 0 },
+ { S("var6"), &vars[6], 0 },
+ { S("var7"), &vars[7], 0 },
+ { 0, 0, 0, 0 },
+};
+
+typedef struct opt_apply opt_apply;
+struct opt_apply {
+ char **opt;
+ char *val;
+};
+
+/*
+ * Specially expand the remote host name first
+ */
+static opt_apply rhost_expansion[] = {
+ { &fs_static.opt_rhost, "${host}" },
+ { 0, 0 },
+};
+/*
+ * List of options which need to be expanded
+ * Note that this the order here _may_ be important.
+ */
+static opt_apply expansions[] = {
+/* { &fs_static.opt_dir, 0 }, */
+ { &fs_static.opt_sublink, 0 },
+ { &fs_static.opt_rfs, "${path}" },
+ { &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" },
+ { &fs_static.opt_opts, "rw" },
+ { &fs_static.opt_remopts, "${opts}" },
+ { &fs_static.opt_mount, 0 },
+ { &fs_static.opt_unmount, 0 },
+ { 0, 0 },
+};
+
+/*
+ * List of options which need to be free'ed before re-use
+ */
+static opt_apply to_free[] = {
+ { &fs_static.fs_glob, 0 },
+ { &fs_static.fs_local, 0 },
+ { &fs_static.fs_mtab, 0 },
+/* { &fs_static.opt_dir, 0 }, */
+ { &fs_static.opt_sublink, 0 },
+ { &fs_static.opt_rfs, 0 },
+ { &fs_static.opt_fs, 0 },
+ { &fs_static.opt_rhost, 0 },
+ { &fs_static.opt_opts, 0 },
+ { &fs_static.opt_remopts, 0 },
+ { &fs_static.opt_mount, 0 },
+ { &fs_static.opt_unmount, 0 },
+ { &vars[0], 0 },
+ { &vars[1], 0 },
+ { &vars[2], 0 },
+ { &vars[3], 0 },
+ { &vars[4], 0 },
+ { &vars[5], 0 },
+ { &vars[6], 0 },
+ { &vars[7], 0 },
+ { 0, 0 },
+};
+
+/*
+ * Skip to next option in the string
+ */
+static char *opt P((char**));
+static char *opt(p)
+char **p;
+{
+ char *cp = *p;
+ char *dp = cp;
+ char *s = cp;
+
+top:
+ while (*cp && *cp != ';') {
+ if (*cp == '\"') {
+ /*
+ * Skip past string
+ */
+ cp++;
+ while (*cp && *cp != '\"')
+ *dp++ = *cp++;
+ if (*cp)
+ cp++;
+ } else {
+ *dp++ = *cp++;
+ }
+ }
+
+ /*
+ * Skip past any remaining ';'s
+ */
+ while (*cp == ';')
+ cp++;
+
+ /*
+ * If we have a zero length string
+ * and there are more fields, then
+ * parse the next one. This allows
+ * sequences of empty fields.
+ */
+ if (*cp && dp == s)
+ goto top;
+
+ *dp = '\0';
+
+ *p = cp;
+ return s;
+}
+
+static int eval_opts P((char*, char*));
+static int eval_opts(opts, mapkey)
+char *opts;
+char *mapkey;
+{
+ /*
+ * Fill in the global structure fs_static by
+ * cracking the string opts. opts may be
+ * scribbled on at will.
+ */
+ char *o = opts;
+ char *f;
+
+ /*
+ * For each user-specified option
+ */
+ while (*(f = opt(&o))) {
+ struct opt *op;
+ enum vs_opt { OldSyn, SelEQ, SelNE, VarAss } vs_opt;
+ char *eq = strchr(f, '=');
+ char *opt;
+ if (!eq || eq[1] == '\0' || eq == f) {
+ /*
+ * No value, just continue
+ */
+ plog(XLOG_USER, "key %s: No value component in \"%s\"", mapkey, f);
+ continue;
+ }
+
+ /*
+ * Check what type of operation is happening
+ * !=, =! is SelNE
+ * == is SelEQ
+ * := is VarAss
+ * = is OldSyn (either SelEQ or VarAss)
+ */
+ if (eq[-1] == '!') { /* != */
+ vs_opt = SelNE;
+ eq[-1] = '\0';
+ opt = eq + 1;
+ } else if (eq[-1] == ':') { /* := */
+ vs_opt = VarAss;
+ eq[-1] = '\0';
+ opt = eq + 1;
+ } else if (eq[1] == '=') { /* == */
+ vs_opt = SelEQ;
+ eq[0] = '\0';
+ opt = eq + 2;
+ } else if (eq[1] == '!') { /* =! */
+ vs_opt = SelNE;
+ eq[0] = '\0';
+ opt = eq + 2;
+ } else { /* = */
+ vs_opt = OldSyn;
+ eq[0] = '\0';
+ opt = eq + 1;
+ }
+
+ /*
+ * For each recognised option
+ */
+ for (op = opt_fields; op->name; op++) {
+ /*
+ * Check whether they match
+ */
+ if (FSTREQ(op->name, f)) {
+ switch (vs_opt) {
+#if AMD_COMPAT <= 5000108
+ case OldSyn:
+ plog(XLOG_WARNING, "key %s: Old syntax selector found: %s=%s", mapkey, f, opt);
+ if (!op->sel_p) {
+ *op->optp = opt;
+ break;
+ }
+ /* fall through ... */
+#endif /* 5000108 */
+ case SelEQ:
+ case SelNE:
+ if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) {
+ plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s",
+ mapkey,
+ op->name,
+ *op->sel_p,
+ vs_opt == SelNE ? "not " : "",
+ opt);
+ return 0;
+ }
+ break;
+
+ case VarAss:
+ if (op->sel_p) {
+ plog(XLOG_USER, "key %s: Can't assign to a selector (%s)", mapkey, op->name);
+ return 0;
+ }
+ *op->optp = opt;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (!op->name)
+ plog(XLOG_USER, "key %s: Unrecognised key/option \"%s\"", mapkey, f);
+ }
+
+ return 1;
+}
+
+/*
+ * Free an option
+ */
+static void free_op P((opt_apply*, int));
+/*ARGSUSED*/
+static void free_op(p, b)
+opt_apply *p;
+int b;
+{
+ if (*p->opt) {
+ free(*p->opt);
+ *p->opt = 0;
+ }
+}
+
+/*
+ * Normalize slashes in the string.
+ */
+void normalize_slash P((char *p));
+void normalize_slash(p)
+char *p;
+{
+ char *f = strchr(p, '/');
+ char *f0 = f;
+ if (f) {
+ char *t = f;
+ do {
+ /* assert(*f == '/'); */
+ if (f == f0 && f[0] == '/' && f[1] == '/') {
+ /* copy double slash iff first */
+ *t++ = *f++;
+ *t++ = *f++;
+ } else {
+ /* copy a single / across */
+ *t++ = *f++;
+ }
+
+ /* assert(f[-1] == '/'); */
+ /* skip past more /'s */
+ while (*f == '/')
+ f++;
+
+ /* assert(*f != '/'); */
+ /* keep copying up to next / */
+ while (*f && *f != '/') {
+ *t++ = *f++;
+ }
+
+ /* assert(*f == 0 || *f == '/'); */
+
+ } while (*f);
+ *t = 0; /* derived from fix by Steven Glassman */
+ }
+}
+
+/*
+ * Macro-expand an option. Note that this does not
+ * handle recursive expansions. They will go badly wrong.
+ * If sel is true then old expand selectors, otherwise
+ * don't expand selectors.
+ */
+static void expand_op P((opt_apply*, int));
+static void expand_op(p, sel_p)
+opt_apply *p;
+int sel_p;
+{
+/*
+ * The BUFSPACE macros checks that there is enough space
+ * left in the expansion buffer. If there isn't then we
+ * give up completely. This is done to avoid crashing the
+ * automounter itself (which would be a bad thing to do).
+ */
+#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN)
+static char expand_error[] = "No space to expand \"%s\"";
+
+ char expbuf[MAXPATHLEN+1];
+ char nbuf[NLEN+1];
+ char *ep = expbuf;
+ char *cp = *p->opt;
+ char *dp;
+#ifdef DEBUG
+ char *cp_orig = *p->opt;
+#endif /* DEBUG */
+ struct opt *op;
+
+ while (dp = strchr(cp, '$')) {
+ char ch;
+ /*
+ * First copy up to the $
+ */
+ { int len = dp - cp;
+ if (BUFSPACE(ep, len)) {
+ strncpy(ep, cp, len);
+ ep += len;
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+ }
+ cp = dp + 1;
+ ch = *cp++;
+ if (ch == '$') {
+ if (BUFSPACE(ep, 1)) {
+ *ep++ = '$';
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+ } else if (ch == '{') {
+ /* Expansion... */
+ enum { E_All, E_Dir, E_File, E_Domain, E_Host } todo;
+ /*
+ * Find closing brace
+ */
+ char *br_p = strchr(cp, '}');
+ int len;
+ /*
+ * Check we found it
+ */
+ if (!br_p) {
+ /*
+ * Just give up
+ */
+ plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
+ goto out;
+ }
+ len = br_p - cp;
+ /*
+ * Figure out which part of the variable to grab.
+ */
+ if (*cp == '/') {
+ /*
+ * Just take the last component
+ */
+ todo = E_File;
+ cp++;
+ --len;
+ } else if (br_p[-1] == '/') {
+ /*
+ * Take all but the last component
+ */
+ todo = E_Dir;
+ --len;
+ } else if (*cp == '.') {
+ /*
+ * Take domain name
+ */
+ todo = E_Domain;
+ cp++;
+ --len;
+ } else if (br_p[-1] == '.') {
+ /*
+ * Take host name
+ */
+ todo = E_Host;
+ --len;
+ } else {
+ /*
+ * Take the whole lot
+ */
+ todo = E_All;
+ }
+ /*
+ * Truncate if too long. Since it won't
+ * match anyway it doesn't matter that
+ * it has been cut short.
+ */
+ if (len > NLEN)
+ len = NLEN;
+ /*
+ * Put the string into another buffer so
+ * we can do comparisons.
+ */
+ strncpy(nbuf, cp, len);
+ nbuf[len] = '\0';
+ /*
+ * Advance cp
+ */
+ cp = br_p + 1;
+ /*
+ * Search the option array
+ */
+ for (op = opt_fields; op->name; op++) {
+ /*
+ * Check for match
+ */
+ if (len == op->nlen && STREQ(op->name, nbuf)) {
+ char xbuf[NLEN+3];
+ char *val;
+ /*
+ * Found expansion. Copy
+ * the correct value field.
+ */
+ if (!(!op->sel_p == !sel_p)) {
+ /*
+ * Copy the string across unexpanded
+ */
+ sprintf(xbuf, "${%s%s%s}",
+ todo == E_File ? "/" :
+ todo == E_Domain ? "." : "",
+ nbuf,
+ todo == E_Dir ? "/" :
+ todo == E_Host ? "." : "");
+ val = xbuf;
+ /*
+ * Make sure expansion doesn't
+ * munge the value!
+ */
+ todo = E_All;
+ } else if (op->sel_p) {
+ val = *op->sel_p;
+ } else {
+ val = *op->optp;
+ }
+ if (val) {
+ /*
+ * Do expansion:
+ * ${/var} means take just the last part
+ * ${var/} means take all but the last part
+ * ${.var} means take all but first part
+ * ${var.} means take just the first part
+ * ${var} means take the whole lot
+ */
+ int vlen = strlen(val);
+ char *vptr = val;
+ switch (todo) {
+ case E_Dir:
+ vptr = strrchr(val, '/');
+ if (vptr)
+ vlen = vptr - val;
+ vptr = val;
+ break;
+ case E_File:
+ vptr = strrchr(val, '/');
+ if (vptr) {
+ vptr++;
+ vlen = strlen(vptr);
+ } else
+ vptr = val;
+ break;
+ case E_Domain:
+ vptr = strchr(val, '.');
+ if (vptr) {
+ vptr++;
+ vlen = strlen(vptr);
+ } else {
+ vptr = "";
+ vlen = 0;
+ }
+ break;
+ case E_Host:
+ vptr = strchr(val, '.');
+ if (vptr)
+ vlen = vptr - val;
+ vptr = val;
+ break;
+ case E_All:
+ break;
+ }
+#ifdef DEBUG
+ /*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/
+#endif /* DEBUG */
+ if (BUFSPACE(ep, vlen)) {
+ strcpy(ep, vptr);
+ ep += vlen;
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+ }
+ /*
+ * Done with this variable
+ */
+ break;
+ }
+ }
+ /*
+ * Check that the search was succesful
+ */